@loafmarkets/ui 0.1.3 → 0.1.5

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
@@ -280,7 +280,7 @@ declare const YourOrders: React.ForwardRefExoticComponent<React.HTMLAttributes<H
280
280
  renderOrderActions?: (order: YourOrder) => React.ReactNode;
281
281
  } & React.RefAttributes<HTMLDivElement>>;
282
282
 
283
- type PriceChartRange = "15m" | "1h" | "4h" | "24h" | "1W" | "1M";
283
+ type PriceChartRange = "30s" | "1m" | "5m" | "15m" | "1h" | "4h" | "24h" | "1W" | "1M";
284
284
  type PriceChartCandle = {
285
285
  time: LightweightCharts.Time;
286
286
  open: number;
package/dist/index.d.ts CHANGED
@@ -280,7 +280,7 @@ declare const YourOrders: React.ForwardRefExoticComponent<React.HTMLAttributes<H
280
280
  renderOrderActions?: (order: YourOrder) => React.ReactNode;
281
281
  } & React.RefAttributes<HTMLDivElement>>;
282
282
 
283
- type PriceChartRange = "15m" | "1h" | "4h" | "24h" | "1W" | "1M";
283
+ type PriceChartRange = "30s" | "1m" | "5m" | "15m" | "1h" | "4h" | "24h" | "1W" | "1M";
284
284
  type PriceChartCandle = {
285
285
  time: LightweightCharts.Time;
286
286
  open: number;
package/dist/index.js CHANGED
@@ -3300,7 +3300,7 @@ function DesktopOrderbookLayout({
3300
3300
  )
3301
3301
  ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-3", children: rightHeader })
3302
3302
  ] }),
3303
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-4 pb-3 pt-2", children: [
3303
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-4 pt-2", children: [
3304
3304
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-3 px-3 py-2 text-xs text-white/60", children: [
3305
3305
  /* @__PURE__ */ jsxRuntime.jsx("div", { children: priceLabel }),
3306
3306
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right", children: amountLabel })
@@ -3354,11 +3354,11 @@ function DesktopOrderbookLayout({
3354
3354
  ))
3355
3355
  }
3356
3356
  ),
