@loafmarkets/ui 0.1.41 → 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.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var React5 = require('react');
3
+ var React9 = require('react');
4
4
  var reactSlot = require('@radix-ui/react-slot');
5
5
  var classVarianceAuthority = require('class-variance-authority');
6
6
  var clsx = require('clsx');
@@ -33,7 +33,7 @@ function _interopNamespace(e) {
33
33
  return Object.freeze(n);
34
34
  }
35
35
 
36
- var React5__namespace = /*#__PURE__*/_interopNamespace(React5);
36
+ var React9__namespace = /*#__PURE__*/_interopNamespace(React9);
37
37
  var styled24__default = /*#__PURE__*/_interopDefault(styled24);
38
38
  var LightweightCharts__namespace = /*#__PURE__*/_interopNamespace(LightweightCharts);
39
39
 
@@ -75,7 +75,7 @@ var buttonVariants = classVarianceAuthority.cva(
75
75
  }
76
76
  }
77
77
  );
78
- var Button = React5__namespace.forwardRef(
78
+ var Button = React9__namespace.forwardRef(
79
79
  ({ className, variant, size, radius, asChild = false, ...props }, ref) => {
80
80
  const Comp = asChild ? reactSlot.Slot : "button";
81
81
  const coercedRadius = radius ?? (variant === "onboarding" || variant === "onboardingOutline" ? "square" : void 0);
@@ -114,11 +114,11 @@ var badgeVariants = classVarianceAuthority.cva(
114
114
  }
115
115
  }
116
116
  );
117
- var Badge = React5__namespace.forwardRef(
117
+ var Badge = React9__namespace.forwardRef(
118
118
  ({ className, variant, size, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("span", { ref, className: cn(badgeVariants({ variant, size }), className), ...props })
119
119
  );
120
120
  Badge.displayName = "Badge";
121
- var Card = React5__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
121
+ var Card = React9__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
122
122
  "div",
123
123
  {
124
124
  ref,
@@ -130,11 +130,11 @@ var Card = React5__namespace.forwardRef(({ className, ...props }, ref) => /* @__
130
130
  }
131
131
  ));
132
132
  Card.displayName = "Card";
133
- var CardHeader = React5__namespace.forwardRef(
133
+ var CardHeader = React9__namespace.forwardRef(
134
134
  ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("flex flex-col space-y-1.5 p-6", className), ...props })
135
135
  );
136
136
  CardHeader.displayName = "CardHeader";
137
- var CardTitle = React5__namespace.forwardRef(
137
+ var CardTitle = React9__namespace.forwardRef(
138
138
  ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
139
139
  "h3",
140
140
  {
@@ -145,15 +145,15 @@ var CardTitle = React5__namespace.forwardRef(
145
145
  )
146
146
  );
147
147
  CardTitle.displayName = "CardTitle";
148
- var CardDescription = React5__namespace.forwardRef(
148
+ var CardDescription = React9__namespace.forwardRef(
149
149
  ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("p", { ref, className: cn("text-sm text-slate-500", className), ...props })
150
150
  );
151
151
  CardDescription.displayName = "CardDescription";
152
- var CardContent = React5__namespace.forwardRef(
152
+ var CardContent = React9__namespace.forwardRef(
153
153
  ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("px-6 pb-6 pt-2 text-sm text-slate-600", className), ...props })
154
154
  );
155
155
  CardContent.displayName = "CardContent";
156
- var CardFooter = React5__namespace.forwardRef(
156
+ var CardFooter = React9__namespace.forwardRef(
157
157
  ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("flex items-center border-t border-slate-100 px-6 py-4", className), ...props })
158
158
  );
159
159
  CardFooter.displayName = "CardFooter";
@@ -171,7 +171,7 @@ var defaultFormatSignedCurrency = (value) => {
171
171
  const sign = value >= 0 ? "+" : "-";
172
172
  return `${sign}${defaultFormatCurrency(Math.abs(value))}`;
173
173
  };
174
- var PortfolioSummary = React5__namespace.forwardRef(
174
+ var PortfolioSummary = React9__namespace.forwardRef(
175
175
  ({
176
176
  availableCash,
177
177
  portfolioValue,
@@ -321,23 +321,23 @@ function HousePositionSlider({
321
321
  className,
322
322
  ...props
323
323
  }) {
324
- const [orderMode, setOrderMode] = React5__namespace.useState("none");
325
- const [buyTrackingMode, setBuyTrackingMode] = React5__namespace.useState("dollars");
326
- const [deltaDollars, setDeltaDollars] = React5__namespace.useState(0);
327
- const [deltaTokensBuy, setDeltaTokensBuy] = React5__namespace.useState(0);
328
- const [deltaTokensSell, setDeltaTokensSell] = React5__namespace.useState(0);
329
- const [_isDragging, setIsDragging] = React5__namespace.useState(false);
330
- const [visualTargetPct, setVisualTargetPct] = React5__namespace.useState(null);
331
- const [orderType, setOrderType] = React5__namespace.useState(defaultOrderType);
332
- const [limitPrice, setLimitPrice] = React5__namespace.useState(currentPrice);
333
- const [limitPriceInput, setLimitPriceInput] = React5__namespace.useState(currentPrice.toFixed(2));
334
- const [limitPriceDirty, setLimitPriceDirty] = React5__namespace.useState(false);
335
- const [ownershipInput, setOwnershipInput] = React5__namespace.useState("");
336
- const [tokenAmountInput, setTokenAmountInput] = React5__namespace.useState("");
337
- const houseRef = React5__namespace.useRef(null);
324
+ const [orderMode, setOrderMode] = React9__namespace.useState("none");
325
+ const [buyTrackingMode, setBuyTrackingMode] = React9__namespace.useState("dollars");
326
+ const [deltaDollars, setDeltaDollars] = React9__namespace.useState(0);
327
+ const [deltaTokensBuy, setDeltaTokensBuy] = React9__namespace.useState(0);
328
+ const [deltaTokensSell, setDeltaTokensSell] = React9__namespace.useState(0);
329
+ const [_isDragging, setIsDragging] = React9__namespace.useState(false);
330
+ const [visualTargetPct, setVisualTargetPct] = React9__namespace.useState(null);
331
+ const [orderType, setOrderType] = React9__namespace.useState(defaultOrderType);
332
+ const [limitPrice, setLimitPrice] = React9__namespace.useState(currentPrice);
333
+ const [limitPriceInput, setLimitPriceInput] = React9__namespace.useState(currentPrice.toFixed(2));
334
+ const [limitPriceDirty, setLimitPriceDirty] = React9__namespace.useState(false);
335
+ const [ownershipInput, setOwnershipInput] = React9__namespace.useState("");
336
+ const [tokenAmountInput, setTokenAmountInput] = React9__namespace.useState("");
337
+ const houseRef = React9__namespace.useRef(null);
338
338
  const asks = orderbook?.asks ?? [];
339
339
  const bids = orderbook?.bids ?? [];
340
- React5__namespace.useEffect(() => {
340
+ React9__namespace.useEffect(() => {
341
341
  if (orderType !== "limit") return;
342
342
  if (limitPriceDirty) return;
343
343
  setLimitPrice(currentPrice);
@@ -412,7 +412,7 @@ function HousePositionSlider({
412
412
  const impliedDisplayTargetOwnership = clamp(targetOwnership + ownershipShift, 0, 100);
413
413
  const displayTargetOwnership = visualTargetPct ?? impliedDisplayTargetOwnership;
414
414
  const estFeeTokens = Math.abs(deltaValue) * 5e-3 / (effectivePrice || 1);
415
- const resetOrder = React5__namespace.useCallback(() => {
415
+ const resetOrder = React9__namespace.useCallback(() => {
416
416
  setOrderMode("none");
417
417
  setBuyTrackingMode("dollars");
418
418
  setDeltaDollars(0);
@@ -420,7 +420,7 @@ function HousePositionSlider({
420
420
  setDeltaTokensSell(0);
421
421
  setVisualTargetPct(null);
422
422
  }, []);
423
- const updateOrderFromTargetValue = React5__namespace.useCallback(
423
+ const updateOrderFromTargetValue = React9__namespace.useCallback(
424
424
  (newTargetValue) => {
425
425
  const newDeltaValue = newTargetValue - holdingsValue;
426
426
  if (newDeltaValue > 0) {
@@ -444,7 +444,7 @@ function HousePositionSlider({
444
444
  },
445
445
  [effectiveAvailableCash, effectivePrice, effectiveTokensHeld, holdingsValue, resetOrder, tokensHeld]
446
446
  );
447
- const updateOrderFromOwnership = React5__namespace.useCallback(
447
+ const updateOrderFromOwnership = React9__namespace.useCallback(
448
448
  (newOwnershipPercent) => {
449
449
  const nextOwnership = clamp(newOwnershipPercent, 0, 100);
450
450
  const newTargetTokens = nextOwnership / 100 * totalTokens;
@@ -453,7 +453,7 @@ function HousePositionSlider({
453
453
  },
454
454
  [effectivePrice, totalTokens, updateOrderFromTargetValue]
455
455
  );
456
- const updateOrderFromTokenAmount = React5__namespace.useCallback(
456
+ const updateOrderFromTokenAmount = React9__namespace.useCallback(
457
457
  (tokenAmountSigned) => {
458
458
  if (tokenAmountSigned > 0) {
459
459
  const maxTokens = effectiveAvailableCash / (effectivePrice || 1);
@@ -476,7 +476,7 @@ function HousePositionSlider({
476
476
  },
477
477
  [effectiveAvailableCash, effectivePrice, effectiveTokensHeld, resetOrder]
478
478
  );
479
- const updateOrderFromSlider = React5__namespace.useCallback(
479
+ const updateOrderFromSlider = React9__namespace.useCallback(
480
480
  (pct) => {
481
481
  const normalized = (pct - 50) / 50;
482
482
  const magnitude = Math.min(Math.abs(normalized), 1);
@@ -520,7 +520,7 @@ function HousePositionSlider({
520
520
  },
521
521
  [effectiveAvailableCash, effectiveTokensHeld, resetOrder]
522
522
  );
523
- const handleDragAtClientY = React5__namespace.useCallback(
523
+ const handleDragAtClientY = React9__namespace.useCallback(
524
524
  (clientY) => {
525
525
  if (!houseRef.current) return;
526
526
  const rect = houseRef.current.getBoundingClientRect();
@@ -1036,18 +1036,18 @@ function HousePositionSliderMobile({
1036
1036
  className,
1037
1037
  ...props
1038
1038
  }) {
1039
- const [orderMode, setOrderMode] = React5__namespace.useState("none");
1040
- const [deltaDollars, setDeltaDollars] = React5__namespace.useState(0);
1041
- const [deltaTokensSell, setDeltaTokensSell] = React5__namespace.useState(0);
1042
- const [deltaTokensBuy, setDeltaTokensBuy] = React5__namespace.useState(0);
1043
- const [buyTrackingMode, setBuyTrackingMode] = React5__namespace.useState("dollars");
1044
- const [orderType, setOrderType] = React5__namespace.useState(defaultOrderType);
1045
- const [limitPrice, setLimitPrice] = React5__namespace.useState(currentPrice);
1046
- const [limitPriceInput, setLimitPriceInput] = React5__namespace.useState(currentPrice.toFixed(2));
1047
- const [limitPriceDirty, setLimitPriceDirty] = React5__namespace.useState(false);
1048
- const [tokenAmountInput, setTokenAmountInput] = React5__namespace.useState("");
1049
- const houseRef = React5__namespace.useRef(null);
1050
- React5__namespace.useEffect(() => {
1039
+ const [orderMode, setOrderMode] = React9__namespace.useState("none");
1040
+ const [deltaDollars, setDeltaDollars] = React9__namespace.useState(0);
1041
+ const [deltaTokensSell, setDeltaTokensSell] = React9__namespace.useState(0);
1042
+ const [deltaTokensBuy, setDeltaTokensBuy] = React9__namespace.useState(0);
1043
+ const [buyTrackingMode, setBuyTrackingMode] = React9__namespace.useState("dollars");
1044
+ const [orderType, setOrderType] = React9__namespace.useState(defaultOrderType);
1045
+ const [limitPrice, setLimitPrice] = React9__namespace.useState(currentPrice);
1046
+ const [limitPriceInput, setLimitPriceInput] = React9__namespace.useState(currentPrice.toFixed(2));
1047
+ const [limitPriceDirty, setLimitPriceDirty] = React9__namespace.useState(false);
1048
+ const [tokenAmountInput, setTokenAmountInput] = React9__namespace.useState("");
1049
+ const houseRef = React9__namespace.useRef(null);
1050
+ React9__namespace.useEffect(() => {
1051
1051
  if (orderType !== "limit") return;
1052
1052
  if (limitPriceDirty) return;
1053
1053
  setLimitPrice(currentPrice);
@@ -1089,7 +1089,7 @@ function HousePositionSliderMobile({
1089
1089
  const hasChange = orderMode !== "none" && (Math.abs(deltaTokens) > 1e-3 || Math.abs(deltaValue) > 0.01);
1090
1090
  const targetOwnership = totalTokens > 0 ? targetTokens / totalTokens * 100 : 0;
1091
1091
  const estFeeTokens = effectivePrice > 0 ? Math.abs(deltaValue) * 5e-3 / effectivePrice : 0;
1092
- const updateOrderFromTargetValue = React5__namespace.useCallback(
1092
+ const updateOrderFromTargetValue = React9__namespace.useCallback(
1093
1093
  (newTargetValue) => {
1094
1094
  const newDeltaValue = newTargetValue - holdingsValue;
1095
1095
  if (newDeltaValue > 0.01) {
@@ -1117,7 +1117,7 @@ function HousePositionSliderMobile({
1117
1117
  },
1118
1118
  [holdingsValue, availableCash, effectivePrice, tokensHeld]
1119
1119
  );
1120
- const updateOrderFromTokenAmount = React5__namespace.useCallback(
1120
+ const updateOrderFromTokenAmount = React9__namespace.useCallback(
1121
1121
  (tokenAmount) => {
1122
1122
  if (tokenAmount > 0) {
1123
1123
  const maxTokens = effectivePrice > 0 ? availableCash / effectivePrice : 0;
@@ -1144,14 +1144,14 @@ function HousePositionSliderMobile({
1144
1144
  },
1145
1145
  [effectivePrice, availableCash, tokensHeld]
1146
1146
  );
1147
- const handleMarkerClick = React5__namespace.useCallback(
1147
+ const handleMarkerClick = React9__namespace.useCallback(
1148
1148
  (pct) => {
1149
1149
  const newTargetValue = pct / 100 * totalCapacity;
1150
1150
  updateOrderFromTargetValue(newTargetValue);
1151
1151
  },
1152
1152
  [totalCapacity, updateOrderFromTargetValue]
1153
1153
  );
1154
- const onMouseDown = React5__namespace.useCallback(
1154
+ const onMouseDown = React9__namespace.useCallback(
1155
1155
  (e) => {
1156
1156
  e.preventDefault();
1157
1157
  const move = (ev) => {
@@ -1171,7 +1171,7 @@ function HousePositionSliderMobile({
1171
1171
  },
1172
1172
  [totalCapacity, updateOrderFromTargetValue]
1173
1173
  );
1174
- const onTouchStart = React5__namespace.useCallback(
1174
+ const onTouchStart = React9__namespace.useCallback(
1175
1175
  (e) => {
1176
1176
  e.preventDefault();
1177
1177
  e.stopPropagation();
@@ -1729,7 +1729,7 @@ var LiquidityText = styled24__default.default.span`
1729
1729
  letter-spacing: 0.1px;
1730
1730
  }
1731
1731
  `;
1732
- var LoafLiquidityBadge = React5__namespace.forwardRef(
1732
+ var LoafLiquidityBadge = React9__namespace.forwardRef(
1733
1733
  ({ className, isGlowing, onClick, children, ...props }, ref) => {
1734
1734
  return /* @__PURE__ */ jsxRuntime.jsxs(
1735
1735
  LogoContainer,
@@ -1757,9 +1757,34 @@ var LoafLiquidityBadge = React5__namespace.forwardRef(
1757
1757
  }
1758
1758
  );
1759
1759
  LoafLiquidityBadge.displayName = "LoafLiquidityBadge";
1760
+ var toSize = (v, fallback) => v == null ? fallback : typeof v === "number" ? `${v}px` : v;
1761
+ var Skeleton = React9__namespace.forwardRef(
1762
+ ({ width, height, radius, className, style, ...props }, ref) => {
1763
+ return /* @__PURE__ */ jsxRuntime.jsx(
1764
+ "div",
1765
+ {
1766
+ ref,
1767
+ "aria-busy": "true",
1768
+ "aria-live": "polite",
1769
+ className: cn(
1770
+ "inline-block align-middle bg-white/10 animate-pulse",
1771
+ className
1772
+ ),
1773
+ style: {
1774
+ width: toSize(width, "100%"),
1775
+ height: toSize(height, "1em"),
1776
+ borderRadius: toSize(radius, "6px"),
1777
+ ...style
1778
+ },
1779
+ ...props
1780
+ }
1781
+ );
1782
+ }
1783
+ );
1784
+ Skeleton.displayName = "Skeleton";
1760
1785
  function useViewportCompact(breakpoint) {
1761
- const [isCompact, setIsCompact] = React5__namespace.useState(false);
1762
- React5__namespace.useEffect(() => {
1786
+ const [isCompact, setIsCompact] = React9__namespace.useState(false);
1787
+ React9__namespace.useEffect(() => {
1763
1788
  if (typeof window === "undefined") return;
1764
1789
  const check = () => setIsCompact(window.innerWidth <= breakpoint);
1765
1790
  check();
@@ -1769,16 +1794,119 @@ function useViewportCompact(breakpoint) {
1769
1794
  return isCompact;
1770
1795
  }
1771
1796
  var formatNumber = (value, precision) => value.toFixed(precision);
1797
+ var FLASH_DURATION_MS = 450;
1798
+ var FLASH_UP_COLOR = "rgba(14, 203, 129, 0.35)";
1799
+ var FLASH_DOWN_COLOR = "rgba(246, 70, 93, 0.35)";
1800
+ function getTradeKey(trade, fallbackIndex) {
1801
+ if (trade.tradeId != null) return `id-${trade.tradeId}`;
1802
+ if (trade.time != null) return `t-${trade.time}-${trade.type}-${trade.price}-${trade.amount}`;
1803
+ return `idx-${fallbackIndex}-${trade.type}-${trade.price}-${trade.amount}`;
1804
+ }
1805
+ function useAmountChangeFlash(ref, amount) {
1806
+ const prevAmountRef = React9__namespace.useRef(amount);
1807
+ React9__namespace.useEffect(() => {
1808
+ const prev = prevAmountRef.current;
1809
+ const node = ref.current;
1810
+ if (prev !== amount && node && typeof node.animate === "function") {
1811
+ const color = amount > prev ? FLASH_UP_COLOR : FLASH_DOWN_COLOR;
1812
+ node.animate(
1813
+ [{ backgroundColor: color }, { backgroundColor: "transparent" }],
1814
+ { duration: FLASH_DURATION_MS, easing: "ease-out" }
1815
+ );
1816
+ }
1817
+ prevAmountRef.current = amount;
1818
+ }, [amount, ref]);
1819
+ }
1820
+ function useMidPriceFlash(ref, midPrice, restBgColor) {
1821
+ const prevMidRef = React9__namespace.useRef(midPrice);
1822
+ React9__namespace.useEffect(() => {
1823
+ const prev = prevMidRef.current;
1824
+ const node = ref.current;
1825
+ if (prev !== midPrice && prev > 0 && midPrice > 0 && node && typeof node.animate === "function") {
1826
+ const color = midPrice > prev ? FLASH_UP_COLOR : FLASH_DOWN_COLOR;
1827
+ node.animate(
1828
+ [{ backgroundColor: color }, { backgroundColor: restBgColor }],
1829
+ { duration: FLASH_DURATION_MS, easing: "ease-out" }
1830
+ );
1831
+ }
1832
+ prevMidRef.current = midPrice;
1833
+ }, [midPrice, ref, restBgColor]);
1834
+ }
1835
+ function TradeRow({
1836
+ trade,
1837
+ tradeKey,
1838
+ precision,
1839
+ amountPrecision,
1840
+ seenTradeKeysRef,
1841
+ compact
1842
+ }) {
1843
+ const rowRef = React9__namespace.useRef(null);
1844
+ const { type } = trade;
1845
+ React9__namespace.useEffect(() => {
1846
+ if (seenTradeKeysRef.current.has(tradeKey)) return;
1847
+ seenTradeKeysRef.current.add(tradeKey);
1848
+ const node = rowRef.current;
1849
+ if (!node || typeof node.animate !== "function") return;
1850
+ const color = type === "buy" ? FLASH_UP_COLOR : FLASH_DOWN_COLOR;
1851
+ node.animate(
1852
+ [{ backgroundColor: color }, { backgroundColor: "transparent" }],
1853
+ { duration: FLASH_DURATION_MS, easing: "ease-out" }
1854
+ );
1855
+ }, [tradeKey, seenTradeKeysRef, type]);
1856
+ if (compact) {
1857
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1858
+ "div",
1859
+ {
1860
+ ref: rowRef,
1861
+ className: "grid",
1862
+ style: { gridTemplateColumns: "1.2fr 0.8fr", padding: "0.2rem 0", fontSize: "0.8rem" },
1863
+ children: [
1864
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { color: trade.type === "buy" ? "#0ecb81" : "#f6465d", fontWeight: 500 }, children: [
1865
+ "$",
1866
+ formatNumber(trade.price, precision)
1867
+ ] }),
1868
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { textAlign: "right", paddingRight: "0.5rem" }, children: formatNumber(trade.amount, amountPrecision) })
1869
+ ]
1870
+ }
1871
+ );
1872
+ }
1873
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1874
+ "div",
1875
+ {
1876
+ ref: rowRef,
1877
+ className: "grid grid-cols-2 items-center gap-3 px-3 py-1.5",
1878
+ children: [
1879
+ /* @__PURE__ */ jsxRuntime.jsxs(
1880
+ "div",
1881
+ {
1882
+ className: cn(
1883
+ "tabular-nums",
1884
+ trade.type === "buy" ? "text-[#0ecb81]" : "text-[#f6465d]"
1885
+ ),
1886
+ children: [
1887
+ "$",
1888
+ formatNumber(trade.price, precision)
1889
+ ]
1890
+ }
1891
+ ),
1892
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right tabular-nums text-white/90", children: formatNumber(trade.amount, amountPrecision) })
1893
+ ]
1894
+ }
1895
+ );
1896
+ }
1772
1897
  function DepthRow({
1773
1898
  side,
1774
1899
  price,
1775
1900
  amount,
1776
1901
  depthPct,
1777
1902
  precision,
1778
- amountPrecision
1903
+ amountPrecision,
1904
+ hasUserOrder
1779
1905
  }) {
1780
1906
  const isAsk = side === "ask";
1781
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative grid grid-cols-2 items-center gap-3 px-3 py-1.5", children: [
1907
+ const rowRef = React9__namespace.useRef(null);
1908
+ useAmountChangeFlash(rowRef, amount);
1909
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: rowRef, className: "relative grid grid-cols-2 items-center gap-3 px-3 py-1.5", children: [
1782
1910
  /* @__PURE__ */ jsxRuntime.jsx(
1783
1911
  "div",
1784
1912
  {
@@ -1786,9 +1914,16 @@ function DepthRow({
1786
1914
  "absolute inset-y-0 right-0",
1787
1915
  isAsk ? "bg-rose-900/30" : "bg-emerald-900/30"
1788
1916
  ),
1789
- style: { width: `${clamp3(depthPct, 0, 100)}%` }
1917
+ style: { width: `${clamp3(depthPct, 0, 100)}%`, transition: "width 300ms ease-out" }
1790
1918
  }
1791
1919
  ),
1920
+ hasUserOrder ? /* @__PURE__ */ jsxRuntime.jsx(
1921
+ "span",
1922
+ {
1923
+ "aria-label": "Your order at this price",
1924
+ 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)]"
1925
+ }
1926
+ ) : null,
1792
1927
  /* @__PURE__ */ jsxRuntime.jsxs(
1793
1928
  "div",
1794
1929
  {
@@ -1808,7 +1943,7 @@ var DEPTH_ROW_HEIGHT_PX = 34;
1808
1943
  var COMPACT_ROWS_VISIBLE = 5;
1809
1944
  var COMPACT_ROW_HEIGHT_PX = 30;
1810
1945
  var COMPACT_BREAKPOINT_PX = 1024;
1811
- var Orderbook = React5__namespace.forwardRef(
1946
+ var Orderbook = React9__namespace.forwardRef(
1812
1947
  ({
1813
1948
  asks,
1814
1949
  bids,
@@ -1823,13 +1958,44 @@ var Orderbook = React5__namespace.forwardRef(
1823
1958
  onTabChange,
1824
1959
  rightHeader = /* @__PURE__ */ jsxRuntime.jsx(LoafLiquidityBadge, { className: "text-[0.6rem]" }),
1825
1960
  variant = "auto",
1961
+ userOrderPrices,
1962
+ isLoading = false,
1826
1963
  className,
1827
1964
  ...props
1828
1965
  }, ref) => {
1829
- const [tab, setTab] = React5__namespace.useState(defaultTab);
1830
- const [tradeFilter, setTradeFilter] = React5__namespace.useState("all");
1966
+ const [tab, setTab] = React9__namespace.useState(defaultTab);
1967
+ const [tradeFilter, setTradeFilter] = React9__namespace.useState("all");
1831
1968
  const viewportCompact = useViewportCompact(COMPACT_BREAKPOINT_PX);
1832
- React5__namespace.useEffect(() => {
1969
+ const { userAskPrices, userBidPrices } = React9__namespace.useMemo(() => {
1970
+ const ask = /* @__PURE__ */ new Set();
1971
+ const bid = /* @__PURE__ */ new Set();
1972
+ if (!userOrderPrices) return { userAskPrices: ask, userBidPrices: bid };
1973
+ for (const entry of userOrderPrices) {
1974
+ if (entry.side === "SELL") ask.add(entry.price);
1975
+ else bid.add(entry.price);
1976
+ }
1977
+ return { userAskPrices: ask, userBidPrices: bid };
1978
+ }, [userOrderPrices]);
1979
+ const seenTradeKeysRef = React9__namespace.useRef(/* @__PURE__ */ new Set());
1980
+ const initializedRef = React9__namespace.useRef(false);
1981
+ if (!initializedRef.current && trades.length > 0) {
1982
+ for (let i = 0; i < trades.length; i++) {
1983
+ seenTradeKeysRef.current.add(getTradeKey(trades[i], i));
1984
+ }
1985
+ initializedRef.current = true;
1986
+ }
1987
+ React9__namespace.useEffect(() => {
1988
+ if (!initializedRef.current) return;
1989
+ const live = /* @__PURE__ */ new Set();
1990
+ for (let i = 0; i < trades.length; i++) {
1991
+ live.add(getTradeKey(trades[i], i));
1992
+ }
1993
+ const seen = seenTradeKeysRef.current;
1994
+ for (const key of seen) {
1995
+ if (!live.has(key)) seen.delete(key);
1996
+ }
1997
+ }, [trades]);
1998
+ React9__namespace.useEffect(() => {
1833
1999
  setTab(defaultTab);
1834
2000
  }, [defaultTab]);
1835
2001
  const handleTab = (next) => {
@@ -1860,7 +2026,11 @@ var Orderbook = React5__namespace.forwardRef(
1860
2026
  midPrice,
1861
2027
  midChangePercent,
1862
2028
  midClass,
1863
- sectionHeight
2029
+ sectionHeight,
2030
+ userAskPrices,
2031
+ userBidPrices,
2032
+ isLoading,
2033
+ seenTradeKeysRef
1864
2034
  };
1865
2035
  return /* @__PURE__ */ jsxRuntime.jsx(
1866
2036
  Card,
@@ -1878,6 +2048,29 @@ var Orderbook = React5__namespace.forwardRef(
1878
2048
  }
1879
2049
  );
1880
2050
  Orderbook.displayName = "Orderbook";
2051
+ function SkeletonRow({ compact }) {
2052
+ if (compact) {
2053
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2054
+ "div",
2055
+ {
2056
+ style: {
2057
+ display: "grid",
2058
+ gridTemplateColumns: "1.2fr 0.8fr",
2059
+ padding: "0.2rem 0",
2060
+ alignItems: "center"
2061
+ },
2062
+ children: [
2063
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: "60%", height: 10 }) }),
2064
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { textAlign: "right", paddingRight: "0.5rem" }, children: /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: "50%", height: 10 }) })
2065
+ ]
2066
+ }
2067
+ );
2068
+ }
2069
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 items-center gap-3 px-3 py-1.5", children: [
2070
+ /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: "60%", height: 12 }),
2071
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right", children: /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: "50%", height: 12 }) })
2072
+ ] });
2073
+ }
1881
2074
  function DesktopOrderbookLayout({
1882
2075
  tab,
1883
2076
  handleTab,
@@ -1896,8 +2089,14 @@ function DesktopOrderbookLayout({
1896
2089
  midPrice,
1897
2090
  midChangePercent,
1898
2091
  midClass,
1899
- sectionHeight
2092
+ sectionHeight,
2093
+ userAskPrices,
2094
+ userBidPrices,
2095
+ isLoading,
2096
+ seenTradeKeysRef
1900
2097
  }) {
2098
+ const midRef = React9__namespace.useRef(null);
2099
+ useMidPriceFlash(midRef, midPrice, "#0b1a24");
1901
2100
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1902
2101
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 pt-4", children: [
1903
2102
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4", children: [
@@ -1981,29 +2180,20 @@ function DesktopOrderbookLayout({
1981
2180
  {
1982
2181
  className: "max-h-[380px] overflow-y-auto overflow-x-hidden",
1983
2182
  style: { scrollbarGutter: "stable" },
1984
- children: tradeFiltered.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-10 text-center text-sm text-white/50", children: "No trades" }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y divide-white/5", children: tradeFiltered.map((trade, i) => /* @__PURE__ */ jsxRuntime.jsxs(
1985
- "div",
1986
- {
1987
- className: "grid grid-cols-2 items-center gap-3 px-3 py-1.5",
1988
- children: [
1989
- /* @__PURE__ */ jsxRuntime.jsxs(
1990
- "div",
1991
- {
1992
- className: cn(
1993
- "tabular-nums",
1994
- trade.type === "buy" ? "text-[#0ecb81]" : "text-[#f6465d]"
1995
- ),
1996
- children: [
1997
- "$",
1998
- formatNumber(trade.price, precision)
1999
- ]
2000
- }
2001
- ),
2002
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right tabular-nums text-white/90", children: formatNumber(trade.amount, amountPrecision) })
2003
- ]
2004
- },
2005
- `${trade.type}-${trade.price}-${trade.amount}-${trade.time ?? i}`
2006
- )) })
2183
+ children: isLoading && tradeFiltered.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y divide-white/5", children: Array.from({ length: LEVEL_ROWS_VISIBLE }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonRow, {}, `trade-skel-${i}`)) }) : tradeFiltered.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-10 text-center text-sm text-white/50", children: "No trades" }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y divide-white/5", children: tradeFiltered.map((trade, i) => {
2184
+ const tradeKey = getTradeKey(trade, i);
2185
+ return /* @__PURE__ */ jsxRuntime.jsx(
2186
+ TradeRow,
2187
+ {
2188
+ trade,
2189
+ tradeKey,
2190
+ precision,
2191
+ amountPrecision,
2192
+ seenTradeKeysRef
2193
+ },
2194
+ tradeKey
2195
+ );
2196
+ }) })
2007
2197
  }
