@loafmarkets/ui 0.1.56 → 0.1.57

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);
@@ -12557,7 +12566,6 @@ function PropertyBuy({
12557
12566
  onSelectorSelect,
12558
12567
  portfolioActivity
12559
12568
  }) {
12560
- const { toast } = useToast();
12561
12569
  const [sliderValue, setSliderValue] = useState(0);
12562
12570
  const [availableBalance, setAvailableBalance] = useState(walletUsdcBalance ?? 0);
12563
12571
  const [manualOrderAmount, setManualOrderAmount] = useState(null);
@@ -12610,13 +12618,6 @@ function PropertyBuy({
12610
12618
  }, [walletPropertyTokenBalance]);
12611
12619
  const handleOrderButtonClick = () => {
12612
12620
  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
12621
  return;
12621
12622
  }
12622
12623
  setShowOrderConfirmModal(true);