@loafmarkets/ui 0.1.52 → 0.1.53

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.d.mts CHANGED
@@ -69,6 +69,7 @@ type OrderbookTrade = {
69
69
  amount: number;
70
70
  time?: string;
71
71
  tradeId?: number;
72
+ txHash?: string;
72
73
  };
73
74
  interface OrderbookProps extends React$1.HTMLAttributes<HTMLDivElement> {
74
75
  asks: OrderbookLevel[];
@@ -100,6 +101,8 @@ interface OrderbookProps extends React$1.HTMLAttributes<HTMLDivElement> {
100
101
  * a custom `rightHeader` is supplied.
101
102
  */
102
103
  onLoafLiquidityClick?: () => void;
104
+ /** Given a trade's txHash, returns the full explorer URL to link to. Defaults to Sepolia Etherscan. */
105
+ tradeExplorerUrl?: (txHash: string) => string;
103
106
  }
104
107
  declare const Orderbook: React$1.ForwardRefExoticComponent<OrderbookProps & React$1.RefAttributes<HTMLDivElement>>;
105
108
 
package/dist/index.d.ts CHANGED
@@ -69,6 +69,7 @@ type OrderbookTrade = {
69
69
  amount: number;
70
70
  time?: string;
71
71
  tradeId?: number;
72
+ txHash?: string;
72
73
  };
73
74
  interface OrderbookProps extends React$1.HTMLAttributes<HTMLDivElement> {
74
75
  asks: OrderbookLevel[];
@@ -100,6 +101,8 @@ interface OrderbookProps extends React$1.HTMLAttributes<HTMLDivElement> {
100
101
  * a custom `rightHeader` is supplied.
101
102
  */
102
103
  onLoafLiquidityClick?: () => void;
104
+ /** Given a trade's txHash, returns the full explorer URL to link to. Defaults to Sepolia Etherscan. */
105
+ tradeExplorerUrl?: (txHash: string) => string;
103
106
  }
104
107
  declare const Orderbook: React$1.ForwardRefExoticComponent<OrderbookProps & React$1.RefAttributes<HTMLDivElement>>;
105
108
 
package/dist/index.js CHANGED
@@ -1832,13 +1832,17 @@ function useMidPriceFlash(ref, midPrice, restBgColor) {
1832
1832
  prevMidRef.current = midPrice;
1833
1833
  }, [midPrice, ref, restBgColor]);
1834
1834
  }
1835
+ function ExternalLinkIcon() {
1836
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "10", height: "10", viewBox: "0 0 10 10", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M1 9L9 1M9 1H4M9 1V6", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) });
1837
+ }
1835
1838
  function TradeRow({
1836
1839
  trade,
1837
1840
  tradeKey,
1838
1841
  precision,
1839
1842
  amountPrecision,
1840
1843
  seenTradeKeysRef,
1841
- compact
1844
+ compact,
1845
+ explorerUrl
1842
1846
  }) {
1843
1847
  const rowRef = React5__namespace.useRef(null);
1844
1848
  const { type } = trade;
@@ -1858,14 +1862,27 @@ function TradeRow({
1858
1862
  "div",
1859
1863
  {
1860
1864
  ref: rowRef,
1861
- className: "grid",
1865
+ className: "grid items-center",
1862
1866
  style: { gridTemplateColumns: "1.2fr 0.8fr", padding: "0.2rem 0", fontSize: "0.8rem" },
1863
1867
  children: [
1864
1868
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { color: trade.type === "buy" ? "#0ecb81" : "#f6465d", fontWeight: 500 }, children: [
1865
1869
  "$",
1866
1870
  formatNumber(trade.price, precision)
1867
1871
  ] }),
1868
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { textAlign: "right", paddingRight: "0.5rem" }, children: formatNumber(trade.amount, amountPrecision) })
1872
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { textAlign: "right", paddingRight: "0.5rem", display: "flex", alignItems: "center", justifyContent: "flex-end", gap: "4px" }, children: [
1873
+ formatNumber(trade.amount, amountPrecision),
1874
+ explorerUrl && /* @__PURE__ */ jsxRuntime.jsx(
1875
+ "a",
1876
+ {
1877
+ href: explorerUrl,
1878
+ target: "_blank",
1879
+ rel: "noopener noreferrer",
1880
+ style: { color: "rgba(255,255,255,0.35)", lineHeight: 0 },
1881
+ onClick: (e) => e.stopPropagation(),
1882
+ children: /* @__PURE__ */ jsxRuntime.jsx(ExternalLinkIcon, {})
1883
+ }
1884
+ )
1885
+ ] })
1869
1886
  ]
1870
1887
  }
1871
1888
  );