2008
2198
  ) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col min-h-0", children: [
2009
2199
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -2011,7 +2201,7 @@ function DesktopOrderbookLayout({
2011
2201
  {
2012
2202
  className: "flex flex-col justify-end divide-y divide-white/5 overflow-y-auto",
2013
2203
  style: { height: `${sectionHeight}px`, scrollbarGutter: "stable" },
2014
- children: asks.map((l, idx) => /* @__PURE__ */ jsxRuntime.jsx(
2204
+ children: isLoading ? Array.from({ length: LEVEL_ROWS_VISIBLE }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonRow, {}, `ask-skel-${i}`)) : asks.map((l) => /* @__PURE__ */ jsxRuntime.jsx(
2015
2205
  DepthRow,
2016
2206
  {
2017
2207
  side: "ask",
@@ -2019,30 +2209,38 @@ function DesktopOrderbookLayout({
2019
2209
  amount: l.amount,
2020
2210
  depthPct: (l.depth ?? l.amount) / maxAskDepth * 100,
2021
2211
  precision,
2022
- amountPrecision
2212
+ amountPrecision,
2213
+ hasUserOrder: userAskPrices.has(l.price)
2023
2214
  },
2024
- `ask-${idx}-${l.price}-${l.amount}`
2215
+ `ask-${l.price}`
2025
2216
  ))
2026
2217
  }
2027
2218
  ),
2028
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 items-center gap-3 bg-[#0b1a24] px-3 py-2", children: [
2029
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("text-lg font-semibold tabular-nums", midClass), children: [
2030
- "$",
2031
- formatNumber(midPrice, precision),
2032
- midChangePercent == null ? null : /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("ml-2 text-sm font-semibold tabular-nums", midClass), children: [
2033
- midChangePercent >= 0 ? "+" : "",
2034
- midChangePercent.toFixed(2),
2035
- "%"
2036
- ] })
2037
- ] }),
2038
- /* @__PURE__ */ jsxRuntime.jsx("div", {})
2039
- ] }),
2219
+ /* @__PURE__ */ jsxRuntime.jsxs(
2220
+ "div",
2221
+ {
2222
+ ref: midRef,
2223
+ className: "grid grid-cols-2 items-center gap-3 bg-[#0b1a24] px-3 py-2",
2224
+ children: [
2225
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("text-lg font-semibold tabular-nums", midClass), children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 110, height: 20 }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2226
+ "$",
2227
+ formatNumber(midPrice, precision),
2228
+ midChangePercent == null ? null : /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("ml-2 text-sm font-semibold tabular-nums", midClass), children: [
2229
+ midChangePercent >= 0 ? "+" : "",
2230
+ midChangePercent.toFixed(2),
2231
+ "%"
2232
+ ] })
2233
+ ] }) }),
2234
+ /* @__PURE__ */ jsxRuntime.jsx("div", {})
2235
+ ]
2236
+ }
2237
+ ),
2040
2238
  /* @__PURE__ */ jsxRuntime.jsx(
2041
2239
  "div",
2042
2240
  {
2043
2241
  className: "divide-y divide-white/5 overflow-y-auto",
2044
2242
  style: { height: `${sectionHeight}px`, scrollbarGutter: "stable" },
2045
- children: bids.map((l, idx) => /* @__PURE__ */ jsxRuntime.jsx(
2243
+ children: isLoading ? Array.from({ length: LEVEL_ROWS_VISIBLE }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonRow, {}, `bid-skel-${i}`)) : bids.map((l) => /* @__PURE__ */ jsxRuntime.jsx(
2046
2244
  DepthRow,
2047
2245
  {
2048
2246
  side: "bid",
@@ -2050,9 +2248,10 @@ function DesktopOrderbookLayout({
2050
2248
  amount: l.amount,
2051
2249
  depthPct: (l.depth ?? l.amount) / maxBidDepth * 100,
2052
2250
  precision,
2053
- amountPrecision
2251
+ amountPrecision,
2252
+ hasUserOrder: userBidPrices.has(l.price)
2054
2253
  },
2055
- `bid-${idx}-${l.price}-${l.amount}`
2254
+ `bid-${l.price}`
2056
2255
  ))
2057
2256
  }
2058
2257
  )
@@ -2078,10 +2277,16 @@ function MobileOrderbookLayout({
2078
2277
  midPrice,
2079
2278
  midChangePercent,
2080
2279
  midClass,
2081
- sectionHeight: _sectionHeight
2280
+ sectionHeight: _sectionHeight,
2281
+ userAskPrices,
2282
+ userBidPrices,
2283
+ isLoading,
2284
+ seenTradeKeysRef
2082
2285
  }) {
2083
- const visibleAsks = React5__namespace.useMemo(() => asks.slice(0, COMPACT_ROWS_VISIBLE), [asks]);
2084
- const visibleBids = React5__namespace.useMemo(() => bids.slice(0, COMPACT_ROWS_VISIBLE), [bids]);
2286
+ const midRef = React9__namespace.useRef(null);
2287
+ useMidPriceFlash(midRef, midPrice, "transparent");
2288
+ const visibleAsks = React9__namespace.useMemo(() => asks.slice(0, COMPACT_ROWS_VISIBLE), [asks]);
2289
+ const visibleBids = React9__namespace.useMemo(() => bids.slice(0, COMPACT_ROWS_VISIBLE), [bids]);
2085
2290
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2086
2291
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 pt-2", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
2087
2292
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
@@ -2150,7 +2355,7 @@ function MobileOrderbookLayout({
2150
2355
  ]
2151
2356
  }
2152
2357
  ),
2153
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column" }, children: visibleAsks.map((l, idx) => /* @__PURE__ */ jsxRuntime.jsx(
2358
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column" }, children: isLoading ? Array.from({ length: COMPACT_ROWS_VISIBLE }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonRow, { compact: true }, `m-ask-skel-${i}`)) : visibleAsks.map((l) => /* @__PURE__ */ jsxRuntime.jsx(
2154
2359
  MobileDepthRow,
2155
2360
  {
2156
2361
  side: "ask",
@@ -2158,13 +2363,15 @@ function MobileOrderbookLayout({
2158
2363
  amount: l.amount,
2159
2364
  depthPct: (l.depth ?? l.amount) / maxAskDepth * 100,
2160
2365
  precision,
2161
- amountPrecision
2366
+ amountPrecision,
2367
+ hasUserOrder: userAskPrices.has(l.price)
2162
2368
  },
2163
- `mobile-ask-${idx}-${l.price}-${l.amount}`
2369
+ `mobile-ask-${l.price}`
2164
2370
  )) }),
2165
2371
  /* @__PURE__ */ jsxRuntime.jsxs(
2166
2372
  "div",
2167
2373
  {
2374
+ ref: midRef,
2168
2375
  className: "grid",
2169
2376
  style: {
2170
2377
  gridTemplateColumns: "1.2fr 0.8fr",
@@ -2174,12 +2381,12 @@ function MobileOrderbookLayout({
2174
2381
  borderBottom: "1px solid rgba(255,255,255,0.1)"
2175
2382
  },
2176
2383
  children: [
2177
- /* @__PURE__ */ jsxRuntime.jsxs(
2384
+ /* @__PURE__ */ jsxRuntime.jsx(
2178
2385
  "div",
2179
2386
  {
2180
2387
  style: { fontWeight: "bold", display: "flex", alignItems: "center", gap: "8px" },
2181
2388
  className: midClass,
2182
- children: [
2389
+ children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 90, height: 16 }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2183
2390
  "$",
2184
2391
  formatNumber(midPrice, precision),
2185
2392
  midChangePercent != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("text-[0.75rem] font-semibold tabular-nums", midClass), children: [
@@ -2187,14 +2394,14 @@ function MobileOrderbookLayout({
2187
2394
  midChangePercent.toFixed(2),
2188
2395
  "%"
2189
2396
  ] })
2190
- ]
2397
+ ] })
2191
2398
  }
2192
2399
  ),
2193
2400
  /* @__PURE__ */ jsxRuntime.jsx("div", {})
2194
2401
  ]
2195
2402
  }
2196
2403
  ),
