@loafmarkets/ui 0.0.5 → 0.0.6

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
@@ -116,9 +116,10 @@ interface HousePositionSliderProps extends React.HTMLAttributes<HTMLDivElement>
116
116
  pendingOrders?: HousePositionPendingOrder[];
117
117
  defaultOrderType?: "market" | "limit";
118
118
  orderbook?: HousePositionOrderbook;
119
+ ownershipPercentOverride?: number;
119
120
  onConfirmOrder?: (payload: HousePositionSliderOrderPayload) => void;
120
121
  }
121
- declare function HousePositionSlider({ tokenId, tokenSymbol, totalTokens, currentPrice, availableCash, tokensHeld, pendingOrders, defaultOrderType, orderbook, onConfirmOrder, className, ...props }: HousePositionSliderProps): react_jsx_runtime.JSX.Element;
122
+ declare function HousePositionSlider({ tokenId, tokenSymbol, totalTokens, currentPrice, availableCash, tokensHeld, pendingOrders, defaultOrderType, orderbook, ownershipPercentOverride, onConfirmOrder, className, ...props }: HousePositionSliderProps): react_jsx_runtime.JSX.Element;
122
123
 
123
124
  type PropertyTourProps = Omit<React.ComponentPropsWithoutRef<typeof Card>, "title"> & {
124
125
  title: string;
package/dist/index.d.ts CHANGED
@@ -116,9 +116,10 @@ interface HousePositionSliderProps extends React.HTMLAttributes<HTMLDivElement>
116
116
  pendingOrders?: HousePositionPendingOrder[];
117
117
  defaultOrderType?: "market" | "limit";
118
118
  orderbook?: HousePositionOrderbook;
119
+ ownershipPercentOverride?: number;
119
120
  onConfirmOrder?: (payload: HousePositionSliderOrderPayload) => void;
120
121
  }
121
- declare function HousePositionSlider({ tokenId, tokenSymbol, totalTokens, currentPrice, availableCash, tokensHeld, pendingOrders, defaultOrderType, orderbook, onConfirmOrder, className, ...props }: HousePositionSliderProps): react_jsx_runtime.JSX.Element;
122
+ declare function HousePositionSlider({ tokenId, tokenSymbol, totalTokens, currentPrice, availableCash, tokensHeld, pendingOrders, defaultOrderType, orderbook, ownershipPercentOverride, onConfirmOrder, className, ...props }: HousePositionSliderProps): react_jsx_runtime.JSX.Element;
122
123
 