@@ -1874,7 +1891,7 @@ function TradeRow({
1874
1891
  "div",
1875
1892
  {
1876
1893
  ref: rowRef,
1877
- className: "grid grid-cols-2 items-center gap-3 px-3 py-1.5",
1894
+ className: "grid grid-cols-3 items-center gap-3 px-3 py-1.5",
1878
1895
  children: [
1879
1896
  /* @__PURE__ */ jsxRuntime.jsxs(
1880
1897
  "div",
@@ -1889,7 +1906,22 @@ function TradeRow({
1889
1906
  ]
1890
1907
  }
1891
1908
  ),
1892
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right tabular-nums text-white/90", children: formatNumber(trade.amount, amountPrecision) })
1909
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right tabular-nums text-white/90", children: formatNumber(trade.amount, amountPrecision) }),
1910
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-1.5", children: [
1911
+ trade.time != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums text-white/50 text-xs", children: trade.time }),
1912
+ explorerUrl && /* @__PURE__ */ jsxRuntime.jsx(
1913
+ "a",
1914
+ {
1915
+ href: explorerUrl,
1916
+ target: "_blank",
1917
+ rel: "noopener noreferrer",
1918
+ className: "text-white/35 hover:text-white/70 transition-colors",
1919
+ onClick: (e) => e.stopPropagation(),
1920
+ "aria-label": "View on explorer",
1921
+ children: /* @__PURE__ */ jsxRuntime.jsx(ExternalLinkIcon, {})
1922
+ }
1923
+ )
1924
+ ] })
1893
1925
  ]
1894
1926
  }
1895
1927
  );
@@ -1898,6 +1930,7 @@ function DepthRow({
1898
1930
  side,
1899
1931
  price,
1900
1932
  amount,
1933
+ cumDepth,
1901
1934
  depthPct,
1902
1935
  precision,
1903
1936
  amountPrecision,
@@ -1910,7 +1943,7 @@ function DepthRow({
1910
1943
  "div",
1911
1944
  {
1912
1945
  ref: rowRef,
1913
- className: "relative grid grid-cols-2 items-center gap-3 px-3 text-[0.8rem]",
1946
+ className: "relative grid grid-cols-3 items-center gap-3 px-3 text-[0.8rem]",
1914
1947
  style: { height: `${DEPTH_ROW_HEIGHT_PX}px` },
1915
1948
  children: [
1916
1949
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -1930,17 +1963,12 @@ function DepthRow({
1930
1963
  className: "absolute left-2 top-1/2 -translate-y-1/2 z-[2] h-[6px] w-[6px] rounded-full bg-[#C9A227] shadow-[0_0_6px_rgba(201,162,39,0.7)]"
1931
1964
  }
1932
1965
  ) : null,
1933
- /* @__PURE__ */ jsxRuntime.jsxs(
1934
- "div",
1935
- {
1936
- className: cn("relative z-[1] tabular-nums", isAsk ? "text-[#f6465d]" : "text-[#0ecb81]"),
1937
- children: [
1938
- "$",
1939
- formatNumber(price, precision)
1940
- ]
1941
- }
1942
- ),
1943
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative z-[1] text-right tabular-nums text-white/90", children: formatNumber(amount, amountPrecision) })
1966
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("relative z-[1] tabular-nums", isAsk ? "text-[#f6465d]" : "text-[#0ecb81]"), children: [
1967
+ "$",
1968
+ formatNumber(price, precision)
1969
+ ] }),
1970
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative z-[1] text-right tabular-nums text-white/90", children: formatNumber(amount, amountPrecision) }),
1971
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative z-[1] text-right tabular-nums text-white/50", children: formatNumber(cumDepth, amountPrecision) })
1944
1972
  ]
1945
1973
  }
1946
1974
  );
@@ -1969,6 +1997,7 @@ var Orderbook = React5__namespace.forwardRef(
1969
1997
  userOrderPrices,
1970
1998
  isLoading = false,
1971
1999
  onLoafLiquidityClick,
2000
+ tradeExplorerUrl,
1972
2001
  className,
1973
2002
  ...props
1974
2003
  }, ref) => {
@@ -2061,7 +2090,8 @@ var Orderbook = React5__namespace.forwardRef(
2061
2090
  userAskPrices,
2062
2091
  userBidPrices,
2063
2092
  isLoading,
2064
- seenTradeKeysRef
2093
+ seenTradeKeysRef,
2094
+ tradeExplorerUrl
2065
2095
  };
2066
2096
  return /* @__PURE__ */ jsxRuntime.jsx(
2067
2097
  Card,
@@ -2097,9 +2127,10 @@ function SkeletonRow({ compact }) {
2097
2127
  }
2098
2128
  );
2099
2129
  }
2100
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 items-center gap-3 px-3 py-1.5", children: [
2130
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-3 items-center gap-3 px-3 py-1.5", children: [
2101
2131
  /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: "60%", height: 12 }),