2197
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column" }, children: visibleBids.map((l, idx) => /* @__PURE__ */ jsxRuntime.jsx(
2404
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column" }, children: isLoading ? Array.from({ length: COMPACT_ROWS_VISIBLE }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonRow, { compact: true }, `m-bid-skel-${i}`)) : visibleBids.map((l) => /* @__PURE__ */ jsxRuntime.jsx(
2198
2405
  MobileDepthRow,
2199
2406
  {
2200
2407
  side: "bid",
@@ -2202,9 +2409,10 @@ function MobileOrderbookLayout({
2202
2409
  amount: l.amount,
2203
2410
  depthPct: (l.depth ?? l.amount) / maxBidDepth * 100,
2204
2411
  precision,
2205
- amountPrecision
2412
+ amountPrecision,
2413
+ hasUserOrder: userBidPrices.has(l.price)
2206
2414
  },
2207
- `mobile-bid-${idx}-${l.price}-${l.amount}`
2415
+ `mobile-bid-${l.price}`
2208
2416
  )) })
2209
2417
  ] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col overflow-hidden px-3 pb-2", children: [
2210
2418
  /* @__PURE__ */ jsxRuntime.jsxs(
@@ -2218,27 +2426,21 @@ function MobileOrderbookLayout({
2218
2426
  ]
2219
2427
  }
2220
2428
  ),
2221
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { flex: 1, overflowY: "auto", minHeight: 0 }, children: tradeFiltered.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-6 text-center text-[0.7rem] text-white/50", children: "No trades" }) : tradeFiltered.map((trade, i) => /* @__PURE__ */ jsxRuntime.jsxs(
2222
- "div",
2223
- {
2224
- className: "grid",
2225
- style: { gridTemplateColumns: "1.2fr 0.8fr", padding: "0.2rem 0", fontSize: "0.8rem" },
2226
- children: [
2227
- /* @__PURE__ */ jsxRuntime.jsxs(
2228
- "div",
2229
- {
2230
- style: { color: trade.type === "buy" ? "#0ecb81" : "#f6465d", fontWeight: 500 },
2231
- children: [
2232
- "$",
2233
- formatNumber(trade.price, precision)
2234
- ]
2235
- }
2236
- ),
2237
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { textAlign: "right", paddingRight: "0.5rem" }, children: formatNumber(trade.amount, amountPrecision) })
2238
- ]
2239
- },
2240
- `${trade.type}-${trade.price}-${trade.amount}-${trade.time ?? i}`
2241
- )) })
2429
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { flex: 1, overflowY: "auto", minHeight: 0 }, children: isLoading && tradeFiltered.length === 0 ? Array.from({ length: COMPACT_ROWS_VISIBLE }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonRow, { compact: true }, `m-trade-skel-${i}`)) : tradeFiltered.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-6 text-center text-[0.7rem] text-white/50", children: "No trades" }) : tradeFiltered.map((trade, i) => {
2430
+ const tradeKey = getTradeKey(trade, i);
2431
+ return /* @__PURE__ */ jsxRuntime.jsx(
2432
+ TradeRow,
2433
+ {
2434
+ trade,
2435
+ tradeKey,
2436
+ precision,
2437
+ amountPrecision,
2438
+ seenTradeKeysRef,
2439
+ compact: true
2440
+ },
2441
+ tradeKey
2442
+ );
2443
+ }) })
2242
2444
  ] })
2243
2445
  ] });
2244
2446
  }
