Merge branch 'serum' into main

This commit is contained in:
tjs 2022-09-14 02:25:15 -04:00
commit 007c3c2fa2
369 changed files with 9005 additions and 225 deletions

View File

@ -3,7 +3,7 @@ import { ReactNode, useEffect } from 'react'
import { ChevronRightIcon } from '@heroicons/react/20/solid'
import { useViewport } from '../hooks/useViewport'
import { breakpoints } from '../utils/theme'
import mangoStore from '../store/mangoStore'
import mangoStore from '@store/mangoStore'
import BottomBar from './mobile/BottomBar'
import BounceLoader from './shared/BounceLoader'
import TopBar from './TopBar'
@ -71,7 +71,9 @@ const Layout = ({ children }: { children: ReactNode }) => {
/>
<TopBar />
</div>
<div className="min-h-screen p-6 pb-20 md:p-8">{children}</div>
<div className="hide-scroll max-h-screen overflow-y-scroll">
{children}
</div>
</div>
</div>
</div>

View File

@ -6,7 +6,7 @@ import {
} from '@heroicons/react/20/solid'
import { Popover, Transition } from '@headlessui/react'
import { MangoAccount } from '@blockworks-foundation/mango-v4'
import mangoStore from '../store/mangoStore'
import mangoStore from '@store/mangoStore'
import { LinkButton } from './shared/Button'
import CreateAccountModal from './modals/CreateAccountModal'
import { useLocalStorageStringState } from '../hooks/useLocalStorageState'

View File

@ -9,20 +9,17 @@ import {
CurrencyDollarIcon,
ChartBarIcon,
Cog8ToothIcon,
ArrowsRightLeftIcon,
} from '@heroicons/react/20/solid'
import { useRouter } from 'next/router'
import { useTranslation } from 'next-i18next'
import { Fragment, ReactNode, useEffect, useState } from 'react'
import { Disclosure, Popover, Transition } from '@headlessui/react'
import MangoAccountSummary from './account/MangoAccountSummary'
import HealthHeart from './account/HealthHeart'
import mangoStore from '../store/mangoStore'
import Tooltip from './shared/Tooltip'
import { HealthType } from '@blockworks-foundation/mango-v4'
const SideNav = ({ collapsed }: { collapsed: boolean }) => {
const { t } = useTranslation('common')
const mangoAccount = mangoStore((s) => s.mangoAccount.current)
const router = useRouter()
const { pathname } = router
@ -70,6 +67,13 @@ const SideNav = ({ collapsed }: { collapsed: boolean }) => {
title={t('account')}
pagePath="/"
/>
<MenuItem
active={pathname === '/swap'}
collapsed={collapsed}
icon={<ArrowsRightLeftIcon className="h-5 w-5" />}
title={t('swap')}
pagePath="/swap"
/>
<MenuItem
active={pathname === '/trade'}
collapsed={collapsed}
@ -125,33 +129,7 @@ const SideNav = ({ collapsed }: { collapsed: boolean }) => {
</ExpandableMenuItem>
</div>
</div>
{mangoAccount ? (
<div className="border-t border-th-bkg-3">
<ExpandableMenuItem
collapsed={collapsed}
icon={
<HealthHeart
health={mangoAccount.getHealthRatioUi(HealthType.maint)!}
size={32}
/>
}
title={
<div className="text-left">
<p className="mb-0.5 whitespace-nowrap text-xs">Health Check</p>
<p className="text-sm font-bold text-th-fgd-1">
{mangoAccount.name}
</p>
</div>
}
alignBottom
hideIconBg
>
<div className="px-4 pb-4 pt-2">
<MangoAccountSummary />
</div>
</ExpandableMenuItem>
</div>
) : null}
<MangoAccountSummary collapsed={collapsed} />
</div>
)
}
@ -219,7 +197,7 @@ const MenuItem = ({
)
}
const ExpandableMenuItem = ({
export const ExpandableMenuItem = ({
alignBottom,
children,
collapsed,

View File

@ -14,7 +14,7 @@ import { Fragment, useCallback, useEffect, useMemo, useState } from 'react'
// import useLocalStorageState from '../hooks/useLocalStorageState'
import { useViewport } from '../hooks/useViewport'
import mangoStore from '../store/mangoStore'
import mangoStore from '@store/mangoStore'
import { COLORS } from '../styles/colors'
// import { SHOW_ZERO_BALANCES_KEY } from '../utils/constants'
import { formatDecimal, formatFixedDecimals } from '../utils/numbers'
@ -46,12 +46,6 @@ const TokenList = () => {
const { width } = useViewport()
const showTableView = width ? width > breakpoints.md : false
useEffect(() => {
if (coingeckoPrices.length === 0) {
actions.fetchCoingeckoPrices()
}
}, [coingeckoPrices, actions])
const banks = useMemo(() => {
if (group) {
const rawBanks = Array.from(group?.banksMapByName, ([key, value]) => ({
@ -424,7 +418,7 @@ const ActionsMenu = ({
s.swap.outputTokenInfo = outputTokenInfo
})
if (asPath === '/') {
router.push('/trade', undefined, { shallow: true })
router.push('/swap', undefined, { shallow: true })
}
}, [bank, router, asPath, set, jupiterTokens])
@ -437,7 +431,7 @@ const ActionsMenu = ({
s.swap.inputTokenInfo = inputTokenInfo
})
if (asPath === '/') {
router.push('/trade', undefined, { shallow: true })
router.push('/swap', undefined, { shallow: true })
}
}, [router, asPath, set, bank, jupiterTokens])

View File

@ -2,7 +2,7 @@ import { useCallback, useState } from 'react'
import { ArrowRightIcon } from '@heroicons/react/20/solid'
import { useTranslation } from 'next-i18next'
import mangoStore from '../store/mangoStore'
import mangoStore from '@store/mangoStore'
import WalletIcon from './icons/WalletIcon'
import MangoAccountsList from './MangoAccountsList'
import { LinkButton } from './shared/Button'

View File

@ -15,7 +15,7 @@ import { IconButton } from './shared/Button'
import { Transition } from '@headlessui/react'
import SheenLoader from './shared/SheenLoader'
import { useWallet } from '@solana/wallet-adapter-react'
import { TradeHistoryItem } from '../store/mangoStore'
import { TradeHistoryItem } from '@store/mangoStore'
import {
countLeadingZeros,
formatFixedDecimals,

View File

@ -1,7 +1,7 @@
import { MangoAccount } from '@blockworks-foundation/mango-v4'
import { useTranslation } from 'next-i18next'
import { useState } from 'react'
import mangoStore from '../../store/mangoStore'
import mangoStore from '@store/mangoStore'
import DetailedAreaChart from '../shared/DetailedAreaChart'
const AccountChart = ({

View File

@ -10,7 +10,7 @@ import { useEffect, useMemo, useState } from 'react'
import AccountActions from './AccountActions'
import DepositModal from '../modals/DepositModal'
import WithdrawModal from '../modals/WithdrawModal'
import mangoStore, { PerformanceDataItem } from '../../store/mangoStore'
import mangoStore, { PerformanceDataItem } from '@store/mangoStore'
import { formatDecimal, formatFixedDecimals } from '../../utils/numbers'
import FlipNumbers from 'react-flip-numbers'
import { DownTriangle, UpTriangle } from '../shared/DirectionTriangles'

View File

@ -1,5 +1,5 @@
import { useEffect, useState } from 'react'
import mangoStore from '../../store/mangoStore'
import mangoStore from '@store/mangoStore'
import TabButtons from '../shared/TabButtons'
import TokenList from '../TokenList'
import TradeHistoryTable from '../TradeHistoryTable'

View File

@ -1,7 +1,7 @@
import { Bank } from '@blockworks-foundation/mango-v4'
import Image from 'next/image'
import { useMemo } from 'react'
import mangoStore from '../../store/mangoStore'
import mangoStore from '@store/mangoStore'
import { formatDecimal } from '../../utils/numbers'
const ActionTokenItem = ({

View File

@ -1,5 +1,5 @@
import { Bank } from '@blockworks-foundation/mango-v4'
import mangoStore from '../../store/mangoStore'
import mangoStore from '@store/mangoStore'
import ActionTokenItem from './ActionTokenItem'
type BankParams = {

View File

@ -1,4 +1,4 @@
import mangoStore from '../../store/mangoStore'
import mangoStore from '@store/mangoStore'
import {
HealthType,
toUiDecimalsForQuote,
@ -10,8 +10,10 @@ import DepositModal from '../modals/DepositModal'
import WithdrawModal from '../modals/WithdrawModal'
import { useTranslation } from 'next-i18next'
import { ArrowDownTrayIcon } from '@heroicons/react/20/solid'
import HealthHeart from './HealthHeart'
import { ExpandableMenuItem } from '../SideNav'
const MangoAccountSummary = () => {
const MangoAccountSummary = ({ collapsed }: { collapsed: boolean }) => {
const { t } = useTranslation('common')
const mangoAccount = mangoStore((s) => s.mangoAccount.current)
const [showDepositModal, setShowDepositModal] = useState(false)
@ -19,59 +21,90 @@ const MangoAccountSummary = () => {
return (
<>
<div className="mb-4 space-y-2">
<div>
<p className="text-sm text-th-fgd-3">{t('health')}</p>
<p className="text-sm font-bold text-th-fgd-1">
{mangoAccount
? mangoAccount.getHealthRatioUi(HealthType.maint)
: 100}
%
</p>
</div>
<div>
<p className="text-sm text-th-fgd-3">{t('account-value')}</p>
<p className="text-sm font-bold text-th-fgd-1">
$
{mangoAccount
? formatDecimal(
toUiDecimalsForQuote(mangoAccount.getEquity()!.toNumber()),
2
)
: (0).toFixed(2)}
</p>
</div>
<div>
<p className="text-sm text-th-fgd-3">{t('free-collateral')}</p>
<p className="text-sm font-bold text-th-fgd-1">
$
{mangoAccount
? formatDecimal(
toUiDecimalsForQuote(
mangoAccount.getCollateralValue()!.toNumber()
),
2
)
: (0).toFixed(2)}
</p>
</div>
</div>
<div className="space-y-2">
<Button
className="flex w-full items-center justify-center"
onClick={() => setShowDepositModal(true)}
>
<ArrowDownTrayIcon className="mr-2 h-5 w-5" />
{t('deposit')}
</Button>
{/* <Button
{mangoAccount ? (
<div className="border-t border-th-bkg-3">
<ExpandableMenuItem
collapsed={collapsed}
icon={
<HealthHeart
health={mangoAccount.getHealthRatioUi(HealthType.maint)!}
size={32}
/>
}
title={
<div className="text-left">
<p className="mb-0.5 whitespace-nowrap text-xs">Health Check</p>
<p className="text-sm font-bold text-th-fgd-1">
{mangoAccount.name}
</p>
</div>
}
alignBottom
hideIconBg
>
<div className="px-4 pb-4 pt-2">
<div className="mb-4 space-y-2">
<div>
<p className="text-sm text-th-fgd-3">{t('health')}</p>
<p className="text-sm font-bold text-th-fgd-1">
{mangoAccount
? mangoAccount.getHealthRatioUi(HealthType.maint)
: 100}
%
</p>
</div>
<div>
<p className="text-sm text-th-fgd-3">{t('account-value')}</p>
<p className="text-sm font-bold text-th-fgd-1">
$
{mangoAccount
? formatDecimal(
toUiDecimalsForQuote(
mangoAccount.getEquity()!.toNumber()
),
2
)
: (0).toFixed(2)}
</p>
</div>
<div>
<p className="text-sm text-th-fgd-3">
{t('free-collateral')}
</p>
<p className="text-sm font-bold text-th-fgd-1">
$
{mangoAccount
? formatDecimal(
toUiDecimalsForQuote(
mangoAccount.getCollateralValue()!.toNumber()
),
2
)
: (0).toFixed(2)}
</p>
</div>
</div>
<div className="space-y-2">
<Button
className="flex w-full items-center justify-center"
onClick={() => setShowDepositModal(true)}
>
<ArrowDownTrayIcon className="mr-2 h-5 w-5" />
{t('deposit')}
</Button>
{/* <Button
className="w-full"
onClick={() => setShowWithdrawModal(true)}
secondary
>
{t('withdraw')}
</Button> */}
</div>
</div>
</div>
</ExpandableMenuItem>
</div>
) : null}
{showDepositModal ? (
<DepositModal
isOpen={showDepositModal}

View File

@ -49,13 +49,13 @@ const BottomBar = () => {
</Link>
<Link
href={{
pathname: '/trade',
pathname: '/swap',
}}
shallow={true}
>
<a
className={`${
asPath === '/trade' ? 'text-th-primary' : 'text-th-fgd-3'
asPath === '/swap' ? 'text-th-primary' : 'text-th-fgd-3'
} col-span-1 flex cursor-pointer flex-col items-center`}
>
<TradeIcon className="mb-1 h-4 w-4" />

View File

@ -1,6 +1,6 @@
import { ModalProps } from '../../types/modal'
import Modal from '../shared/Modal'
import mangoStore from '../../store/mangoStore'
import mangoStore from '@store/mangoStore'
import { notify } from '../../utils/notifications'
import Button from '../shared/Button'
import { useTranslation } from 'next-i18next'

View File

@ -9,7 +9,7 @@ import { useTranslation } from 'next-i18next'
import Image from 'next/image'
import React, { ChangeEvent, useCallback, useMemo, useState } from 'react'
import NumberFormat, { NumberFormatValues } from 'react-number-format'
import mangoStore from '../../store/mangoStore'
import mangoStore from '@store/mangoStore'
import { ModalProps } from '../../types/modal'
import { INPUT_TOKEN_DEFAULT } from '../../utils/constants'
import { notify } from '../../utils/notifications'

View File

@ -1,6 +1,6 @@
import { ModalProps } from '../../types/modal'
import Modal from '../shared/Modal'
import mangoStore from '../../store/mangoStore'
import mangoStore from '@store/mangoStore'
import { notify } from '../../utils/notifications'
import { useWallet } from '@solana/wallet-adapter-react'
import Button from '../shared/Button'

View File

@ -2,7 +2,7 @@ import { ChangeEvent, useState } from 'react'
import { useTranslation } from 'next-i18next'
import { ModalProps } from '../../types/modal'
import Modal from '../shared/Modal'
import mangoStore from '../../store/mangoStore'
import mangoStore from '@store/mangoStore'
import { notify } from '../../utils/notifications'
import Button from '../shared/Button'
import BounceLoader from '../shared/BounceLoader'

View File

@ -17,7 +17,7 @@ import React, {
useState,
} from 'react'
import NumberFormat, { NumberFormatValues } from 'react-number-format'
import mangoStore from '../../store/mangoStore'
import mangoStore from '@store/mangoStore'
import { ModalProps } from '../../types/modal'
import { ALPHA_DEPOSIT_LIMIT, INPUT_TOKEN_DEFAULT } from '../../utils/constants'
import { notify } from '../../utils/notifications'

View File

@ -1,5 +1,5 @@
import { useState, useEffect } from 'react'
import mangoStore from '../../store/mangoStore'
import mangoStore from '@store/mangoStore'
import { useWallet } from '@solana/wallet-adapter-react'
import { PhotoIcon } from '@heroicons/react/20/solid'
import Modal from '../shared/Modal'

View File

@ -18,7 +18,7 @@ import {
XMarkIcon,
} from '@heroicons/react/20/solid'
import { useWallet } from '@solana/wallet-adapter-react'
import mangoStore from '../../store/mangoStore'
import mangoStore from '@store/mangoStore'
import { EnterRightExitLeft, FadeInFadeOut } from '../shared/Transitions'
import Image from 'next/image'
import BounceLoader from '../shared/BounceLoader'

View File

@ -10,7 +10,7 @@ import Image from 'next/image'
import { ChangeEvent, useCallback, useMemo, useState } from 'react'
import NumberFormat, { NumberFormatValues } from 'react-number-format'
import mangoStore from '../../store/mangoStore'
import mangoStore from '@store/mangoStore'
import { ModalProps } from '../../types/modal'
import { INPUT_TOKEN_DEFAULT } from '../../utils/constants'
import { notify } from '../../utils/notifications'

View File

@ -15,7 +15,7 @@ const ContentBox = ({
}: ContentBoxProps) => {
return (
<div
className={`rounded-lg ${hideBorder ? '' : 'border border-th-bkg-3'} ${
className={`rounded ${hideBorder ? '' : 'border border-th-bkg-3'} ${
showBackground ? 'bg-th-bkg-2' : ''
} ${hidePadding ? '' : 'p-6'} ${className}`}
>

View File

@ -3,7 +3,7 @@ import { ArrowRightIcon } from '@heroicons/react/20/solid'
import { PublicKey } from '@solana/web3.js'
import { useTranslation } from 'next-i18next'
import { useMemo } from 'react'
import mangoStore from '../../store/mangoStore'
import mangoStore from '@store/mangoStore'
const HealthImpact = ({
uiAmount,

View File

@ -5,7 +5,7 @@ import {
InformationCircleIcon,
XCircleIcon,
} from '@heroicons/react/20/solid'
import mangoStore, { CLUSTER } from '../../store/mangoStore'
import mangoStore, { CLUSTER } from '@store/mangoStore'
import { Notification, notify } from '../../utils/notifications'
import Loading from './Loading'
import { Transition } from '@headlessui/react'

View File

@ -2,7 +2,7 @@ import { useWallet } from '@solana/wallet-adapter-react'
import { PublicKey } from '@solana/web3.js'
import { getProfilePicture } from '@solflare-wallet/pfp'
import { useEffect, useState } from 'react'
import mangoStore from '../../store/mangoStore'
import mangoStore from '@store/mangoStore'
import ProfileIcon from '../icons/ProfileIcon'
const ProfileImage = ({

View File

@ -0,0 +1,25 @@
import React, { FunctionComponent } from 'react'
import { useTranslation } from 'next-i18next'
type SideBadgeProps = {
side: string
}
const SideBadge: FunctionComponent<SideBadgeProps> = ({ side }) => {
const { t } = useTranslation('common')
return (
<div
className={`inline-block rounded uppercase ${
side === 'buy' || side === 'long'
? 'border border-th-green text-th-green'
: 'border border-th-red text-th-red'
}
-my-0.5 px-1.5 py-0.5 text-xs uppercase`}
>
{t(side)}
</div>
)
}
export default SideBadge

View File

@ -1,5 +1,5 @@
import { MangoAccount } from '@blockworks-foundation/mango-v4'
import mangoStore from '../../store/mangoStore'
import mangoStore from '@store/mangoStore'
export default function useMangoAccount(): {
mangoAccount: MangoAccount | undefined

View File

@ -0,0 +1,15 @@
import { useEffect, useRef } from 'react'
export default function usePrevious(value: any): any {
// The ref object is a generic container whose current property is mutable ...
// ... and can hold any value, similar to an instance property on a class
const ref = useRef()
// Store current value in ref
useEffect(() => {
ref.current = value
}, [value]) // Only re-run if value changes
// Return previous value (happens before update in useEffect above)
return ref.current
}

View File

@ -8,7 +8,7 @@ import Image from 'next/image'
import { Fragment, useMemo, useState } from 'react'
import { useViewport } from '../../hooks/useViewport'
import mangoStore from '../../store/mangoStore'
import mangoStore from '@store/mangoStore'
import { formatDecimal, formatFixedDecimals } from '../../utils/numbers'
import { breakpoints } from '../../utils/theme'
import { IconButton } from '../shared/Button'

View File

@ -11,7 +11,7 @@ import { Jupiter, RouteInfo, TransactionFeeInfo } from '@jup-ag/core'
import JSBI from 'jsbi'
import Decimal from 'decimal.js'
import mangoStore from '../../store/mangoStore'
import mangoStore from '@store/mangoStore'
import RoutesModal from './RoutesModal'
import Button, { IconButton } from '../shared/Button'
import Loading from '../shared/Loading'

View File

@ -1,6 +1,6 @@
import Decimal from 'decimal.js'
import { ChangeEvent, useEffect, useRef, useState } from 'react'
import mangoStore from '../../store/mangoStore'
import mangoStore from '@store/mangoStore'
import { useTokenMax } from './useTokenMax'
const LeverageSlider = ({

View File

@ -2,7 +2,7 @@ import { RouteInfo } from '@jup-ag/core'
import { Dispatch, SetStateAction } from 'react'
import JSBI from 'jsbi'
import mangoStore from '../../store/mangoStore'
import mangoStore from '@store/mangoStore'
import { Token } from '../../types/jupiter'
import { formatDecimal } from '../../utils/numbers'
import Modal from '../shared/Modal'

View File

@ -10,7 +10,7 @@ import {
import { RouteInfo } from '@jup-ag/core'
import NumberFormat, { NumberFormatValues } from 'react-number-format'
import Decimal from 'decimal.js'
import mangoStore from '../../store/mangoStore'
import mangoStore from '@store/mangoStore'
import ContentBox from '../shared/ContentBox'
import JupiterRouteInfo from './JupiterRouteInfo'
import TokenSelect from './TokenSelect'

View File

@ -1,7 +1,7 @@
import { memo, useMemo, useState, useEffect, ChangeEvent } from 'react'
import Image from 'next/image'
import { Token } from '../../types/jupiter'
import mangoStore from '../../store/mangoStore'
import mangoStore from '@store/mangoStore'
import Input from '../forms/Input'
import { IconButton } from '../shared/Button'
import {

View File

@ -1,7 +1,7 @@
import { XMarkIcon } from '@heroicons/react/20/solid'
import { useTranslation } from 'next-i18next'
import { useState } from 'react'
import mangoStore from '../../store/mangoStore'
import mangoStore from '@store/mangoStore'
import ButtonGroup from '../forms/ButtonGroup'
import Input from '../forms/Input'
import Switch from '../forms/Switch'

View File

@ -3,7 +3,7 @@ import {
QuestionMarkCircleIcon,
} from '@heroicons/react/20/solid'
import Image from 'next/image'
import mangoStore from '../../store/mangoStore'
import mangoStore from '@store/mangoStore'
type TokenSelectProps = {
tokenSymbol: string | undefined

View File

@ -1,6 +1,6 @@
import Swap from './SwapForm'
import SwapTokenChart from './SwapTokenChart'
import mangoStore from '../../store/mangoStore'
import mangoStore from '@store/mangoStore'
import AccountTabs from '../account/AccountTabs'
const TradeSimplePage = () => {

View File

@ -4,7 +4,7 @@ import { useEffect, useState } from 'react'
import JSBI from 'jsbi'
import Decimal from 'decimal.js'
import mangoStore, { CLUSTER } from '../../store/mangoStore'
import mangoStore, { CLUSTER } from '@store/mangoStore'
import { Token } from '../../types/jupiter'
import { PublicKey } from '@solana/web3.js'

View File

@ -1,7 +1,7 @@
import { Bank, Group, MangoAccount } from '@blockworks-foundation/mango-v4'
import Decimal from 'decimal.js'
import { useMemo } from 'react'
import mangoStore from '../../store/mangoStore'
import mangoStore from '@store/mangoStore'
import { floorToDecimal } from '../../utils/numbers'
import useMangoAccount from '../shared/useMangoAccount'

View File

@ -0,0 +1,131 @@
import { Serum3Market } from '@blockworks-foundation/mango-v4'
import PercentageChange from '@components/shared/PercentageChange'
import { Popover } from '@headlessui/react'
import { ChevronDownIcon } from '@heroicons/react/20/solid'
import mangoStore from '@store/mangoStore'
import { useTranslation } from 'next-i18next'
import { useCallback, useMemo } from 'react'
import { DEFAULT_MARKET_NAME } from 'utils/constants'
import { formatFixedDecimals } from 'utils/numbers'
const MarketSelectDropdown = () => {
const selectedMarket = mangoStore((s) => s.selectedMarket.current)
const serumMarkets = mangoStore((s) => s.serumMarkets)
const set = mangoStore((s) => s.set)
const handleSelectMarket = useCallback(
(market: Serum3Market, close: any) => {
set((s) => {
s.selectedMarket.current = market
})
close()
},
[set]
)
return (
<Popover>
{({ close, open }) => (
<div className="relative flex flex-col overflow-visible">
<Popover.Button className="flex w-full items-center hover:text-th-primary">
<div className="p-4">
<div className="text-lg">
{selectedMarket?.name || DEFAULT_MARKET_NAME}
</div>
</div>
<ChevronDownIcon
className={`${
open ? 'rotate-180' : 'rotate-360'
} mt-0.5 h-6 w-6 flex-shrink-0 text-th-fgd-3`}
/>
</Popover.Button>
<Popover.Panel className="absolute top-16 z-50 mr-4 w-56 border border-th-bkg-3 bg-th-bkg-1">
{serumMarkets?.length
? serumMarkets.map((m) => (
<div
key={m.publicKey.toString()}
className="bg-th-bkg-1 py-2 px-4 hover:cursor-pointer hover:bg-th-bkg-2"
onClick={() => handleSelectMarket(m, close)}
>
{m.name}
</div>
))
: null}
</Popover.Panel>
</div>
)}
</Popover>
)
}
const OraclePrice = () => {
const group = mangoStore((s) => s.group)
const selectedMarket = mangoStore((s) => s.selectedMarket.current)
if (!group || !selectedMarket) return null
const baseTokenBank = group.getFirstBankByTokenIndex(
selectedMarket?.baseTokenIndex
)
return (
<div className="text-th-fgd-1 md:text-xs">
$
{baseTokenBank.uiPrice
? formatFixedDecimals(baseTokenBank.uiPrice)
: null}
</div>
)
}
const AdvancedMarketHeader = () => {
const { t } = useTranslation('common')
const selectedMarket = mangoStore((s) => s.selectedMarket.current)
const coingeckoPrices = mangoStore((s) => s.coingeckoPrices.data)
const baseSymbol = useMemo(() => {
return selectedMarket?.name.split('/')[0]
}, [selectedMarket])
const coingeckoData = coingeckoPrices.find((asset) =>
baseSymbol === 'soETH'
? asset.symbol === 'ETH'
: asset.symbol === baseSymbol
)
const change = coingeckoData
? ((coingeckoData.prices[coingeckoData.prices.length - 1][1] -
coingeckoData.prices[0][1]) /
coingeckoData.prices[0][1]) *
100
: 0
return (
<div className="flex items-center border border-th-bkg-3 bg-th-bkg-1">
<div className="hidden md:block md:pr-6 lg:pb-0">
<div className="flex items-center">
<MarketSelectDropdown />
</div>
</div>
<div className="ml-6 flex-col">
<div className="text-th-fgd-4 md:pb-0.5 md:text-xs">
{t('oracle-price')}
</div>
<OraclePrice />
</div>
<div className="ml-6 flex-col">
<div className="text-th-fgd-4 md:pb-0.5 md:text-xs">
{t('rolling-change')}
</div>
<div
className={`text-xs ${change < 0 ? 'text-th-red' : 'text-th-gree'}`}
>
{isNaN(change) ? '0.00' : change.toFixed(2)}%
</div>
</div>
</div>
)
}
export default AdvancedMarketHeader

View File

@ -0,0 +1,311 @@
import {
Serum3OrderType,
Serum3SelfTradeBehavior,
Serum3Side,
} from '@blockworks-foundation/mango-v4'
import Checkbox from '@components/forms/Checkbox'
import Button from '@components/shared/Button'
import Tooltip from '@components/shared/Tooltip'
import mangoStore from '@store/mangoStore'
import Decimal from 'decimal.js'
import { useTranslation } from 'next-i18next'
import { useCallback, useMemo, useState } from 'react'
import NumberFormat, { NumberFormatValues } from 'react-number-format'
import { notify } from 'utils/notifications'
const AdvancedTradeForm = () => {
const { t } = useTranslation('common')
const set = mangoStore.getState().set
const tradeForm = mangoStore((s) => s.tradeForm)
const selectedMarket = mangoStore((s) => s.selectedMarket.current)
const [useMargin, setUseMargin] = useState(true)
const baseSymbol = useMemo(() => {
return selectedMarket?.name.split('/')[0]
}, [selectedMarket])
const quoteSymbol = useMemo(() => {
return selectedMarket?.name.split('/')[1]
}, [selectedMarket])
const setTradeType = useCallback(
(tradeType: 'Limit' | 'Market') => {
set((s) => {
s.tradeForm.tradeType = tradeType
})
},
[set]
)
const handlePriceChange = useCallback(
(e: NumberFormatValues) => {
set((s) => {
s.tradeForm.price = e.value
})
},
[set]
)
const handleBaseSizeChange = useCallback(
(e: NumberFormatValues) => {
set((s) => {
s.tradeForm.baseSize = e.value
})
},
[set]
)
const handlePostOnlyChange = useCallback(
(postOnly: boolean) => {
set((s) => {
s.tradeForm.postOnly = postOnly
if (s.tradeForm.ioc === true) {
s.tradeForm.ioc = !postOnly
}
})
},
[set]
)
const handleIocChange = useCallback(
(ioc: boolean) => {
set((s) => {
s.tradeForm.ioc = ioc
if (s.tradeForm.postOnly === true) {
s.tradeForm.postOnly = !ioc
}
})
},
[set]
)
const handleSetSide = useCallback(
(side: 'buy' | 'sell') => {
set((s) => {
s.tradeForm.side = side
})
},
[set]
)
const handlePlaceOrder = useCallback(async () => {
const client = mangoStore.getState().client
const group = mangoStore.getState().group
const mangoAccount = mangoStore.getState().mangoAccount.current
const tradeForm = mangoStore.getState().tradeForm
const actions = mangoStore.getState().actions
if (!group || !mangoAccount) return
try {
const orderType = tradeForm.ioc
? Serum3OrderType.immediateOrCancel
: tradeForm.postOnly
? Serum3OrderType.postOnly
: Serum3OrderType.limit
const tx = await client.serum3PlaceOrder(
group,
mangoAccount,
selectedMarket!.serumMarketExternal,
tradeForm.side === 'buy' ? Serum3Side.bid : Serum3Side.ask,
new Decimal(tradeForm.price).toNumber(),
new Decimal(tradeForm.baseSize).toNumber(),
Serum3SelfTradeBehavior.decrementTake,
orderType,
Date.now(),
10
)
actions.reloadMangoAccount()
notify({
type: 'success',
title: 'Transaction successful',
txid: tx,
})
} catch (e: any) {
notify({
title: t('order-error'),
description: e.message,
txid: e.txid,
type: 'error',
})
console.error('Place trade error:', e)
}
}, [])
return (
<div>
<div className="grid select-none grid-cols-2 justify-between border-b border-th-bkg-3 text-base">
<div
onClick={() => setTradeType('Limit')}
className={`py-3 px-4 text-center text-sm hover:cursor-pointer ${
tradeForm.tradeType === 'Limit'
? 'bg-th-bkg-2 text-th-primary'
: 'text-th-fgd-4 hover:text-th-fgd-2'
}`}
>
Limit
</div>
<div
onClick={() => setTradeType('Market')}
className={`py-3 px-4 text-center text-sm hover:cursor-pointer ${
tradeForm.tradeType === 'Market'
? 'bg-th-bkg-2 text-th-primary'
: 'text-th-fgd-4 hover:text-th-fgd-2'
}`}
>
Market
</div>
</div>
<div className="mt-6 px-6">
<div
className={`relative mb-3 md:-mt-2.5 md:border-b md:border-th-bkg-3`}
>
<div
className={`absolute hidden md:block ${
tradeForm.side === 'buy'
? 'translate-x-0 bg-th-green'
: 'translate-x-full bg-th-red'
} default-transition bottom-[-1px] left-0 h-0.5 w-1/2 transform`}
/>
<nav className="-mb-px flex space-x-2" aria-label="Tabs">
<button
onClick={() => handleSetSide('buy')}
className={`default-transition relative flex w-1/2 cursor-pointer
items-center justify-center whitespace-nowrap py-1 text-sm font-semibold md:text-base md:hover:opacity-100
${
tradeForm.side === 'buy'
? `border border-th-green text-th-green md:border-0`
: `border border-th-fgd-4 text-th-fgd-4 md:border-0 md:hover:border-th-green md:hover:text-th-green`
}
`}
>
{t('buy')}
</button>
<button
onClick={() => handleSetSide('sell')}
className={`default-transition relative flex w-1/2 cursor-pointer
items-center justify-center whitespace-nowrap py-1 text-sm font-semibold md:text-base md:hover:opacity-100
${
tradeForm.side === 'sell'
? `border border-th-red text-th-red md:border-0`
: `border border-th-fgd-4 text-th-fgd-4 md:border-0 md:hover:border-th-red md:hover:text-th-red`
}
`}
>
{t('sell')}
</button>
</nav>
</div>
</div>
<div className="mt-6 px-4">
<div className="my-2 flex items-center justify-between">
<p className="text-xs text-th-fgd-3">{t('amount')}</p>
</div>
<div className="flex items-center rounded-md bg-th-bkg-2 p-2 text-lg font-bold text-th-fgd-1">
<NumberFormat
inputMode="decimal"
thousandSeparator=","
allowNegative={false}
isNumericString={true}
decimalScale={6}
name="amountIn"
id="amountIn"
className="w-full bg-th-bkg-2 text-right font-mono focus:outline-none"
placeholder="0.00"
value={tradeForm.baseSize}
onValueChange={handleBaseSizeChange}
/>
<div className="ml-2 text-sm text-th-fgd-4">{baseSymbol}</div>
</div>
<div className="my-2 flex items-center justify-between">
<p className="text-xs text-th-fgd-3">Limit Price</p>
</div>
<div className="flex items-center rounded-md bg-th-bkg-2 p-2 text-lg font-bold text-th-fgd-1">
<NumberFormat
inputMode="decimal"
thousandSeparator=","
allowNegative={false}
isNumericString={true}
decimalScale={6}
name="amountIn"
id="amountIn"
className="w-full bg-th-bkg-2 text-right font-mono focus:outline-none"
placeholder="0.00"
value={tradeForm.price}
onValueChange={handlePriceChange}
/>
<div className="ml-2 text-sm text-th-fgd-4">{quoteSymbol}</div>
</div>
</div>
<div className="mt-5 flex px-5">
{tradeForm.tradeType === 'Limit' ? (
<div className="flex">
<div className="mr-4 ">
<Tooltip
className="hidden md:block"
delay={250}
placement="left"
content={t('tooltip-post')}
>
<Checkbox
checked={tradeForm.postOnly}
onChange={(e) => handlePostOnlyChange(e.target.checked)}
>
Post
</Checkbox>
</Tooltip>
</div>
<div className="mr-4 ">
<Tooltip
className="hidden md:block"
delay={250}
placement="top"
content={t('tooltip-ioc')}
>
<div className="flex items-center text-xs text-th-fgd-3">
<Checkbox
checked={tradeForm.ioc}
onChange={(e) => handleIocChange(e.target.checked)}
>
IOC
</Checkbox>
</div>
</Tooltip>
</div>
</div>
) : null}
<div className="">
<Tooltip
delay={250}
placement="left"
content={t('tooltip-enable-margin')}
>
<Checkbox
checked={useMargin}
onChange={(e) => setUseMargin(e.target.checked)}
>
{t('margin')}
</Checkbox>
</Tooltip>
</div>
</div>
<div className="mt-5 flex px-4">
<Button
onClick={handlePlaceOrder}
className={`flex w-full items-center justify-center text-base ${
tradeForm.side === 'buy'
? 'bg-th-green-dark text-white'
: 'bg-th-red-dark text-th-fgd-1'
}`}
disabled={false}
size="medium"
>
<span className="capitalize">Place {tradeForm.side} Order</span>
</Button>
</div>
</div>
)
}
export default AdvancedTradeForm

View File

@ -0,0 +1,216 @@
import { Serum3Side } from '@blockworks-foundation/mango-v4'
import Button from '@components/shared/Button'
import SideBadge from '@components/shared/SideBadge'
import { QuestionMarkCircleIcon } from '@heroicons/react/20/solid'
import { Order } from '@project-serum/serum/lib/market'
import mangoStore from '@store/mangoStore'
import { useTranslation } from 'next-i18next'
import Image from 'next/image'
import { useCallback, useEffect, useMemo, useState } from 'react'
import { notify } from 'utils/notifications'
import { formatDecimal, formatFixedDecimals } from 'utils/numbers'
const TABS = ['Balances', 'Open Orders']
const BalanceAndOpenOrders = () => {
const [selectedTab, setSelectedTab] = useState('Open Orders')
const mangoAccount = mangoStore((s) => s.mangoAccount.current)
const openOrders = mangoStore((s) => s.mangoAccount.openOrders)
const selectedMarket = mangoStore((s) => s.selectedMarket.current)
useEffect(() => {
const actions = mangoStore.getState().actions
if (mangoAccount && selectedMarket) {
actions.fetchOpenOrdersForMarket(selectedMarket)
}
}, [mangoAccount, selectedMarket])
return (
<div className="h-full overflow-y-scroll">
<div className="sticky top-0 flex select-none border-b border-th-bkg-3 bg-th-bkg-1 text-th-fgd-3">
{TABS.map((tab) => {
return (
<div
key={tab}
onClick={() => setSelectedTab(tab)}
className={`border-r border-th-bkg-3 px-4 py-4 ${
selectedTab === tab
? 'bg-th-bkg-2 text-th-primary'
: 'hover:cursor-pointer hover:text-th-fgd-2'
}`}
>
{tab}
</div>
)
})}
</div>
{selectedTab === 'Balances' ? <Balances /> : null}
{selectedTab === 'Open Orders' ? <OpenOrders /> : null}
</div>
)
}
const Balances = () => {
const { t } = useTranslation('common')
const mangoAccount = mangoStore((s) => s.mangoAccount.current)
const group = mangoStore((s) => s.group)
const jupiterTokens = mangoStore((s) => s.jupiterTokens)
const banks = useMemo(() => {
if (group) {
const rawBanks = Array.from(group?.banksMapByName, ([key, value]) => ({
key,
value,
}))
const sortedBanks = mangoAccount
? rawBanks.sort(
(a, b) =>
Math.abs(
mangoAccount?.getTokenBalanceUi(b.value[0]) *
b.value[0].uiPrice!
) -
Math.abs(
mangoAccount?.getTokenBalanceUi(a.value[0]) *
a.value[0].uiPrice!
)
)
: rawBanks
return mangoAccount
? sortedBanks.filter(
(b) => mangoAccount?.getTokenBalanceUi(b.value[0]) !== 0
)
: sortedBanks
}
return []
}, [group, mangoAccount])
return (
<table className="min-w-full">
<thead>
<tr>
<th className="bg-th-bkg-1 text-left">{t('token')}</th>
<th className="bg-th-bkg-1 text-right">{t('balance')}</th>
<th className="bg-th-bkg-1 text-right">In Orders</th>
<th className="bg-th-bkg-1 text-right">Unsettled</th>
</tr>
</thead>
<tbody>
{banks.map(({ key, value }) => {
const bank = value[0]
const oraclePrice = bank.uiPrice
let logoURI
if (jupiterTokens.length) {
logoURI = jupiterTokens.find(
(t) => t.address === bank.mint.toString()
)!.logoURI
}
return (
<tr key={key} className="text-sm">
<td>
<div className="flex items-center">
<div className="mr-2.5 flex flex-shrink-0 items-center">
{logoURI ? (
<Image alt="" width="20" height="20" src={logoURI} />
) : (
<QuestionMarkCircleIcon className="h-7 w-7 text-th-fgd-3" />
)}
</div>
<span>{bank.name}</span>
</div>
</td>
<td className="pt-4 text-right font-mono text-sm">
<p>
{mangoAccount
? formatDecimal(
mangoAccount.getTokenBalanceUi(bank),
bank.mintDecimals
)
: 0}
</p>
</td>
<td className="text-right font-mono text-sm">0.00</td>
<td className="text-right font-mono text-sm">0.00</td>
</tr>
)
})}
</tbody>
</table>
)
}
const OpenOrders = () => {
const { t } = useTranslation('common')
const openOrders = mangoStore((s) => s.mangoAccount.openOrders)
const handleCancelOrder = useCallback(
async (o: Order) => {
const client = mangoStore.getState().client
const group = mangoStore.getState().group
const mangoAccount = mangoStore.getState().mangoAccount.current
const selectedMarket = mangoStore.getState().selectedMarket.current
if (!group || !mangoAccount) return
try {
const tx = await client.serum3CancelOrder(
group,
mangoAccount,
selectedMarket!.serumMarketExternal,
o.side === 'buy' ? Serum3Side.bid : Serum3Side.ask,
o.orderId
)
notify({
type: 'success',
title: 'Transaction successful',
txid: tx,
})
} catch (e: any) {
console.error('Error canceling', e)
notify({
title: t('order-error'),
description: e.message,
txid: e.txid,
type: 'error',
})
}
},
[t]
)
return (
<table>
<thead>
<tr className="">
<th className="text-right">Side</th>
<th className="text-right">Size</th>
<th className="text-right">Price</th>
<th className="text-right"></th>
</tr>
</thead>
<tbody>
{openOrders.map((o) => {
return (
<tr key={`${o.side}${o.size}${o.price}`} className="my-1 p-2">
<td className="text-right">
<SideBadge side={o.side} />
</td>
<td className="text-right">{o.size}</td>
<td className="text-right">{o.price}</td>
<td className="text-right">
<Button size="small" onClick={() => handleCancelOrder(o)}>
Cancel
</Button>
</td>
</tr>
)
})}
</tbody>
</table>
)
}
export default BalanceAndOpenOrders

View File

@ -0,0 +1,516 @@
import { AccountInfo } from '@solana/web3.js'
import Big from 'big.js'
import mangoStore from '@store/mangoStore'
import { useEffect, useMemo, useRef, useState } from 'react'
import { Market, Orderbook as SpotOrderBook } from '@project-serum/serum'
import useInterval from '@components/shared/useInterval'
import isEqualLodash from 'lodash/isEqual'
import usePrevious from '@components/shared/usePrevious'
import { PerpMarket } from '@blockworks-foundation/mango-v4/dist/types/src/accounts/perp'
import useLocalStorageState from 'hooks/useLocalStorageState'
import { floorToDecimal, formatDecimal, getDecimalCount } from 'utils/numbers'
import { ORDERBOOK_FLASH_KEY } from 'utils/constants'
import { useTranslation } from 'next-i18next'
import Decimal from 'decimal.js'
function decodeBookL2(
market: Market,
accInfo: AccountInfo<Buffer>
): number[][] {
if (market && accInfo?.data) {
const depth = 40
if (market instanceof Market) {
const book = SpotOrderBook.decode(market, accInfo.data)
return book.getL2(depth).map(([price, size]) => [price, size])
}
// else if (market instanceof PerpMarket) {
// // FIXME: Review the null being passed here
// const book = new BookSide(
// // @ts-ignore
// null,
// market,
// BookSideLayout.decode(accInfo.data),
// undefined,
// 100000
// )
// return book.getL2Ui(depth)
// }
}
return []
}
export function decodeBook(
market: Market,
accInfo: AccountInfo<Buffer>
): SpotOrderBook | undefined {
if (market && accInfo?.data) {
if (market instanceof Market) {
return SpotOrderBook.decode(market, accInfo.data)
}
// else if (market instanceof PerpMarket) {
// // FIXME: Review the null being passed here
// return new BookSide(
// // @ts-ignore
// null,
// market,
// BookSideLayout.decode(accInfo.data),
// undefined,
// 100000
// )
// }
}
}
type cumOrderbookSide = {
price: number
size: number
cumulativeSize: number
sizePercent: number
maxSizePercent: number
}
const getCumulativeOrderbookSide = (
orders: any[],
totalSize: number,
maxSize: number,
depth: number,
backwards = false
): cumOrderbookSide[] => {
let cumulative = orders
.slice(0, depth)
.reduce((cumulative, [price, size], i) => {
const cumulativeSize = (cumulative[i - 1]?.cumulativeSize || 0) + size
cumulative.push({
price,
size,
cumulativeSize,
sizePercent: Math.round((cumulativeSize / (totalSize || 1)) * 100),
maxSizePercent: Math.round((size / (maxSize || 1)) * 100),
})
return cumulative
}, [])
if (backwards) {
cumulative = cumulative.reverse()
}
return cumulative
}
const groupBy = (
ordersArray: number[][],
market: Market,
grouping: number,
isBids: boolean
) => {
if (!ordersArray || !market || !grouping || grouping == market?.tickSize) {
return ordersArray || []
}
const groupFloors: Record<number, number> = {}
for (let i = 0; i < ordersArray.length; i++) {
if (typeof ordersArray[i] == 'undefined') {
break
}
const bigGrouping = Big(grouping)
const bigOrder = Big(ordersArray[i][0])
const floor = isBids
? bigOrder
.div(bigGrouping)
.round(0, Big.roundDown)
.times(bigGrouping)
.toNumber()
: bigOrder
.div(bigGrouping)
.round(0, Big.roundUp)
.times(bigGrouping)
.toNumber()
if (typeof groupFloors[floor] == 'undefined') {
groupFloors[floor] = ordersArray[i][1]
} else {
groupFloors[floor] = ordersArray[i][1] + groupFloors[floor]
}
}
const sortedGroups = Object.entries(groupFloors)
.map((entry) => {
return [
+parseFloat(entry[0]).toFixed(getDecimalCount(grouping)),
entry[1],
]
})
.sort((a: number[], b: number[]) => {
if (!a || !b) {
return -1
}
return isBids ? b[0] - a[0] : a[0] - b[0]
})
return sortedGroups
}
const Orderbook = ({ depth = 12 }) => {
const { t } = useTranslation('common')
const selectedMarket = mangoStore((s) => s.selectedMarket.current)
const [openOrderPrices, setOpenOrderPrices] = useState<any[]>([])
const [orderbookData, setOrderbookData] = useState<any | null>(null)
const [defaultLayout, setDefaultLayout] = useState(true)
const [displayCumulativeSize, setDisplayCumulativeSize] = useState(false)
const [grouping, setGrouping] = useState(0.01)
const currentOrderbookData = useRef<any>(null)
const nextOrderbookData = useRef<any>(null)
const previousDepth = usePrevious(depth)
const previousGrouping = usePrevious(grouping)
const serum3MarketExternal = useMemo(() => {
const group = mangoStore.getState().group
if (!group || !selectedMarket) return
return group.serum3MarketExternalsMap.get(
selectedMarket.serumMarketExternal.toBase58()
)
}, [selectedMarket])
useEffect(() => {
if (serum3MarketExternal) {
setGrouping(serum3MarketExternal.tickSize)
}
}, [serum3MarketExternal])
useEffect(
() =>
mangoStore.subscribe(
(state) => [state.selectedMarket.orderbook],
(orderbook) => (nextOrderbookData.current = orderbook)
),
[]
)
useInterval(() => {
const orderbook = mangoStore.getState().selectedMarket.orderbook
const group = mangoStore.getState().group
if (!selectedMarket || !group) return
const serum3MarketExternal = group.serum3MarketExternalsMap.get(
selectedMarket.serumMarketExternal.toBase58()
)
if (
nextOrderbookData?.current &&
(!isEqualLodash(
currentOrderbookData.current,
nextOrderbookData.current
) ||
previousDepth !== depth ||
previousGrouping !== grouping)
) {
// check if user has open orders so we can highlight them on orderbook
// const openOrders = mangoStore.getState().mangoAccount.openOrders
// const newOpenOrderPrices = openOrders?.length
// ? openOrders
// .filter(({ market }) =>
// market.account.publicKey.equals(marketConfig.publicKey)
// )
// .map(({ order }) => order.price)
// : []
// if (!isEqualLodash(newOpenOrderPrices, openOrderPrices)) {
// setOpenOrderPrices(newOpenOrderPrices)
// }
// updated orderbook data
const bids =
groupBy(orderbook?.bids, serum3MarketExternal!, grouping, true) || []
const asks =
groupBy(orderbook?.asks, serum3MarketExternal!, grouping, false) || []
const sum = (total: number, [, size]: number[], index: number) =>
index < depth ? total + size : total
const totalSize = bids.reduce(sum, 0) + asks.reduce(sum, 0)
const maxSize =
Math.max(
...asks.map((a: number[]) => {
return a[1]
})
) +
Math.max(
...bids.map((b: number[]) => {
return b[1]
})
)
const bidsToDisplay = defaultLayout
? getCumulativeOrderbookSide(bids, totalSize, maxSize, depth, false)
: getCumulativeOrderbookSide(bids, totalSize, maxSize, depth / 2, false)
const asksToDisplay = defaultLayout
? getCumulativeOrderbookSide(asks, totalSize, maxSize, depth, false)
: getCumulativeOrderbookSide(
asks,
totalSize,
maxSize,
(depth + 1) / 2,
true
)
currentOrderbookData.current = {
bids: orderbook?.bids,
asks: orderbook?.asks,
}
if (bidsToDisplay[0] || asksToDisplay[0]) {
const bid = bidsToDisplay[0]?.price
const ask = defaultLayout
? asksToDisplay[0]?.price
: asksToDisplay[asksToDisplay.length - 1]?.price
let spread = 0,
spreadPercentage = 0
if (bid && ask) {
spread = ask - bid
spreadPercentage = (spread / ask) * 100
}
setOrderbookData({
bids: bidsToDisplay,
asks: asksToDisplay.reverse(),
spread,
spreadPercentage,
})
} else {
setOrderbookData(null)
}
}
}, 400)
useEffect(() => {
const connection = mangoStore.getState().connection
const group = mangoStore.getState().group
const set = mangoStore.getState().set
let previousBidInfo: AccountInfo<Buffer> | null = null
let previousAskInfo: AccountInfo<Buffer> | null = null
if (!serum3MarketExternal || !group) return
console.log('in orderbook WS useEffect')
const bidsPk = serum3MarketExternal['_decoded'].bids
const bidSubscriptionId = connection.onAccountChange(
bidsPk,
(info, context) => {
if (
!previousBidInfo ||
!previousBidInfo.data.equals(info.data) ||
previousBidInfo.lamports !== info.lamports
) {
previousBidInfo = info
// info['parsed'] = decodeBook(serum3MarketExternal, info)
set((state) => {
// state.accountInfos[bidsPk.toString()] = info
state.selectedMarket.orderbook.bids = decodeBookL2(
serum3MarketExternal,
info
)
})
}
}
)
const asksPk = serum3MarketExternal['_decoded'].asks
const askSubscriptionId = connection.onAccountChange(
asksPk,
(info, context) => {
if (
!previousAskInfo ||
!previousAskInfo.data.equals(info.data) ||
previousAskInfo.lamports !== info.lamports
) {
previousAskInfo = info
// info['parsed'] = decodeBook(serum3MarketExternal, info)
set((state) => {
// state.accountInfos[asksPk.toString()] = info
state.selectedMarket.orderbook.asks = decodeBookL2(
serum3MarketExternal,
info
)
})
}
}
)
return () => {
connection.removeAccountChangeListener(bidSubscriptionId)
connection.removeAccountChangeListener(askSubscriptionId)
}
}, [serum3MarketExternal])
if (!serum3MarketExternal) return null
return (
<div>
{orderbookData?.asks.map(
({
price,
size,
cumulativeSize,
sizePercent,
maxSizePercent,
}: cumOrderbookSide) => (
<OrderbookRow
market={serum3MarketExternal}
// hasOpenOrder={hasOpenOrderForPriceGroup(
// openOrderPrices,
// price,
// grouping
// )}
key={price + ''}
price={price}
size={displayCumulativeSize ? cumulativeSize : size}
side="sell"
sizePercent={displayCumulativeSize ? maxSizePercent : sizePercent}
grouping={grouping}
/>
)
)}
<div className="my-2 flex justify-between border-y border-th-bkg-2 py-2 px-4 text-xs">
<div className="text-th-fgd-3">{t('spread')}</div>
<div className="text-th-fgd-1">{orderbookData?.spread.toFixed(2)}</div>
<div className="text-th-fgd-1">
{orderbookData?.spreadPercentage.toFixed(2)}%
</div>
</div>
{orderbookData?.bids.map(
({
price,
size,
cumulativeSize,
sizePercent,
maxSizePercent,
}: cumOrderbookSide) => (
<OrderbookRow
market={serum3MarketExternal}
// hasOpenOrder={hasOpenOrderForPriceGroup(
// openOrderPrices,
// price,
// grouping
// )}
key={price + ''}
price={price}
size={displayCumulativeSize ? cumulativeSize : size}
side="buy"
sizePercent={displayCumulativeSize ? maxSizePercent : sizePercent}
grouping={grouping}
/>
)
)}
</div>
)
}
const OrderbookRow = ({
side,
price,
size,
sizePercent,
// invert,
// hasOpenOrder,
market,
grouping,
}: {
side: 'buy' | 'sell'
price: number
size: number
sizePercent: number
// hasOpenOrder: boolean
// invert: boolean
grouping: number
market: Market
}) => {
const element = useRef<HTMLDivElement>(null)
// const set = mangoStore.getState().set
const [showOrderbookFlash] = useLocalStorageState(ORDERBOOK_FLASH_KEY, true)
const flashClassName = side === 'sell' ? 'red-flash' : 'green-flash'
useEffect(() => {
showOrderbookFlash &&
!element.current?.classList.contains(`${flashClassName}`) &&
element.current?.classList.add(`${flashClassName}`)
const id = setTimeout(
() =>
element.current?.classList.contains(`${flashClassName}`) &&
element.current?.classList.remove(`${flashClassName}`),
250
)
return () => clearTimeout(id)
}, [price, size])
const formattedSize =
market!.minOrderSize && !isNaN(size)
? floorToDecimal(size, getDecimalCount(market.minOrderSize))
: new Decimal(size)
const formattedPrice =
market!.tickSize && !isNaN(price)
? floorToDecimal(price, getDecimalCount(market.tickSize))
: new Decimal(price)
// const handlePriceClick = () => {
// set((state) => {
// state.tradeForm.price = Number(formattedPrice)
// })
// }
// const handleSizeClick = () => {
// set((state) => {
// state.tradeForm.baseSize = Number(formattedSize)
// })
// }
const groupingDecimalCount = useMemo(
() => getDecimalCount(grouping),
[grouping]
)
const minOrderSizeDecimals = useMemo(
() => getDecimalCount(market.minOrderSize),
[market.minOrderSize]
)
if (!market) return null
return (
<div
className={`relative flex cursor-pointer justify-between border-b border-b-th-bkg-1 text-sm`}
ref={element}
>
<>
<div className="flex w-full items-center justify-between hover:bg-th-bkg-2">
<div
style={{ fontFeatureSettings: 'zero 1' }}
className={`z-10 text-right font-mono text-xs tabular-nums leading-5 md:ml-4 md:leading-6 ${
/*hasOpenOrder*/ false ? 'text-th-primary' : 'text-th-fgd-3'
}`}
// onClick={handleSizeClick}
>
{formattedSize.toFixed(minOrderSizeDecimals)}
</div>
<div
className={`z-10 font-mono text-xs tabular-nums leading-5 text-th-fgd-3 hover:normal-nums md:pr-4 md:leading-6`}
// onClick={handlePriceClick}
>
{formattedPrice.toFixed(groupingDecimalCount)}
</div>
</div>
<Line
className={`absolute right-0 opacity-90 ${
side === 'buy' ? `bg-th-green-muted` : `bg-th-red-muted`
}`}
data-width={sizePercent + '%'}
/>
</>
</div>
)
}
const Line = (props: any) => {
return (
<div
className={`${props.className}`}
style={{
textAlign: props.invert ? 'left' : 'right',
height: '100%',
width: `${props['data-width'] ? props['data-width'] : ''}`,
}}
/>
)
}
export default Orderbook

View File

@ -0,0 +1,157 @@
import { useCallback, useEffect, useMemo, useState } from 'react'
import { useTranslation } from 'next-i18next'
import dynamic from 'next/dynamic'
import ReactGridLayout, { Responsive, WidthProvider } from 'react-grid-layout'
import mangoStore from '@store/mangoStore'
import { GRID_LAYOUT_KEY } from 'utils/constants'
import useLocalStorageState from 'hooks/useLocalStorageState'
import { breakpoints } from 'utils/theme'
import { useViewport } from 'hooks/useViewport'
import Orderbook from './Orderbook'
import AdvancedMarketHeader from './AdvancedMarketHeader'
import AdvancedTradeForm from './AdvancedTradeForm'
import BalanceAndOpenOrders from './BalanceAndOpenOrders'
const ResponsiveGridLayout = WidthProvider(Responsive)
const TradingViewChart = dynamic(() => import('./TradingViewChart'), {
ssr: false,
})
const gridBreakpoints = {
// sm: breakpoints.sm,
// md: breakpoints.md,
// lg: breakpoints.lg,
xl: breakpoints.xl,
xxl: breakpoints['2xl'],
xxxl: breakpoints['3xl'],
}
const totalCols = 24
const TradeAdvancedPage = () => {
const { height } = useViewport()
const [currentBreakpoint, setCurrentBreakpoint] = useState<string>()
const [orderbookDepth, setOrderbookDepth] = useState(12)
const { uiLocked } = mangoStore((s) => s.settings)
const defaultLayouts: ReactGridLayout.Layouts = useMemo(() => {
const innerHeight = Math.max(height - 36, 800)
const tvChartHeight = 432
const headerHeight = 60
const balancesHeight = innerHeight - tvChartHeight - headerHeight
return {
xxxl: [
{ i: 'market-header', x: 0, y: 0, w: 16, h: headerHeight },
{ i: 'tv-chart', x: 0, y: 1, w: 16, h: tvChartHeight },
{ i: 'balances', x: 0, y: 2, w: 16, h: balancesHeight },
{ i: 'orderbook', x: 16, y: 1, w: 4, h: innerHeight },
{ i: 'trade-form', x: 20, y: 1, w: 4, h: innerHeight },
],
xxl: [
{ i: 'market-header', x: 0, y: 0, w: 14, h: headerHeight },
{ i: 'tv-chart', x: 0, y: 1, w: 14, h: tvChartHeight },
{ i: 'balances', x: 0, y: 2, w: 14, h: balancesHeight },
{ i: 'orderbook', x: 14, y: 1, w: 5, h: innerHeight },
{ i: 'trade-form', x: 20, y: 1, w: 5, h: innerHeight },
],
xl: [
{ i: 'market-header', x: 0, y: 0, w: 14, h: headerHeight },
{ i: 'tv-chart', x: 0, y: 1, w: 14, h: tvChartHeight },
{ i: 'balances', x: 0, y: 2, w: 14, h: balancesHeight },
{ i: 'orderbook', x: 14, y: 1, w: 5, h: innerHeight },
{ i: 'trade-form', x: 20, y: 1, w: 5, h: innerHeight },
],
}
}, [height])
const [savedLayouts, setSavedLayouts] = useLocalStorageState(
GRID_LAYOUT_KEY,
defaultLayouts
)
useEffect(() => {
const adjustOrderBook = (
layouts: ReactGridLayout.Layouts,
breakpoint?: string | null
) => {
const bp = 'xxl'
const orderbookLayout = layouts[bp].find((obj) => {
return obj.i === 'orderbook'
})
let depth = orderbookLayout!.h / 24 / 2 - 2
const maxNum = Math.max(1, depth)
if (typeof maxNum === 'number') {
depth = Math.round(maxNum)
}
setOrderbookDepth(depth)
}
adjustOrderBook(defaultLayouts, currentBreakpoint)
}, [currentBreakpoint, defaultLayouts])
const onLayoutChange = useCallback((layouts: ReactGridLayout.Layouts) => {
if (layouts) {
setSavedLayouts(layouts)
}
}, [])
const onBreakpointChange = useCallback((newBreakpoint: string) => {
setCurrentBreakpoint(newBreakpoint)
}, [])
return (
<div className="relative">
<ResponsiveGridLayout
// layouts={savedLayouts ? savedLayouts : defaultLayouts}
layouts={defaultLayouts}
breakpoints={gridBreakpoints}
cols={{
xxxl: totalCols,
xxl: totalCols,
xl: totalCols,
lg: totalCols,
md: totalCols,
sm: totalCols,
}}
rowHeight={1}
isDraggable={!uiLocked}
isResizable={!uiLocked}
onBreakpointChange={(newBreakpoint) =>
onBreakpointChange(newBreakpoint)
}
onLayoutChange={(layout, layouts) => onLayoutChange(layouts)}
measureBeforeMount
containerPadding={{ xxl: [0, 0] }}
margin={[0, 0]}
>
<div key="market-header" className="z-10">
<AdvancedMarketHeader />
</div>
<div key="tv-chart" className="h-full border border-th-bkg-3">
<div className={`relative h-full overflow-auto`}>
<TradingViewChart />
</div>
</div>
<div key="balances" className="h-full border border-th-bkg-3">
<BalanceAndOpenOrders />
</div>
<div key="orderbook" className="border border-th-bkg-3">
<div className="flex items-center justify-between px-4 py-2 text-xs text-th-fgd-4">
<div>Size</div>
<div>Price</div>
</div>
<div className="hide-scroll h-full overflow-y-scroll">
<Orderbook depth={orderbookDepth} />
</div>
</div>
<div key="trade-form" className="border border-th-bkg-3">
<AdvancedTradeForm />
</div>
</ResponsiveGridLayout>
</div>
)
}
export default TradeAdvancedPage

View File

@ -0,0 +1,189 @@
import { useEffect, useRef, useMemo, useState } from 'react'
import { useTheme } from 'next-themes'
import {
widget,
ChartingLibraryWidgetOptions,
IChartingLibraryWidget,
ResolutionString,
} from '@public/charting_library'
import mangoStore from '@store/mangoStore'
import { useWallet } from '@solana/wallet-adapter-react'
import { useViewport } from 'hooks/useViewport'
import { CHART_DATA_FEED, DEFAULT_MARKET_NAME } from 'utils/constants'
import { breakpoints } from 'utils/theme'
import { COLORS } from 'styles/colors'
export interface ChartContainerProps {
container: ChartingLibraryWidgetOptions['container']
symbol: ChartingLibraryWidgetOptions['symbol']
interval: ChartingLibraryWidgetOptions['interval']
datafeedUrl: string
libraryPath: ChartingLibraryWidgetOptions['library_path']
chartsStorageUrl: ChartingLibraryWidgetOptions['charts_storage_url']
chartsStorageApiVersion: ChartingLibraryWidgetOptions['charts_storage_api_version']
clientId: ChartingLibraryWidgetOptions['client_id']
userId: ChartingLibraryWidgetOptions['user_id']
fullscreen: ChartingLibraryWidgetOptions['fullscreen']
autosize: ChartingLibraryWidgetOptions['autosize']
studiesOverrides: ChartingLibraryWidgetOptions['studies_overrides']
theme: string
}
const TradingViewChart = () => {
const { theme } = useTheme()
const { width } = useViewport()
const { publicKey } = useWallet()
const [chartReady, setChartReady] = useState(false)
const selectedMarketName = mangoStore((s) => s.selectedMarket.current?.name)
const isMobile = width ? width < breakpoints.sm : false
// @ts-ignore
const defaultProps: ChartContainerProps = useMemo(
() => ({
symbol: DEFAULT_MARKET_NAME,
interval: '60' as ResolutionString,
theme: 'Dark',
container: 'tv_chart_container',
datafeedUrl: CHART_DATA_FEED,
libraryPath: '/charting_library/',
fullscreen: false,
autosize: true,
studiesOverrides: {
'volume.volume.color.0': theme === 'Mango' ? '#E54033' : '#CC2929',
'volume.volume.color.1': theme === 'Mango' ? '#AFD803' : '#5EBF4D',
'volume.precision': 4,
},
}),
[theme]
)
const tvWidgetRef = useRef<IChartingLibraryWidget | null>(null)
let chartStyleOverrides = {
'paneProperties.background': 'rgba(0,0,0,0)',
'paneProperties.backgroundType': 'solid',
'paneProperties.legendProperties.showBackground': false,
'paneProperties.vertGridProperties.color': 'rgba(0,0,0,0)',
'paneProperties.horzGridProperties.color': 'rgba(0,0,0,0)',
'paneProperties.legendProperties.showStudyTitles': false,
'scalesProperties.showStudyLastValue': false,
}
const mainSeriesProperties = [
'candleStyle',
'hollowCandleStyle',
'haStyle',
'barStyle',
]
mainSeriesProperties.forEach((prop) => {
chartStyleOverrides = {
...chartStyleOverrides,
[`mainSeriesProperties.${prop}.barColorsOnPrevClose`]: true,
[`mainSeriesProperties.${prop}.drawWick`]: true,
[`mainSeriesProperties.${prop}.drawBorder`]: true,
[`mainSeriesProperties.${prop}.upColor`]:
theme === 'Mango' ? '#AFD803' : '#5EBF4D',
[`mainSeriesProperties.${prop}.downColor`]:
theme === 'Mango' ? '#E54033' : '#CC2929',
[`mainSeriesProperties.${prop}.borderColor`]:
theme === 'Mango' ? '#AFD803' : '#5EBF4D',
[`mainSeriesProperties.${prop}.borderUpColor`]:
theme === 'Mango' ? '#AFD803' : '#5EBF4D',
[`mainSeriesProperties.${prop}.borderDownColor`]:
theme === 'Mango' ? '#E54033' : '#CC2929',
[`mainSeriesProperties.${prop}.wickUpColor`]:
theme === 'Mango' ? '#AFD803' : '#5EBF4D',
[`mainSeriesProperties.${prop}.wickDownColor`]:
theme === 'Mango' ? '#E54033' : '#CC2929',
}
})
useEffect(() => {
if (tvWidgetRef.current && chartReady && selectedMarketName) {
console.log('selectedMarketName', selectedMarketName)
console.log(
'tvWidgetRef.current?.activeChart()?.symbol()',
tvWidgetRef.current?.activeChart()?.symbol()
)
tvWidgetRef.current.setSymbol(
selectedMarketName!,
tvWidgetRef.current.activeChart().resolution(),
() => {}
)
}
}, [selectedMarketName, chartReady])
useEffect(() => {
if (window) {
const widgetOptions: ChartingLibraryWidgetOptions = {
// debug: true,
symbol: defaultProps.symbol,
// BEWARE: no trailing slash is expected in feed URL
// tslint:disable-next-line:no-any
datafeed: new (window as any).Datafeeds.UDFCompatibleDatafeed(
defaultProps.datafeedUrl
),
interval:
defaultProps.interval as ChartingLibraryWidgetOptions['interval'],
container:
defaultProps.container as ChartingLibraryWidgetOptions['container'],
library_path: defaultProps.libraryPath as string,
locale: 'en',
enabled_features: ['hide_left_toolbar_by_default'],
disabled_features: [
'use_localstorage_for_settings',
'timeframes_toolbar',
isMobile ? 'left_toolbar' : '',
'show_logo_on_all_charts',
'caption_buttons_text_if_possible',
'header_settings',
// 'header_chart_type',
'header_compare',
'compare_symbol',
'header_screenshot',
// 'header_widget_dom_node',
// 'header_widget',
!publicKey ? 'header_saveload' : '',
'header_undo_redo',
'header_interval_dialog_button',
'show_interval_dialog_on_key_press',
'header_symbol_search',
],
fullscreen: defaultProps.fullscreen,
autosize: defaultProps.autosize,
studies_overrides: defaultProps.studiesOverrides,
theme: theme === 'Light' ? 'Light' : 'Dark',
custom_css_url: '/styles/tradingview.css',
loading_screen: {
backgroundColor:
theme === 'Dark'
? COLORS.BKG1.Dark
: theme === 'Light'
? COLORS.BKG1.Light
: COLORS.BKG1.Mango,
},
overrides: {
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
...chartStyleOverrides,
},
}
const tvWidget = new widget(widgetOptions)
tvWidgetRef.current = tvWidget
tvWidgetRef.current.onChartReady(function () {
setChartReady(true)
})
//eslint-disable-next-line
}
}, [theme, isMobile, publicKey, defaultProps])
return (
<div id={defaultProps.container as string} className="tradingview-chart" />
)
}
export default TradingViewChart

View File

@ -5,7 +5,7 @@ import { useTranslation } from 'next-i18next'
// import AccountsModal from './AccountsModal'
import uniqBy from 'lodash/uniqBy'
import WalletSelect from './WalletSelect'
import mangoStore from '../../store/mangoStore'
import mangoStore from '@store/mangoStore'
import { Wallet as AnchorWallet } from '@project-serum/anchor'
import { notify } from '../../utils/notifications'
import Loading from '../shared/Loading'
@ -100,7 +100,7 @@ export const ConnectWalletButton: React.FC = () => {
disabled={!group}
className={` text-white focus:outline-none disabled:cursor-wait disabled:opacity-25`}
>
<div className="relative flex h-16 w-44 bg-gradient-to-bl from-mango-theme-yellow to-mango-theme-red-dark before:absolute before:inset-0 before:bg-gradient-to-r before:from-transparent before:via-[rgba(255,255,255,0.25)] before:to-transparent before:opacity-0 hover:overflow-hidden hover:before:-translate-x-full hover:before:animate-[shimmer_0.75s_normal] hover:before:opacity-100">
<div className="relative flex w-44 rounded bg-gradient-to-bl from-mango-theme-yellow to-mango-theme-red-dark py-2 before:absolute before:inset-0 before:bg-gradient-to-r before:from-transparent before:via-[rgba(255,255,255,0.25)] before:to-transparent before:opacity-0 hover:overflow-hidden hover:before:-translate-x-full hover:before:animate-[shimmer_0.75s_normal] hover:before:opacity-100">
<div className="default-transition flex h-full flex-row items-center justify-center space-x-3 px-4">
<div
className={`flex h-[28px] w-[28px] items-center justify-center rounded-full ${
@ -118,7 +118,7 @@ export const ConnectWalletButton: React.FC = () => {
/>
</div>
<div className="text-left">
<div className="mb-1.5 flex justify-center text-base font-bold leading-none">
<div className="mb-0.5 flex justify-center text-base font-bold leading-none">
{connecting ? <Loading className="h-4 w-4" /> : t('connect')}
</div>
{wallet?.adapter?.name && (

View File

@ -3,7 +3,7 @@ import { ArrowRightOnRectangleIcon } from '@heroicons/react/20/solid'
import { useWallet } from '@solana/wallet-adapter-react'
import { useTranslation } from 'next-i18next'
import { Fragment, useCallback, useState } from 'react'
import mangoStore from '../../store/mangoStore'
import mangoStore from '@store/mangoStore'
import { notify } from '../../utils/notifications'
import ProfileImage from '../shared/ProfileImage'
import { abbreviateAddress } from '../../utils/formatting'

View File

@ -2,7 +2,7 @@ import React, { Fragment } from 'react'
import { useWallet } from '@solana/wallet-adapter-react'
import { ChevronDownIcon } from '@heroicons/react/20/solid'
import { Menu, Transition } from '@headlessui/react'
import mangoStore from '../../store/mangoStore'
import mangoStore from '@store/mangoStore'
const WalletSelect = () => {
const { wallets, select } = useWallet()
@ -13,7 +13,7 @@ const WalletSelect = () => {
{({ open }) => (
<>
<Menu.Button
className={`flex h-full w-14 cursor-pointer items-center justify-center rounded-none bg-transparent text-white hover:brightness-[1.1] focus:outline-none disabled:opacity-25`}
className={`flex h-full w-12 cursor-pointer items-center justify-center rounded-none bg-transparent text-white hover:brightness-[1.1] focus:outline-none disabled:opacity-25`}
disabled={!group}
>
<ChevronDownIcon

View File

@ -1,6 +1,7 @@
import {
createContext,
ReactNode,
useCallback,
useContext,
useEffect,
useState,
@ -8,6 +9,7 @@ import {
type ViewportContextProps = {
width: number
height: number
}
const ViewportContext = createContext({} as ViewportContextProps)
@ -15,30 +17,32 @@ const ViewportContext = createContext({} as ViewportContextProps)
export const ViewportProvider = ({ children }: { children: ReactNode }) => {
const [mounted, setMounted] = useState(false)
const [width, setWidth] = useState<number>(0)
const [height, setHeight] = useState<number>(0)
const handleWindowResize = () => {
const handleWindowResize = useCallback(() => {
if (typeof window !== 'undefined') {
setWidth(window.innerWidth)
setHeight(window.innerHeight)
}
}
}, [])
useEffect(() => {
handleWindowResize()
window.addEventListener('resize', handleWindowResize)
return () => window.removeEventListener('resize', handleWindowResize)
}, [])
}, [handleWindowResize])
useEffect(() => setMounted(true), [])
if (!mounted) return null
return (
<ViewportContext.Provider value={{ width }}>
<ViewportContext.Provider value={{ width, height }}>
{children}
</ViewportContext.Provider>
)
}
export const useViewport = () => {
const { width } = useContext(ViewportContext)
return { width }
const { width, height } = useContext(ViewportContext)
return { width, height }
}

View File

@ -8,7 +8,8 @@
"start": "next start",
"lint": "next lint",
"typecheck": "tsc",
"prepare": "husky install"
"prepare": "husky install",
"postinstall": "tar -xzC public -f vendor/charting_library.tgz;tar -xzC public -f vendor/datafeeds.tgz"
},
"dependencies": {
"@blockworks-foundation/mango-v4": "git+https://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:x-oauth-basic@github.com/blockworks-foundation/mango-v4.git#main",
@ -22,10 +23,12 @@
"@solflare-wallet/pfp": "^0.0.6",
"@tippyjs/react": "^4.2.6",
"assert": "^2.0.0",
"big.js": "^6.2.1",
"dayjs": "^1.11.3",
"decimal.js": "^10.4.0",
"immer": "^9.0.12",
"jsbi": "^4.3.0",
"lodash": "^4.17.21",
"lodash.debounce": "^4.0.8",
"next": "12.2.2",
"next-i18next": "^11.1.1",
@ -34,6 +37,7 @@
"react": "18.0.0",
"react-dom": "18.0.0",
"react-flip-numbers": "^3.0.5",
"react-grid-layout": "^1.3.4",
"react-number-format": "^4.9.2",
"react-tsparticles": "^2.2.4",
"react-window": "^1.8.7",
@ -49,6 +53,7 @@
"@types/node": "17.0.23",
"@types/react": "18.0.3",
"@types/react-dom": "18.0.0",
"@types/react-grid-layout": "^1.3.2",
"@types/react-window": "^1.8.5",
"autoprefixer": "^10.4.4",
"eslint": "^8.13.0",
@ -60,7 +65,7 @@
"postcss": "^8.4.12",
"prettier": "^2.6.2",
"prettier-plugin-tailwindcss": "^0.1.8",
"tailwindcss": "^3.0.24",
"tailwindcss": "^3.1.8",
"typescript": "4.6.3"
}
}

View File

@ -10,7 +10,7 @@ import {
import { clusterApiUrl } from '@solana/web3.js'
import '../styles/globals.css'
import mangoStore from '../store/mangoStore'
import mangoStore from '@store/mangoStore'
import useInterval from '../components/shared/useInterval'
import Notifications from '../components/shared/Notification'
import { ThemeProvider } from 'next-themes'
@ -19,7 +19,7 @@ import Layout from '../components/Layout'
import { ViewportProvider } from '../hooks/useViewport'
import { WalletProvider } from '../components/wallet/WalletProvider'
const hydrateStore = async () => {
const rehydrateStore = async () => {
const actions = mangoStore.getState().actions
actions.fetchGroup()
const mangoAccount = mangoStore.getState().mangoAccount.current
@ -30,7 +30,7 @@ const hydrateStore = async () => {
const HydrateStore = () => {
useInterval(() => {
hydrateStore()
rehydrateStore()
}, 5000)
useEffect(() => {
@ -38,6 +38,7 @@ const HydrateStore = () => {
actions.fetchGroup().then(() => {
actions.fetchJupiterTokens()
})
actions.fetchCoingeckoPrices()
}, [])
return null

View File

@ -1,4 +1,5 @@
import Document, { Html, Head, Main, NextScript } from 'next/document'
import Script from 'next/script'
class MyDocument extends Document {
render() {
@ -9,8 +10,16 @@ class MyDocument extends Document {
href="https://fonts.googleapis.com/css2?family=Lato:wght@200;300;400;500;600;700&display=swap"
rel="stylesheet"
/>
<link
href="https://fonts.googleapis.com/css?family=Roboto Mono&display=swap"
rel="stylesheet"
></link>
<Script
src="/datafeeds/udf/dist/bundle.js"
strategy="beforeInteractive"
></Script>
</Head>
<body>
<body className="overflow-hidden bg-th-bkg-1">
<Main />
<NextScript />
</body>

View File

@ -15,7 +15,11 @@ export async function getStaticProps({ locale }: { locale: string }) {
}
const Index: NextPage = () => {
return <AccountPage />
return (
<div className="p-8 pb-20 md:p-12">
<AccountPage />
</div>
)
}
export default Index

View File

@ -47,30 +47,32 @@ const Settings: NextPage = () => {
}
return (
<div className="grid grid-cols-12">
<div className="col-span-12 border-b border-th-bkg-3 lg:col-span-8 lg:col-start-3">
<h1 className="mb-4">{t('settings')}</h1>
<div className="flex flex-col border-t border-th-bkg-3 p-4 md:flex-row md:items-center md:justify-between">
<p className="mb-2 lg:mb-0">{t('theme')}</p>
<div className="w-full min-w-[220px] md:w-auto">
<ButtonGroup
activeValue={theme}
onChange={(t) => setTheme(t)}
values={THEMES}
large
/>
<div className="p-8 pb-20 md:p-12">
<div className="grid grid-cols-12">
<div className="col-span-12 border-b border-th-bkg-3 lg:col-span-8 lg:col-start-3">
<h1 className="mb-4">{t('settings')}</h1>
<div className="flex flex-col border-t border-th-bkg-3 p-4 md:flex-row md:items-center md:justify-between">
<p className="mb-2 lg:mb-0">{t('theme')}</p>
<div className="w-full min-w-[220px] md:w-auto">
<ButtonGroup
activeValue={theme}
onChange={(t) => setTheme(t)}
values={THEMES}
large
/>
</div>
</div>
</div>
<div className="flex flex-col border-t border-th-bkg-3 p-4 md:flex-row md:items-center md:justify-between">
<p className="mb-2 lg:mb-0">{t('language')}</p>
<div className="w-full min-w-[330px] md:w-auto">
<ButtonGroup
activeValue={savedLanguage}
onChange={(l) => handleLangChange(l)}
values={LANGS.map((val) => val.locale)}
names={LANGS.map((val) => t(val.name))}
large
/>
<div className="flex flex-col border-t border-th-bkg-3 p-4 md:flex-row md:items-center md:justify-between">
<p className="mb-2 lg:mb-0">{t('language')}</p>
<div className="w-full min-w-[330px] md:w-auto">
<ButtonGroup
activeValue={savedLanguage}
onChange={(l) => handleLangChange(l)}
values={LANGS.map((val) => val.locale)}
names={LANGS.map((val) => t(val.name))}
large
/>
</div>
</div>
</div>
</div>

View File

@ -18,10 +18,12 @@ const Stats: NextPage = () => {
const { pathname, asPath, query } = router
return (
<div className="grid grid-cols-12">
<div className="col-span-12">
<h1 className="mb-4">{t('stats')}</h1>
<TokenStats />
<div className="p-8 pb-20 md:p-12">
<div className="grid grid-cols-12">
<div className="col-span-12">
<h1 className="mb-4">{t('stats')}</h1>
<TokenStats />
</div>
</div>
</div>
)

21
pages/swap.tsx Normal file
View File

@ -0,0 +1,21 @@
import type { NextPage } from 'next'
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
import TradeSimplePage from '../components/swap/TradeSimplePage'
export async function getStaticProps({ locale }: { locale: string }) {
return {
props: {
...(await serverSideTranslations(locale, ['common', 'trade'])),
},
}
}
const Trade: NextPage = () => {
return (
<div className="p-8 pb-20 md:p-12">
<TradeSimplePage />
</div>
)
}
export default Trade

View File

@ -1,6 +1,6 @@
import TradeAdvancedPage from '@components/trade/TradeAdvancedPage'
import type { NextPage } from 'next'
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
import TradeSimplePage from '../components/swap/TradeSimplePage'
export async function getStaticProps({ locale }: { locale: string }) {
return {
@ -11,7 +11,7 @@ export async function getStaticProps({ locale }: { locale: string }) {
}
const Trade: NextPage = () => {
return <TradeSimplePage />
return <TradeAdvancedPage />
}
export default Trade

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,3 @@
"use strict";(self.webpackChunktradingview=self.webpackChunktradingview||[]).push([[1529],{1529:(t,e,n)=>{n.r(e),n.d(e,{default:()=>M});var r=function(){if("undefined"!=typeof Map)return Map;function t(t,e){var n=-1;return t.some((function(t,r){return t[0]===e&&(n=r,!0)})),n}return function(){function e(){this.__entries__=[]}return Object.defineProperty(e.prototype,"size",{get:function(){return this.__entries__.length},enumerable:!0,configurable:!0}),e.prototype.get=function(e){var n=t(this.__entries__,e),r=this.__entries__[n];return r&&r[1]},e.prototype.set=function(e,n){var r=t(this.__entries__,e);~r?this.__entries__[r][1]=n:this.__entries__.push([e,n])},e.prototype.delete=function(e){var n=this.__entries__,r=t(n,e);~r&&n.splice(r,1)},e.prototype.has=function(e){return!!~t(this.__entries__,e)},e.prototype.clear=function(){this.__entries__.splice(0)},e.prototype.forEach=function(t,e){void 0===e&&(e=null);for(var n=0,r=this.__entries__;n<r.length;n++){var i=r[n];t.call(e,i[1],i[0])}},e}()}(),i="undefined"!=typeof window&&"undefined"!=typeof document&&window.document===document,o=void 0!==n.g&&n.g.Math===Math?n.g:"undefined"!=typeof self&&self.Math===Math?self:"undefined"!=typeof window&&window.Math===Math?window:Function("return this")(),s="function"==typeof requestAnimationFrame?requestAnimationFrame.bind(o):function(t){return setTimeout((function(){return t(Date.now())}),1e3/60)};var c=["top","right","bottom","left","width","height","size","weight"],a="undefined"!=typeof MutationObserver,h=function(){function t(){this.connected_=!1,this.mutationEventsAdded_=!1,this.mutationsObserver_=null,this.observers_=[],this.onTransitionEnd_=this.onTransitionEnd_.bind(this),this.refresh=function(t,e){var n=!1,r=!1,i=0;function o(){n&&(n=!1,t()),r&&a()}function c(){s(o)}function a(){var t=Date.now();if(n){if(t-i<2)return;r=!0}else n=!0,r=!1,setTimeout(c,e);i=t}return a}(this.refresh.bind(this),20)}return t.prototype.addObserver=function(t){~this.observers_.indexOf(t)||this.observers_.push(t),this.connected_||this.connect_()},t.prototype.removeObserver=function(t){var e=this.observers_,n=e.indexOf(t);~n&&e.splice(n,1),!e.length&&this.connected_&&this.disconnect_()},t.prototype.refresh=function(){this.updateObservers_()&&this.refresh()},t.prototype.updateObservers_=function(){var t=this.observers_.filter((function(t){return t.gatherActive(),t.hasActive()}));return t.forEach((function(t){return t.broadcastActive()})),t.length>0},t.prototype.connect_=function(){i&&!this.connected_&&(document.addEventListener("transitionend",this.onTransitionEnd_),window.addEventListener("resize",this.refresh),a?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener("DOMSubtreeModified",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},t.prototype.disconnect_=function(){i&&this.connected_&&(document.removeEventListener("transitionend",this.onTransitionEnd_),
window.removeEventListener("resize",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener("DOMSubtreeModified",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},t.prototype.onTransitionEnd_=function(t){var e=t.propertyName,n=void 0===e?"":e;c.some((function(t){return!!~n.indexOf(t)}))&&this.refresh()},t.getInstance=function(){return this.instance_||(this.instance_=new t),this.instance_},t.instance_=null,t}(),u=function(t,e){for(var n=0,r=Object.keys(e);n<r.length;n++){var i=r[n];Object.defineProperty(t,i,{value:e[i],enumerable:!1,writable:!1,configurable:!0})}return t},f=function(t){return t&&t.ownerDocument&&t.ownerDocument.defaultView||o},d=m(0,0,0,0);function p(t){return parseFloat(t)||0}function v(t){for(var e=[],n=1;n<arguments.length;n++)e[n-1]=arguments[n];return e.reduce((function(e,n){return e+p(t["border-"+n+"-width"])}),0)}function _(t){var e=t.clientWidth,n=t.clientHeight;if(!e&&!n)return d;var r=f(t).getComputedStyle(t),i=function(t){for(var e={},n=0,r=["top","right","bottom","left"];n<r.length;n++){var i=r[n],o=t["padding-"+i];e[i]=p(o)}return e}(r),o=i.left+i.right,s=i.top+i.bottom,c=p(r.width),a=p(r.height);if("border-box"===r.boxSizing&&(Math.round(c+o)!==e&&(c-=v(r,"left","right")+o),Math.round(a+s)!==n&&(a-=v(r,"top","bottom")+s)),!function(t){return t===f(t).document.documentElement}(t)){var h=Math.round(c+o)-e,u=Math.round(a+s)-n;1!==Math.abs(h)&&(c-=h),1!==Math.abs(u)&&(a-=u)}return m(i.left,i.top,c,a)}var l="undefined"!=typeof SVGGraphicsElement?function(t){return t instanceof f(t).SVGGraphicsElement}:function(t){return t instanceof f(t).SVGElement&&"function"==typeof t.getBBox};function b(t){return i?l(t)?function(t){var e=t.getBBox();return m(0,0,e.width,e.height)}(t):_(t):d}function m(t,e,n,r){return{x:t,y:e,width:n,height:r}}var y=function(){function t(t){this.broadcastWidth=0,this.broadcastHeight=0,this.contentRect_=m(0,0,0,0),this.target=t}return t.prototype.isActive=function(){var t=b(this.target);return this.contentRect_=t,t.width!==this.broadcastWidth||t.height!==this.broadcastHeight},t.prototype.broadcastRect=function(){var t=this.contentRect_;return this.broadcastWidth=t.width,this.broadcastHeight=t.height,t},t}(),w=function(t,e){var n,r,i,o,s,c,a,h=(r=(n=e).x,i=n.y,o=n.width,s=n.height,c="undefined"!=typeof DOMRectReadOnly?DOMRectReadOnly:Object,a=Object.create(c.prototype),u(a,{x:r,y:i,width:o,height:s,top:i,right:r+o,bottom:s+i,left:r}),a);u(this,{target:t,contentRect:h})},g=function(){function t(t,e,n){if(this.activeObservations_=[],this.observations_=new r,"function"!=typeof t)throw new TypeError("The callback provided as parameter 1 is not a function.");this.callback_=t,this.controller_=e,this.callbackCtx_=n}return t.prototype.observe=function(t){if(!arguments.length)throw new TypeError("1 argument required, but only 0 present.");if("undefined"!=typeof Element&&Element instanceof Object){
if(!(t instanceof f(t).Element))throw new TypeError('parameter 1 is not of type "Element".');var e=this.observations_;e.has(t)||(e.set(t,new y(t)),this.controller_.addObserver(this),this.controller_.refresh())}},t.prototype.unobserve=function(t){if(!arguments.length)throw new TypeError("1 argument required, but only 0 present.");if("undefined"!=typeof Element&&Element instanceof Object){if(!(t instanceof f(t).Element))throw new TypeError('parameter 1 is not of type "Element".');var e=this.observations_;e.has(t)&&(e.delete(t),e.size||this.controller_.removeObserver(this))}},t.prototype.disconnect=function(){this.clearActive(),this.observations_.clear(),this.controller_.removeObserver(this)},t.prototype.gatherActive=function(){var t=this;this.clearActive(),this.observations_.forEach((function(e){e.isActive()&&t.activeObservations_.push(e)}))},t.prototype.broadcastActive=function(){if(this.hasActive()){var t=this.callbackCtx_,e=this.activeObservations_.map((function(t){return new w(t.target,t.broadcastRect())}));this.callback_.call(t,e,t),this.clearActive()}},t.prototype.clearActive=function(){this.activeObservations_.splice(0)},t.prototype.hasActive=function(){return this.activeObservations_.length>0},t}(),E="undefined"!=typeof WeakMap?new WeakMap:new r,O=function t(e){if(!(this instanceof t))throw new TypeError("Cannot call a class as a function.");if(!arguments.length)throw new TypeError("1 argument required, but only 0 present.");var n=h.getInstance(),r=new g(e,n,this);E.set(this,r)};["observe","unobserve","disconnect"].forEach((function(t){O.prototype[t]=function(){var e;return(e=E.get(this))[t].apply(e,arguments)}}));const M=void 0!==o.ResizeObserver?o.ResizeObserver:O}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
.tabs-3I2ohC86{display:flex;position:relative;width:100%}.tab-3I2ohC86{border-bottom:1px solid;border-color:#e0e3eb;color:var(--tv-tabs-slider-text-color,#131722);flex:1 1;padding:13px 0;text-align:center;transition:color .35s ease;-webkit-user-select:none;user-select:none}html.theme-dark .tab-3I2ohC86{border-color:#434651;color:var(--tv-tabs-slider-text-color,#d1d4dc)}.tab-3I2ohC86.noBorder-3I2ohC86{border-bottom:0}.tab-3I2ohC86.disabled-3I2ohC86{color:#eceff2}.tab-3I2ohC86.active-3I2ohC86,html.theme-dark .tab-3I2ohC86.active-3I2ohC86{color:#2962ff}.defaultCursor-3I2ohC86{cursor:default}.slider-3I2ohC86{bottom:0;height:3px;left:0;position:absolute;transition-timing-function:cubic-bezier(.215,.61,.355,1)}.slider-3I2ohC86,html.theme-dark .slider-3I2ohC86{background-color:#2962ff}.content-3I2ohC86{width:100%}

View File

@ -0,0 +1 @@
.tabs-3I2ohC86{display:flex;position:relative;width:100%}.tab-3I2ohC86{border-bottom:1px solid;border-color:#e0e3eb;color:var(--tv-tabs-slider-text-color,#131722);flex:1 1;padding:13px 0;text-align:center;transition:color .35s ease;-webkit-user-select:none;user-select:none}html.theme-dark .tab-3I2ohC86{border-color:#434651;color:var(--tv-tabs-slider-text-color,#d1d4dc)}.tab-3I2ohC86.noBorder-3I2ohC86{border-bottom:0}.tab-3I2ohC86.disabled-3I2ohC86{color:#eceff2}.tab-3I2ohC86.active-3I2ohC86,html.theme-dark .tab-3I2ohC86.active-3I2ohC86{color:#2962ff}.defaultCursor-3I2ohC86{cursor:default}.slider-3I2ohC86{bottom:0;height:3px;left:0;position:absolute;transition-timing-function:cubic-bezier(.215,.61,.355,1)}.slider-3I2ohC86,html.theme-dark .slider-3I2ohC86{background-color:#2962ff}.content-3I2ohC86{width:100%}

View File

@ -0,0 +1,3 @@
(self.webpackChunktradingview=self.webpackChunktradingview||[]).push([[1829],{40266:e=>{e.exports={container:"container-QDd7xRJ1","intent-default":"intent-default-QDd7xRJ1",focused:"focused-QDd7xRJ1",readonly:"readonly-QDd7xRJ1",disabled:"disabled-QDd7xRJ1","with-highlight":"with-highlight-QDd7xRJ1",grouped:"grouped-QDd7xRJ1","adjust-position":"adjust-position-QDd7xRJ1","first-row":"first-row-QDd7xRJ1","first-col":"first-col-QDd7xRJ1",stretch:"stretch-QDd7xRJ1","font-size-medium":"font-size-medium-QDd7xRJ1","font-size-large":"font-size-large-QDd7xRJ1","size-small":"size-small-QDd7xRJ1","size-medium":"size-medium-QDd7xRJ1","size-large":"size-large-QDd7xRJ1","intent-success":"intent-success-QDd7xRJ1","intent-warning":"intent-warning-QDd7xRJ1","intent-danger":"intent-danger-QDd7xRJ1","intent-primary":"intent-primary-QDd7xRJ1","border-none":"border-none-QDd7xRJ1","border-thin":"border-thin-QDd7xRJ1","border-thick":"border-thick-QDd7xRJ1","no-corner-top-left":"no-corner-top-left-QDd7xRJ1","no-corner-top-right":"no-corner-top-right-QDd7xRJ1","no-corner-bottom-right":"no-corner-bottom-right-QDd7xRJ1","no-corner-bottom-left":"no-corner-bottom-left-QDd7xRJ1",highlight:"highlight-QDd7xRJ1",shown:"shown-QDd7xRJ1"}},16321:e=>{e.exports={"inner-slot":"inner-slot-1cMNQxXi",interactive:"interactive-1cMNQxXi",icon:"icon-1cMNQxXi","inner-middle-slot":"inner-middle-slot-1cMNQxXi","before-slot":"before-slot-1cMNQxXi","after-slot":"after-slot-1cMNQxXi"}},93463:e=>{e.exports={input:"input-saRppuvn","with-start-slot":"with-start-slot-saRppuvn","with-end-slot":"with-end-slot-saRppuvn"}},94618:(e,t,n)=>{"use strict";n.d(t,{ControlGroupContext:()=>o});const o=n(67294).createContext({isGrouped:!1,cellState:{isTop:!0,isRight:!0,isBottom:!0,isLeft:!0}})},48413:(e,t,n)=>{"use strict";function o(e){let t=0;return e.isTop&&e.isLeft||(t+=1),e.isTop&&e.isRight||(t+=2),e.isBottom&&e.isLeft||(t+=8),e.isBottom&&e.isRight||(t+=4),t}n.d(t,{getGroupCellRemoveRoundBorders:()=>o})},11888:(e,t,n)=>{"use strict";n.d(t,{ControlSkeleton:()=>x,InputClasses:()=>m});var o=n(67294),r=n(94184),s=n(16282),i=n(66364),l=n(74818),u=n(94618),a=n(48413);var c=n(40266),d=n.n(c);function f(e){let t="";return 0!==e&&(1&e&&(t=r(t,d()["no-corner-top-left"])),2&e&&(t=r(t,d()["no-corner-top-right"])),4&e&&(t=r(t,d()["no-corner-bottom-right"])),8&e&&(t=r(t,d()["no-corner-bottom-left"]))),t}function h(e,t,n,o){const{removeRoundBorder:s,className:i,intent:l="default",borderStyle:u="thin",size:c,highlight:h,disabled:p,readonly:m,stretch:g,noReadonlyStyles:R,isFocused:x}=e,b=f(null!=s?s:(0,a.getGroupCellRemoveRoundBorders)(n));return r(d().container,d()["intent-"+l],d()["border-"+u],c&&d()["size-"+c],b,h&&d()["with-highlight"],p&&d().disabled,m&&!R&&d().readonly,x&&d().focused,g&&d().stretch,t&&d().grouped,!o&&d()["adjust-position"],n.isTop&&d()["first-row"],n.isLeft&&d()["first-col"],i)}function p(e,t){const{highlight:n,highlightRemoveRoundBorder:o}=e;if(!n)return d().highlight;const s=f(null!=o?o:(0,a.getGroupCellRemoveRoundBorders)(t));return r(d().highlight,d().shown,s)}const m={
FontSizeMedium:(0,s.ensureDefined)(d()["font-size-medium"]),FontSizeLarge:(0,s.ensureDefined)(d()["font-size-large"])},g={passive:!1};function R(e,t){const{id:n,role:r,onFocus:s,onBlur:a,onMouseOver:c,onMouseOut:d,onMouseDown:f,onMouseUp:m,onKeyDown:R,onClick:x,tabIndex:b,startSlot:D,middleSlot:v,endSlot:C,onWheel:M,onWheelNoPassive:w=null}=e,{isGrouped:Q,cellState:S,disablePositionAdjustment:J=!1}=(0,o.useContext)(u.ControlGroupContext),y=function(e,t=null,n){const r=(0,o.useRef)(null),s=(0,o.useRef)(null),i=(0,o.useCallback)(()=>{if(null===r.current||null===s.current)return;const[e,t,n]=s.current;null!==t&&r.current.addEventListener(e,t,n)},[]),l=(0,o.useCallback)(()=>{if(null===r.current||null===s.current)return;const[e,t,n]=s.current;null!==t&&r.current.removeEventListener(e,t,n)},[]),u=(0,o.useCallback)(e=>{l(),r.current=e,i()},[]);return(0,o.useEffect)(()=>(s.current=[e,t,n],i(),l),[e,t,n]),u}("wheel",w,g);return o.createElement("span",{id:n,role:r,className:h(e,Q,S,J),tabIndex:b,ref:(0,i.useMergedRefs)([t,y]),onFocus:s,onBlur:a,onMouseOver:c,onMouseOut:d,onMouseDown:f,onMouseUp:m,onKeyDown:R,onClick:x,onWheel:M,...(0,l.filterDataProps)(e),...(0,l.filterAriaProps)(e)},D,v,C,o.createElement("span",{className:p(e,S)}))}R.displayName="ControlSkeleton";const x=o.forwardRef(R)},92136:(e,t,n)=>{"use strict";n.d(t,{StartSlot:()=>l,MiddleSlot:()=>u,EndSlot:()=>a,AfterSlot:()=>c});var o=n(67294),r=n(94184),s=n(16321),i=n.n(s);function l(e){const{className:t,interactive:n=!0,icon:s=!1,children:l}=e;return o.createElement("span",{className:r(i()["inner-slot"],n&&i().interactive,s&&i().icon,t)},l)}function u(e){const{className:t,children:n}=e;return o.createElement("span",{className:r(i()["inner-slot"],i()["inner-middle-slot"],t)},n)}function a(e){const{className:t,interactive:n=!0,icon:s=!1,children:l}=e;return o.createElement("span",{className:r(i()["inner-slot"],n&&i().interactive,s&&i().icon,t)},l)}function c(e){const{className:t,children:n}=e;return o.createElement("span",{className:r(i()["after-slot"],t)},n)}},81829:(e,t,n)=>{"use strict";n.d(t,{InputControl:()=>x});var o=n(67294),r=n(94184),s=n(74818),i=n(66213),l=n(1130),u=n(66364),a=n(65686),c=n(15965),d=n(53563),f=n(11888),h=n(92136),p=n(93463),m=n.n(p);function g(e){return!(0,s.isAriaAttribute)(e)&&!(0,s.isDataAttribute)(e)}function R(e){const{id:t,title:n,role:i,tabIndex:l,placeholder:u,name:a,type:c,value:d,defaultValue:p,draggable:R,autoComplete:x,autoFocus:b,maxLength:D,min:v,max:C,step:M,pattern:w,inputMode:Q,onSelect:S,onFocus:J,onBlur:y,onKeyDown:F,onKeyUp:N,onKeyPress:k,onChange:E,onDragStart:B,size:z="medium",className:I,inputClassName:A,disabled:L,readonly:P,containerTabIndex:K,startSlot:G,endSlot:T,reference:U,containerReference:O,onContainerFocus:X,...j}=e,H=(0,s.filterProps)(j,g),W={...(0,s.filterAriaProps)(j),...(0,s.filterDataProps)(j),id:t,title:n,role:i,tabIndex:l,placeholder:u,name:a,type:c,value:d,defaultValue:p,draggable:R,autoComplete:x,autoFocus:b,maxLength:D,min:v,max:C,step:M,pattern:w,inputMode:Q,onSelect:S,onFocus:J,onBlur:y,
onKeyDown:F,onKeyUp:N,onKeyPress:k,onChange:E,onDragStart:B};return o.createElement(f.ControlSkeleton,{...H,disabled:L,readonly:P,tabIndex:K,className:r(m().container,I),size:z,ref:O,onFocus:X,startSlot:G,middleSlot:o.createElement(h.MiddleSlot,null,o.createElement("input",{...W,className:r(m().input,A,G&&m()["with-start-slot"],T&&m()["with-end-slot"]),disabled:L,readOnly:P,ref:U})),endSlot:T})}function x(e){e=(0,a.useControl)(e);const{disabled:t,autoSelectOnFocus:n,tabIndex:r=0,onFocus:s,onBlur:f,reference:h,containerReference:p=null}=e,m=(0,o.useRef)(null),g=(0,o.useRef)(null),[x,b]=(0,c.useFocus)(),D=t?void 0:x?-1:r,v=t?void 0:x?r:-1,{isMouseDown:C,handleMouseDown:M,handleMouseUp:w}=(0,d.useIsMouseDown)(),Q=(0,i.createSafeMulticastEventHandler)(b.onFocus,(function(e){n&&!C.current&&(0,l.selectAllContent)(e.currentTarget)}),s),S=(0,i.createSafeMulticastEventHandler)(b.onBlur,f),J=(0,o.useCallback)(e=>{m.current=e,h&&("function"==typeof h&&h(e),"object"==typeof h&&(h.current=e))},[m,h]);return o.createElement(R,{...e,isFocused:x,containerTabIndex:D,tabIndex:v,onContainerFocus:function(e){g.current===e.target&&null!==m.current&&m.current.focus()},onFocus:Q,onBlur:S,reference:J,containerReference:(0,u.useMergedRefs)([g,p]),onMouseDown:M,onMouseUp:w})}},65686:(e,t,n)=>{"use strict";n.d(t,{useControl:()=>s});var o=n(66213),r=n(15965);function s(e){const{onFocus:t,onBlur:n,intent:s,highlight:i,disabled:l}=e,[u,a]=(0,r.useFocus)(),c=(0,o.createSafeMulticastEventHandler)(l?void 0:a.onFocus,t),d=(0,o.createSafeMulticastEventHandler)(l?void 0:a.onBlur,n);return{...e,intent:s||(u?"primary":"default"),highlight:null!=i?i:u,onFocus:c,onBlur:d}}},15965:(e,t,n)=>{"use strict";n.d(t,{useFocus:()=>r});var o=n(67294);function r(e){const[t,n]=(0,o.useState)(!1);return[t,{onFocus:(0,o.useCallback)((function(t){void 0!==e&&e.current!==t.target||n(!0)}),[e]),onBlur:(0,o.useCallback)((function(t){void 0!==e&&e.current!==t.target||n(!1)}),[e])}]}},53563:(e,t,n)=>{"use strict";n.d(t,{useIsMouseDown:()=>r});var o=n(67294);function r(){const e=(0,o.useRef)(!1),t=(0,o.useCallback)(()=>{e.current=!0},[e]),n=(0,o.useCallback)(()=>{e.current=!1},[e]);return{isMouseDown:e,handleMouseDown:t,handleMouseUp:n}}},66364:(e,t,n)=>{"use strict";n.d(t,{useMergedRefs:()=>r});var o=n(67294);function r(e){return(0,o.useCallback)(function(e){return t=>{e.forEach(e=>{"function"==typeof e?e(t):null!==e&&(e.current=t)})}}(e),e)}},1130:(e,t,n)=>{"use strict";function o(e){null!==e&&e.setSelectionRange(0,e.value.length)}n.d(t,{selectAllContent:()=>o})},66213:(e,t,n)=>{"use strict";function o(...e){return t=>{for(const n of e)void 0!==n&&n(t)}}n.d(t,{createSafeMulticastEventHandler:()=>o})}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

View File

@ -0,0 +1 @@
.defaultsButtonText-3mn75BN0{color:#131722;font-size:16px;width:100px}html.theme-dark .defaultsButtonText-3mn75BN0{color:#b2b5be}.defaultsButtonItem-3mn75BN0{min-width:100px}.defaultsButtonIcon-3mn75BN0{display:flex}.themesButtonText-3nid3QQp{color:#131722;font-size:14px;width:100px}html.theme-dark .themesButtonText-3nid3QQp{color:#b2b5be}.themesButtonIcon-3nid3QQp{display:flex}.defaultsButtonText-3nid3QQp{color:#131722;font-size:16px;width:100px}html.theme-dark .defaultsButtonText-3nid3QQp{color:#b2b5be}.defaultsButtonItem-3nid3QQp{min-width:100px}

View File

@ -0,0 +1 @@
.defaultsButtonText-3mn75BN0{color:#131722;font-size:16px;width:100px}html.theme-dark .defaultsButtonText-3mn75BN0{color:#b2b5be}.defaultsButtonItem-3mn75BN0{min-width:100px}.defaultsButtonIcon-3mn75BN0{display:flex}.themesButtonText-3nid3QQp{color:#131722;font-size:14px;width:100px}html.theme-dark .themesButtonText-3nid3QQp{color:#b2b5be}.themesButtonIcon-3nid3QQp{display:flex}.defaultsButtonText-3nid3QQp{color:#131722;font-size:16px;width:100px}html.theme-dark .defaultsButtonText-3nid3QQp{color:#b2b5be}.defaultsButtonItem-3nid3QQp{min-width:100px}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
.themesButtonText-3vn5WLwC{color:#131722;font-size:14px;width:100px}html.theme-dark .themesButtonText-3vn5WLwC{color:#b2b5be}.themesButtonIcon-3vn5WLwC{display:flex}.defaultsButtonText-3vn5WLwC{color:#131722;font-size:16px;width:100px}html.theme-dark .defaultsButtonText-3vn5WLwC{color:#b2b5be}.defaultsButtonItem-3vn5WLwC{min-width:100px}.backButton-ukxmTk5_{align-items:center;color:#131722;display:flex;height:100%;padding-right:20px;width:28px}html.theme-dark .backButton-ukxmTk5_{color:#b2b5be}.withSidebar-1e-cIUlp{display:block;max-width:750px;min-width:610px;width:auto}@media screen and (max-width:768px){.withSidebar-1e-cIUlp{max-width:610px;min-width:420px;width:auto}}@media screen and (max-width:428px){.withSidebar-1e-cIUlp{min-height:auto;min-width:100%}}.withSidebar-1e-cIUlp .content-1e-cIUlp{border-top:1px solid #e0e3eb;display:flex;flex:1 1 auto;flex-direction:row;overflow:hidden}html.theme-dark .withSidebar-1e-cIUlp .content-1e-cIUlp{border-top:1px solid #434651}.withSidebar-1e-cIUlp .tabContent-1e-cIUlp{-webkit-overflow-scrolling:touch;flex:1 1 auto;min-height:145px;overflow-x:hidden;overflow-y:auto;scrollbar-color:#9598a1 #0000;scrollbar-width:thin;width:auto}html.theme-dark .withSidebar-1e-cIUlp .tabContent-1e-cIUlp{scrollbar-color:#363a45 #0000}@media screen and (max-height:290px){.withSidebar-1e-cIUlp .tabContent-1e-cIUlp{min-height:auto}}.withSidebar-1e-cIUlp .tabContent-1e-cIUlp::-webkit-scrollbar{height:5px;width:5px}.withSidebar-1e-cIUlp .tabContent-1e-cIUlp::-webkit-scrollbar-thumb{background-color:#9598a1;border:1px solid #f0f3fa;border-radius:3px}html.theme-dark .withSidebar-1e-cIUlp .tabContent-1e-cIUlp::-webkit-scrollbar-thumb{background-color:#363a45;border-color:#1e222d}.withSidebar-1e-cIUlp .tabContent-1e-cIUlp::-webkit-scrollbar-track{background-color:initial;border-radius:3px}.withSidebar-1e-cIUlp .tabContent-1e-cIUlp::-webkit-scrollbar-corner{display:none}.withSidebar-1e-cIUlp .applyToAllButton-1e-cIUlp{padding-right:12px}

View File

@ -0,0 +1 @@
.themesButtonText-3vn5WLwC{color:#131722;font-size:14px;width:100px}html.theme-dark .themesButtonText-3vn5WLwC{color:#b2b5be}.themesButtonIcon-3vn5WLwC{display:flex}.defaultsButtonText-3vn5WLwC{color:#131722;font-size:16px;width:100px}html.theme-dark .defaultsButtonText-3vn5WLwC{color:#b2b5be}.defaultsButtonItem-3vn5WLwC{min-width:100px}.backButton-ukxmTk5_{align-items:center;color:#131722;display:flex;height:100%;padding-left:20px;width:28px}html.theme-dark .backButton-ukxmTk5_{color:#b2b5be}.backButton-ukxmTk5_ svg{transform:rotate(180deg)}.withSidebar-1e-cIUlp{display:block;max-width:750px;min-width:610px;width:auto}@media screen and (max-width:768px){.withSidebar-1e-cIUlp{max-width:610px;min-width:420px;width:auto}}@media screen and (max-width:428px){.withSidebar-1e-cIUlp{min-height:auto;min-width:100%}}.withSidebar-1e-cIUlp .content-1e-cIUlp{border-top:1px solid #e0e3eb;display:flex;flex:1 1 auto;flex-direction:row;overflow:hidden}html.theme-dark .withSidebar-1e-cIUlp .content-1e-cIUlp{border-top:1px solid #434651}.withSidebar-1e-cIUlp .tabContent-1e-cIUlp{-webkit-overflow-scrolling:touch;flex:1 1 auto;min-height:145px;overflow-x:hidden;overflow-y:auto;scrollbar-color:#9598a1 #0000;scrollbar-width:thin;width:auto}html.theme-dark .withSidebar-1e-cIUlp .tabContent-1e-cIUlp{scrollbar-color:#363a45 #0000}@media screen and (max-height:290px){.withSidebar-1e-cIUlp .tabContent-1e-cIUlp{min-height:auto}}.withSidebar-1e-cIUlp .tabContent-1e-cIUlp::-webkit-scrollbar{height:5px;width:5px}.withSidebar-1e-cIUlp .tabContent-1e-cIUlp::-webkit-scrollbar-thumb{background-color:#9598a1;border:1px solid #f0f3fa;border-radius:3px}html.theme-dark .withSidebar-1e-cIUlp .tabContent-1e-cIUlp::-webkit-scrollbar-thumb{background-color:#363a45;border-color:#1e222d}.withSidebar-1e-cIUlp .tabContent-1e-cIUlp::-webkit-scrollbar-track{background-color:initial;border-radius:3px}.withSidebar-1e-cIUlp .tabContent-1e-cIUlp::-webkit-scrollbar-corner{display:none}.withSidebar-1e-cIUlp .applyToAllButton-1e-cIUlp{padding-left:12px}

View File

@ -0,0 +1 @@
.loader-38qh0l_K{bottom:0;font-size:0;height:100%;left:0;margin:0 auto;opacity:1;position:absolute;right:0;text-align:center;top:0;transition:opacity .35s ease}.loader-38qh0l_K.static-38qh0l_K{display:inline-flex;position:static}.loader-38qh0l_K:after{content:" ";display:inline-block;height:100%;vertical-align:middle}.loader-38qh0l_K .item-38qh0l_K{--ui-lib-loader-color-default:currentColor;animation:tv-button-loader-38qh0l_K .96s ease-in-out infinite both;background-color:var(--ui-lib-loader-color,var(--ui-lib-loader-color-default));border-radius:100%;display:inline-block;height:10px;margin-left:2px;margin-right:2px;opacity:1;transform:translateY(0) scale(.6);transition:transform .35s cubic-bezier(.68,-.55,.265,1.55);vertical-align:middle;width:10px}.loader-38qh0l_K .item-38qh0l_K:nth-child(2){animation-delay:.151s;transition-delay:.11666667s}.loader-38qh0l_K .item-38qh0l_K:nth-child(3){animation-delay:.32s;transition-delay:233.33333ms}.loader-38qh0l_K .item-38qh0l_K.black-38qh0l_K{--ui-lib-loader-color-default:#787b86}.loader-38qh0l_K .item-38qh0l_K.white-38qh0l_K{--ui-lib-loader-color-default:#fff}.loader-38qh0l_K .item-38qh0l_K.gray-38qh0l_K{--ui-lib-loader-color-default:#b2b5be}.loader-38qh0l_K .item-38qh0l_K.primary-38qh0l_K{--ui-lib-loader-color-default:#131722}html.theme-dark .loader-38qh0l_K .item-38qh0l_K.primary-38qh0l_K{--ui-lib-loader-color-default:#d1d4dc}.loader-38qh0l_K.loader-initial-38qh0l_K{opacity:.1}.loader-38qh0l_K.loader-initial-38qh0l_K .item-38qh0l_K{animation:none;transform:translateY(12px) scale(.6)}.loader-38qh0l_K.loader-appear-38qh0l_K{opacity:1;transition:opacity .7s ease}.loader-38qh0l_K.loader-appear-38qh0l_K .item-38qh0l_K{animation:none;transform:translateY(0) scale(.6)}@keyframes tv-button-loader-38qh0l_K{0%,to{transform:scale(.6)}50%{transform:scale(.9)}}

View File

@ -0,0 +1 @@
.loader-38qh0l_K{bottom:0;font-size:0;height:100%;left:0;margin:0 auto;opacity:1;position:absolute;right:0;text-align:center;top:0;transition:opacity .35s ease}.loader-38qh0l_K.static-38qh0l_K{display:inline-flex;position:static}.loader-38qh0l_K:after{content:" ";display:inline-block;height:100%;vertical-align:middle}.loader-38qh0l_K .item-38qh0l_K{--ui-lib-loader-color-default:currentColor;animation:tv-button-loader-38qh0l_K .96s ease-in-out infinite both;background-color:var(--ui-lib-loader-color,var(--ui-lib-loader-color-default));border-radius:100%;display:inline-block;height:10px;margin-left:2px;margin-right:2px;opacity:1;transform:translateY(0) scale(.6);transition:transform .35s cubic-bezier(.68,-.55,.265,1.55);vertical-align:middle;width:10px}.loader-38qh0l_K .item-38qh0l_K:nth-child(2){animation-delay:.151s;transition-delay:.11666667s}.loader-38qh0l_K .item-38qh0l_K:nth-child(3){animation-delay:.32s;transition-delay:233.33333ms}.loader-38qh0l_K .item-38qh0l_K.black-38qh0l_K{--ui-lib-loader-color-default:#787b86}.loader-38qh0l_K .item-38qh0l_K.white-38qh0l_K{--ui-lib-loader-color-default:#fff}.loader-38qh0l_K .item-38qh0l_K.gray-38qh0l_K{--ui-lib-loader-color-default:#b2b5be}.loader-38qh0l_K .item-38qh0l_K.primary-38qh0l_K{--ui-lib-loader-color-default:#131722}html.theme-dark .loader-38qh0l_K .item-38qh0l_K.primary-38qh0l_K{--ui-lib-loader-color-default:#d1d4dc}.loader-38qh0l_K.loader-initial-38qh0l_K{opacity:.1}.loader-38qh0l_K.loader-initial-38qh0l_K .item-38qh0l_K{animation:none;transform:translateY(12px) scale(.6)}.loader-38qh0l_K.loader-appear-38qh0l_K{opacity:1;transition:opacity .7s ease}.loader-38qh0l_K.loader-appear-38qh0l_K .item-38qh0l_K{animation:none;transform:translateY(0) scale(.6)}@keyframes tv-button-loader-38qh0l_K{0%,to{transform:scale(.6)}50%{transform:scale(.9)}}

View File

@ -0,0 +1 @@
.icon-26rGYU-z{display:flex}.wrap-3JkbcgoB{position:relative}.input-3JkbcgoB{bottom:0;left:0;margin:0;max-width:100%;min-width:100%;opacity:0;position:absolute;top:0}

View File

@ -0,0 +1 @@
.icon-26rGYU-z{display:flex}.wrap-3JkbcgoB{position:relative}.input-3JkbcgoB{bottom:0;margin:0;max-width:100%;min-width:100%;opacity:0;position:absolute;right:0;top:0}

View File

@ -0,0 +1 @@
.favorite-I_fAY9V2{align-items:center;background-color:var(--tv-list-item-button-background-color);border-radius:4px;color:#787b86;display:inline-flex;font-size:0;height:22px;justify-content:center;min-width:22px;width:22px}.favorite-I_fAY9V2:active{background-color:var(--tv-list-item-button-background-hover-color,#e0e3eb);color:#131722}@media (any-hover:hover),(min--moz-device-pixel-ratio:0){.favorite-I_fAY9V2:hover{background-color:var(--tv-list-item-button-background-hover-color,#e0e3eb);color:#131722}}html.theme-dark .favorite-I_fAY9V2:active{background-color:var(--tv-list-item-button-background-hover-color,#363a45)}@media (any-hover:hover),(min--moz-device-pixel-ratio:0){html.theme-dark .favorite-I_fAY9V2:hover{background-color:var(--tv-list-item-button-background-hover-color,#363a45)}}html.theme-dark .favorite-I_fAY9V2:active{color:#b2b5be}@media (any-hover:hover),(min--moz-device-pixel-ratio:0){html.theme-dark .favorite-I_fAY9V2:hover{color:#b2b5be}}.favorite-I_fAY9V2.disabled-I_fAY9V2,.favorite-I_fAY9V2.disabled-I_fAY9V2:active{background-color:var(--tv-list-item-button-disabled-background-color,#0000)}@media (any-hover:hover),(min--moz-device-pixel-ratio:0){.favorite-I_fAY9V2.disabled-I_fAY9V2:hover{background-color:var(--tv-list-item-button-disabled-background-color,#0000)}}html.theme-dark .favorite-I_fAY9V2.disabled-I_fAY9V2,html.theme-dark .favorite-I_fAY9V2.disabled-I_fAY9V2:active{background-color:var(--tv-list-item-button-disabled-background-color,#0000)}@media (any-hover:hover),(min--moz-device-pixel-ratio:0){html.theme-dark .favorite-I_fAY9V2.disabled-I_fAY9V2:hover{background-color:var(--tv-list-item-button-disabled-background-color,#0000)}}.favorite-I_fAY9V2.active-I_fAY9V2,html.theme-dark .favorite-I_fAY9V2.active-I_fAY9V2{color:#90bff9}.favorite-I_fAY9V2.active-I_fAY9V2:active{background-color:#1848cc}@media (any-hover:hover),(min--moz-device-pixel-ratio:0){.favorite-I_fAY9V2.active-I_fAY9V2:hover{background-color:#1848cc}}html.theme-dark .favorite-I_fAY9V2.active-I_fAY9V2:active{background-color:#1848cc}@media (any-hover:hover),(min--moz-device-pixel-ratio:0){html.theme-dark .favorite-I_fAY9V2.active-I_fAY9V2:hover{background-color:#1848cc}}.favorite-I_fAY9V2.checked-I_fAY9V2{color:#fbc02d}html.theme-dark .favorite-I_fAY9V2.checked-I_fAY9V2{color:#f9a825}

View File

@ -0,0 +1 @@
.favorite-I_fAY9V2{align-items:center;background-color:var(--tv-list-item-button-background-color);border-radius:4px;color:#787b86;display:inline-flex;font-size:0;height:22px;justify-content:center;min-width:22px;width:22px}.favorite-I_fAY9V2:active{background-color:var(--tv-list-item-button-background-hover-color,#e0e3eb);color:#131722}@media (any-hover:hover),(min--moz-device-pixel-ratio:0){.favorite-I_fAY9V2:hover{background-color:var(--tv-list-item-button-background-hover-color,#e0e3eb);color:#131722}}html.theme-dark .favorite-I_fAY9V2:active{background-color:var(--tv-list-item-button-background-hover-color,#363a45)}@media (any-hover:hover),(min--moz-device-pixel-ratio:0){html.theme-dark .favorite-I_fAY9V2:hover{background-color:var(--tv-list-item-button-background-hover-color,#363a45)}}html.theme-dark .favorite-I_fAY9V2:active{color:#b2b5be}@media (any-hover:hover),(min--moz-device-pixel-ratio:0){html.theme-dark .favorite-I_fAY9V2:hover{color:#b2b5be}}.favorite-I_fAY9V2.disabled-I_fAY9V2,.favorite-I_fAY9V2.disabled-I_fAY9V2:active{background-color:var(--tv-list-item-button-disabled-background-color,#0000)}@media (any-hover:hover),(min--moz-device-pixel-ratio:0){.favorite-I_fAY9V2.disabled-I_fAY9V2:hover{background-color:var(--tv-list-item-button-disabled-background-color,#0000)}}html.theme-dark .favorite-I_fAY9V2.disabled-I_fAY9V2,html.theme-dark .favorite-I_fAY9V2.disabled-I_fAY9V2:active{background-color:var(--tv-list-item-button-disabled-background-color,#0000)}@media (any-hover:hover),(min--moz-device-pixel-ratio:0){html.theme-dark .favorite-I_fAY9V2.disabled-I_fAY9V2:hover{background-color:var(--tv-list-item-button-disabled-background-color,#0000)}}.favorite-I_fAY9V2.active-I_fAY9V2,html.theme-dark .favorite-I_fAY9V2.active-I_fAY9V2{color:#90bff9}.favorite-I_fAY9V2.active-I_fAY9V2:active{background-color:#1848cc}@media (any-hover:hover),(min--moz-device-pixel-ratio:0){.favorite-I_fAY9V2.active-I_fAY9V2:hover{background-color:#1848cc}}html.theme-dark .favorite-I_fAY9V2.active-I_fAY9V2:active{background-color:#1848cc}@media (any-hover:hover),(min--moz-device-pixel-ratio:0){html.theme-dark .favorite-I_fAY9V2.active-I_fAY9V2:hover{background-color:#1848cc}}.favorite-I_fAY9V2.checked-I_fAY9V2{color:#fbc02d}html.theme-dark .favorite-I_fAY9V2.checked-I_fAY9V2{color:#f9a825}

View File

@ -0,0 +1,5 @@
(self.webpackChunktradingview=self.webpackChunktradingview||[]).push([[2391],{80152:e=>{e.exports={button:"button-14c_DKWJ",disabled:"disabled-14c_DKWJ",hidden:"hidden-14c_DKWJ",icon:"icon-14c_DKWJ",dropped:"dropped-14c_DKWJ"}},31722:e=>{e.exports={button:"button-1WqyvKNY","button-children":"button-children-1WqyvKNY",hiddenArrow:"hiddenArrow-1WqyvKNY",invisibleFocusHandler:"invisibleFocusHandler-1WqyvKNY"}},31199:e=>{e.exports={placeholder:"placeholder-1J6emFeA"}},41615:(e,t,n)=>{"use strict";n.d(t,{createDomId:()=>a,joinDomIds:()=>c});const l=/\s/g;function o(e){return"string"==typeof e}function r(e){switch(typeof e){case"string":return e;case"number":case"bigint":return e.toString(10);case"boolean":case"symbol":return e.toString();default:return null}}function i(e){return e.trim().length>0}function s(e){return e.replace(l,"-")}function a(...e){const t=e.map(r).filter(o).filter(i).map(s);return(t.length>0&&t[0].startsWith("id_")?t:["id",...t]).join("_")}function c(...e){return e.map(r).filter(o).filter(i).join(" ")}},5862:(e,t,n)=>{"use strict";n.d(t,{useKeyboardToggle:()=>r,useKeyboardClose:()=>i,useKeyboardOpen:()=>s});var l=n(67294),o=n(42998);function r(e){return(0,l.useCallback)(t=>{switch(t){case 13:case 32:return e(),!0;default:return!1}},[e])}function i(e,t){return(0,l.useCallback)(n=>{if(!e)return!1;switch(n){case 9:case o.Modifiers.Shift+9:case 27:return t(),!0;default:return!1}},[e,t])}function s(e,t){return(0,l.useCallback)(n=>{if(e)return!1;switch(n){case 40:case 38:return t(),!0;default:return!1}},[e,t])}},98981:(e,t,n)=>{"use strict";n.d(t,{DisclosureMenuView:()=>v});var l=n(67294),o=n(94184),r=n.n(o),i=n(16282),s=n(66364),a=n(11888),c=n(92136),u=n(49775),d=n(20914),h=n(80152);function f(e){const{isDropped:t}=e;return l.createElement(u.Icon,{className:r()(h.icon,t&&h.dropped),icon:d})}function p(e){const{className:t,disabled:n,isDropped:o}=e;return l.createElement("span",{className:r()(h.button,n&&h.disabled,t)},l.createElement(f,{isDropped:o}))}var b=n(76420),m=n(31722);const v=l.forwardRef((e,t)=>{const{listboxId:n,className:o,listboxClassName:u,listboxTabIndex:d,hideArrowButton:h,matchButtonAndListboxWidths:f,disabled:v,isOpened:g,scrollWrapReference:C,listboxReference:S,size:w="medium",onClose:y,onOpen:k,onListboxFocus:_,onListboxBlur:E,onListboxKeyDown:x,buttonChildren:N,children:M,caretClassName:R,listboxAria:z,...D}=e,B=(0,l.useRef)(null),F=(0,l.useCallback)(()=>{const e=(0,i.ensureNotNull)(B.current).getBoundingClientRect(),t={x:e.left,y:e.top+e.height};return f&&(t.overrideWidth=e.width),t},[]),I=!h&&l.createElement(c.EndSlot,null,l.createElement(p,{isDropped:g,disabled:v,className:R}));return l.createElement(l.Fragment,null,l.createElement(a.ControlSkeleton,{...D,"data-role":"listbox","aria-expanded":g,"aria-owns":g?n:void 0,"aria-controls":g?n:void 0,"aria-disabled":v,disabled:v,className:r()(m.button,o),size:w,ref:(0,s.useMergedRefs)([B,t]),middleSlot:l.createElement(c.MiddleSlot,null,l.createElement("span",{className:r()(m["button-children"],h&&m.hiddenArrow)},N)),endSlot:I
}),l.createElement(b.PopupMenu,{...z,id:n,className:u,tabIndex:d,isOpened:g,position:F,onClose:y,onOpen:k,doNotCloseOn:B.current,reference:S,scrollWrapReference:C,onFocus:_,onBlur:E,onKeyDown:x},M))});v.displayName="DisclosureMenuView"},22904:(e,t,n)=>{"use strict";n.d(t,{useDisclosureMenuControl:()=>a});var l=n(67294),o=n(16282),r=n(15965),i=n(66213),s=n(15738);function a(e){const{disabled:t,intent:n,highlight:a,onFocus:c,onBlur:u,onClick:d}=e,[h,f]=(0,l.useState)(!1),[p,b]=(0,r.useFocus)(),m=p||h,v=null!=a?a:m,g=null!=n?n:m?"primary":"default",C=(0,l.useRef)(null),S=(0,l.useCallback)(()=>(0,o.ensureNotNull)(C.current).focus(),[C]),w=(0,l.useRef)(null),y=(0,l.useCallback)(()=>(0,o.ensureNotNull)(w.current).focus(),[w]),k=(0,l.useCallback)(()=>f(!0),[f]),_=(0,l.useCallback)(()=>{f(!1);const{activeElement:e}=document;e&&(0,s.isTextEditingField)(e)||S()},[f,S]),E=(0,l.useCallback)(()=>{h?_():k()},[h,_,k]),x=t?[]:[c,b.onFocus],N=t?[]:[u,b.onBlur],M=t?[]:[d,E],R=(0,i.createSafeMulticastEventHandler)(...x),z=(0,i.createSafeMulticastEventHandler)(...N),D=(0,i.createSafeMulticastEventHandler)(...M);return{isOpened:h,isFocused:m,highlight:v,intent:g,open:k,onOpen:y,close:_,toggle:E,buttonFocusBindings:{onFocus:R,onBlur:z},onButtonClick:D,buttonRef:C,listboxRef:w}}},45221:(e,t,n)=>{"use strict";n.d(t,{Select:()=>_});var l=n(67294),o=n(16282),r=n(41615),i=n(8596);const s={duration:200},a={vertical:{scrollSize:"scrollHeight",clientSize:"clientHeight",start:"top",end:"bottom",size:"height"},horizontal:{scrollSize:"scrollWidth",clientSize:"clientWidth",start:"left",end:"right",size:"width"}};function c(e,t){const n=a[e];return t[n.scrollSize]>t[n.clientSize]}function u(e,t,n,l,o,r){const s=function(e,t,n){const l=a[e];return{start:0,middle:-1*(Math.floor(n[l.size]/2)-Math.floor(t[l.size]/2)),end:-1*(n[l.size]-t[l.size])}}(e,l,o);let c=0;if(function(e,t,n){const l=a[e];return t[l.start]<n[l.start]-n[l.size]/2||t[l.end]>n[l.end]+n[l.size]/2}(e,l,o))c=s.middle;else{const t=function(e){const{start:t,middle:n,end:l}=e,o=new Map([[Math.abs(t),{key:"start",value:Math.sign(t)}],[Math.abs(n),{key:"middle",value:Math.sign(n)}],[Math.abs(l),{key:"end",value:Math.sign(l)}]]),r=Math.min(...o.keys());return o.get(r)}(function(e,t,n){const l=a[e],o=t[l.start]+Math.floor(t[l.size]/2),r=n[l.start]+Math.floor(n[l.size]/2);return{start:t[l.start]-n[l.start],middle:o-r,end:t[l.end]-n[l.end]}}(e,l,o));c=void 0!==t?s[t.key]:0}return function(e){const{additionalScroll:t=0,duration:n=i.dur,func:l=i.easingFunc.easeInOutCubic,onScrollEnd:o,target:r,wrap:s,direction:a="vertical"}=e;let{targetRect:c,wrapRect:u}=e;c=null!=c?c:r.getBoundingClientRect(),u=null!=u?u:s.getBoundingClientRect();const d=("vertical"===a?c.top-u.top:c.left-u.left)+t,h="vertical"===a?"scrollTop":"scrollLeft",f=s?s[h]:0;let p,b=0;return b=window.requestAnimationFrame((function e(t){let r;if(p?r=t-p:(r=0,p=t),r>=n)return s[h]=f+d,void(o&&o());const i=f+d*l(r/n);s[h]=Math.floor(i),b=window.requestAnimationFrame(e)})),function(){window.cancelAnimationFrame(b),o&&o()}}({...r,target:t,
targetRect:l,wrap:n,wrapRect:o,additionalScroll:c,direction:e})}class d{constructor(e=null){this._container=null,this._lastScrolledElement=null,this._stopVerticalScroll=null,this._stopHorizontalScroll=null,this._container=e}scrollTo(e,t=s){if(null!==this._container&&null!==e&&!function(e,t){const n=e.getBoundingClientRect(),l=t.getBoundingClientRect();return n.top>=l.top&&n.bottom<=l.bottom&&n.left>=l.left&&n.right<=l.right}(e,this._container)){const n=e.getBoundingClientRect(),l=this._container.getBoundingClientRect();this.stopScroll(),c("vertical",this._container)&&(this._stopVerticalScroll=u("vertical",e,this._container,n,l,this._modifyOptions("vertical",t))),c("horizontal",this._container)&&(this._stopHorizontalScroll=u("horizontal",e,this._container,n,l,this._modifyOptions("horizontal",t)))}this._lastScrolledElement=e}scrollToLastElement(e){this.scrollTo(this._lastScrolledElement,e)}stopScroll(){null!==this._stopVerticalScroll&&this._stopVerticalScroll(),null!==this._stopHorizontalScroll&&this._stopHorizontalScroll()}setContainer(e){var t;this._container=e,(null===(t=this._container)||void 0===t?void 0:t.contains(this._lastScrolledElement))||(this._lastScrolledElement=null)}destroy(){this.stopScroll(),this._container=null,this._lastScrolledElement=null}_handleScrollEnd(e){"vertical"===e?this._stopVerticalScroll=null:this._stopHorizontalScroll=null}_modifyOptions(e,t){return Object.assign({},t,{onScrollEnd:()=>{this._handleScrollEnd(e),void 0!==t.onScrollEnd&&t.onScrollEnd()}})}}var h=n(66364),f=n(95860),p=n(99479),b=n(58848);var m=n(98981),v=n(5862),g=n(22904),C=n(42998),S=n(31199);function w(e){return!e.readonly}function y(e,t){var n;return null!==(n=null==t?void 0:t.id)&&void 0!==n?n:(0,r.createDomId)(e,"item",null==t?void 0:t.value)}function k(e){var t,n;const{selectedItem:o,placeholder:r}=e;if(!o)return l.createElement("span",{className:S.placeholder},r);const i=null!==(n=null!==(t=o.selectedContent)&&void 0!==t?t:o.content)&&void 0!==n?n:o.value;return l.createElement("span",null,i)}const _=l.forwardRef((e,t)=>{const{id:n,menuClassName:i,menuItemClassName:s,tabIndex:a=0,disabled:c,highlight:u,intent:S,hideArrowButton:_,placeholder:E,addPlaceholderToItems:x=!0,value:N,"aria-labelledby":M,onFocus:R,onBlur:z,onClick:D,onChange:B,...F}=e;let{items:I}=e;if(E&&x){I=[{value:void 0,content:E,id:(0,r.createDomId)(n,"placeholder")},...I]}const{isOpened:W,isFocused:K,highlight:O,intent:A,open:T,onOpen:H,close:L,toggle:V,buttonFocusBindings:q,onButtonClick:J,buttonRef:j,listboxRef:P}=(0,g.useDisclosureMenuControl)({disabled:c,intent:S,highlight:u,onFocus:R,onBlur:z,onClick:D}),Y=function(e){const t=(0,l.useRef)(null);return(0,l.useEffect)(()=>(t.current=new d(e),()=>(0,o.ensureNotNull)(t.current).destroy()),[]),t}(),G=(0,l.useRef)(null),Q=(0,l.useRef)(new WeakMap),U=I.filter(w),X=U.find(e=>e.value===N);(0,l.useEffect)(()=>ae(),[X,ae]);const Z=(0,r.joinDomIds)(M,n),$=Z.length>0?Z:void 0,ee=(0,r.createDomId)(n,"listbox"),te=(0,l.useMemo)(()=>({role:"listbox","aria-labelledby":M,"aria-activedescendant":y(n,X)
}),[M,X]),ne=function(e,t,n){const o=(0,l.useCallback)(()=>{const l=e.findIndex(e=>e.value===t);l!==e.length-1&&n&&n(e[l+1].value)},[e,t,n]),r=(0,l.useCallback)(()=>{const l=e.findIndex(e=>e.value===t);if(0===l)return;n&&n(e[l>0?l-1:0].value)},[e,t,n]),i=(0,l.useCallback)(()=>{n&&n(e[0].value)},[n,e]),s=(0,l.useCallback)(()=>{n&&n(e[e.length-1].value)},[n,e]);return(0,l.useCallback)(e=>{switch(e){case 40:return o(),!0;case 38:return r(),!0;case 34:return s(),!0;case 33:return i(),!0;default:return!1}},[o,r,i,s])}(U,N,B),le=(0,v.useKeyboardToggle)(V),oe=(0,v.useKeyboardClose)(W,L),re=(0,v.useKeyboardOpen)(W,T),ie=function(e){const t=(0,l.useRef)(""),n=(0,l.useMemo)(()=>(0,p.default)(()=>{t.current=""},500),[]),o=(0,l.useMemo)(()=>(0,b.default)(e,200),[e]);return(0,l.useCallback)(e=>{e.key.length>0&&e.key.length<3&&(t.current+=e.key,o(t.current,e),n())},[n,o])}((e,t)=>{const n=function(e,t){return e.find(e=>{var n;const l=t.toLowerCase();return!e.readonly&&(!e.readonly&&("string"==typeof e.content&&e.content.toLowerCase().startsWith(l)||String(null!==(n=e.value)&&void 0!==n?n:"").toLowerCase().startsWith(l)))})}(U,e);void 0!==n&&B&&(t.stopPropagation(),W||T(),B(n.value))});return l.createElement(m.DisclosureMenuView,{...F,...q,id:n,role:"button",tabIndex:c?-1:a,"aria-haspopup":"listbox","aria-labelledby":$,disabled:c,hideArrowButton:_,isFocused:K,isOpened:W,highlight:O,intent:A,ref:(0,h.useMergedRefs)([j,t]),onClick:J,onOpen:function(){ae({duration:0}),H()},onClose:L,onKeyDown:function(e){const t=(0,C.hashFromEvent)(e);if(le(t)||oe(t)||re(t))return void e.preventDefault();ie(e)},listboxId:ee,listboxTabIndex:-1,listboxClassName:i,listboxAria:te,listboxReference:P,scrollWrapReference:function(e){G.current=e,(0,o.ensureNotNull)(Y.current).setContainer(e)},onListboxKeyDown:function(e){const t=(0,C.hashFromEvent)(e);if(ne(t)||le(t)||oe(t))return void e.preventDefault();ie(e)},buttonChildren:l.createElement(k,{selectedItem:X,placeholder:E})},I.map((e,t)=>{var o;if(e.readonly)return l.createElement(l.Fragment,{key:"readonly_item_"+t},e.content);const r=y(n,e);return l.createElement(f.PopupMenuItem,{key:r,id:r,className:s,role:"option","aria-selected":N===e.value,isActive:N===e.value,label:null!==(o=e.content)&&void 0!==o?o:e.value,onClick:se,onClickArg:e.value,isDisabled:e.disabled,reference:t=>function(e,t){Q.current.set(e,t)}(e,t)})}));function se(e){B&&B(e)}function ae(e){if(W&&void 0!==X){const t=Q.current.get(X);null!=t&&(0,o.ensureNotNull)(Y.current).scrollTo(t,e)}}});_.displayName="Select"},73991:(e,t,n)=>{"use strict";n.d(t,{TouchScrollContainer:()=>s});var l=n(67294),o=n(67891),r=n(16282),i=n(43367);function s(e){const{reference:t,children:n,...r}=e,s=(0,l.useRef)(null),c=(0,l.useCallback)(e=>{t&&(t.current=e),i.CheckMobile.iOS()&&(null!==s.current&&(0,o.enableBodyScroll)(s.current),s.current=e,null!==s.current&&(0,o.disableBodyScroll)(s.current,{allowTouchMove:a(s)}))},[t]);return l.createElement("div",{ref:c,...r},n)}function a(e){return t=>{const n=(0,r.ensureNotNull)(e.current),l=document.activeElement
;return!n.contains(t)||null!==l&&n.contains(l)&&l.contains(t)}}},20914:e=>{e.exports='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 11 7" width="11" height="7" fill="none"><path stroke="currentColor" stroke-width="1.3" d="M.5 1.5l5 4 5-4"/></svg>'}}]);

View File

@ -0,0 +1,4 @@
(self.webpackChunktradingview=self.webpackChunktradingview||[]).push([[2402],{66541:t=>{t.exports={dialog:"dialog-UM6w7sFp",rounded:"rounded-UM6w7sFp",shadowed:"shadowed-UM6w7sFp",fullscreen:"fullscreen-UM6w7sFp",darker:"darker-UM6w7sFp",backdrop:"backdrop-UM6w7sFp"}},27898:t=>{t.exports={"tablet-normal-breakpoint":"screen and (max-width: 768px)","tooltip-offset":"20px",dialog:"dialog-2AogBbC7",dragging:"dragging-2AogBbC7",dialogAnimatedAppearance:"dialogAnimatedAppearance-2AogBbC7",dialogAnimation:"dialogAnimation-2AogBbC7",dialogTooltip:"dialogTooltip-2AogBbC7"}},90714:(t,e,i)=>{"use strict";i.d(e,{PopupContext:()=>s});const s=i(67294).createContext(null)},32402:(t,e,i)=>{"use strict";i.d(e,{PopupDialog:()=>T});var s=i(67294),o=i(94184),n=i(16282),a=i(78106),r=i(90071),l=i(74818),h=i(66541);class d extends s.PureComponent{constructor(){super(...arguments),this._manager=new r.OverlapManager,this._handleSlot=t=>{this._manager.setContainer(t)}}render(){const{rounded:t=!0,shadowed:e=!0,fullscreen:i=!1,darker:n=!1,className:r,backdrop:d}=this.props,c=o(r,h.dialog,t&&h.rounded,e&&h.shadowed,i&&h.fullscreen,n&&h.darker),u=(0,l.filterDataProps)(this.props),g=this.props.style?{...this._createStyles(),...this.props.style}:this._createStyles();return s.createElement(s.Fragment,null,s.createElement(a.SlotContext.Provider,{value:this._manager},d&&s.createElement("div",{onClick:this.props.onClickBackdrop,className:h.backdrop}),s.createElement("div",{...u,className:c,style:g,ref:this.props.reference,onFocus:this.props.onFocus,onMouseDown:this.props.onMouseDown,onMouseUp:this.props.onMouseUp,onClick:this.props.onClick,onKeyDown:this.props.onKeyDown,tabIndex:-1},this.props.children)),s.createElement(a.Slot,{reference:this._handleSlot}))}_createStyles(){const{bottom:t,left:e,width:i,right:s,top:o,zIndex:n,height:a}=this.props;return{bottom:t,left:e,right:s,top:o,zIndex:n,maxWidth:i,height:a}}}var c=i(36668),u=i(13894),g=i(57968);function p(t,e,i,s){return t+e>s&&(t=s-e),t<i&&(t=i),t}function _(t){return{x:(0,g.clamp)(t.x,20,document.documentElement.clientWidth-20),y:(0,g.clamp)(t.y,20,window.innerHeight-20)}}function m(t){return{x:t.clientX,y:t.clientY}}function f(t){return{x:t.touches[0].clientX,y:t.touches[0].clientY}}class v{constructor(t,e,i={boundByScreen:!0}){this._drag=null,this._canBeTouchClick=!1,this._frame=null,this._onMouseDragStart=t=>{if(0!==t.button)return;t.preventDefault(),document.addEventListener("mousemove",this._onMouseDragMove),document.addEventListener("mouseup",this._onMouseDragEnd);const e=_(m(t));this._dragStart(e)},this._onTouchDragStart=t=>{this._canBeTouchClick=!0,t.preventDefault(),this._header.addEventListener("touchmove",this._onTouchDragMove,{passive:!1});const e=_(f(t));this._dragStart(e)},this._onMouseDragEnd=t=>{t.target instanceof Node&&this._header.contains(t.target)&&t.preventDefault(),document.removeEventListener("mousemove",this._onMouseDragMove),document.removeEventListener("mouseup",this._onMouseDragEnd),this._onDragStop()},this._onTouchDragEnd=t=>{
this._header.removeEventListener("touchmove",this._onTouchDragMove),this._onDragStop(),this._canBeTouchClick&&(this._canBeTouchClick=!1,function(t){if(t instanceof SVGElement){const e=document.createEvent("SVGEvents");e.initEvent("click",!0,!0),t.dispatchEvent(e)}t instanceof HTMLElement&&t.click()}(t.target))},this._onMouseDragMove=t=>{const e=_(m(t));this._dragMove(e)},this._onTouchDragMove=t=>{this._canBeTouchClick=!1,t.preventDefault();const e=_(f(t));this._dragMove(e)},this._onDragStop=()=>{this._drag=null,this._header.classList.remove("dragging")},this._dialog=t,this._header=e,this._options=i,this._header.addEventListener("mousedown",this._onMouseDragStart),this._header.addEventListener("touchstart",this._onTouchDragStart),this._header.addEventListener("touchend",this._onTouchDragEnd)}destroy(){null!==this._frame&&cancelAnimationFrame(this._frame),this._header.removeEventListener("mousedown",this._onMouseDragStart),document.removeEventListener("mouseup",this._onMouseDragEnd),this._header.removeEventListener("touchstart",this._onTouchDragStart),this._header.removeEventListener("touchend",this._onTouchDragEnd),document.removeEventListener("mouseleave",this._onMouseDragEnd)}updateOptions(t){this._options=t}_dragStart(t){const e=this._dialog.getBoundingClientRect();this._drag={startX:t.x,startY:t.y,finishX:t.x,finishY:t.y,dialogX:e.left,dialogY:e.top};const i=Math.round(e.left),s=Math.round(e.top);this._dialog.style.transform=`translate(${i}px, ${s}px)`,this._header.classList.add("dragging"),this._options.onDragStart&&this._options.onDragStart()}_dragMove(t){if(this._drag){if(this._drag.finishX=t.x,this._drag.finishY=t.y,null!==this._frame)return;this._frame=requestAnimationFrame(()=>{if(this._drag){const e=t.x-this._drag.startX,i=t.y-this._drag.startY;this._moveDialog(this._drag.dialogX+e,this._drag.dialogY+i)}this._frame=null})}}_moveDialog(t,e){const i=this._dialog.getBoundingClientRect(),{boundByScreen:s}=this._options,o=p(t,i.width,s?0:-1/0,s?window.innerWidth:1/0),n=p(e,i.height,s?0:-1/0,s?window.innerHeight:1/0);this._dialog.style.transform=`translate(${Math.round(o)}px, ${Math.round(n)}px)`}}const y={vertical:0};class D{constructor(t,e){this._frame=null,this._isFullscreen=!1,this._handleResize=()=>{null===this._frame&&(this._frame=requestAnimationFrame(()=>{this.recalculateBounds(),this._frame=null}))},this._dialog=t,this._guard=e.guard||y,this._calculateDialogPosition=e.calculateDialogPosition,this._initialHeight=t.style.height,window.addEventListener("resize",this._handleResize)}updateOptions(t){this._guard=t.guard||y,this._calculateDialogPosition=t.calculateDialogPosition}setFullscreen(t){this._isFullscreen!==t&&(this._isFullscreen=t,this.recalculateBounds())}centerAndFit(){const{x:t,y:e}=this.getDialogsTopLeftCoordinates(),i=this._calcAvailableHeight(),s=this._calcDialogHeight();i===s&&(this._dialog.style.height=s+"px"),this._dialog.style.top="0px",this._dialog.style.left="0px",this._dialog.style.transform=`translate(${t}px, ${e}px)`}getDialogsTopLeftCoordinates(){
const{clientHeight:t,clientWidth:e}=document.documentElement,i=this._calcDialogHeight(),s=e/2-this._dialog.clientWidth/2,o=t/2-i/2;return{x:Math.round(s),y:Math.round(o)}}recalculateBounds(){const{clientHeight:t,clientWidth:e}=document.documentElement;if(this._isFullscreen)this._dialog.style.top="0px",this._dialog.style.left="0px",this._dialog.style.width="100%",this._dialog.style.height="100%",this._dialog.style.transform="none";else{const{vertical:i}=this._guard;if(this._calculateDialogPosition){const s=this._calculateDialogPosition(this._dialog,{clientWidth:e,clientHeight:t},{vertical:i}),{left:o,top:n}=s;this._dialog.style.transform=`translate(${Math.round(o)}px, ${Math.round(n)}px)`}else{this._dialog.style.width="",this._dialog.style.height="";const s=this._dialog.getBoundingClientRect(),o=t-2*i,n=p(s.left,s.width,0,e),a=p(s.top,s.height,i,t);this._dialog.style.top="0px",this._dialog.style.left="0px",this._dialog.style.transform=`translate(${Math.round(n)}px, ${Math.round(a)}px)`,this._dialog.style.height=o<s.height?o+"px":this._initialHeight}}}destroy(){window.removeEventListener("resize",this._handleResize),null!==this._frame&&(cancelAnimationFrame(this._frame),this._frame=null)}_calcDialogHeight(){const t=this._calcAvailableHeight();return t<this._dialog.clientHeight?t:this._dialog.clientHeight}_calcAvailableHeight(){return document.documentElement.clientHeight-2*this._guard.vertical}}var x=i(4735),E=i(90714),S=i(75761),M=i(27898);M["tooltip-offset"];class w extends s.PureComponent{constructor(t){super(t),this._dialog=null,this._handleDialogRef=t=>{const{reference:e}=this.props;this._dialog=t,"function"==typeof e&&e(t)},this._handleFocus=t=>{this._moveToTop()},this._handleMouseDown=t=>{this._moveToTop()},this._handleTouchStart=t=>{this._moveToTop()},this.state={canFitTooltip:!1}}render(){return s.createElement(E.PopupContext.Provider,{value:this},s.createElement(u.OutsideEvent,{mouseDown:!0,touchStart:!0,handler:this.props.onClickOutside},t=>s.createElement("div",{ref:t,"data-outside-boundary-for":this.props.name,onFocus:this._handleFocus,onMouseDown:this._handleMouseDown,onTouchStart:this._handleTouchStart,"data-dialog-name":this.props["data-dialog-name"]},s.createElement(d,{style:this._applyAnimationCSSVariables(),...this.props,reference:this._handleDialogRef,className:o(M.dialog,this.props.className)},!1,this.props.children))))}componentDidMount(){const{draggable:t,boundByScreen:e,onDragStart:i}=this.props,s=(0,n.ensureNotNull)(this._dialog);if(t){const t=s.querySelector("[data-dragg-area]");t&&t instanceof HTMLElement&&(this._drag=new v(s,t,{boundByScreen:Boolean(e),onDragStart:i}))}this.props.autofocus&&!s.contains(document.activeElement)&&s.focus(),(this._isFullScreen()||this.props.fixedBody)&&(0,S.setFixedBodyState)(!0);const{guard:o,calculateDialogPosition:a}=this.props;this._resize=new D(s,{guard:o,calculateDialogPosition:a}),this.props.isAnimationEnabled&&this.props.growPoint&&this._applyAppearanceAnimation(this.props.growPoint),this.props.centeredOnMount&&this._resize.centerAndFit(),
this._resize.setFullscreen(this._isFullScreen()),this.props.shouldForceFocus&&s.focus()}componentDidUpdate(){if(this._resize){const{guard:t,calculateDialogPosition:e}=this.props;this._resize.updateOptions({guard:t,calculateDialogPosition:e}),this._resize.setFullscreen(this._isFullScreen())}this._drag&&this._drag.updateOptions({boundByScreen:Boolean(this.props.boundByScreen),onDragStart:this.props.onDragStart})}componentWillUnmount(){this._drag&&this._drag.destroy(),this._resize&&this._resize.destroy(),(this._isFullScreen()||this.props.fixedBody)&&(0,S.setFixedBodyState)(!1)}focus(){this._dialog&&this._dialog.focus()}centerAndFit(){this._resize&&this._resize.centerAndFit()}recalculateBounds(){this._resize&&this._resize.recalculateBounds()}_moveToTop(){null!==this.context&&this.context.moveToTop()}_applyAnimationCSSVariables(){return{"--animationTranslateStartX":null,"--animationTranslateStartY":null,"--animationTranslateEndX":null,"--animationTranslateEndY":null}}_applyAppearanceAnimation(t){if(this._resize&&this._dialog){const{x:e,y:i}=t,{x:s,y:o}=this._resize.getDialogsTopLeftCoordinates();this._dialog.style.setProperty("--animationTranslateStartX",e+"px"),this._dialog.style.setProperty("--animationTranslateStartY",i+"px"),this._dialog.style.setProperty("--animationTranslateEndX",s+"px"),this._dialog.style.setProperty("--animationTranslateEndY",o+"px"),this._dialog.classList.add(M.dialogAnimatedAppearance)}}_handleTooltipFit(){0}_isFullScreen(){return Boolean(this.props.fullscreen)}}w.contextType=x.PortalContext,w.defaultProps={boundByScreen:!0,draggable:!0,centeredOnMount:!0};const T=(0,c.makeOverlapable)(w)},13894:(t,e,i)=>{"use strict";i.d(e,{OutsideEvent:()=>o});var s=i(47165);function o(t){const{children:e,...i}=t;return e((0,s.useOutsideEvent)(i))}},36668:(t,e,i)=>{"use strict";i.d(e,{makeOverlapable:()=>n});var s=i(67294),o=i(4735);function n(t){return class extends s.PureComponent{render(){const{isOpened:e,root:i}=this.props;if(!e)return null;const n=s.createElement(t,{...this.props,zIndex:150});return"parent"===i?n:s.createElement(o.Portal,null,n)}}}}}]);

View File

@ -0,0 +1,2 @@
(self.webpackChunktradingview=self.webpackChunktradingview||[]).push([[2444],{36677:t=>{t.exports={wrap:"wrap-3obNZqvj",wrapWithArrowsOuting:"wrapWithArrowsOuting-3obNZqvj",wrapOverflow:"wrapOverflow-3obNZqvj",scrollWrap:"scrollWrap-3obNZqvj",noScrollBar:"noScrollBar-3obNZqvj",icon:"icon-3obNZqvj",scrollLeft:"scrollLeft-3obNZqvj",scrollRight:"scrollRight-3obNZqvj",isVisible:"isVisible-3obNZqvj",iconWrap:"iconWrap-3obNZqvj",fadeLeft:"fadeLeft-3obNZqvj",fadeRight:"fadeRight-3obNZqvj"}},52444:(t,e,s)=>{"use strict";s.d(e,{HorizontalScroll:()=>R});var i=s(67294),r=s(94184),o=s(5383),n=s(16282),l=s(49775),a=s(99432),h=s(83939),c=s(76553),u=s(38508),d=s(36677);const p={isVisibleScrollbar:!0,shouldMeasure:!0,hideButtonsFrom:1};function f(t){return i.createElement("div",{className:r(d.fadeLeft,t.className,{[d.isVisible]:t.isVisible})})}function w(t){return i.createElement("div",{className:r(d.fadeRight,t.className,{[d.isVisible]:t.isVisible})})}function b(t){return i.createElement(v,{...t,className:d.scrollLeft})}function m(t){return i.createElement(v,{...t,className:d.scrollRight})}function v(t){return i.createElement("div",{className:r(t.className,{[d.isVisible]:t.isVisible}),onClick:t.onClick},i.createElement("div",{className:d.iconWrap},i.createElement(l.Icon,{icon:u,className:d.icon})))}const R=function(t=b,e=m,s=f,l=w){var u;return(u=class extends i.PureComponent{constructor(t){super(t),this._scroll=i.createRef(),this._wrapMeasureRef=i.createRef(),this._contentMeasureRef=i.createRef(),this._handleScrollLeft=()=>{if(this.props.onScrollButtonClick)return void this.props.onScrollButtonClick("left");const t=this.props.scrollStepSize||this.state.widthWrap-50;this.animateTo(Math.max(0,this.currentPosition()-t))},this._handleScrollRight=()=>{if(this.props.onScrollButtonClick)return void this.props.onScrollButtonClick("right");const t=this.props.scrollStepSize||this.state.widthWrap-50;this.animateTo(Math.min((this.state.widthContent||0)-(this.state.widthWrap||0),this.currentPosition()+t))},this._handleResizeWrap=t=>{this.props.onMeasureWrap&&this.props.onMeasureWrap(t),this.setState({widthWrap:t.width}),this._checkButtonsVisibility()},this._handleResizeContent=t=>{this.props.onMeasureContent&&this.props.onMeasureContent(t);const{shouldDecreaseWidthContent:e,buttonsWidthIfDecreasedWidthContent:s}=this.props;e&&s?this.setState({widthContent:t.width+2*s}):this.setState({widthContent:t.width})},this._handleScroll=()=>{const{onScroll:t}=this.props;t&&t(this.currentPosition(),this.isAtLeft(),this.isAtRight()),this._checkButtonsVisibility()},this._checkButtonsVisibility=()=>{const{isVisibleLeftButton:t,isVisibleRightButton:e}=this.state,s=this.isAtLeft(),i=this.isAtRight();s||t?s&&t&&this.setState({isVisibleLeftButton:!1}):this.setState({isVisibleLeftButton:!0}),i||e?i&&e&&this.setState({isVisibleRightButton:!1}):this.setState({isVisibleRightButton:!0})},this.state={widthContent:0,widthWrap:0,isVisibleRightButton:!1,isVisibleLeftButton:!1}}componentDidMount(){this._checkButtonsVisibility()}componentDidUpdate(t,e){
e.widthWrap===this.state.widthWrap&&e.widthContent===this.state.widthContent||this._handleScroll(),this.props.shouldMeasure&&this._wrapMeasureRef.current&&this._contentMeasureRef.current&&(this._wrapMeasureRef.current.measure(),this._contentMeasureRef.current.measure())}currentPosition(){return this._scroll.current?(0,c.isRtl)()?(0,c.getLTRScrollLeft)(this._scroll.current):this._scroll.current.scrollLeft:0}isAtLeft(){return!this._isOverflowed()||this.currentPosition()<=(0,n.ensureDefined)(this.props.hideButtonsFrom)}isAtRight(){return!this._isOverflowed()||this.currentPosition()+this.state.widthWrap>=this.state.widthContent-(0,n.ensureDefined)(this.props.hideButtonsFrom)}animateTo(t,e=h.dur){const s=this._scroll.current;s&&((0,c.isRtl)()&&(t=(0,c.getLTRScrollLeftOffset)(s,t)),e<=0?s.scrollLeft=Math.round(t):(0,a.doAnimate)({onStep(t,e){s.scrollLeft=Math.round(e)},from:s.scrollLeft,to:Math.round(t),easing:h.easingFunc.easeInOutCubic,duration:e}))}render(){const{children:n,isVisibleScrollbar:a,isVisibleFade:h,isVisibleButtons:c,shouldMeasure:u,shouldDecreaseWidthContent:p,buttonsWidthIfDecreasedWidthContent:f,onMouseOver:w,onMouseOut:b,scrollWrapClassName:m,fadeClassName:v}=this.props,{isVisibleRightButton:R,isVisibleLeftButton:S}=this.state,_=p&&f;return i.createElement(o,{whitelist:["width"],onMeasure:this._handleResizeWrap,shouldMeasure:u,ref:this._wrapMeasureRef},i.createElement("div",{className:d.wrapOverflow,onMouseOver:w,onMouseOut:b},i.createElement("div",{className:r(d.wrap,_?d.wrapWithArrowsOuting:"")},i.createElement("div",{className:r(d.scrollWrap,m,{[d.noScrollBar]:!a}),onScroll:this._handleScroll,ref:this._scroll},i.createElement(o,{onMeasure:this._handleResizeContent,whitelist:["width"],shouldMeasure:u,ref:this._contentMeasureRef},n)),h&&i.createElement(s,{isVisible:S,className:v}),h&&i.createElement(l,{isVisible:R,className:v}),c&&i.createElement(t,{onClick:this._handleScrollLeft,isVisible:S}),c&&i.createElement(e,{onClick:this._handleScrollRight,isVisible:R}))))}_isOverflowed(){const{widthContent:t,widthWrap:e}=this.state;return t>e}}).defaultProps=p,u}(b,m,f,w)},38508:t=>{t.exports='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 10" width="20" height="10"><path fill="none" stroke="currentColor" stroke-width="1.5" d="M2 1l8 8 8-8"/></svg>'}}]);

View File

@ -0,0 +1 @@
.dialog-23lGwisF{min-width:254px;padding:40px;width:auto}.dialogInner-23lGwisF{align-items:center;display:flex;flex-direction:column}.titleWrapper-23lGwisF{align-items:center;display:flex;justify-content:center;margin-bottom:16px;max-width:100%}.title-23lGwisF{color:#131722;cursor:default;font-size:20px;font-weight:700;line-height:28px;overflow:hidden;white-space:nowrap}html.theme-dark .title-23lGwisF{color:#b2b5be}.infoHint-23lGwisF{color:#787b86;height:18px;margin-left:8px;width:18px}.form-23lGwisF{display:flex;max-width:200px;width:100%}.inputWrapper-23lGwisF{flex-grow:1}.input-23lGwisF{font-size:24px;text-align:center}.hint-23lGwisF{color:#787b86;cursor:default;font-size:12px;line-height:18px;margin-top:3px;max-width:100%;overflow:hidden;white-space:nowrap}.error-23lGwisF{color:#f23645}

View File

@ -0,0 +1 @@
.dialog-23lGwisF{min-width:254px;padding:40px;width:auto}.dialogInner-23lGwisF{align-items:center;display:flex;flex-direction:column}.titleWrapper-23lGwisF{align-items:center;display:flex;justify-content:center;margin-bottom:16px;max-width:100%}.title-23lGwisF{color:#131722;cursor:default;font-size:20px;font-weight:700;line-height:28px;overflow:hidden;white-space:nowrap}html.theme-dark .title-23lGwisF{color:#b2b5be}.infoHint-23lGwisF{color:#787b86;height:18px;margin-right:8px;width:18px}.form-23lGwisF{display:flex;max-width:200px;width:100%}.inputWrapper-23lGwisF{flex-grow:1}.input-23lGwisF{font-size:24px;text-align:center}.hint-23lGwisF{color:#787b86;cursor:default;font-size:12px;line-height:18px;margin-top:3px;max-width:100%;overflow:hidden;white-space:nowrap}.error-23lGwisF{color:#f23645}

View File

@ -0,0 +1 @@
.button-14c_DKWJ{align-items:center;background-color:initial;border:none;border-radius:2px;box-sizing:border-box;cursor:default;display:flex;flex:none;height:100%;justify-content:center;margin:0;outline:none!important;padding:0;width:21px}@media (any-hover:hover),(min--moz-device-pixel-ratio:0){.button-14c_DKWJ:hover:not(.disabled-14c_DKWJ){background-color:#f0f3fa}html.theme-dark .button-14c_DKWJ:hover:not(.disabled-14c_DKWJ){background-color:#363a45}}.button-14c_DKWJ.hidden-14c_DKWJ{display:none}.icon-14c_DKWJ{align-items:center;display:flex;flex:none;justify-content:center;transition:transform .35s ease}.icon-14c_DKWJ.dropped-14c_DKWJ{transform:rotate(180deg)}.button-1WqyvKNY{cursor:default;-webkit-user-select:none;user-select:none}.button-children-1WqyvKNY{display:block;overflow:hidden;padding:0 2px 0 6px;text-overflow:ellipsis;white-space:nowrap;width:100%}.button-children-1WqyvKNY.hiddenArrow-1WqyvKNY{padding-right:6px}.invisibleFocusHandler-1WqyvKNY{height:0;opacity:0;pointer-events:none;width:0}.placeholder-1J6emFeA{-webkit-text-fill-color:currentColor;color:#a3a6af;opacity:1}html.theme-dark .placeholder-1J6emFeA{color:#434651}

View File

@ -0,0 +1 @@
.button-14c_DKWJ{align-items:center;background-color:initial;border:none;border-radius:2px;box-sizing:border-box;cursor:default;display:flex;flex:none;height:100%;justify-content:center;margin:0;outline:none!important;padding:0;width:21px}@media (any-hover:hover),(min--moz-device-pixel-ratio:0){.button-14c_DKWJ:hover:not(.disabled-14c_DKWJ){background-color:#f0f3fa}html.theme-dark .button-14c_DKWJ:hover:not(.disabled-14c_DKWJ){background-color:#363a45}}.button-14c_DKWJ.hidden-14c_DKWJ{display:none}.icon-14c_DKWJ{align-items:center;display:flex;flex:none;justify-content:center;transition:transform .35s ease}.icon-14c_DKWJ.dropped-14c_DKWJ{transform:rotate(-180deg)}.button-1WqyvKNY{cursor:default;-webkit-user-select:none;user-select:none}.button-children-1WqyvKNY{display:block;overflow:hidden;padding:0 6px 0 2px;text-overflow:ellipsis;white-space:nowrap;width:100%}.button-children-1WqyvKNY.hiddenArrow-1WqyvKNY{padding-left:6px}.invisibleFocusHandler-1WqyvKNY{height:0;opacity:0;pointer-events:none;width:0}.placeholder-1J6emFeA{-webkit-text-fill-color:currentColor;color:#a3a6af;opacity:1}html.theme-dark .placeholder-1J6emFeA{color:#434651}

View File

@ -0,0 +1 @@
.wrapper-DggvOZTm{display:flex;flex:1 1 auto;height:100%;overflow:hidden}.container-DggvOZTm{-webkit-overflow-scrolling:touch;border-right:1px solid #e0e3eb;display:flex;flex:1 1 auto;flex:none;flex-direction:column;min-height:145px;overflow-x:hidden;overflow-y:auto;padding-bottom:6px;padding-top:6px;scrollbar-color:#9598a1 #0000;scrollbar-width:thin;width:200px}html.theme-dark .container-DggvOZTm{border-right:1px solid #434651;scrollbar-color:#363a45 #0000}@media screen and (max-height:290px){.container-DggvOZTm{min-height:auto}}.container-DggvOZTm::-webkit-scrollbar{height:5px;width:5px}.container-DggvOZTm::-webkit-scrollbar-thumb{background-color:#9598a1;border:1px solid #f0f3fa;border-radius:3px}html.theme-dark .container-DggvOZTm::-webkit-scrollbar-thumb{background-color:#363a45;border-color:#1e222d}.container-DggvOZTm::-webkit-scrollbar-track{background-color:initial;border-radius:3px}.container-DggvOZTm::-webkit-scrollbar-corner{display:none}.tab-DggvOZTm{align-items:center;color:#131722;display:flex;padding:6px 0 6px 20px}html.theme-dark .tab-DggvOZTm{color:#b2b5be}@media (any-hover:hover),(min--moz-device-pixel-ratio:0){.tab-DggvOZTm:hover{background-color:#f0f3fa}html.theme-dark .tab-DggvOZTm:hover{background-color:#2a2e39}}.tab-DggvOZTm.active-DggvOZTm,html.theme-dark .tab-DggvOZTm.active-DggvOZTm{background-color:#2962ff}.tab-DggvOZTm.active-DggvOZTm .icon-DggvOZTm,.tab-DggvOZTm.active-DggvOZTm .title-DggvOZTm{color:#fff}html.theme-dark .tab-DggvOZTm.active-DggvOZTm .icon-DggvOZTm,html.theme-dark .tab-DggvOZTm.active-DggvOZTm .title-DggvOZTm{color:#d1d4dc}.icon-DggvOZTm{height:28px;width:28px}.title-DggvOZTm{cursor:default;display:flex;font-size:14px;margin-left:8px;min-width:0;white-space:nowrap}.titleText-DggvOZTm{flex:0 100%;min-width:0;overflow:hidden;text-overflow:ellipsis}.nested-DggvOZTm{align-items:center;color:#787b86;display:flex;flex:1 1 auto;height:0;justify-content:flex-end;padding-right:8px}.isTablet-DggvOZTm.container-DggvOZTm{width:48px}.isTablet-DggvOZTm.tab-DggvOZTm{justify-content:center;padding-left:0}.isMobile-DggvOZTm.container-DggvOZTm{width:100%}.isMobile-DggvOZTm.tab-DggvOZTm{justify-content:flex-start;padding:0 0 0 20px}.isMobile-DggvOZTm.tab-DggvOZTm:last-child .title-DggvOZTm{border-bottom-width:0}.isMobile-DggvOZTm .title-DggvOZTm{align-items:center;border-bottom:1px solid #e0e3eb;display:flex;flex:1 1 auto;font-size:18px;padding-bottom:17px;padding-top:17px}html.theme-dark .isMobile-DggvOZTm .title-DggvOZTm{border-bottom-color:#434651}

View File

@ -0,0 +1 @@
.wrapper-DggvOZTm{display:flex;flex:1 1 auto;height:100%;overflow:hidden}.container-DggvOZTm{-webkit-overflow-scrolling:touch;border-left:1px solid #e0e3eb;display:flex;flex:1 1 auto;flex:none;flex-direction:column;min-height:145px;overflow-x:hidden;overflow-y:auto;padding-bottom:6px;padding-top:6px;scrollbar-color:#9598a1 #0000;scrollbar-width:thin;width:200px}html.theme-dark .container-DggvOZTm{border-left:1px solid #434651;scrollbar-color:#363a45 #0000}@media screen and (max-height:290px){.container-DggvOZTm{min-height:auto}}.container-DggvOZTm::-webkit-scrollbar{height:5px;width:5px}.container-DggvOZTm::-webkit-scrollbar-thumb{background-color:#9598a1;border:1px solid #f0f3fa;border-radius:3px}html.theme-dark .container-DggvOZTm::-webkit-scrollbar-thumb{background-color:#363a45;border-color:#1e222d}.container-DggvOZTm::-webkit-scrollbar-track{background-color:initial;border-radius:3px}.container-DggvOZTm::-webkit-scrollbar-corner{display:none}.tab-DggvOZTm{align-items:center;color:#131722;display:flex;padding:6px 20px 6px 0}html.theme-dark .tab-DggvOZTm{color:#b2b5be}@media (any-hover:hover),(min--moz-device-pixel-ratio:0){.tab-DggvOZTm:hover{background-color:#f0f3fa}html.theme-dark .tab-DggvOZTm:hover{background-color:#2a2e39}}.tab-DggvOZTm.active-DggvOZTm,html.theme-dark .tab-DggvOZTm.active-DggvOZTm{background-color:#2962ff}.tab-DggvOZTm.active-DggvOZTm .icon-DggvOZTm,.tab-DggvOZTm.active-DggvOZTm .title-DggvOZTm{color:#fff}html.theme-dark .tab-DggvOZTm.active-DggvOZTm .icon-DggvOZTm,html.theme-dark .tab-DggvOZTm.active-DggvOZTm .title-DggvOZTm{color:#d1d4dc}.icon-DggvOZTm{height:28px;width:28px}.title-DggvOZTm{cursor:default;display:flex;font-size:14px;margin-right:8px;min-width:0;white-space:nowrap}.titleText-DggvOZTm{flex:0 100%;min-width:0;overflow:hidden;text-overflow:ellipsis}.nested-DggvOZTm{align-items:center;color:#787b86;display:flex;flex:1 1 auto;height:0;justify-content:flex-end;padding-left:8px}.nested-DggvOZTm svg{transform:rotate(180deg)}.isTablet-DggvOZTm.container-DggvOZTm{width:48px}.isTablet-DggvOZTm.tab-DggvOZTm{justify-content:center;padding-right:0}.isMobile-DggvOZTm.container-DggvOZTm{width:100%}.isMobile-DggvOZTm.tab-DggvOZTm{justify-content:flex-start;padding:0 20px 0 0}.isMobile-DggvOZTm.tab-DggvOZTm:last-child .title-DggvOZTm{border-bottom-width:0}.isMobile-DggvOZTm .title-DggvOZTm{align-items:center;border-bottom:1px solid #e0e3eb;display:flex;flex:1 1 auto;font-size:18px;padding-bottom:17px;padding-top:17px}html.theme-dark .isMobile-DggvOZTm .title-DggvOZTm{border-bottom-color:#434651}

View File

@ -0,0 +1,2 @@
"use strict";(self.webpackChunktradingview=self.webpackChunktradingview||[]).push([[306],{49775:(e,t,n)=>{n.d(t,{Icon:()=>i});var o=n(67294);const i=o.forwardRef((e,t)=>{const{icon:n="",...i}=e;return o.createElement("span",{...i,ref:t,dangerouslySetInnerHTML:{__html:n}})})},75761:(e,t,n)=>{n.d(t,{setFixedBodyState:()=>a});const o=(()=>{let e;return()=>{var t;if(void 0===e){const n=document.createElement("div"),o=n.style;o.visibility="hidden",o.width="100px",o.msOverflowStyle="scrollbar",document.body.appendChild(n);const i=n.offsetWidth;n.style.overflow="scroll";const s=document.createElement("div");s.style.width="100%",n.appendChild(s);const r=s.offsetWidth;null===(t=n.parentNode)||void 0===t||t.removeChild(n),e=i-r}return e}})();function i(e,t,n){null!==e&&e.style.setProperty(t,n)}function s(e,t){return getComputedStyle(e,null).getPropertyValue(t)}function r(e,t){return parseInt(s(e,t))}let d=0,l=!1;function a(e){const{body:t}=document,n=t.querySelector(".widgetbar-wrap");if(e&&1==++d){const e=s(t,"overflow"),d=r(t,"padding-right");"hidden"!==e.toLowerCase()&&t.scrollHeight>t.offsetHeight&&(i(n,"right",o()+"px"),t.style.paddingRight=d+o()+"px",l=!0),t.classList.add("i-no-scroll")}else if(!e&&d>0&&0==--d&&(t.classList.remove("i-no-scroll"),l)){i(n,"right","0px");let e=0;0,t.scrollHeight<=t.clientHeight&&(e-=o()),t.style.paddingRight=(e<0?0:e)+"px",l=!1}}},47165:(e,t,n)=>{n.d(t,{useOutsideEvent:()=>s});var o=n(67294),i=n(59726);function s(e){const{click:t,mouseDown:n,touchEnd:s,touchStart:r,handler:d,reference:l,ownerDocument:a=document}=e,c=(0,o.useRef)(null),h=(0,o.useRef)(new CustomEvent("timestamp").timeStamp);return(0,o.useLayoutEffect)(()=>{const e={click:t,mouseDown:n,touchEnd:s,touchStart:r},o=l?l.current:c.current;return(0,i.addOutsideEventListener)(h.current,o,d,a,e)},[t,n,s,r,d]),l||c}},90071:(e,t,n)=>{n.d(t,{OverlapManager:()=>s,getRootOverlapManager:()=>d});var o=n(16282);class i{constructor(){this._storage=[]}add(e){this._storage.push(e)}remove(e){this._storage=this._storage.filter(t=>e!==t)}has(e){return this._storage.includes(e)}getItems(){return this._storage}}class s{constructor(e=document){this._storage=new i,this._windows=new Map,this._index=0,this._document=e,this._container=e.createDocumentFragment()}setContainer(e){const t=this._container,n=null===e?this._document.createDocumentFragment():e;!function(e,t){Array.from(e.childNodes).forEach(e=>{e.nodeType===Node.ELEMENT_NODE&&t.appendChild(e)})}(t,n),this._container=n}registerWindow(e){this._storage.has(e)||this._storage.add(e)}ensureWindow(e,t={position:"fixed",direction:"normal"}){const n=this._windows.get(e);if(void 0!==n)return n;this.registerWindow(e);const o=this._document.createElement("div");if(o.style.position=t.position,o.style.zIndex=this._index.toString(),o.dataset.id=e,void 0!==t.index){const e=this._container.childNodes.length;if(t.index>=e)this._container.appendChild(o);else if(t.index<=0)this._container.insertBefore(o,this._container.firstChild);else{const e=this._container.childNodes[t.index];this._container.insertBefore(o,e)}
}else"reverse"===t.direction?this._container.insertBefore(o,this._container.firstChild):this._container.appendChild(o);return this._windows.set(e,o),++this._index,o}unregisterWindow(e){this._storage.remove(e);const t=this._windows.get(e);void 0!==t&&(null!==t.parentElement&&t.parentElement.removeChild(t),this._windows.delete(e))}getZindex(e){const t=this.ensureWindow(e);return parseInt(t.style.zIndex||"0")}moveToTop(e){if(this.getZindex(e)!==this._index){this.ensureWindow(e).style.zIndex=(++this._index).toString()}}removeWindow(e){this.unregisterWindow(e)}}const r=new WeakMap;function d(e=document){const t=e.getElementById("overlap-manager-root");if(null!==t)return(0,o.ensureDefined)(r.get(t));{const t=new s(e),n=function(e){const t=e.createElement("div");return t.style.position="absolute",t.style.zIndex=150..toString(),t.style.top="0px",t.style.left="0px",t.id="overlap-manager-root",t}(e);return r.set(n,t),t.setContainer(n),e.body.appendChild(n),t}}},4735:(e,t,n)=>{n.d(t,{Portal:()=>l,PortalContext:()=>a});var o=n(67294),i=n(73935),s=n(45259),r=n(90071),d=n(78106);class l extends o.PureComponent{constructor(){super(...arguments),this._uuid=(0,s.guid)()}componentWillUnmount(){this._manager().removeWindow(this._uuid)}render(){const e=this._manager().ensureWindow(this._uuid,this.props.layerOptions);return e.style.top=this.props.top||"",e.style.bottom=this.props.bottom||"",e.style.left=this.props.left||"",e.style.right=this.props.right||"",e.style.pointerEvents=this.props.pointerEvents||"",i.createPortal(o.createElement(a.Provider,{value:this},this.props.children),e)}moveToTop(){this._manager().moveToTop(this._uuid)}_manager(){return null===this.context?(0,r.getRootOverlapManager)():this.context}}l.contextType=d.SlotContext;const a=o.createContext(null)},78106:(e,t,n)=>{n.d(t,{Slot:()=>i,SlotContext:()=>s});var o=n(67294);class i extends o.Component{shouldComponentUpdate(){return!1}render(){return o.createElement("div",{style:{position:"fixed",zIndex:150,left:0,top:0},ref:this.props.reference})}}const s=o.createContext(null)}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,3 @@
(self.webpackChunktradingview=self.webpackChunktradingview||[]).push([[3463],{67891:function(e,t){var o,n,r;n=[t],void 0===(r="function"==typeof(o=function(e){"use strict";function t(e){if(Array.isArray(e)){for(var t=0,o=Array(e.length);t<e.length;t++)o[t]=e[t];return o}return Array.from(e)}Object.defineProperty(e,"__esModule",{value:!0});var o=!1;if("undefined"!=typeof window){var n={get passive(){o=!0}};window.addEventListener("testPassive",null,n),window.removeEventListener("testPassive",null,n)}var r="undefined"!=typeof window&&window.navigator&&window.navigator.platform&&/iP(ad|hone|od)/.test(window.navigator.platform),l=[],i=!1,c=-1,a=void 0,s=void 0,u=function(e){return l.some((function(t){return!(!t.options.allowTouchMove||!t.options.allowTouchMove(e))}))},d=function(e){var t=e||window.event;return!!u(t.target)||1<t.touches.length||(t.preventDefault&&t.preventDefault(),!1)},v=function(){setTimeout((function(){void 0!==s&&(document.body.style.paddingRight=s,s=void 0),void 0!==a&&(document.body.style.overflow=a,a=void 0)}))};e.disableBodyScroll=function(e,n){if(r){if(!e)return void console.error("disableBodyScroll unsuccessful - targetElement must be provided when calling disableBodyScroll on IOS devices.");if(e&&!l.some((function(t){return t.targetElement===e}))){var v={targetElement:e,options:n||{}};l=[].concat(t(l),[v]),e.ontouchstart=function(e){1===e.targetTouches.length&&(c=e.targetTouches[0].clientY)},e.ontouchmove=function(t){var o,n,r,l;1===t.targetTouches.length&&(n=e,l=(o=t).targetTouches[0].clientY-c,!u(o.target)&&(n&&0===n.scrollTop&&0<l||(r=n)&&r.scrollHeight-r.scrollTop<=r.clientHeight&&l<0?d(o):o.stopPropagation()))},i||(document.addEventListener("touchmove",d,o?{passive:!1}:void 0),i=!0)}}else{m=n,setTimeout((function(){if(void 0===s){var e=!!m&&!0===m.reserveScrollBarGap,t=window.innerWidth-document.documentElement.clientWidth;e&&0<t&&(s=document.body.style.paddingRight,document.body.style.paddingRight=t+"px")}void 0===a&&(a=document.body.style.overflow,document.body.style.overflow="hidden")}));var f={targetElement:e,options:n||{}};l=[].concat(t(l),[f])}var m},e.clearAllBodyScrollLocks=function(){r?(l.forEach((function(e){e.targetElement.ontouchstart=null,e.targetElement.ontouchmove=null})),i&&(document.removeEventListener("touchmove",d,o?{passive:!1}:void 0),i=!1),l=[],c=-1):(v(),l=[])},e.enableBodyScroll=function(e){if(r){if(!e)return void console.error("enableBodyScroll unsuccessful - targetElement must be provided when calling enableBodyScroll on IOS devices.");e.ontouchstart=null,e.ontouchmove=null,l=l.filter((function(t){return t.targetElement!==e})),i&&0===l.length&&(document.removeEventListener("touchmove",d,o?{passive:!1}:void 0),i=!1)}else 1===l.length&&l[0].targetElement===e?(v(),l=[]):l=l.filter((function(t){return t.targetElement!==e}))}})?o.apply(t,n):o)||(e.exports=r)},32550:e=>{e.exports={item:"item-21ifTYt7",label:"label-21ifTYt7",labelRow:"labelRow-21ifTYt7",toolbox:"toolbox-21ifTYt7"}},66549:e=>{e.exports={"tablet-small-breakpoint":"screen and (max-width: 428px)",
item:"item-2IihgTnv",hovered:"hovered-2IihgTnv",isDisabled:"isDisabled-2IihgTnv",isActive:"isActive-2IihgTnv",shortcut:"shortcut-2IihgTnv",toolbox:"toolbox-2IihgTnv",withIcon:"withIcon-2IihgTnv",icon:"icon-2IihgTnv",labelRow:"labelRow-2IihgTnv",label:"label-2IihgTnv",showOnHover:"showOnHover-2IihgTnv"}},78706:e=>{e.exports={separator:"separator-eqcGT_ow",small:"small-eqcGT_ow",normal:"normal-eqcGT_ow",large:"large-eqcGT_ow"}},53178:(e,t,o)=>{"use strict";o.d(t,{validateRegistry:()=>c,RegistryProvider:()=>a,registryContextType:()=>s});var n=o(67294),r=o(45697),l=o.n(r);const i=n.createContext({});function c(e,t){l().checkPropTypes(t,e,"context","RegistryContext")}function a(e){const{validation:t,value:o}=e;return c(o,t),n.createElement(i.Provider,{value:o},e.children)}function s(){return i}},11086:(e,t,o)=>{"use strict";o.d(t,{hoverMouseEventFilter:()=>l,useAccurateHover:()=>i,useHover:()=>r});var n=o(67294);function r(){const[e,t]=(0,n.useState)(!1);return[e,{onMouseOver:function(e){l(e)&&t(!0)},onMouseOut:function(e){l(e)&&t(!1)}}]}function l(e){return!e.currentTarget.contains(e.relatedTarget)}function i(e){const[t,o]=(0,n.useState)(!1);return(0,n.useEffect)(()=>{const t=t=>{if(null===e.current)return;const n=e.current.contains(t.target);o(n)};return document.addEventListener("mouseover",t),()=>document.removeEventListener("mouseover",t)},[]),t}},95860:(e,t,o)=>{"use strict";o.d(t,{DEFAULT_POPUP_MENU_ITEM_THEME:()=>s,PopupMenuItem:()=>v});var n=o(67294),r=o(94184),l=o(79424),i=o(87438),c=o(74818),a=o(66549);const s=a;function u(e){const{reference:t,...o}=e,r={...o,ref:t};return n.createElement(e.href?"a":"div",r)}function d(e){e.stopPropagation()}function v(e){const{id:t,role:o,"aria-selected":s,className:v,title:f,labelRowClassName:m,labelClassName:h,shortcut:g,forceShowShortcuts:p,icon:b,isActive:w,isDisabled:E,isHovered:T,appearAsDisabled:y,label:C,link:k,showToolboxOnHover:O,target:x,rel:M,toolbox:I,reference:S,onMouseOut:P,onMouseOver:N,suppressToolboxClick:A=!0,theme:R=a}=e,_=(0,c.filterDataProps)(e),D=(0,n.useRef)(null);return n.createElement(u,{..._,id:t,role:o,"aria-selected":s,className:r(v,R.item,b&&R.withIcon,{[R.isActive]:w,[R.isDisabled]:E||y,[R.hovered]:T}),title:f,href:k,target:x,rel:M,reference:function(e){D.current=e,"function"==typeof S&&S(e);"object"==typeof S&&(S.current=e)},onClick:function(t){const{dontClosePopup:o,onClick:n,onClickArg:r,trackEventObject:c}=e;if(E)return;c&&(0,i.trackEvent)(c.category,c.event,c.label);n&&n(r,t);o||(0,l.globalCloseMenu)()},onContextMenu:function(t){const{trackEventObject:o,trackRightClick:n}=e;o&&n&&(0,i.trackEvent)(o.category,o.event,o.label+"_rightClick")},onMouseUp:function(t){const{trackEventObject:o,trackMouseWheelClick:n}=e;if(1===t.button&&k&&o){let e=o.label;n&&(e+="_mouseWheelClick"),(0,i.trackEvent)(o.category,o.event,e)}},onMouseOver:N,onMouseOut:P},void 0!==b&&n.createElement("div",{className:R.icon,dangerouslySetInnerHTML:{__html:b}}),n.createElement("div",{className:r(R.labelRow,m)},n.createElement("div",{className:r(R.label,h)
},C)),(void 0!==g||p)&&n.createElement("div",{className:R.shortcut},(H=g)&&H.split("+").join(" + ")),void 0!==I&&n.createElement("div",{onClick:A?d:void 0,className:r(R.toolbox,{[R.showOnHover]:O})},I));var H}},82879:(e,t,o)=>{"use strict";o.d(t,{multilineLabelWithIconAndToolboxTheme:()=>i});var n=o(4598),r=o(66549),l=o(32550);const i=(0,n.mergeThemes)(r,l)},10869:(e,t,o)=>{"use strict";o.d(t,{PopupMenuSeparator:()=>c});var n=o(67294),r=o(94184),l=o.n(r),i=o(78706);function c(e){const{size:t="normal",className:o}=e;return n.createElement("div",{className:l()(i.separator,"small"===t&&i.small,"normal"===t&&i.normal,"large"===t&&i.large,o)})}},76420:(e,t,o)=>{"use strict";o.d(t,{PopupMenu:()=>s});var n=o(67294),r=o(73935),l=o(4735),i=o(90901),c=o(94884),a=o(47165);function s(e){const{controller:t,children:o,isOpened:s,closeOnClickOutside:u=!0,doNotCloseOn:d,onClickOutside:v,onClose:f,...m}=e,h=(0,n.useContext)(c.CloseDelegateContext),g=(0,a.useOutsideEvent)({handler:function(e){v&&v(e);if(!u)return;if(d&&e.target instanceof Node){const t=r.findDOMNode(d);if(t instanceof Node&&t.contains(e.target))return}f()},mouseDown:!0,touchStart:!0});return s?n.createElement(l.Portal,{top:"0",left:"0",right:"0",bottom:"0",pointerEvents:"none"},n.createElement("span",{ref:g,style:{pointerEvents:"auto"}},n.createElement(i.Menu,{...m,onClose:f,onScroll:function(t){const{onScroll:o}=e;o&&o(t)},customCloseDelegate:h,ref:t},o))):null}}}]);

Some files were not shown because too many files have changed in this diff Show More