3357
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 grid grid-cols-2 items-center gap-3 bg-[#0b1a24] px-3 py-2", children: [
3357
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 items-center gap-3 bg-[#0b1a24] px-3 py-2", children: [
3358
3358
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("text-lg font-semibold tabular-nums", midClass), children: [
3359
3359
  "$",
3360
3360
  formatNumber(midPrice, precision),
3361
- midChangePercent == null ? null : /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ml-2 text-sm font-semibold", children: [
3361
+ midChangePercent == null ? null : /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("ml-2 text-sm font-semibold tabular-nums", midClass), children: [
3362
3362
  midChangePercent >= 0 ? "+" : "",
3363
3363
  midChangePercent.toFixed(2),
3364
3364
  "%"
@@ -3413,18 +3413,18 @@ function MobileOrderbookLayout({
3413
3413
  const visibleBids = o__namespace.useMemo(() => bids.slice(0, COMPACT_ROWS_VISIBLE), [bids]);
3414
3414
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3415
3415
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 pt-2", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
3416
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
3416
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
3417
3417
  /* @__PURE__ */ jsxRuntime.jsx(
3418
3418
  "span",
3419
3419
  {
3420
3420
  onClick: () => handleTab("orderbook"),
3421
3421
  style: {
3422
3422
  cursor: "pointer",
3423
- fontSize: "0.8rem",
3423
+ fontSize: "0.72rem",
3424
3424
  fontWeight: tab === "orderbook" ? 600 : 400,
3425
3425
  color: tab === "orderbook" ? "#fff" : "rgba(255,255,255,0.6)",
3426
3426
  borderBottom: tab === "orderbook" ? "2px solid #C9A227" : "none",
3427
- paddingBottom: "0.25rem"
3427
+ paddingBottom: "0.2rem"
3428
3428
  },
3429
3429
  children: "Orderbook"
3430
3430
  }
@@ -3435,11 +3435,11 @@ function MobileOrderbookLayout({
3435
3435
  onClick: () => handleTab("trades"),
3436
3436
  style: {
3437
3437
  cursor: "pointer",
3438
- fontSize: "0.8rem",
3438
+ fontSize: "0.72rem",
3439
3439
  fontWeight: tab === "trades" ? 600 : 400,
3440
3440
  color: tab === "trades" ? "#fff" : "rgba(255,255,255,0.6)",
3441
3441
  borderBottom: tab === "trades" ? "2px solid #C9A227" : "none",
3442
- paddingBottom: "0.25rem"
3442
+ paddingBottom: "0.2rem"
3443
3443
  },
3444
3444
  children: "Trades"
3445
3445
  }
@@ -3499,20 +3499,26 @@ function MobileOrderbookLayout({
3499
3499
  gridTemplateColumns: "1.2fr 0.8fr",
3500
3500
  padding: "0.3rem 0",
3501
3501
  fontSize: "0.8rem",
3502
- backgroundColor: "rgba(0, 123, 255, 0.05)",
3503
3502
  borderTop: "1px solid rgba(255,255,255,0.1)",
3504
3503
  borderBottom: "1px solid rgba(255,255,255,0.1)"
3505
3504
  },
3506
3505
  children: [
3507
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { fontWeight: "bold", display: "flex", alignItems: "center", gap: "8px" }, className: midClass, children: [
3508
- "$",
3509
- formatNumber(midPrice, precision),
3510
- midChangePercent != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { fontSize: "0.8rem" }, className: midClass, children: [
3511
- midChangePercent >= 0 ? "+" : "",
3512
- midChangePercent.toFixed(2),
3513
- "%"
3514
- ] })
3515
- ] }),
3506
+ /* @__PURE__ */ jsxRuntime.jsxs(
3507
+ "div",
3508
+ {
3509
+ style: { fontWeight: "bold", display: "flex", alignItems: "center", gap: "8px" },
3510
+ className: midClass,
3511
+ children: [
3512
+ "$",
3513
+ formatNumber(midPrice, precision),
3514
+ midChangePercent != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("text-[0.75rem] font-semibold tabular-nums", midClass), children: [
3515
+ midChangePercent >= 0 ? "+" : "",
3516
+ midChangePercent.toFixed(2),
3517
+ "%"
3518
+ ] })
3519
+ ]
3520
+ }
3521
+ ),
3516
3522
  /* @__PURE__ */ jsxRuntime.jsx("div", {})
3517
3523
  ]
3518
3524
  }
@@ -4405,6 +4411,10 @@ var YourOrders = o__namespace.forwardRef(
4405
4411
  const resolvedTabs = tabs ?? DEFAULT_TABS.map((t) => ({ ...t, orders: orders ?? [], emptyState: `No ${t.label.toLowerCase()} data available.` }));
4406
4412
  const activeTab = resolvedTabs.find((t) => t.id === effectiveActiveTabId) ?? resolvedTabs[0];
4407
4413
  const activeOrders = activeTab?.orders ?? orders ?? [];
4414
+ const tabSupportsActions = activeTab?.enableCancel ?? true;
4415
+ const showActionsColumn = Boolean(renderOrderActions && tabSupportsActions);
4416
+ const baseGridTemplate = "1.8fr 0.9fr 0.7fr 0.8fr 0.8fr 1fr";
4417
+ const gridTemplateColumns = showActionsColumn ? "1.8fr 0.8fr 0.7fr 0.8fr 0.8fr 0.9fr 0.8fr" : baseGridTemplate;
4408
4418
  const displayTitle = title ?? activeTab?.title ?? activeTab?.label ?? "Portfolio Holdings";
4409
4419
  console.log("[YourOrders] tabs:", tabs?.map((t) => ({ id: t.id, ordersCount: t.orders?.length })));
4410
4420
  console.log("[YourOrders] activeTabId prop:", activeTabId);
@@ -4417,13 +4427,14 @@ var YourOrders = o__namespace.forwardRef(
4417
4427
  return /* @__PURE__ */ jsxRuntime.jsx("div", { style: emptyStateStyle, children: emptyMessage });
4418
4428
  }
4419
4429
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4420
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: tableHeaderStyle, children: [
4430
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { ...tableHeaderStyle, gridTemplateColumns }, children: [
4421
4431
  /* @__PURE__ */ jsxRuntime.jsx("div", { style: tableHeaderCell, children: "Property" }),
4422
4432
  /* @__PURE__ */ jsxRuntime.jsx("div", { style: tableHeaderCell, children: "Value" }),
4423
4433
  /* @__PURE__ */ jsxRuntime.jsx("div", { style: tableHeaderCell, children: "Holding" }),
4424
4434
  /* @__PURE__ */ jsxRuntime.jsx("div", { style: tableHeaderCell, children: "% of Property" }),
4425
4435
  /* @__PURE__ */ jsxRuntime.jsx("div", { style: tableHeaderCell, children: "Avg Price" }),
4426
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: tableHeaderCell, children: "P&L" })
4436
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: tableHeaderCell, children: "P&L" }),
4437
+ showActionsColumn ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { ...tableHeaderCell, textAlign: "right" }, children: "Actions" }) : null
4427
4438
  ] }),
