@loafmarkets/ui 0.1.56 → 0.1.58

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 CHANGED
@@ -9416,191 +9416,6 @@ var SignInButton = styled25__default.default.button`
9416
9416
  background: rgba(240, 185, 11, 0.1);
9417
9417
  }
9418
9418
  `;
9419
- var slideIn = styled25.keyframes`
9420
- from { transform: translateX(110%); opacity: 0; }
9421
- to { transform: translateX(0); opacity: 1; }
9422
- `;
9423
- var slideOut = styled25.keyframes`
9424
- from { transform: translateX(0); opacity: 1; }
9425
- to { transform: translateX(110%); opacity: 0; }
9426
- `;
9427
- var progressShrink = styled25.keyframes`
9428
- from { width: 100%; }
9429
- to { width: 0%; }
9430
- `;
9431
- var VARIANT_COLORS = {
9432
- success: { accent: "#0ecb81", icon: "\u2713" },
9433
- error: { accent: "#f6465d", icon: "\u2715" },
9434
- info: { accent: "#E6C656", icon: "\u2139" },
9435
- pending: { accent: "#7EB3E6", icon: "\u25CC" }
9436
- };
9437
- var Wrapper = styled25__default.default.div`
9438
- position: relative;
9439
- display: flex;
9440
- flex-direction: column;
9441
- gap: 0;
9442
- width: 340px;
9443
- background: #0d0f1a;
9444
- border: 1px solid rgba(255, 255, 255, 0.08);
9445
- border-radius: 10px;
9446
- overflow: hidden;
9447
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255,255,255,0.04);
9448
- animation: ${({ $exiting }) => $exiting ? styled25.css`${slideOut} 0.28s cubic-bezier(0.4,0,1,1) forwards` : styled25.css`${slideIn} 0.32s cubic-bezier(0,0,0.2,1) forwards`};
9449
- pointer-events: all;
9450
- `;
9451
- var Body = styled25__default.default.div`
9452
- display: flex;
9453
- align-items: flex-start;
9454
- gap: 12px;
9455
- padding: 14px 16px 12px;
9456
- `;
9457
- var IconDot = styled25__default.default.div`
9458
- flex-shrink: 0;
9459
- width: 28px;
9460
- height: 28px;
9461
- border-radius: 50%;
9462
- background: ${({ $color }) => $color}1a;
9463
- border: 1px solid ${({ $color }) => $color}55;
9464
- display: flex;
9465
- align-items: center;
9466
- justify-content: center;
9467
- font-size: 0.75rem;
9468
- font-weight: 700;
9469
- color: ${({ $color }) => $color};
9470
- margin-top: 1px;
9471
- `;
9472
- var Content = styled25__default.default.div`
9473
- flex: 1;
9474
- min-width: 0;
9475
- `;
9476
- var Title2 = styled25__default.default.p`
9477
- margin: 0 0 2px;
9478
- font-size: 0.8rem;
9479
- font-weight: 600;
9480
- color: #fff;
9481
- letter-spacing: 0.01em;
9482
- `;
9483
- var Amount = styled25__default.default.p`
9484
- margin: 0 0 6px;
9485
- font-size: 1.05rem;
9486
- font-weight: 700;
9487
- color: #E6C656;
9488
- letter-spacing: -0.01em;
9489
- `;
9490
- var TxRow = styled25__default.default.a`
9491
- display: inline-flex;
9492
- align-items: center;
9493
- gap: 5px;
9494
- font-family: 'IBM Plex Mono', 'Space Mono', monospace;
9495
- font-size: 0.68rem;
9496
- color: rgba(255, 255, 255, 0.4);
9497
- text-decoration: none;
9498
- transition: color 0.15s;
9499
- &:hover {
9500
- color: #7EB3E6;
9501
- }
9502
- `;
9503
- var TxArrow = styled25__default.default.span`
9504
- font-size: 0.6rem;
9505
- opacity: 0.6;
9506
- `;
9507
- var CloseBtn = styled25__default.default.button`
9508
- flex-shrink: 0;
9509
- background: none;
9510
- border: none;
9511
- padding: 2px 4px;
9512
- cursor: pointer;
9513
- color: rgba(255, 255, 255, 0.25);
9514
- font-size: 0.9rem;
9515
- line-height: 1;
9516
- transition: color 0.15s;
9517
- &:hover { color: rgba(255, 255, 255, 0.7); }
9518
- `;
9519
- var ProgressBar = styled25__default.default.div`
9520
- height: 2px;
9521
- background: rgba(255, 255, 255, 0.06);
9522
- position: relative;
9523
- &::after {
9524
- content: '';
9525
- position: absolute;
9526
- left: 0;
9527
- top: 0;
9528
- height: 100%;
9529
- background: ${({ $color }) => $color};
9530
- animation: ${styled25.css`${progressShrink} ${({ $duration }) => $duration}ms linear forwards`};
9531
- }
9532
- `;
9533
- var Container = styled25__default.default.div`
9534
- position: fixed;
9535
- bottom: 24px;
9536
- right: 24px;
9537
- z-index: 9999;
9538
- display: flex;
9539
- flex-direction: column-reverse;
9540
- gap: 10px;
9541
- pointer-events: none;
9542
- `;
9543
- var DEFAULT_EXPLORER = "https://sepolia.basescan.org/tx/";
9544
- function truncateHash(hash) {
9545
- return `${hash.slice(0, 6)}\u2026${hash.slice(-4)}`;
9546
- }
9547
- function ToastItem({ toast, onDismiss }) {
9548
- const [exiting, setExiting] = React5.useState(false);
9549
- const timerRef = React5.useRef(null);
9550
- const dismiss = React5.useCallback(() => {
9551
- setExiting(true);
9552
- setTimeout(() => onDismiss(toast.id), 280);
9553
- }, [onDismiss, toast.id]);
9554
- React5.useEffect(() => {
9555
- const duration2 = toast.duration ?? 6e3;
9556
- if (duration2 > 0) {
9557
- timerRef.current = setTimeout(dismiss, duration2);
9558
- }
9559
- return () => {
9560
- if (timerRef.current) clearTimeout(timerRef.current);
9561
- };
9562
- }, [dismiss, toast.duration]);
9563
- const { accent, icon } = VARIANT_COLORS[toast.variant];
9564
- const duration = toast.duration ?? 6e3;
9565
- const explorerBase = toast.explorerUrl ?? DEFAULT_EXPLORER;
9566
- const txUrl = toast.txHash ? `${explorerBase}${toast.txHash}` : void 0;
9567
- return /* @__PURE__ */ jsxRuntime.jsxs(Wrapper, { $exiting: exiting, children: [
9568
- /* @__PURE__ */ jsxRuntime.jsxs(Body, { children: [
9569
- /* @__PURE__ */ jsxRuntime.jsx(IconDot, { $color: accent, children: icon }),
9570
- /* @__PURE__ */ jsxRuntime.jsxs(Content, { children: [
9571
- /* @__PURE__ */ jsxRuntime.jsx(Title2, { children: toast.title }),
9572
- toast.amount && /* @__PURE__ */ jsxRuntime.jsx(Amount, { children: toast.amount }),
9573
- toast.txHash && txUrl && /* @__PURE__ */ jsxRuntime.jsxs(TxRow, { href: txUrl, target: "_blank", rel: "noopener noreferrer", children: [
9574
- truncateHash(toast.txHash),
9575
- /* @__PURE__ */ jsxRuntime.jsx(TxArrow, { children: "\u2197" })
9576
- ] })
9577
- ] }),
9578
- /* @__PURE__ */ jsxRuntime.jsx(CloseBtn, { type: "button", onClick: dismiss, "aria-label": "Dismiss", children: "\u2715" })
9579
- ] }),
9580
- duration > 0 && /* @__PURE__ */ jsxRuntime.jsx(ProgressBar, { $color: accent, $duration: duration })
9581
- ] });
9582
- }
9583
- var ToastContext = React5.createContext(null);
9584
- function ToastProvider({ children }) {
9585
- const [toasts, setToasts] = React5.useState([]);
9586
- const addToast = React5.useCallback((data) => {
9587
- const id = `toast-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
9588
- setToasts((prev) => [...prev, { ...data, id }]);
9589
- return id;
9590
- }, []);
9591
- const dismiss = React5.useCallback((id) => {
9592
- setToasts((prev) => prev.filter((t) => t.id !== id));
9593
- }, []);
9594
- return /* @__PURE__ */ jsxRuntime.jsxs(ToastContext.Provider, { value: { toast: addToast, dismiss }, children: [
9595
- children,
9596
- /* @__PURE__ */ jsxRuntime.jsx(Container, { children: toasts.map((t) => /* @__PURE__ */ jsxRuntime.jsx(ToastItem, { toast: t, onDismiss: dismiss }, t.id)) })
9597
- ] });
9598
- }
9599
- function useToast() {
9600
- const ctx = React5.useContext(ToastContext);
9601
- if (!ctx) throw new Error("useToast must be used within a ToastProvider");
9602
- return ctx;
9603
- }
9604
9419
  function AssetSelectorBar({
9605
9420
  propertyName,
9606
9421
  tokenPrice,
@@ -9907,7 +9722,7 @@ function OfferingProgressCard({
9907
9722
  const interval = setInterval(() => setCountdown(calculateCountdown()), 1e3);
9908
9723
  return () => clearInterval(interval);
9909
9724
  }, [opensAt]);
9910
- return /* @__PURE__ */ jsxRuntime.jsxs(Container2, { children: [
9725
+ return /* @__PURE__ */ jsxRuntime.jsxs(Container, { children: [
9911
9726
  /* @__PURE__ */ jsxRuntime.jsxs(Header2, { children: [
9912
9727
  /* @__PURE__ */ jsxRuntime.jsxs("h3", { children: [
9913
9728
  /* @__PURE__ */ jsxRuntime.jsx(fa.FaChartLine, {}),
@@ -10008,7 +9823,7 @@ function OfferingProgressCard({
10008
9823
  ] })
10009
9824
  ] });
10010
9825
  }
10011
- var Container2 = styled25__default.default.div`
9826
+ var Container = styled25__default.default.div`
10012
9827
  background-color: var(--color-card-darker, #111);
10013
9828
  border-radius: 8px;
10014
9829
  padding: 1.5rem;
@@ -10544,6 +10359,191 @@ var LiveIndicatorDot = styled25__default.default.span`
10544
10359
  100% { box-shadow: 0 0 0 0 rgba(14,203,129,0); }
10545
10360
  }
10546
10361
  `;
10362
+ var slideIn = styled25.keyframes`
10363
+ from { transform: translateX(110%); opacity: 0; }
10364
+ to { transform: translateX(0); opacity: 1; }
10365
+ `;
10366
+ var slideOut = styled25.keyframes`
10367
+ from { transform: translateX(0); opacity: 1; }
10368
+ to { transform: translateX(110%); opacity: 0; }
10369
+ `;
10370
+ var progressShrink = styled25.keyframes`
10371
+ from { width: 100%; }
10372
+ to { width: 0%; }
10373
+ `;
10374
+ var VARIANT_COLORS = {
10375
+ success: { accent: "#0ecb81", icon: "\u2713" },
10376
+ error: { accent: "#f6465d", icon: "\u2715" },
10377
+ info: { accent: "#E6C656", icon: "\u2139" },
10378
+ pending: { accent: "#7EB3E6", icon: "\u25CC" }
10379
+ };
10380
+ var Wrapper = styled25__default.default.div`
10381
+ position: relative;
10382
+ display: flex;
10383
+ flex-direction: column;
10384
+ gap: 0;
10385
+ width: 340px;
10386
+ background: #0d0f1a;
10387
+ border: 1px solid rgba(255, 255, 255, 0.08);
10388
+ border-radius: 10px;
10389
+ overflow: hidden;
10390
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255,255,255,0.04);
10391
+ animation: ${({ $exiting }) => $exiting ? styled25.css`${slideOut} 0.28s cubic-bezier(0.4,0,1,1) forwards` : styled25.css`${slideIn} 0.32s cubic-bezier(0,0,0.2,1) forwards`};
10392
+ pointer-events: all;
10393
+ `;
10394
+ var Body = styled25__default.default.div`
10395
+ display: flex;
10396
+ align-items: flex-start;
10397
+ gap: 12px;
10398
+ padding: 14px 16px 12px;
10399
+ `;
10400
+ var IconDot = styled25__default.default.div`
10401
+ flex-shrink: 0;
10402
+ width: 28px;
10403
+ height: 28px;
10404
+ border-radius: 50%;
10405
+ background: ${({ $color }) => $color}1a;
10406
+ border: 1px solid ${({ $color }) => $color}55;
10407
+ display: flex;
10408
+ align-items: center;
10409
+ justify-content: center;
10410
+ font-size: 0.75rem;
10411
+ font-weight: 700;
10412
+ color: ${({ $color }) => $color};
10413
+ margin-top: 1px;
10414
+ `;
10415
+ var Content = styled25__default.default.div`
10416
+ flex: 1;
10417
+ min-width: 0;
10418
+ `;
10419
+ var Title2 = styled25__default.default.p`
10420
+ margin: 0 0 2px;
10421
+ font-size: 0.8rem;
10422
+ font-weight: 600;
10423
+ color: #fff;
10424
+ letter-spacing: 0.01em;
10425
+ `;
10426
+ var Amount = styled25__default.default.p`
10427
+ margin: 0 0 6px;
10428
+ font-size: 1.05rem;
10429
+ font-weight: 700;
10430
+ color: #E6C656;
10431
+ letter-spacing: -0.01em;
10432
+ `;
10433
+ var TxRow = styled25__default.default.a`
10434
+ display: inline-flex;
10435
+ align-items: center;
10436
+ gap: 5px;
10437
+ font-family: 'IBM Plex Mono', 'Space Mono', monospace;
10438
+ font-size: 0.68rem;
10439
+ color: rgba(255, 255, 255, 0.4);
10440
+ text-decoration: none;
10441
+ transition: color 0.15s;
10442
+ &:hover {
10443
+ color: #7EB3E6;
10444
+ }
10445
+ `;
10446
+ var TxArrow = styled25__default.default.span`
10447
+ font-size: 0.6rem;
10448
+ opacity: 0.6;
10449
+ `;
10450
+ var CloseBtn = styled25__default.default.button`
10451
+ flex-shrink: 0;
10452
+ background: none;
10453
+ border: none;
10454
+ padding: 2px 4px;
10455
+ cursor: pointer;
10456
+ color: rgba(255, 255, 255, 0.25);
10457
+ font-size: 0.9rem;
10458
+ line-height: 1;
10459
+ transition: color 0.15s;
10460
+ &:hover { color: rgba(255, 255, 255, 0.7); }
10461
+ `;
10462
+ var ProgressBar = styled25__default.default.div`
10463
+ height: 2px;
10464
+ background: rgba(255, 255, 255, 0.06);
10465
+ position: relative;
10466
+ &::after {
10467
+ content: '';
10468
+ position: absolute;
10469
+ left: 0;
10470
+ top: 0;
10471
+ height: 100%;
10472
+ background: ${({ $color }) => $color};
10473
+ animation: ${styled25.css`${progressShrink} ${({ $duration }) => $duration}ms linear forwards`};
10474
+ }
10475
+ `;
10476
+ var Container2 = styled25__default.default.div`
10477
+ position: fixed;
10478
+ bottom: 24px;
10479
+ right: 24px;
10480
+ z-index: 9999;
10481
+ display: flex;
10482
+ flex-direction: column-reverse;
10483
+ gap: 10px;
10484
+ pointer-events: none;
10485
+ `;
10486
+ var DEFAULT_EXPLORER = "https://sepolia.basescan.org/tx/";
10487
+ function truncateHash(hash) {
10488
+ return `${hash.slice(0, 6)}\u2026${hash.slice(-4)}`;
10489
+ }
10490
+ function ToastItem({ toast, onDismiss }) {
10491
+ const [exiting, setExiting] = React5.useState(false);
10492
+ const timerRef = React5.useRef(null);
10493
+ const dismiss = React5.useCallback(() => {
10494
+ setExiting(true);
10495
+ setTimeout(() => onDismiss(toast.id), 280);
10496
+ }, [onDismiss, toast.id]);
10497
+ React5.useEffect(() => {
10498
+ const duration2 = toast.duration ?? 6e3;
10499
+ if (duration2 > 0) {
10500
+ timerRef.current = setTimeout(dismiss, duration2);
10501
+ }
10502
+ return () => {
10503
+ if (timerRef.current) clearTimeout(timerRef.current);
10504
+ };
10505
+ }, [dismiss, toast.duration]);
10506
+ const { accent, icon } = VARIANT_COLORS[toast.variant];
10507
+ const duration = toast.duration ?? 6e3;
10508
+ const explorerBase = toast.explorerUrl ?? DEFAULT_EXPLORER;
10509
+ const txUrl = toast.txHash ? `${explorerBase}${toast.txHash}` : void 0;
10510
+ return /* @__PURE__ */ jsxRuntime.jsxs(Wrapper, { $exiting: exiting, children: [
10511
+ /* @__PURE__ */ jsxRuntime.jsxs(Body, { children: [
10512
+ /* @__PURE__ */ jsxRuntime.jsx(IconDot, { $color: accent, children: icon }),
10513
+ /* @__PURE__ */ jsxRuntime.jsxs(Content, { children: [
10514
+ /* @__PURE__ */ jsxRuntime.jsx(Title2, { children: toast.title }),
10515
+ toast.amount && /* @__PURE__ */ jsxRuntime.jsx(Amount, { children: toast.amount }),
10516
+ toast.txHash && txUrl && /* @__PURE__ */ jsxRuntime.jsxs(TxRow, { href: txUrl, target: "_blank", rel: "noopener noreferrer", children: [
10517
+ truncateHash(toast.txHash),
10518
+ /* @__PURE__ */ jsxRuntime.jsx(TxArrow, { children: "\u2197" })
10519
+ ] })
10520
+ ] }),
10521
+ /* @__PURE__ */ jsxRuntime.jsx(CloseBtn, { type: "button", onClick: dismiss, "aria-label": "Dismiss", children: "\u2715" })
10522
+ ] }),
10523
+ duration > 0 && /* @__PURE__ */ jsxRuntime.jsx(ProgressBar, { $color: accent, $duration: duration })
10524
+ ] });
10525
+ }
10526
+ var ToastContext = React5.createContext(null);
10527
+ function ToastProvider({ children }) {
10528
+ const [toasts, setToasts] = React5.useState([]);
10529
+ const addToast = React5.useCallback((data) => {
10530
+ const id = `toast-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
10531
+ setToasts((prev) => [...prev, { ...data, id }]);
10532
+ return id;
10533
+ }, []);
10534
+ const dismiss = React5.useCallback((id) => {
10535
+ setToasts((prev) => prev.filter((t) => t.id !== id));
10536
+ }, []);
10537
+ return /* @__PURE__ */ jsxRuntime.jsxs(ToastContext.Provider, { value: { toast: addToast, dismiss }, children: [
10538
+ children,
10539
+ /* @__PURE__ */ jsxRuntime.jsx(Container2, { children: toasts.map((t) => /* @__PURE__ */ jsxRuntime.jsx(ToastItem, { toast: t, onDismiss: dismiss }, t.id)) })
10540
+ ] });
10541
+ }
10542
+ function useToast() {
10543
+ const ctx = React5.useContext(ToastContext);
10544
+ if (!ctx) throw new Error("useToast must be used within a ToastProvider");
10545
+ return ctx;
10546
+ }
10547
10547
  function OrderPanel({
10548
10548
  statusLabel,
10549
10549
  statusColor,
@@ -10576,6 +10576,7 @@ function OrderPanel({
10576
10576
  tokenDisplayName,
10577
10577
  tokenSymbol
10578
10578
  }) {
10579
+ const { toast } = useToast();
10579
10580
  const [payInputValue, setPayInputValue] = React5.useState("");
10580
10581
  const [receiveInputValue, setReceiveInputValue] = React5.useState("");
10581
10582
  const [isPayInputFocused, setIsPayInputFocused] = React5.useState(false);
@@ -10586,6 +10587,14 @@ function OrderPanel({
10586
10587
  if (parsed <= 0) {
10587
10588
  setManualOrderAmount(null);
10588
10589
  setSliderValue(0);
10590
+ } else if (parsed < tokenPrice) {
10591
+ toast({
10592
+ variant: "error",
10593
+ title: "Amount too low",
10594
+ amount: `Minimum purchase is 1 token ($${tokenPrice.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })})`
10595
+ });
10596
+ setManualOrderAmount(null);
10597
+ setSliderValue(0);
10589
10598
  } else if (parsed >= availableBalance) {
10590
10599
  setManualOrderAmount(null);
10591
10600
  setSliderValue(100);
@@ -10709,6 +10718,17 @@ function OrderPanel({
10709
10718
  const v = e.target.value;
10710
10719
  if (v === "" || /^\d*\.?\d{0,2}$/.test(v)) {
10711
10720
  setPayInputValue(v);
10721
+ const parsed = parseInt(v.replace(/[^0-9]/g, ""), 10) || 0;
10722
+ if (parsed <= 0) {
10723
+ setManualOrderAmount(null);
10724
+ setSliderValue(0);
10725
+ } else if (parsed >= availableBalance) {
10726
+ setManualOrderAmount(null);
10727
+ setSliderValue(100);
10728
+ } else {
10729
+ setManualOrderAmount(parsed);
10730
+ setSliderValue(availableBalance === 0 ? 0 : Math.round(Math.max(0, parsed / availableBalance * 100)));
10731
+ }
10712
10732
  }
10713
10733
  },
10714
10734
  onKeyDown: (e) => {
@@ -10780,6 +10800,18 @@ function OrderPanel({
10780
10800
  const v = e.target.value;
10781
10801
  if (v === "" || /^\d+$/.test(v)) {
10782
10802
  setReceiveInputValue(v);
10803
+ const units = Math.floor(parseInt(v.replace(/[^0-9]/g, ""), 10) || 0);
10804
+ const spend = units * tokenPrice;
10805
+ if (units <= 0) {
10806
+ setManualOrderAmount(null);
10807
+ setSliderValue(0);
10808
+ } else if (spend >= availableBalance) {
10809
+ setManualOrderAmount(null);
10810
+ setSliderValue(100);
10811
+ } else {
10812
+ setManualOrderAmount(spend);
10813
+ setSliderValue(availableBalance === 0 ? 0 : Math.round(Math.max(0, spend / availableBalance * 100)));
10814
+ }
10783
10815
  }
10784
10816
  },
10785
10817
  onKeyDown: (e) => {
@@ -12582,7 +12614,6 @@ function PropertyBuy({
12582
12614
  onSelectorSelect,
12583
12615
  portfolioActivity
12584
12616
  }) {
12585
- const { toast } = useToast();
12586
12617
  const [sliderValue, setSliderValue] = React5.useState(0);
12587
12618
  const [availableBalance, setAvailableBalance] = React5.useState(walletUsdcBalance ?? 0);
12588
12619
  const [manualOrderAmount, setManualOrderAmount] = React5.useState(null);
@@ -12635,13 +12666,6 @@ function PropertyBuy({
12635
12666
  }, [walletPropertyTokenBalance]);
12636
12667
  const handleOrderButtonClick = () => {
12637
12668
  if (!ipoStarted || tokenQuantity === 0) {
12638
- if (rawSpend > 0 && tokenQuantity === 0) {
12639
- toast({
12640
- variant: "error",
12641
- title: "Amount too low",
12642
- amount: `Minimum purchase is 1 token ($${tokenPrice.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })})`
12643
- });
12644
- }
12645
12669
  return;
12646
12670
  }
12647
12671
  setShowOrderConfirmModal(true);