123
124
  type PropertyTourProps = Omit<React.ComponentPropsWithoutRef<typeof Card>, "title"> & {
124
125
  title: string;
package/dist/index.js CHANGED
@@ -304,6 +304,7 @@ function HousePositionSlider({
304
304
  pendingOrders = [],
305
305
  defaultOrderType = "market",
306
306
  orderbook,
307
+ ownershipPercentOverride,
307
308
  onConfirmOrder,
308
309
  className,
309
310
  ...props
@@ -314,6 +315,7 @@ function HousePositionSlider({
314
315
  const [deltaTokensBuy, setDeltaTokensBuy] = React5__namespace.useState(0);
315
316
  const [deltaTokensSell, setDeltaTokensSell] = React5__namespace.useState(0);
316
317
  const [isDragging, setIsDragging] = React5__namespace.useState(false);
318
+ const [visualTargetPct, setVisualTargetPct] = React5__namespace.useState(null);
317
319
  const [orderType, setOrderType] = React5__namespace.useState(defaultOrderType);
318
320
  const [limitPrice, setLimitPrice] = React5__namespace.useState(currentPrice);
319
321
  const [limitPriceInput, setLimitPriceInput] = React5__namespace.useState(currentPrice.toFixed(2));
@@ -335,9 +337,8 @@ function HousePositionSlider({
335
337
  const effectiveAvailableCash = Math.max(0, availableCash - pendingBuyValue);
336
338
  const effectiveTokensHeld = Math.max(0, tokensHeld - pendingSellTokens);
337
339
  const holdingsValue = tokensHeld * effectivePrice;
338
- const sliderHoldingsValue = effectiveTokensHeld * effectivePrice;
339
- const sliderTotalCapacity = sliderHoldingsValue + effectiveAvailableCash;
340
- const baselinePct = sliderTotalCapacity <= 0 ? 0 : sliderHoldingsValue / sliderTotalCapacity * 100;
340
+ const safeTotalTokens = totalTokens > 0 ? totalTokens : 1;
341
+ const baselineOwnershipActual = clamp(effectiveTokensHeld / safeTotalTokens * 100, 0, 100);
341
342
  let deltaTokens = 0;
342
343
  let deltaValue = 0;
343
344
  let marketAvgPrice = null;
@@ -383,29 +384,21 @@ function HousePositionSlider({
383
384
  }
384
385
  targetTokens = tokensHeld + deltaTokens;
385
386
  targetValue = targetTokens * effectivePrice;
386
- const plannedDeltaValue = (() => {
387
- if (orderMode === "buy") {
388
- if (buyTrackingMode === "dollars") {
389
- const notional = Math.min(Math.max(0, deltaDollars), effectiveAvailableCash);
390
- return notional;
391
- }
392
- const tokensPlanned = Math.max(0, deltaTokensBuy);
393
- const referencePrice = orderType === "market" ? currentPrice || limitPriceSafe : limitPriceSafe;
394
- return Math.min(tokensPlanned * referencePrice, effectiveAvailableCash);
395
- }
396
- if (orderMode === "sell") {
397
- const tokensToSell = Math.abs(Math.min(0, deltaTokensSell));
398
- const sellValue = tokensToSell * effectivePrice;
399
- return -Math.min(sellValue, sliderHoldingsValue);
400
- }
401
- return 0;
402
- })();
403
- const sliderTargetValue = clamp(sliderHoldingsValue + plannedDeltaValue, 0, sliderTotalCapacity);
404
- const targetPct = sliderTotalCapacity <= 0 ? 0 : sliderTargetValue / sliderTotalCapacity * 100;
387
+ const sliderTargetTokens = clamp(effectiveTokensHeld + deltaTokens, 0, safeTotalTokens);
388
+ const normalizedTargetPct = sliderTargetTokens / safeTotalTokens * 100;
405
389
  const isIncrease = orderMode === "buy";
406
390
  const hasChange = orderMode !== "none" && (Math.abs(deltaTokens) > 1e-3 || Math.abs(deltaValue) > 0.01);
407
- const currentOwnership = totalTokens <= 0 ? 0 : tokensHeld / totalTokens * 100;
408
- const targetOwnership = totalTokens <= 0 ? 0 : targetTokens / totalTokens * 100;
391
+ const currentOwnership = totalTokens <= 0 ? 0 : clamp(tokensHeld / totalTokens * 100, 0, 100);
392
+ const targetOwnership = totalTokens <= 0 ? 0 : clamp(targetTokens / totalTokens * 100, 0, 100);
393
+ const ownershipOverrideValue = typeof ownershipPercentOverride === "number" && Number.isFinite(ownershipPercentOverride) ? clamp(ownershipPercentOverride, 0, 100) : null;
394
+ const ownershipShift = ownershipOverrideValue != null ? ownershipOverrideValue - baselineOwnershipActual : 0;
395
+ const baselinePct = clamp(ownershipOverrideValue ?? baselineOwnershipActual, 0, 100);
396
+ const impliedTargetPct = clamp(normalizedTargetPct + ownershipShift, 0, 100);
397
+ const displayTargetPct = visualTargetPct ?? impliedTargetPct;
398
+ const targetPct = displayTargetPct;
399
+ const displayCurrentOwnership = clamp(ownershipOverrideValue ?? currentOwnership, 0, 100);
400
+ const impliedDisplayTargetOwnership = clamp(targetOwnership + ownershipShift, 0, 100);
401
+ const displayTargetOwnership = visualTargetPct ?? impliedDisplayTargetOwnership;
409
402
  const estFeeTokens = Math.abs(deltaValue) * 5e-3 / (effectivePrice || 1);
410
403
  const resetOrder = React5__namespace.useCallback(() => {
411
404
  setOrderMode("none");
@@ -413,6 +406,7 @@ function HousePositionSlider({
413
406
  setDeltaDollars(0);
414
407
  setDeltaTokensBuy(0);
415
408
  setDeltaTokensSell(0);
409
+ setVisualTargetPct(null);
416
410
  }, []);
417
411
  const updateOrderFromTargetValue = React5__namespace.useCallback(
418
412
  (newTargetValue) => {
@@ -443,6 +437,7 @@ function HousePositionSlider({
443
437
  const nextOwnership = clamp(newOwnershipPercent, 0, 100);
444
438
  const newTargetTokens = nextOwnership / 100 * totalTokens;
445
439
  updateOrderFromTargetValue(newTargetTokens * effectivePrice);
440
+ setVisualTargetPct(nextOwnership);
446
441
  },
447
442
  [effectivePrice, totalTokens, updateOrderFromTargetValue]
448
443
  );
@@ -475,12 +470,14 @@ function HousePositionSlider({
475
470
  const magnitude = Math.min(Math.abs(normalized), 1);
476
471
  if (magnitude < 0.02) {
477
472
  resetOrder();
473
+ setVisualTargetPct(null);
478
474
  return;
479
475
  }
480
476
  if (normalized > 0) {
481
477
  const notional = clamp(magnitude * effectiveAvailableCash, 0, effectiveAvailableCash);
482
478
  if (notional <= 0) {
483
479
  resetOrder();
480
+ setVisualTargetPct(null);
484
481
  return;
485
482
  }
486
483
  setOrderMode("buy");
@@ -488,12 +485,14 @@ function HousePositionSlider({
488
485
  setDeltaDollars(notional);
489
486
  setDeltaTokensBuy(0);
490
487
  setDeltaTokensSell(0);
488
+ setVisualTargetPct(clamp(pct, 0, 100));
491
489
  return;
492
490
  }
493
491
  if (normalized < 0) {
494
492
  const tokensToSell = clamp(magnitude * effectiveTokensHeld, 0, effectiveTokensHeld);
495
493
  if (tokensToSell <= 0) {
496
494
  resetOrder();
495
+ setVisualTargetPct(null);
497
496
  return;
498
497
  }
499
498
  setOrderMode("sell");
@@ -501,9 +500,11 @@ function HousePositionSlider({
501
500
  setDeltaTokensSell(-tokensToSell);
502
501
  setDeltaDollars(0);
503
502
  setDeltaTokensBuy(0);
503
+ setVisualTargetPct(clamp(pct, 0, 100));
504
504
  return;
505
505
  }
506
506
  resetOrder();
507
+ setVisualTargetPct(null);
507
508
  },
508
509
  [effectiveAvailableCash, effectiveTokensHeld, resetOrder]
509
510
  );
@@ -666,19 +667,19 @@ function HousePositionSlider({
666
667
  " Ownership"
667
668
  ] }),
668
669
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-white", children: [
669
- currentOwnership.toFixed(2),
670
+ displayCurrentOwnership.toFixed(2),
670
671
  "%",
671
672
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mx-1.5 text-white/50", children: "\u2192" }),
672
673
  /* @__PURE__ */ jsxRuntime.jsx(
673
674
  "input",
674
675
  {
675
676
  type: "text",
676
- value: ownershipInput || targetOwnership.toFixed(2),
677
+ value: ownershipInput || displayTargetOwnership.toFixed(2),
677
678
  onChange: (e) => {
678
679
  const val = e.target.value;
679
680
  if (val === "" || /^[0-9]*\.?[0-9]*$/.test(val)) setOwnershipInput(val);
680
681
  },
681
- onFocus: () => setOwnershipInput(targetOwnership.toFixed(2)),
682
+ onFocus: () => setOwnershipInput(displayTargetOwnership.toFixed(2)),
682
683
  onBlur: () => {
683
684
  const num = Number.parseFloat(ownershipInput);
684
685
  if (Number.isFinite(num)) updateOrderFromOwnership(num);
@@ -689,7 +690,7 @@ function HousePositionSlider({
689
690
  },
690
691
  className: cn(
691
692
  "w-[70px] rounded-[4px] border bg-white/10 px-2 py-1 text-right font-semibold outline-none",
692
- targetOwnership >= currentOwnership ? "border-[rgba(14,203,129,0.3)] text-[#0ecb81] focus:border-[#0ecb81]" : "border-[rgba(246,70,93,0.3)] text-[#f6465d] focus:border-[#f6465d]"
693
+ displayTargetOwnership >= displayCurrentOwnership ? "border-[rgba(14,203,129,0.3)] text-[#0ecb81] focus:border-[#0ecb81]" : "border-[rgba(246,70,93,0.3)] text-[#f6465d] focus:border-[#f6465d]"
693
694
  )
694
695
  }
695
696
  )
@@ -1317,12 +1318,13 @@ var PropertyCompareBar = React5__namespace.forwardRef(
1317
1318
  {
1318
1319
  ref,
1319
1320
  className: cn(
1320
- "flex w-full flex-col gap-3 rounded-[14px] border border-[#1a1f2b] bg-[#0f131c] px-4 py-3 text-white shadow-[0_18px_45px_rgba(0,0,0,0.55)] md:flex-row md:items-center md:gap-4",
1321
+ "flex w-full flex-col gap-3 border border-white/10 px-4 py-3 text-white shadow-[0_18px_40px_rgba(0,0,0,0.55)] md:flex-row md:items-center md:justify-between md:gap-4",
1321
1322
  className
1322
1323
  ),
1324
+ style: { borderRadius: "16px" },
1323
1325
  ...props,
1324
1326
  children: [
1325
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex-1", ref: dropdownRef, children: [
1327
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-auto", ref: dropdownRef, children: [
1326
1328
  /* @__PURE__ */ jsxRuntime.jsxs(
1327
1329
  "button",
1328
1330
  {
@@ -1330,7 +1332,7 @@ var PropertyCompareBar = React5__namespace.forwardRef(
1330
1332
  disabled: !hasAddresses,
1331
1333
  onClick: () => setIsDropdownOpen((prev) => !prev),
1332
1334
  className: cn(
1333
- "flex h-[42px] w-full items-center justify-between rounded-[10px] border border-[#202632] bg-[#181c27] px-4 text-left text-[15px] font-semibold text-white shadow-[inset_0_1px_0_rgba(255,255,255,0.05)] transition hover:bg-[#1d222e] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-accent,#e6c87e)]",
1335
+ "flex h-[42px] w-auto items-center gap-2 rounded-[12px] border border-transparent bg-transparent px-0 text-left text-[15px] font-semibold text-white transition hover:text-white/80 focus-visible:outline-none",
1334
1336
  !hasAddresses && "text-white/40"
1335
1337
  ),
1336
1338
  children: [
@@ -1349,7 +1351,7 @@ var PropertyCompareBar = React5__namespace.forwardRef(
1349
1351
  ]
1350
1352
  }
1351
1353
  ),
1352
- isDropdownOpen && hasAddresses ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-0 top-[calc(100%+8px)] z-20 w-full rounded-[12px] border border-[#1f2431] bg-[#161925] py-1 shadow-[0_25px_55px_rgba(0,0,0,0.65)] backdrop-blur-sm", children: normalizedAddresses.map((option) => {
1354
+ isDropdownOpen && hasAddresses ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-0 top-[calc(100%+8px)] z-20 w-full rounded-[12px] border border-white/10 py-1 shadow-[0_25px_55px_rgba(0,0,0,0.6)] bg-black", children: normalizedAddresses.map((option) => {
1353
1355
  const active = option.id === resolvedSelectedId;
1354
1356
  return /* @__PURE__ */ jsxRuntime.jsx(
1355
1357
  "button",
@@ -1371,7 +1373,7 @@ var PropertyCompareBar = React5__namespace.forwardRef(
1371
1373
  {
1372
1374
  variant: "accentOutline",
1373
1375
  size: "sm",
1374
- className: "flex w-full items-center justify-center gap-2 rounded-[10px] border-[var(--color-accent,#e6c87e)] bg-transparent px-4 py-2 text-[14px] font-semibold text-[var(--color-accent,#e6c87e)] shadow-[0_10px_25px_rgba(0,0,0,0.45)] transition hover:bg-[rgba(230,200,126,0.08)] md:w-max",
1376
+ className: "flex items-center justify-center gap-2 rounded-[10px] border-[var(--color-accent,#e6c87e)] bg-transparent px-4 py-2 text-[14px] font-semibold text-[var(--color-accent,#e6c87e)] transition hover:bg-[rgba(230,200,126,0.08)] md:ml-auto",
1375
1377
  onClick: onCompareClick,
1376
1378
  disabled: !hasAddresses,
1377
1379
  children: [