UNPKG

@orderly.network/ui-share

Version:

1,562 lines (1,556 loc) 49.9 kB
'use strict'; var ui = require('@orderly.network/ui'); var React = require('react'); var hooks = require('@orderly.network/hooks'); var i18n = require('@orderly.network/i18n'); var types = require('@orderly.network/types'); var jsxRuntime = require('react/jsx-runtime'); var utils = require('@orderly.network/utils'); function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; } var React__default = /*#__PURE__*/_interopDefault(React); // src/index.ts var useSharePnLScript = (props) => { const { pnl, hide } = props; const entity = pnl?.entity; const symbolInfo = hooks.useSymbolsInfo(); const { getFirstRefCode } = hooks.useReferralInfo(); const referralInfo = React.useMemo(() => { const code = getFirstRefCode()?.code; const info = { code: pnl?.refCode ?? code, slogan: pnl?.refSlogan, link: pnl?.refLink }; return info; }, [getFirstRefCode, pnl]); const base_dp = React.useMemo(() => { if (!entity) return void 0; return symbolInfo[entity?.symbol]("base_dp"); }, [entity, symbolInfo]); const quote_dp = React.useMemo(() => { if (!entity) return void 0; return symbolInfo[entity?.symbol]("quote_dp"); }, [entity, symbolInfo]); return { entity, baseDp: base_dp, quoteDp: quote_dp, referralInfo, shareOptions: pnl, hide }; }; var Poster = React.forwardRef((props, parentRef) => { const { width, height, className, data, style } = props; const { ref, download, toDataURL, copy, toBlob } = hooks.usePoster(data, { ratio: props.ratio }); React.useImperativeHandle(parentRef, () => ({ download, toDataURL, toBlob, copy })); return /* @__PURE__ */ jsxRuntime.jsx( "canvas", { ref, width, height, className, style } ); }); function getPnLPosterData(position, message, domain, pnlType, options, baseDp, quoteDp, referral) { const { t } = i18n.useTranslation(); const { symbol, currency } = processSymbol(position.symbol); const positionData = { symbol, currency, side: position.side }; switch (pnlType) { case "pnl": { if (position.pnl != null) { positionData["pnl"] = utils.formatNum.pnl(position.pnl)?.toFixed(2); } break; } case "roi": { if (position.roi != null) { positionData["ROI"] = utils.formatNum.roi(position.roi)?.toFixed(2); } break; } case "roi_pnl": { if (position.pnl != null) { positionData["pnl"] = utils.formatNum.pnl(position.pnl)?.toFixed(2); } if (position.roi != null) { positionData["ROI"] = utils.formatNum.roi(position.roi)?.toFixed(2); } break; } } const informations = []; if (options.has("leverage")) { positionData["leverage"] = position.leverage; } const array = [ "openPrice", "closePrice", "openTime", "closeTime", "markPrice", "quantity" ]; array.forEach((key) => { if (options.has(key)) { switch (key) { case "leverage": { break; } case "openPrice": { if (position.openPrice != null) { informations.push({ title: t("share.pnl.optionalInfo.openPrice"), value: formatFixed(position.openPrice, quoteDp || 2) }); } break; } case "closePrice": { if (position.closePrice != null) { informations.push({ title: t("share.pnl.optionalInfo.closePrice"), value: formatFixed(position.closePrice, quoteDp || 2) }); } break; } case "openTime": { if (position.openTime != null) { informations.push({ title: t("share.pnl.optionalInfo.openTime"), value: formatOpenTime(position.openTime) }); } break; } case "closeTime": { if (position.closeTime != null) { informations.push({ title: t("share.pnl.optionalInfo.closeTime"), value: formatOpenTime(position.closeTime) }); } break; } case "markPrice": { if (position.markPrice != null) { informations.push({ title: t("common.markPrice"), value: formatFixed(position.markPrice, quoteDp || 2) }); } break; } case "quantity": { if (position.quantity != null) { informations.push({ title: t("common.quantity"), value: formatFixed(position.quantity, baseDp || 2) }); } } } } }); positionData["informations"] = informations; const data = { position: positionData, updateTime: formatShareTime(/* @__PURE__ */ new Date()), domain }; if (message.length > 0) { data["message"] = message; } if (typeof referral !== "undefined" && referral["code"] !== void 0) { data["referral"] = referral; } return data; } function processSymbol(symbol) { const tokens = symbol.split("_"); if (tokens.length !== 3) { return { symbol, currency: "USDC" }; } const [symbol1, symbol2, symbol3] = tokens; const formattedString = `${symbol2}-${symbol1}`; return { symbol: formattedString, currency: symbol3 || "USDC" }; } function formatShareTime(input) { const date = input instanceof Date ? input : new Date(input); const options = { year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", hourCycle: "h23" }; const formatter = new Intl.DateTimeFormat("en-US", options); const formattedParts = formatter.formatToParts(date); const year = formattedParts.find( (part) => part.type === "year" ? part.value : "" )?.value; const month = formattedParts.find( (part) => part.type === "month" ? part.value : "" )?.value; const day = formattedParts.find( (part) => part.type === "day" ? part.value : "" )?.value; const hour = formattedParts.find( (part) => part.type === "hour" ? part.value : "" )?.value; const minute = formattedParts.find( (part) => part.type === "minute" ? part.value : "" )?.value; return `${year}-${month}-${day} ${hour}:${minute}`; } function formatOpenTime(input) { const date = input instanceof Date ? input : new Date(input); const options = { year: "numeric", month: "short", day: "2-digit", hour: "2-digit", minute: "2-digit", hourCycle: "h23" }; const formatter = new Intl.DateTimeFormat("en-US", options); const formattedParts = formatter.formatToParts(date); const month = formattedParts.find( (part) => part.type === "month" ? part.value : "" )?.value; const day = formattedParts.find( (part) => part.type === "day" ? part.value : "" )?.value; const hour = formattedParts.find( (part) => part.type === "hour" ? part.value : "" )?.value; const minute = formattedParts.find( (part) => part.type === "minute" ? part.value : "" )?.value; return `${month}-${day} ${hour}:${minute}`; } function formatFixed(value, dp) { return new utils.Decimal(value).toFixed(dp, utils.Decimal.ROUND_DOWN); } function savePnlInfo(format, options, bgIndex, message) { localStorage.setItem( "pnl_config_key", JSON.stringify({ bgIndex, pnlFormat: format, options: Array.from(options), message }) ); } function getPnlInfo() { const str = localStorage.getItem("pnl_config_key"); if (str && str.length > 0) { try { const json = JSON.parse(str); return json; } catch (e) { } } return { bgIndex: 0, pnlFormat: "roi_pnl", options: [ "openPrice", "closePrice", "openTime", "closeTime", "markPrice", "quantity", "leverage" ], message: "" }; } var BottomButtons = (props) => { const { onClickDownload, onClickCopy } = props; const { t } = i18n.useTranslation(); return /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { px: 8, gap: 3, mt: 3, itemAlign: "center", children: [ /* @__PURE__ */ jsxRuntime.jsxs( ui.Button, { color: "secondary", className: "oui-flex-1 oui-flex oui-gap-1", onClick: onClickDownload, children: [ /* @__PURE__ */ jsxRuntime.jsx("span", { children: /* @__PURE__ */ jsxRuntime.jsx(DownloadIcon, {}) }), t("common.download") ] } ), /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { className: "oui-flex-1 oui-flex oui-gap-1", onClick: onClickCopy, children: [ /* @__PURE__ */ jsxRuntime.jsx("span", { children: /* @__PURE__ */ jsxRuntime.jsx(CopyIcon, {}) }), t("common.copy") ] }) ] }); }; var DownloadIcon = () => { return /* @__PURE__ */ jsxRuntime.jsx( "svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsxRuntime.jsx( "path", { d: "M4.66 1.994A2.667 2.667 0 0 0 1.995 4.66v6.666a2.667 2.667 0 0 0 2.667 2.667h6.666a2.667 2.667 0 0 0 2.667-2.667V4.661a2.667 2.667 0 0 0-2.667-2.667zM7.995 4.66c.368 0 .667.298.667.666V8.66h2l-2.667 2.666L5.328 8.66h2V5.327c0-.368.299-.667.667-.667", fill: "#fff", fillOpacity: ".98" } ) } ); }; var CopyIcon = () => { return /* @__PURE__ */ jsxRuntime.jsx( "svg", { width: "17", height: "16", viewBox: "0 0 17 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsxRuntime.jsx( "path", { d: "M5.166 1.994A2.667 2.667 0 0 0 2.499 4.66v4a2.667 2.667 0 0 0 2.667 2.667 2.667 2.667 0 0 0 2.666 2.667h4a2.667 2.667 0 0 0 2.667-2.667v-4a2.667 2.667 0 0 0-2.667-2.667 2.667 2.667 0 0 0-2.666-2.666zm6.666 4c.737 0 1.334.596 1.334 1.333v4c0 .737-.597 1.334-1.334 1.334h-4A1.333 1.333 0 0 1 6.5 11.327h2.667a2.667 2.667 0 0 0 2.666-2.667z", fill: "#fff", fillOpacity: ".98" } ) } ); }; var PrevButton = (props) => { const { children, ...restProps } = props; return /* @__PURE__ */ jsxRuntime.jsx("button", { ...restProps, children: /* @__PURE__ */ jsxRuntime.jsxs( "svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [ /* @__PURE__ */ jsxRuntime.jsx("rect", { width: "20", height: "20", rx: "10", fill: "#333948" }), /* @__PURE__ */ jsxRuntime.jsx( "path", { d: "M11.186 5.348a.67.67 0 0 0-.436.27l-2.657 4a.69.69 0 0 0 0 .75l2.657 4a.68.68 0 0 0 .934.188.685.685 0 0 0 .187-.937L9.463 9.993 11.87 6.37a.685.685 0 0 0-.187-.938.65.65 0 0 0-.498-.083", fill: "#fff", fillOpacity: ".54" } ) ] } ) }); }; var NextButton = (props) => { const { children, ...restProps } = props; return /* @__PURE__ */ jsxRuntime.jsx("button", { ...restProps, children: /* @__PURE__ */ jsxRuntime.jsxs( "svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [ /* @__PURE__ */ jsxRuntime.jsx("rect", { width: "20", height: "20", rx: "10", fill: "#333948" }), /* @__PURE__ */ jsxRuntime.jsx( "path", { d: "M8.777 5.348a.65.65 0 0 0-.498.083.685.685 0 0 0-.187.938L10.5 9.993 8.092 13.62a.685.685 0 0 0 .187.937.68.68 0 0 0 .934-.187l2.657-4a.69.69 0 0 0 0-.75l-2.657-4a.67.67 0 0 0-.436-.271", fill: "#fff", fillOpacity: ".54" } ) ] } ) }); }; var CarouselBackgroundImage = (props) => { const { backgroundImages, selectedSnap, setSelectedSnap } = props; const [emblaRef, emblaApi] = ui.useEmblaCarousel({ // loop: true, containScroll: "keepSnaps", dragFree: true }); const onPrevButtonClick = React.useCallback(() => { if (!emblaApi) { return; } if (emblaApi?.canScrollPrev()) { emblaApi.scrollPrev(); } else if (selectedSnap - 1 >= 0) { setSelectedSnap(selectedSnap - 1); } }, [emblaApi, selectedSnap]); const onNextButtonClick = React.useCallback(() => { if (!emblaApi) { return; } if (emblaApi?.canScrollNext()) { emblaApi.scrollNext(); } else if (selectedSnap + 1 < backgroundImages.length) { setSelectedSnap(selectedSnap + 1); } }, [emblaApi, selectedSnap]); const onSelect = React.useCallback((emblaApi2) => { setSelectedSnap(emblaApi2.selectedScrollSnap()); }, []); React.useEffect(() => { if (!emblaApi) { return; } onSelect(emblaApi); emblaApi.on("reInit", onSelect); emblaApi.on("select", onSelect); emblaApi?.scrollTo(selectedSnap); return () => { emblaApi.off("reInit", onSelect); emblaApi.off("select", onSelect); }; }, [emblaApi, onSelect]); return /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { mt: 4, px: 2, children: [ /* @__PURE__ */ jsxRuntime.jsx(PrevButton, { onClick: onPrevButtonClick }), /* @__PURE__ */ jsxRuntime.jsx( "div", { ref: emblaRef, className: "oui-w-full oui-overflow oui-overflow-x-auto oui-scrollbar-hidden oui-hide-scrollbar oui-mx-0", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, { children: backgroundImages.map((e, index) => /* @__PURE__ */ jsxRuntime.jsx( ui.Box, { onClick: () => { if (emblaApi?.canScrollPrev() || emblaApi?.canScrollNext()) { emblaApi?.scrollTo(index); } else { setSelectedSnap(index); } }, mx: 2, my: 1, mr: 6, r: "base", className: ui.cn( "oui-shrink-0 oui-w-[162px]", selectedSnap === index && "oui-outline oui-outline-1 oui-outline-primary-darken" ), children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: e, className: "oui-rounded-sm" }) }, e )) }) } ), /* @__PURE__ */ jsxRuntime.jsx(NextButton, { onClick: onNextButtonClick }) ] }); }; var Checkbox = (props) => { const { size = 16, className } = props; return /* @__PURE__ */ jsxRuntime.jsx( "button", { type: "button", onClick: (e) => { props.onCheckedChange(!props.checked); }, className, children: props.checked ? /* @__PURE__ */ jsxRuntime.jsx( "svg", { width: size, height: size, viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsxRuntime.jsx( "path", { fillRule: "evenodd", clipRule: "evenodd", d: "M4.66 1.953A2.667 2.667 0 0 0 1.995 4.62v6.667a2.667 2.667 0 0 0 2.667 2.666h6.666a2.667 2.667 0 0 0 2.667-2.666V4.62a2.667 2.667 0 0 0-2.667-2.667zm6.664 2.922a.8.8 0 0 1 .557-.208c.2 0 .406.063.558.208a.734.734 0 0 1 0 1.063l-5.434 5.179a.826.826 0 0 1-1.115 0l-2.33-2.22a.736.736 0 0 1 0-1.063.827.827 0 0 1 1.117 0l1.77 1.687z", fill: "#fff", fillOpacity: ".8" } ) } ) : /* @__PURE__ */ jsxRuntime.jsx( "svg", { width: size, height: size, viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsxRuntime.jsx( "path", { d: "M4.66 1.953A2.667 2.667 0 0 0 1.995 4.62v6.667a2.667 2.667 0 0 0 2.667 2.666h6.666a2.667 2.667 0 0 0 2.667-2.666V4.62a2.667 2.667 0 0 0-2.667-2.667zm0 1.334h6.667c.737 0 1.334.596 1.334 1.333v6.667c0 .736-.597 1.333-1.334 1.333H4.661a1.333 1.333 0 0 1-1.334-1.333V4.62c0-.737.597-1.333 1.334-1.333", fill: "#fff", fillOpacity: ".8" } ) } ) } ); }; var Message = (props) => { const { message, setMessage, check, setCheck } = props; const [focus, setFocus] = React.useState(false); const inputRef = React.useRef(null); const { t } = i18n.useTranslation(); return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "oui-mt-3 oui-mb-6 oui-flex oui-items-center", children: [ /* @__PURE__ */ jsxRuntime.jsx( Checkbox, { className: "oui-mt-[2px]", checked: check, onCheckedChange: (e) => { setCheck(e); } } ), /* @__PURE__ */ jsxRuntime.jsx( "div", { className: "oui-text-xs oui-text-base-contrast-54 oui-ml-1 hover:oui-cursor-pointer", onClick: () => { setCheck(!props.check); }, children: t("share.pnl.optionalInfo.message") } ), /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oui-bg-base-900 oui-mx-2 oui-rounded-sm", children: /* @__PURE__ */ jsxRuntime.jsx( ui.Input, { ref: inputRef, placeholder: t("share.pnl.optionalInfo.message.placeholder"), classNames: { root: "oui-w-[320px]" }, size: "sm", value: message, autoFocus: false, suffix: focus && /* @__PURE__ */ jsxRuntime.jsx( "button", { className: "oui-mr-3 oui-cursor-pointer", onMouseDown: (e) => { setMessage(""); setTimeout(() => { inputRef.current?.focus(); }, 50); e.stopPropagation(); }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.CloseCircleFillIcon, { size: 18, color: "white" }) } ), onFocus: () => setFocus(true), onBlur: () => setFocus(false), onChange: (e) => { if (e.target.value.length > 25) { ui.toast.error(t("share.pnl.optionalInfo.message.maxLength")); return; } setCheck(e.target.value.length > 0); setMessage(e.target.value); } } ) }) ] }); }; var ShareOption = (props) => { const { type, curType, setShareOption } = props; const { t } = i18n.useTranslation(); const text = React.useMemo(() => { switch (type) { case "openPrice": return t("share.pnl.optionalInfo.openPrice"); case "closePrice": return t("share.pnl.optionalInfo.closePrice"); case "openTime": return t("share.pnl.optionalInfo.openTime"); case "closeTime": return t("share.pnl.optionalInfo.closeTime"); case "markPrice": return t("common.markPrice"); case "quantity": return t("common.quantity"); case "leverage": return t("common.leverage"); } }, [type, t]); const isSelected = curType.has(type); return /* @__PURE__ */ jsxRuntime.jsxs( ui.Flex, { itemAlign: "center", gap: 1, className: ui.cn("hover:oui-cursor-pointer"), onClick: () => { setShareOption((value) => { const updateSet = new Set(value); if (isSelected) { updateSet.delete(type); } else { updateSet.add(type); } return updateSet; }); }, children: [ /* @__PURE__ */ jsxRuntime.jsx( Checkbox, { size: 16, checked: isSelected, className: "oui-pt-[2px]", onCheckedChange: (checked) => { setShareOption((value) => { const updateSet = new Set(value); if (isSelected) { updateSet.delete(type); } else { updateSet.add(type); } return updateSet; }); } } ), /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xs", intensity: 54, children: text }) ] } ); }; var PnlFormatView = (props) => { const { type, curType, setPnlFormat } = props; const { t } = i18n.useTranslation(); const text = React.useMemo(() => { switch (type) { case "roi_pnl": return t("share.pnl.displayFormat.roi&Pnl"); case "roi": return t("share.pnl.displayFormat.roi"); case "pnl": return t("share.pnl.displayFormat.pnl"); } }, [type, t]); const isSelected = type === curType; let clsName = "oui-flex oui-items-center oui-gap-1 oui-cursor-pointer"; if (isSelected) { clsName += " oui-text-base-contrast"; } else { clsName += ""; } return /* @__PURE__ */ jsxRuntime.jsxs( "div", { className: clsName, onClick: () => { setPnlFormat(type); }, children: [ /* @__PURE__ */ jsxRuntime.jsx(RadioButton, { sel: isSelected }), /* @__PURE__ */ jsxRuntime.jsx( ui.Text, { size: "xs", intensity: 54, className: ui.cn( "oui-ml-2 " // isSelected && "oui-text-base-contrast" ), children: text } ) ] } ); }; var RadioButton = (props) => { return /* @__PURE__ */ jsxRuntime.jsx( "button", { type: "button", children: props.sel === true ? /* @__PURE__ */ jsxRuntime.jsx(SelIcon, {}) : /* @__PURE__ */ jsxRuntime.jsx(UnselIcon, {}) } ); }; var SelIcon = () => { return /* @__PURE__ */ jsxRuntime.jsxs( "svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "currentColor", xmlns: "http://www.w3.org/2000/svg", className: "oui-fill-primary-darken", children: [ /* @__PURE__ */ jsxRuntime.jsx( "path", { d: "M8.01 1.333a6.667 6.667 0 1 0 0 13.333 6.667 6.667 0 0 0 0-13.333m0 1.333a5.334 5.334 0 1 1-.001 10.667 5.334 5.334 0 0 1 0-10.667", fill: "#fff", fillOpacity: ".36" } ), /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "8", cy: "8", r: "3.333" }) ] } ); }; var UnselIcon = () => { return /* @__PURE__ */ jsxRuntime.jsx( "svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsxRuntime.jsx( "path", { d: "M8.01 1.333a6.667 6.667 0 1 0 0 13.333 6.667 6.667 0 0 0 0-13.333m0 1.333a5.334 5.334 0 1 1-.001 10.667 5.334 5.334 0 0 1 0-10.667", fill: "#fff", fillOpacity: ".54" } ) } ); }; var DesktopSharePnLContent = (props) => { const { shareOptions } = props; const { t } = i18n.useTranslation(); const localPnlConfig = getPnlInfo(); const hasRoiAndPnl = props.entity.roi != null && props.entity.pnl != null; const formats = hasRoiAndPnl ? ["roi_pnl", "roi", "pnl"] : props.entity.roi != null ? ["roi"] : props.entity.pnl != null ? ["pnl"] : []; const [pnlFormat, setPnlFormat] = React.useState( formats.length == 1 ? formats[0] : localPnlConfig.pnlFormat ); const [shareOption, setShareOption] = React.useState( new Set(localPnlConfig.options) ); const [selectedSnap, setSelectedSnap] = React.useState(localPnlConfig.bgIndex); const [message, setMessage] = React.useState(localPnlConfig.message); const [check, setCheck] = React.useState(false); const { backgroundImages, ...resetOptions } = shareOptions ?? { backgroundImages: [] }; const [domain, setDomain] = React.useState(""); const posterRef = React.useRef(null); React.useEffect(() => { const currentDomain = window.location.hostname; setDomain(currentDomain); }, []); const curBgImg = React.useMemo(() => { return shareOptions?.backgroundImages?.[selectedSnap]; }, [shareOptions?.backgroundImages, selectedSnap]); const posterData = getPnLPosterData( props.entity, check ? message : "", domain, pnlFormat, shareOption, props.baseDp, props.quoteDp, props.referral ); const onCopy = () => { posterRef.current?.copy().then(() => { props.hide?.(); ui.toast.success(t("share.pnl.image.copied")); }).catch((e) => { ui.toast.error(() => { return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [ /* @__PURE__ */ jsxRuntime.jsx("div", { children: t("common.copy.failed") }), /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oui-mt-2 oui-max-w-[396px] oui-text-2xs oui-text-base-contrast-54", children: t("share.pnl.copy.failed.description") }) ] }); }); }); }; const onDownload = () => { posterRef.current?.download("Poster.png"); props.hide?.(); }; const options = React.useMemo(() => { const mapping = [ "openPrice", "closePrice", "markPrice", "openTime", "closeTime", "leverage", "quantity" ]; return mapping.filter((key) => !!props.entity[key]); }, [props.entity]); savePnlInfo(pnlFormat, shareOption, selectedSnap, message); return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "oui-relative oui-flex oui-size-full oui-flex-col", children: [ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "oui-h-full oui-flex-1 oui-overflow-y-auto", children: [ /* @__PURE__ */ jsxRuntime.jsxs(ui.Box, { mt: 9, height: 422, children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, { itemAlign: "center", justify: "center", children: /* @__PURE__ */ jsxRuntime.jsx( Poster, { width: 552, height: 310, data: { backgroundImg: curBgImg, ...resetOptions, data: posterData }, ratio: 3, ref: posterRef } ) }), /* @__PURE__ */ jsxRuntime.jsx( CarouselBackgroundImage, { backgroundImages: shareOptions?.backgroundImages ?? types.EMPTY_LIST, selectedSnap, setSelectedSnap } ) ] }), /* @__PURE__ */ jsxRuntime.jsxs( ui.Flex, { direction: "column", px: 10, mt: 6, justify: "start", itemAlign: "start", width: "100%", children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "sm", intensity: 80, children: t("share.pnl.displayFormat") }), /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, { pt: 3, gap: 3, itemAlign: "center", children: formats.map((e, index) => /* @__PURE__ */ jsxRuntime.jsx( PnlFormatView, { setPnlFormat, type: e, curType: pnlFormat }, index )) }), /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { className: "oui-w-full oui-border-white/10 oui-pt-6" }), /* @__PURE__ */ jsxRuntime.jsxs( ui.Flex, { mt: 6, direction: "column", justify: "start", itemAlign: "start", children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "sm", intensity: 80, children: t("share.pnl.optionalInfo") }), /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, { mt: 3, gap: 4, className: "oui-flex-wrap", children: options.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx( ShareOption, { setShareOption, type: item, curType: shareOption }, index )) }) ] } ), /* @__PURE__ */ jsxRuntime.jsx( Message, { message, setMessage, check, setCheck } ) ] } ) ] }), /* @__PURE__ */ jsxRuntime.jsx(BottomButtons, { onClickCopy: onCopy, onClickDownload: onDownload }) ] }); }; var CarouselContext = React__default.default.createContext(null); function useCarousel() { const context = React__default.default.useContext(CarouselContext); if (!context) { throw new Error("useCarousel must be used within a <Carousel />"); } return context; } var Carousel = React__default.default.forwardRef((originalProps, ref) => { const { orientation = "horizontal", opts, setApi, plugins, className, children, ...props } = originalProps; const [carouselRef, api] = ui.useEmblaCarousel( { ...opts, axis: orientation === "horizontal" ? "x" : "y" }, plugins ); const [canScrollPrev, setCanScrollPrev] = React__default.default.useState(false); const [canScrollNext, setCanScrollNext] = React__default.default.useState(false); const [selectedIndex, setSelectedIndex] = React__default.default.useState( props.initIndex || 0 ); const [scrollSnaps, setScrollSnaps] = React__default.default.useState([]); const onSelect = React__default.default.useCallback( (api2) => { if (!api2) { return; } if (scrollSnaps.length === 0) { setScrollSnaps(api2.scrollSnapList()); } setSelectedIndex(api2.selectedScrollSnap()); setCanScrollPrev(api2.canScrollPrev()); setCanScrollNext(api2.canScrollNext()); }, [scrollSnaps] ); const scrollPrev = React__default.default.useCallback(() => { api?.scrollPrev(); }, [api]); const scrollNext = React__default.default.useCallback(() => { api?.scrollNext(); }, [api]); const handleKeyDown = React__default.default.useCallback( (event) => { if (event.key === "ArrowLeft") { event.preventDefault(); scrollPrev(); } else if (event.key === "ArrowRight") { event.preventDefault(); scrollNext(); } }, [scrollPrev, scrollNext] ); React__default.default.useEffect(() => { if (!api || !setApi) { return; } setApi(api); }, [api, setApi]); React__default.default.useEffect(() => { if (!api) { return; } onSelect(api); api.on("reInit", onSelect); api.on("select", onSelect); if (props.initIndex) { api.scrollTo(props.initIndex); } return () => { api?.off("select", onSelect); }; }, [api, onSelect]); const memoizedValue = React__default.default.useMemo(() => { return { carouselRef, api, opts, orientation: orientation || (opts?.axis === "y" ? "vertical" : "horizontal"), scrollPrev, scrollNext, canScrollPrev, canScrollNext, selectedIndex, scrollSnaps }; }, [ carouselRef, api, opts, orientation, scrollPrev, scrollNext, canScrollPrev, canScrollNext, selectedIndex, scrollSnaps ]); return /* @__PURE__ */ jsxRuntime.jsx(CarouselContext.Provider, { value: memoizedValue, children: /* @__PURE__ */ jsxRuntime.jsx( "div", { ref, onKeyDownCapture: handleKeyDown, className: ui.cn("oui-relative", className), role: "region", "aria-roledescription": "carousel", ...props, children } ) }); }); Carousel.displayName = "Carousel"; var CarouselContent = React__default.default.forwardRef((originalProps, ref) => { const { className, children, ...props } = originalProps; const { carouselRef, orientation } = useCarousel(); return /* @__PURE__ */ jsxRuntime.jsx("div", { ref: carouselRef, className: "oui-overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx( "div", { ref, className: ui.cn( "oui-flex", orientation === "horizontal" ? "oui--ml-4" : "oui--mt-4 oui-flex-col", className ), ...props, children } ) }); }); CarouselContent.displayName = "CarouselContent"; var CarouselItem = React__default.default.forwardRef((originalProps, ref) => { const { className, children, ...props } = originalProps; const { orientation } = useCarousel(); return /* @__PURE__ */ jsxRuntime.jsx( "div", { ref, role: "group", "aria-roledescription": "slide", className: ui.cn( "oui-min-w-0 oui-shrink-0 oui-grow-0 oui-basis-full", orientation === "horizontal" ? "oui-pl-4" : "oui-pt-4", className ), ...props, children } ); }); CarouselItem.displayName = "CarouselItem"; var CarouselPrevious = React__default.default.forwardRef((originalProps, ref) => { const { className, variant = "contained", size = "icon", ...props } = originalProps; const { orientation, scrollPrev, canScrollPrev } = useCarousel(); return /* @__PURE__ */ jsxRuntime.jsxs( ui.Button, { ref, variant, className: ui.cn( "oui-absolute oui-size-8 oui-rounded-full", orientation === "horizontal" ? "oui--left-12 oui-top-1/2 oui--translate-y-1/2" : "oui--top-12 oui-left-1/2 oui--translate-x-1/2 oui-rotate-90", className ), disabled: !canScrollPrev, onClick: scrollPrev, ...props, children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.ChevronLeftIcon, { size: 20 }), /* @__PURE__ */ jsxRuntime.jsx("span", { className: "oui-sr-only", children: "Previous slide" }) ] } ); }); CarouselPrevious.displayName = "CarouselPrevious"; var CarouselNext = React__default.default.forwardRef((originalProps, ref) => { const { className, variant = "contained", size = "icon", ...props } = originalProps; const { orientation, scrollNext, canScrollNext } = useCarousel(); return /* @__PURE__ */ jsxRuntime.jsxs( ui.Button, { ref, variant, className: ui.cn( "oui-absolute oui-size-8 oui-rounded-full", orientation === "horizontal" ? "oui--right-12 oui-top-1/2 oui--translate-y-1/2" : "oui--bottom-12 oui-left-1/2 oui--translate-x-1/2 oui-rotate-90", className ), disabled: !canScrollNext, onClick: scrollNext, ...props, children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.ChevronRightIcon, { size: 20 }), /* @__PURE__ */ jsxRuntime.jsx("span", { className: "oui-sr-only", children: "Next slide" }) ] } ); }); CarouselNext.displayName = "CarouselNext"; var CarouselIdentifier = (props) => { const { scrollSnaps, selectedIndex } = useCarousel(); return /* @__PURE__ */ jsxRuntime.jsx("div", { className: ui.cn("oui-flex oui-gap-1", props.className), children: scrollSnaps.map((_, index) => { return /* @__PURE__ */ jsxRuntime.jsx( Dot, { index, active: index === selectedIndex, onClick: props.onClick, className: props.dotClassName, activeClassName: props.dotActiveClassName }, index ); }) }); }; CarouselIdentifier.displayName = "CarouselIdentifier"; var Dot = ({ index, active, onClick, className, activeClassName }) => { const activedClassName = activeClassName || "oui-bg-primary-darken"; return /* @__PURE__ */ jsxRuntime.jsx( "button", { onClick: () => onClick?.(index), className: ui.cn( "oui-size-2 oui-rounded-full oui-bg-white/30", className, active && `active ${activedClassName}` ) } ); }; // src/sharePnL/carousel/index.tsx var Carousel2 = Carousel; Carousel2.Content = CarouselContent; Carousel2.Item = CarouselItem; Carousel2.Next = CarouselNext; Carousel2.Previous = CarouselPrevious; Carousel2.indentify = CarouselIdentifier; var MobileSharePnLContent = (props) => { const { shareOptions } = props; const { t } = i18n.useTranslation(); const localPnlConfig = getPnlInfo(); const hasRoiAndPnl = props.entity.roi != null && props.entity.pnl != null; const formats = hasRoiAndPnl ? ["roi_pnl", "roi", "pnl"] : props.entity.roi != null ? ["roi"] : props.entity.pnl != null ? ["pnl"] : []; const [pnlFormat, setPnlFormat] = React.useState( formats.length == 1 ? formats[0] : localPnlConfig.pnlFormat ); const [shareOption, setShareOption] = React.useState( new Set(localPnlConfig.options) ); const [message, setMessage] = React.useState(localPnlConfig.message); const [selectIndex, setSelectIndex] = React.useState(localPnlConfig.bgIndex); const { backgroundImages, ...resetOptions } = shareOptions ?? { backgroundImages: [] }; const [domain, setDomain] = React.useState(""); const posterRefs = shareOptions?.backgroundImages?.map( () => React.useRef(null) ); React.useEffect(() => { const currentDomain = window.location.hostname; setDomain(currentDomain); }, []); const posterData = getPnLPosterData( props.entity, message, domain, pnlFormat, shareOption, props.baseDp, props.quoteDp, props.referral ); const carouselRef = React.useRef(); const aspectRatio = 552 / 310; const [scale, setScale] = React.useState(1); const [carouselHeight, setCarouselHeight] = React.useState(0); const [focus, setFocus] = React.useState(false); const inputRef = React.useRef(null); React.useEffect(() => { if (carouselRef.current) { const divWidth = carouselRef.current.offsetWidth; const divHeight = divWidth / aspectRatio; setCarouselHeight(divHeight); setScale(divWidth / 552); } }, [carouselRef, domain]); const onSharePnL = async (posterRef) => { if (!posterRef.current) return; const data = posterRef.current?.toDataURL(); const blob = dataURItoBlob(data); try { if (navigator.share) { await navigator.share({ // title: "Share PnL", text: message, // url: imageUrl, files: [new File([blob], "image.png", { type: "image/png" })] }); } else { } props.hide?.(); } catch (error) { } }; const options = React.useMemo(() => { const mapping = [ "openPrice", "closePrice", "openTime", "closeTime", "leverage", "markPrice", "quantity" ]; return mapping.filter((key) => !!props.entity[key]); }, [props.entity]); savePnlInfo(pnlFormat, shareOption, selectIndex, message); return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "oui-w-full", children: [ /* @__PURE__ */ jsxRuntime.jsx( "div", { ref: carouselRef, className: "oui-mt-4 oui-w-full oui-overflow-hidden", style: { height: `${carouselHeight + 20}px` }, children: /* @__PURE__ */ jsxRuntime.jsxs( Carousel2, { className: "oui-w-full oui-overflow-hidden", opts: { align: "start" }, initIndex: selectIndex, children: [ /* @__PURE__ */ jsxRuntime.jsx(CarouselContent, { style: { height: `${carouselHeight}px` }, children: shareOptions?.backgroundImages?.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx(CarouselItem, { children: /* @__PURE__ */ jsxRuntime.jsx( Poster, { className: "oui-origin-top-left oui-transform", style: { scale: `${scale}` }, width: 552, height: 310, data: { backgroundImg: item, ...resetOptions, data: posterData }, ratio: 3, ref: posterRefs?.[index] } ) }, index)) }), /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oui-mb-1 oui-mt-2 oui-flex oui-justify-center", children: /* @__PURE__ */ jsxRuntime.jsx( MyIdentifier, { dotClassName: "oui-w-[16px] oui-h-[4px] oui-bg-base-300", dotActiveClassName: "!oui-bg-primary-darken oui-w-[20px]", setSelectIndex } ) }) ] } ) } ), /* @__PURE__ */ jsxRuntime.jsxs(ui.ScrollArea, { className: "oui-custom-scrollbar oui-max-h-[200px] oui-overflow-y-auto", children: [ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "oui-mt-4", children: [ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oui-text-3xs oui-text-base-contrast-54", children: t("share.pnl.displayFormat") }), /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oui-row-span-1 oui-grid oui-grid-cols-3 oui-justify-between oui-gap-3 oui-px-1 oui-pt-3", children: formats.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx( PnlFormatView2, { setPnlFormat, type: item, curType: pnlFormat }, index )) }) ] }), /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "oui-mt-3", children: [ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oui-h-[18px] oui-text-3xs oui-text-base-contrast-54", children: t("share.pnl.optionalInfo") }), /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oui-mt-3 oui-flex oui-flex-wrap oui-gap-3", children: options.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx( ShareOption2, { setShareOption, type: item, curType: shareOption }, index )) }) ] }), /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "oui-mb-8 oui-mt-3", children: [ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oui-h-[18px] oui-text-3xs oui-text-base-contrast-54", children: t("share.pnl.optionalInfo.message") }), /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oui-bg-base-600 oui-mx-1 oui-mt-3 oui-h-[48px]", children: /* @__PURE__ */ jsxRuntime.jsx( ui.Input, { placeholder: t("share.pnl.optionalInfo.message.placeholder"), containerClassName: "oui-bg-transparent oui-h-[48px]", value: message, autoFocus: false, onChange: (e) => { if (e.target.value.length > 25) { ui.toast.error(t("share.pnl.optionalInfo.message.maxLength")); return; } setMessage(e.target.value); }, ref: inputRef, onFocus: () => setFocus(true), onBlur: () => setFocus(false), suffix: focus && /* @__PURE__ */ jsxRuntime.jsx( "button", { className: "oui-mr-3 oui-cursor-pointer", onMouseDown: (e) => { setMessage(""); setTimeout(() => { inputRef.current?.focus(); }, 50); e.stopPropagation(); }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.CloseCircleFillIcon, { size: 18, color: "white" }) } ) } ) }) ] }) ] }), /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oui-pt-2", children: /* @__PURE__ */ jsxRuntime.jsx( ui.Button, { fullWidth: true, className: "oui-h-[40px] oui-text-[16px]", onClick: () => { const ref = posterRefs?.[selectIndex]; if (ref) { onSharePnL(ref); } }, children: t("common.share") } ) }) ] }); }; var PnlFormatView2 = (props) => { const { type, curType, setPnlFormat } = props; const { t } = i18n.useTranslation(); const text = React.useMemo(() => { switch (type) { case "roi_pnl": return t("share.pnl.displayFormat.roi&Pnl"); case "roi": return t("share.pnl.displayFormat.roi"); case "pnl": return t("share.pnl.displayFormat.pnl"); } }, [type]); const isSelected = type === curType; return /* @__PURE__ */ jsxRuntime.jsx( "div", { className: ui.cn( "oui-referral-shadow oui-flex oui-h-[46px] oui-flex-1 oui-items-center oui-rounded-lg oui-bg-base-4 oui-px-3 oui-shadow-lg hover:oui-cursor-pointer", isSelected && "oui-dot-sel oui-bg-primary-darken" ), onClick: () => { setPnlFormat(type); }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oui-text-sm oui-text-base-contrast", children: text }) } ); }; var ShareOption2 = (props) => { const { type, curType, setShareOption } = props; const { t } = i18n.useTranslation(); const text = React.useMemo(() => { switch (type) { case "openPrice": return t("share.pnl.optionalInfo.openPrice"); case "closePrice": return t("share.pnl.optionalInfo.closePrice"); case "openTime": return t("share.pnl.optionalInfo.openTime"); case "closeTime": return t("share.pnl.optionalInfo.closeTime"); case "markPrice": return t("common.markPrice"); case "quantity": return t("common.quantity"); case "leverage": return t("common.leverage"); } }, [type, t]); const isSelected = curType.has(type); return /* @__PURE__ */ jsxRuntime.jsxs( "div", { className: ui.cn( "oui-referral-shadow oui-mt-0 oui-flex oui-h-[46px] oui-w-[calc(50%-6px)] oui-items-center oui-rounded-lg oui-bg-base-4 oui-p-3 oui-shadow-lg hover:oui-cursor-pointer" ), onClick: () => { setShareOption((value) => { const updateSet = new Set(value); if (isSelected) { updateSet.delete(type); } else { updateSet.add(type); } return updateSet; }); }, children: [ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oui-flex-1 oui-text-sm oui-text-base-contrast", children: text }), isSelected && /* @__PURE__ */ jsxRuntime.jsx(ChoicesFillIcon, {}) ] } ); }; function dataURItoBlob(dataURI) { const byteString = atob(dataURI.split(",")[1]); const mimeString = dataURI.split(",")[0].split(":")[1].split(";")[0]; const ab = new ArrayBuffer(byteString.length); const ia = new Uint8Array(ab); for (let i = 0; i < byteString.length; i++) { ia[i] = byteString.charCodeAt(i); } return new Blob([ab], { type: mimeString }); } var MyIdentifier = (props) => { const { scrollSnaps, selectedIndex } = useCarousel(); React.useEffect(() => { props.setSelectIndex(selectedIndex); }, [selectedIndex]); return /* @__PURE__ */ jsxRuntime.jsx("div", { className: ui.cn("oui-flex oui-gap-1"), children: scrollSnaps.map((_, index) => { return /* @__PURE__ */ jsxRuntime.jsx( Dot, { index, active: index === selectedIndex, onClick: props.onClick, className: props.dotClassName, activeClassName: props.dotActiveClassName }, index ); }) }); }; var ChoicesFillIcon = () => { return /* @__PURE__ */ jsxRuntime.jsx( "svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsxRuntime.jsx( "path", { fillRule: "evenodd", clipRule: "evenodd", d: "M2.01416 11.9989C2.01416 6.47589 6.49136 1.9989 12.0142 1.9989C17.5372 1.9989 22.0142 6.47589 22.0142 11.9989C22.0142 17.5219 17.5372 21.9989 12.0142 21.9989C6.49136 21.9989 2.01416 17.5219 2.01416 11.9989ZM16.9853 7.31211C17.2125 7.09537 17.5236 7 17.8218 7C18.1201 7 18.4312 7.09537 18.6583 7.31211C19.1139 7.74546 19.1139 8.47384 18.6583 8.9072L10.5077 16.675C10.0534 17.1083 9.28909 17.1083 8.83472 16.675L5.34077 13.3459C4.88641 12.9126 4.88641 12.1841 5.34077 11.7508C5.79631 11.3175 6.56057 11.3175 7.01493 11.7508L9.67122 14.2822L16.9853 7.31211Z", fill: "white", fillOpacity: "1" } ) } ); }; var DesktopSharePnL = (props) => { const { entity, baseDp, quoteDp, referralInfo, shareOptions, hide } = props; if (!shareOptions || !entity) { return null; } return /* @__PURE__ */ jsxRuntime.jsx( DesktopSharePnLContent, { entity, hide, baseDp, quoteDp, referral: referralInfo, shareOptions } ); }; var MobileSharePnL = (props) => { const { entity, baseDp, quoteDp, referralInfo, shareOptions, hide } = props; if (!shareOptions || !entity) { return null; } return /* @__PURE__ */ jsxRuntime.jsx( MobileSharePnLContent, { entity, hide, baseDp, quoteDp, referral: referralInfo, shareOptions } ); }; var SharePnLBottomSheetWidget = (props) => { const state = useSharePnLScript({ hide: props.hide, pnl: props.pnl }); return /* @__PURE__ */ jsxRuntime.jsx(MobileSharePnL, { ...state }); }; var SharePnLDialogWidget = (props) => { const state = useSharePnLScript({ hide: props.hide, pnl: props.pnl }); return /* @__PURE__ */ jsxRuntime.jsx(DesktopSharePnL, { ...state }); }; var SharePnLDialogId = "sharePnLDialog"; var SharePnLBottomSheetId = "sharePnLBottomSheet"; ui.registerSimpleDialog(SharePnLDialogId, SharePnLDialogWidget, { classNames: { content: "!oui-max-w-[624px] oui-p-0" } }); ui.registerSimpleSheet(SharePnLBottomSheetId, SharePnLBottomSheetWidget, { title: i18n.i18n.t("share.pnl.sharePnl"), classNames: { body: "oui-pb-4 oui-pt-0" } }); exports.SharePnLBottomSheetId = SharePnLBottomSheetId; exports.SharePnLBottomSheetWidget = SharePnLBottomSheetWidget; exports.SharePnLDialogId = SharePnLDialogId; exports.SharePnLDialogWidget = SharePnLDialogWidget; exports.useSharePnLScript = useSharePnLScript; //# sourceMappingURL=out.js.map //# sourceMappingURL=index.js.map