@loafmarkets/ui 0.0.1 → 0.0.3
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 +35 -30
- package/dist/index.d.ts +35 -30
- package/dist/index.js +230 -65
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +230 -65
- package/dist/index.mjs.map +1 -1
- package/package.json +11 -11
package/dist/index.mjs
CHANGED
|
@@ -212,6 +212,66 @@ var PortfolioSummary = React5.forwardRef(
|
|
|
212
212
|
PortfolioSummary.displayName = "PortfolioSummary";
|
|
213
213
|
var clamp = (v, min, max) => Math.min(max, Math.max(min, v));
|
|
214
214
|
var fmt0 = (v) => Math.abs(v).toLocaleString(void 0, { maximumFractionDigits: 0 });
|
|
215
|
+
var normalizeLevels = (levels = []) => levels.filter((level) => Number.isFinite(level.price) && level.price > 0 && Number.isFinite(level.amount) && level.amount > 0);
|
|
216
|
+
var estimateMarketBuyFromUsd = (levels = [], usdAmount) => {
|
|
217
|
+
if (!Number.isFinite(usdAmount) || usdAmount <= 0) return { tokens: 0, value: 0, avgPrice: null };
|
|
218
|
+
const asks = normalizeLevels(levels).sort((a, b) => a.price - b.price);
|
|
219
|
+
let remainingUsd = usdAmount;
|
|
220
|
+
let tokensFilled = 0;
|
|
221
|
+
let spent = 0;
|
|
222
|
+
for (const level of asks) {
|
|
223
|
+
if (remainingUsd <= 0) break;
|
|
224
|
+
const levelValueCapacity = level.amount * level.price;
|
|
225
|
+
const usdToSpend = Math.min(remainingUsd, levelValueCapacity);
|
|
226
|
+
const tokensFromLevel = usdToSpend / level.price;
|
|
227
|
+
tokensFilled += tokensFromLevel;
|
|
228
|
+
spent += usdToSpend;
|
|
229
|
+
remainingUsd -= usdToSpend;
|
|
230
|
+
}
|
|
231
|
+
return {
|
|
232
|
+
tokens: tokensFilled,
|
|
233
|
+
value: spent,
|
|
234
|
+
avgPrice: tokensFilled > 0 ? spent / tokensFilled : null
|
|
235
|
+
};
|
|
236
|
+
};
|
|
237
|
+
var estimateMarketBuyFromTokens = (levels = [], tokenAmount) => {
|
|
238
|
+
if (!Number.isFinite(tokenAmount) || tokenAmount <= 0) return { tokens: 0, value: 0, avgPrice: null };
|
|
239
|
+
const asks = normalizeLevels(levels).sort((a, b) => a.price - b.price);
|
|
240
|
+
let remainingTokens = tokenAmount;
|
|
241
|
+
let tokensFilled = 0;
|
|
242
|
+
let spent = 0;
|
|
243
|
+
for (const level of asks) {
|
|
244
|
+
if (remainingTokens <= 0) break;
|
|
245
|
+
const tokensFromLevel = Math.min(remainingTokens, level.amount);
|
|
246
|
+
spent += tokensFromLevel * level.price;
|
|
247
|
+
tokensFilled += tokensFromLevel;
|
|
248
|
+
remainingTokens -= tokensFromLevel;
|
|
249
|
+
}
|
|
250
|
+
return {
|
|
251
|
+
tokens: tokensFilled,
|
|
252
|
+
value: spent,
|
|
253
|
+
avgPrice: tokensFilled > 0 ? spent / tokensFilled : null
|
|
254
|
+
};
|
|
255
|
+
};
|
|
256
|
+
var estimateMarketSellFromTokens = (levels = [], tokenAmount) => {
|
|
257
|
+
if (!Number.isFinite(tokenAmount) || tokenAmount <= 0) return { tokens: 0, value: 0, avgPrice: null };
|
|
258
|
+
const bids = normalizeLevels(levels).sort((a, b) => b.price - a.price);
|
|
259
|
+
let remainingTokens = tokenAmount;
|
|
260
|
+
let tokensFilled = 0;
|
|
261
|
+
let received = 0;
|
|
262
|
+
for (const level of bids) {
|
|
263
|
+
if (remainingTokens <= 0) break;
|
|
264
|
+
const tokensFromLevel = Math.min(remainingTokens, level.amount);
|
|
265
|
+
received += tokensFromLevel * level.price;
|
|
266
|
+
tokensFilled += tokensFromLevel;
|
|
267
|
+
remainingTokens -= tokensFromLevel;
|
|
268
|
+
}
|
|
269
|
+
return {
|
|
270
|
+
tokens: tokensFilled,
|
|
271
|
+
value: received,
|
|
272
|
+
avgPrice: tokensFilled > 0 ? received / tokensFilled : null
|
|
273
|
+
};
|
|
274
|
+
};
|
|
215
275
|
function HousePositionSlider({
|
|
216
276
|
tokenId,
|
|
217
277
|
tokenSymbol,
|
|
@@ -221,6 +281,7 @@ function HousePositionSlider({
|
|
|
221
281
|
tokensHeld,
|
|
222
282
|
pendingOrders = [],
|
|
223
283
|
defaultOrderType = "market",
|
|
284
|
+
orderbook,
|
|
224
285
|
onConfirmOrder,
|
|
225
286
|
className,
|
|
226
287
|
...props
|
|
@@ -234,45 +295,103 @@ function HousePositionSlider({
|
|
|
234
295
|
const [orderType, setOrderType] = React5.useState(defaultOrderType);
|
|
235
296
|
const [limitPrice, setLimitPrice] = React5.useState(currentPrice);
|
|
236
297
|
const [limitPriceInput, setLimitPriceInput] = React5.useState(currentPrice.toFixed(2));
|
|
298
|
+
const [limitPriceDirty, setLimitPriceDirty] = React5.useState(false);
|
|
237
299
|
const [ownershipInput, setOwnershipInput] = React5.useState("");
|
|
238
300
|
const [tokenAmountInput, setTokenAmountInput] = React5.useState("");
|
|
239
301
|
const houseRef = React5.useRef(null);
|
|
302
|
+
const asks = orderbook?.asks ?? [];
|
|
303
|
+
const bids = orderbook?.bids ?? [];
|
|
240
304
|
React5.useEffect(() => {
|
|
305
|
+
if (orderType !== "limit") return;
|
|
306
|
+
if (limitPriceDirty) return;
|
|
241
307
|
setLimitPrice(currentPrice);
|
|
242
308
|
setLimitPriceInput(currentPrice.toFixed(2));
|
|
243
|
-
}, [currentPrice]);
|
|
309
|
+
}, [currentPrice, limitPriceDirty, orderType]);
|
|
244
310
|
const effectivePrice = orderType === "limit" ? limitPrice : currentPrice;
|
|
245
|
-
const holdingsValue = tokensHeld * effectivePrice;
|
|
246
|
-
const totalCapacity = holdingsValue + availableCash;
|
|
247
311
|
const pendingBuyValue = pendingOrders.filter((o) => o.type === "buy").reduce((s, o) => s + o.value, 0);
|
|
248
312
|
const pendingSellTokens = pendingOrders.filter((o) => o.type === "sell").reduce((s, o) => s + Math.abs(o.tokens), 0);
|
|
249
313
|
const effectiveAvailableCash = Math.max(0, availableCash - pendingBuyValue);
|
|
250
314
|
const effectiveTokensHeld = Math.max(0, tokensHeld - pendingSellTokens);
|
|
251
|
-
const
|
|
315
|
+
const holdingsValue = tokensHeld * effectivePrice;
|
|
316
|
+
const sliderHoldingsValue = effectiveTokensHeld * effectivePrice;
|
|
317
|
+
const sliderTotalCapacity = sliderHoldingsValue + effectiveAvailableCash;
|
|
318
|
+
const baselinePct = sliderTotalCapacity <= 0 ? 0 : sliderHoldingsValue / sliderTotalCapacity * 100;
|
|
252
319
|
let deltaTokens = 0;
|
|
253
320
|
let deltaValue = 0;
|
|
321
|
+
let marketAvgPrice = null;
|
|
254
322
|
let targetTokens = tokensHeld;
|
|
255
323
|
let targetValue = holdingsValue;
|
|
324
|
+
const limitPriceSafe = limitPrice > 0 ? limitPrice : currentPrice || 1;
|
|
256
325
|
if (orderMode === "buy") {
|
|
257
|
-
if (
|
|
258
|
-
|
|
259
|
-
|
|
326
|
+
if (orderType === "market") {
|
|
327
|
+
if (buyTrackingMode === "tokens") {
|
|
328
|
+
const desiredTokens = Math.max(0, deltaTokensBuy);
|
|
329
|
+
const result = estimateMarketBuyFromTokens(asks, desiredTokens);
|
|
330
|
+
deltaTokens = result.tokens;
|
|
331
|
+
deltaValue = result.value;
|
|
332
|
+
marketAvgPrice = result.avgPrice;
|
|
333
|
+
} else {
|
|
334
|
+
const notional = Math.min(Math.max(0, deltaDollars), effectiveAvailableCash);
|
|
335
|
+
const result = estimateMarketBuyFromUsd(asks, notional);
|
|
336
|
+
deltaTokens = result.tokens;
|
|
337
|
+
deltaValue = result.value;
|
|
338
|
+
marketAvgPrice = result.avgPrice;
|
|
339
|
+
}
|
|
260
340
|
} else {
|
|
261
|
-
|
|
262
|
-
|
|
341
|
+
if (buyTrackingMode === "tokens") {
|
|
342
|
+
deltaTokens = deltaTokensBuy;
|
|
343
|
+
deltaValue = deltaTokensBuy * limitPriceSafe;
|
|
344
|
+
} else {
|
|
345
|
+
const notional = Math.min(Math.max(0, deltaDollars), effectiveAvailableCash);
|
|
346
|
+
deltaValue = notional;
|
|
347
|
+
deltaTokens = notional / limitPriceSafe;
|
|
348
|
+
}
|
|
263
349
|
}
|
|
264
350
|
} else if (orderMode === "sell") {
|
|
265
|
-
|
|
266
|
-
|
|
351
|
+
if (orderType === "market") {
|
|
352
|
+
const tokensToSell = Math.abs(deltaTokensSell);
|
|
353
|
+
const result = estimateMarketSellFromTokens(bids, tokensToSell);
|
|
354
|
+
deltaTokens = -result.tokens;
|
|
355
|
+
deltaValue = -result.value;
|
|
356
|
+
marketAvgPrice = result.avgPrice;
|
|
357
|
+
} else {
|
|
358
|
+
deltaTokens = deltaTokensSell;
|
|
359
|
+
deltaValue = deltaTokensSell * limitPriceSafe;
|
|
360
|
+
}
|
|
267
361
|
}
|
|
268
362
|
targetTokens = tokensHeld + deltaTokens;
|
|
269
363
|
targetValue = targetTokens * effectivePrice;
|
|
270
|
-
const
|
|
364
|
+
const plannedDeltaValue = (() => {
|
|
365
|
+
if (orderMode === "buy") {
|
|
366
|
+
if (buyTrackingMode === "dollars") {
|
|
367
|
+
const notional = Math.min(Math.max(0, deltaDollars), effectiveAvailableCash);
|
|
368
|
+
return notional;
|
|
369
|
+
}
|
|
370
|
+
const tokensPlanned = Math.max(0, deltaTokensBuy);
|
|
371
|
+
const referencePrice = orderType === "market" ? currentPrice || limitPriceSafe : limitPriceSafe;
|
|
372
|
+
return Math.min(tokensPlanned * referencePrice, effectiveAvailableCash);
|
|
373
|
+
}
|
|
374
|
+
if (orderMode === "sell") {
|
|
375
|
+
const tokensToSell = Math.abs(Math.min(0, deltaTokensSell));
|
|
376
|
+
const sellValue = tokensToSell * effectivePrice;
|
|
377
|
+
return -Math.min(sellValue, sliderHoldingsValue);
|
|
378
|
+
}
|
|
379
|
+
return 0;
|
|
380
|
+
})();
|
|
381
|
+
const sliderTargetValue = clamp(sliderHoldingsValue + plannedDeltaValue, 0, sliderTotalCapacity);
|
|
382
|
+
const targetPct = sliderTotalCapacity <= 0 ? 0 : sliderTargetValue / sliderTotalCapacity * 100;
|
|
271
383
|
const isIncrease = orderMode === "buy";
|
|
272
384
|
const hasChange = orderMode !== "none" && (Math.abs(deltaTokens) > 1e-3 || Math.abs(deltaValue) > 0.01);
|
|
273
385
|
const currentOwnership = totalTokens <= 0 ? 0 : tokensHeld / totalTokens * 100;
|
|
274
386
|
const targetOwnership = totalTokens <= 0 ? 0 : targetTokens / totalTokens * 100;
|
|
275
387
|
const estFeeTokens = Math.abs(deltaValue) * 5e-3 / (effectivePrice || 1);
|
|
388
|
+
const resetOrder = React5.useCallback(() => {
|
|
389
|
+
setOrderMode("none");
|
|
390
|
+
setBuyTrackingMode("dollars");
|
|
391
|
+
setDeltaDollars(0);
|
|
392
|
+
setDeltaTokensBuy(0);
|
|
393
|
+
setDeltaTokensSell(0);
|
|
394
|
+
}, []);
|
|
276
395
|
const updateOrderFromTargetValue = React5.useCallback(
|
|
277
396
|
(newTargetValue) => {
|
|
278
397
|
const newDeltaValue = newTargetValue - holdingsValue;
|
|
@@ -293,13 +412,9 @@ function HousePositionSlider({
|
|
|
293
412
|
setDeltaTokensBuy(0);
|
|
294
413
|
return;
|
|
295
414
|
}
|
|
296
|
-
|
|
297
|
-
setBuyTrackingMode("dollars");
|
|
298
|
-
setDeltaDollars(0);
|
|
299
|
-
setDeltaTokensBuy(0);
|
|
300
|
-
setDeltaTokensSell(0);
|
|
415
|
+
resetOrder();
|
|
301
416
|
},
|
|
302
|
-
[effectiveAvailableCash, effectivePrice, effectiveTokensHeld, holdingsValue, tokensHeld]
|
|
417
|
+
[effectiveAvailableCash, effectivePrice, effectiveTokensHeld, holdingsValue, resetOrder, tokensHeld]
|
|
303
418
|
);
|
|
304
419
|
const updateOrderFromOwnership = React5.useCallback(
|
|
305
420
|
(newOwnershipPercent) => {
|
|
@@ -328,13 +443,47 @@ function HousePositionSlider({
|
|
|
328
443
|
setDeltaTokensBuy(0);
|
|
329
444
|
return;
|
|
330
445
|
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
446
|
+
resetOrder();
|
|
447
|
+
},
|
|
448
|
+
[effectiveAvailableCash, effectivePrice, effectiveTokensHeld, resetOrder]
|
|
449
|
+
);
|
|
450
|
+
const updateOrderFromSlider = React5.useCallback(
|
|
451
|
+
(pct) => {
|
|
452
|
+
const normalized = (pct - 50) / 50;
|
|
453
|
+
const magnitude = Math.min(Math.abs(normalized), 1);
|
|
454
|
+
if (magnitude < 0.02) {
|
|
455
|
+
resetOrder();
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
if (normalized > 0) {
|
|
459
|
+
const notional = clamp(magnitude * effectiveAvailableCash, 0, effectiveAvailableCash);
|
|
460
|
+
if (notional <= 0) {
|
|
461
|
+
resetOrder();
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
setOrderMode("buy");
|
|
465
|
+
setBuyTrackingMode("dollars");
|
|
466
|
+
setDeltaDollars(notional);
|
|
467
|
+
setDeltaTokensBuy(0);
|
|
468
|
+
setDeltaTokensSell(0);
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
if (normalized < 0) {
|
|
472
|
+
const tokensToSell = clamp(magnitude * effectiveTokensHeld, 0, effectiveTokensHeld);
|
|
473
|
+
if (tokensToSell <= 0) {
|
|
474
|
+
resetOrder();
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
setOrderMode("sell");
|
|
478
|
+
setBuyTrackingMode("dollars");
|
|
479
|
+
setDeltaTokensSell(-tokensToSell);
|
|
480
|
+
setDeltaDollars(0);
|
|
481
|
+
setDeltaTokensBuy(0);
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
resetOrder();
|
|
336
485
|
},
|
|
337
|
-
[effectiveAvailableCash,
|
|
486
|
+
[effectiveAvailableCash, effectiveTokensHeld, resetOrder]
|
|
338
487
|
);
|
|
339
488
|
const handleDragAtClientY = React5.useCallback(
|
|
340
489
|
(clientY) => {
|
|
@@ -342,9 +491,9 @@ function HousePositionSlider({
|
|
|
342
491
|
const rect = houseRef.current.getBoundingClientRect();
|
|
343
492
|
const y = clientY - rect.top;
|
|
344
493
|
const pct = clamp(100 - y / rect.height * 100, 0, 100);
|
|
345
|
-
|
|
494
|
+
updateOrderFromSlider(pct);
|
|
346
495
|
},
|
|
347
|
-
[
|
|
496
|
+
[updateOrderFromSlider]
|
|
348
497
|
);
|
|
349
498
|
const onMouseDown = (e) => {
|
|
350
499
|
e.preventDefault();
|
|
@@ -374,15 +523,21 @@ function HousePositionSlider({
|
|
|
374
523
|
document.addEventListener("touchend", onEnd);
|
|
375
524
|
};
|
|
376
525
|
const handleCancel = () => {
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
526
|
+
resetOrder();
|
|
527
|
+
};
|
|
528
|
+
const handleOrderTypeSelection = (next) => {
|
|
529
|
+
setOrderType(next);
|
|
530
|
+
if (next === "limit") {
|
|
531
|
+
setLimitPriceDirty(false);
|
|
532
|
+
setLimitPrice(currentPrice);
|
|
533
|
+
setLimitPriceInput(currentPrice.toFixed(2));
|
|
534
|
+
} else {
|
|
535
|
+
setLimitPriceDirty(false);
|
|
536
|
+
}
|
|
382
537
|
};
|
|
383
538
|
const handleConfirm = () => {
|
|
384
539
|
if (!hasChange) return;
|
|
385
|
-
const priceToUse = orderType === "market" ? currentPrice : limitPrice;
|
|
540
|
+
const priceToUse = orderType === "market" ? marketAvgPrice ?? currentPrice : limitPrice;
|
|
386
541
|
onConfirmOrder?.({
|
|
387
542
|
side: isIncrease ? "buy" : "sell",
|
|
388
543
|
orderType,
|
|
@@ -407,6 +562,8 @@ function HousePositionSlider({
|
|
|
407
562
|
const showIncrease = targetPct > baselinePct;
|
|
408
563
|
const showDecrease = targetPct < baselinePct;
|
|
409
564
|
const valueLabel = orderType === "limit" ? `${tokenSymbol} Owned at Limit` : `${tokenSymbol} Owned`;
|
|
565
|
+
const deltaSign = deltaValue > 0 ? "+" : deltaValue < 0 ? "-" : "";
|
|
566
|
+
const percentMarkers = [100, 50, 25, 0];
|
|
410
567
|
return /* @__PURE__ */ jsxs("div", { className: cn("relative flex w-full flex-col items-center gap-6 rounded-[12px] bg-black/20 px-8 pb-6 pt-12", className), ...props, children: [
|
|
411
568
|
/* @__PURE__ */ jsx("div", { className: "absolute left-4 top-4 text-[1.1rem] font-semibold tracking-[0.5px] text-white", children: "Place Order" }),
|
|
412
569
|
hasChange ? /* @__PURE__ */ jsx(
|
|
@@ -420,46 +577,53 @@ function HousePositionSlider({
|
|
|
420
577
|
) : null,
|
|
421
578
|
/* @__PURE__ */ jsxs("div", { className: "text-center", children: [
|
|
422
579
|
/* @__PURE__ */ jsx("div", { className: "mb-2 text-xs uppercase tracking-[1px] text-[#888]", children: valueLabel }),
|
|
423
|
-
/* @__PURE__ */
|
|
424
|
-
|
|
425
|
-
{
|
|
426
|
-
className: cn("text-[2rem] font-semibold", deltaValue >= 0 ? "text-[#0ecb81]" : "text-[#f6465d]"),
|
|
427
|
-
children: [
|
|
428
|
-
deltaValue > 0 ? "+" : deltaValue < 0 ? "-" : "",
|
|
429
|
-
"$",
|
|
430
|
-
fmt0(deltaValue)
|
|
431
|
-
]
|
|
432
|
-
}
|
|
433
|
-
) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
434
|
-
/* @__PURE__ */ jsxs("span", { children: [
|
|
435
|
-
"$",
|
|
436
|
-
fmt0(targetValue)
|
|
437
|
-
] }),
|
|
438
|
-
hasChange ? /* @__PURE__ */ jsxs(
|
|
580
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-baseline justify-center gap-3", children: [
|
|
581
|
+
/* @__PURE__ */ jsxs(
|
|
439
582
|
"span",
|
|
440
583
|
{
|
|
441
584
|
className: cn(
|
|
442
|
-
"
|
|
585
|
+
"text-[2.2rem] font-semibold",
|
|
443
586
|
deltaValue >= 0 ? "text-[#0ecb81]" : "text-[#f6465d]"
|
|
444
587
|
),
|
|
445
588
|
children: [
|
|
446
|
-
|
|
589
|
+
deltaSign,
|
|
590
|
+
"$",
|
|
447
591
|
fmt0(deltaValue)
|
|
448
592
|
]
|
|
449
593
|
}
|
|
450
|
-
)
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
/* @__PURE__ */ jsx("clipPath", { id: "loaf-clip", children: /* @__PURE__ */ jsx("rect", { x: "10", y: "10", width: "100", height: "140", rx: "8" }) }),
|
|
456
|
-
/* @__PURE__ */ jsxs("g", { clipPath: "url(#loaf-clip)", children: [
|
|
457
|
-
/* @__PURE__ */ jsx("rect", { x: "10", y: showDecrease ? targetFillY : baselineFillY, width: "100", height: showDecrease ? targetFillHeight : baselineFillHeight, fill: "rgba(220,175,120,0.7)" }),
|
|
458
|
-
showIncrease ? /* @__PURE__ */ jsx("rect", { x: "10", y: targetFillY, width: "100", height: targetFillHeight - baselineFillHeight, fill: "rgba(14,203,129,0.35)" }) : null,
|
|
459
|
-
showDecrease ? /* @__PURE__ */ jsx("rect", { x: "10", y: baselineFillY, width: "100", height: baselineFillHeight - targetFillHeight, fill: "rgba(246,70,93,0.35)" }) : null,
|
|
460
|
-
/* @__PURE__ */ jsx("line", { x1: "12", y1: targetFillY, x2: "108", y2: targetFillY, stroke: showIncrease ? "#0ecb81" : showDecrease ? "#f6465d" : "rgba(234,217,162,1)", strokeWidth: "2", strokeLinecap: "round" })
|
|
594
|
+
),
|
|
595
|
+
/* @__PURE__ */ jsxs("span", { className: "text-lg font-semibold text-white/60", children: [
|
|
596
|
+
"$",
|
|
597
|
+
fmt0(targetValue)
|
|
598
|
+
] })
|
|
461
599
|
] })
|
|
462
|
-
] })
|
|
600
|
+
] }),
|
|
601
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
|
|
602
|
+
/* @__PURE__ */ jsx("div", { className: "flex h-[200px] flex-col justify-between text-xs text-white/40", children: percentMarkers.map((marker) => /* @__PURE__ */ jsxs("span", { children: [
|
|
603
|
+
marker,
|
|
604
|
+
"%"
|
|
605
|
+
] }, marker)) }),
|
|
606
|
+
/* @__PURE__ */ jsx(
|
|
607
|
+
"div",
|
|
608
|
+
{
|
|
609
|
+
ref: houseRef,
|
|
610
|
+
className: "h-[200px] w-[160px] select-none touch-none",
|
|
611
|
+
style: { cursor: "ns-resize" },
|
|
612
|
+
onMouseDown,
|
|
613
|
+
onTouchStart,
|
|
614
|
+
children: /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 120 160", className: "h-full w-full overflow-visible", children: [
|
|
615
|
+
/* @__PURE__ */ jsx("rect", { x: "10", y: "10", width: "100", height: "140", rx: "8", fill: "rgba(255,255,255,0.04)", stroke: "rgba(255,255,255,0.10)" }),
|
|
616
|
+
/* @__PURE__ */ jsx("clipPath", { id: "loaf-clip", children: /* @__PURE__ */ jsx("rect", { x: "10", y: "10", width: "100", height: "140", rx: "8" }) }),
|
|
617
|
+
/* @__PURE__ */ jsxs("g", { clipPath: "url(#loaf-clip)", children: [
|
|
618
|
+
/* @__PURE__ */ jsx("rect", { x: "10", y: showDecrease ? targetFillY : baselineFillY, width: "100", height: showDecrease ? targetFillHeight : baselineFillHeight, fill: "rgba(220,175,120,0.7)" }),
|
|
619
|
+
showIncrease ? /* @__PURE__ */ jsx("rect", { x: "10", y: targetFillY, width: "100", height: targetFillHeight - baselineFillHeight, fill: "rgba(14,203,129,0.35)" }) : null,
|
|
620
|
+
showDecrease ? /* @__PURE__ */ jsx("rect", { x: "10", y: baselineFillY, width: "100", height: baselineFillHeight - targetFillHeight, fill: "rgba(246,70,93,0.35)" }) : null,
|
|
621
|
+
/* @__PURE__ */ jsx("line", { x1: "12", y1: targetFillY, x2: "108", y2: targetFillY, stroke: showIncrease ? "#0ecb81" : showDecrease ? "#f6465d" : "rgba(234,217,162,1)", strokeWidth: "2", strokeLinecap: "round" })
|
|
622
|
+
] })
|
|
623
|
+
] })
|
|
624
|
+
}
|
|
625
|
+
)
|
|
626
|
+
] }),
|
|
463
627
|
/* @__PURE__ */ jsx(
|
|
464
628
|
"button",
|
|
465
629
|
{
|
|
@@ -509,7 +673,7 @@ function HousePositionSlider({
|
|
|
509
673
|
)
|
|
510
674
|
] })
|
|
511
675
|
] }),
|
|
512
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between py-2", children: [
|
|
676
|
+
orderType === "market" ? null : /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between py-2", children: [
|
|
513
677
|
/* @__PURE__ */ jsx("span", { className: "text-white/50", children: isIncrease ? "Buying" : "Selling" }),
|
|
514
678
|
/* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1", children: [
|
|
515
679
|
orderMode === "buy" && buyTrackingMode === "dollars" ? /* @__PURE__ */ jsx("span", { className: "mr-1 text-[#0ecb81]", children: "~" }) : null,
|
|
@@ -558,7 +722,7 @@ function HousePositionSlider({
|
|
|
558
722
|
"button",
|
|
559
723
|
{
|
|
560
724
|
type: "button",
|
|
561
|
-
onClick: () =>
|
|
725
|
+
onClick: () => handleOrderTypeSelection("market"),
|
|
562
726
|
className: cn(
|
|
563
727
|
"flex-1 rounded-[6px] px-3 py-2 text-[0.8rem] font-medium transition",
|
|
564
728
|
orderType === "market" ? "bg-[rgba(201,162,39,0.2)] text-[#C9A227]" : "text-white/50 hover:bg-white/5"
|
|
@@ -570,7 +734,7 @@ function HousePositionSlider({
|
|
|
570
734
|
"button",
|
|
571
735
|
{
|
|
572
736
|
type: "button",
|
|
573
|
-
onClick: () =>
|
|
737
|
+
onClick: () => handleOrderTypeSelection("limit"),
|
|
574
738
|
className: cn(
|
|
575
739
|
"flex-1 rounded-[6px] px-3 py-2 text-[0.8rem] font-medium transition",
|
|
576
740
|
orderType === "limit" ? "bg-[rgba(201,162,39,0.2)] text-[#C9A227]" : "text-white/50 hover:bg-white/5"
|
|
@@ -588,6 +752,7 @@ function HousePositionSlider({
|
|
|
588
752
|
onChange: (e) => {
|
|
589
753
|
const input = e.target.value;
|
|
590
754
|
if (input === "" || /^[0-9]*\.?[0-9]*$/.test(input)) {
|
|
755
|
+
setLimitPriceDirty(true);
|
|
591
756
|
setLimitPriceInput(input);
|
|
592
757
|
const num = Number.parseFloat(input);
|
|
593
758
|
if (Number.isFinite(num) && num > 0) setLimitPrice(num);
|