4428
4439
  /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column", gap: "0.65rem" }, children: activeOrders.map((order) => {
4429
4440
  const propertyName = order.asset;
@@ -4441,7 +4452,7 @@ var YourOrders = o__namespace.forwardRef(
4441
4452
  const currentPrice = order.currentPrice ?? order.price;
4442
4453
  const priceChangePercent = order.priceChangePercent ?? order.pnlPercent;
4443
4454
  const priceChangePositive = order.priceChangePositive ?? (priceChangePercent != null ? priceChangePercent >= 0 : void 0);
4444
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { ...rowStyle, gridTemplateColumns: renderOrderActions ? "1.8fr 0.8fr 0.7fr 0.8fr 0.8fr 0.9fr 0.8fr" : "1.8fr 0.9fr 0.7fr 0.8fr 0.8fr 1fr" }, children: [
4455
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { ...rowStyle, gridTemplateColumns }, children: [
4445
4456
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: "1rem", alignItems: "center" }, children: [
4446
4457
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.15rem" }, children: [
4447
4458
  /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "0.9rem", fontWeight: 500 }, children: propertyName }),
@@ -4513,7 +4524,7 @@ var YourOrders = o__namespace.forwardRef(
4513
4524
  ]
4514
4525
  }
4515
4526
  ),
4516
- renderOrderActions ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", justifyContent: "flex-end" }, children: renderOrderActions(order) }) : null
4527
+ showActionsColumn ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", justifyContent: "flex-end" }, children: renderOrderActions?.(order) }) : null
4517
4528
  ] }, order.id);
4518
4529
  }) })
4519
4530
  ] });
@@ -4586,6 +4597,27 @@ var createTickFormatter = (formatOptions) => {
4586
4597
  };