@@ -2248,12 +2450,16 @@ function MobileDepthRow({
2248
2450
  amount,
2249
2451
  depthPct,
2250
2452
  precision,
2251
- amountPrecision
2453
+ amountPrecision,
2454
+ hasUserOrder
2252
2455
  }) {
2253
2456
  const isAsk = side === "ask";
2457
+ const rowRef = React9__namespace.useRef(null);
2458
+ useAmountChangeFlash(rowRef, amount);
2254
2459
  return /* @__PURE__ */ jsxRuntime.jsxs(
2255
2460
  "div",
2256
2461
  {
2462
+ ref: rowRef,
2257
2463
  style: {
2258
2464
  display: "grid",
2259
2465
  gridTemplateColumns: "1.2fr 0.8fr",
@@ -2262,6 +2468,24 @@ function MobileDepthRow({
2262
2468
  position: "relative"
2263
2469
  },
2264
2470
  children: [
2471
+ hasUserOrder ? /* @__PURE__ */ jsxRuntime.jsx(
2472
+ "span",
2473
+ {
2474
+ "aria-label": "Your order at this price",
2475
+ style: {
2476
+ position: "absolute",
2477
+ left: 0,
2478
+ top: 0,
2479
+ bottom: 0,
2480
+ width: "3px",
2481
+ backgroundColor: "#C9A227",
2482
+ boxShadow: "0 0 6px rgba(201,162,39,0.6)",
2483
+ borderTopRightRadius: "2px",
2484
+ borderBottomRightRadius: "2px",
2485
+ zIndex: 2
2486
+ }
2487
+ }
2488
+ ) : null,
2265
2489
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative", zIndex: 1, color: isAsk ? "#f6465d" : "#0ecb81" }, children: [
2266
2490
  "$",
2267
2491
  formatNumber(price, precision)
@@ -2278,7 +2502,8 @@ function MobileDepthRow({
2278
2502
  width: `${clamp3(depthPct, 0, 100)}%`,
2279
2503
  backgroundColor: isAsk ? "#f6465d" : "#0ecb81",
2280
2504
  opacity: 0.1,
2281
- zIndex: 0
2505
+ zIndex: 0,
2506
+ transition: "width 300ms ease-out"
2282
2507
  }
2283
2508
  }
2284
2509
  )
@@ -2286,7 +2511,7 @@ function MobileDepthRow({
2286
2511
  }
2287
2512
  );
2288
2513
  }
2289
- var PropertyTour = React5__namespace.forwardRef(
2514
+ var PropertyTour = React9__namespace.forwardRef(
2290
2515
  ({
2291
2516
  className,
2292
2517
  title,
@@ -2299,8 +2524,8 @@ var PropertyTour = React5__namespace.forwardRef(
2299
2524
  playsInline = true,
2300
2525
  ...props
2301
2526
  }, ref) => {
2302
- const videoRef = React5__namespace.useRef(null);
2303
- React5__namespace.useEffect(() => {
2527
+ const videoRef = React9__namespace.useRef(null);
2528
+ React9__namespace.useEffect(() => {
2304
2529
  const video = videoRef.current;
2305
2530
  if (!video) return;
2306
2531
  const handleFullscreenChange = () => {
@@ -2432,7 +2657,7 @@ var formatTimeAgo = (timestamp) => {
2432
2657
  if (diff < 3600) return `${Math.floor(diff / 60)}m ago`;
2433
2658
  return `${Math.floor(diff / 3600)}h ago`;
2434
2659
  };
2435
- var PropertyNewsUpdates = React5__namespace.forwardRef(
2660
+ var PropertyNewsUpdates = React9__namespace.forwardRef(
2436
2661
  ({
2437
2662
  className,
2438
2663
  heading,
@@ -2449,15 +2674,15 @@ var PropertyNewsUpdates = React5__namespace.forwardRef(
2449
2674
  const isPurchaseVariant = variant === "purchases";
2450
2675
  const isHomeVariant = variant === "home";
2451
2676
  const resolvedHeading = heading ?? (isPurchaseVariant ? "Live Purchases" : "Property News & Headlines");
2452
- const [homeTab, setHomeTab] = React5__namespace.useState("all");
2677
+ const [homeTab, setHomeTab] = React9__namespace.useState("all");
2453
2678
  const purchaseItems = purchasesProp ?? [];
2454
- const [page, setPage] = React5__namespace.useState(0);
2455
- React5__namespace.useEffect(() => {
2679
+ const [page, setPage] = React9__namespace.useState(0);
2680
+ React9__namespace.useEffect(() => {
2456
2681
  ensureAnimationsInjected();
2457
2682
  }, []);
2458
2683
  const hasItems = Array.isArray(items) && items.length > 0;
2459
- const totalPages = React5__namespace.useMemo(() => hasItems ? Math.max(1, Math.ceil(items.length / ITEMS_PER_PAGE)) : 1, [hasItems, items.length]);
2460
- React5__namespace.useEffect(() => {
2684
+ const totalPages = React9__namespace.useMemo(() => hasItems ? Math.max(1, Math.ceil(items.length / ITEMS_PER_PAGE)) : 1, [hasItems, items.length]);
2685
+ React9__namespace.useEffect(() => {
2461
2686
  setPage((prev) => Math.min(prev, totalPages - 1));
2462
2687
  }, [totalPages]);
2463
2688
  const paginatedItems = hasItems ? items.slice(page * ITEMS_PER_PAGE, page * ITEMS_PER_PAGE + ITEMS_PER_PAGE) : [];
@@ -2765,7 +2990,7 @@ var defaultFormat = (value) => new Intl.NumberFormat("en-US", {
2765
2990
  notation: value >= 1e5 ? "compact" : "standard",
2766
2991
  maximumFractionDigits: value >= 1e3 ? 0 : 2
2767
2992
  }).format(value);
2768
- var TradingSlider = React5__namespace.forwardRef(
2993
+ var TradingSlider = React9__namespace.forwardRef(
2769
2994
  ({
2770
2995
  label = "Trade size",
2771
2996
  helperText = "Drag to pick the desired notional.",
@@ -2783,7 +3008,7 @@ var TradingSlider = React5__namespace.forwardRef(
2783
3008
  ...rest
2784
3009
  }, ref) => {
2785
3010
  const isControlled = value !== void 0;
2786
- const [internalValue, setInternalValue] = React5__namespace.useState(
3011
+ const [internalValue, setInternalValue] = React9__namespace.useState(
2787
3012
  defaultValue ?? (typeof min === "number" ? min : 0)
2788
3013
  );
2789
3014
  const currentValue = isControlled ? Number(value) : internalValue;
@@ -2886,7 +3111,7 @@ var MobileToggleButton = styled24__default.default.button`
2886
3111
  padding: 0.6rem 0.5rem;
2887
3112
  }
2888
3113
  `;
2889
- var MobileTradeNav = React5__namespace.forwardRef(
3114
+ var MobileTradeNav = React9__namespace.forwardRef(
2890
3115
  ({ className, items, activeId, onChange, ...props }, ref) => {
2891
3116
  return /* @__PURE__ */ jsxRuntime.jsx(MobileToggleContainer, { ref, className: cn(className), ...props, children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsxs(
2892
3117
  MobileToggleButton,
@@ -3537,7 +3762,7 @@ var formatPercent = (value, fractionDigits = 2) => {
3537
3762
  if (value == null || Number.isNaN(value)) return "\u2014";
3538
3763
  return `${value.toFixed(fractionDigits)}%`;
3539
3764
  };
3540
- var YourOrders = React5__namespace.forwardRef(
3765
+ var YourOrders = React9__namespace.forwardRef(
3541
3766
  ({
3542
3767
  className,
3543
3768
  title,
@@ -3550,10 +3775,10 @@ var YourOrders = React5__namespace.forwardRef(
3550
3775
  pageSize: pageSizeOverride,
3551
3776
  ...props
3552
3777
  }, ref) => {
3553
- const [internalActiveTab, setInternalActiveTab] = React5__namespace.useState(tabs?.[0]?.id ?? "portfolio");
3554
- const [page, setPage] = React5__namespace.useState(0);
3778
+ const [internalActiveTab, setInternalActiveTab] = React9__namespace.useState(tabs?.[0]?.id ?? "portfolio");
3779
+ const [page, setPage] = React9__namespace.useState(0);
3555
3780
  const effectiveActiveTabId = activeTabId ?? internalActiveTab;
3556
- React5__namespace.useEffect(() => {
3781
+ React9__namespace.useEffect(() => {
3557
3782
  setPage(0);
3558
3783
  }, [effectiveActiveTabId]);
3559
3784
  const handleTabChange = (tabId) => {
@@ -3935,7 +4160,7 @@ function createCandlestickSeries(chart, options) {
3935
4160
  }
3936
4161
  throw new Error("Candlestick series API is not available in the current lightweight-charts version.");
3937
4162
  }
3938
- var PriceChart = React5__namespace.forwardRef(
4163
+ var PriceChart = React9__namespace.forwardRef(
3939
4164
  ({
3940
4165
  className,
3941
4166
  title = "Price Chart",
@@ -3949,18 +4174,18 @@ var PriceChart = React5__namespace.forwardRef(
3949
4174
  height = 301.52,
3950
4175
  ...props
3951
4176
  }, ref) => {
3952
- const containerRef = React5__namespace.useRef(null);
3953
- const chartRef = React5__namespace.useRef(null);
3954
- const seriesRef = React5__namespace.useRef(null);
3955
- const priceLineRef = React5__namespace.useRef(null);
3956
- const [hoveredRange, setHoveredRange] = React5__namespace.useState(null);
3957
- const [dropdownOpen, setDropdownOpen] = React5__namespace.useState(false);
3958
- const dropdownRef = React5__namespace.useRef(null);
3959
- const isAutoScrollRef = React5__namespace.useRef(true);
4177
+ const containerRef = React9__namespace.useRef(null);
4178
+ const chartRef = React9__namespace.useRef(null);
4179
+ const seriesRef = React9__namespace.useRef(null);
4180
+ const priceLineRef = React9__namespace.useRef(null);
4181
+ const [hoveredRange, setHoveredRange] = React9__namespace.useState(null);
4182
+ const [dropdownOpen, setDropdownOpen] = React9__namespace.useState(false);
4183
+ const dropdownRef = React9__namespace.useRef(null);
4184
+ const isAutoScrollRef = React9__namespace.useRef(true);
3960
4185
  const visibleRanges = ranges.slice(0, VISIBLE_RANGE_COUNT);
3961
4186
  const dropdownRanges = ranges.slice(VISIBLE_RANGE_COUNT);
3962
4187
  const selectedInDropdown = dropdownRanges.includes(selectedRange);
3963
- React5__namespace.useEffect(() => {
4188
+ React9__namespace.useEffect(() => {
3964
4189
  const handleClickOutside = (e) => {
3965
4190
  if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
3966
4191
  setDropdownOpen(false);
@@ -3969,25 +4194,25 @@ var PriceChart = React5__namespace.forwardRef(
3969
4194
  document.addEventListener("mousedown", handleClickOutside);
3970
4195
  return () => document.removeEventListener("mousedown", handleClickOutside);
3971
4196
  }, []);
3972
- const resolvedPrice = React5__namespace.useMemo(() => {
4197
+ const resolvedPrice = React9__namespace.useMemo(() => {
3973
4198
  if (price != null) return price;
3974
4199
  const last = data.at(-1);
3975
4200
  return last?.close;
3976
4201
  }, [data, price]);
3977
- const inferredChangePercent = React5__namespace.useMemo(() => {
4202
+ const inferredChangePercent = React9__namespace.useMemo(() => {
3978
4203
  if (changePercent != null) return changePercent;
3979
4204
  const first = data[0]?.open;
3980
4205
  const last = data.at(-1)?.close;
3981
4206
  if (first == null || last == null || first === 0) return void 0;
3982
4207
  return (last - first) / first * 100;
3983
4208
  }, [changePercent, data]);
3984
- const dollarChange = React5__namespace.useMemo(() => {
4209
+ const dollarChange = React9__namespace.useMemo(() => {
3985
4210
  const first = data[0]?.open;
3986
4211
  const last = data.at(-1)?.close;
3987
4212
  if (first == null || last == null) return void 0;
3988
4213
  return last - first;
3989
4214
  }, [data]);
3990
- React5__namespace.useEffect(() => {
4215
+ React9__namespace.useEffect(() => {
3991
4216
  const el = containerRef.current;
3992
4217
  if (!el) return;
3993
4218
  const chart = LightweightCharts__namespace.createChart(el, {
@@ -4032,7 +4257,7 @@ var PriceChart = React5__namespace.forwardRef(
4032
4257
  chart.remove();
4033
4258
  };
4034
4259
  }, []);
4035
- React5__namespace.useEffect(() => {
4260
+ React9__namespace.useEffect(() => {
4036
4261
  const chart = chartRef.current;
4037
4262
  if (!chart) return;
4038
4263
  const effectiveRange = selectedRange ?? ranges?.[0] ?? "1D";
@@ -4040,7 +4265,7 @@ var PriceChart = React5__namespace.forwardRef(
4040
4265
  timeScale: getTimeScaleOptions(effectiveRange)
4041
4266
  });
4042
4267
  }, [selectedRange, ranges]);
4043
- React5__namespace.useEffect(() => {
4268
+ React9__namespace.useEffect(() => {
4044
4269
  const chart = chartRef.current;
4045
4270
  const series = seriesRef.current;
4046
4271
  if (!chart || !series) return;
@@ -4245,7 +4470,7 @@ var formatPrice3 = (value, currencySymbol) => {
4245
4470
  maximumFractionDigits: 3
4246
4471
  })}`;
4247
4472
  };
4248
- var PropertyHeroHeader = React5__namespace.forwardRef(
4473
+ var PropertyHeroHeader = React9__namespace.forwardRef(
4249
4474
  ({
4250
4475
  className,
4251
4476
  imageUrl,
@@ -4266,14 +4491,15 @@ var PropertyHeroHeader = React5__namespace.forwardRef(
4266
4491
  makeOfferDisabled = false,
4267
4492
  hideMakeOfferButton = false,
4268
4493
  statusBadge,
4494
+ isLoading = false,
4269
4495
  ...props
4270
4496
  }, ref) => {
4271
4497
  const isPositive = changePercent == null ? void 0 : changePercent >= 0;
4272
4498
  const accentColor = "#e6c87e";
4273
4499
  const tradeHoverColor = "#f5dd9a";
4274
- const [isTradeInteracting, setIsTradeInteracting] = React5__namespace.useState(false);
4275
- const [isOfferInteracting, setIsOfferInteracting] = React5__namespace.useState(false);
4276
- const hasAmenities = beds != null || baths != null || cars != null || propertyTypeLabel != null;
4500
+ const [isTradeInteracting, setIsTradeInteracting] = React9__namespace.useState(false);
4501
+ const [isOfferInteracting, setIsOfferInteracting] = React9__namespace.useState(false);
4502
+ const hasAmenities = isLoading || beds != null || baths != null || cars != null || propertyTypeLabel != null;
4277
4503
  const isTradeDisabled = !onTrade;
4278
4504
  const isMakeOfferButtonDisabled = makeOfferDisabled || !onMakeOffer;
4279
4505
  const showMakeOfferButton = !hideMakeOfferButton;
@@ -4313,7 +4539,7 @@ var PropertyHeroHeader = React5__namespace.forwardRef(
4313
4539
  /* @__PURE__ */ jsxRuntime.jsx("h1", { style: headingStyle, className: "break-words", children: name }),
4314
4540
  /* @__PURE__ */ jsxRuntime.jsxs(InfoRow, { className: "mb-3 max-[768px]:mb-[0.6rem] max-[480px]:mb-[0.5rem]", children: [
4315
4541
  /* @__PURE__ */ jsxRuntime.jsx(LocationText, { children: location }),
4316
- price == null ? null : /* @__PURE__ */ jsxRuntime.jsxs(PriceBlock, { children: [
4542
+ isLoading ? /* @__PURE__ */ jsxRuntime.jsx(PriceBlock, { children: /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 110, height: 18 }) }) : price == null ? null : /* @__PURE__ */ jsxRuntime.jsxs(PriceBlock, { children: [
4317
4543
  formatPrice3(price, currencySymbol),
4318
4544
  changePercent == null ? null : /* @__PURE__ */ jsxRuntime.jsxs(
4319
4545
  "span",
@@ -4343,7 +4569,21 @@ var PropertyHeroHeader = React5__namespace.forwardRef(
4343
4569
  ] })
4344
4570
  ] })
4345
4571
  ] }),
4346
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-6 text-[0.95rem] text-white/90 max-[768px]:hidden", children: [
4572
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-6 text-[0.95rem] text-white/90 max-[768px]:hidden", children: isLoading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4573
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center", children: [
4574
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BedDouble, { className: "mr-2 h-[18px] w-[18px] opacity-60" }),
4575
+ /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 52, height: 14 })
4576
+ ] }),
4577
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center", children: [
4578
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Bath, { className: "mr-2 h-[18px] w-[18px] opacity-60" }),
4579
+ /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 56, height: 14 })
4580
+ ] }),
4581
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center", children: [
4582
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CarFront, { className: "mr-2 h-[18px] w-[18px] opacity-60" }),
4583
+ /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 50, height: 14 })
4584
+ ] }),
4585
+ /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 60, height: 14 })
4586
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4347
4587
  beds == null ? null : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center", children: [
4348
4588
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BedDouble, { className: "mr-2 h-[18px] w-[18px]" }),
4349
4589
  /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
@@ -4366,7 +4606,7 @@ var PropertyHeroHeader = React5__namespace.forwardRef(
4366
4606
  ] })
4367
4607
  ] }),
4368
4608
  propertyTypeLabel == null ? null : /* @__PURE__ */ jsxRuntime.jsx("div", { children: propertyTypeLabel })
4369
- ] })
4609
+ ] }) })
4370
4610
  ] }),
4371
4611
  /* @__PURE__ */ jsxRuntime.jsxs(ActionButtons, { children: [
4372
4612
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -4428,7 +4668,21 @@ var PropertyHeroHeader = React5__namespace.forwardRef(
4428
4668
  ] })
4429
4669
  ] }) })
4430
4670
  ] }),
4431
- hasAmenities ? /* @__PURE__ */ jsxRuntime.jsxs(MobileAmenities, { children: [
4671
+ hasAmenities ? /* @__PURE__ */ jsxRuntime.jsx(MobileAmenities, { children: isLoading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4672
+ /* @__PURE__ */ jsxRuntime.jsxs(MobileAmenity, { children: [
4673
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BedDouble, { className: "h-4 w-4 opacity-60" }),
4674
+ /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 40, height: 12 })
4675
+ ] }),
4676
+ /* @__PURE__ */ jsxRuntime.jsxs(MobileAmenity, { children: [
4677
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Bath, { className: "h-4 w-4 opacity-60" }),
4678
+ /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 44, height: 12 })
4679
+ ] }),
4680
+ /* @__PURE__ */ jsxRuntime.jsxs(MobileAmenity, { children: [
4681
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CarFront, { className: "h-4 w-4 opacity-60" }),
4682
+ /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 42, height: 12 })
4683
+ ] }),
4684
+ /* @__PURE__ */ jsxRuntime.jsx(MobileAmenity, { children: /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 52, height: 12 }) })
4685
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4432
4686
  beds == null ? null : /* @__PURE__ */ jsxRuntime.jsxs(MobileAmenity, { children: [
4433
4687
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BedDouble, { className: "h-4 w-4" }),
4434
4688
  /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
@@ -4451,7 +4705,7 @@ var PropertyHeroHeader = React5__namespace.forwardRef(
4451
4705
  ] })
4452
4706
  ] }),
4453
4707
  propertyTypeLabel == null ? null : /* @__PURE__ */ jsxRuntime.jsx(MobileAmenity, { children: propertyTypeLabel })
4454
- ] }) : null
4708
+ ] }) }) : null
4455
4709
  ] });
4456
4710
  }
4457
4711
  );
@@ -4688,12 +4942,21 @@ var Header = ({
4688
4942
  onWalletNavigate: _onWalletNavigate,
4689
4943
  showTradeTab = true
4690
4944
  }) => {
4691
- const [isUserMenuOpen, setIsUserMenuOpen] = React5.useState(false);
4692
- const [isMobileMenuOpen, setIsMobileMenuOpen] = React5.useState(false);
4693
- const [isMoreMenuOpen, setIsMoreMenuOpen] = React5.useState(false);
4694
- const [showLoginPopup, setShowLoginPopup] = React5.useState(false);
4695
- const [loginPopupInitialView, setLoginPopupInitialView] = React5.useState(void 0);
4696
- React5.useEffect(() => {
4945
+ const [isUserMenuOpen, setIsUserMenuOpen] = React9.useState(false);
4946
+ const [isMobileMenuOpen, setIsMobileMenuOpen] = React9.useState(false);
4947
+ const [isMoreMenuOpen, setIsMoreMenuOpen] = React9.useState(false);
4948
+ const [showLoginPopup, setShowLoginPopup] = React9.useState(false);
4949
+ const [loginPopupInitialView, setLoginPopupInitialView] = React9.useState(void 0);
4950
+ React9.useEffect(() => {
4951
+ if (typeof window === "undefined") return;
4952
+ const ua = navigator.userAgent;
4953
+ const isTelegram = /Telegram/i.test(ua);
4954
+ const isIOS = /iPhone|iPad|iPod/.test(ua);
4955
+ if (isTelegram && isIOS) {
4956
+ document.documentElement.style.setProperty("--telegram-safe-top", "59px");
4957
+ }
4958
+ }, []);
4959
+ React9.useEffect(() => {
4697
4960
  const handleClickOutside = (event) => {
4698
4961
  const target = event.target;
4699
4962
  if (!target) return;
@@ -4713,7 +4976,7 @@ var Header = ({
4713
4976
  document.removeEventListener("mousedown", handleClickOutside);
4714
4977
  };
4715
4978
  }, [isUserMenuOpen, isMobileMenuOpen, isMoreMenuOpen]);
4716
- React5.useEffect(() => {
4979
+ React9.useEffect(() => {
4717
4980
  if (typeof window === "undefined") return;
4718
4981
  const handleExternalLoginPopup = (event) => {
4719
4982
  const customEvent = event;
@@ -4843,7 +5106,7 @@ var Header = ({
4843
5106
  setShowLoginPopup(true);
4844
5107
  }
4845
5108
  };
4846
- const handleLoginPopupClose = React5__namespace.default.useCallback(() => {
5109
+ const handleLoginPopupClose = React9__namespace.default.useCallback(() => {
4847
5110
  setShowLoginPopup(false);
4848
5111
  setLoginPopupInitialView(void 0);
4849
5112
  }, []);
@@ -4877,7 +5140,7 @@ var Header = ({
4877
5140
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4878
5141
  /* @__PURE__ */ jsxRuntime.jsx(SafeAreaCover, {}),
4879
5142
  /* @__PURE__ */ jsxRuntime.jsx(Overlay, { $isOpen: isMobileMenuOpen, onClick: () => setIsMobileMenuOpen(false) }),
4880
- /* @__PURE__ */ jsxRuntime.jsxs(HeaderContainer, { children: [
5143
+ /* @__PURE__ */ jsxRuntime.jsxs(HeaderContainer, { id: "loaf-header", children: [
4881
5144
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center" }, children: [
4882
5145
  /* @__PURE__ */ jsxRuntime.jsxs(Logo, { children: [
4883
5146
  /* @__PURE__ */ jsxRuntime.jsx(LogoLink, { href: logoHref ?? resolvedHomePath, onClick: handleLogoNavigation, children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: Loaf_logo_Banner_default, alt: "LOAF Logo" }) }),
@@ -5115,6 +5378,7 @@ var Header = ({
5115
5378
  )
5116
5379
  ] })
5117
5380
  ] }),
5381
+ /* @__PURE__ */ jsxRuntime.jsx(HeaderSpacer, {}),
5118
5382
  LoginPopupComponent && showLoginPopup && /* @__PURE__ */ jsxRuntime.jsx(
5119
5383
  LoginPopupComponent,
5120
5384
  {
@@ -5130,8 +5394,8 @@ var SafeAreaCover = styled24__default.default.div`
5130
5394
  top: 0;
5131
5395
  left: 0;
5132
5396
  right: 0;
5133
- height: env(safe-area-inset-top, 0px);
5134
- min-height: env(safe-area-inset-top, 0px);
5397
+ height: max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px));
5398
+ min-height: max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px));
5135
5399
  background-color: #0d1117;
5136
5400
  z-index: 1001;
5137
5401
  pointer-events: none;
@@ -5185,23 +5449,31 @@ var HeaderContainer = styled24__default.default.header`
5185
5449
  /* Split padding so browsers that don't support env() inside shorthand
5186
5450
  still get the horizontal padding — only the top falls back to 0 */
5187
5451
  padding: 0 2rem;
5188
- padding-top: env(safe-area-inset-top, 0px);
5452
+ padding-top: max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px));
5189
5453
  background-color: #0d1117;
5190
5454
  border-bottom: 1px solid #232a32;
5191
- position: sticky;
5455
+ position: fixed;
5192
5456
  top: 0;
5457
+ left: 0;
5458
+ right: 0;
5193
5459
  z-index: 1000;
5194
5460
  width: 100%;
5195
5461
  /* Fallback min-height for browsers that can't evaluate calc+env */
5196
5462
  min-height: 56px;
5197
- min-height: calc(56px + env(safe-area-inset-top, 0px));
5463
+ min-height: calc(56px + max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px)));
5198
5464
  box-sizing: border-box;
5199
5465
 
5200
5466
  @media (max-width: 768px) {
5201
5467
  padding: 0 1rem;
5202
- padding-top: env(safe-area-inset-top, 0px);
5468
+ padding-top: max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px));
5203
5469
  }
5204
5470
  `;
5471
+ var HeaderSpacer = styled24__default.default.div`
5472
+ width: 100%;
5473
+ min-height: 56px;
5474
+ min-height: calc(56px + max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px)));
5475
+ flex-shrink: 0;
5476
+ `;
5205
5477
  var Logo = styled24__default.default.div`
5206
5478
  display: flex;
5207
5479
  align-items: center;
@@ -5254,10 +5526,12 @@ var Nav = styled24__default.default.nav`
5254
5526
  @media (max-width: 1300px) {
5255
5527
  position: fixed;
5256
5528
  top: 56px;
5529
+ top: calc(56px + max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px)));
5257
5530
  right: ${(props) => props.$isOpen ? "0" : "-100%"} ;
5258
5531
  width: 280px;
5259
5532
  max-width: 280px;
5260
5533
  height: calc(100vh - 56px);
5534
+ height: calc(100vh - 56px - max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px)));
5261
5535
  background: linear-gradient(180deg, #0f1419 0%, #0a0e13 100%);
5262
5536
  z-index: 1000;
5263
5537
  transition: right 0.3s ease;
@@ -5530,10 +5804,10 @@ var MobileNavItem = styled24__default.default.div`
5530
5804
  padding-left: 24px;
5531
5805
  }
5532
5806
  `;
5533
- var PropertySubheader = React5__namespace.forwardRef(
5807
+ var PropertySubheader = React9__namespace.forwardRef(
5534
5808
  ({ className, tabs, activeTabId, onTabChange, actions, ...props }, ref) => {
5535
- const tabsContainerRef = React5__namespace.useRef(null);
5536
- React5__namespace.useEffect(() => {
5809
+ const tabsContainerRef = React9__namespace.useRef(null);
5810
+ React9__namespace.useEffect(() => {
5537
5811
  const container = tabsContainerRef.current;
5538
5812
  if (!container) return;
5539
5813
  const isMobile = window.innerWidth <= 768;
@@ -5675,27 +5949,27 @@ var LoginPopup = ({
5675
5949
  onFundWallet,
5676
5950
  initialView
5677
5951
  }) => {
5678
- const [view, setView] = React5.useState(() => initialView ?? "main");
5679
- const [email, setEmail] = React5.useState("");
5680
- const [handle, setHandle] = React5.useState("");
5681
- const [otp, setOtp] = React5.useState(Array(OTP_INPUT_LENGTH).fill(""));
5682
- const [error, setError] = React5.useState("");
5683
- const [loading, setLoading] = React5.useState(false);
5684
- const [isSignUp, setIsSignUp] = React5.useState(false);
5685
- const [fundingAmount] = React5.useState("");
5686
- const [kycLoading, setKycLoading] = React5.useState(false);
5687
- const [showKycWidget, setShowKycWidget] = React5.useState(false);
5688
- const [cryptoFundingLoading, setCryptoFundingLoading] = React5.useState(false);
5689
- const [fiatFundingLoading, setFiatFundingLoading] = React5.useState(false);
5690
- const [fundingError, setFundingError] = React5.useState("");
5691
- const [transakWidgetUrl, setTransakWidgetUrl] = React5.useState(null);
5692
- const suppressAutoCloseRef = React5__namespace.default.useRef(false);
5693
- React5.useEffect(() => {
5952
+ const [view, setView] = React9.useState(() => initialView ?? "main");
5953
+ const [email, setEmail] = React9.useState("");
5954
+ const [handle, setHandle] = React9.useState("");
5955
+ const [otp, setOtp] = React9.useState(Array(OTP_INPUT_LENGTH).fill(""));
5956
+ const [error, setError] = React9.useState("");
5957
+ const [loading, setLoading] = React9.useState(false);
5958
+ const [isSignUp, setIsSignUp] = React9.useState(false);
5959
+ const [fundingAmount] = React9.useState("");
5960
+ const [kycLoading, setKycLoading] = React9.useState(false);
5961
+ const [showKycWidget, setShowKycWidget] = React9.useState(false);
5962
+ const [cryptoFundingLoading, setCryptoFundingLoading] = React9.useState(false);
5963
+ const [fiatFundingLoading, setFiatFundingLoading] = React9.useState(false);
5964
+ const [fundingError, setFundingError] = React9.useState("");
5965
+ const [transakWidgetUrl, setTransakWidgetUrl] = React9.useState(null);
5966
+ const suppressAutoCloseRef = React9__namespace.default.useRef(false);
5967
+ React9.useEffect(() => {
5694
5968
  if (typeof initialView === "string") {
5695
5969
  setView(initialView);
5696
5970
  }
5697
5971
  }, [initialView]);
5698
- React5.useEffect(() => {
5972
+ React9.useEffect(() => {
5699
5973
  if (!transakWidgetUrl) return;
5700
5974
  const handleTransakMessage = (event) => {
5701
5975
  if (!event.origin.includes("transak.com") && !event.origin.includes("global.transak.com")) {
@@ -5720,7 +5994,7 @@ var LoginPopup = ({
5720
5994
  window.addEventListener("message", handleTransakMessage);
5721
5995
  return () => window.removeEventListener("message", handleTransakMessage);
5722
5996
  }, [transakWidgetUrl, onClose]);
5723
- React5.useEffect(() => {
5997
+ React9.useEffect(() => {
5724
5998
  if (!autoCloseOnAuth) {
5725
5999
  return;
5726
6000
  }
@@ -6692,8 +6966,8 @@ var TransakIframe = styled24__default.default.iframe`
6692
6966
  border-radius: var(--border-radius, 12px);
6693
6967
  `;
6694
6968
  var MiniLiveFeed = () => {
6695
- const [purchases, setPurchases] = React5.useState([]);
6696
- React5.useEffect(() => {
6969
+ const [purchases, setPurchases] = React9.useState([]);
6970
+ React9.useEffect(() => {
6697
6971
  const handles = [
6698
6972
  "Landlord",
6699
6973
  "PropertyKing",
@@ -6869,7 +7143,7 @@ var MiniLiveFeed = () => {
6869
7143
  );
6870
7144
  };
6871
7145
  LoginPopup.displayName = "LoginPopup";
6872
- var PropertyCompareBar = React5__namespace.forwardRef(
7146
+ var PropertyCompareBar = React9__namespace.forwardRef(
6873
7147
  ({
6874
7148
  className,
6875
7149
  addresses,
@@ -6880,7 +7154,7 @@ var PropertyCompareBar = React5__namespace.forwardRef(
6880
7154
  price,
6881
7155
  ...props
6882
7156
  }, ref) => {
6883
- const normalizedAddresses = React5__namespace.useMemo(() => {
7157
+ const normalizedAddresses = React9__namespace.useMemo(() => {
6884
7158
  return addresses.map(
6885
7159
  (option) => typeof option === "string" ? { id: option, label: option } : option
6886
7160
  );
@@ -6888,11 +7162,11 @@ var PropertyCompareBar = React5__namespace.forwardRef(
6888
7162
  const hasAddresses = normalizedAddresses.length > 0;
6889
7163
  const firstAddressId = normalizedAddresses[0]?.id;
6890
7164
  const isControlled = selectedAddressId !== void 0;
6891
- const [internalSelectedId, setInternalSelectedId] = React5__namespace.useState(
7165
+ const [internalSelectedId, setInternalSelectedId] = React9__namespace.useState(
6892
7166
  () => isControlled ? void 0 : firstAddressId
6893
7167
  );
6894
7168
  const resolvedSelectedId = isControlled ? selectedAddressId : internalSelectedId;
6895
- React5__namespace.useEffect(() => {
7169
+ React9__namespace.useEffect(() => {
6896
7170
  if (!isControlled) {
6897
7171
  setInternalSelectedId((current) => {
6898
7172
  if (current != null && normalizedAddresses.some((option) => option.id === current)) {
@@ -6903,9 +7177,9 @@ var PropertyCompareBar = React5__namespace.forwardRef(
6903
7177
  }
6904
7178
  }, [firstAddressId, isControlled, normalizedAddresses]);
6905
7179
  const selectedOption = normalizedAddresses.find((option) => option.id === resolvedSelectedId) ?? normalizedAddresses[0];
6906
- const [isDropdownOpen, setIsDropdownOpen] = React5__namespace.useState(false);
6907
- const dropdownRef = React5__namespace.useRef(null);
6908
- React5__namespace.useEffect(() => {
7180
+ const [isDropdownOpen, setIsDropdownOpen] = React9__namespace.useState(false);
7181
+ const dropdownRef = React9__namespace.useRef(null);
7182
+ React9__namespace.useEffect(() => {
6909
7183
  if (!isDropdownOpen) return;
6910
7184
  const handleClick = (event) => {
6911
7185
  if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
@@ -7308,11 +7582,11 @@ function GalleryMapSection({
7308
7582
  autoPlay = true,
7309
7583
  autoPlayInterval = 4e3
7310
7584
  }) {
7311
- const [carouselIndex, setCarouselIndex] = React5.useState(0);
7312
- const [showVideo, setShowVideo] = React5.useState(false);
7313
- const [autoPlaying, setAutoPlaying] = React5.useState(autoPlay);
7585
+ const [carouselIndex, setCarouselIndex] = React9.useState(0);
7586
+ const [showVideo, setShowVideo] = React9.useState(false);
7587
+ const [autoPlaying, setAutoPlaying] = React9.useState(autoPlay);
7314
7588
  const resolvedMapUrl = mapUrl ?? (tokenName ? `/map/${tokenName}?embed=true&zoom=14&hideOthers=true` : "about:blank");
7315
- React5.useEffect(() => {
7589
+ React9.useEffect(() => {
7316
7590
  if (!autoPlaying || images.length <= 1) return;
7317
7591
  const interval = setInterval(() => {
7318
7592
  setCarouselIndex((p) => (p + 1) % images.length);
@@ -7628,9 +7902,10 @@ function PropertyOverview({
7628
7902
  bathrooms,
7629
7903
  carSpaces,
7630
7904
  propertyTypeLabel,
7631
- tokensIssued: tokensIssuedProp
7905
+ tokensIssued: tokensIssuedProp,
7906
+ isLoading = false
7632
7907
  }) {
7633
- const [isDescExpanded, setDescExpanded] = React5.useState(false);
7908
+ const [isDescExpanded, setDescExpanded] = React9.useState(false);
7634
7909
  const description = descriptionProp ?? overviewData?.description ?? DEFAULT_DESCRIPTION;
7635
7910
  const landSize = landProp ?? overviewData?.landSizeSqm ?? null;
7636
7911
  const buildingSize = buildingProp ?? overviewData?.buildingSizeSqm ?? null;
@@ -7666,13 +7941,14 @@ function PropertyOverview({
7666
7941
  const weeklyRent = overviewData?.weeklyRent ?? 0;
7667
7942
  const annualRent = weeklyRent * 52;
7668
7943
  const dividendYield = resolvedValuation && annualRent > 0 ? (annualRent / resolvedValuation * 100).toFixed(2) : null;
7944
+ const loadingSkeleton = /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 90, height: 18 });
7669
7945
  const financialItems = financialItemsProp ?? [
7670
- { label: "Token Price", value: tokenPriceValue ? `$${tokenPriceValue.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}` : "N/A", gold: true },
7671
- { label: "Property Value", value: resolvedValuation ? resolvedValuation >= 1e6 ? `$${(resolvedValuation / 1e6).toFixed(2)}M` : `$${resolvedValuation.toLocaleString()}` : "N/A" },
7672
- { label: "Weekly Rent", value: weeklyRent > 0 ? `$${weeklyRent.toLocaleString()}/wk` : "N/A", badge: weeklyRent > 0 ? "Rented" : void 0 },
7673
- { label: "Dividend Yield", value: dividendYield ? `${dividendYield}%` : "N/A" },
7674
- { label: "Total Tokens", value: resolvedTokensIssued ? resolvedTokensIssued.toLocaleString() : "N/A" },
7675
- { label: "Indicative Listing", value: overviewData?.indicativeListing ?? "N/A" }
7946
+ { label: "Token Price", value: isLoading && tokenPriceValue == null ? loadingSkeleton : tokenPriceValue ? `$${tokenPriceValue.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}` : "N/A", gold: true },
7947
+ { label: "Property Value", value: isLoading && resolvedValuation == null ? loadingSkeleton : resolvedValuation ? resolvedValuation >= 1e6 ? `$${(resolvedValuation / 1e6).toFixed(2)}M` : `$${resolvedValuation.toLocaleString()}` : "N/A" },
7948
+ { label: "Weekly Rent", value: isLoading && !overviewData ? loadingSkeleton : weeklyRent > 0 ? `$${weeklyRent.toLocaleString()}/wk` : "N/A", badge: weeklyRent > 0 ? "Rented" : void 0 },
7949
+ { label: "Dividend Yield", value: isLoading && dividendYield == null && resolvedValuation == null ? loadingSkeleton : dividendYield ? `${dividendYield}%` : "N/A" },
7950
+ { label: "Total Tokens", value: isLoading && resolvedTokensIssued == null ? loadingSkeleton : resolvedTokensIssued ? resolvedTokensIssued.toLocaleString() : "N/A" },
7951
+ { label: "Indicative Listing", value: isLoading && !overviewData ? loadingSkeleton : overviewData?.indicativeListing ?? "N/A" }
7676
7952
  ];
7677
7953
  const galleryImages = images ?? [];
7678
7954
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
@@ -7976,8 +8252,8 @@ var OfferPricePulse = styled24__default.default.span`
7976
8252
  `;
7977
8253
  var eventTypes = ["Leased", "Renovated", "Extended", "Rebuilt", "Rezoned", "DA Approval"];
7978
8254
  function PropertyHistory() {
7979
- const [historyFilter, setHistoryFilter] = React5.useState("all");
7980
- const pastSales = React5.useMemo(() => generateMockPastSales(), []);
8255
+ const [historyFilter, setHistoryFilter] = React9.useState("all");
8256
+ const pastSales = React9.useMemo(() => generateMockPastSales(), []);
7981
8257
  const loafListing = pastSales.find((sale) => sale.type === "Listed");
7982
8258
  const loafEvents = pastSales.filter(
7983
8259
  (sale) => sale.ownershipPeriod === "current" && sale.type !== "Listed" && (sale.id === "leased-current" || sale.id === "da-approval")
@@ -8114,7 +8390,7 @@ function PropertyHistory() {
8114
8390
  ] });
8115
8391
  }
8116
8392
  function EventDetails({ event }) {
8117
- const [expanded, setExpanded] = React5.useState(false);
8393
+ const [expanded, setExpanded] = React9.useState(false);
8118
8394
  const toggleExpand = () => {
8119
8395
  setExpanded((prev) => !prev);
8120
8396
  };
@@ -8902,7 +9178,7 @@ function AssetSelectorBar({
8902
9178
  selectorItems,
8903
9179
  onSelect
8904
9180
  }) {
8905
- const [isDropdownOpen, setIsDropdownOpen] = React5.useState(false);
9181
+ const [isDropdownOpen, setIsDropdownOpen] = React9.useState(false);
8906
9182
  const hasItems = selectorItems && selectorItems.length > 0;
8907
9183
  const metrics = metricsProp ?? [
8908
9184
  ...tokenPrice != null ? [{ label: "Unit Price", value: `$${tokenPrice.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`, accent: true }] : [],
@@ -9171,15 +9447,15 @@ function OfferingProgressCard({
9171
9447
  targetAmount,
9172
9448
  isPrivateClient = false
9173
9449
  }) {
9174
- const [currentTime, setCurrentTime] = React5.useState(/* @__PURE__ */ new Date());
9175
- const [countdown, setCountdown] = React5.useState(null);
9450
+ const [currentTime, setCurrentTime] = React9.useState(/* @__PURE__ */ new Date());
9451
+ const [countdown, setCountdown] = React9.useState(null);
9176
9452
  const computedRaised = raisedAmount ?? totalSold * tokenPrice;
9177
9453
  const computedTarget = targetAmount ?? supplyToSell * tokenPrice;
9178
- React5.useEffect(() => {
9454
+ React9.useEffect(() => {
9179
9455
  const timer = setInterval(() => setCurrentTime(/* @__PURE__ */ new Date()), 1e3);
9180
9456
  return () => clearInterval(timer);
9181
9457
  }, []);
9182
- React5.useEffect(() => {
9458
+ React9.useEffect(() => {
9183
9459
  if (!opensAt) {
9184
9460
  setCountdown(null);
9185
9461
  return;
@@ -9516,14 +9792,19 @@ var formatTimeAgo2 = (timestamp) => {
9516
9792
  };
9517
9793
  function VideoActivitySection({
9518
9794
  ipoStarted,
9795
+ ipoEnded = false,
9796
+ isLoading = false,
9519
9797
  recentOrders = [],
9520
9798
  ordersAllocated = 0,
9521
9799
  tokenPrice = 0
9522
9800
  }) {
9523
- const sortedOrders = React5.useMemo(
9801
+ const sortedOrders = React9.useMemo(
9524
9802
  () => [...recentOrders].sort((a, b) => b.timestamp - a.timestamp).slice(0, 7),
9525
9803
  [recentOrders]
9526
9804
  );
9805
+ 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";
9806
+ const showSkeletonFeed = ipoStarted && isLoading && sortedOrders.length === 0;
9807
+ const showOrderFeed = !showSkeletonFeed && (ipoStarted || ipoEnded && sortedOrders.length > 0);
9527
9808
  return /* @__PURE__ */ jsxRuntime.jsxs(Section3, { children: [
9528
9809
  /* @__PURE__ */ jsxRuntime.jsxs(VideoPanel, { children: [
9529
9810
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "section-header", children: /* @__PURE__ */ jsxRuntime.jsx("h3", { children: "Musgrave" }) }),
@@ -9535,31 +9816,40 @@ function VideoActivitySection({
9535
9816
  /* @__PURE__ */ jsxRuntime.jsxs(ActivityPanel, { children: [
9536
9817
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "section-header", children: [
9537
9818
  /* @__PURE__ */ jsxRuntime.jsxs("h3", { children: [
9538
- /* @__PURE__ */ jsxRuntime.jsx(LiveIndicatorDot, { $active: ipoStarted }),
9819
+ /* @__PURE__ */ jsxRuntime.jsx(LiveIndicatorDot, { $active: ipoStarted && !ipoEnded }),
9539
9820
  "Recent Order Activity"
9540
9821
  ] }),
9541
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: ipoStarted ? `Active orders: ${ordersAllocated.toLocaleString()}` : "Waiting for Offer to Open" })
9822
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: headerStatusText })
9542
9823
  ] }),
9543
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "activity-content", children: ipoStarted ? /* @__PURE__ */ jsxRuntime.jsx(FeedList, { children: sortedOrders.map((order, index) => {
9544
- const amount = tokenPrice * order.quantity;
9545
- const barPercent = Math.min(85, Math.max(15, amount / MAX_DISPLAY_AMOUNT * 100));
9546
- const isAlternate = index % 2 === 1;
9547
- return /* @__PURE__ */ jsxRuntime.jsxs(
9548
- PurchaseItem,
9549
- {
9550
- $barWidth: `${barPercent}%`,
9551
- $isAlternate: isAlternate,
9552
- children: [
9553
- /* @__PURE__ */ jsxRuntime.jsxs(PurchaseInfo, { children: [
9554
- /* @__PURE__ */ jsxRuntime.jsx(PurchaseName, { children: order.buyerHandle || `${order.buyerAddress.slice(0, 6)}...${order.buyerAddress.slice(-4)}` }),
9555
- /* @__PURE__ */ jsxRuntime.jsx(PurchaseTime, { children: formatTimeAgo2(order.timestamp) })
9556
- ] }),
9557
- /* @__PURE__ */ jsxRuntime.jsx(PurchaseAmount, { children: formatCurrency4(amount) })
9558
- ]
9559
- },
9560
- order.txHash
9561
- );
9562
- }) }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "activity-empty", children: [
9824
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "activity-content", children: showSkeletonFeed ? /* @__PURE__ */ jsxRuntime.jsx(FeedList, { children: Array.from({ length: 6 }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsxs(SkeletonFeedRow, { children: [
9825
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "info-col", children: [
9826
+ /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 110, height: 14 }),
9827
+ /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 56, height: 10 })
9828
+ ] }),
9829
+ /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 70, height: 14 })
9830
+ ] }, `feed-skel-${i}`)) }) : showOrderFeed ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
9831
+ ipoEnded && /* @__PURE__ */ jsxRuntime.jsx(EndedBanner, { children: "Sale ended \u2014 final allocations" }),
9832
+ /* @__PURE__ */ jsxRuntime.jsx(FeedList, { children: sortedOrders.map((order, index) => {
9833
+ const amount = tokenPrice * order.quantity;
9834
+ const barPercent = Math.min(85, Math.max(15, amount / MAX_DISPLAY_AMOUNT * 100));
9835
+ const isAlternate = index % 2 === 1;
9836
+ return /* @__PURE__ */ jsxRuntime.jsxs(
9837
+ PurchaseItem,
9838
+ {
9839
+ $barWidth: `${barPercent}%`,
9840
+ $isAlternate: isAlternate,
9841
+ children: [
9842
+ /* @__PURE__ */ jsxRuntime.jsxs(PurchaseInfo, { children: [
9843
+ /* @__PURE__ */ jsxRuntime.jsx(PurchaseName, { children: order.buyerHandle || `${order.buyerAddress.slice(0, 6)}...${order.buyerAddress.slice(-4)}` }),
9844
+ /* @__PURE__ */ jsxRuntime.jsx(PurchaseTime, { children: formatTimeAgo2(order.timestamp) })
9845
+ ] }),
9846
+ /* @__PURE__ */ jsxRuntime.jsx(PurchaseAmount, { children: formatCurrency4(amount) })
9847
+ ]
9848
+ },
9849
+ order.txHash
9850
+ );
9851
+ }) })
9852
+ ] }) : ipoEnded ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "activity-empty", children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Sale ended \u2014 no orders were placed." }) }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "activity-empty", children: [
9563
9853
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "spinner" }),
9564
9854
  /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Activity will appear once the Offering opens" })
9565
9855
  ] }) })
@@ -9700,6 +9990,43 @@ var ActivityPanel = styled24__default.default.div`
9700
9990
  to { transform: rotate(360deg); }
9701
9991
  }
9702
9992
  `;
9993
+ var SkeletonFeedRow = styled24__default.default.div`
9994
+ padding: 0.625rem 0.75rem;
9995
+ border-bottom: 1px solid rgba(255,255,255,0.04);
9996
+ display: flex;
9997
+ justify-content: space-between;
9998
+ align-items: center;
9999
+ gap: 1rem;
10000
+
10001
+ &:last-child {
10002
+ border-bottom: none;
10003
+ }
10004
+
10005
+ .info-col {
10006
+ display: flex;
10007
+ flex-direction: column;
10008
+ gap: 0.3rem;
10009
+ min-width: 0;
10010
+ flex: 1;
10011
+ }
10012
+
10013
+ @media (max-width: 768px) {
10014
+ padding: 0.4rem 0.6rem;
10015
+ }
10016
+ `;
10017
+ var EndedBanner = styled24__default.default.div`
10018
+ font-size: 0.7rem;
10019
+ font-weight: 600;
10020
+ letter-spacing: 0.04em;
10021
+ text-transform: uppercase;
10022
+ color: rgba(255, 255, 255, 0.55);
10023
+ background: rgba(255, 255, 255, 0.04);
10024
+ border: 1px solid rgba(255, 255, 255, 0.08);
10025
+ border-radius: 6px;
10026
+ padding: 0.4rem 0.6rem;
10027
+ margin-bottom: 0.5rem;
10028
+ text-align: center;
10029
+ `;
9703
10030
  var FeedList = styled24__default.default.div`
9704
10031
  width: 100%;
9705
10032
  overflow-y: auto;
@@ -9817,10 +10144,10 @@ function OrderPanel({
9817
10144
  tokenDisplayName,
9818
10145
  tokenSymbol
9819
10146
  }) {
9820
- const [payInputValue, setPayInputValue] = React5.useState("");
9821
- const [receiveInputValue, setReceiveInputValue] = React5.useState("");
9822
- const [isPayInputFocused, setIsPayInputFocused] = React5.useState(false);
9823
- const [isReceiveInputFocused, setIsReceiveInputFocused] = React5.useState(false);
10147
+ const [payInputValue, setPayInputValue] = React9.useState("");
10148
+ const [receiveInputValue, setReceiveInputValue] = React9.useState("");
10149
+ const [isPayInputFocused, setIsPayInputFocused] = React9.useState(false);
10150
+ const [isReceiveInputFocused, setIsReceiveInputFocused] = React9.useState(false);
9824
10151
  const handlePayBlur = () => {
9825
10152
  setIsPayInputFocused(false);
9826
10153
  const parsed = parseInt(payInputValue.replace(/[^0-9]/g, ""), 10) || 0;
@@ -10666,9 +10993,9 @@ function PortfolioActivityPanel({
10666
10993
  style
10667
10994
  }) {
10668
10995
  const resolvedDefaultTab = defaultTab ?? (showPositionsTab ? "positions" : "subscriptions");
10669
- const [activeTab, setActiveTab] = React5.useState(resolvedDefaultTab);
10670
- const [activityPage, setActivityPage] = React5.useState(0);
10671
- const activeTabTotal = React5.useMemo(() => {
10996
+ const [activeTab, setActiveTab] = React9.useState(resolvedDefaultTab);
10997
+ const [activityPage, setActivityPage] = React9.useState(0);
10998
+ const activeTabTotal = React9.useMemo(() => {
10672
10999
  switch (activeTab) {
10673
11000
  case "positions":
10674
11001
  return positions.length;
@@ -10686,6 +11013,22 @@ function PortfolioActivityPanel({
10686
11013
  return 0;
10687
11014
  }
10688
11015
  }, [activeTab, positions.length, offeringOrders.length, openOrders.length, orderHistory.length, tradeHistory.length, transfers.length]);
11016
+ const positionsCount = positions.length;
11017
+ const openOrdersCount = React9.useMemo(
11018
+ () => openOrders.filter((o) => o.status === "OPEN" || o.status === "PARTIALLY_FILLED").length,
11019
+ [openOrders]
11020
+ );
11021
+ const pendingHistoryCount = React9.useMemo(
11022
+ () => orderHistory.filter((o) => o.status === "OPEN" || o.status === "PARTIALLY_FILLED").length,
11023
+ [orderHistory]
11024
+ );
11025
+ const pendingOfferingsCount = React9.useMemo(
11026
+ () => offeringOrders.filter((o) => {
11027
+ const s = o.status.toUpperCase();
11028
+ return s !== "FILLED" && s !== "ALLOCATED" && s !== "CONFIRMED" && s !== "CANCELLED" && s !== "CANCELED" && s !== "REJECTED";
11029
+ }).length,
11030
+ [offeringOrders]
11031
+ );
10689
11032
  const activityTotalPages = Math.ceil(activeTabTotal / pageSize);
10690
11033
  const pageSlice = (arr) => arr.slice(activityPage * pageSize, (activityPage + 1) * pageSize);
10691
11034
  const handleTabChange = (tab) => {
@@ -10695,10 +11038,38 @@ function PortfolioActivityPanel({
10695
11038
  return /* @__PURE__ */ jsxRuntime.jsxs(Container2, { className, style, children: [
10696
11039
  /* @__PURE__ */ jsxRuntime.jsx(PanelTitle, { children: "Activity" }),
10697
11040
  /* @__PURE__ */ jsxRuntime.jsxs(TabContainer, { children: [
10698
- showPositionsTab && /* @__PURE__ */ jsxRuntime.jsx(Tab, { $active: activeTab === "positions", onClick: () => handleTabChange("positions"), children: "Positions" }),
10699
- /* @__PURE__ */ jsxRuntime.jsx(Tab, { $active: activeTab === "subscriptions", onClick: () => handleTabChange("subscriptions"), children: "Initial Offerings" }),
10700
- /* @__PURE__ */ jsxRuntime.jsx(Tab, { $active: activeTab === "open-orders", onClick: () => handleTabChange("open-orders"), children: "Open Orders" }),
10701
- /* @__PURE__ */ jsxRuntime.jsx(Tab, { $active: activeTab === "orders", onClick: () => handleTabChange("orders"), children: "Order History" }),
11041
+ showPositionsTab && /* @__PURE__ */ jsxRuntime.jsxs(Tab, { $active: activeTab === "positions", onClick: () => handleTabChange("positions"), children: [
11042
+ "Positions",
11043
+ positionsCount > 0 && /* @__PURE__ */ jsxRuntime.jsxs(TabCount, { children: [
11044
+ " (",
11045
+ positionsCount,
11046
+ ")"
11047
+ ] })
11048
+ ] }),
11049
+ /* @__PURE__ */ jsxRuntime.jsxs(Tab, { $active: activeTab === "subscriptions", onClick: () => handleTabChange("subscriptions"), children: [
11050
+ "Initial Offerings",
11051
+ pendingOfferingsCount > 0 && /* @__PURE__ */ jsxRuntime.jsxs(TabCount, { children: [
11052
+ " (",
11053
+ pendingOfferingsCount,
11054
+ ")"
11055
+ ] })
11056
+ ] }),
11057
+ /* @__PURE__ */ jsxRuntime.jsxs(Tab, { $active: activeTab === "open-orders", onClick: () => handleTabChange("open-orders"), children: [
11058
+ "Open Orders",
11059
+ openOrdersCount > 0 && /* @__PURE__ */ jsxRuntime.jsxs(TabCount, { children: [
11060
+ " (",
11061
+ openOrdersCount,
11062
+ ")"
11063
+ ] })
11064
+ ] }),
11065
+ /* @__PURE__ */ jsxRuntime.jsxs(Tab, { $active: activeTab === "orders", onClick: () => handleTabChange("orders"), children: [
11066
+ "Order History",
11067
+ pendingHistoryCount > 0 && /* @__PURE__ */ jsxRuntime.jsxs(TabCount, { children: [
11068
+ " (",
11069
+ pendingHistoryCount,
11070
+ ")"
11071
+ ] })
11072
+ ] }),
10702
11073
  /* @__PURE__ */ jsxRuntime.jsx(Tab, { $active: activeTab === "trades", onClick: () => handleTabChange("trades"), children: "Trade History" }),
10703
11074
  /* @__PURE__ */ jsxRuntime.jsx(Tab, { $active: activeTab === "transfers", onClick: () => handleTabChange("transfers"), children: "Transfers" })
10704
11075
  ] }),
@@ -10783,8 +11154,10 @@ function PortfolioActivityPanel({
10783
11154
  openOrders.length === 0 && /* @__PURE__ */ jsxRuntime.jsx(EmptyState, { children: "Open orders will appear here while they are working in the market." }),
10784
11155
  pageSlice(openOrders).map((order) => {
10785
11156
  const meta = getOrderStatusMeta(order.status);
10786
- const priceDisplay = order.price ? formatCurrency5(order.price) : "Market";
10787
- const amountDisplay = order.price ? formatCurrency5(order.price * order.quantity) : "\u2014";
11157
+ const isMarket = order.type === "MARKET";
11158
+ const priceSegment = isMarket || !order.price ? "" : ` \xB7 ${formatCurrency5(order.price)}`;
11159
+ const filledPercent = order.quantity > 0 ? Math.round(order.filledQuantity / order.quantity * 100) : 0;
11160
+ const amountDisplay = !isMarket && order.price ? formatCurrency5(order.price * order.quantity) : "\u2014";
10788
11161
  const isCancelling = cancellingOrderId === order.id;
10789
11162
  return /* @__PURE__ */ jsxRuntime.jsxs(ActivityRow, { children: [
10790
11163
  /* @__PURE__ */ jsxRuntime.jsx(ActivitySideBadge, { $side: sideLabel(order.side), children: sideLabel(order.side) }),
@@ -10794,9 +11167,10 @@ function PortfolioActivityPanel({
10794
11167
  formatNumber2(order.quantity),
10795
11168
  " tokens \xB7 ",
10796
11169
  prettyLabel(order.type),
11170
+ priceSegment,
10797
11171
  " \xB7 ",
10798
- priceDisplay,
10799
- " \xB7 ",
11172
+ filledPercent,
11173
+ "% filled \xB7 ",
10800
11174
  formatTimestamp(order.createdAt)
10801
11175
  ] })
10802
11176
  ] }),
@@ -10823,8 +11197,10 @@ function PortfolioActivityPanel({
10823
11197
  orderHistory.length === 0 && /* @__PURE__ */ jsxRuntime.jsx(EmptyState, { children: "No orders yet. Place a trade to see it appear here." }),
10824
11198
  pageSlice(orderHistory).map((order) => {
10825
11199
  const meta = getOrderStatusMeta(order.status);
10826
- const priceDisplay = order.price ? formatCurrency5(order.price) : "Market";
10827
- const amountDisplay = order.price ? formatCurrency5(order.price * order.quantity) : "\u2014";
11200
+ const isMarket = order.type === "MARKET";
11201
+ const priceSegment = isMarket || !order.price ? "" : ` \xB7 ${formatCurrency5(order.price)}`;
11202
+ const filledPercent = order.quantity > 0 ? Math.round(order.filledQuantity / order.quantity * 100) : 0;
11203
+ const amountDisplay = !isMarket && order.price ? formatCurrency5(order.price * order.quantity) : "\u2014";
10828
11204
  return /* @__PURE__ */ jsxRuntime.jsxs(ActivityRow, { children: [
10829
11205
  /* @__PURE__ */ jsxRuntime.jsx(ActivitySideBadge, { $side: sideLabel(order.side), children: sideLabel(order.side) }),
10830
11206
  /* @__PURE__ */ jsxRuntime.jsxs(ActivityInfo, { children: [
@@ -10833,9 +11209,10 @@ function PortfolioActivityPanel({
10833
11209
  formatNumber2(order.quantity),
10834
11210
  " tokens \xB7 ",
10835
11211
  prettyLabel(order.type),
11212
+ priceSegment,
10836
11213
  " \xB7 ",
10837
- priceDisplay,
10838
- " \xB7 ",
11214
+ filledPercent,
11215
+ "% filled \xB7 ",
10839
11216
  formatTimestamp(order.createdAt)
10840
11217
  ] })
10841
11218
  ] }),
@@ -10977,6 +11354,12 @@ var Tab = styled24__default.default.button`
10977
11354
  color: ${({ $active }) => $active ? "#fff" : "rgba(255, 255, 255, 0.65)"};
10978
11355
  }
10979
11356
  `;
11357
+ var TabCount = styled24__default.default.span`
11358
+ color: inherit;
11359
+ opacity: 0.7;
11360
+ font-weight: 500;
11361
+ margin-left: 2px;
11362
+ `;
10980
11363
  var ActivityRow = styled24__default.default.div`
10981
11364
  display: grid;
10982
11365
  grid-template-columns: auto 1fr auto auto;
@@ -11620,23 +12003,24 @@ function PropertyBuy({
11620
12003
  recentOrders = [],
11621
12004
  ordersAllocated = 0,
11622
12005
  subscribers = 0,
12006
+ isLoadingActivity = false,
11623
12007
  selectorItems,
11624
12008
  onSelectorSelect,
11625
12009
  portfolioActivity
11626
12010
  }) {
11627
- const [sliderValue, setSliderValue] = React5.useState(0);
11628
- const [availableBalance, setAvailableBalance] = React5.useState(walletUsdcBalance ?? 0);
11629
- const [manualOrderAmount, setManualOrderAmount] = React5.useState(null);
11630
- const [ownedTokens, setOwnedTokens] = React5.useState(0);
11631
- const [displayedOwnedTokens, setDisplayedOwnedTokens] = React5.useState(0);
11632
- const [ownedTokensJustUpdated, setOwnedTokensJustUpdated] = React5.useState(false);
11633
- const [lastOrderQuantity, setLastOrderQuantity] = React5.useState(0);
11634
- const [orderPendingAllocation, setOrderPendingAllocation] = React5.useState(false);
11635
- const [orderPlacedSuccess, setOrderPlacedSuccess] = React5.useState(false);
11636
- const [lastOrderDetails, setLastOrderDetails] = React5.useState(null);
11637
- const [showOrderConfirmModal, setShowOrderConfirmModal] = React5.useState(false);
11638
- const [, setLiveNewsIndex] = React5.useState(0);
11639
- const [newsItems, setNewsItems] = React5.useState(
12011
+ const [sliderValue, setSliderValue] = React9.useState(0);
12012
+ const [availableBalance, setAvailableBalance] = React9.useState(walletUsdcBalance ?? 0);
12013
+ const [manualOrderAmount, setManualOrderAmount] = React9.useState(null);
12014
+ const [ownedTokens, setOwnedTokens] = React9.useState(0);
12015
+ const [displayedOwnedTokens, setDisplayedOwnedTokens] = React9.useState(0);
12016
+ const [ownedTokensJustUpdated, setOwnedTokensJustUpdated] = React9.useState(false);
12017
+ const [lastOrderQuantity, setLastOrderQuantity] = React9.useState(0);
12018
+ const [orderPendingAllocation, setOrderPendingAllocation] = React9.useState(false);
12019
+ const [orderPlacedSuccess, setOrderPlacedSuccess] = React9.useState(false);
12020
+ const [lastOrderDetails, setLastOrderDetails] = React9.useState(null);
12021
+ const [showOrderConfirmModal, setShowOrderConfirmModal] = React9.useState(false);
12022
+ const [, setLiveNewsIndex] = React9.useState(0);
12023
+ const [newsItems, setNewsItems] = React9.useState(
11640
12024
  () => allNewsItems.slice(0, 4).map((item, index) => ({
11641
12025
  ...item,
11642
12026
  displayId: `${item.id}-initial-${index}`,
@@ -11652,6 +12036,7 @@ function PropertyBuy({
11652
12036
  const offeringValuation = saleData?.offeringValuation ?? tokenPrice * supplyToSell;
11653
12037
  const ipoStatus = saleData?.status ?? "PENDING";
11654
12038
  const ipoStarted = ipoStatus === "LIVE" || isPrivateClient && ipoStatus === "PENDING";
12039
+ const ipoEnded = ipoStatus === "CLOSED" || ipoStatus === "CANCELLED";
11655
12040
  const statusLabel = ipoStatus;
11656
12041
  const statusColor = STATUS_COLOR2[ipoStatus] ?? "#D4AF37";
11657
12042
  const displayStatusLabel = isPrivateClient && ipoStatus !== "LIVE" ? "Private Client Access" : statusLabel;
@@ -11662,12 +12047,12 @@ function PropertyBuy({
11662
12047
  const orderTotal = tokenQuantity * tokenPrice + feeInUsd;
11663
12048
  const estExposure = (tokenQuantity / supplyToSell * 100).toFixed(4);
11664
12049
  const hasInsufficientFunds = orderTotal > availableBalance;
11665
- React5.useEffect(() => {
12050
+ React9.useEffect(() => {
11666
12051
  if (walletUsdcBalance != null) {
11667
12052
  setAvailableBalance(walletUsdcBalance);
11668
12053
  }
11669
12054
  }, [walletUsdcBalance]);
11670
- React5.useEffect(() => {
12055
+ React9.useEffect(() => {
11671
12056
  if (walletPropertyTokenBalance != null) {
11672
12057
  setOwnedTokens(walletPropertyTokenBalance);
11673
12058
  setDisplayedOwnedTokens(walletPropertyTokenBalance);
@@ -11679,13 +12064,13 @@ function PropertyBuy({
11679
12064
  }
11680
12065
  setShowOrderConfirmModal(true);
11681
12066
  };
11682
- React5.useEffect(() => {
12067
+ React9.useEffect(() => {
11683
12068
  if (purchaseStatus === "success" && orderPendingAllocation) {
11684
12069
  setOrderPendingAllocation(false);
11685
12070
  setOrderPlacedSuccess(true);
11686
12071
  }
11687
12072
  }, [purchaseStatus, orderPendingAllocation]);
11688
- const handlePlaceAnotherOrder = React5.useCallback(() => {
12073
+ const handlePlaceAnotherOrder = React9.useCallback(() => {
11689
12074
  setOrderPlacedSuccess(false);
11690
12075
  setOrderPendingAllocation(false);
11691
12076
  }, []);
@@ -11742,7 +12127,7 @@ function PropertyBuy({
11742
12127
  setSliderValue(0);
11743
12128
  setManualOrderAmount(null);
11744
12129
  };
11745
- React5.useEffect(() => {
12130
+ React9.useEffect(() => {
11746
12131
  const newsInterval = setInterval(() => {
11747
12132
  setLiveNewsIndex((prev) => {
11748
12133
  const nextIndex = (prev + 1) % allNewsItems.length;
@@ -11802,6 +12187,8 @@ function PropertyBuy({
11802
12187
  VideoActivitySection,
11803
12188
  {
11804
12189
  ipoStarted,
12190
+ ipoEnded,
12191
+ isLoading: isLoadingActivity,
11805
12192
  recentOrders,
11806
12193
  ordersAllocated,
11807
12194
  tokenPrice
@@ -12036,7 +12423,7 @@ function PaymentPopup({
12036
12423
  userTokenHoldings,
12037
12424
  propertyName
12038
12425
  }) {
12039
- const [selectedPaymentMethod, setSelectedPaymentMethod] = React5.useState(
12426
+ const [selectedPaymentMethod, setSelectedPaymentMethod] = React9.useState(
12040
12427
  "tokens"
12041
12428
  );
12042
12429
  if (!isOpen) return null;
@@ -12215,20 +12602,20 @@ function PaymentPopup({
12215
12602
  var payment_popup_default = PaymentPopup;
12216
12603
  var SUMMER_MONTHS = /* @__PURE__ */ new Set([11, 0, 1]);
12217
12604
  var OwnerBooking = ({ propertyName, token }) => {
12218
- const today = React5.useMemo(() => {
12605
+ const today = React9.useMemo(() => {
12219
12606
  const base = /* @__PURE__ */ new Date();
12220
12607
  base.setHours(0, 0, 0, 0);
12221
12608
  return base;
12222
12609
  }, []);
12223
- const [currentYear, setCurrentYear] = React5.useState(today.getFullYear());
12224
- const [currentMonth, setCurrentMonth] = React5.useState(today.getMonth());
12225
- const [dateRanges, setDateRanges] = React5.useState([]);
12226
- const [selectedDates, setSelectedDates] = React5.useState([]);
12227
- const [hoverDate, setHoverDate] = React5.useState(null);
12228
- const [isDateSelectorOpen, setIsDateSelectorOpen] = React5.useState(false);
12229
- const [selectorYear, setSelectorYear] = React5.useState(today.getFullYear());
12230
- const [isPaymentPopupOpen, setIsPaymentPopupOpen] = React5.useState(false);
12231
- const dateSelectorRef = React5.useRef(null);
12610
+ const [currentYear, setCurrentYear] = React9.useState(today.getFullYear());
12611
+ const [currentMonth, setCurrentMonth] = React9.useState(today.getMonth());
12612
+ const [dateRanges, setDateRanges] = React9.useState([]);
12613
+ const [selectedDates, setSelectedDates] = React9.useState([]);
12614
+ const [hoverDate, setHoverDate] = React9.useState(null);
12615
+ const [isDateSelectorOpen, setIsDateSelectorOpen] = React9.useState(false);
12616
+ const [selectorYear, setSelectorYear] = React9.useState(today.getFullYear());
12617
+ const [isPaymentPopupOpen, setIsPaymentPopupOpen] = React9.useState(false);
12618
+ const dateSelectorRef = React9.useRef(null);
12232
12619
  const tokenPrice = token.price ?? 700;
12233
12620
  const userTokenHoldings = 2.2;
12234
12621
  const MIN_NIGHTS = 3;
@@ -12238,25 +12625,25 @@ var OwnerBooking = ({ propertyName, token }) => {
12238
12625
  { bg: "rgba(230, 126, 34, 0.25)", border: "rgba(230, 126, 34, 0.6)" },
12239
12626
  { bg: "rgba(46, 204, 113, 0.25)", border: "rgba(46, 204, 113, 0.6)" }
12240
12627
  ];
12241
- const calculateTokensPerDayOwner = React5.useCallback(() => {
12628
+ const calculateTokensPerDayOwner = React9.useCallback(() => {
12242
12629
  if (tokenPrice <= 0) return 0;
12243
12630
  const target = 650;
12244
12631
  const raw = target / tokenPrice;
12245
12632
  return Math.ceil(raw * 1e4) / 1e4;
12246
12633
  }, [tokenPrice]);
12247
- const calculateTokensPerDayMarket = React5.useCallback(() => {
12634
+ const calculateTokensPerDayMarket = React9.useCallback(() => {
12248
12635
  if (tokenPrice <= 0) return 0;
12249
12636
  const target = 900;
12250
12637
  const raw = target / tokenPrice;
12251
12638
  return Math.ceil(raw * 1e4) / 1e4;
12252
12639
  }, [tokenPrice]);
12253
12640
  const qualifiesForOwnerRate = userTokenHoldings >= 0.1;
12254
- const getTokensPerDay = React5.useCallback(
12641
+ const getTokensPerDay = React9.useCallback(
12255
12642
  () => calculateTokensPerDayOwner() ,
12256
12643
  [qualifiesForOwnerRate, calculateTokensPerDayOwner, calculateTokensPerDayMarket]
12257
12644
  );
12258
12645
  const getRateLabel = () => "Owner's Rate" ;
12259
- const selectionStats = React5.useMemo(() => {
12646
+ const selectionStats = React9.useMemo(() => {
12260
12647
  if (selectedDates.length !== 2) return null;
12261
12648
  const [a, b] = selectedDates;
12262
12649
  const start = a < b ? a : b;
@@ -12267,10 +12654,10 @@ var OwnerBooking = ({ propertyName, token }) => {
12267
12654
  const usd = tokens * tokenPrice;
12268
12655
  return { nights, tokensPerDay, tokens, usd, start, end };
12269
12656
  }, [selectedDates, getTokensPerDay, tokenPrice]);
12270
- const totalNights = React5.useMemo(() => dateRanges.reduce((sum, r) => sum + r.nights, 0), [dateRanges]);
12271
- const totalTokens = React5.useMemo(() => dateRanges.reduce((sum, r) => sum + r.tokens, 0), [dateRanges]);
12657
+ const totalNights = React9.useMemo(() => dateRanges.reduce((sum, r) => sum + r.nights, 0), [dateRanges]);
12658
+ const totalTokens = React9.useMemo(() => dateRanges.reduce((sum, r) => sum + r.tokens, 0), [dateRanges]);
12272
12659
  const totalUSD = totalTokens * tokenPrice;
12273
- const generateCalendarDays = React5.useCallback(
12660
+ const generateCalendarDays = React9.useCallback(
12274
12661
  (year, month) => {
12275
12662
  const first = new Date(year, month, 1);
12276
12663
  const last = new Date(year, month + 1, 0);
@@ -12299,11 +12686,11 @@ var OwnerBooking = ({ propertyName, token }) => {
12299
12686
  },
12300
12687
  [today]
12301
12688
  );
12302
- const calendarDays = React5.useMemo(
12689
+ const calendarDays = React9.useMemo(
12303
12690
  () => generateCalendarDays(currentYear, currentMonth),
12304
12691
  [currentYear, currentMonth, generateCalendarDays]
12305
12692
  );
12306
- const isDateReserved = React5.useCallback(
12693
+ const isDateReserved = React9.useCallback(
12307
12694
  (date) => dateRanges.some((r) => date >= r.arrival && date <= r.departure),
12308
12695
  [dateRanges]
12309
12696
  );
@@ -12397,14 +12784,14 @@ var OwnerBooking = ({ propertyName, token }) => {
12397
12784
  "December"
12398
12785
  ];
12399
12786
  const dayNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
12400
- const setMonthYear = React5.useCallback(
12787
+ const setMonthYear = React9.useCallback(
12401
12788
  (month, year) => {
12402
12789
  setCurrentMonth(month);
12403
12790
  setCurrentYear(year);
12404
12791
  },
12405
12792
  [setCurrentMonth, setCurrentYear]
12406
12793
  );
12407
- const shiftMonth = React5.useCallback(
12794
+ const shiftMonth = React9.useCallback(
12408
12795
  (direction) => {
12409
12796
  const delta = direction === "prev" ? -1 : 1;
12410
12797
  let newMonth = currentMonth + delta;
@@ -12421,7 +12808,7 @@ var OwnerBooking = ({ propertyName, token }) => {
12421
12808
  },
12422
12809
  [currentMonth, currentYear, setMonthYear]
12423
12810
  );
12424
- const jumpToNextAvailable = React5.useCallback(() => {
12811
+ const jumpToNextAvailable = React9.useCallback(() => {
12425
12812
  for (let offset = 1; offset <= 12; offset++) {
12426
12813
  const candidateMonth = (currentMonth + offset) % 12;
12427
12814
  if (!SUMMER_MONTHS.has(candidateMonth)) continue;
@@ -12438,7 +12825,7 @@ var OwnerBooking = ({ propertyName, token }) => {
12438
12825
  setMonthYear(month, selectorYear);
12439
12826
  setIsDateSelectorOpen(false);
12440
12827
  };
12441
- React5.useEffect(() => {
12828
+ React9.useEffect(() => {
12442
12829
  const handleClickOutside = (event) => {
12443
12830
  if (dateSelectorRef.current && !dateSelectorRef.current.contains(event.target)) {
12444
12831
  setIsDateSelectorOpen(false);
@@ -12882,21 +13269,21 @@ function PropertyValuation({
12882
13269
  loading = false,
12883
13270
  error = null
12884
13271
  }) {
12885
- const now = React5.useMemo(() => /* @__PURE__ */ new Date(), []);
12886
- const lastPrice = React5.useMemo(() => {
13272
+ const now = React9.useMemo(() => /* @__PURE__ */ new Date(), []);
13273
+ const lastPrice = React9.useMemo(() => {
12887
13274
  const fallback = Number.isFinite(tokenPrice) && tokenPrice > 0 ? tokenPrice : 0;
12888
13275
  if (!summary?.lastPrice || summary.lastPrice <= 0) {
12889
13276
  return fallback;
12890
13277
  }
12891
13278
  return summary.lastPrice;
12892
13279
  }, [summary, tokenPrice]);
12893
- const fairValue = React5.useMemo(() => {
13280
+ const fairValue = React9.useMemo(() => {
12894
13281
  if (summary?.fairValue && summary.fairValue > 0) {
12895
13282
  return summary.fairValue;
12896
13283
  }
12897
13284
  return lastPrice || 1;
12898
13285
  }, [summary, lastPrice]);
12899
- const tokensOutstanding = React5.useMemo(() => {
13286
+ const tokensOutstanding = React9.useMemo(() => {
12900
13287
  if (summary?.totalTokens && summary.totalTokens > 0) {
12901
13288
  return summary.totalTokens;
12902
13289
  }
@@ -12911,8 +13298,8 @@ function PropertyValuation({
12911
13298
  const valuationStatus = summary?.valuationStatus ?? (lastPrice < fairValue ? "Undervalued" : lastPrice > fairValue ? "Overvalued" : "Fair Value");
12912
13299
  const valuationDelta = summary?.valuationDeltaPercent ?? (lastPrice - fairValue) / fairValue * 100;
12913
13300
  const valuationDeltaFormatted = `${valuationDelta >= 0 ? "+" : ""}${valuationDelta.toFixed(1)}%`;
12914
- const { valuationPath, fairValuePath, axisLabels } = React5.useMemo(() => buildChartPaths(history, fairValue), [history, fairValue]);
12915
- const recentSales = React5.useMemo(() => {
13301
+ const { valuationPath, fairValuePath, axisLabels } = React9.useMemo(() => buildChartPaths(history, fairValue), [history, fairValue]);
13302
+ const recentSales = React9.useMemo(() => {
12916
13303
  if (summary?.recentSales?.length) {
12917
13304
  return summary.recentSales;
12918
13305
  }
@@ -14064,19 +14451,19 @@ function PropertyPhotoGallery({
14064
14451
  );
14065
14452
  }
14066
14453
  function GalleryContent({ galleryImages, startIndex, title, subtitle, onClose }) {
14067
- const [currentIndex, setCurrentIndex] = React5.useState(() => clampIndex(startIndex, galleryImages.length));
14068
- const [activeHotspotId, setActiveHotspotId] = React5.useState(null);
14069
- const sliderRef = React5.useRef(null);
14070
- const [isDragging, setIsDragging] = React5.useState(false);
14071
- const wasDraggingRef = React5.useRef(false);
14072
- const touchStartX = React5.useRef(null);
14073
- const touchStartY = React5.useRef(null);
14074
- const isSwiping = React5.useRef(false);
14075
- const progress = React5.useMemo(() => {
14454
+ const [currentIndex, setCurrentIndex] = React9.useState(() => clampIndex(startIndex, galleryImages.length));
14455
+ const [activeHotspotId, setActiveHotspotId] = React9.useState(null);
14456
+ const sliderRef = React9.useRef(null);
14457
+ const [isDragging, setIsDragging] = React9.useState(false);
14458
+ const wasDraggingRef = React9.useRef(false);
14459
+ const touchStartX = React9.useRef(null);
14460
+ const touchStartY = React9.useRef(null);
14461
+ const isSwiping = React9.useRef(false);
14462
+ const progress = React9.useMemo(() => {
14076
14463
  if (galleryImages.length <= 1) return 0;
14077
14464
  return currentIndex / (galleryImages.length - 1) * 100;
14078
14465
  }, [currentIndex, galleryImages.length]);
14079
- React5.useEffect(() => {
14466
+ React9.useEffect(() => {
14080
14467
  document.body.style.overflow = "hidden";
14081
14468
  document.body.style.touchAction = "none";
14082
14469
  return () => {
@@ -14084,7 +14471,7 @@ function GalleryContent({ galleryImages, startIndex, title, subtitle, onClose })
14084
14471
  document.body.style.touchAction = "";
14085
14472
  };
14086
14473
  }, []);
14087
- React5.useEffect(() => {
14474
+ React9.useEffect(() => {
14088
14475
  const handleKey = (event) => {
14089
14476
  if (event.key === "Escape") onClose();
14090
14477
  if (event.key === "ArrowLeft") setCurrentIndex((i) => i === 0 ? galleryImages.length - 1 : i - 1);
@@ -14357,13 +14744,13 @@ function truncateHash(hash) {
14357
14744
  return `${hash.slice(0, 6)}\u2026${hash.slice(-4)}`;
14358
14745
  }
14359
14746
  function ToastItem({ toast, onDismiss }) {
14360
- const [exiting, setExiting] = React5.useState(false);
14361
- const timerRef = React5.useRef(null);
14362
- const dismiss = React5.useCallback(() => {
14747
+ const [exiting, setExiting] = React9.useState(false);
14748
+ const timerRef = React9.useRef(null);
14749
+ const dismiss = React9.useCallback(() => {
14363
14750
  setExiting(true);
14364
14751
  setTimeout(() => onDismiss(toast.id), 280);
14365
14752
  }, [onDismiss, toast.id]);
14366
- React5.useEffect(() => {
14753
+ React9.useEffect(() => {
14367
14754
  const duration2 = toast.duration ?? 6e3;
14368
14755
  if (duration2 > 0) {
14369
14756
  timerRef.current = setTimeout(dismiss, duration2);
@@ -14392,15 +14779,15 @@ function ToastItem({ toast, onDismiss }) {
14392
14779
  duration > 0 && /* @__PURE__ */ jsxRuntime.jsx(ProgressBar, { $color: accent, $duration: duration })
14393
14780
  ] });
14394
14781
  }
14395
- var ToastContext = React5.createContext(null);
14782
+ var ToastContext = React9.createContext(null);
14396
14783
  function ToastProvider({ children }) {
14397
- const [toasts, setToasts] = React5.useState([]);
14398
- const addToast = React5.useCallback((data) => {
14784
+ const [toasts, setToasts] = React9.useState([]);
14785
+ const addToast = React9.useCallback((data) => {
14399
14786
  const id = `toast-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
14400
14787
  setToasts((prev) => [...prev, { ...data, id }]);
14401
14788
  return id;
14402
14789
  }, []);
14403
- const dismiss = React5.useCallback((id) => {
14790
+ const dismiss = React9.useCallback((id) => {
14404
14791
  setToasts((prev) => prev.filter((t) => t.id !== id));
14405
14792
  }, []);
14406
14793
  return /* @__PURE__ */ jsxRuntime.jsxs(ToastContext.Provider, { value: { toast: addToast, dismiss }, children: [
@@ -14409,10 +14796,71 @@ function ToastProvider({ children }) {
14409
14796
  ] });
14410
14797
  }
14411
14798
  function useToast() {
14412
- const ctx = React5.useContext(ToastContext);
14799
+ const ctx = React9.useContext(ToastContext);
14413
14800
  if (!ctx) throw new Error("useToast must be used within a ToastProvider");
14414
14801
  return ctx;
14415
14802
  }
14803
+ var INTERVALS = [1e3, 2e3, 4e3, 5e3, 7e3, 1e4, 12e3];
14804
+ function useAdaptivePolling({ enabled, onPoll }) {
14805
+ const onPollRef = React9.useRef(onPoll);
14806
+ onPollRef.current = onPoll;
14807
+ React9.useEffect(() => {
14808
+ if (!enabled) return;
14809
+ let cancelled = false;
14810
+ let timeoutId = null;
14811
+ let step = 0;
14812
+ const clear = () => {
14813
+ if (timeoutId) {
14814
+ clearTimeout(timeoutId);
14815
+ timeoutId = null;
14816
+ }
14817
+ };
14818
+ const isHidden = () => typeof document !== "undefined" && document.visibilityState === "hidden";
14819
+ const tick = async () => {
14820
+ if (cancelled) return;
14821
+ if (isHidden()) {
14822
+ return;
14823
+ }
14824
+ try {
14825
+ await onPollRef.current();
14826
+ } catch {
14827
+ }
14828
+ if (cancelled) return;
14829
+ step = Math.min(step + 1, INTERVALS.length - 1);
14830
+ timeoutId = setTimeout(tick, INTERVALS[step]);
14831
+ };
14832
+ const onVisibility = () => {
14833
+ if (document.visibilityState === "visible") {
14834
+ step = 0;
14835
+ clear();
14836
+ timeoutId = setTimeout(tick, 0);
14837
+ }
14838
+ };
14839
+ if (typeof document !== "undefined") {
14840
+ document.addEventListener("visibilitychange", onVisibility);
14841
+ }
14842
+ timeoutId = setTimeout(tick, INTERVALS[0]);
14843
+ return () => {
14844
+ cancelled = true;
14845
+ clear();
14846
+ if (typeof document !== "undefined") {
14847
+ document.removeEventListener("visibilitychange", onVisibility);
14848
+ }
14849
+ };
14850
+ }, [enabled]);
14851
+ }
14852
+ function hasPendingActivity(data) {
14853
+ if (!data) return false;
14854
+ const openPending = data.openOrders?.some((o) => {
14855
+ const s = o.status.toUpperCase();
14856
+ return s === "OPEN" || s === "PARTIALLY_FILLED";
14857
+ }) ?? false;
14858
+ if (openPending) return true;
14859
+ return data.offeringOrders?.some((o) => {
14860
+ const s = o.status.toUpperCase();
14861
+ return s !== "FILLED" && s !== "ALLOCATED" && s !== "CONFIRMED" && s !== "CANCELLED" && s !== "CANCELED" && s !== "REJECTED";
14862
+ }) ?? false;
14863
+ }
14416
14864
 
14417
14865
  exports.AssetSelectorBar = AssetSelectorBar;
14418
14866
  exports.Badge = Badge;
@@ -14449,12 +14897,15 @@ exports.PropertyPhotoGallery = PropertyPhotoGallery;
14449
14897
  exports.PropertySubheader = PropertySubheader;
14450
14898
  exports.PropertyTour = PropertyTour;
14451
14899
  exports.PropertyValuation = PropertyValuation;
14900
+ exports.Skeleton = Skeleton;
14452
14901
  exports.ToastProvider = ToastProvider;
14453
14902
  exports.TradeConfirmationModal = TradeConfirmationModal;
14454
14903
  exports.TradingSlider = TradingSlider;
14455
14904
  exports.YourOrders = YourOrders;
14456
14905
  exports.badgeVariants = badgeVariants;
14457
14906
  exports.buttonVariants = buttonVariants;
14907
+ exports.hasPendingActivity = hasPendingActivity;
14908
+ exports.useAdaptivePolling = useAdaptivePolling;
14458
14909
  exports.useToast = useToast;
14459
14910
  //# sourceMappingURL=index.js.map
14460
14911
  //# sourceMappingURL=index.js.map