@loafmarkets/ui 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -4275,7 +4275,7 @@ var PriceChange = at.span`
4275
4275
  gap: 0.35rem;
4276
4276
  color: ${(props) => props.$isPositive == null ? "var(--color-text-secondary, rgba(255, 255, 255, 0.6))" : props.$isPositive ? "var(--color-positive, #0ecb81)" : "var(--color-negative, #f6465d)"};
4277
4277
  `;
4278
- var TABS = [
4278
+ var DEFAULT_TABS = [
4279
4279
  { id: "portfolio", label: "Portfolio" },
4280
4280
  { id: "openOrders", label: "Open Orders" },
4281
4281
  { id: "tradeHistory", label: "Trade History" },
@@ -4370,12 +4370,29 @@ var formatPercent = (value, fractionDigits = 2) => {
4370
4370
  return `${value.toFixed(fractionDigits)}%`;
4371
4371
  };
4372
4372
  var YourOrders = o.forwardRef(
4373
- ({ className, title = "Portfolio Holdings (Demo)", orders, renderOrderActions, ...props }, ref) => {
4374
- const [activeTab, setActiveTab] = o.useState("portfolio");
4375
- const hasOrders = Array.isArray(orders) && orders.length > 0;
4376
- const renderPortfolio = () => {
4373
+ ({ className, title, orders, tabs, activeTabId, onTabChange, renderOrderActions, ...props }, ref) => {
4374
+ const [internalActiveTab, setInternalActiveTab] = o.useState(tabs?.[0]?.id ?? "portfolio");
4375
+ const effectiveActiveTabId = activeTabId ?? internalActiveTab;
4376
+ const handleTabChange = (tabId) => {
4377
+ if (onTabChange) {
4378
+ onTabChange(tabId);
4379
+ } else {
4380
+ setInternalActiveTab(tabId);
4381
+ }
4382
+ };
4383
+ const resolvedTabs = tabs ?? DEFAULT_TABS.map((t) => ({ ...t, orders: orders ?? [], emptyState: `No ${t.label.toLowerCase()} data available.` }));
4384
+ const activeTab = resolvedTabs.find((t) => t.id === effectiveActiveTabId) ?? resolvedTabs[0];
4385
+ const activeOrders = activeTab?.orders ?? orders ?? [];
4386
+ const displayTitle = title ?? activeTab?.title ?? activeTab?.label ?? "Portfolio Holdings";
4387
+ console.log("[YourOrders] tabs:", tabs?.map((t) => ({ id: t.id, ordersCount: t.orders?.length })));
4388
+ console.log("[YourOrders] activeTabId prop:", activeTabId);
4389
+ console.log("[YourOrders] effectiveActiveTabId:", effectiveActiveTabId);
4390
+ console.log("[YourOrders] activeTab:", activeTab?.id, "orders count:", activeOrders?.length);
4391
+ const hasOrders = Array.isArray(activeOrders) && activeOrders.length > 0;
4392
+ const emptyMessage = activeTab?.emptyState ?? "No holdings yet. Start trading to build your portfolio.";
4393
+ const renderOrders = () => {
4377
4394
  if (!hasOrders) {
4378
- return /* @__PURE__ */ jsx("div", { style: emptyStateStyle, children: "No holdings yet. Start trading to build your portfolio." });
4395
+ return /* @__PURE__ */ jsx("div", { style: emptyStateStyle, children: emptyMessage });
4379
4396
  }
4380
4397
  return /* @__PURE__ */ jsxs(Fragment, { children: [
4381
4398
  /* @__PURE__ */ jsxs("div", { style: tableHeaderStyle, children: [
@@ -4386,7 +4403,7 @@ var YourOrders = o.forwardRef(
4386
4403
  /* @__PURE__ */ jsx("div", { style: tableHeaderCell, children: "Avg Price" }),
4387
4404
  /* @__PURE__ */ jsx("div", { style: tableHeaderCell, children: "P&L" })
4388
4405
  ] }),
4389
- /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: "0.65rem" }, children: orders.map((order) => {
4406
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: "0.65rem" }, children: activeOrders.map((order) => {
4390
4407
  const propertyName = order.asset;
4391
4408
  const holding = order.holdingLabel ?? `${order.amount.toLocaleString(void 0, {
4392
4409
  minimumFractionDigits: 0,
@@ -4479,24 +4496,7 @@ var YourOrders = o.forwardRef(
4479
4496
  }) })
4480
4497
  ] });
4481
4498
  };
4482
- const renderOtherTab = (label) => /* @__PURE__ */ jsx("div", { style: emptyStateStyle, children: `No ${label.toLowerCase()} data available.` });
4483
- let tabContent = null;
4484
- switch (activeTab) {
4485
- case "portfolio":
4486
- tabContent = renderPortfolio();
4487
- break;
4488
- case "openOrders":
4489
- tabContent = renderOtherTab("Open Orders");
4490
- break;
4491
- case "tradeHistory":
4492
- tabContent = renderOtherTab("Trade History");
4493
- break;
4494
- case "orderHistory":
4495
- tabContent = renderOtherTab("Order History");
4496
- break;
4497
- default:
4498
- tabContent = null;
4499
- }
4499
+ const tabContent = renderOrders();
4500
4500
  return /* @__PURE__ */ jsxs(
4501
4501
  "div",
4502
4502
  {
@@ -4505,14 +4505,14 @@ var YourOrders = o.forwardRef(
4505
4505
  className,
4506
4506
  ...props,
4507
4507
  children: [
4508
- /* @__PURE__ */ jsx("div", { style: headerStyle, children: /* @__PURE__ */ jsx("h3", { style: titleStyle, children: title }) }),
4509
- /* @__PURE__ */ jsx("div", { style: tabsRowStyle, children: TABS.map((tab) => {
4510
- const isActive = activeTab === tab.id;
4508
+ /* @__PURE__ */ jsx("div", { style: headerStyle, children: /* @__PURE__ */ jsx("h3", { style: titleStyle, children: displayTitle }) }),
4509
+ resolvedTabs.length > 1 && /* @__PURE__ */ jsx("div", { style: tabsRowStyle, children: resolvedTabs.map((tab) => {
4510
+ const isActive = effectiveActiveTabId === tab.id;
4511
4511
  return /* @__PURE__ */ jsxs(
4512
4512
  "button",
4513
4513
  {
4514
4514
  type: "button",
4515
- onClick: () => setActiveTab(tab.id),
4515
+ onClick: () => handleTabChange(tab.id),
4516
4516
  style: {
4517
4517
  ...tabButtonBase,
4518
4518
  color: isActive ? "#ffffff" : "rgba(255,255,255,0.55)",
@@ -5118,243 +5118,99 @@ var PriceBlock2 = at.span`
5118
5118
  `;
5119
5119
  var PropertySubheader = o.forwardRef(
5120
5120
  ({ className, tabs, activeTabId, onTabChange, actions, ...props }, ref) => {
5121
- const tabRefs = o.useRef([]);
5122
- const tabsWrapperRef = o.useRef(null);
5123
- const scrollContainerRef = o.useRef(null);
5124
- const indicatorRef = o.useRef(null);
5125
- const [isMobile, setIsMobile] = o.useState(false);
5126
- const [tabScrollThumb, setTabScrollThumb] = o.useState({
5127
- widthPercent: 100,
5128
- leftPercent: 0,
5129
- scrollable: false
5130
- });
5131
- const actionContainerStyle = o.useMemo(() => {
5132
- if (isMobile) {
5133
- return {
5134
- order: -1,
5135
- justifyContent: "center",
5136
- gap: "0.45rem",
5137
- flexWrap: "wrap"
5138
- };
5139
- }
5140
- return { order: 0 };
5141
- }, [isMobile]);
5142
- const actionButtonStyle = o.useMemo(() => {
5143
- if (isMobile) {
5144
- return { padding: "0.35rem 0.6rem", fontSize: "11px" };
5145
- }
5146
- return void 0;
5147
- }, [isMobile]);
5148
- const updateTabScrollThumb = o.useCallback(() => {
5149
- const container = scrollContainerRef.current;
5150
- if (!container) return;
5151
- const visibleWidth = container.clientWidth;
5152
- const totalWidth = container.scrollWidth;
5153
- if (totalWidth <= visibleWidth || visibleWidth === 0) {
5154
- setTabScrollThumb(
5155
- (prev2) => prev2.scrollable ? { widthPercent: 100, leftPercent: 0, scrollable: false } : prev2
5156
- );
5157
- return;
5158
- }
5159
- const widthPercent = visibleWidth / totalWidth * 100;
5160
- const maxScroll = Math.max(totalWidth - visibleWidth, 0);
5161
- const scrollRatio = maxScroll === 0 ? 0 : container.scrollLeft / maxScroll;
5162
- const usableTrack = Math.max(100 - widthPercent, 0);
5163
- const leftPercent = scrollRatio * usableTrack;
5164
- setTabScrollThumb({
5165
- widthPercent,
5166
- leftPercent,
5167
- scrollable: true
5168
- });
5169
- }, []);
5170
- const updateMobileIndicator = o.useCallback(() => {
5171
- if (typeof window === "undefined") return;
5172
- if (!indicatorRef.current || !tabsWrapperRef.current) return;
5173
- const isMobile2 = window.matchMedia("(max-width: 768px)").matches;
5174
- if (!isMobile2) {
5175
- indicatorRef.current.style.width = "0px";
5176
- indicatorRef.current.style.transform = "translateX(0)";
5177
- setTabScrollThumb(
5178
- (prev2) => prev2.scrollable ? { widthPercent: 100, leftPercent: 0, scrollable: false } : prev2
5179
- );
5180
- return;
5181
- }
5182
- const activeIndex = tabs.findIndex((tab) => tab.id === activeTabId);
5183
- if (activeIndex === -1) return;
5184
- const activeButton = tabRefs.current[activeIndex];
5185
- if (!activeButton) return;
5186
- const wrapperRect = tabsWrapperRef.current.getBoundingClientRect();
5187
- const buttonRect = activeButton.getBoundingClientRect();
5188
- const width = buttonRect.width;
5189
- const left = buttonRect.left - wrapperRect.left;
5190
- indicatorRef.current.style.width = `${width}px`;
5191
- indicatorRef.current.style.transform = `translateX(${left}px)`;
5192
- updateTabScrollThumb();
5193
- }, [activeTabId, tabs, updateTabScrollThumb]);
5194
- o.useEffect(() => {
5195
- updateMobileIndicator();
5196
- }, [updateMobileIndicator]);
5121
+ const tabsContainerRef = o.useRef(null);
5197
5122
  o.useEffect(() => {
5198
- if (typeof window === "undefined") return;
5199
- const handleResize = () => updateMobileIndicator();
5200
- window.addEventListener("resize", handleResize);
5201
- return () => window.removeEventListener("resize", handleResize);
5202
- }, [updateMobileIndicator]);
5203
- o.useEffect(() => {
5204
- const scrollEl = scrollContainerRef.current;
5205
- if (!scrollEl) return;
5206
- const handleScroll = () => {
5207
- updateMobileIndicator();
5208
- updateTabScrollThumb();
5123
+ const container = tabsContainerRef.current;
5124
+ if (!container) return;
5125
+ const isMobile = window.innerWidth <= 768;
5126
+ if (!isMobile) return;
5127
+ const forceScrollbar = () => {
5128
+ if (container.scrollWidth > container.clientWidth) {
5129
+ container.scrollTop = 1;
5130
+ container.scrollTop = 0;
5131
+ container.scrollLeft = 1;
5132
+ container.scrollLeft = 0;
5133
+ }
5209
5134
  };
5210
- scrollEl.addEventListener("scroll", handleScroll, { passive: true });
5211
- return () => scrollEl.removeEventListener("scroll", handleScroll);
5212
- }, [updateMobileIndicator, updateTabScrollThumb]);
5213
- o.useEffect(() => {
5214
- if (isMobile) {
5215
- updateTabScrollThumb();
5216
- }
5217
- }, [isMobile, updateTabScrollThumb, tabs.length]);
5218
- o.useEffect(() => {
5219
- if (typeof window === "undefined") return;
5220
- const media = window.matchMedia("(max-width: 768px)");
5221
- const setMatch = () => setIsMobile(media.matches);
5222
- setMatch();
5223
- media.addEventListener("change", setMatch);
5224
- return () => media.removeEventListener("change", setMatch);
5225
- }, []);
5135
+ setTimeout(forceScrollbar, 100);
5136
+ window.addEventListener("resize", forceScrollbar);
5137
+ return () => window.removeEventListener("resize", forceScrollbar);
5138
+ }, [tabs]);
5226
5139
  return /* @__PURE__ */ jsxs(
5227
5140
  "div",
5228
5141
  {
5229
5142
  ref,
5230
- className: cn("w-full font-normal flex flex-col gap-3 md:flex-row md:items-center md:justify-between", className),
5143
+ className: cn(
5144
+ "w-full font-normal",
5145
+ "flex flex-col-reverse gap-3",
5146
+ "md:flex-row md:items-center md:justify-between",
5147
+ className
5148
+ ),
5231
5149
  ...props,
5232
5150
  children: [
5233
- /* @__PURE__ */ jsxs(
5151
+ /* @__PURE__ */ jsx(
5234
5152
  "div",
5235
5153
  {
5236
- ref: tabsWrapperRef,
5154
+ ref: tabsContainerRef,
5237
5155
  className: cn(
5238
- "relative flex w-full min-w-0 flex-col",
5239
- "max-[768px]:gap-0",
5240
- "max-[768px]:order-0",
5241
- "md:flex-row md:items-center md:justify-between"
5156
+ "flex items-center border-b border-white/10",
5157
+ "overflow-x-auto md:overflow-visible",
5158
+ "[-webkit-overflow-scrolling:touch]",
5159
+ "[scroll-behavior:smooth]",
5160
+ "[touch-action:pan-x]",
5161
+ "md:border-b-0"
5242
5162
  ),
5243
- style: isMobile ? { gap: 0 } : void 0,
5244
- children: [
5245
- /* @__PURE__ */ jsx(
5246
- "div",
5163
+ style: { WebkitTapHighlightColor: "transparent" },
5164
+ children: /* @__PURE__ */ jsx("div", { className: "flex min-w-max", children: tabs.map((tab) => {
5165
+ const active = tab.id === activeTabId;
5166
+ return /* @__PURE__ */ jsxs(
5167
+ "button",
5247
5168
  {
5248
- ref: scrollContainerRef,
5169
+ type: "button",
5170
+ onClick: () => onTabChange?.(tab.id),
5249
5171
  className: cn(
5250
- "flex w-full min-w-0 items-center",
5251
- "overflow-x-auto md:overflow-visible",
5252
- "[-webkit-overflow-scrolling:touch]",
5253
- "[scrollbar-width:none]",
5254
- "[scroll-behavior:smooth]",
5255
- "[touch-action:pan-x]",
5256
- "md:border-b md:border-white/10"
5172
+ "relative whitespace-nowrap",
5173
+ "px-6 py-4",
5174
+ "font-normal",
5175
+ "transition-colors",
5176
+ "max-[768px]:px-[1.2rem] max-[768px]:py-[0.8rem]",
5177
+ "max-[480px]:px-4 max-[480px]:py-[0.7rem] max-[480px]:text-[0.9rem]",
5178
+ active ? "font-semibold text-[var(--color-accent,#e6c87e)]" : "text-white/60 hover:text-white"
5257
5179
  ),
5258
- style: { WebkitTapHighlightColor: "transparent" },
5259
- children: /* @__PURE__ */ jsx("div", { className: "flex min-w-max gap-2 lg:gap-4", children: tabs.map((tab, index) => {
5260
- const active = tab.id === activeTabId;
5261
- return /* @__PURE__ */ jsxs(
5262
- "button",
5263
- {
5264
- ref: (node2) => {
5265
- tabRefs.current[index] = node2;
5266
- },
5267
- type: "button",
5268
- onClick: () => onTabChange?.(tab.id),
5269
- className: cn(
5270
- "relative whitespace-nowrap",
5271
- "px-5 py-4 lg:px-6",
5272
- "text-[16px]",
5273
- "font-medium",
5274
- "transition-colors",
5275
- "max-[768px]:rounded-full max-[768px]:px-5 max-[768px]:py-3",
5276
- "max-[768px]:text-[15px]",
5277
- "max-[480px]:px-4 max-[480px]:py-[0.75rem] max-[480px]:text-sm",
5278
- active ? "font-semibold text-[var(--color-accent,#e6c87e)] hover:text-[var(--color-accent,#f1d27a)]" : "text-white/65 hover:text-white"
5279
- ),
5280
- style: {
5281
- borderBottom: active ? "2px solid var(--color-accent, #e6c87e)" : "2px solid transparent",
5282
- minWidth: "80px",
5283
- touchAction: "manipulation"
5284
- },
5285
- children: [
5286
- /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1", children: [
5287
- tab.id === "trade" ? /* @__PURE__ */ jsx("span", { className: "hidden h-4 w-4 items-center justify-center rounded-full bg-white/10 text-[11px] text-[var(--color-accent,#e6c87e)] max-[768px]:inline-flex", children: "\u21C5" }) : null,
5288
- tab.label
5289
- ] }),
5290
- tab.hasNotification ? /* @__PURE__ */ jsx(
5291
- "span",
5292
- {
5293
- className: "absolute right-[10px] top-[10px] h-2 w-2 rounded-full animate-pulse",
5294
- style: {
5295
- backgroundColor: tab.notificationColor ?? "#f6465d",
5296
- boxShadow: "0 0 0 0 rgba(246, 70, 93, 0.7)"
5297
- }
5298
- }
5299
- ) : null
5300
- ]
5301
- },
5302
- tab.id
5303
- );
5304
- }) })
5305
- }
5306
- ),
5307
- /* @__PURE__ */ jsx("div", { className: "pointer-events-none relative hidden h-[3px] w-full min-w-0 overflow-hidden rounded-full bg-white/10 max-[768px]:block", style: { marginBottom: "1px" }, children: /* @__PURE__ */ jsx(
5308
- "span",
5309
- {
5310
- ref: indicatorRef,
5311
- className: "absolute left-0 top-0 block h-full rounded-full bg-[var(--color-accent,#e6c87e)] transition-all duration-300 ease-out"
5312
- }
5313
- ) }),
5314
- /* @__PURE__ */ jsx(
5315
- "div",
5316
- {
5317
5180
  style: {
5318
- display: isMobile ? "block" : "none",
5319
- height: "8px",
5320
- width: "100%",
5321
- borderRadius: "999px",
5322
- background: "rgba(18,19,22,0.85)",
5323
- marginTop: "0",
5324
- position: "relative"
5181
+ borderBottom: active ? "2px solid var(--color-accent, #e6c87e)" : "2px solid transparent",
5182
+ minWidth: "80px",
5183
+ touchAction: "manipulation"
5325
5184
  },
5326
- children: /* @__PURE__ */ jsx(
5327
- "div",
5328
- {
5329
- style: {
5330
- position: "absolute",
5331
- top: 0,
5332
- left: `${tabScrollThumb.leftPercent}%`,
5333
- height: "100%",
5334
- borderRadius: "999px",
5335
- background: "rgba(92,94,102,0.85)",
5336
- width: `${tabScrollThumb.widthPercent}%`,
5337
- transition: "left 0.2s ease-out, width 0.2s ease-out, opacity 0.2s ease-out",
5338
- opacity: tabScrollThumb.scrollable ? 1 : 0.25
5185
+ children: [
5186
+ tab.label,
5187
+ tab.hasNotification ? /* @__PURE__ */ jsx(
5188
+ "span",
5189
+ {
5190
+ className: "absolute right-[10px] top-[10px] h-2 w-2 rounded-full animate-pulse",
5191
+ style: {
5192
+ backgroundColor: tab.notificationColor ?? "#f6465d",
5193
+ boxShadow: "0 0 0 0 rgba(246, 70, 93, 0.7)"
5194
+ }
5339
5195
  }
5340
- }
5341
- )
5342
- }
5343
- )
5344
- ]
5196
+ ) : null
5197
+ ]
5198
+ },
5199
+ tab.id
5200
+ );
5201
+ }) })
5345
5202
  }
5346
5203
  ),
5347
5204
  actions != null && actions.length > 0 ? /* @__PURE__ */ jsx(
5348
5205
  "div",
5349
5206
  {
5350
5207
  className: cn(
5351
- "flex items-center gap-[4px] md:gap-[10px]",
5352
- "justify-center md:justify-end",
5208
+ "flex items-center gap-[10px]",
5353
5209
  "overflow-x-auto md:overflow-visible",
5354
5210
  "[scrollbar-width:none]",
5355
- "max-[768px]:w-full max-[768px]:pb-2 max-[768px]:mb-2"
5211
+ "md:justify-end",
5212
+ "max-[768px]:w-full max-[768px]:justify-center max-[768px]:pb-2 max-[768px]:mb-4"
5356
5213
  ),
5357
- style: actionContainerStyle,
5358
5214
  children: actions.map((action) => /* @__PURE__ */ jsxs(
5359
5215
  "button",
5360
5216
  {
@@ -5362,14 +5218,14 @@ var PropertySubheader = o.forwardRef(
5362
5218
  onClick: action.onClick,
5363
5219
  className: cn(
5364
5220
  "flex shrink-0 items-center gap-[5px] whitespace-nowrap",
5365
- "rounded-[6px]",
5366
- "border border-white/15",
5221
+ "rounded",
5222
+ "border border-white/10",
5367
5223
  "bg-transparent",
5368
- "px-3.5 py-1.5 text-[14px] font-medium",
5224
+ "px-3 py-1.5 text-[14px] font-normal",
5369
5225
  "transition-all",
5226
+ "max-[768px]:px-2.5 max-[768px]:py-[5px] max-[768px]:text-[13px]",
5370
5227
  "hover:bg-white/5 hover:border-[var(--color-accent,#e6c87e)] hover:text-[var(--color-accent,#e6c87e)]"
5371
5228
  ),
5372
- style: actionButtonStyle,
5373
5229
  children: [
5374
5230
  action.icon,
5375
5231
  action.label