4587
4598
  var getTimeScaleOptions = (range) => {
4588
4599
  switch (range) {
4600
+ case "30s":
4601
+ return {
4602
+ timeVisible: true,
4603
+ secondsVisible: true,
4604
+ borderColor: "rgba(255,255,255,0.06)",
4605
+ tickMarkFormatter: createTickFormatter({ hour: "2-digit", minute: "2-digit", second: "2-digit" })
4606
+ };
4607
+ case "1m":
4608
+ return {
4609
+ timeVisible: true,
4610
+ secondsVisible: true,
4611
+ borderColor: "rgba(255,255,255,0.06)",
4612
+ tickMarkFormatter: createTickFormatter({ hour: "2-digit", minute: "2-digit", second: "2-digit" })
4613
+ };
4614
+ case "5m":
4615
+ return {
4616
+ timeVisible: true,
4617
+ secondsVisible: false,
4618
+ borderColor: "rgba(255,255,255,0.06)",
4619
+ tickMarkFormatter: createTickFormatter({ hour: "2-digit", minute: "2-digit" })
4620
+ };
4589
4621
  case "15m":
4590
4622
  return {
4591
4623
  timeVisible: true,
@@ -4657,7 +4689,8 @@ var getPriceScaleOptions = (data) => {
4657
4689
  scaleMargins
4658
4690
  };
4659
4691
  };
4660
- var defaultRanges = ["15m", "1h", "4h", "24h", "1W", "1M"];
4692
+ var defaultRanges = ["30s", "1m", "5m", "15m", "1h", "4h", "24h", "1W", "1M"];
4693
+ var VISIBLE_RANGE_COUNT = 4;
4661
4694
  var formatPrice = (value, currencySymbol) => {
4662
4695
  return `${currencySymbol}${value.toLocaleString(void 0, {
4663
4696
  minimumFractionDigits: 2,
@@ -4694,6 +4727,21 @@ var PriceChart = o__namespace.forwardRef(
4694
4727
  const seriesRef = o__namespace.useRef(null);
4695
4728
  const priceLineRef = o__namespace.useRef(null);
4696
4729
  const [hoveredRange, setHoveredRange] = o__namespace.useState(null);
4730
+ const [dropdownOpen, setDropdownOpen] = o__namespace.useState(false);
4731
+ const dropdownRef = o__namespace.useRef(null);
4732
+ const isAutoScrollRef = o__namespace.useRef(true);
4733
+ const visibleRanges = ranges.slice(0, VISIBLE_RANGE_COUNT);
4734
+ const dropdownRanges = ranges.slice(VISIBLE_RANGE_COUNT);
4735
+ const selectedInDropdown = dropdownRanges.includes(selectedRange);
4736
+ o__namespace.useEffect(() => {
4737
+ const handleClickOutside = (e) => {
4738
+ if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
4739
+ setDropdownOpen(false);
4740
+ }
4741
+ };
4742
+ document.addEventListener("mousedown", handleClickOutside);
4743
+ return () => document.removeEventListener("mousedown", handleClickOutside);
4744
+ }, []);
4697
4745
  const resolvedPrice = o__namespace.useMemo(() => {
4698
4746
  if (price != null) return price;
4699
4747
  const last = data.at(-1);
@@ -4742,9 +4790,18 @@ var PriceChart = o__namespace.forwardRef(
4742
4790
  });
4743
4791
  chartRef.current = chart;
4744
4792
  seriesRef.current = series;
4793
+ const handleVisibleRangeChange = () => {
4794
+ const timeScale2 = chart.timeScale();
4795
+ const position2 = timeScale2.scrollPosition();
4796
+ const atRightEdge = position2 <= 0.01;
4797
+ isAutoScrollRef.current = atRightEdge;
4798
+ };
4799
+ const timeScale = chart.timeScale();
4800
+ timeScale.subscribeVisibleLogicalRangeChange(handleVisibleRangeChange);
4745
4801
  return () => {
4746
4802
  chartRef.current = null;
4747
4803
  seriesRef.current = null;
4804
+ timeScale.unsubscribeVisibleLogicalRangeChange(handleVisibleRangeChange);
4748
4805
  chart.remove();
4749
4806
  };
4750
4807
  }, []);
@@ -4779,7 +4836,9 @@ var PriceChart = o__namespace.forwardRef(
4779
4836
  title: resolvedPrice.toFixed(2)
4780
4837
  });
4781
4838
  }
4782
- chart.timeScale().fitContent();
4839
+ if (isAutoScrollRef.current) {
4840
+ chart.timeScale().scrollToPosition(0, true);
4841
+ }
4783
4842
  }, [data, resolvedPrice]);
4784
4843
  const sign = inferredChangePercent == null ? null : inferredChangePercent >= 0 ? "+" : "";
4785
4844
  const changeClass = inferredChangePercent == null ? "" : inferredChangePercent >= 0 ? "text-[#0ecb81]" : "text-[#f6465d]";
@@ -4811,30 +4870,97 @@ var PriceChart = o__namespace.forwardRef(
4811
4870
  /* @__PURE__ */ jsxRuntime.jsxs(CardHeader, { className: "flex flex-col gap-4 px-4 pb-2 pt-5 md:flex-row md:items-start md:justify-between md:px-6 md:pt-6", children: [
4812
4871
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full flex-col gap-3 md:w-auto", children: [
4813
4872
  /* @__PURE__ */ jsxRuntime.jsx(CardTitle, { className: "m-0 text-[1.1rem] font-semibold text-white", children: title }),
4814
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2", children: ranges.map((r2) => {
4815
- const active = r2 === selectedRange;
4816
- const hovered = hoveredRange === r2;
4817
- const style = {
4818
- ...btnBaseStyle,
4819
- ...hovered ? btnHoverStyle : null,
4820
- ...active ? btnActiveStyle : null
4821
- };
4822
- return /* @__PURE__ */ jsxRuntime.jsx(
4873
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
4874
+ visibleRanges.map((r2) => {
4875
+ const active = r2 === selectedRange;
4876
+ const hovered = hoveredRange === r2;
4877
+ const style = {
4878
+ ...btnBaseStyle,
4879
+ ...hovered ? btnHoverStyle : null,
4880
+ ...active ? btnActiveStyle : null
4881
+ };
4882
+ return /* @__PURE__ */ jsxRuntime.jsx(
4883
+ "button",
4884
+ {
4885
+ type: "button",
4886
+ onClick: () => onRangeChange?.(r2),
4887
+ onMouseEnter: () => setHoveredRange(r2),
4888
+ onMouseLeave: () => setHoveredRange((prev2) => prev2 === r2 ? null : prev2),
4889
+ style,
4890
+ className: cn(
4891
+ "rounded border px-3 py-1 text-[0.85rem] font-medium transition-all duration-200"
4892
+ ),
4893
+ children: r2
4894
+ },
4895
+ r2
4896
+ );
4897
+ }),
4898
+ selectedInDropdown && selectedRange ? /* @__PURE__ */ jsxRuntime.jsx(
4823
4899
  "button",
4824
4900
  {
4825
4901
  type: "button",
4826
- onClick: () => onRangeChange?.(r2),
4827
- onMouseEnter: () => setHoveredRange(r2),
4828
- onMouseLeave: () => setHoveredRange((prev2) => prev2 === r2 ? null : prev2),
4829
- style,
4902
+ style: {
4903
+ ...btnBaseStyle,
4904
+ ...btnActiveStyle
4905
+ },
4830
4906
  className: cn(
4831
4907
  "rounded border px-3 py-1 text-[0.85rem] font-medium transition-all duration-200"
4832
4908
  ),
4833
- children: r2
4834
- },
4835
- r2
4836
- );
4837
- }) })
4909
+ disabled: true,
4910
+ children: selectedRange
4911
+ }
4912
+ ) : null,
4913
+ dropdownRanges.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", ref: dropdownRef, children: [
4914
+ /* @__PURE__ */ jsxRuntime.jsxs(
4915
+ "button",
4916
+ {
4917
+ type: "button",
4918
+ onClick: () => setDropdownOpen((prev2) => !prev2),
4919
+ onMouseEnter: () => setHoveredRange("__dropdown__"),
4920
+ onMouseLeave: () => setHoveredRange((prev2) => prev2 === "__dropdown__" ? null : prev2),
4921
+ style: {
4922
+ ...btnBaseStyle,
4923
+ ...hoveredRange === "__dropdown__" ? btnHoverStyle : null
4924
+ },
4925
+ className: cn(
4926
+ "flex items-center gap-1 rounded border px-3 py-1 text-[0.85rem] font-medium transition-all duration-200"
4927
+ ),
4928
+ children: [
4929
+ "More",
4930
+ /* @__PURE__ */ jsxRuntime.jsx(
4931
+ "svg",
4932
+ {
4933
+ className: cn("h-3 w-3 transition-transform", dropdownOpen && "rotate-180"),
4934
+ fill: "none",
4935
+ stroke: "currentColor",
4936
+ viewBox: "0 0 24 24",
4937
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" })
4938
+ }
4939
+ )
4940
+ ]
4941
+ }
4942
+ ),
4943
+ dropdownOpen && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-0 top-full z-50 mt-1 min-w-[80px] rounded border border-white/10 bg-black/90 py-1 backdrop-blur-md", children: dropdownRanges.map((r2) => {
4944
+ const active = r2 === selectedRange;
4945
+ return /* @__PURE__ */ jsxRuntime.jsx(
4946
+ "button",
4947
+ {
4948
+ type: "button",
4949
+ onClick: () => {
4950
+ onRangeChange?.(r2);
4951
+ setDropdownOpen(false);
4952
+ },
4953
+ className: cn(
4954
+ "block w-full px-3 py-1.5 text-left text-[0.85rem] font-medium transition-colors hover:bg-white/10",
4955
+ active ? "bg-[#e6c87e]/20 text-[#e6c87e]" : "text-white/70"
4956
+ ),
4957
+ children: r2
4958
+ },
4959
+ r2
4960
+ );
4961
+ }) })
4962
+ ] })
4963
+ ] })
4838
4964
  ] }),
4839
4965
  resolvedPrice == null && inferredChangePercent == null ? null : /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center" }, children: [
4840
4966
  resolvedPrice == null ? null : /* @__PURE__ */ jsxRuntime.jsx(