@orderly.network/ui-order-entry 3.0.0-beta.3 → 3.0.0-beta.4

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.js CHANGED
@@ -2048,6 +2048,7 @@ var OrderTypeSelect = (props) => {
2048
2048
  [types.OrderType.TRAILING_STOP]: t("orderEntry.orderType.trailingStop")
2049
2049
  };
2050
2050
  }, [t]);
2051
+ const mobileOptions = React3.useMemo(() => allOptions, [allOptions]);
2051
2052
  if (!isMobile) {
2052
2053
  const baseButtonClassName = "oui-flex oui-flex-1 oui-items-center oui-justify-center oui-gap-x-1 oui-rounded oui-px-3 oui-py-0.5 oui-text-xs oui-font-semibold oui-h-8";
2053
2054
  const selectedButtonClassName = ui.cn(
@@ -2146,7 +2147,6 @@ var OrderTypeSelect = (props) => {
2146
2147
  }
2147
2148
  );
2148
2149
  }
2149
- const mobileOptions = React3.useMemo(() => allOptions, [allOptions]);
2150
2150
  const handleMobileValueChange = (value) => {
2151
2151
  if (marketOrderDisabled && value === types.OrderType.MARKET && marketOrderDisabledTooltip) {
2152
2152
  ui.modal.alert({
@@ -4866,10 +4866,19 @@ var usePnlInputContext = () => {
4866
4866
  };
4867
4867
 
4868
4868
  // src/components/pnlInput/useBuilder.script.ts
4869
+ function normalizeSlPnlForStore(raw) {
4870
+ const v = `${raw}`.replace(/,/g, "").trim();
4871
+ if (v === "" || v === "-") return v;
4872
+ const withoutTrailingDot = v.replace(/\.$/, "");
4873
+ const num = Number(withoutTrailingDot);
4874
+ if (!isNaN(num) && num === 0) return "0";
4875
+ if (v.startsWith("-")) return v;
4876
+ return `-${v}`;
4877
+ }
4869
4878
  var usePNLInputBuilder = (props) => {
4870
4879
  const { type, values, quote_dp } = props;
4871
4880
  const { t } = i18n.useTranslation();
4872
- const [focus, setFocus] = React3.useState(true);
4881
+ const [, setFocus] = React3.useState(true);
4873
4882
  const { mode, setMode, tipsEle } = usePnlInputContext();
4874
4883
  const [tipVisible, setTipVisible] = React3.useState(false);
4875
4884
  const [isFocused, setIsFocused] = React3.useState(false);
@@ -4879,10 +4888,14 @@ var usePNLInputBuilder = (props) => {
4879
4888
  return `${type.toLowerCase()}_offset`;
4880
4889
  case "Offset%" /* PERCENTAGE */:
4881
4890
  return `${type.toLowerCase()}_offset_percentage`;
4891
+ case "OffsetFromMark" /* OFFSET_FROM_MARK */:
4892
+ return `${type.toLowerCase()}_offset_from_mark`;
4893
+ case "PercentageFromMark" /* PERCENTAGE_FROM_MARK */:
4894
+ return `${type.toLowerCase()}_offset_percentage_from_mark`;
4882
4895
  default:
4883
4896
  return `${type.toLowerCase()}_pnl`;
4884
4897
  }
4885
- }, [mode]);
4898
+ }, [mode, type]);
4886
4899
  const [innerValue, setInnerValue] = React3.useState(
4887
4900
  values[mode]
4888
4901
  );
@@ -4905,23 +4918,39 @@ var usePNLInputBuilder = (props) => {
4905
4918
  testId: `${"Offset" /* OFFSET */}_mneu_item`
4906
4919
  },
4907
4920
  {
4908
- label: `${t("tpsl.offset")}%`,
4921
+ label: t("tpsl.offsetPercent"),
4909
4922
  value: "Offset%" /* PERCENTAGE */,
4910
4923
  testId: `${"Offset%" /* PERCENTAGE */}_menu_item`
4924
+ },
4925
+ {
4926
+ // @ts-ignore
4927
+ label: t("tpsl.offsetMark"),
4928
+ value: "OffsetFromMark" /* OFFSET_FROM_MARK */,
4929
+ testId: `${"OffsetFromMark" /* OFFSET_FROM_MARK */}_menu_item`
4930
+ },
4931
+ {
4932
+ // @ts-ignore
4933
+ label: t("tpsl.offsetPercentMark"),
4934
+ value: "PercentageFromMark" /* PERCENTAGE_FROM_MARK */,
4935
+ testId: `${"PercentageFromMark" /* PERCENTAGE_FROM_MARK */}_menu_item`
4911
4936
  }
4912
4937
  ];
4913
4938
  }, [t]);
