@loafmarkets/ui 0.1.42 → 0.1.43

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
@@ -1,5 +1,5 @@
1
- import * as React5 from 'react';
2
- import React5__default, { createContext, useState, useEffect, useMemo, useCallback, useRef, useContext } from 'react';
1
+ import * as React9 from 'react';
2
+ import React9__default, { createContext, useState, useEffect, useMemo, useCallback, useRef, useContext } from 'react';
3
3
  import { Slot } from '@radix-ui/react-slot';
4
4
  import { cva } from 'class-variance-authority';
5
5
  import { clsx } from 'clsx';
@@ -50,7 +50,7 @@ var buttonVariants = cva(
50
50
  }
51
51
  }
52
52
  );
53
- var Button = React5.forwardRef(
53
+ var Button = React9.forwardRef(
54
54
  ({ className, variant, size, radius, asChild = false, ...props }, ref) => {
55
55
  const Comp = asChild ? Slot : "button";
56
56
  const coercedRadius = radius ?? (variant === "onboarding" || variant === "onboardingOutline" ? "square" : void 0);
@@ -89,11 +89,11 @@ var badgeVariants = cva(
89
89
  }
90
90
  }
91
91
  );
92
- var Badge = React5.forwardRef(
92
+ var Badge = React9.forwardRef(
93
93
  ({ className, variant, size, ...props }, ref) => /* @__PURE__ */ jsx("span", { ref, className: cn(badgeVariants({ variant, size }), className), ...props })
94
94
  );
95
95
  Badge.displayName = "Badge";
96
- var Card = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
96
+ var Card = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
97
97
  "div",
98
98
  {
99
99
  ref,
@@ -105,11 +105,11 @@ var Card = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ j
105
105
  }
106
106
  ));
107
107
  Card.displayName = "Card";
108
- var CardHeader = React5.forwardRef(
108
+ var CardHeader = React9.forwardRef(
109
109
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("flex flex-col space-y-1.5 p-6", className), ...props })
110
110
  );
111
111
  CardHeader.displayName = "CardHeader";
