@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.mjs CHANGED
@@ -9391,191 +9391,6 @@ var SignInButton = styled25.button`
9391
9391
  background: rgba(240, 185, 11, 0.1);
9392
9392
  }
9393
9393
  `;
9394
- var slideIn = keyframes`
9395
- from { transform: translateX(110%); opacity: 0; }
9396
- to { transform: translateX(0); opacity: 1; }
9397
- `;
9398
- var slideOut = keyframes`
9399
- from { transform: translateX(0); opacity: 1; }
9400
- to { transform: translateX(110%); opacity: 0; }
9401
- `;
9402
- var progressShrink = keyframes`
9403
- from { width: 100%; }
9404
- to { width: 0%; }
9405
- `;
9406
- var VARIANT_COLORS = {
9407
- success: { accent: "#0ecb81", icon: "\u2713" },
9408
- error: { accent: "#f6465d", icon: "\u2715" },
9409
- info: { accent: "#E6C656", icon: "\u2139" },
9410
- pending: { accent: "#7EB3E6", icon: "\u25CC" }
9411
- };
9412
- var Wrapper = styled25.div`
9413
- position: relative;
9414
- display: flex;
9415
- flex-direction: column;
9416
- gap: 0;
9417
- width: 340px;
9418
- background: #0d0f1a;
9419
- border: 1px solid rgba(255, 255, 255, 0.08);
9420
- border-radius: 10px;
9421
- overflow: hidden;
9422
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255,255,255,0.04);
9423
- animation: ${({ $exiting }) => $exiting ? css`${slideOut} 0.28s cubic-bezier(0.4,0,1,1) forwards` : css`${slideIn} 0.32s cubic-bezier(0,0,0.2,1) forwards`};
9424
- pointer-events: all;
9425
- `;
9426
- var Body = styled25.div`
9427
- display: flex;
9428
- align-items: flex-start;
9429
- gap: 12px;
9430
- padding: 14px 16px 12px;
9431
- `;
9432
- var IconDot = styled25.div`
9433
- flex-shrink: 0;
9434
- width: 28px;
9435
- height: 28px;
9436
- border-radius: 50%;
9437
- background: ${({ $color }) => $color}1a;
9438
- border: 1px solid ${({ $color }) => $color}55;
9439
- display: flex;
9440
- align-items: center;
9441
- justify-content: center;
9442
- font-size: 0.75rem;
9443
- font-weight: 700;
9444
- color: ${({ $color }) => $color};
9445
- margin-top: 1px;
9446
- `;
9447
- var Content = styled25.div`
9448
- flex: 1;
9449
- min-width: 0;
9450
- `;
9451
- var Title2 = styled25.p`
9452
- margin: 0 0 2px;
9453
- font-size: 0.8rem;
9454
- font-weight: 600;
9455
- color: #fff;
9456
- letter-spacing: 0.01em;
9457
- `;
9458
- var Amount = styled25.p`
9459
- margin: 0 0 6px;
9460
- font-size: 1.05rem;
9461
- font-weight: 700;
9462
- color: #E6C656;
9463
- letter-spacing: -0.01em;
9464
- `;
9465
- var TxRow = styled25.a`
9466
- display: inline-flex;
9467
- align-items: center;
9468
- gap: 5px;
9469
- font-family: 'IBM Plex Mono', 'Space Mono', monospace;
9470
- font-size: 0.68rem;
9471
- color: rgba(255, 255, 255, 0.4);
9472
- text-decoration: none;
9473
- transition: color 0.15s;
9474
- &:hover {
9475
- color: #7EB3E6;
9476
- }
9477
- `;
9478
- var TxArrow = styled25.span`
9479
- font-size: 0.6rem;
9480
- opacity: 0.6;
9481
- `;
9482
- var CloseBtn = styled25.button`
9483
- flex-shrink: 0;
9484
- background: none;
9485
- border: none;
9486
- padding: 2px 4px;
9487
- cursor: pointer;
9488
- color: rgba(255, 255, 255, 0.25);
9489
- font-size: 0.9rem;
9490
- line-height: 1;
9491
- transition: color 0.15s;
9492
- &:hover { color: rgba(255, 255, 255, 0.7); }
9493
- `;
9494
- var ProgressBar = styled25.div`
9495
- height: 2px;
9496
- background: rgba(255, 255, 255, 0.06);
9497
- position: relative;
9498
- &::after {
9499
- content: '';
9500
- position: absolute;
9501
- left: 0;
9502
- top: 0;
9503
- height: 100%;
9504
- background: ${({ $color }) => $color};
9505
- animation: ${css`${progressShrink} ${({ $duration }) => $duration}ms linear forwards`};
9506
- }
9507
- `;
9508
- var Container = styled25.div`
9509
- position: fixed;
9510
- bottom: 24px;
9511
- right: 24px;
9512
- z-index: 9999;
9513
- display: flex;
9514
- flex-direction: column-reverse;
9515
- gap: 10px;
9516
- pointer-events: none;
9517
- `;
9518
- var DEFAULT_EXPLORER = "https://sepolia.basescan.org/tx/";
9519
- function truncateHash(hash) {
9520
- return `${hash.slice(0, 6)}\u2026${hash.slice(-4)}`;
9521
- }
9522
- function ToastItem({ toast, onDismiss }) {
9523
- const [exiting, setExiting] = useState(false);
9524
- const timerRef = useRef(null);
9525
- const dismiss = useCallback(() => {
9526
- setExiting(true);
9527
- setTimeout(() => onDismiss(toast.id), 280);
9528
- }, [onDismiss, toast.id]);
9529
- useEffect(() => {
9530
- const duration2 = toast.duration ?? 6e3;
9531
- if (duration2 > 0) {
9532
- timerRef.current = setTimeout(dismiss, duration2);
9533
- }
9534
- return () => {
9535
- if (timerRef.current) clearTimeout(timerRef.current);
9536
- };
9537
- }, [dismiss, toast.duration]);
9538
- const { accent, icon } = VARIANT_COLORS[toast.variant];
9539
- const duration = toast.duration ?? 6e3;
9540
- const explorerBase = toast.explorerUrl ?? DEFAULT_EXPLORER;
9541
- const txUrl = toast.txHash ? `${explorerBase}${toast.txHash}` : void 0;
9542
- return /* @__PURE__ */ jsxs(Wrapper, { $exiting: exiting, children: [
9543
- /* @__PURE__ */ jsxs(Body, { children: [
9544
- /* @__PURE__ */ jsx(IconDot, { $color: accent, children: icon }),
9545
- /* @__PURE__ */ jsxs(Content, { children: [
9546
- /* @__PURE__ */ jsx(Title2, { children: toast.title }),
9547
- toast.amount && /* @__PURE__ */ jsx(Amount, { children: toast.amount }),
9548
- toast.txHash && txUrl && /* @__PURE__ */ jsxs(TxRow, { href: txUrl, target: "_blank", rel: "noopener noreferrer", children: [
9549
- truncateHash(toast.txHash),
9550
- /* @__PURE__ */ jsx(TxArrow, { children: "\u2197" })
9551
- ] })
9552
- ] }),
9553
- /* @__PURE__ */ jsx(CloseBtn, { type: "button", onClick: dismiss, "aria-label": "Dismiss", children: "\u2715" })
9554
- ] }),
9555
- duration > 0 && /* @__PURE__ */ jsx(ProgressBar, { $color: accent, $duration: duration })
9556
- ] });
9557
- }
9558
- var ToastContext = createContext(null);
9559
- function ToastProvider({ children }) {
9560
- const [toasts, setToasts] = useState([]);
9561
- const addToast = useCallback((data) => {
9562
- const id = `toast-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
9563
- setToasts((prev) => [...prev, { ...data, id }]);
9564
- return id;
9565
- }, []);
9566
- const dismiss = useCallback((id) => {
9567
- setToasts((prev) => prev.filter((t) => t.id !== id));
9568
- }, []);
9569
- return /* @__PURE__ */ jsxs(ToastContext.Provider, { value: { toast: addToast, dismiss }, children: [
9570
- children,
9571
- /* @__PURE__ */ jsx(Container, { children: toasts.map((t) => /* @__PURE__ */ jsx(ToastItem, { toast: t, onDismiss: dismiss }, t.id)) })
9572
- ] });
9573
- }
9574
- function useToast() {
9575
- const ctx = useContext(ToastContext);
9576
- if (!ctx) throw new Error("useToast must be used within a ToastProvider");
9577
- return ctx;
9578
- }
9579
9394
  function AssetSelectorBar({
9580
9395
  propertyName,
9581
9396
  tokenPrice,
@@ -9882,7 +9697,7 @@ function OfferingProgressCard({
9882
9697
  const interval = setInterval(() => setCountdown(calculateCountdown()), 1e3);
9883
9698
  return () => clearInterval(interval);
9884
9699
  }, [opensAt]);
9885
- return /* @__PURE__ */ jsxs(Container2, { children: [
9700
+ return /* @__PURE__ */ jsxs(Container, { children: [
9886
9701
  /* @__PURE__ */ jsxs(Header2, { children: [
9887
9702
  /* @__PURE__ */ jsxs("h3", { children: [
9888
9703
  /* @__PURE__ */ jsx(FaChartLine, {}),
@@ -9983,7 +9798,7 @@ function OfferingProgressCard({
9983
9798
  ] })
9984
9799
  ] });
9985
9800
  }
9986
- var Container2 = styled25.div`
9801
+ var Container = styled25.div`
9987
9802
  background-color: var(--color-card-darker, #111);
9988
9803
  border-radius: 8px;
9989
9804
  padding: 1.5rem;
@@ -10519,6 +10334,191 @@ var LiveIndicatorDot = styled25.span`
10519
10334
  100% { box-shadow: 0 0 0 0 rgba(14,203,129,0); }
10520
10335
  }
10521
10336
  `;
10337
+ var slideIn = keyframes`
10338
+ from { transform: translateX(110%); opacity: 0; }
10339
+ to { transform: translateX(0); opacity: 1; }
10340
+ `;
10341
+ var slideOut = keyframes`
10342
+ from { transform: translateX(0); opacity: 1; }
10343
+ to { transform: translateX(110%); opacity: 0; }
10344
+ `;
10345
+ var progressShrink = keyframes`
10346
+ from { width: 100%; }
10347
+ to { width: 0%; }
10348
+ `;
10349
+ var VARIANT_COLORS = {
10350
+ success: { accent: "#0ecb81", icon: "\u2713" },
10351
+ error: { accent: "#f6465d", icon: "\u2715" },
10352
+ info: { accent: "#E6C656", icon: "\u2139" },
10353
+ pending: { accent: "#7EB3E6", icon: "\u25CC" }
10354
+ };
10355
+ var Wrapper = styled25.div`
10356
+ position: relative;
10357
+ display: flex;
10358
+ flex-direction: column;
10359
+ gap: 0;
10360
+ width: 340px;
10361
+ background: #0d0f1a;
10362
+ border: 1px solid rgba(255, 255, 255, 0.08);
10363
+ border-radius: 10px;
10364
+ overflow: hidden;
10365
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255,255,255,0.04);
10366
+ animation: ${({ $exiting }) => $exiting ? css`${slideOut} 0.28s cubic-bezier(0.4,0,1,1) forwards` : css`${slideIn} 0.32s cubic-bezier(0,0,0.2,1) forwards`};
10367
+ pointer-events: all;
10368
+ `;
10369
+ var Body = styled25.div`
10370
+ display: flex;
10371
+ align-items: flex-start;
10372
+ gap: 12px;
10373
+ padding: 14px 16px 12px;
10374
+ `;
10375
+ var IconDot = styled25.div`
10376
+ flex-shrink: 0;
10377
+ width: 28px;
10378
+ height: 28px;
10379
+ border-radius: 50%;
10380
+ background: ${({ $color }) => $color}1a;
10381
+ border: 1px solid ${({ $color }) => $color}55;
10382
+ display: flex;
10383
+ align-items: center;
10384
+ justify-content: center;
10385
+ font-size: 0.75rem;
10386
+ font-weight: 700;
10387
+ color: ${({ $color }) => $color};
10388
+ margin-top: 1px;
10389
+ `;
10390
+ var Content = styled25.div`
10391
+ flex: 1;
10392
+ min-width: 0;
10393
+ `;
10394
+ var Title2 = styled25.p`
10395
+ margin: 0 0 2px;
10396
+ font-size: 0.8rem;
10397
+ font-weight: 600;
10398
+ color: #fff;
10399
+ letter-spacing: 0.01em;
10400
+ `;
10401
+ var Amount = styled25.p`
10402
+ margin: 0 0 6px;
10403
+ font-size: 1.05rem;
10404
+ font-weight: 700;
10405
+ color: #E6C656;
10406
+ letter-spacing: -0.01em;
10407
+ `;
10408
+ var TxRow = styled25.a`
10409
+ display: inline-flex;
10410
+ align-items: center;
10411
+ gap: 5px;
10412
+ font-family: 'IBM Plex Mono', 'Space Mono', monospace;
10413
+ font-size: 0.68rem;
10414
+ color: rgba(255, 255, 255, 0.4);
10415
+ text-decoration: none;
10416
+ transition: color 0.15s;
10417
+ &:hover {
10418
+ color: #7EB3E6;
10419
+ }
10420
+ `;
10421
+ var TxArrow = styled25.span`
10422
+ font-size: 0.6rem;
10423
+ opacity: 0.6;
10424
+ `;
10425
+ var CloseBtn = styled25.button`
10426
+ flex-shrink: 0;
10427
+ background: none;
10428
+ border: none;
10429
+ padding: 2px 4px;
10430
+ cursor: pointer;
10431
+ color: rgba(255, 255, 255, 0.25);
10432
+ font-size: 0.9rem;
10433
+ line-height: 1;
10434
+ transition: color 0.15s;
10435
+ &:hover { color: rgba(255, 255, 255, 0.7); }
10436
+ `;
10437
+ var ProgressBar = styled25.div`
10438
+ height: 2px;
10439
+ background: rgba(255, 255, 255, 0.06);
10440
+ position: relative;
10441
+ &::after {
10442
+ content: '';
10443
+ position: absolute;
10444
+ left: 0;
10445
+ top: 0;
10446
+ height: 100%;
10447
+ background: ${({ $color }) => $color};
10448
+ animation: ${css`${progressShrink} ${({ $duration }) => $duration}ms linear forwards`};
10449
+ }
10450
+ `;
10451
+ var Container2 = styled25.div`
10452
+ position: fixed;
10453
+ bottom: 24px;
10454
+ right: 24px;
10455
+ z-index: 9999;
10456
+ display: flex;
10457
+ flex-direction: column-reverse;
10458
+ gap: 10px;
10459
+ pointer-events: none;
10460
+ `;
10461
+ var DEFAULT_EXPLORER = "https://sepolia.basescan.org/tx/";
10462
+ function truncateHash(hash) {
10463
+ return `${hash.slice(0, 6)}\u2026${hash.slice(-4)}`;
10464
+ }
10465
+ function ToastItem({ toast, onDismiss }) {
10466
+ const [exiting, setExiting] = useState(false);
10467
+ const timerRef = useRef(null);
10468
+ const dismiss = useCallback(() => {
10469
+ setExiting(true);
10470
+ setTimeout(() => onDismiss(toast.id), 280);
10471
+ }, [onDismiss, toast.id]);
10472
+ useEffect(() => {
10473
+ const duration2 = toast.duration ?? 6e3;
10474
+ if (duration2 > 0) {
10475
+ timerRef.current = setTimeout(dismiss, duration2);
10476
+ }
10477
+ return () => {
10478
+ if (timerRef.current) clearTimeout(timerRef.current);
10479
+ };
10480
+ }, [dismiss, toast.duration]);
10481
+ const { accent, icon } = VARIANT_COLORS[toast.variant];
10482
+ const duration = toast.duration ?? 6e3;
10483
+ const explorerBase = toast.explorerUrl ?? DEFAULT_EXPLORER;
10484
+ const txUrl = toast.txHash ? `${explorerBase}${toast.txHash}` : void 0;
10485
+ return /* @__PURE__ */ jsxs(Wrapper, { $exiting: exiting, children: [
10486
+ /* @__PURE__ */ jsxs(Body, { children: [
10487
+ /* @__PURE__ */ jsx(IconDot, { $color: accent, children: icon }),
10488
+ /* @__PURE__ */ jsxs(Content, { children: [
10489
+ /* @__PURE__ */ jsx(Title2, { children: toast.title }),
10490
+ toast.amount && /* @__PURE__ */ jsx(Amount, { children: toast.amount }),
10491
+ toast.txHash && txUrl && /* @__PURE__ */ jsxs(TxRow, { href: txUrl, target: "_blank", rel: "noopener noreferrer", children: [
10492
+ truncateHash(toast.txHash),
10493
+ /* @__PURE__ */ jsx(TxArrow, { children: "\u2197" })
10494
+ ] })
10495
+ ] }),
10496
+ /* @__PURE__ */ jsx(CloseBtn, { type: "button", onClick: dismiss, "aria-label": "Dismiss", children: "\u2715" })
10497
+ ] }),
10498
+ duration > 0 && /* @__PURE__ */ jsx(ProgressBar, { $color: accent, $duration: duration })
10499
+ ] });
10500
+ }
10501
+ var ToastContext = createContext(null);
10502
+ function ToastProvider({ children }) {
10503
+ const [toasts, setToasts] = useState([]);
10504
+ const addToast = useCallback((data) => {
10505
+ const id = `toast-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
10506
+ setToasts((prev) => [...prev, { ...data, id }]);
10507
+ return id;
10508
+ }, []);
10509
+ const dismiss = useCallback((id) => {
10510
+ setToasts((prev) => prev.filter((t) => t.id !== id));
10511
+ }, []);
10512
+ return /* @__PURE__ */ jsxs(ToastContext.Provider, { value: { toast: addToast, dismiss }, children: [
10513
+ children,
10514
+ /* @__PURE__ */ jsx(Container2, { children: toasts.map((t) => /* @__PURE__ */ jsx(ToastItem, { toast: t, onDismiss: dismiss }, t.id)) })
10515
+ ] });
10516
+ }
10517
+ function useToast() {
10518
+ const ctx = useContext(ToastContext);
10519
+ if (!ctx) throw new Error("useToast must be used within a ToastProvider");
10520
+ return ctx;
10521
+ }
10522
10522
  function OrderPanel({
10523
10523
  statusLabel,
10524
10524
  statusColor,
@@ -10551,6 +10551,7 @@ function OrderPanel({
10551
10551
  tokenDisplayName,
10552
10552
  tokenSymbol
10553
10553
  }) {
10554
+ const { toast } = useToast();
10554
10555
  const [payInputValue, setPayInputValue] = useState("");
10555
10556
  const [receiveInputValue, setReceiveInputValue] = useState("");
10556
10557
  const [isPayInputFocused, setIsPayInputFocused] = useState(false);
@@ -10561,6 +10562,14 @@ function OrderPanel({
10561
10562
  if (parsed <= 0) {
10562
10563
  setManualOrderAmount(null);
10563
10564
  setSliderValue(0);
10565
+ } else if (parsed < tokenPrice) {
10566
+ toast({
10567
+ variant: "error",
10568
+ title: "Amount too low",
10569
+ amount: `Minimum purchase is 1 token ($${tokenPrice.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })})`
10570
+ });
10571
+ setManualOrderAmount(null);
10572
+ setSliderValue(0);
10564
10573
  } else if (parsed >= availableBalance) {
10565
10574
  setManualOrderAmount(null);
10566
10575
  setSliderValue(100);
@@ -10684,6 +10693,17 @@ function OrderPanel({
10684
10693
  const v = e.target.value;
10685
10694
  if (v === "" || /^\d*\.?\d{0,2}$/.test(v)) {
10686
10695
  setPayInputValue(v);
10696
+ const parsed = parseInt(v.replace(/[^0-9]/g, ""), 10) || 0;
10697
+ if (parsed <= 0) {
10698
+ setManualOrderAmount(null);
10699
+ setSliderValue(0);
10700
+ } else if (parsed >= availableBalance) {
10701
+ setManualOrderAmount(null);
10702
+ setSliderValue(100);
10703
+ } else {
10704
+ setManualOrderAmount(parsed);
10705
+ setSliderValue(availableBalance === 0 ? 0 : Math.round(Math.max(0, parsed / availableBalance * 100)));
10706
+ }
10687
10707
  }
10688
10708
  },
10689
10709
  onKeyDown: (e) => {
@@ -10755,6 +10775,18 @@ function OrderPanel({
10755
10775
  const v = e.target.value;
10756
10776
  if (v === "" || /^\d+$/.test(v)) {
10757
10777
  setReceiveInputValue(v);
10778
+ const units = Math.floor(parseInt(v.replace(/[^0-9]/g, ""), 10) || 0);
10779
+ const spend = units * tokenPrice;
10780
+ if (units <= 0) {
10781
+ setManualOrderAmount(null);
10782
+ setSliderValue(0);
10783
+ } else if (spend >= availableBalance) {
10784
+ setManualOrderAmount(null);
10785
+ setSliderValue(100);
10786
+ } else {
10787
+ setManualOrderAmount(spend);
10788
+ setSliderValue(availableBalance === 0 ? 0 : Math.round(Math.max(0, spend / availableBalance * 100)));
10789
+ }
10758
10790
  }
10759
10791
  },
10760
10792
  onKeyDown: (e) => {
@@ -12557,7 +12589,6 @@ function PropertyBuy({
12557
12589
  onSelectorSelect,
12558
12590
  portfolioActivity
12559
12591
  }) {
12560
- const { toast } = useToast();
12561
12592
  const [sliderValue, setSliderValue] = useState(0);
12562
12593
  const [availableBalance, setAvailableBalance] = useState(walletUsdcBalance ?? 0);
12563
12594
  const [manualOrderAmount, setManualOrderAmount] = useState(null);
@@ -12610,13 +12641,6 @@ function PropertyBuy({
12610
12641
  }, [walletPropertyTokenBalance]);
12611
12642
  const handleOrderButtonClick = () => {
12612
12643
  if (!ipoStarted || tokenQuantity === 0) {
12613
- if (rawSpend > 0 && tokenQuantity === 0) {
12614
- toast({
12615
- variant: "error",
12616
- title: "Amount too low",
12617
- amount: `Minimum purchase is 1 token ($${tokenPrice.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })})`
12618
- });
12619
- }
12620
12644
  return;
12621
12645
  }
12622
12646
  setShowOrderConfirmModal(true);