4914
4939
  const modeLabelMap = React3.useMemo(() => {
4915
4940
  return {
4916
4941
  ["PnL" /* PnL */]: t("tpsl.pnl"),
4917
- ["Offset" /* OFFSET */]: t("tpsl.offset"),
4918
- ["Offset%" /* PERCENTAGE */]: `${t("tpsl.offset")}%`
4942
+ ["Offset" /* OFFSET */]: t("tpsl.offsetHolder"),
4943
+ ["Offset%" /* PERCENTAGE */]: `${t("tpsl.offsetHolder")}`,
4944
+ // Extend locale keys; not yet in LocaleMessages typings
4945
+ ["OffsetFromMark" /* OFFSET_FROM_MARK */]: t("tpsl.offsetHolder"),
4946
+ ["PercentageFromMark" /* PERCENTAGE_FROM_MARK */]: t("tpsl.offsetHolder")
4919
4947
  };
4920
4948
  }, [t]);
4921
4949
  const percentageSuffix = React3.useRef("");
4922
4950
  const onValueChange = (value) => {
4923
4951
  setInnerValue(value);
4924
- props.onChange(key, value);
4952
+ const outgoing = key === "sl_pnl" ? normalizeSlPnlForStore(value) : value;
4953
+ props.onChange(key, outgoing);
4925
4954
  };