2102
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right", children: /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: "50%", height: 12 }) })
2132
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right", children: /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: "50%", height: 12 }) }),
2133
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right", children: /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: "40%", height: 12 }) })
2103
2134
  ] });
2104
2135
  }
2105
2136
  function DesktopOrderbookLayout({
@@ -2125,7 +2156,8 @@ function DesktopOrderbookLayout({
2125
2156
  userAskPrices,
2126
2157
  userBidPrices,
2127
2158
  isLoading,
2128
- seenTradeKeysRef
2159
+ seenTradeKeysRef,
2160
+ tradeExplorerUrl
2129
2161
  }) {
2130
2162
  const midRef = React5__namespace.useRef(null);
2131
2163
  useMidPriceFlash(midRef, midPrice, "#0b1a24");
@@ -2203,9 +2235,10 @@ function DesktopOrderbookLayout({
2203
2235
  ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-3", children: rightHeader })
2204
2236
  ] }),
2205
2237
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col min-h-0 px-4 pt-2", children: [
2206
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-3 px-3 py-2 text-xs text-white/60", children: [
2238
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-3 gap-3 px-3 py-2 text-xs text-white/60", children: [
2207
2239
  /* @__PURE__ */ jsxRuntime.jsx("div", { children: priceLabel }),
2208
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right", children: amountLabel })
2240
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right", children: amountLabel }),
2241
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right", children: tab === "orderbook" ? "Total" : "Time" })
2209
2242
  ] }),
2210
2243
  tab === "trades" ? /* @__PURE__ */ jsxRuntime.jsx(
2211
2244
  "div",
@@ -2214,6 +2247,7 @@ function DesktopOrderbookLayout({
2214
2247
  style: { scrollbarGutter: "stable" },
2215
2248
  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) => {
2216
2249
  const tradeKey = getTradeKey(trade, i);
2250
+ const explorerUrl = trade.txHash && tradeExplorerUrl ? tradeExplorerUrl(trade.txHash) : trade.txHash ? `https://sepolia.etherscan.io/tx/${trade.txHash}` : void 0;
2217
2251
  return /* @__PURE__ */ jsxRuntime.jsx(
2218
2252
  TradeRow,
2219
2253
  {
@@ -2221,7 +2255,8 @@ function DesktopOrderbookLayout({
2221
2255
  tradeKey,
2222
2256
  precision,
2223
2257
  amountPrecision,
2224
- seenTradeKeysRef
2258
+ seenTradeKeysRef,
2259
+ explorerUrl
2225
2260
  },
2226
2261
  tradeKey
2227
2262
  );
@@ -2239,6 +2274,7 @@ function DesktopOrderbookLayout({
2239
2274
  side: "ask",
2240
2275
  price: l.price,
2241
2276
  amount: l.amount,
2277
+ cumDepth: askCumDepths[i],
2242
2278
  depthPct: askCumDepths[i] / combinedMaxCumDepth * 100,
2243
2279
  precision,
2244
2280
  amountPrecision,
@@ -2278,6 +2314,7 @@ function DesktopOrderbookLayout({
2278
2314
  side: "bid",
2279
2315
  price: l.price,
2280
2316
  amount: l.amount,
2317
+ cumDepth: bidCumDepths[i],
2281
2318
  depthPct: bidCumDepths[i] / combinedMaxCumDepth * 100,
2282
2319
  precision,
2283
2320
  amountPrecision,
@@ -2314,7 +2351,8 @@ function MobileOrderbookLayout({
2314
2351
  userAskPrices,
2315
2352
  userBidPrices,
2316
2353
  isLoading,
2317
- seenTradeKeysRef
2354
+ seenTradeKeysRef,
2355
+ tradeExplorerUrl
2318
2356
  }) {
2319
2357
  const midRef = React5__namespace.useRef(null);
2320
2358
  useMidPriceFlash(midRef, midPrice, "transparent");
@@ -2459,6 +2497,7 @@ function MobileOrderbookLayout({
2459
2497
  ),
2460
2498
  /* @__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) => {
2461
2499
  const tradeKey = getTradeKey(trade, i);
2500
+ const explorerUrl = trade.txHash && tradeExplorerUrl ? tradeExplorerUrl(trade.txHash) : trade.txHash ? `https://sepolia.etherscan.io/tx/${trade.txHash}` : void 0;
2462
2501
  return /* @__PURE__ */ jsxRuntime.jsx(
2463
2502
  TradeRow,
2464
2503
  {
@@ -2467,7 +2506,8 @@ function MobileOrderbookLayout({
2467
2506
  precision,
2468
2507
  amountPrecision,
2469
2508
  seenTradeKeysRef,
2470
- compact: true
2509
+ compact: true,
2510
+ explorerUrl
2471
2511
  },
2472
2512
  tradeKey
2473
2513
  );