112
- var CardTitle = React5.forwardRef(
112
+ var CardTitle = React9.forwardRef(
113
113
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
114
114
  "h3",
115
115
  {
@@ -120,15 +120,15 @@ var CardTitle = React5.forwardRef(
120
120
  )
121
121
  );
122
122
  CardTitle.displayName = "CardTitle";
123
- var CardDescription = React5.forwardRef(
123
+ var CardDescription = React9.forwardRef(
124
124
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx("p", { ref, className: cn("text-sm text-slate-500", className), ...props })
125
125
  );
126
126
  CardDescription.displayName = "CardDescription";
127
- var CardContent = React5.forwardRef(
127
+ var CardContent = React9.forwardRef(
128
128
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("px-6 pb-6 pt-2 text-sm text-slate-600", className), ...props })
129
129
  );
130
130
  CardContent.displayName = "CardContent";
131
- var CardFooter = React5.forwardRef(
131
+ var CardFooter = React9.forwardRef(
132
132
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("flex items-center border-t border-slate-100 px-6 py-4", className), ...props })
133
133
  );
134
134
  CardFooter.displayName = "CardFooter";
@@ -146,7 +146,7 @@ var defaultFormatSignedCurrency = (value) => {
146
146
  const sign = value >= 0 ? "+" : "-";
147
147
  return `${sign}${defaultFormatCurrency(Math.abs(value))}`;
148
148
  };
149
- var PortfolioSummary = React5.forwardRef(
149
+ var PortfolioSummary = React9.forwardRef(
150
150
  ({
151
151
  availableCash,
152
152
  portfolioValue,
@@ -296,23 +296,23 @@ function HousePositionSlider({
296
296
  className,
297
297
  ...props
298
298
  }) {
299
- const [orderMode, setOrderMode] = React5.useState("none");
300
- const [buyTrackingMode, setBuyTrackingMode] = React5.useState("dollars");
301
- const [deltaDollars, setDeltaDollars] = React5.useState(0);
302
- const [deltaTokensBuy, setDeltaTokensBuy] = React5.useState(0);
303
- const [deltaTokensSell, setDeltaTokensSell] = React5.useState(0);
304
- const [_isDragging, setIsDragging] = React5.useState(false);
305
- const [visualTargetPct, setVisualTargetPct] = React5.useState(null);
306
- const [orderType, setOrderType] = React5.useState(defaultOrderType);
307
- const [limitPrice, setLimitPrice] = React5.useState(currentPrice);
308
- const [limitPriceInput, setLimitPriceInput] = React5.useState(currentPrice.toFixed(2));
309
- const [limitPriceDirty, setLimitPriceDirty] = React5.useState(false);
310
- const [ownershipInput, setOwnershipInput] = React5.useState("");
311
- const [tokenAmountInput, setTokenAmountInput] = React5.useState("");
312
- const houseRef = React5.useRef(null);
299
+ const [orderMode, setOrderMode] = React9.useState("none");
300
+ const [buyTrackingMode, setBuyTrackingMode] = React9.useState("dollars");
301
+ const [deltaDollars, setDeltaDollars] = React9.useState(0);
302
+ const [deltaTokensBuy, setDeltaTokensBuy] = React9.useState(0);
303
+ const [deltaTokensSell, setDeltaTokensSell] = React9.useState(0);
304
+ const [_isDragging, setIsDragging] = React9.useState(false);
305
+ const [visualTargetPct, setVisualTargetPct] = React9.useState(null);
306
+ const [orderType, setOrderType] = React9.useState(defaultOrderType);
307
+ const [limitPrice, setLimitPrice] = React9.useState(currentPrice);
308
+ const [limitPriceInput, setLimitPriceInput] = React9.useState(currentPrice.toFixed(2));
309
+ const [limitPriceDirty, setLimitPriceDirty] = React9.useState(false);
310
+ const [ownershipInput, setOwnershipInput] = React9.useState("");
311
+ const [tokenAmountInput, setTokenAmountInput] = React9.useState("");
312
+ const houseRef = React9.useRef(null);
313
313
  const asks = orderbook?.asks ?? [];
314
314
  const bids = orderbook?.bids ?? [];
315
- React5.useEffect(() => {
315
+ React9.useEffect(() => {
316
316
  if (orderType !== "limit") return;
317
317
  if (limitPriceDirty) return;
318
318
  setLimitPrice(currentPrice);
@@ -387,7 +387,7 @@ function HousePositionSlider({
387
387
  const impliedDisplayTargetOwnership = clamp(targetOwnership + ownershipShift, 0, 100);
388
388
  const displayTargetOwnership = visualTargetPct ?? impliedDisplayTargetOwnership;
389
389
  const estFeeTokens = Math.abs(deltaValue) * 5e-3 / (effectivePrice || 1);
390
- const resetOrder = React5.useCallback(() => {
390
+ const resetOrder = React9.useCallback(() => {
391
391
  setOrderMode("none");
392
392
  setBuyTrackingMode("dollars");
393
393
  setDeltaDollars(0);
@@ -395,7 +395,7 @@ function HousePositionSlider({
395
395
  setDeltaTokensSell(0);
396
396
  setVisualTargetPct(null);
397
397
  }, []);
398
- const updateOrderFromTargetValue = React5.useCallback(
398
+ const updateOrderFromTargetValue = React9.useCallback(
399
399
  (newTargetValue) => {
400
400
  const newDeltaValue = newTargetValue - holdingsValue;
401
401
  if (newDeltaValue > 0) {
@@ -419,7 +419,7 @@ function HousePositionSlider({
419
419
  },
420
420
  [effectiveAvailableCash, effectivePrice, effectiveTokensHeld, holdingsValue, resetOrder, tokensHeld]
421
421
  );
422
- const updateOrderFromOwnership = React5.useCallback(
422
+ const updateOrderFromOwnership = React9.useCallback(
423
423
  (newOwnershipPercent) => {
424
424
  const nextOwnership = clamp(newOwnershipPercent, 0, 100);
425
425
  const newTargetTokens = nextOwnership / 100 * totalTokens;
@@ -428,7 +428,7 @@ function HousePositionSlider({
428
428
  },
429
429
  [effectivePrice, totalTokens, updateOrderFromTargetValue]
430
430
  );
431
- const updateOrderFromTokenAmount = React5.useCallback(
431
+ const updateOrderFromTokenAmount = React9.useCallback(
432
432
  (tokenAmountSigned) => {
433
433
  if (tokenAmountSigned > 0) {
434
434
  const maxTokens = effectiveAvailableCash / (effectivePrice || 1);
@@ -451,7 +451,7 @@ function HousePositionSlider({
451
451
  },
452
452
  [effectiveAvailableCash, effectivePrice, effectiveTokensHeld, resetOrder]
453
453
  );
454
- const updateOrderFromSlider = React5.useCallback(
454
+ const updateOrderFromSlider = React9.useCallback(
455
455
  (pct) => {
456
456
  const normalized = (pct - 50) / 50;
457
457
  const magnitude = Math.min(Math.abs(normalized), 1);
@@ -495,7 +495,7 @@ function HousePositionSlider({
495
495
  },
496
496
  [effectiveAvailableCash, effectiveTokensHeld, resetOrder]
497
497
  );
498
- const handleDragAtClientY = React5.useCallback(
498
+ const handleDragAtClientY = React9.useCallback(
499
499
  (clientY) => {
500
500
  if (!houseRef.current) return;
501
501
  const rect = houseRef.current.getBoundingClientRect();
@@ -1011,18 +1011,18 @@ function HousePositionSliderMobile({
1011
1011
  className,
1012
1012
  ...props
1013
1013
  }) {
1014
- const [orderMode, setOrderMode] = React5.useState("none");
1015
- const [deltaDollars, setDeltaDollars] = React5.useState(0);
1016
- const [deltaTokensSell, setDeltaTokensSell] = React5.useState(0);
1017
- const [deltaTokensBuy, setDeltaTokensBuy] = React5.useState(0);
1018
- const [buyTrackingMode, setBuyTrackingMode] = React5.useState("dollars");
1019
- const [orderType, setOrderType] = React5.useState(defaultOrderType);
1020
- const [limitPrice, setLimitPrice] = React5.useState(currentPrice);
1021
- const [limitPriceInput, setLimitPriceInput] = React5.useState(currentPrice.toFixed(2));
1022
- const [limitPriceDirty, setLimitPriceDirty] = React5.useState(false);
1023
- const [tokenAmountInput, setTokenAmountInput] = React5.useState("");
1024
- const houseRef = React5.useRef(null);
1025
- React5.useEffect(() => {
1014
+ const [orderMode, setOrderMode] = React9.useState("none");
1015
+ const [deltaDollars, setDeltaDollars] = React9.useState(0);
1016
+ const [deltaTokensSell, setDeltaTokensSell] = React9.useState(0);
1017
+ const [deltaTokensBuy, setDeltaTokensBuy] = React9.useState(0);
1018
+ const [buyTrackingMode, setBuyTrackingMode] = React9.useState("dollars");
1019
+ const [orderType, setOrderType] = React9.useState(defaultOrderType);
1020
+ const [limitPrice, setLimitPrice] = React9.useState(currentPrice);
1021
+ const [limitPriceInput, setLimitPriceInput] = React9.useState(currentPrice.toFixed(2));
1022
+ const [limitPriceDirty, setLimitPriceDirty] = React9.useState(false);
1023
+ const [tokenAmountInput, setTokenAmountInput] = React9.useState("");
1024
+ const houseRef = React9.useRef(null);
1025
+ React9.useEffect(() => {
1026
1026
  if (orderType !== "limit") return;
1027
1027
  if (limitPriceDirty) return;
1028
1028
  setLimitPrice(currentPrice);
@@ -1064,7 +1064,7 @@ function HousePositionSliderMobile({
1064
1064
  const hasChange = orderMode !== "none" && (Math.abs(deltaTokens) > 1e-3 || Math.abs(deltaValue) > 0.01);
1065
1065
  const targetOwnership = totalTokens > 0 ? targetTokens / totalTokens * 100 : 0;
1066
1066
  const estFeeTokens = effectivePrice > 0 ? Math.abs(deltaValue) * 5e-3 / effectivePrice : 0;
1067
- const updateOrderFromTargetValue = React5.useCallback(
1067
+ const updateOrderFromTargetValue = React9.useCallback(
1068
1068
  (newTargetValue) => {
1069
1069
  const newDeltaValue = newTargetValue - holdingsValue;
1070
1070
  if (newDeltaValue > 0.01) {
@@ -1092,7 +1092,7 @@ function HousePositionSliderMobile({
1092
1092
  },
1093
1093
  [holdingsValue, availableCash, effectivePrice, tokensHeld]
1094
1094
  );
1095
- const updateOrderFromTokenAmount = React5.useCallback(
1095
+ const updateOrderFromTokenAmount = React9.useCallback(
1096
1096
  (tokenAmount) => {
1097
1097
  if (tokenAmount > 0) {
1098
1098
  const maxTokens = effectivePrice > 0 ? availableCash / effectivePrice : 0;
@@ -1119,14 +1119,14 @@ function HousePositionSliderMobile({
1119
1119
  },
1120
1120
  [effectivePrice, availableCash, tokensHeld]
1121
1121
  );
1122
- const handleMarkerClick = React5.useCallback(
1122
+ const handleMarkerClick = React9.useCallback(
1123
1123
  (pct) => {
1124
1124
  const newTargetValue = pct / 100 * totalCapacity;
1125
1125
  updateOrderFromTargetValue(newTargetValue);
1126
1126
  },
1127
1127
  [totalCapacity, updateOrderFromTargetValue]
1128
1128
  );
1129
- const onMouseDown = React5.useCallback(
1129
+ const onMouseDown = React9.useCallback(
1130
1130
  (e) => {
1131
1131
  e.preventDefault();
1132
1132
  const move = (ev) => {
@@ -1146,7 +1146,7 @@ function HousePositionSliderMobile({
1146
1146
  },
1147
1147
  [totalCapacity, updateOrderFromTargetValue]
1148
1148
  );
1149
- const onTouchStart = React5.useCallback(
1149
+ const onTouchStart = React9.useCallback(
1150
1150
  (e) => {
1151
1151
  e.preventDefault();
1152
1152
  e.stopPropagation();
@@ -1704,7 +1704,7 @@ var LiquidityText = styled24.span`
1704
1704
  letter-spacing: 0.1px;
1705
1705
  }
1706
1706
  `;
1707
- var LoafLiquidityBadge = React5.forwardRef(
1707
+ var LoafLiquidityBadge = React9.forwardRef(
1708
1708
  ({ className, isGlowing, onClick, children, ...props }, ref) => {
1709
1709
  return /* @__PURE__ */ jsxs(
1710
1710
  LogoContainer,
@@ -1732,9 +1732,34 @@ var LoafLiquidityBadge = React5.forwardRef(
1732
1732
  }
1733
1733
  );
1734
1734
  LoafLiquidityBadge.displayName = "LoafLiquidityBadge";
1735
+ var toSize = (v, fallback) => v == null ? fallback : typeof v === "number" ? `${v}px` : v;
1736
+ var Skeleton = React9.forwardRef(
1737
+ ({ width, height, radius, className, style, ...props }, ref) => {
1738
+ return /* @__PURE__ */ jsx(
1739
+ "div",
1740
+ {
1741
+ ref,
1742
+ "aria-busy": "true",
1743
+ "aria-live": "polite",
1744
+ className: cn(
1745
+ "inline-block align-middle bg-white/10 animate-pulse",
1746
+ className
1747
+ ),
1748
+ style: {
1749
+ width: toSize(width, "100%"),
1750
+ height: toSize(height, "1em"),
1751
+ borderRadius: toSize(radius, "6px"),
1752
+ ...style
1753
+ },
1754
+ ...props
1755
+ }
1756
+ );
1757
+ }
1758
+ );
1759
+ Skeleton.displayName = "Skeleton";
1735
1760
  function useViewportCompact(breakpoint) {
1736
- const [isCompact, setIsCompact] = React5.useState(false);
1737
- React5.useEffect(() => {
1761
+ const [isCompact, setIsCompact] = React9.useState(false);
1762
+ React9.useEffect(() => {
1738
1763
  if (typeof window === "undefined") return;
1739
1764
  const check = () => setIsCompact(window.innerWidth <= breakpoint);
1740
1765
  check();
@@ -1744,16 +1769,119 @@ function useViewportCompact(breakpoint) {
1744
1769
  return isCompact;
1745
1770
  }
1746
1771
  var formatNumber = (value, precision) => value.toFixed(precision);
1772
+ var FLASH_DURATION_MS = 450;
1773
+ var FLASH_UP_COLOR = "rgba(14, 203, 129, 0.35)";
1774
+ var FLASH_DOWN_COLOR = "rgba(246, 70, 93, 0.35)";
1775
+ function getTradeKey(trade, fallbackIndex) {
1776
+ if (trade.tradeId != null) return `id-${trade.tradeId}`;
1777
+ if (trade.time != null) return `t-${trade.time}-${trade.type}-${trade.price}-${trade.amount}`;
1778
+ return `idx-${fallbackIndex}-${trade.type}-${trade.price}-${trade.amount}`;
1779
+ }
1780
+ function useAmountChangeFlash(ref, amount) {
1781
+ const prevAmountRef = React9.useRef(amount);
1782
+ React9.useEffect(() => {
1783
+ const prev = prevAmountRef.current;
1784
+ const node = ref.current;
1785
+ if (prev !== amount && node && typeof node.animate === "function") {
1786
+ const color = amount > prev ? FLASH_UP_COLOR : FLASH_DOWN_COLOR;
1787
+ node.animate(
1788
+ [{ backgroundColor: color }, { backgroundColor: "transparent" }],
1789
+ { duration: FLASH_DURATION_MS, easing: "ease-out" }
1790
+ );
1791
+ }
1792
+ prevAmountRef.current = amount;
1793
+ }, [amount, ref]);
1794
+ }
1795
+ function useMidPriceFlash(ref, midPrice, restBgColor) {
1796
+ const prevMidRef = React9.useRef(midPrice);
1797
+ React9.useEffect(() => {
1798
+ const prev = prevMidRef.current;
1799
+ const node = ref.current;
1800
+ if (prev !== midPrice && prev > 0 && midPrice > 0 && node && typeof node.animate === "function") {
1801
+ const color = midPrice > prev ? FLASH_UP_COLOR : FLASH_DOWN_COLOR;
1802
+ node.animate(
1803
+ [{ backgroundColor: color }, { backgroundColor: restBgColor }],
1804
+ { duration: FLASH_DURATION_MS, easing: "ease-out" }
1805
+ );
1806
+ }
1807
+ prevMidRef.current = midPrice;
1808
+ }, [midPrice, ref, restBgColor]);
1809
+ }
1810
+ function TradeRow({
1811
+ trade,
1812
+ tradeKey,
1813
+ precision,
1814
+ amountPrecision,
1815
+ seenTradeKeysRef,
1816
+ compact
1817
+ }) {
1818
+ const rowRef = React9.useRef(null);
1819
+ const { type } = trade;
1820
+ React9.useEffect(() => {
1821
+ if (seenTradeKeysRef.current.has(tradeKey)) return;
1822
+ seenTradeKeysRef.current.add(tradeKey);
1823
+ const node = rowRef.current;
1824
+ if (!node || typeof node.animate !== "function") return;
1825
+ const color = type === "buy" ? FLASH_UP_COLOR : FLASH_DOWN_COLOR;
1826
+ node.animate(
1827
+ [{ backgroundColor: color }, { backgroundColor: "transparent" }],
1828
+ { duration: FLASH_DURATION_MS, easing: "ease-out" }
1829
+ );
1830
+ }, [tradeKey, seenTradeKeysRef, type]);
1831
+ if (compact) {
1832
+ return /* @__PURE__ */ jsxs(
1833
+ "div",
1834
+ {
1835
+ ref: rowRef,
1836
+ className: "grid",
1837
+ style: { gridTemplateColumns: "1.2fr 0.8fr", padding: "0.2rem 0", fontSize: "0.8rem" },
1838
+ children: [
1839
+ /* @__PURE__ */ jsxs("div", { style: { color: trade.type === "buy" ? "#0ecb81" : "#f6465d", fontWeight: 500 }, children: [
1840
+ "$",
1841
+ formatNumber(trade.price, precision)
1842
+ ] }),
1843
+ /* @__PURE__ */ jsx("div", { style: { textAlign: "right", paddingRight: "0.5rem" }, children: formatNumber(trade.amount, amountPrecision) })
1844
+ ]
1845
+ }
1846
+ );
1847
+ }
1848
+ return /* @__PURE__ */ jsxs(
1849
+ "div",
1850
+ {
1851
+ ref: rowRef,
1852
+ className: "grid grid-cols-2 items-center gap-3 px-3 py-1.5",
1853
+ children: [
1854
+ /* @__PURE__ */ jsxs(
1855
+ "div",
1856
+ {
1857
+ className: cn(
1858
+ "tabular-nums",
1859
+ trade.type === "buy" ? "text-[#0ecb81]" : "text-[#f6465d]"
1860
+ ),
1861
+ children: [
1862
+ "$",
1863
+ formatNumber(trade.price, precision)
1864
+ ]
1865
+ }
1866
+ ),
1867
+ /* @__PURE__ */ jsx("div", { className: "text-right tabular-nums text-white/90", children: formatNumber(trade.amount, amountPrecision) })
1868
+ ]
1869
+ }
1870
+ );
1871
+ }
1747
1872
  function DepthRow({
1748
1873
  side,
1749
1874
  price,
1750
1875
  amount,
1751
1876
  depthPct,
1752
1877
  precision,
1753
- amountPrecision
1878
+ amountPrecision,
1879
+ hasUserOrder
1754
1880
  }) {
1755
1881
  const isAsk = side === "ask";
1756
- return /* @__PURE__ */ jsxs("div", { className: "relative grid grid-cols-2 items-center gap-3 px-3 py-1.5", children: [
1882
+ const rowRef = React9.useRef(null);
1883
+ useAmountChangeFlash(rowRef, amount);
1884
+ return /* @__PURE__ */ jsxs("div", { ref: rowRef, className: "relative grid grid-cols-2 items-center gap-3 px-3 py-1.5", children: [
1757
1885
  /* @__PURE__ */ jsx(
1758
1886
  "div",
1759
1887
  {
@@ -1761,9 +1889,16 @@ function DepthRow({
1761
1889
  "absolute inset-y-0 right-0",
1762
1890
  isAsk ? "bg-rose-900/30" : "bg-emerald-900/30"
1763
1891
  ),
1764
- style: { width: `${clamp3(depthPct, 0, 100)}%` }
1892
+ style: { width: `${clamp3(depthPct, 0, 100)}%`, transition: "width 300ms ease-out" }
1765
1893
  }
1766
1894
  ),
1895
+ hasUserOrder ? /* @__PURE__ */ jsx(
1896
+ "span",
1897
+ {
1898
+ "aria-label": "Your order at this price",
1899
+ className: "absolute left-0 top-0 bottom-0 z-[2] w-[3px] rounded-r-sm bg-[#C9A227] shadow-[0_0_6px_rgba(201,162,39,0.6)]"
1900
+ }
1901
+ ) : null,
1767
1902
  /* @__PURE__ */ jsxs(
1768
1903
  "div",
1769
1904
  {
@@ -1783,7 +1918,7 @@ var DEPTH_ROW_HEIGHT_PX = 34;
1783
1918
  var COMPACT_ROWS_VISIBLE = 5;
1784
1919
  var COMPACT_ROW_HEIGHT_PX = 30;
1785
1920
  var COMPACT_BREAKPOINT_PX = 1024;
1786
- var Orderbook = React5.forwardRef(
1921
+ var Orderbook = React9.forwardRef(
1787
1922
  ({
1788
1923
  asks,
1789
1924
  bids,
@@ -1798,13 +1933,44 @@ var Orderbook = React5.forwardRef(
1798
1933
  onTabChange,
1799
1934
  rightHeader = /* @__PURE__ */ jsx(LoafLiquidityBadge, { className: "text-[0.6rem]" }),
1800
1935
  variant = "auto",
1936
+ userOrderPrices,
1937
+ isLoading = false,
1801
1938
  className,
1802
1939
  ...props
1803
1940
  }, ref) => {
1804
- const [tab, setTab] = React5.useState(defaultTab);
1805
- const [tradeFilter, setTradeFilter] = React5.useState("all");
1941
+ const [tab, setTab] = React9.useState(defaultTab);
1942
+ const [tradeFilter, setTradeFilter] = React9.useState("all");
1806
1943
  const viewportCompact = useViewportCompact(COMPACT_BREAKPOINT_PX);
1807
- React5.useEffect(() => {
1944
+ const { userAskPrices, userBidPrices } = React9.useMemo(() => {
1945
+ const ask = /* @__PURE__ */ new Set();
1946
+ const bid = /* @__PURE__ */ new Set();
1947
+ if (!userOrderPrices) return { userAskPrices: ask, userBidPrices: bid };
1948
+ for (const entry of userOrderPrices) {
1949
+ if (entry.side === "SELL") ask.add(entry.price);
1950
+ else bid.add(entry.price);
1951
+ }
1952
+ return { userAskPrices: ask, userBidPrices: bid };
1953
+ }, [userOrderPrices]);
1954
+ const seenTradeKeysRef = React9.useRef(/* @__PURE__ */ new Set());
1955
+ const initializedRef = React9.useRef(false);
1956
+ if (!initializedRef.current && trades.length > 0) {
1957
+ for (let i = 0; i < trades.length; i++) {
1958
+ seenTradeKeysRef.current.add(getTradeKey(trades[i], i));
1959
+ }
1960
+ initializedRef.current = true;
1961
+ }
1962
+ React9.useEffect(() => {
1963
+ if (!initializedRef.current) return;
1964
+ const live = /* @__PURE__ */ new Set();
1965
+ for (let i = 0; i < trades.length; i++) {
1966
+ live.add(getTradeKey(trades[i], i));
1967
+ }
1968
+ const seen = seenTradeKeysRef.current;
1969
+ for (const key of seen) {
1970
+ if (!live.has(key)) seen.delete(key);
1971
+ }
1972
+ }, [trades]);
1973
+ React9.useEffect(() => {
1808
1974
  setTab(defaultTab);
1809
1975
  }, [defaultTab]);
1810
1976
  const handleTab = (next) => {
@@ -1835,7 +2001,11 @@ var Orderbook = React5.forwardRef(
1835
2001
  midPrice,
1836
2002
  midChangePercent,
1837
2003
  midClass,
1838
- sectionHeight
2004
+ sectionHeight,
2005
+ userAskPrices,
2006
+ userBidPrices,
2007
+ isLoading,
2008
+ seenTradeKeysRef
1839
2009
  };
1840
2010
  return /* @__PURE__ */ jsx(
1841
2011
  Card,
@@ -1853,6 +2023,29 @@ var Orderbook = React5.forwardRef(
1853
2023
  }
1854
2024
  );
1855
2025
  Orderbook.displayName = "Orderbook";
2026
+ function SkeletonRow({ compact }) {
2027
+ if (compact) {
2028
+ return /* @__PURE__ */ jsxs(
2029
+ "div",
2030
+ {
2031
+ style: {
2032
+ display: "grid",
2033
+ gridTemplateColumns: "1.2fr 0.8fr",
2034
+ padding: "0.2rem 0",
2035
+ alignItems: "center"
2036
+ },
2037
+ children: [
2038
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Skeleton, { width: "60%", height: 10 }) }),
2039
+ /* @__PURE__ */ jsx("div", { style: { textAlign: "right", paddingRight: "0.5rem" }, children: /* @__PURE__ */ jsx(Skeleton, { width: "50%", height: 10 }) })
2040
+ ]
2041
+ }
2042
+ );
2043
+ }
2044
+ return /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 items-center gap-3 px-3 py-1.5", children: [
2045
+ /* @__PURE__ */ jsx(Skeleton, { width: "60%", height: 12 }),
2046
+ /* @__PURE__ */ jsx("div", { className: "text-right", children: /* @__PURE__ */ jsx(Skeleton, { width: "50%", height: 12 }) })
2047
+ ] });
2048
+ }
1856
2049
  function DesktopOrderbookLayout({
1857
2050
  tab,
1858
2051
  handleTab,
@@ -1871,8 +2064,14 @@ function DesktopOrderbookLayout({
1871
2064
  midPrice,
1872
2065
  midChangePercent,
1873
2066
  midClass,
1874
- sectionHeight
2067
+ sectionHeight,
2068
+ userAskPrices,
2069
+ userBidPrices,
2070
+ isLoading,
2071
+ seenTradeKeysRef
1875
2072
  }) {
2073
+ const midRef = React9.useRef(null);
2074
+ useMidPriceFlash(midRef, midPrice, "#0b1a24");
1876
2075
  return /* @__PURE__ */ jsxs(Fragment, { children: [
1877
2076
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 pt-4", children: [
1878
2077
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
@@ -1956,29 +2155,20 @@ function DesktopOrderbookLayout({
1956
2155
  {
1957
2156
  className: "max-h-[380px] overflow-y-auto overflow-x-hidden",
1958
2157
  style: { scrollbarGutter: "stable" },
1959
- children: tradeFiltered.length === 0 ? /* @__PURE__ */ jsx("div", { className: "px-3 py-10 text-center text-sm text-white/50", children: "No trades" }) : /* @__PURE__ */ jsx("div", { className: "divide-y divide-white/5", children: tradeFiltered.map((trade, i) => /* @__PURE__ */ jsxs(
1960
- "div",
1961
- {
1962
- className: "grid grid-cols-2 items-center gap-3 px-3 py-1.5",
1963
- children: [
1964
- /* @__PURE__ */ jsxs(
1965
- "div",
1966
- {
1967
- className: cn(
1968
- "tabular-nums",
1969
- trade.type === "buy" ? "text-[#0ecb81]" : "text-[#f6465d]"
1970
- ),
1971
- children: [
1972
- "$",
1973
- formatNumber(trade.price, precision)
1974
- ]
1975
- }
1976
- ),
1977
- /* @__PURE__ */ jsx("div", { className: "text-right tabular-nums text-white/90", children: formatNumber(trade.amount, amountPrecision) })
1978
- ]
1979
- },
1980
- `${trade.type}-${trade.price}-${trade.amount}-${trade.time ?? i}`
1981
- )) })
2158
+ children: isLoading && tradeFiltered.length === 0 ? /* @__PURE__ */ jsx("div", { className: "divide-y divide-white/5", children: Array.from({ length: LEVEL_ROWS_VISIBLE }).map((_, i) => /* @__PURE__ */ jsx(SkeletonRow, {}, `trade-skel-${i}`)) }) : tradeFiltered.length === 0 ? /* @__PURE__ */ jsx("div", { className: "px-3 py-10 text-center text-sm text-white/50", children: "No trades" }) : /* @__PURE__ */ jsx("div", { className: "divide-y divide-white/5", children: tradeFiltered.map((trade, i) => {
2159
+ const tradeKey = getTradeKey(trade, i);
2160
+ return /* @__PURE__ */ jsx(
2161
+ TradeRow,
2162
+ {
2163
+ trade,
2164
+ tradeKey,
2165
+ precision,
2166
+ amountPrecision,
2167
+ seenTradeKeysRef
2168
+ },
2169
+ tradeKey
2170
+ );
2171
+ }) })
1982
2172
  }
1983
2173
  ) : /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col min-h-0", children: [
1984
2174
  /* @__PURE__ */ jsx(
@@ -1986,7 +2176,7 @@ function DesktopOrderbookLayout({
1986
2176
  {
1987
2177
  className: "flex flex-col justify-end divide-y divide-white/5 overflow-y-auto",
1988
2178
  style: { height: `${sectionHeight}px`, scrollbarGutter: "stable" },
1989
- children: asks.map((l, idx) => /* @__PURE__ */ jsx(
2179
+ children: isLoading ? Array.from({ length: LEVEL_ROWS_VISIBLE }).map((_, i) => /* @__PURE__ */ jsx(SkeletonRow, {}, `ask-skel-${i}`)) : asks.map((l) => /* @__PURE__ */ jsx(
1990
2180
  DepthRow,
1991
2181
  {
1992
2182
  side: "ask",
@@ -1994,30 +2184,38 @@ function DesktopOrderbookLayout({
1994
2184
  amount: l.amount,
1995
2185
  depthPct: (l.depth ?? l.amount) / maxAskDepth * 100,
1996
2186
  precision,
1997
- amountPrecision
2187
+ amountPrecision,
2188
+ hasUserOrder: userAskPrices.has(l.price)
1998
2189
  },
1999
- `ask-${idx}-${l.price}-${l.amount}`
2190
+ `ask-${l.price}`
2000
2191
  ))
2001
2192
  }
2002
2193
  ),
2003
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 items-center gap-3 bg-[#0b1a24] px-3 py-2", children: [
2004
- /* @__PURE__ */ jsxs("div", { className: cn("text-lg font-semibold tabular-nums", midClass), children: [
2005
- "$",
2006
- formatNumber(midPrice, precision),
2007
- midChangePercent == null ? null : /* @__PURE__ */ jsxs("span", { className: cn("ml-2 text-sm font-semibold tabular-nums", midClass), children: [
2008
- midChangePercent >= 0 ? "+" : "",
2009
- midChangePercent.toFixed(2),
2010
- "%"
2011
- ] })
2012
- ] }),
2013
- /* @__PURE__ */ jsx("div", {})
2014
- ] }),
2194
+ /* @__PURE__ */ jsxs(
2195
+ "div",
2196
+ {
2197
+ ref: midRef,
2198
+ className: "grid grid-cols-2 items-center gap-3 bg-[#0b1a24] px-3 py-2",
2199
+ children: [
2200
+ /* @__PURE__ */ jsx("div", { className: cn("text-lg font-semibold tabular-nums", midClass), children: isLoading ? /* @__PURE__ */ jsx(Skeleton, { width: 110, height: 20 }) : /* @__PURE__ */ jsxs(Fragment, { children: [
2201
+ "$",
2202
+ formatNumber(midPrice, precision),
2203
+ midChangePercent == null ? null : /* @__PURE__ */ jsxs("span", { className: cn("ml-2 text-sm font-semibold tabular-nums", midClass), children: [
2204
+ midChangePercent >= 0 ? "+" : "",
2205
+ midChangePercent.toFixed(2),
2206
+ "%"
2207
+ ] })
2208
+ ] }) }),
2209
+ /* @__PURE__ */ jsx("div", {})
2210
+ ]
2211
+ }
2212
+ ),
2015
2213
  /* @__PURE__ */ jsx(
2016
2214
  "div",
2017
2215
  {
2018
2216
  className: "divide-y divide-white/5 overflow-y-auto",
2019
2217
  style: { height: `${sectionHeight}px`, scrollbarGutter: "stable" },
2020
- children: bids.map((l, idx) => /* @__PURE__ */ jsx(
2218
+ children: isLoading ? Array.from({ length: LEVEL_ROWS_VISIBLE }).map((_, i) => /* @__PURE__ */ jsx(SkeletonRow, {}, `bid-skel-${i}`)) : bids.map((l) => /* @__PURE__ */ jsx(
2021
2219
  DepthRow,
2022
2220
  {
2023
2221
  side: "bid",
@@ -2025,9 +2223,10 @@ function DesktopOrderbookLayout({
2025
2223
  amount: l.amount,
2026
2224
  depthPct: (l.depth ?? l.amount) / maxBidDepth * 100,
2027
2225
  precision,
2028
- amountPrecision
2226
+ amountPrecision,
2227
+ hasUserOrder: userBidPrices.has(l.price)
2029
2228
  },
2030
- `bid-${idx}-${l.price}-${l.amount}`
2229
+ `bid-${l.price}`
2031
2230
  ))
2032
2231
  }
2033
2232
  )
@@ -2053,10 +2252,16 @@ function MobileOrderbookLayout({
2053
2252
  midPrice,
2054
2253
  midChangePercent,
2055
2254
  midClass,
2056
- sectionHeight: _sectionHeight
2255
+ sectionHeight: _sectionHeight,
2256
+ userAskPrices,
2257
+ userBidPrices,
2258
+ isLoading,
2259
+ seenTradeKeysRef
2057
2260
  }) {
2058
- const visibleAsks = React5.useMemo(() => asks.slice(0, COMPACT_ROWS_VISIBLE), [asks]);
2059
- const visibleBids = React5.useMemo(() => bids.slice(0, COMPACT_ROWS_VISIBLE), [bids]);
2261
+ const midRef = React9.useRef(null);
2262
+ useMidPriceFlash(midRef, midPrice, "transparent");
2263
+ const visibleAsks = React9.useMemo(() => asks.slice(0, COMPACT_ROWS_VISIBLE), [asks]);
2264
+ const visibleBids = React9.useMemo(() => bids.slice(0, COMPACT_ROWS_VISIBLE), [bids]);
2060
2265
  return /* @__PURE__ */ jsxs(Fragment, { children: [
2061
2266
  /* @__PURE__ */ jsx("div", { className: "px-3 pt-2", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
2062
2267
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
@@ -2125,7 +2330,7 @@ function MobileOrderbookLayout({
2125
2330
  ]
2126
2331
  }
2127
2332
  ),
2128
- /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column" }, children: visibleAsks.map((l, idx) => /* @__PURE__ */ jsx(
2333
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column" }, children: isLoading ? Array.from({ length: COMPACT_ROWS_VISIBLE }).map((_, i) => /* @__PURE__ */ jsx(SkeletonRow, { compact: true }, `m-ask-skel-${i}`)) : visibleAsks.map((l) => /* @__PURE__ */ jsx(
2129
2334
  MobileDepthRow,
2130
2335
  {
2131
2336
  side: "ask",
@@ -2133,13 +2338,15 @@ function MobileOrderbookLayout({
2133
2338
  amount: l.amount,
2134
2339
  depthPct: (l.depth ?? l.amount) / maxAskDepth * 100,
2135
2340
  precision,
2136
- amountPrecision
2341
+ amountPrecision,
2342
+ hasUserOrder: userAskPrices.has(l.price)
2137
2343
  },
2138
- `mobile-ask-${idx}-${l.price}-${l.amount}`
2344
+ `mobile-ask-${l.price}`
2139
2345
  )) }),
2140
2346
  /* @__PURE__ */ jsxs(
2141
2347
  "div",
2142
2348
  {
2349
+ ref: midRef,
2143
2350
  className: "grid",
2144
2351
  style: {
2145
2352
  gridTemplateColumns: "1.2fr 0.8fr",
@@ -2149,12 +2356,12 @@ function MobileOrderbookLayout({
2149
2356
  borderBottom: "1px solid rgba(255,255,255,0.1)"
2150
2357
  },
2151
2358
  children: [
2152
- /* @__PURE__ */ jsxs(
2359
+ /* @__PURE__ */ jsx(
2153
2360
  "div",
2154
2361
  {
2155
2362
  style: { fontWeight: "bold", display: "flex", alignItems: "center", gap: "8px" },
2156
2363
  className: midClass,
2157
- children: [
2364
+ children: isLoading ? /* @__PURE__ */ jsx(Skeleton, { width: 90, height: 16 }) : /* @__PURE__ */ jsxs(Fragment, { children: [
2158
2365
  "$",
2159
2366
  formatNumber(midPrice, precision),
2160
2367
  midChangePercent != null && /* @__PURE__ */ jsxs("span", { className: cn("text-[0.75rem] font-semibold tabular-nums", midClass), children: [
@@ -2162,14 +2369,14 @@ function MobileOrderbookLayout({
2162
2369
  midChangePercent.toFixed(2),
2163
2370
  "%"
2164
2371
  ] })
2165
- ]
2372
+ ] })
2166
2373
  }
2167
2374
  ),
2168
2375
  /* @__PURE__ */ jsx("div", {})
2169
2376
  ]
2170
2377
  }
2171
2378
  ),
2172
- /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column" }, children: visibleBids.map((l, idx) => /* @__PURE__ */ jsx(
2379
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column" }, children: isLoading ? Array.from({ length: COMPACT_ROWS_VISIBLE }).map((_, i) => /* @__PURE__ */ jsx(SkeletonRow, { compact: true }, `m-bid-skel-${i}`)) : visibleBids.map((l) => /* @__PURE__ */ jsx(
2173
2380
  MobileDepthRow,
2174
2381
  {
2175
2382
  side: "bid",
@@ -2177,9 +2384,10 @@ function MobileOrderbookLayout({
2177
2384
  amount: l.amount,
2178
2385
  depthPct: (l.depth ?? l.amount) / maxBidDepth * 100,
2179
2386
  precision,
2180
- amountPrecision
2387
+ amountPrecision,
2388
+ hasUserOrder: userBidPrices.has(l.price)
2181
2389
  },
2182
- `mobile-bid-${idx}-${l.price}-${l.amount}`
2390
+ `mobile-bid-${l.price}`
2183
2391
  )) })
2184
2392
  ] }) : /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col overflow-hidden px-3 pb-2", children: [
2185
2393
  /* @__PURE__ */ jsxs(
@@ -2193,27 +2401,21 @@ function MobileOrderbookLayout({
2193
2401
  ]
2194
2402
  }
2195
2403
  ),
2196
- /* @__PURE__ */ jsx("div", { style: { flex: 1, overflowY: "auto", minHeight: 0 }, children: tradeFiltered.length === 0 ? /* @__PURE__ */ jsx("div", { className: "py-6 text-center text-[0.7rem] text-white/50", children: "No trades" }) : tradeFiltered.map((trade, i) => /* @__PURE__ */ jsxs(
2197
- "div",
2198
- {
2199
- className: "grid",
2200
- style: { gridTemplateColumns: "1.2fr 0.8fr", padding: "0.2rem 0", fontSize: "0.8rem" },
2201
- children: [
2202
- /* @__PURE__ */ jsxs(
2203
- "div",
2204
- {
2205
- style: { color: trade.type === "buy" ? "#0ecb81" : "#f6465d", fontWeight: 500 },
2206
- children: [
2207
- "$",
2208
- formatNumber(trade.price, precision)
2209
- ]
2210
- }
2211
- ),
2212
- /* @__PURE__ */ jsx("div", { style: { textAlign: "right", paddingRight: "0.5rem" }, children: formatNumber(trade.amount, amountPrecision) })
2213
- ]
2214
- },
2215
- `${trade.type}-${trade.price}-${trade.amount}-${trade.time ?? i}`
2216
- )) })
2404
+ /* @__PURE__ */ jsx("div", { style: { flex: 1, overflowY: "auto", minHeight: 0 }, children: isLoading && tradeFiltered.length === 0 ? Array.from({ length: COMPACT_ROWS_VISIBLE }).map((_, i) => /* @__PURE__ */ jsx(SkeletonRow, { compact: true }, `m-trade-skel-${i}`)) : tradeFiltered.length === 0 ? /* @__PURE__ */ jsx("div", { className: "py-6 text-center text-[0.7rem] text-white/50", children: "No trades" }) : tradeFiltered.map((trade, i) => {
2405
+ const tradeKey = getTradeKey(trade, i);
2406
+ return /* @__PURE__ */ jsx(
2407
+ TradeRow,
2408
+ {
2409
+ trade,
2410
+ tradeKey,
2411
+ precision,
2412
+ amountPrecision,
2413
+ seenTradeKeysRef,
2414
+ compact: true
2415
+ },
2416
+ tradeKey
2417
+ );
2418
+ }) })
2217
2419
  ] })
2218
2420
  ] });
2219
2421
  }
@@ -2223,12 +2425,16 @@ function MobileDepthRow({
2223
2425
  amount,
2224
2426
  depthPct,
2225
2427
  precision,
2226
- amountPrecision
2428
+ amountPrecision,
2429
+ hasUserOrder
2227
2430
  }) {
2228
2431
  const isAsk = side === "ask";
2432
+ const rowRef = React9.useRef(null);
2433
+ useAmountChangeFlash(rowRef, amount);
2229
2434
  return /* @__PURE__ */ jsxs(
2230
2435
  "div",
2231
2436
  {
2437
+ ref: rowRef,
2232
2438
  style: {
2233
2439
  display: "grid",
2234
2440
  gridTemplateColumns: "1.2fr 0.8fr",
@@ -2237,6 +2443,24 @@ function MobileDepthRow({
2237
2443
  position: "relative"
2238
2444
  },
2239
2445
  children: [
2446
+ hasUserOrder ? /* @__PURE__ */ jsx(
2447
+ "span",
2448
+ {
2449
+ "aria-label": "Your order at this price",
2450
+ style: {
2451
+ position: "absolute",
2452
+ left: 0,
2453
+ top: 0,
2454
+ bottom: 0,
2455
+ width: "3px",
2456
+ backgroundColor: "#C9A227",
2457
+ boxShadow: "0 0 6px rgba(201,162,39,0.6)",
2458
+ borderTopRightRadius: "2px",
2459
+ borderBottomRightRadius: "2px",
2460
+ zIndex: 2
2461
+ }
2462
+ }
2463
+ ) : null,
2240
2464
  /* @__PURE__ */ jsxs("div", { style: { position: "relative", zIndex: 1, color: isAsk ? "#f6465d" : "#0ecb81" }, children: [
2241
2465
  "$",
2242
2466
  formatNumber(price, precision)
@@ -2253,7 +2477,8 @@ function MobileDepthRow({
2253
2477
  width: `${clamp3(depthPct, 0, 100)}%`,
2254
2478
  backgroundColor: isAsk ? "#f6465d" : "#0ecb81",
2255
2479
  opacity: 0.1,
2256
- zIndex: 0
2480
+ zIndex: 0,
2481
+ transition: "width 300ms ease-out"
2257
2482
  }
2258
2483
  }
2259
2484
  )
@@ -2261,7 +2486,7 @@ function MobileDepthRow({
2261
2486
  }
2262
2487
  );
2263
2488
  }
2264
- var PropertyTour = React5.forwardRef(
2489
+ var PropertyTour = React9.forwardRef(
2265
2490
  ({
2266
2491
  className,
2267
2492
  title,
@@ -2274,8 +2499,8 @@ var PropertyTour = React5.forwardRef(
2274
2499
  playsInline = true,
2275
2500
  ...props
2276
2501
  }, ref) => {
2277
- const videoRef = React5.useRef(null);
2278
- React5.useEffect(() => {
2502
+ const videoRef = React9.useRef(null);
2503
+ React9.useEffect(() => {
2279
2504
  const video = videoRef.current;
2280
2505
  if (!video) return;
2281
2506
  const handleFullscreenChange = () => {
@@ -2407,7 +2632,7 @@ var formatTimeAgo = (timestamp) => {
2407
2632
  if (diff < 3600) return `${Math.floor(diff / 60)}m ago`;
2408
2633
  return `${Math.floor(diff / 3600)}h ago`;
2409
2634
  };
2410
- var PropertyNewsUpdates = React5.forwardRef(
2635
+ var PropertyNewsUpdates = React9.forwardRef(
2411
2636
  ({
2412
2637
  className,
2413
2638
  heading,
@@ -2424,15 +2649,15 @@ var PropertyNewsUpdates = React5.forwardRef(
2424
2649
  const isPurchaseVariant = variant === "purchases";
2425
2650
  const isHomeVariant = variant === "home";
2426
2651
  const resolvedHeading = heading ?? (isPurchaseVariant ? "Live Purchases" : "Property News & Headlines");
2427
- const [homeTab, setHomeTab] = React5.useState("all");
2652
+ const [homeTab, setHomeTab] = React9.useState("all");
2428
2653
  const purchaseItems = purchasesProp ?? [];
2429
- const [page, setPage] = React5.useState(0);
2430
- React5.useEffect(() => {
2654
+ const [page, setPage] = React9.useState(0);
2655
+ React9.useEffect(() => {
2431
2656
  ensureAnimationsInjected();
2432
2657
  }, []);
2433
2658
  const hasItems = Array.isArray(items) && items.length > 0;
2434
- const totalPages = React5.useMemo(() => hasItems ? Math.max(1, Math.ceil(items.length / ITEMS_PER_PAGE)) : 1, [hasItems, items.length]);
2435
- React5.useEffect(() => {
2659
+ const totalPages = React9.useMemo(() => hasItems ? Math.max(1, Math.ceil(items.length / ITEMS_PER_PAGE)) : 1, [hasItems, items.length]);
2660
+ React9.useEffect(() => {
2436
2661
  setPage((prev) => Math.min(prev, totalPages - 1));
2437
2662
  }, [totalPages]);
2438
2663
  const paginatedItems = hasItems ? items.slice(page * ITEMS_PER_PAGE, page * ITEMS_PER_PAGE + ITEMS_PER_PAGE) : [];
@@ -2740,7 +2965,7 @@ var defaultFormat = (value) => new Intl.NumberFormat("en-US", {
2740
2965
  notation: value >= 1e5 ? "compact" : "standard",
2741
2966
  maximumFractionDigits: value >= 1e3 ? 0 : 2
2742
2967
  }).format(value);
2743
- var TradingSlider = React5.forwardRef(
2968
+ var TradingSlider = React9.forwardRef(
2744
2969
  ({
2745
2970
  label = "Trade size",
2746
2971
  helperText = "Drag to pick the desired notional.",
@@ -2758,7 +2983,7 @@ var TradingSlider = React5.forwardRef(
2758
2983
  ...rest
2759
2984
  }, ref) => {
2760
2985
  const isControlled = value !== void 0;
2761
- const [internalValue, setInternalValue] = React5.useState(
2986
+ const [internalValue, setInternalValue] = React9.useState(
2762
2987
  defaultValue ?? (typeof min === "number" ? min : 0)
2763
2988
  );
2764
2989
  const currentValue = isControlled ? Number(value) : internalValue;
@@ -2861,7 +3086,7 @@ var MobileToggleButton = styled24.button`
2861
3086
  padding: 0.6rem 0.5rem;
2862
3087
  }
2863
3088
  `;
2864
- var MobileTradeNav = React5.forwardRef(
3089
+ var MobileTradeNav = React9.forwardRef(
2865
3090
  ({ className, items, activeId, onChange, ...props }, ref) => {
2866
3091
  return /* @__PURE__ */ jsx(MobileToggleContainer, { ref, className: cn(className), ...props, children: items.map((item) => /* @__PURE__ */ jsxs(
2867
3092
  MobileToggleButton,
@@ -3512,7 +3737,7 @@ var formatPercent = (value, fractionDigits = 2) => {
3512
3737
  if (value == null || Number.isNaN(value)) return "\u2014";
3513
3738
  return `${value.toFixed(fractionDigits)}%`;
3514
3739
  };
3515
- var YourOrders = React5.forwardRef(
3740
+ var YourOrders = React9.forwardRef(
3516
3741
  ({
3517
3742
  className,
3518
3743
  title,
@@ -3525,10 +3750,10 @@ var YourOrders = React5.forwardRef(
3525
3750
  pageSize: pageSizeOverride,
3526
3751
  ...props
3527
3752
  }, ref) => {
3528
- const [internalActiveTab, setInternalActiveTab] = React5.useState(tabs?.[0]?.id ?? "portfolio");
3529
- const [page, setPage] = React5.useState(0);
3753
+ const [internalActiveTab, setInternalActiveTab] = React9.useState(tabs?.[0]?.id ?? "portfolio");
3754
+ const [page, setPage] = React9.useState(0);
3530
3755
  const effectiveActiveTabId = activeTabId ?? internalActiveTab;
3531
- React5.useEffect(() => {
3756
+ React9.useEffect(() => {
3532
3757
  setPage(0);
3533
3758
  }, [effectiveActiveTabId]);
3534
3759
  const handleTabChange = (tabId) => {
@@ -3910,7 +4135,7 @@ function createCandlestickSeries(chart, options) {
3910
4135
  }
3911
4136
  throw new Error("Candlestick series API is not available in the current lightweight-charts version.");
3912
4137
  }
3913
- var PriceChart = React5.forwardRef(
4138
+ var PriceChart = React9.forwardRef(
3914
4139
  ({
3915
4140
  className,
3916
4141
  title = "Price Chart",
@@ -3924,18 +4149,18 @@ var PriceChart = React5.forwardRef(
3924
4149
  height = 301.52,
3925
4150
  ...props
3926
4151
  }, ref) => {
3927
- const containerRef = React5.useRef(null);
3928
- const chartRef = React5.useRef(null);
3929
- const seriesRef = React5.useRef(null);
3930
- const priceLineRef = React5.useRef(null);
3931
- const [hoveredRange, setHoveredRange] = React5.useState(null);
3932
- const [dropdownOpen, setDropdownOpen] = React5.useState(false);
3933
- const dropdownRef = React5.useRef(null);
3934
- const isAutoScrollRef = React5.useRef(true);
4152
+ const containerRef = React9.useRef(null);
4153
+ const chartRef = React9.useRef(null);
4154
+ const seriesRef = React9.useRef(null);
4155
+ const priceLineRef = React9.useRef(null);
4156
+ const [hoveredRange, setHoveredRange] = React9.useState(null);
4157
+ const [dropdownOpen, setDropdownOpen] = React9.useState(false);
4158
+ const dropdownRef = React9.useRef(null);
4159
+ const isAutoScrollRef = React9.useRef(true);
3935
4160
  const visibleRanges = ranges.slice(0, VISIBLE_RANGE_COUNT);
3936
4161
  const dropdownRanges = ranges.slice(VISIBLE_RANGE_COUNT);
3937
4162
  const selectedInDropdown = dropdownRanges.includes(selectedRange);
3938
- React5.useEffect(() => {
4163
+ React9.useEffect(() => {
3939
4164
  const handleClickOutside = (e) => {
3940
4165
  if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
3941
4166
  setDropdownOpen(false);
@@ -3944,25 +4169,25 @@ var PriceChart = React5.forwardRef(
3944
4169
  document.addEventListener("mousedown", handleClickOutside);
3945
4170
  return () => document.removeEventListener("mousedown", handleClickOutside);
3946
4171
  }, []);
3947
- const resolvedPrice = React5.useMemo(() => {
4172
+ const resolvedPrice = React9.useMemo(() => {
3948
4173
  if (price != null) return price;
3949
4174
  const last = data.at(-1);
3950
4175
  return last?.close;
3951
4176
  }, [data, price]);
3952
- const inferredChangePercent = React5.useMemo(() => {
4177
+ const inferredChangePercent = React9.useMemo(() => {
3953
4178
  if (changePercent != null) return changePercent;
3954
4179
  const first = data[0]?.open;
3955
4180
  const last = data.at(-1)?.close;
3956
4181
  if (first == null || last == null || first === 0) return void 0;
3957
4182
  return (last - first) / first * 100;
3958
4183
  }, [changePercent, data]);
3959
- const dollarChange = React5.useMemo(() => {
4184
+ const dollarChange = React9.useMemo(() => {
3960
4185
  const first = data[0]?.open;
3961
4186
  const last = data.at(-1)?.close;
3962
4187
  if (first == null || last == null) return void 0;
3963
4188
  return last - first;
3964
4189
  }, [data]);
3965
- React5.useEffect(() => {
4190
+ React9.useEffect(() => {
3966
4191
  const el = containerRef.current;
3967
4192
  if (!el) return;
3968
4193
  const chart = LightweightCharts.createChart(el, {
@@ -4007,7 +4232,7 @@ var PriceChart = React5.forwardRef(
4007
4232
  chart.remove();
4008
4233
  };
4009
4234
  }, []);
4010
- React5.useEffect(() => {
4235
+ React9.useEffect(() => {
4011
4236
  const chart = chartRef.current;
4012
4237
  if (!chart) return;
4013
4238
  const effectiveRange = selectedRange ?? ranges?.[0] ?? "1D";
@@ -4015,7 +4240,7 @@ var PriceChart = React5.forwardRef(
4015
4240
  timeScale: getTimeScaleOptions(effectiveRange)
4016
4241
  });
4017
4242
  }, [selectedRange, ranges]);
4018
- React5.useEffect(() => {
4243
+ React9.useEffect(() => {
4019
4244
  const chart = chartRef.current;
4020
4245
  const series = seriesRef.current;
4021
4246
  if (!chart || !series) return;
@@ -4220,7 +4445,7 @@ var formatPrice3 = (value, currencySymbol) => {
4220
4445
  maximumFractionDigits: 3
4221
4446
  })}`;
4222
4447
  };
4223
- var PropertyHeroHeader = React5.forwardRef(
4448
+ var PropertyHeroHeader = React9.forwardRef(
4224
4449
  ({
4225
4450
  className,
4226
4451
  imageUrl,
@@ -4241,14 +4466,15 @@ var PropertyHeroHeader = React5.forwardRef(
4241
4466
  makeOfferDisabled = false,
4242
4467
  hideMakeOfferButton = false,
4243
4468
  statusBadge,
4469
+ isLoading = false,
4244
4470
  ...props
4245
4471
  }, ref) => {
4246
4472
  const isPositive = changePercent == null ? void 0 : changePercent >= 0;
4247
4473
  const accentColor = "#e6c87e";
4248
4474
  const tradeHoverColor = "#f5dd9a";
4249
- const [isTradeInteracting, setIsTradeInteracting] = React5.useState(false);
4250
- const [isOfferInteracting, setIsOfferInteracting] = React5.useState(false);
4251
- const hasAmenities = beds != null || baths != null || cars != null || propertyTypeLabel != null;
4475
+ const [isTradeInteracting, setIsTradeInteracting] = React9.useState(false);
4476
+ const [isOfferInteracting, setIsOfferInteracting] = React9.useState(false);
4477
+ const hasAmenities = isLoading || beds != null || baths != null || cars != null || propertyTypeLabel != null;
4252
4478
  const isTradeDisabled = !onTrade;
4253
4479
  const isMakeOfferButtonDisabled = makeOfferDisabled || !onMakeOffer;
4254
4480
  const showMakeOfferButton = !hideMakeOfferButton;
@@ -4288,7 +4514,7 @@ var PropertyHeroHeader = React5.forwardRef(
4288
4514
  /* @__PURE__ */ jsx("h1", { style: headingStyle, className: "break-words", children: name }),
4289
4515
  /* @__PURE__ */ jsxs(InfoRow, { className: "mb-3 max-[768px]:mb-[0.6rem] max-[480px]:mb-[0.5rem]", children: [
4290
4516
  /* @__PURE__ */ jsx(LocationText, { children: location }),
4291
- price == null ? null : /* @__PURE__ */ jsxs(PriceBlock, { children: [
4517
+ isLoading ? /* @__PURE__ */ jsx(PriceBlock, { children: /* @__PURE__ */ jsx(Skeleton, { width: 110, height: 18 }) }) : price == null ? null : /* @__PURE__ */ jsxs(PriceBlock, { children: [
4292
4518
  formatPrice3(price, currencySymbol),
4293
4519
  changePercent == null ? null : /* @__PURE__ */ jsxs(
4294
4520
  "span",
@@ -4318,7 +4544,21 @@ var PropertyHeroHeader = React5.forwardRef(
4318
4544
  ] })
4319
4545
  ] })
4320
4546
  ] }),
4321
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-6 text-[0.95rem] text-white/90 max-[768px]:hidden", children: [
4547
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-6 text-[0.95rem] text-white/90 max-[768px]:hidden", children: isLoading ? /* @__PURE__ */ jsxs(Fragment, { children: [
4548
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
4549
+ /* @__PURE__ */ jsx(BedDouble, { className: "mr-2 h-[18px] w-[18px] opacity-60" }),
4550
+ /* @__PURE__ */ jsx(Skeleton, { width: 52, height: 14 })
4551
+ ] }),
4552
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
4553
+ /* @__PURE__ */ jsx(Bath, { className: "mr-2 h-[18px] w-[18px] opacity-60" }),
4554
+ /* @__PURE__ */ jsx(Skeleton, { width: 56, height: 14 })
4555
+ ] }),
4556
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
4557
+ /* @__PURE__ */ jsx(CarFront, { className: "mr-2 h-[18px] w-[18px] opacity-60" }),
4558
+ /* @__PURE__ */ jsx(Skeleton, { width: 50, height: 14 })
4559
+ ] }),
4560
+ /* @__PURE__ */ jsx(Skeleton, { width: 60, height: 14 })
4561
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
4322
4562
  beds == null ? null : /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
4323
4563
  /* @__PURE__ */ jsx(BedDouble, { className: "mr-2 h-[18px] w-[18px]" }),
4324
4564
  /* @__PURE__ */ jsxs("span", { children: [
@@ -4341,7 +4581,7 @@ var PropertyHeroHeader = React5.forwardRef(
4341
4581
  ] })
4342
4582
  ] }),
4343
4583
  propertyTypeLabel == null ? null : /* @__PURE__ */ jsx("div", { children: propertyTypeLabel })
4344
- ] })
4584
+ ] }) })
4345
4585
  ] }),
4346
4586
  /* @__PURE__ */ jsxs(ActionButtons, { children: [
4347
4587
  /* @__PURE__ */ jsx(
@@ -4403,7 +4643,21 @@ var PropertyHeroHeader = React5.forwardRef(
4403
4643
  ] })
4404
4644
  ] }) })
4405
4645
  ] }),
4406
- hasAmenities ? /* @__PURE__ */ jsxs(MobileAmenities, { children: [
4646
+ hasAmenities ? /* @__PURE__ */ jsx(MobileAmenities, { children: isLoading ? /* @__PURE__ */ jsxs(Fragment, { children: [
4647
+ /* @__PURE__ */ jsxs(MobileAmenity, { children: [
4648
+ /* @__PURE__ */ jsx(BedDouble, { className: "h-4 w-4 opacity-60" }),
4649
+ /* @__PURE__ */ jsx(Skeleton, { width: 40, height: 12 })
4650
+ ] }),
4651
+ /* @__PURE__ */ jsxs(MobileAmenity, { children: [
4652
+ /* @__PURE__ */ jsx(Bath, { className: "h-4 w-4 opacity-60" }),
4653
+ /* @__PURE__ */ jsx(Skeleton, { width: 44, height: 12 })
4654
+ ] }),
4655
+ /* @__PURE__ */ jsxs(MobileAmenity, { children: [
4656
+ /* @__PURE__ */ jsx(CarFront, { className: "h-4 w-4 opacity-60" }),
4657
+ /* @__PURE__ */ jsx(Skeleton, { width: 42, height: 12 })
4658
+ ] }),
4659
+ /* @__PURE__ */ jsx(MobileAmenity, { children: /* @__PURE__ */ jsx(Skeleton, { width: 52, height: 12 }) })
4660
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
4407
4661
  beds == null ? null : /* @__PURE__ */ jsxs(MobileAmenity, { children: [
4408
4662
  /* @__PURE__ */ jsx(BedDouble, { className: "h-4 w-4" }),
4409
4663
  /* @__PURE__ */ jsxs("span", { children: [
@@ -4426,7 +4680,7 @@ var PropertyHeroHeader = React5.forwardRef(
4426
4680
  ] })
4427
4681
  ] }),
4428
4682
  propertyTypeLabel == null ? null : /* @__PURE__ */ jsx(MobileAmenity, { children: propertyTypeLabel })
4429
- ] }) : null
4683
+ ] }) }) : null
4430
4684
  ] });
4431
4685
  }
4432
4686
  );
@@ -4668,6 +4922,15 @@ var Header = ({
4668
4922
  const [isMoreMenuOpen, setIsMoreMenuOpen] = useState(false);
4669
4923
  const [showLoginPopup, setShowLoginPopup] = useState(false);
4670
4924
  const [loginPopupInitialView, setLoginPopupInitialView] = useState(void 0);
4925
+ useEffect(() => {
4926
+ if (typeof window === "undefined") return;
4927
+ const ua = navigator.userAgent;
4928
+ const isTelegram = /Telegram/i.test(ua);
4929
+ const isIOS = /iPhone|iPad|iPod/.test(ua);
4930
+ if (isTelegram && isIOS) {
4931
+ document.documentElement.style.setProperty("--telegram-safe-top", "59px");
4932
+ }
4933
+ }, []);
4671
4934
  useEffect(() => {
4672
4935
  const handleClickOutside = (event) => {
4673
4936
  const target = event.target;
@@ -4818,7 +5081,7 @@ var Header = ({
4818
5081
  setShowLoginPopup(true);
4819
5082
  }
4820
5083
  };
4821
- const handleLoginPopupClose = React5__default.useCallback(() => {
5084
+ const handleLoginPopupClose = React9__default.useCallback(() => {
4822
5085
  setShowLoginPopup(false);
4823
5086
  setLoginPopupInitialView(void 0);
4824
5087
  }, []);
@@ -5106,8 +5369,8 @@ var SafeAreaCover = styled24.div`
5106
5369
  top: 0;
5107
5370
  left: 0;
5108
5371
  right: 0;
5109
- height: env(safe-area-inset-top, 0px);
5110
- min-height: env(safe-area-inset-top, 0px);
5372
+ height: max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px));
5373
+ min-height: max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px));
5111
5374
  background-color: #0d1117;
5112
5375
  z-index: 1001;
5113
5376
  pointer-events: none;
@@ -5161,7 +5424,7 @@ var HeaderContainer = styled24.header`
5161
5424
  /* Split padding so browsers that don't support env() inside shorthand
5162
5425
  still get the horizontal padding — only the top falls back to 0 */
5163
5426
  padding: 0 2rem;
5164
- padding-top: env(safe-area-inset-top, 0px);
5427
+ padding-top: max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px));
5165
5428
  background-color: #0d1117;
5166
5429
  border-bottom: 1px solid #232a32;
5167
5430
  position: fixed;
@@ -5172,18 +5435,18 @@ var HeaderContainer = styled24.header`
5172
5435
  width: 100%;
5173
5436
  /* Fallback min-height for browsers that can't evaluate calc+env */
5174
5437
  min-height: 56px;
5175
- min-height: calc(56px + env(safe-area-inset-top, 0px));
5438
+ min-height: calc(56px + max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px)));
5176
5439
  box-sizing: border-box;
5177
5440
 
5178
5441
  @media (max-width: 768px) {
5179
5442
  padding: 0 1rem;
5180
- padding-top: env(safe-area-inset-top, 0px);
5443
+ padding-top: max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px));
5181
5444
  }
5182
5445
  `;
5183
5446
  var HeaderSpacer = styled24.div`
5184
5447
  width: 100%;
5185
5448
  min-height: 56px;
5186
- min-height: calc(56px + env(safe-area-inset-top, 0px));
5449
+ min-height: calc(56px + max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px)));
5187
5450
  flex-shrink: 0;
5188
5451
  `;
5189
5452
  var Logo = styled24.div`
@@ -5238,12 +5501,12 @@ var Nav = styled24.nav`
5238
5501
  @media (max-width: 1300px) {
5239
5502
  position: fixed;
5240
5503
  top: 56px;
5241
- top: calc(56px + env(safe-area-inset-top, 0px));
5504
+ top: calc(56px + max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px)));
5242
5505
  right: ${(props) => props.$isOpen ? "0" : "-100%"} ;
5243
5506
  width: 280px;
5244
5507
  max-width: 280px;
5245
5508
  height: calc(100vh - 56px);
5246
- height: calc(100vh - 56px - env(safe-area-inset-top, 0px));
5509
+ height: calc(100vh - 56px - max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px)));
5247
5510
  background: linear-gradient(180deg, #0f1419 0%, #0a0e13 100%);
5248
5511
  z-index: 1000;
5249
5512
  transition: right 0.3s ease;
@@ -5516,10 +5779,10 @@ var MobileNavItem = styled24.div`
5516
5779
  padding-left: 24px;
5517
5780
  }
5518
5781
  `;
5519
- var PropertySubheader = React5.forwardRef(
5782
+ var PropertySubheader = React9.forwardRef(
5520
5783
  ({ className, tabs, activeTabId, onTabChange, actions, ...props }, ref) => {
5521
- const tabsContainerRef = React5.useRef(null);
5522
- React5.useEffect(() => {
5784
+ const tabsContainerRef = React9.useRef(null);
5785
+ React9.useEffect(() => {
5523
5786
  const container = tabsContainerRef.current;
5524
5787
  if (!container) return;
5525
5788
  const isMobile = window.innerWidth <= 768;
@@ -5675,7 +5938,7 @@ var LoginPopup = ({
5675
5938
  const [fiatFundingLoading, setFiatFundingLoading] = useState(false);
5676
5939
  const [fundingError, setFundingError] = useState("");
5677
5940
  const [transakWidgetUrl, setTransakWidgetUrl] = useState(null);
5678
- const suppressAutoCloseRef = React5__default.useRef(false);
5941
+ const suppressAutoCloseRef = React9__default.useRef(false);
5679
5942
  useEffect(() => {
5680
5943
  if (typeof initialView === "string") {
5681
5944
  setView(initialView);
@@ -6855,7 +7118,7 @@ var MiniLiveFeed = () => {
6855
7118
  );
6856
7119
  };
6857
7120
  LoginPopup.displayName = "LoginPopup";
6858
- var PropertyCompareBar = React5.forwardRef(
7121
+ var PropertyCompareBar = React9.forwardRef(
6859
7122
  ({
6860
7123
  className,
6861
7124
  addresses,
@@ -6866,7 +7129,7 @@ var PropertyCompareBar = React5.forwardRef(
6866
7129
  price,
6867
7130
  ...props
6868
7131
  }, ref) => {
6869
- const normalizedAddresses = React5.useMemo(() => {
7132
+ const normalizedAddresses = React9.useMemo(() => {
6870
7133
  return addresses.map(
6871
7134
  (option) => typeof option === "string" ? { id: option, label: option } : option
6872
7135
  );
@@ -6874,11 +7137,11 @@ var PropertyCompareBar = React5.forwardRef(
6874
7137
  const hasAddresses = normalizedAddresses.length > 0;
6875
7138
  const firstAddressId = normalizedAddresses[0]?.id;
6876
7139
  const isControlled = selectedAddressId !== void 0;
6877
- const [internalSelectedId, setInternalSelectedId] = React5.useState(
7140
+ const [internalSelectedId, setInternalSelectedId] = React9.useState(
6878
7141
  () => isControlled ? void 0 : firstAddressId
6879
7142
  );
6880
7143
  const resolvedSelectedId = isControlled ? selectedAddressId : internalSelectedId;
6881
- React5.useEffect(() => {
7144
+ React9.useEffect(() => {
6882
7145
  if (!isControlled) {
6883
7146
  setInternalSelectedId((current) => {
6884
7147
  if (current != null && normalizedAddresses.some((option) => option.id === current)) {
@@ -6889,9 +7152,9 @@ var PropertyCompareBar = React5.forwardRef(
6889
7152
  }
6890
7153
  }, [firstAddressId, isControlled, normalizedAddresses]);
6891
7154
  const selectedOption = normalizedAddresses.find((option) => option.id === resolvedSelectedId) ?? normalizedAddresses[0];
6892
- const [isDropdownOpen, setIsDropdownOpen] = React5.useState(false);
6893
- const dropdownRef = React5.useRef(null);
6894
- React5.useEffect(() => {
7155
+ const [isDropdownOpen, setIsDropdownOpen] = React9.useState(false);
7156
+ const dropdownRef = React9.useRef(null);
7157
+ React9.useEffect(() => {
6895
7158
  if (!isDropdownOpen) return;
6896
7159
  const handleClick = (event) => {
6897
7160
  if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
@@ -7614,7 +7877,8 @@ function PropertyOverview({
7614
7877
  bathrooms,
7615
7878
  carSpaces,
7616
7879
  propertyTypeLabel,
7617
- tokensIssued: tokensIssuedProp
7880
+ tokensIssued: tokensIssuedProp,
7881
+ isLoading = false
7618
7882
  }) {
7619
7883
  const [isDescExpanded, setDescExpanded] = useState(false);
7620
7884
  const description = descriptionProp ?? overviewData?.description ?? DEFAULT_DESCRIPTION;
@@ -7652,13 +7916,14 @@ function PropertyOverview({
7652
7916
  const weeklyRent = overviewData?.weeklyRent ?? 0;
7653
7917
  const annualRent = weeklyRent * 52;
7654
7918
  const dividendYield = resolvedValuation && annualRent > 0 ? (annualRent / resolvedValuation * 100).toFixed(2) : null;
7919
+ const loadingSkeleton = /* @__PURE__ */ jsx(Skeleton, { width: 90, height: 18 });
7655
7920
  const financialItems = financialItemsProp ?? [
7656
- { label: "Token Price", value: tokenPriceValue ? `$${tokenPriceValue.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}` : "N/A", gold: true },
7657
- { label: "Property Value", value: resolvedValuation ? resolvedValuation >= 1e6 ? `$${(resolvedValuation / 1e6).toFixed(2)}M` : `$${resolvedValuation.toLocaleString()}` : "N/A" },
7658
- { label: "Weekly Rent", value: weeklyRent > 0 ? `$${weeklyRent.toLocaleString()}/wk` : "N/A", badge: weeklyRent > 0 ? "Rented" : void 0 },
7659
- { label: "Dividend Yield", value: dividendYield ? `${dividendYield}%` : "N/A" },
7660
- { label: "Total Tokens", value: resolvedTokensIssued ? resolvedTokensIssued.toLocaleString() : "N/A" },
7661
- { label: "Indicative Listing", value: overviewData?.indicativeListing ?? "N/A" }
7921
+ { label: "Token Price", value: isLoading && tokenPriceValue == null ? loadingSkeleton : tokenPriceValue ? `$${tokenPriceValue.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}` : "N/A", gold: true },
7922
+ { label: "Property Value", value: isLoading && resolvedValuation == null ? loadingSkeleton : resolvedValuation ? resolvedValuation >= 1e6 ? `$${(resolvedValuation / 1e6).toFixed(2)}M` : `$${resolvedValuation.toLocaleString()}` : "N/A" },
7923
+ { label: "Weekly Rent", value: isLoading && !overviewData ? loadingSkeleton : weeklyRent > 0 ? `$${weeklyRent.toLocaleString()}/wk` : "N/A", badge: weeklyRent > 0 ? "Rented" : void 0 },
7924
+ { label: "Dividend Yield", value: isLoading && dividendYield == null && resolvedValuation == null ? loadingSkeleton : dividendYield ? `${dividendYield}%` : "N/A" },
7925
+ { label: "Total Tokens", value: isLoading && resolvedTokensIssued == null ? loadingSkeleton : resolvedTokensIssued ? resolvedTokensIssued.toLocaleString() : "N/A" },
7926
+ { label: "Indicative Listing", value: isLoading && !overviewData ? loadingSkeleton : overviewData?.indicativeListing ?? "N/A" }
7662
7927
  ];
7663
7928
  const galleryImages = images ?? [];
7664
7929
  return /* @__PURE__ */ jsxs("div", { children: [
@@ -9502,6 +9767,8 @@ var formatTimeAgo2 = (timestamp) => {
9502
9767
  };
9503
9768
  function VideoActivitySection({
9504
9769
  ipoStarted,
9770
+ ipoEnded = false,
9771
+ isLoading = false,
9505
9772
  recentOrders = [],
9506
9773
  ordersAllocated = 0,
9507
9774
  tokenPrice = 0
@@ -9510,6 +9777,9 @@ function VideoActivitySection({
9510
9777
  () => [...recentOrders].sort((a, b) => b.timestamp - a.timestamp).slice(0, 7),
9511
9778
  [recentOrders]
9512
9779
  );
9780
+ const headerStatusText = ipoEnded ? `Sale ended${ordersAllocated > 0 ? ` \xB7 ${ordersAllocated.toLocaleString()} orders` : ""}` : ipoStarted ? isLoading && sortedOrders.length === 0 ? "Loading orders\u2026" : `Active orders: ${ordersAllocated.toLocaleString()}` : "Waiting for Offer to Open";
9781
+ const showSkeletonFeed = ipoStarted && isLoading && sortedOrders.length === 0;
9782
+ const showOrderFeed = !showSkeletonFeed && (ipoStarted || ipoEnded && sortedOrders.length > 0);
9513
9783
  return /* @__PURE__ */ jsxs(Section3, { children: [
9514
9784
  /* @__PURE__ */ jsxs(VideoPanel, { children: [
9515
9785
  /* @__PURE__ */ jsx("div", { className: "section-header", children: /* @__PURE__ */ jsx("h3", { children: "Musgrave" }) }),
@@ -9521,31 +9791,40 @@ function VideoActivitySection({
9521
9791
  /* @__PURE__ */ jsxs(ActivityPanel, { children: [
9522
9792
  /* @__PURE__ */ jsxs("div", { className: "section-header", children: [
9523
9793
  /* @__PURE__ */ jsxs("h3", { children: [
9524
- /* @__PURE__ */ jsx(LiveIndicatorDot, { $active: ipoStarted }),
9794
+ /* @__PURE__ */ jsx(LiveIndicatorDot, { $active: ipoStarted && !ipoEnded }),
9525
9795
  "Recent Order Activity"
9526
9796
  ] }),
9527
- /* @__PURE__ */ jsx("span", { children: ipoStarted ? `Active orders: ${ordersAllocated.toLocaleString()}` : "Waiting for Offer to Open" })
9797
+ /* @__PURE__ */ jsx("span", { children: headerStatusText })
9528
9798
  ] }),
9529
- /* @__PURE__ */ jsx("div", { className: "activity-content", children: ipoStarted ? /* @__PURE__ */ jsx(FeedList, { children: sortedOrders.map((order, index) => {
9530
- const amount = tokenPrice * order.quantity;
9531
- const barPercent = Math.min(85, Math.max(15, amount / MAX_DISPLAY_AMOUNT * 100));
9532
- const isAlternate = index % 2 === 1;
9533
- return /* @__PURE__ */ jsxs(
9534
- PurchaseItem,
9535
- {
9536
- $barWidth: `${barPercent}%`,
9537
- $isAlternate: isAlternate,
9538
- children: [
9539
- /* @__PURE__ */ jsxs(PurchaseInfo, { children: [
9540
- /* @__PURE__ */ jsx(PurchaseName, { children: order.buyerHandle || `${order.buyerAddress.slice(0, 6)}...${order.buyerAddress.slice(-4)}` }),
9541
- /* @__PURE__ */ jsx(PurchaseTime, { children: formatTimeAgo2(order.timestamp) })
9542
- ] }),
9543
- /* @__PURE__ */ jsx(PurchaseAmount, { children: formatCurrency4(amount) })
9544
- ]
9545
- },
9546
- order.txHash
9547
- );
9548
- }) }) : /* @__PURE__ */ jsxs("div", { className: "activity-empty", children: [
9799
+ /* @__PURE__ */ jsx("div", { className: "activity-content", children: showSkeletonFeed ? /* @__PURE__ */ jsx(FeedList, { children: Array.from({ length: 6 }).map((_, i) => /* @__PURE__ */ jsxs(SkeletonFeedRow, { children: [
9800
+ /* @__PURE__ */ jsxs("div", { className: "info-col", children: [
9801
+ /* @__PURE__ */ jsx(Skeleton, { width: 110, height: 14 }),
9802
+ /* @__PURE__ */ jsx(Skeleton, { width: 56, height: 10 })
9803
+ ] }),
9804
+ /* @__PURE__ */ jsx(Skeleton, { width: 70, height: 14 })
9805
+ ] }, `feed-skel-${i}`)) }) : showOrderFeed ? /* @__PURE__ */ jsxs(Fragment, { children: [
9806
+ ipoEnded && /* @__PURE__ */ jsx(EndedBanner, { children: "Sale ended \u2014 final allocations" }),
9807
+ /* @__PURE__ */ jsx(FeedList, { children: sortedOrders.map((order, index) => {
9808
+ const amount = tokenPrice * order.quantity;
9809
+ const barPercent = Math.min(85, Math.max(15, amount / MAX_DISPLAY_AMOUNT * 100));
9810
+ const isAlternate = index % 2 === 1;
9811
+ return /* @__PURE__ */ jsxs(
9812
+ PurchaseItem,
9813
+ {
9814
+ $barWidth: `${barPercent}%`,
9815
+ $isAlternate: isAlternate,
9816
+ children: [
9817
+ /* @__PURE__ */ jsxs(PurchaseInfo, { children: [
9818
+ /* @__PURE__ */ jsx(PurchaseName, { children: order.buyerHandle || `${order.buyerAddress.slice(0, 6)}...${order.buyerAddress.slice(-4)}` }),
9819
+ /* @__PURE__ */ jsx(PurchaseTime, { children: formatTimeAgo2(order.timestamp) })
9820
+ ] }),
9821
+ /* @__PURE__ */ jsx(PurchaseAmount, { children: formatCurrency4(amount) })
9822
+ ]
9823
+ },
9824
+ order.txHash
9825
+ );
9826
+ }) })
9827
+ ] }) : ipoEnded ? /* @__PURE__ */ jsx("div", { className: "activity-empty", children: /* @__PURE__ */ jsx("p", { children: "Sale ended \u2014 no orders were placed." }) }) : /* @__PURE__ */ jsxs("div", { className: "activity-empty", children: [
9549
9828
  /* @__PURE__ */ jsx("div", { className: "spinner" }),
9550
9829
  /* @__PURE__ */ jsx("p", { children: "Activity will appear once the Offering opens" })
9551
9830
  ] }) })
@@ -9686,6 +9965,43 @@ var ActivityPanel = styled24.div`
9686
9965
  to { transform: rotate(360deg); }
9687
9966
  }
9688
9967
  `;
9968
+ var SkeletonFeedRow = styled24.div`
9969
+ padding: 0.625rem 0.75rem;
9970
+ border-bottom: 1px solid rgba(255,255,255,0.04);
9971
+ display: flex;
9972
+ justify-content: space-between;
9973
+ align-items: center;
9974
+ gap: 1rem;
9975
+
9976
+ &:last-child {
9977
+ border-bottom: none;
9978
+ }
9979
+
9980
+ .info-col {
9981
+ display: flex;
9982
+ flex-direction: column;
9983
+ gap: 0.3rem;
9984
+ min-width: 0;
9985
+ flex: 1;
9986
+ }
9987
+
9988
+ @media (max-width: 768px) {
9989
+ padding: 0.4rem 0.6rem;
9990
+ }
9991
+ `;
9992
+ var EndedBanner = styled24.div`
9993
+ font-size: 0.7rem;
9994
+ font-weight: 600;
9995
+ letter-spacing: 0.04em;
9996
+ text-transform: uppercase;
9997
+ color: rgba(255, 255, 255, 0.55);
9998
+ background: rgba(255, 255, 255, 0.04);
9999
+ border: 1px solid rgba(255, 255, 255, 0.08);
10000
+ border-radius: 6px;
10001
+ padding: 0.4rem 0.6rem;
10002
+ margin-bottom: 0.5rem;
10003
+ text-align: center;
10004
+ `;
9689
10005
  var FeedList = styled24.div`
9690
10006
  width: 100%;
9691
10007
  overflow-y: auto;
@@ -10672,6 +10988,22 @@ function PortfolioActivityPanel({
10672
10988
  return 0;
10673
10989
  }
10674
10990
  }, [activeTab, positions.length, offeringOrders.length, openOrders.length, orderHistory.length, tradeHistory.length, transfers.length]);
10991
+ const positionsCount = positions.length;
10992
+ const openOrdersCount = useMemo(
10993
+ () => openOrders.filter((o) => o.status === "OPEN" || o.status === "PARTIALLY_FILLED").length,
10994
+ [openOrders]
10995
+ );
10996
+ const pendingHistoryCount = useMemo(
10997
+ () => orderHistory.filter((o) => o.status === "OPEN" || o.status === "PARTIALLY_FILLED").length,
10998
+ [orderHistory]
10999
+ );
11000
+ const pendingOfferingsCount = useMemo(
11001
+ () => offeringOrders.filter((o) => {
11002
+ const s = o.status.toUpperCase();
11003
+ return s !== "FILLED" && s !== "ALLOCATED" && s !== "CONFIRMED" && s !== "CANCELLED" && s !== "CANCELED" && s !== "REJECTED";
11004
+ }).length,
11005
+ [offeringOrders]
11006
+ );
10675
11007
  const activityTotalPages = Math.ceil(activeTabTotal / pageSize);
10676
11008
  const pageSlice = (arr) => arr.slice(activityPage * pageSize, (activityPage + 1) * pageSize);
10677
11009
  const handleTabChange = (tab) => {
@@ -10681,10 +11013,38 @@ function PortfolioActivityPanel({
10681
11013
  return /* @__PURE__ */ jsxs(Container2, { className, style, children: [
10682
11014
  /* @__PURE__ */ jsx(PanelTitle, { children: "Activity" }),
10683
11015
  /* @__PURE__ */ jsxs(TabContainer, { children: [
10684
- showPositionsTab && /* @__PURE__ */ jsx(Tab, { $active: activeTab === "positions", onClick: () => handleTabChange("positions"), children: "Positions" }),
10685
- /* @__PURE__ */ jsx(Tab, { $active: activeTab === "subscriptions", onClick: () => handleTabChange("subscriptions"), children: "Initial Offerings" }),
10686
- /* @__PURE__ */ jsx(Tab, { $active: activeTab === "open-orders", onClick: () => handleTabChange("open-orders"), children: "Open Orders" }),
10687
- /* @__PURE__ */ jsx(Tab, { $active: activeTab === "orders", onClick: () => handleTabChange("orders"), children: "Order History" }),
11016
+ showPositionsTab && /* @__PURE__ */ jsxs(Tab, { $active: activeTab === "positions", onClick: () => handleTabChange("positions"), children: [
11017
+ "Positions",
11018
+ positionsCount > 0 && /* @__PURE__ */ jsxs(TabCount, { children: [
11019
+ " (",
11020
+ positionsCount,
11021
+ ")"
11022
+ ] })
11023
+ ] }),
11024
+ /* @__PURE__ */ jsxs(Tab, { $active: activeTab === "subscriptions", onClick: () => handleTabChange("subscriptions"), children: [
11025
+ "Initial Offerings",
11026
+ pendingOfferingsCount > 0 && /* @__PURE__ */ jsxs(TabCount, { children: [
11027
+ " (",
11028
+ pendingOfferingsCount,
11029
+ ")"
11030
+ ] })
11031
+ ] }),
11032
+ /* @__PURE__ */ jsxs(Tab, { $active: activeTab === "open-orders", onClick: () => handleTabChange("open-orders"), children: [
11033
+ "Open Orders",
11034
+ openOrdersCount > 0 && /* @__PURE__ */ jsxs(TabCount, { children: [
11035
+ " (",
11036
+ openOrdersCount,
11037
+ ")"
11038
+ ] })
11039
+ ] }),
11040
+ /* @__PURE__ */ jsxs(Tab, { $active: activeTab === "orders", onClick: () => handleTabChange("orders"), children: [
11041
+ "Order History",
11042
+ pendingHistoryCount > 0 && /* @__PURE__ */ jsxs(TabCount, { children: [
11043
+ " (",
11044
+ pendingHistoryCount,
11045
+ ")"
11046
+ ] })
11047
+ ] }),
10688
11048
  /* @__PURE__ */ jsx(Tab, { $active: activeTab === "trades", onClick: () => handleTabChange("trades"), children: "Trade History" }),
10689
11049
  /* @__PURE__ */ jsx(Tab, { $active: activeTab === "transfers", onClick: () => handleTabChange("transfers"), children: "Transfers" })
10690
11050
  ] }),
@@ -10769,8 +11129,10 @@ function PortfolioActivityPanel({
10769
11129
  openOrders.length === 0 && /* @__PURE__ */ jsx(EmptyState, { children: "Open orders will appear here while they are working in the market." }),
10770
11130
  pageSlice(openOrders).map((order) => {
10771
11131
  const meta = getOrderStatusMeta(order.status);
10772
- const priceDisplay = order.price ? formatCurrency5(order.price) : "Market";
10773
- const amountDisplay = order.price ? formatCurrency5(order.price * order.quantity) : "\u2014";
11132
+ const isMarket = order.type === "MARKET";
11133
+ const priceSegment = isMarket || !order.price ? "" : ` \xB7 ${formatCurrency5(order.price)}`;
11134
+ const filledPercent = order.quantity > 0 ? Math.round(order.filledQuantity / order.quantity * 100) : 0;
11135
+ const amountDisplay = !isMarket && order.price ? formatCurrency5(order.price * order.quantity) : "\u2014";
10774
11136
  const isCancelling = cancellingOrderId === order.id;
10775
11137
  return /* @__PURE__ */ jsxs(ActivityRow, { children: [
10776
11138
  /* @__PURE__ */ jsx(ActivitySideBadge, { $side: sideLabel(order.side), children: sideLabel(order.side) }),
@@ -10780,9 +11142,10 @@ function PortfolioActivityPanel({
10780
11142
  formatNumber2(order.quantity),
10781
11143
  " tokens \xB7 ",
10782
11144
  prettyLabel(order.type),
11145
+ priceSegment,
10783
11146
  " \xB7 ",
10784
- priceDisplay,
10785
- " \xB7 ",
11147
+ filledPercent,
11148
+ "% filled \xB7 ",
10786
11149
  formatTimestamp(order.createdAt)
10787
11150
  ] })
10788
11151
  ] }),
@@ -10809,8 +11172,10 @@ function PortfolioActivityPanel({
10809
11172
  orderHistory.length === 0 && /* @__PURE__ */ jsx(EmptyState, { children: "No orders yet. Place a trade to see it appear here." }),
10810
11173
  pageSlice(orderHistory).map((order) => {
10811
11174
  const meta = getOrderStatusMeta(order.status);
10812
- const priceDisplay = order.price ? formatCurrency5(order.price) : "Market";
10813
- const amountDisplay = order.price ? formatCurrency5(order.price * order.quantity) : "\u2014";
11175
+ const isMarket = order.type === "MARKET";
11176
+ const priceSegment = isMarket || !order.price ? "" : ` \xB7 ${formatCurrency5(order.price)}`;
11177
+ const filledPercent = order.quantity > 0 ? Math.round(order.filledQuantity / order.quantity * 100) : 0;
11178
+ const amountDisplay = !isMarket && order.price ? formatCurrency5(order.price * order.quantity) : "\u2014";
10814
11179
  return /* @__PURE__ */ jsxs(ActivityRow, { children: [
10815
11180
  /* @__PURE__ */ jsx(ActivitySideBadge, { $side: sideLabel(order.side), children: sideLabel(order.side) }),
10816
11181
  /* @__PURE__ */ jsxs(ActivityInfo, { children: [
@@ -10819,9 +11184,10 @@ function PortfolioActivityPanel({
10819
11184
  formatNumber2(order.quantity),
10820
11185
  " tokens \xB7 ",
10821
11186
  prettyLabel(order.type),
11187
+ priceSegment,
10822
11188
  " \xB7 ",
10823
- priceDisplay,
10824
- " \xB7 ",
11189
+ filledPercent,
11190
+ "% filled \xB7 ",
10825
11191
  formatTimestamp(order.createdAt)
10826
11192
  ] })
10827
11193
  ] }),
@@ -10963,6 +11329,12 @@ var Tab = styled24.button`
10963
11329
  color: ${({ $active }) => $active ? "#fff" : "rgba(255, 255, 255, 0.65)"};
10964
11330
  }
10965
11331
  `;
11332
+ var TabCount = styled24.span`
11333
+ color: inherit;
11334
+ opacity: 0.7;
11335
+ font-weight: 500;
11336
+ margin-left: 2px;
11337
+ `;
10966
11338
  var ActivityRow = styled24.div`
10967
11339
  display: grid;
10968
11340
  grid-template-columns: auto 1fr auto auto;
@@ -11606,6 +11978,7 @@ function PropertyBuy({
11606
11978
  recentOrders = [],
11607
11979
  ordersAllocated = 0,
11608
11980
  subscribers = 0,
11981
+ isLoadingActivity = false,
11609
11982
  selectorItems,
11610
11983
  onSelectorSelect,
11611
11984
  portfolioActivity
@@ -11638,6 +12011,7 @@ function PropertyBuy({
11638
12011
  const offeringValuation = saleData?.offeringValuation ?? tokenPrice * supplyToSell;
11639
12012
  const ipoStatus = saleData?.status ?? "PENDING";
11640
12013
  const ipoStarted = ipoStatus === "LIVE" || isPrivateClient && ipoStatus === "PENDING";
12014
+ const ipoEnded = ipoStatus === "CLOSED" || ipoStatus === "CANCELLED";
11641
12015
  const statusLabel = ipoStatus;
11642
12016
  const statusColor = STATUS_COLOR2[ipoStatus] ?? "#D4AF37";
11643
12017
  const displayStatusLabel = isPrivateClient && ipoStatus !== "LIVE" ? "Private Client Access" : statusLabel;
@@ -11788,6 +12162,8 @@ function PropertyBuy({
11788
12162
  VideoActivitySection,
11789
12163
  {
11790
12164
  ipoStarted,
12165
+ ipoEnded,
12166
+ isLoading: isLoadingActivity,
11791
12167
  recentOrders,
11792
12168
  ordersAllocated,
11793
12169
  tokenPrice
@@ -14399,7 +14775,68 @@ function useToast() {
14399
14775
  if (!ctx) throw new Error("useToast must be used within a ToastProvider");
14400
14776
  return ctx;
14401
14777
  }
14778
+ var INTERVALS = [1e3, 2e3, 4e3, 5e3, 7e3, 1e4, 12e3];
14779
+ function useAdaptivePolling({ enabled, onPoll }) {
14780
+ const onPollRef = useRef(onPoll);
14781
+ onPollRef.current = onPoll;
14782
+ useEffect(() => {
14783
+ if (!enabled) return;
14784
+ let cancelled = false;
14785
+ let timeoutId = null;
14786
+ let step = 0;
14787
+ const clear = () => {
14788
+ if (timeoutId) {
14789
+ clearTimeout(timeoutId);
14790
+ timeoutId = null;
14791
+ }
14792
+ };
14793
+ const isHidden = () => typeof document !== "undefined" && document.visibilityState === "hidden";
14794
+ const tick = async () => {
14795
+ if (cancelled) return;
14796
+ if (isHidden()) {
14797
+ return;
14798
+ }
14799
+ try {
14800
+ await onPollRef.current();
14801
+ } catch {
14802
+ }
14803
+ if (cancelled) return;
14804
+ step = Math.min(step + 1, INTERVALS.length - 1);
14805
+ timeoutId = setTimeout(tick, INTERVALS[step]);
14806
+ };
14807
+ const onVisibility = () => {
14808
+ if (document.visibilityState === "visible") {
14809
+ step = 0;
14810
+ clear();
14811
+ timeoutId = setTimeout(tick, 0);
14812
+ }
14813
+ };
14814
+ if (typeof document !== "undefined") {
14815
+ document.addEventListener("visibilitychange", onVisibility);
14816
+ }
14817
+ timeoutId = setTimeout(tick, INTERVALS[0]);
14818
+ return () => {
14819
+ cancelled = true;
14820
+ clear();
14821
+ if (typeof document !== "undefined") {
14822
+ document.removeEventListener("visibilitychange", onVisibility);
14823
+ }
14824
+ };
14825
+ }, [enabled]);
14826
+ }
14827
+ function hasPendingActivity(data) {
14828
+ if (!data) return false;
14829
+ const openPending = data.openOrders?.some((o) => {
14830
+ const s = o.status.toUpperCase();
14831
+ return s === "OPEN" || s === "PARTIALLY_FILLED";
14832
+ }) ?? false;
14833
+ if (openPending) return true;
14834
+ return data.offeringOrders?.some((o) => {
14835
+ const s = o.status.toUpperCase();
14836
+ return s !== "FILLED" && s !== "ALLOCATED" && s !== "CONFIRMED" && s !== "CANCELLED" && s !== "CANCELED" && s !== "REJECTED";
14837
+ }) ?? false;
14838
+ }
14402
14839
 
14403
- export { AssetSelectorBar, Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Header, HousePositionSlider, HousePositionSliderMobile, LoafLiquidityBadge, LoafLiquidityLogo, LoginPopup, MobileTradeNav, Orderbook, owner_booking_default as OwnerBooking, PaymentPopup, PortfolioActivityPanel, PortfolioSummary, PriceChart, PropertyBuy, PropertyCompareBar, PropertyDocuments, PropertyHeroHeader, PropertyHistory, PropertyInspectionTimes, PropertyNewsUpdates, PropertyOffers, PropertyOverview, PropertyPhotoGallery, PropertySubheader, PropertyTour, PropertyValuation, ToastProvider, TradeConfirmationModal, TradingSlider, YourOrders, badgeVariants, buttonVariants, useToast };
14840
+ export { AssetSelectorBar, Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Header, HousePositionSlider, HousePositionSliderMobile, LoafLiquidityBadge, LoafLiquidityLogo, LoginPopup, MobileTradeNav, Orderbook, owner_booking_default as OwnerBooking, PaymentPopup, PortfolioActivityPanel, PortfolioSummary, PriceChart, PropertyBuy, PropertyCompareBar, PropertyDocuments, PropertyHeroHeader, PropertyHistory, PropertyInspectionTimes, PropertyNewsUpdates, PropertyOffers, PropertyOverview, PropertyPhotoGallery, PropertySubheader, PropertyTour, PropertyValuation, Skeleton, ToastProvider, TradeConfirmationModal, TradingSlider, YourOrders, badgeVariants, buttonVariants, hasPendingActivity, useAdaptivePolling, useToast };
14404
14841
  //# sourceMappingURL=index.mjs.map
14405
14842
  //# sourceMappingURL=index.mjs.map