@kodiak-finance/orderly-ui-leverage 2.8.18 → 2.8.19
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 +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +741 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +731 -3
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +8 -8
package/dist/index.mjs
CHANGED
|
@@ -1,14 +1,742 @@
|
|
|
1
1
|
import { i18n, useTranslation, Trans } from '@kodiak-finance/orderly-i18n';
|
|
2
2
|
import { registerSimpleSheet, registerSimpleDialog, useScreen, TokenIcon, Text, cn, Badge, Divider, Flex, modal, inputFormatter, ReduceIcon, Input, PlusIcon, Box, Slider, Button, toast } from '@kodiak-finance/orderly-ui';
|
|
3
|
-
import
|
|
3
|
+
import React, { useState, useMemo, useCallback, useId } from 'react';
|
|
4
4
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
5
5
|
import { useSymbolLeverage, useLeverage, useSymbolsInfo, useAccountInfo, useMarkPricesStream, usePortfolio, useLocalStorage, usePositionStream } from '@kodiak-finance/orderly-hooks';
|
|
6
6
|
import { positions, account } from '@kodiak-finance/orderly-perp';
|
|
7
7
|
import { OrderSide } from '@kodiak-finance/orderly-types';
|
|
8
8
|
import { zero } from '@kodiak-finance/orderly-utils';
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
// src/index.ts
|
|
11
|
+
var IconButton = (props) => {
|
|
12
|
+
const { Icon, onClick, disabled } = props;
|
|
13
|
+
return /* @__PURE__ */ jsx(
|
|
14
|
+
Icon,
|
|
15
|
+
{
|
|
16
|
+
onClick: disabled ? void 0 : onClick,
|
|
17
|
+
className: cn(
|
|
18
|
+
"oui-m-2 oui-text-white oui-transition-all",
|
|
19
|
+
disabled ? "oui-cursor-not-allowed oui-opacity-20" : "oui-cursor-pointer oui-opacity-100"
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
);
|
|
23
|
+
};
|
|
24
|
+
var LeverageInput = (props) => {
|
|
25
|
+
const formatters = React.useMemo(
|
|
26
|
+
() => [inputFormatter.numberFormatter, inputFormatter.dpFormatter(0)],
|
|
27
|
+
[]
|
|
28
|
+
);
|
|
29
|
+
const id = useId();
|
|
30
|
+
return /* @__PURE__ */ jsxs(
|
|
31
|
+
"label",
|
|
32
|
+
{
|
|
33
|
+
htmlFor: id,
|
|
34
|
+
className: cn(
|
|
35
|
+
"oui-w-full",
|
|
36
|
+
"oui-rounded",
|
|
37
|
+
"oui-bg-base-6",
|
|
38
|
+
"oui-flex",
|
|
39
|
+
"oui-items-center",
|
|
40
|
+
"oui-justify-between",
|
|
41
|
+
"oui-outline",
|
|
42
|
+
"oui-outline-offset-0",
|
|
43
|
+
"oui-outline-1",
|
|
44
|
+
"oui-outline-transparent",
|
|
45
|
+
"focus-within:oui-outline-primary-light",
|
|
46
|
+
"oui-input-root"
|
|
47
|
+
),
|
|
48
|
+
children: [
|
|
49
|
+
/* @__PURE__ */ jsx(
|
|
50
|
+
IconButton,
|
|
51
|
+
{
|
|
52
|
+
Icon: ReduceIcon,
|
|
53
|
+
onClick: props.onLeverageReduce,
|
|
54
|
+
disabled: props.isReduceDisabled
|
|
55
|
+
}
|
|
56
|
+
),
|
|
57
|
+
/* @__PURE__ */ jsxs(Flex, { itemAlign: "center", justify: "center", className: "oui-mr-4", children: [
|
|
58
|
+
/* @__PURE__ */ jsx(
|
|
59
|
+
Input,
|
|
60
|
+
{
|
|
61
|
+
value: props.value,
|
|
62
|
+
id,
|
|
63
|
+
autoComplete: "off",
|
|
64
|
+
classNames: {
|
|
65
|
+
input: cn("oui-text-right oui-text-[24px]"),
|
|
66
|
+
root: cn(
|
|
67
|
+
"oui-w-12",
|
|
68
|
+
"oui-px-0",
|
|
69
|
+
"oui-outline",
|
|
70
|
+
"oui-outline-offset-0",
|
|
71
|
+
"oui-outline-1",
|
|
72
|
+
"oui-outline-transparent",
|
|
73
|
+
"focus-within:oui-outline-primary-none"
|
|
74
|
+
)
|
|
75
|
+
},
|
|
76
|
+
formatters,
|
|
77
|
+
onChange: props.onInputChange
|
|
78
|
+
}
|
|
79
|
+
),
|
|
80
|
+
/* @__PURE__ */ jsx(
|
|
81
|
+
"div",
|
|
82
|
+
{
|
|
83
|
+
className: cn(
|
|
84
|
+
"oui-ml-1 oui-mt-1 oui-select-none",
|
|
85
|
+
"oui-text-base oui-text-base-contrast-36"
|
|
86
|
+
),
|
|
87
|
+
children: "x"
|
|
88
|
+
}
|
|
89
|
+
)
|
|
90
|
+
] }),
|
|
91
|
+
/* @__PURE__ */ jsx(
|
|
92
|
+
IconButton,
|
|
93
|
+
{
|
|
94
|
+
Icon: PlusIcon,
|
|
95
|
+
onClick: props.onLeverageIncrease,
|
|
96
|
+
disabled: props.isIncreaseDisabled
|
|
97
|
+
}
|
|
98
|
+
)
|
|
99
|
+
]
|
|
100
|
+
}
|
|
101
|
+
);
|
|
102
|
+
};
|
|
103
|
+
var Leverage = (props) => {
|
|
104
|
+
const { currentLeverage } = props;
|
|
105
|
+
const { t } = useTranslation();
|
|
106
|
+
return /* @__PURE__ */ jsxs(Flex, { itemAlign: "start", direction: "column", mb: 0, children: [
|
|
107
|
+
/* @__PURE__ */ jsx(LeverageHeader, { currentLeverage }),
|
|
108
|
+
/* @__PURE__ */ jsx(LeverageInput, { ...props }),
|
|
109
|
+
/* @__PURE__ */ jsx(LeverageSelector, { ...props }),
|
|
110
|
+
/* @__PURE__ */ jsx(LeverageSlider, { ...props }),
|
|
111
|
+
/* @__PURE__ */ jsx(LeverageFooter, { ...props })
|
|
112
|
+
] });
|
|
113
|
+
};
|
|
114
|
+
var LeverageFooter = (props) => {
|
|
115
|
+
const { t } = useTranslation();
|
|
116
|
+
return /* @__PURE__ */ jsxs(Flex, { direction: "row", gap: 2, width: "100%", mt: 0, pt: 5, children: [
|
|
117
|
+
/* @__PURE__ */ jsx(
|
|
118
|
+
Button,
|
|
119
|
+
{
|
|
120
|
+
variant: "contained",
|
|
121
|
+
color: "gray",
|
|
122
|
+
fullWidth: true,
|
|
123
|
+
onClick: props.onCancel,
|
|
124
|
+
"data-testid": "oui-testid-leverage-cancel-btn",
|
|
125
|
+
size: props.isMobile ? "md" : "lg",
|
|
126
|
+
children: t("common.cancel")
|
|
127
|
+
}
|
|
128
|
+
),
|
|
129
|
+
/* @__PURE__ */ jsx(
|
|
130
|
+
Button,
|
|
131
|
+
{
|
|
132
|
+
fullWidth: true,
|
|
133
|
+
loading: props.isLoading,
|
|
134
|
+
onClick: props.onSave,
|
|
135
|
+
"data-testid": "oui-testid-leverage-save-btn",
|
|
136
|
+
disabled: props.disabled,
|
|
137
|
+
size: props.isMobile ? "md" : "lg",
|
|
138
|
+
children: t("common.save")
|
|
139
|
+
}
|
|
140
|
+
)
|
|
141
|
+
] });
|
|
142
|
+
};
|
|
143
|
+
var LeverageHeader = (props) => {
|
|
144
|
+
const { t } = useTranslation();
|
|
145
|
+
const { currentLeverage } = props;
|
|
146
|
+
return /* @__PURE__ */ jsx(Flex, { justify: "center", width: "100%", mb: 2, children: /* @__PURE__ */ jsxs(Flex, { gap: 1, children: [
|
|
147
|
+
`${t("common.current")}:`,
|
|
148
|
+
/* @__PURE__ */ jsx(Text.numeral, { unit: "x", size: "sm", intensity: 80, dp: 0, children: currentLeverage ?? "--" })
|
|
149
|
+
] }) });
|
|
150
|
+
};
|
|
151
|
+
var LeverageSelector = (props) => {
|
|
152
|
+
const { value, onLeverageChange } = props;
|
|
153
|
+
return /* @__PURE__ */ jsx(
|
|
154
|
+
Flex,
|
|
155
|
+
{
|
|
156
|
+
itemAlign: "center",
|
|
157
|
+
justify: "between",
|
|
158
|
+
width: "100%",
|
|
159
|
+
mt: 4,
|
|
160
|
+
className: "oui-text-base-contrast-80",
|
|
161
|
+
children: props.toggles.map((option) => /* @__PURE__ */ jsx(
|
|
162
|
+
Flex,
|
|
163
|
+
{
|
|
164
|
+
itemAlign: "center",
|
|
165
|
+
justify: "center",
|
|
166
|
+
className: cn(
|
|
167
|
+
`oui-box-border oui-cursor-pointer oui-rounded-md oui-border oui-border-solid oui-bg-clip-padding oui-px-3 oui-py-2.5 oui-transition-all`,
|
|
168
|
+
value === option ? "oui-border-primary oui-bg-base-6" : "oui-border-line-12"
|
|
169
|
+
),
|
|
170
|
+
onClick: () => onLeverageChange?.(option),
|
|
171
|
+
children: /* @__PURE__ */ jsxs(
|
|
172
|
+
Flex,
|
|
173
|
+
{
|
|
174
|
+
itemAlign: "center",
|
|
175
|
+
justify: "center",
|
|
176
|
+
className: cn(`oui-h-3 oui-w-9 oui-select-none`),
|
|
177
|
+
children: [
|
|
178
|
+
option,
|
|
179
|
+
"x"
|
|
180
|
+
]
|
|
181
|
+
}
|
|
182
|
+
)
|
|
183
|
+
},
|
|
184
|
+
option
|
|
185
|
+
))
|
|
186
|
+
}
|
|
187
|
+
);
|
|
188
|
+
};
|
|
189
|
+
var getMarkPosition = (item, index, max, total) => {
|
|
190
|
+
const min = 1;
|
|
191
|
+
const maxSteps = max - min;
|
|
192
|
+
const percentPerStep = 100 / maxSteps;
|
|
193
|
+
const position = percentPerStep * (item - min);
|
|
194
|
+
if (index === 0)
|
|
195
|
+
return Math.min(position + 2, 100);
|
|
196
|
+
if (index === total - 1)
|
|
197
|
+
return Math.max(position - 3, 0);
|
|
198
|
+
return position;
|
|
199
|
+
};
|
|
200
|
+
var LeverageSlider = (props) => {
|
|
201
|
+
const {
|
|
202
|
+
leverageLevers,
|
|
203
|
+
maxLeverage = 0,
|
|
204
|
+
className,
|
|
205
|
+
value,
|
|
206
|
+
showSliderTip,
|
|
207
|
+
marks
|
|
208
|
+
} = props;
|
|
209
|
+
const sliderMax = leverageLevers.length > 0 ? Math.max(...leverageLevers) : maxLeverage;
|
|
210
|
+
return /* @__PURE__ */ jsxs(Box, { pt: 4, width: "100%", className, children: [
|
|
211
|
+
/* @__PURE__ */ jsx(
|
|
212
|
+
Slider,
|
|
213
|
+
{
|
|
214
|
+
max: maxLeverage,
|
|
215
|
+
min: 1,
|
|
216
|
+
marks,
|
|
217
|
+
value: [value],
|
|
218
|
+
onValueChange: (e) => {
|
|
219
|
+
props.onLeverageChange(e[0]);
|
|
220
|
+
props.setShowSliderTip(true);
|
|
221
|
+
},
|
|
222
|
+
color: "primary",
|
|
223
|
+
onValueCommit: (e) => {
|
|
224
|
+
props.onValueCommit?.(e);
|
|
225
|
+
props.setShowSliderTip(false);
|
|
226
|
+
},
|
|
227
|
+
showTip: showSliderTip,
|
|
228
|
+
tipFormatter: (value2) => {
|
|
229
|
+
return `${value2}x`;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
),
|
|
233
|
+
/* @__PURE__ */ jsx(Flex, { justify: "between", width: "100%", pt: 3, children: leverageLevers?.map((item, index) => {
|
|
234
|
+
const position = getMarkPosition(
|
|
235
|
+
item,
|
|
236
|
+
index,
|
|
237
|
+
sliderMax,
|
|
238
|
+
leverageLevers.length
|
|
239
|
+
);
|
|
240
|
+
return /* @__PURE__ */ jsx(
|
|
241
|
+
"button",
|
|
242
|
+
{
|
|
243
|
+
onClick: () => {
|
|
244
|
+
props.onLeverageChange(item);
|
|
245
|
+
props.onValueCommit?.([item]);
|
|
246
|
+
},
|
|
247
|
+
className: cn(
|
|
248
|
+
"oui-absolute oui-pb-3 oui-text-2xs oui-transform oui--translate-x-1/2",
|
|
249
|
+
Number(props.value) >= Number(item) ? "oui-text-primary-light" : "oui-text-base-contrast-54"
|
|
250
|
+
),
|
|
251
|
+
style: {
|
|
252
|
+
left: `${position}%`
|
|
253
|
+
},
|
|
254
|
+
"data-testid": `oui-testid-leverage-${item}-btn`,
|
|
255
|
+
children: `${item}x`
|
|
256
|
+
},
|
|
257
|
+
item
|
|
258
|
+
);
|
|
259
|
+
}) })
|
|
260
|
+
] });
|
|
261
|
+
};
|
|
262
|
+
var useLeverageScript = (options) => {
|
|
263
|
+
const [showSliderTip, setShowSliderTip] = useState(false);
|
|
264
|
+
const { t } = useTranslation();
|
|
265
|
+
const { curLeverage, maxLeverage, isLoading, leverageLevers, update } = useLeverage();
|
|
266
|
+
const marks = useMemo(() => {
|
|
267
|
+
return leverageLevers.map((e) => ({
|
|
268
|
+
label: `${e}x`,
|
|
269
|
+
value: e
|
|
270
|
+
}));
|
|
271
|
+
}, [leverageLevers]);
|
|
272
|
+
const [leverage, setLeverage] = useState(curLeverage ?? 0);
|
|
273
|
+
const step = 100 / ((marks?.length || 0) - 1);
|
|
274
|
+
const onLeverageChange = (leverage2) => {
|
|
275
|
+
setLeverage(leverage2);
|
|
276
|
+
};
|
|
277
|
+
const onLeverageIncrease = () => {
|
|
278
|
+
setLeverage((prev) => prev + 1);
|
|
279
|
+
};
|
|
280
|
+
const onLeverageReduce = () => {
|
|
281
|
+
setLeverage((prev) => prev - 1);
|
|
282
|
+
};
|
|
283
|
+
const onInputChange = useCallback(
|
|
284
|
+
(e) => {
|
|
285
|
+
const parsed = Number.parseInt(e.target.value);
|
|
286
|
+
const value = Number.isNaN(parsed) ? "" : parsed;
|
|
287
|
+
setLeverage(value);
|
|
288
|
+
},
|
|
289
|
+
[maxLeverage]
|
|
290
|
+
);
|
|
291
|
+
const onSave = async () => {
|
|
292
|
+
try {
|
|
293
|
+
update({ leverage }).then(
|
|
294
|
+
() => {
|
|
295
|
+
options?.close?.();
|
|
296
|
+
toast.success(t("leverage.updated"));
|
|
297
|
+
},
|
|
298
|
+
(err) => {
|
|
299
|
+
toast.error(err.message);
|
|
300
|
+
}
|
|
301
|
+
);
|
|
302
|
+
} catch (err) {
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
const isReduceDisabled = leverage <= 1;
|
|
306
|
+
const isIncreaseDisabled = leverage >= maxLeverage;
|
|
307
|
+
const disabled = !leverage || leverage < 1 || leverage > maxLeverage;
|
|
308
|
+
const toggles = useMemo(() => {
|
|
309
|
+
return [5, 10, 20, 50, 100].filter((e) => e <= maxLeverage);
|
|
310
|
+
}, [maxLeverage]);
|
|
311
|
+
return {
|
|
312
|
+
leverageLevers,
|
|
313
|
+
currentLeverage: curLeverage,
|
|
314
|
+
value: leverage,
|
|
315
|
+
marks,
|
|
316
|
+
onLeverageChange,
|
|
317
|
+
onLeverageIncrease,
|
|
318
|
+
onLeverageReduce,
|
|
319
|
+
onInputChange,
|
|
320
|
+
isReduceDisabled,
|
|
321
|
+
isIncreaseDisabled,
|
|
322
|
+
disabled,
|
|
323
|
+
step,
|
|
324
|
+
onCancel: options?.close,
|
|
325
|
+
onSave,
|
|
326
|
+
isLoading,
|
|
327
|
+
showSliderTip,
|
|
328
|
+
setShowSliderTip,
|
|
329
|
+
maxLeverage,
|
|
330
|
+
toggles
|
|
331
|
+
};
|
|
332
|
+
};
|
|
333
|
+
var LeverageEditor = (props) => {
|
|
334
|
+
const state = useLeverageScript({ close: props.close });
|
|
335
|
+
return /* @__PURE__ */ jsx(Leverage, { ...state });
|
|
336
|
+
};
|
|
337
|
+
var useSymbolLeverageScript = (options) => {
|
|
338
|
+
const { curLeverage = 1, symbol, side } = options;
|
|
339
|
+
const [showSliderTip, setShowSliderTip] = useState(false);
|
|
340
|
+
const [leverage, setLeverage] = useState(curLeverage);
|
|
341
|
+
const { t } = useTranslation();
|
|
342
|
+
const { isMobile } = useScreen();
|
|
343
|
+
const {
|
|
344
|
+
maxLeverage: originalMaxLeverage,
|
|
345
|
+
update,
|
|
346
|
+
isLoading
|
|
347
|
+
} = useSymbolLeverage(symbol);
|
|
348
|
+
const maxLeverage = originalMaxLeverage;
|
|
349
|
+
const {
|
|
350
|
+
position,
|
|
351
|
+
maxPositionNotional,
|
|
352
|
+
maxPositionLeverage,
|
|
353
|
+
overMaxPositionLeverage,
|
|
354
|
+
overRequiredMargin
|
|
355
|
+
} = useCalc({ symbol, leverage, maxLeverage });
|
|
356
|
+
const formattedLeverageLevers = useMemo(() => {
|
|
357
|
+
return generateLeverageLeversForSelector(maxLeverage);
|
|
358
|
+
}, [maxLeverage]);
|
|
359
|
+
const leverageLevers = useMemo(() => {
|
|
360
|
+
return generateLeverageLevers(maxLeverage);
|
|
361
|
+
}, [maxLeverage]);
|
|
362
|
+
const marks = useMemo(() => {
|
|
363
|
+
return leverageLevers.map((e) => ({
|
|
364
|
+
label: `${e}x`,
|
|
365
|
+
value: e
|
|
366
|
+
})) || [];
|
|
367
|
+
}, [leverageLevers]);
|
|
368
|
+
const step = useMemo(() => {
|
|
369
|
+
return 100 / ((marks?.length || 0) - 1);
|
|
370
|
+
}, [marks]);
|
|
371
|
+
const onLeverageChange = (leverage2) => {
|
|
372
|
+
setLeverage(leverage2);
|
|
373
|
+
};
|
|
374
|
+
const onLeverageIncrease = () => {
|
|
375
|
+
setLeverage((prev) => prev + 1);
|
|
376
|
+
};
|
|
377
|
+
const onLeverageReduce = () => {
|
|
378
|
+
setLeverage((prev) => prev - 1);
|
|
379
|
+
};
|
|
380
|
+
const onInputChange = useCallback(
|
|
381
|
+
(e) => {
|
|
382
|
+
const parsed = Number.parseInt(e.target.value);
|
|
383
|
+
if (!Number.isNaN(parsed)) {
|
|
384
|
+
setLeverage(parsed);
|
|
385
|
+
}
|
|
386
|
+
},
|
|
387
|
+
[]
|
|
388
|
+
);
|
|
389
|
+
const onConfirmSave = async () => {
|
|
390
|
+
try {
|
|
391
|
+
update?.({ leverage, symbol }).then(
|
|
392
|
+
(res) => {
|
|
393
|
+
if (res.success) {
|
|
394
|
+
options?.close?.();
|
|
395
|
+
toast.success(t("leverage.updated"));
|
|
396
|
+
} else {
|
|
397
|
+
toast.error(res.message);
|
|
398
|
+
}
|
|
399
|
+
},
|
|
400
|
+
(err) => {
|
|
401
|
+
toast.error(err.message);
|
|
402
|
+
}
|
|
403
|
+
);
|
|
404
|
+
} catch (err) {
|
|
405
|
+
}
|
|
406
|
+
};
|
|
407
|
+
const onSave = async () => {
|
|
408
|
+
modal.confirm({
|
|
409
|
+
title: t("leverage.confirm"),
|
|
410
|
+
content: /* @__PURE__ */ jsx(Text, { intensity: 54, children: t("leverage.confirm.content") }),
|
|
411
|
+
onOk: onConfirmSave,
|
|
412
|
+
onCancel: () => {
|
|
413
|
+
return Promise.resolve();
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
};
|
|
417
|
+
const isReduceDisabled = leverage <= 1;
|
|
418
|
+
const isIncreaseDisabled = leverage >= maxLeverage;
|
|
419
|
+
const isBuy = side ? side === OrderSide.BUY : position?.position_qty && position.position_qty > 0;
|
|
420
|
+
const disabled = !leverage || leverage < 1 || leverage > maxLeverage || overRequiredMargin || overMaxPositionLeverage;
|
|
421
|
+
return {
|
|
422
|
+
leverageLevers,
|
|
423
|
+
currentLeverage: curLeverage,
|
|
424
|
+
// Keep the displayed leverage fixed until the user confirms the change.
|
|
425
|
+
value: leverage,
|
|
426
|
+
// Input and slider reflect the temporary value being edited.
|
|
427
|
+
marks,
|
|
428
|
+
onLeverageChange,
|
|
429
|
+
onLeverageIncrease,
|
|
430
|
+
onLeverageReduce,
|
|
431
|
+
onInputChange,
|
|
432
|
+
isReduceDisabled,
|
|
433
|
+
isIncreaseDisabled,
|
|
434
|
+
disabled,
|
|
435
|
+
step,
|
|
436
|
+
onCancel: options?.close,
|
|
437
|
+
onSave,
|
|
438
|
+
isLoading,
|
|
439
|
+
showSliderTip,
|
|
440
|
+
setShowSliderTip,
|
|
441
|
+
maxLeverage,
|
|
442
|
+
toggles: formattedLeverageLevers,
|
|
443
|
+
symbol,
|
|
444
|
+
maxPositionNotional,
|
|
445
|
+
maxPositionLeverage,
|
|
446
|
+
overMaxPositionLeverage,
|
|
447
|
+
overRequiredMargin,
|
|
448
|
+
isBuy,
|
|
449
|
+
isMobile
|
|
450
|
+
};
|
|
451
|
+
};
|
|
452
|
+
var generateLeverageLeversForSelector = (max) => {
|
|
453
|
+
if (max === 10) {
|
|
454
|
+
return [1, 3, 5, 8, 10];
|
|
455
|
+
} else if (max === 50) {
|
|
456
|
+
return [1, 10, 20, 35, 50];
|
|
457
|
+
}
|
|
458
|
+
const min = 1;
|
|
459
|
+
const parts = 5;
|
|
460
|
+
const step = (max - min) / (parts - 1);
|
|
461
|
+
const result = [];
|
|
462
|
+
for (let i = 0; i < parts; i++) {
|
|
463
|
+
result.push(Math.floor(min + step * i));
|
|
464
|
+
}
|
|
465
|
+
return result;
|
|
466
|
+
};
|
|
467
|
+
var generateEvenlyDistributedMarks = (max) => {
|
|
468
|
+
const result = [];
|
|
469
|
+
if (max % 5 === 0) {
|
|
470
|
+
const step = max / 5;
|
|
471
|
+
for (let i = 0; i < 6; i++) {
|
|
472
|
+
const value = step * i;
|
|
473
|
+
result.push(value === 0 ? 1 : value);
|
|
474
|
+
}
|
|
475
|
+
} else {
|
|
476
|
+
result.push(1);
|
|
477
|
+
const quarter = max * 0.25;
|
|
478
|
+
const half = max * 0.5;
|
|
479
|
+
const threeQuarter = max * 0.75;
|
|
480
|
+
const quarterRounded = Math.round(quarter);
|
|
481
|
+
const halfRounded = Math.round(half);
|
|
482
|
+
const threeQuarterRounded = Math.round(threeQuarter);
|
|
483
|
+
if (quarterRounded > 1 && quarterRounded !== halfRounded) {
|
|
484
|
+
result.push(quarterRounded);
|
|
485
|
+
}
|
|
486
|
+
if (halfRounded > 1) {
|
|
487
|
+
result.push(halfRounded);
|
|
488
|
+
}
|
|
489
|
+
if (threeQuarterRounded > halfRounded && threeQuarterRounded < max) {
|
|
490
|
+
result.push(threeQuarterRounded);
|
|
491
|
+
}
|
|
492
|
+
if (max > 1) {
|
|
493
|
+
result.push(max);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
return result;
|
|
497
|
+
};
|
|
498
|
+
var generateLeverageLevers = (max) => {
|
|
499
|
+
switch (max) {
|
|
500
|
+
case 10:
|
|
501
|
+
return [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
|
502
|
+
case 20:
|
|
503
|
+
return [1, 5, 10, 15, 20];
|
|
504
|
+
case 50:
|
|
505
|
+
return [1, 10, 20, 30, 40, 50];
|
|
506
|
+
case 100:
|
|
507
|
+
return [1, 20, 40, 60, 80, 100];
|
|
508
|
+
}
|
|
509
|
+
const result = [];
|
|
510
|
+
if (max < 10) {
|
|
511
|
+
for (let i = 1; i <= max; i++) {
|
|
512
|
+
result.push(i);
|
|
513
|
+
}
|
|
514
|
+
} else {
|
|
515
|
+
result.push(...generateEvenlyDistributedMarks(max));
|
|
516
|
+
}
|
|
517
|
+
return result;
|
|
518
|
+
};
|
|
519
|
+
function useCalc(inputs) {
|
|
520
|
+
const { symbol, leverage, maxLeverage } = inputs;
|
|
521
|
+
const symbolsInfo = useSymbolsInfo();
|
|
522
|
+
const { data: accountInfo } = useAccountInfo();
|
|
523
|
+
const { data: markPrices } = useMarkPricesStream();
|
|
524
|
+
const { totalCollateral } = usePortfolio();
|
|
525
|
+
const [unPnlPriceBasis, setUnPnlPriceBasic] = useLocalStorage(
|
|
526
|
+
"unPnlPriceBasis",
|
|
527
|
+
"markPrice"
|
|
528
|
+
);
|
|
529
|
+
const [positions$1] = usePositionStream("all", {
|
|
530
|
+
calcMode: unPnlPriceBasis
|
|
531
|
+
});
|
|
532
|
+
const position = useMemo(() => {
|
|
533
|
+
if (symbol && positions$1?.rows?.length) {
|
|
534
|
+
return positions$1.rows.find((item) => item.symbol === symbol);
|
|
535
|
+
}
|
|
536
|
+
}, [positions$1, symbol]);
|
|
537
|
+
const maxPositionLeverage = useMemo(() => {
|
|
538
|
+
const IMRFactor = accountInfo?.imr_factor?.[symbol];
|
|
539
|
+
const notional = position?.notional;
|
|
540
|
+
if (IMRFactor && notional) {
|
|
541
|
+
const maxPositionLeverage2 = positions.maxPositionLeverage({
|
|
542
|
+
IMRFactor,
|
|
543
|
+
notional
|
|
544
|
+
});
|
|
545
|
+
return Math.min(maxPositionLeverage2, maxLeverage);
|
|
546
|
+
}
|
|
547
|
+
return maxLeverage;
|
|
548
|
+
}, [position, maxLeverage, symbol]);
|
|
549
|
+
const maxPositionNotional = useMemo(() => {
|
|
550
|
+
const IMRFactor = accountInfo?.imr_factor?.[symbol];
|
|
551
|
+
if (leverage && IMRFactor) {
|
|
552
|
+
return positions.maxPositionNotional({
|
|
553
|
+
leverage,
|
|
554
|
+
IMRFactor
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
}, [leverage, symbol]);
|
|
558
|
+
const overMaxPositionLeverage = useMemo(() => {
|
|
559
|
+
return leverage > maxPositionLeverage;
|
|
560
|
+
}, [leverage, maxPositionLeverage]);
|
|
561
|
+
const freeCollateral = useMemo(() => {
|
|
562
|
+
if (!accountInfo || !markPrices || !symbolsInfo) {
|
|
563
|
+
return zero;
|
|
564
|
+
}
|
|
565
|
+
const positionList = leverage ? positions$1?.rows.map((item) => {
|
|
566
|
+
if (item.symbol === symbol) {
|
|
567
|
+
return {
|
|
568
|
+
...item,
|
|
569
|
+
leverage
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
return item;
|
|
573
|
+
}) : positions$1?.rows;
|
|
574
|
+
const totalInitialMarginWithOrders = account.totalInitialMarginWithQty({
|
|
575
|
+
positions: positionList,
|
|
576
|
+
markPrices,
|
|
577
|
+
IMR_Factors: accountInfo.imr_factor,
|
|
578
|
+
// not used
|
|
579
|
+
maxLeverage: accountInfo.max_leverage,
|
|
580
|
+
symbolInfo: symbolsInfo
|
|
581
|
+
});
|
|
582
|
+
const freeCollateral2 = account.freeCollateral({
|
|
583
|
+
totalCollateral,
|
|
584
|
+
totalInitialMarginWithOrders
|
|
585
|
+
});
|
|
586
|
+
return freeCollateral2;
|
|
587
|
+
}, [
|
|
588
|
+
positions$1,
|
|
589
|
+
symbolsInfo,
|
|
590
|
+
accountInfo,
|
|
591
|
+
markPrices,
|
|
592
|
+
totalCollateral,
|
|
593
|
+
leverage,
|
|
594
|
+
symbol
|
|
595
|
+
]);
|
|
596
|
+
const overRequiredMargin = useMemo(() => {
|
|
597
|
+
return freeCollateral.eq(0) || freeCollateral.isNegative();
|
|
598
|
+
}, [freeCollateral]);
|
|
599
|
+
return {
|
|
600
|
+
position,
|
|
601
|
+
freeCollateral,
|
|
602
|
+
maxPositionNotional,
|
|
603
|
+
maxPositionLeverage,
|
|
604
|
+
overMaxPositionLeverage,
|
|
605
|
+
overRequiredMargin
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
var SymbolLeverage = (props) => {
|
|
609
|
+
const { t } = useTranslation();
|
|
610
|
+
return /* @__PURE__ */ jsxs("div", { className: "oui-flex oui-flex-col oui-gap-3 lg:oui-gap-4", children: [
|
|
611
|
+
/* @__PURE__ */ jsxs("div", { className: "oui-flex oui-items-center oui-gap-2", children: [
|
|
612
|
+
/* @__PURE__ */ jsx(TokenIcon, { symbol: props.symbol, className: "oui-size-5" }),
|
|
613
|
+
/* @__PURE__ */ jsx(
|
|
614
|
+
Text.formatted,
|
|
615
|
+
{
|
|
616
|
+
rule: "symbol",
|
|
617
|
+
formatString: "base-type",
|
|
618
|
+
size: props.isMobile ? "xs" : "base",
|
|
619
|
+
weight: "semibold",
|
|
620
|
+
intensity: 98,
|
|
621
|
+
children: props.symbol
|
|
622
|
+
}
|
|
623
|
+
),
|
|
624
|
+
/* @__PURE__ */ jsxs(
|
|
625
|
+
"div",
|
|
626
|
+
{
|
|
627
|
+
className: cn(["oui-ml-auto oui-flex oui-items-center oui-gap-1"]),
|
|
628
|
+
children: [
|
|
629
|
+
/* @__PURE__ */ jsx(Badge, { color: props.isBuy ? "success" : "danger", size: "xs", children: props.isBuy ? t("common.long") : t("common.short") }),
|
|
630
|
+
/* @__PURE__ */ jsx(LeverageBadge, { leverage: props.currentLeverage })
|
|
631
|
+
]
|
|
632
|
+
}
|
|
633
|
+
)
|
|
634
|
+
] }),
|
|
635
|
+
/* @__PURE__ */ jsx(Divider, {}),
|
|
636
|
+
/* @__PURE__ */ jsxs(Flex, { itemAlign: "start", direction: "column", mb: 0, children: [
|
|
637
|
+
/* @__PURE__ */ jsx(LeverageHeader, { currentLeverage: props.currentLeverage }),
|
|
638
|
+
/* @__PURE__ */ jsx(LeverageInput, { ...props }),
|
|
639
|
+
/* @__PURE__ */ jsx(LeverageSelector, { ...props }),
|
|
640
|
+
/* @__PURE__ */ jsx(LeverageSlider, { ...props }),
|
|
641
|
+
/* @__PURE__ */ jsx(Divider, { className: "oui-mb-3 oui-w-full" }),
|
|
642
|
+
/* @__PURE__ */ jsxs("div", { className: "oui-flex oui-flex-col oui-gap-1 oui-pb-4 oui-text-xs oui-font-normal oui-text-base-contrast-54", children: [
|
|
643
|
+
/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
|
|
644
|
+
Trans,
|
|
645
|
+
{
|
|
646
|
+
i18nKey: "leverage.maxAvailableLeverage.tips",
|
|
647
|
+
values: { leverage: props.maxPositionLeverage },
|
|
648
|
+
components: [
|
|
649
|
+
// @ts-ignore
|
|
650
|
+
/* @__PURE__ */ jsx(
|
|
651
|
+
Text.numeral,
|
|
652
|
+
{
|
|
653
|
+
dp: 0,
|
|
654
|
+
suffix: "x",
|
|
655
|
+
as: "span",
|
|
656
|
+
className: "oui-text-base-contrast"
|
|
657
|
+
},
|
|
658
|
+
"0"
|
|
659
|
+
)
|
|
660
|
+
]
|
|
661
|
+
}
|
|
662
|
+
) }),
|
|
663
|
+
/* @__PURE__ */ jsx("div", { children: t("leverage.actualPositionLeverage.tips") })
|
|
664
|
+
] }),
|
|
665
|
+
/* @__PURE__ */ jsxs(
|
|
666
|
+
"div",
|
|
667
|
+
{
|
|
668
|
+
className: cn([
|
|
669
|
+
"-oui-mb-2",
|
|
670
|
+
props.overRequiredMargin || props.overMaxPositionLeverage ? "oui-block oui-text-xs oui-font-normal" : "oui-hidden"
|
|
671
|
+
]),
|
|
672
|
+
children: [
|
|
673
|
+
props.overRequiredMargin && /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Text, { color: "warning", children: t("leverage.overRequiredMargin.tips") }) }),
|
|
674
|
+
props.overMaxPositionLeverage && /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Text, { color: "warning", children: /* @__PURE__ */ jsx(
|
|
675
|
+
Trans,
|
|
676
|
+
{
|
|
677
|
+
i18nKey: "leverage.overMaxPositionLeverage.tips",
|
|
678
|
+
values: { leverage: props.maxPositionLeverage },
|
|
679
|
+
components: [
|
|
680
|
+
// @ts-ignore
|
|
681
|
+
/* @__PURE__ */ jsx(Text.numeral, { dp: 0, suffix: "X", as: "span" }, "0")
|
|
682
|
+
]
|
|
683
|
+
}
|
|
684
|
+
) }) })
|
|
685
|
+
]
|
|
686
|
+
}
|
|
687
|
+
),
|
|
688
|
+
/* @__PURE__ */ jsx(LeverageFooter, { ...props })
|
|
689
|
+
] })
|
|
690
|
+
] });
|
|
691
|
+
};
|
|
692
|
+
var LeverageBadge = ({ leverage }) => {
|
|
693
|
+
return /* @__PURE__ */ jsxs(
|
|
694
|
+
"div",
|
|
695
|
+
{
|
|
696
|
+
className: cn(
|
|
697
|
+
"oui-flex oui-h-[18px] oui-items-center oui-gap-1",
|
|
698
|
+
"oui-cursor-pointer oui-rounded oui-bg-line-6 oui-px-2",
|
|
699
|
+
"oui-text-2xs oui-font-semibold oui-text-base-contrast-36"
|
|
700
|
+
),
|
|
701
|
+
children: [
|
|
702
|
+
/* @__PURE__ */ jsx(Text, { children: "Cross" }),
|
|
703
|
+
/* @__PURE__ */ jsx(Text.numeral, { dp: 0, size: "2xs", unit: "X", children: leverage })
|
|
704
|
+
]
|
|
705
|
+
}
|
|
706
|
+
);
|
|
707
|
+
};
|
|
708
|
+
var SymbolLeverageWidget = (props) => {
|
|
709
|
+
const state = useSymbolLeverageScript(props);
|
|
710
|
+
return /* @__PURE__ */ jsx(SymbolLeverage, { ...state });
|
|
711
|
+
};
|
|
11
712
|
|
|
12
|
-
|
|
713
|
+
// src/symbolLeverage/index.ts
|
|
714
|
+
var SymbolLeverageSheetId = "SymbolLeverageSheetId";
|
|
715
|
+
var SymbolLeverageDialogId = "SymbolLeverageDialogId";
|
|
716
|
+
registerSimpleSheet(SymbolLeverageSheetId, SymbolLeverageWidget, {
|
|
717
|
+
title: () => i18n.t("leverage.adjustedLeverage"),
|
|
718
|
+
classNames: {
|
|
719
|
+
// content: "oui-p-5",
|
|
720
|
+
}
|
|
721
|
+
});
|
|
722
|
+
registerSimpleDialog(SymbolLeverageDialogId, SymbolLeverageWidget, {
|
|
723
|
+
title: () => i18n.t("leverage.adjustedLeverage"),
|
|
724
|
+
classNames: {
|
|
725
|
+
content: "oui-w-[420px]"
|
|
726
|
+
}
|
|
727
|
+
});
|
|
728
|
+
|
|
729
|
+
// src/index.ts
|
|
730
|
+
var LeverageWidgetWithDialogId = "LeverageWidgetWithDialog";
|
|
731
|
+
var LeverageWidgetWithSheetId = "LeverageWidgetWithSheet";
|
|
732
|
+
registerSimpleDialog(LeverageWidgetWithDialogId, LeverageEditor, {
|
|
733
|
+
title: () => i18n.t("leverage.maxAccountLeverage"),
|
|
734
|
+
size: "md"
|
|
735
|
+
});
|
|
736
|
+
registerSimpleSheet(LeverageWidgetWithSheetId, LeverageEditor, {
|
|
737
|
+
title: () => i18n.t("leverage.maxAccountLeverage")
|
|
738
|
+
});
|
|
739
|
+
|
|
740
|
+
export { Leverage, LeverageEditor, LeverageHeader, LeverageSlider, LeverageWidgetWithDialogId, LeverageWidgetWithSheetId, SymbolLeverageDialogId, SymbolLeverageSheetId, SymbolLeverageWidget, useLeverageScript };
|
|
13
741
|
//# sourceMappingURL=out.js.map
|
|
14
742
|
//# sourceMappingURL=index.mjs.map
|