4926
4955
  const onFocus = () => {
4927
4956
  setTipVisible(true);
@@ -4930,20 +4959,19 @@ var usePNLInputBuilder = (props) => {
4930
4959
  const onBlur = () => {
4931
4960
  setTipVisible(false);
4932
4961
  setIsFocused(false);
4933
- props.onChange(key, innerValue);
4962
+ const outgoing = key === "sl_pnl" ? normalizeSlPnlForStore(innerValue) : innerValue;
4963
+ props.onChange(key, outgoing);
4934
4964
  };
4935
4965
  const formatter = (options2) => {
4936
4966
  const { dp = 2 } = options2;
4937
4967
  return {
4938
4968
  onRenderBefore: (value, options3) => {
4939
4969
  value = `${value}`;
4940
- if (focus) {
4941
- if (type === "SL" && mode === "PnL" /* PnL */) {
4942
- value = value.startsWith("-") ? value : "-" + value;
4943
- }
4970
+ if (type === "SL" && mode === "PnL" /* PnL */) {
4971
+ value = value.startsWith("-") ? value : "-" + value;
4944
4972
  }
4945
4973
  if (value === "" || value === "-") return "";
4946
- if (mode === "Offset%" /* PERCENTAGE */) {
4974
+ if (mode === "Offset%" /* PERCENTAGE */ || mode === "PercentageFromMark" /* PERCENTAGE_FROM_MARK */) {
4947
4975
  let normalized = value.replace(
4948
4976
  new RegExp(percentageSuffix.current.replace(".", "\\.") + "$"),
4949
4977
  ""
@@ -4953,7 +4981,7 @@ var usePNLInputBuilder = (props) => {
4953
4981
  return value;
4954
4982
  }
4955
4983
  return `${new utils.Decimal(normalized).mul(100).todp(2, 4).toString()}${percentageSuffix.current}`;
4956
- } else if (mode === "Offset" /* OFFSET */) {
4984
+ } else if (mode === "Offset" /* OFFSET */ || mode === "OffsetFromMark" /* OFFSET_FROM_MARK */) {
4957
4985
  value = utils.todpIfNeed(value, dp);
4958
4986
  } else ;
4959
4987
  return `${value}`;
@@ -4962,7 +4990,7 @@ var usePNLInputBuilder = (props) => {
4962
4990
  if (/^\-?0{2,}$/.test(value)) {
4963
4991
  return "0";
4964
4992
  }
4965
- if (mode === "Offset%" /* PERCENTAGE */) {
4993
+ if (mode === "Offset%" /* PERCENTAGE */ || mode === "PercentageFromMark" /* PERCENTAGE_FROM_MARK */) {
4966
4994
  if (value !== "") {
4967
4995
  value = utils.todpIfNeed(value, 2);
4968
4996
  const endStr = value.match(/\.0{0,2}$/);
@@ -4977,7 +5005,7 @@ var usePNLInputBuilder = (props) => {
4977
5005
  value = new utils.Decimal(value).div(100).toString();
4978
5006
  value = `${value}${percentageSuffix.current}`;
4979
5007
  }
4980
- } else if (mode === "PnL" /* PnL */ && type === "SL" && focus) {
5008
+ } else if (mode === "PnL" /* PnL */ && type === "SL") {
4981
5009
  value = value.startsWith("-") ? value : "-" + value;
4982
5010
  } else {
4983
5011
  value = utils.todpIfNeed(value, dp);
@@ -5021,21 +5049,28 @@ var PNLInput = (props) => {
5021
5049
  setFocus
5022
5050
  } = props;
5023
5051
  const [prefix, setPrefix] = React3.useState(mode);
5052
+ const isPercentageMode = mode === "Offset%" /* PERCENTAGE */ || mode === "PercentageFromMark" /* PERCENTAGE_FROM_MARK */;
5024
5053
  const [placeholder, setPlaceholder] = React3.useState(
5025
- mode === "Offset%" /* PERCENTAGE */ ? "%" : quote
5054
+ isPercentageMode ? "%" : quote
5026
5055
  );
5027
5056
  React3.useEffect(() => {
5028
5057
  setPrefix(mode);
5029
- setPlaceholder(mode === "Offset%" /* PERCENTAGE */ ? "%" : quote);
5030
- }, [mode]);
5058
+ setPlaceholder(isPercentageMode ? "%" : quote);
5059
+ }, [mode, isPercentageMode, quote]);
5031
5060
  React3.useEffect(() => {
5032
5061
  setPrefix(!!value ? "" : mode);
5033
5062
  }, [value]);
5034
- const id = React3.useMemo(() => `${type.toLowerCase()}_${mode.toLowerCase()}`, []);
5063
+ const id = React3.useMemo(
5064
+ () => `${type.toLowerCase()}_${mode.toLowerCase()}`,
5065
+ [type, mode]
5066
+ );
5067
+ const prefixLabel = prefix === "" ? "" : String(
5068
+ modeLabelMap[prefix] ?? prefix ?? ""
5069
+ );
5035
5070
  return /* @__PURE__ */ jsxRuntime.jsx(
5036
5071
  ui.Input.tooltip,
5037
5072
  {
5038
- prefix: modeLabelMap[prefix] || prefix,
5073
+ prefix: prefixLabel,
5039
5074
  size: "md",
5040
5075
  placeholder,
5041
5076
  id,
@@ -5072,11 +5107,11 @@ var PNLInput = (props) => {
5072
5107
  },
5073
5108
  onBlur: () => {
5074
5109
  setPrefix(!!value ? "" : mode);
5075
- setPlaceholder(mode === "Offset%" /* PERCENTAGE */ ? "%" : quote);
5110
+ setPlaceholder(isPercentageMode ? "%" : quote);
5076
5111
  onBlur();
5077
5112
  },
5078
5113
  suffix: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5079
- mode === "Offset%" /* PERCENTAGE */ && !!value && /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "2xs", color: "inherit", className: "oui-ml-[2px]", children: "%" }),
5114
+ isPercentageMode && !!value && /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "2xs", color: "inherit", className: "oui-ml-[2px]", children: "%" }),
5080
5115
  /* @__PURE__ */ jsxRuntime.jsx(
5081
5116
  PNLMenus,
5082
5117
  {
@@ -5496,6 +5531,8 @@ var TPSLInputRow = (props) => {
5496
5531
  PnL: props.values.PnL,
5497
5532
  Offset: props.values.Offset,
5498
5533
  "Offset%": props.values["Offset%"],
5534
+ OffsetFromMark: props.values.OffsetFromMark,
5535
+ PercentageFromMark: props.values.PercentageFromMark,
5499
5536
  ROI: props.values.ROI
5500
5537
  }
5501
5538
  }
@@ -5715,6 +5752,8 @@ var OrderEntry = (props) => {
5715
5752
  tp_pnl: order.tp_pnl,
5716
5753
  tp_offset: order.tp_offset,
5717
5754
  tp_offset_percentage: order.tp_offset_percentage,
5755
+ tp_offset_from_mark: order.tp_offset_from_mark,
5756
+ tp_offset_percentage_from_mark: order.tp_offset_percentage_from_mark,
5718
5757
  tp_ROI: order.tp_ROI,
5719
5758
  tp_trigger_price: order.tp_trigger_price,
5720
5759
  tp_order_price: order.tp_order_price,
@@ -5724,6 +5763,8 @@ var OrderEntry = (props) => {
5724
5763
  sl_pnl: order.sl_pnl,
5725
5764
  sl_offset: order.sl_offset,
5726
5765
  sl_offset_percentage: order.sl_offset_percentage,
5766
+ sl_offset_from_mark: order.sl_offset_from_mark,
5767
+ sl_offset_percentage_from_mark: order.sl_offset_percentage_from_mark,
5727
5768
  sl_ROI: order.sl_ROI
5728
5769
  });
5729
5770
  setShowTPSLAdvanced(false);
@@ -5740,6 +5781,14 @@ var OrderEntry = (props) => {
5740
5781
  sl_order_type: types.OrderType.MARKET,
5741
5782
  tp_pnl: void 0,
5742
5783
  sl_pnl: void 0,
5784
+ tp_offset: void 0,
5785
+ tp_offset_percentage: void 0,
5786
+ tp_offset_from_mark: void 0,
5787
+ tp_offset_percentage_from_mark: void 0,
5788
+ sl_offset: void 0,
5789
+ sl_offset_percentage: void 0,
5790
+ sl_offset_from_mark: void 0,
5791
+ sl_offset_percentage_from_mark: void 0,
5743
5792
  position_type: types.PositionType.FULL
5744
5793
  });
5745
5794
  };
@@ -5908,6 +5957,8 @@ var OrderEntry = (props) => {
5908
5957
  PnL: formattedOrder.tp_pnl ?? "",
5909
5958
  Offset: formattedOrder.tp_offset ?? "",
5910
5959
  "Offset%": formattedOrder.tp_offset_percentage ?? "",
5960
+ OffsetFromMark: formattedOrder.tp_offset_from_mark ?? "",
5961
+ PercentageFromMark: formattedOrder.tp_offset_percentage_from_mark ?? "",
5911
5962
  ROI: formattedOrder.tp_ROI ?? ""
5912
5963
  },
5913
5964
  sl: {
@@ -5915,6 +5966,8 @@ var OrderEntry = (props) => {
5915
5966
  PnL: formattedOrder.sl_pnl ?? "",
5916
5967
  Offset: formattedOrder.sl_offset ?? "",
5917
5968
  "Offset%": formattedOrder.sl_offset_percentage ?? "",
5969
+ OffsetFromMark: formattedOrder.sl_offset_from_mark ?? "",
5970
+ PercentageFromMark: formattedOrder.sl_offset_percentage_from_mark ?? "",
5918
5971
  ROI: formattedOrder.sl_ROI ?? ""
5919
5972
  }
5920
5973
  },
@@ -6431,10 +6484,24 @@ var useOrderEntryScript = (inputs) => {
6431
6484
  const { priceInputContainerRef, priceInputContainerWidth } = usePriceInputContainer({
6432
6485
  order_type_ext: formattedOrder.order_type_ext
6433
6486
  });
6487
+ const effectiveEstLiqPriceForSlCheck = React3.useMemo(() => {
6488
+ const estLiqPrice = state.estLiqPrice;
6489
+ if (estLiqPrice == null || formattedOrder.side == null || state.markPrice == null) {
6490
+ return null;
6491
+ }
6492
+ if (formattedOrder.side === types.OrderSide.BUY && estLiqPrice > state.markPrice || formattedOrder.side === types.OrderSide.SELL && estLiqPrice < state.markPrice) {
6493
+ return null;
6494
+ }
6495
+ if (!Number.isFinite(estLiqPrice) || estLiqPrice <= 0) {
6496
+ return null;
6497
+ }
6498
+ return estLiqPrice;
6499
+ }, [state.estLiqPrice, state.markPrice, formattedOrder.side]);
6434
6500
  const slPriceError = hooks.useTpslPriceChecker({
6435
6501
  slPrice: formattedOrder.sl_trigger_price,
6436
- liqPrice: state.estLiqPrice,
6502
+ liqPrice: effectiveEstLiqPriceForSlCheck,
6437
6503
  side: formattedOrder.side,
6504
+ markPrice: state.markPrice,
6438
6505
  currentPosition: state.currentPosition,
6439
6506
  orderQuantity: Number(formattedOrder.order_quantity)
6440
6507
  });
@@ -6449,12 +6516,7 @@ var useOrderEntryScript = (inputs) => {
6449
6516
  }
6450
6517
  }, [tpslSwitch]);
6451
6518
  React3.useEffect(() => {
6452
- let estLiqPrice = state.estLiqPrice;
6453
- if (estLiqPrice == null || formattedOrder.side == null || state.markPrice == null) {
6454
- estLiqPrice = null;
6455
- } else if (formattedOrder.side === types.OrderSide.BUY && estLiqPrice > state.markPrice || formattedOrder.side === types.OrderSide.SELL && estLiqPrice < state.markPrice) {
6456
- estLiqPrice = null;
6457
- }
6519
+ const estLiqPrice = effectiveEstLiqPriceForSlCheck;
6458
6520
  const lastActive = lastUserActiveTimeRef.current;
6459
6521
  const now = Date.now();
6460
6522
  const isUserActive = now - lastActive <= ORDER_ENTRY_EST_LIQ_ACTIVE_WINDOW_MS;
@@ -6463,7 +6525,7 @@ var useOrderEntryScript = (inputs) => {
6463
6525
  estLiqPrice,
6464
6526
  isUserActive
6465
6527
  });
6466
- }, [ee, symbol, state.estLiqPrice, state.markPrice, formattedOrder.side]);
6528
+ }, [ee, symbol, effectiveEstLiqPriceForSlCheck]);
6467
6529
  React3.useEffect(() => {
6468
6530
  setOrderValue("margin_mode", marginMode);
6469
6531
  }, [marginMode]);