diff --git a/src/containers/Accounts/AMM/AMMAccounts/AMMAccountHeader/AMMAccountHeader.tsx b/src/containers/Accounts/AMM/AMMAccounts/AMMAccountHeader/AMMAccountHeader.tsx
index 09de6edd5..872bb1263 100644
--- a/src/containers/Accounts/AMM/AMMAccounts/AMMAccountHeader/AMMAccountHeader.tsx
+++ b/src/containers/Accounts/AMM/AMMAccounts/AMMAccountHeader/AMMAccountHeader.tsx
@@ -1,7 +1,5 @@
import { useTranslation } from 'react-i18next'
-import '../../../../shared/css/nested-menu.scss'
import '../../../AccountHeader/styles.scss'
-import '../../../AccountHeader/balance-selector.scss'
import {
formatTradingFee,
localizeBalance,
diff --git a/src/containers/Accounts/AccountHeader/BalanceSelector.jsx b/src/containers/Accounts/AccountHeader/BalanceSelector.jsx
deleted file mode 100644
index b073338d8..000000000
--- a/src/containers/Accounts/AccountHeader/BalanceSelector.jsx
+++ /dev/null
@@ -1,91 +0,0 @@
-import PropTypes from 'prop-types'
-import { localizeNumber } from '../../shared/utils'
-import IconDownArrow from '../../shared/images/down_arrow.svg'
-import iconClose from '../../shared/images/close.png'
-import Currency from '../../shared/components/Currency'
-import '../../shared/css/nested-menu.scss'
-import './styles.scss'
-import './balance-selector.scss'
-
-const BalanceSelector = ({
- language,
- text,
- balances,
- onClick,
- expandMenu,
- onMouseLeave,
- onSetCurrencySelected,
- currencySelected,
-}) => {
- const balanceMenuItems = Object.entries(balances).map(([currency, value]) => {
- if (currency === currencySelected) {
- return null
- }
- const formattedValue =
- localizeNumber(value, language, {
- style: 'currency',
- currency,
- minimumFractionDigits: 0,
- maximumFractionDigits: 2,
- }) || '0.00'
- return (
-
- )
- })
- return (
-
setTimeout(onMouseLeave, 2000)}
- >
-
- {expandMenu &&
{balanceMenuItems}
}
-
- )
-}
-
-BalanceSelector.propTypes = {
- language: PropTypes.string.isRequired,
- text: PropTypes.string.isRequired,
- expandMenu: PropTypes.bool.isRequired,
- balances: PropTypes.shape({}).isRequired,
- onClick: PropTypes.func.isRequired,
- onMouseLeave: PropTypes.func.isRequired,
- onSetCurrencySelected: PropTypes.func.isRequired,
- currencySelected: PropTypes.string.isRequired,
-}
-
-export default BalanceSelector
diff --git a/src/containers/Accounts/AccountHeader/BalanceSelector/BalanceSelector.tsx b/src/containers/Accounts/AccountHeader/BalanceSelector/BalanceSelector.tsx
new file mode 100644
index 000000000..a73ff4dca
--- /dev/null
+++ b/src/containers/Accounts/AccountHeader/BalanceSelector/BalanceSelector.tsx
@@ -0,0 +1,40 @@
+import { useTranslation } from 'react-i18next'
+import { Dropdown } from '../../../shared/components/Dropdown'
+import { BalanceSelectorItem } from './BalanceSelectorItem'
+import './balance-selector.scss'
+
+export interface BalanceSelectorProps {
+ balances: { [currency: string]: string }
+ onSetCurrencySelected: (currency: string) => void
+ currencySelected: string
+}
+
+export const BalanceSelector = ({
+ balances,
+ onSetCurrencySelected,
+ currencySelected,
+}: BalanceSelectorProps) => {
+ const { t } = useTranslation()
+ const balanceTuples = Object.entries(balances)
+ const title = `${balanceTuples.length - 1} ${t('accounts.other_balances')}`
+
+ return (
+
+ {balanceTuples.map(([currency, value]) => {
+ if (currency === currencySelected) {
+ return <>>
+ }
+
+ return (
+ {
+ onSetCurrencySelected(currency)
+ }}
+ value={value}
+ />
+ )
+ })}
+
+ )
+}
diff --git a/src/containers/Accounts/AccountHeader/BalanceSelector/BalanceSelectorItem.tsx b/src/containers/Accounts/AccountHeader/BalanceSelector/BalanceSelectorItem.tsx
new file mode 100644
index 000000000..27a7da75c
--- /dev/null
+++ b/src/containers/Accounts/AccountHeader/BalanceSelector/BalanceSelectorItem.tsx
@@ -0,0 +1,32 @@
+import React from 'react'
+import { useLanguage } from '../../../shared/hooks'
+import { CURRENCY_OPTIONS } from '../../../shared/transactionUtils'
+import { localizeNumber } from '../../../shared/utils'
+import { DropdownItem } from '../../../shared/components/Dropdown'
+import Currency from '../../../shared/components/Currency'
+
+export interface BalanceSelectorItemProps {
+ currency: string
+ handler: (currency) => void
+ value: string
+}
+
+export const BalanceSelectorItem = React.memo(
+ ({ currency, value, handler }: BalanceSelectorItemProps) => {
+ const language = useLanguage()
+ const options = {
+ ...CURRENCY_OPTIONS,
+ currency,
+ minimumFractionDigits: 0,
+ maximumFractionDigits: 2,
+ }
+ const formattedValue = localizeNumber(value, language, options) || '0.00'
+
+ return (
+
+
+ {formattedValue}
+
+ )
+ },
+)
diff --git a/src/containers/Accounts/AccountHeader/BalanceSelector/balance-selector.scss b/src/containers/Accounts/AccountHeader/BalanceSelector/balance-selector.scss
new file mode 100644
index 000000000..dc6c77018
--- /dev/null
+++ b/src/containers/Accounts/AccountHeader/BalanceSelector/balance-selector.scss
@@ -0,0 +1,32 @@
+@import 'src/containers/shared/css/variables';
+
+.balance-selector {
+ position: relative;
+ display: block;
+ width: 100%;
+
+ @include for-size(tablet-landscape-up) {
+ width: 280px;
+ }
+
+ .dropdown-toggle {
+ padding: 12px 16px;
+ }
+
+ .dropdown-menu {
+ width: 100%;
+ }
+
+ .dropdown-item {
+ display: flex;
+ }
+
+ .currency {
+ font-weight: bold;
+ }
+
+ .total-balance {
+ margin-left: auto;
+ color: $black-40;
+ }
+}
diff --git a/src/containers/Accounts/AccountHeader/balance-selector.scss b/src/containers/Accounts/AccountHeader/balance-selector.scss
deleted file mode 100644
index 6a0668340..000000000
--- a/src/containers/Accounts/AccountHeader/balance-selector.scss
+++ /dev/null
@@ -1,98 +0,0 @@
-@import '../../shared/css/variables';
-
-.balance-selector {
- position: relative;
- display: block;
- width: 100%;
-
- @include for-size(tablet-landscape-up) {
- width: 280px;
- }
-
- .balance-selector-button {
- position: relative;
- display: block;
- width: 100%;
- outline: inherit;
- text-align: left;
-
- @include for-size(desktop-up) {
- font-size: 16px;
- }
- }
-
- .menu-item {
- width: 100%;
- padding: 8px 16px;
- border-style: none;
- background-color: $black;
- color: $white;
- cursor: pointer;
- font-size: 14px;
- outline: none;
-
- &:hover {
- background-color: $black-80;
- color: $green;
- }
-
- @include for-size(desktop-up) {
- padding: 8px 16px;
- font-size: 16px;
- }
- }
-
- .menu-item-currency {
- @include bold;
- }
-
- .menu-item > div {
- overflow: hidden;
- max-width: 50%;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
-
- .selector-text {
- display: inline-block;
- padding: 2px 0px;
- margin-right: 8px;
- @include medium;
- }
-
- .selector-icon {
- display: inline-block;
- width: 18px;
- height: 16px;
- margin: 4px 0px;
- color: $black-40;
- vertical-align: middle;
-
- @include for-size(desktop-up) {
- float: right;
- }
-
- &.selector-icon-close {
- width: 14px;
- height: 14px;
- }
- }
-
- &.is-active {
- .balance-selector-button {
- z-index: 100001;
- }
-
- .nested-items {
- position: absolute;
- z-index: 100000;
- right: 0;
- height: auto;
- border: 1px solid $black-70;
- border-radius: 9px;
- background-color: $black;
- box-shadow: 0px 0px 5px 0px $black-70;
- color: $black-40;
- }
- }
-}
diff --git a/src/containers/Accounts/AccountHeader/index.tsx b/src/containers/Accounts/AccountHeader/index.tsx
index 0017f2808..fad5ac628 100644
--- a/src/containers/Accounts/AccountHeader/index.tsx
+++ b/src/containers/Accounts/AccountHeader/index.tsx
@@ -1,13 +1,11 @@
-import { useContext, useState, useEffect } from 'react'
+import { useContext, useEffect } from 'react'
import { useTranslation } from 'react-i18next'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { loadAccountState } from './actions'
import Loader from '../../shared/components/Loader'
-import '../../shared/css/nested-menu.scss'
import './styles.scss'
-import './balance-selector.scss'
-import BalanceSelector from './BalanceSelector'
+import { BalanceSelector } from './BalanceSelector/BalanceSelector'
import { Account } from '../../shared/components/Account'
import { localizeNumber } from '../../shared/utils'
import SocketContext from '../../shared/SocketContext'
@@ -22,7 +20,7 @@ const CURRENCY_OPTIONS = {
}
interface AccountHeaderProps {
- onSetCurrencySelected: Function
+ onSetCurrencySelected: (currency: string) => void
currencySelected: string
loading: boolean
accountId: string
@@ -69,7 +67,6 @@ interface AccountHeaderProps {
}
const AccountHeader = (props: AccountHeaderProps) => {
- const [showBalanceSelector, setShowBalanceSelector] = useState(false)
const { t } = useTranslation()
const rippledSocket = useContext(SocketContext)
const language = useLanguage()
@@ -87,27 +84,14 @@ const AccountHeader = (props: AccountHeaderProps) => {
actions.loadAccountState(accountId, rippledSocket)
}, [accountId, actions, rippledSocket])
- function toggleBalanceSelector(force?) {
- setShowBalanceSelector(force !== undefined ? force : !showBalanceSelector)
- }
-
function renderBalancesSelector() {
const { balances = {} } = data
return (
Object.keys(balances).length > 1 && (
toggleBalanceSelector()}
- onMouseLeave={() => toggleBalanceSelector(false)}
- onSetCurrencySelected={(currency) =>
- onSetCurrencySelected(currency)
- }
+ onSetCurrencySelected={onSetCurrencySelected}
currencySelected={currencySelected}
/>
diff --git a/src/containers/Accounts/AccountHeader/styles.scss b/src/containers/Accounts/AccountHeader/styles.scss
index 25c15732b..4e810d5a3 100644
--- a/src/containers/Accounts/AccountHeader/styles.scss
+++ b/src/containers/Accounts/AccountHeader/styles.scss
@@ -149,7 +149,6 @@
.secondary {
padding: 0px 8px;
margin-bottom: 20px;
- color: $black-40;
font-size: 12px;
@include bold;
diff --git a/src/containers/Accounts/test/index.test.js b/src/containers/Accounts/test/index.test.js
index a071260fd..ec6ff57f0 100644
--- a/src/containers/Accounts/test/index.test.js
+++ b/src/containers/Accounts/test/index.test.js
@@ -52,7 +52,7 @@ describe('Account container', () => {
wrapper.update()
expect(wrapper.find(AccountHeader).length).toBe(1)
expect(wrapper.find(AccountTransactionTable).length).toBe(1)
- wrapper.find('.balance-selector-button').simulate('click')
+ wrapper.find('.balance-selector button').simulate('click')
wrapper.unmount()
})
})
diff --git a/src/containers/Header/menu.scss b/src/containers/Header/menu.scss
index 066ad5265..1bdc2f09a 100644
--- a/src/containers/Header/menu.scss
+++ b/src/containers/Header/menu.scss
@@ -42,51 +42,6 @@
}
}
- .nested-menu {
- position: relative;
- display: inline-block;
- padding: 8px 20px 18px 16px;
- margin-left: 4px;
- cursor: pointer;
-
- .title {
- margin-right: 10px;
- }
-
- .arrow {
- position: relative;
- top: 1px;
- }
-
- .menu-item {
- display: block;
- }
-
- .nested-items {
- position: absolute;
- top: 35px;
- left: -8px;
- padding: 8px 1px;
- border-radius: 4px;
- background-color: $white;
- box-shadow: 0px 0px 5px 0px rgb(35 41 47 / 24%);
-
- .menu-item {
- text-align: left;
- }
- }
-
- .vertical {
- margin-bottom: 1px;
-
- &:hover,
- &:focus {
- background-color: $black-70;
- color: $black-70;
- }
- }
- }
-
.horizontal-selected,
.vertical-selected {
color: $white;
diff --git a/src/containers/NFT/NFTHeader/NFTHeader.tsx b/src/containers/NFT/NFTHeader/NFTHeader.tsx
index 741d88091..c9ffa8784 100644
--- a/src/containers/NFT/NFTHeader/NFTHeader.tsx
+++ b/src/containers/NFT/NFTHeader/NFTHeader.tsx
@@ -2,7 +2,6 @@ import { useEffect, useContext, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useQuery } from 'react-query'
import Loader from '../../shared/components/Loader'
-import '../../shared/css/nested-menu.scss'
import './styles.scss'
import SocketContext from '../../shared/SocketContext'
import Tooltip from '../../shared/components/Tooltip'
diff --git a/src/containers/PayStrings/PayStringHeader/index.tsx b/src/containers/PayStrings/PayStringHeader/index.tsx
index 182e2329a..9c85c55ed 100644
--- a/src/containers/PayStrings/PayStringHeader/index.tsx
+++ b/src/containers/PayStrings/PayStringHeader/index.tsx
@@ -3,7 +3,6 @@ import { useTranslation } from 'react-i18next'
import PayStringLogomark from '../../shared/images/PayString_Logomark.png'
import QuestIcon from '../../shared/images/hover_question.svg'
import Tooltip from '../../shared/components/Tooltip'
-import '../../shared/css/nested-menu.scss'
import './styles.scss'
import { useLanguage } from '../../shared/hooks'
diff --git a/src/containers/Token/TokenHeader/index.tsx b/src/containers/Token/TokenHeader/index.tsx
index d83b08376..2059bde35 100644
--- a/src/containers/Token/TokenHeader/index.tsx
+++ b/src/containers/Token/TokenHeader/index.tsx
@@ -5,7 +5,6 @@ import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { loadTokenState } from './actions'
import Loader from '../../shared/components/Loader'
-import '../../shared/css/nested-menu.scss'
import './styles.scss'
import { localizeNumber, formatLargeNumber } from '../../shared/utils'
import SocketContext from '../../shared/SocketContext'
diff --git a/src/containers/shared/components/Dropdown/Dropdown.tsx b/src/containers/shared/components/Dropdown/Dropdown.tsx
new file mode 100644
index 000000000..86a957500
--- /dev/null
+++ b/src/containers/shared/components/Dropdown/Dropdown.tsx
@@ -0,0 +1,83 @@
+import classnames from 'classnames'
+import { useCallback, useEffect, useRef, useState } from 'react'
+import ArrowIcon from '../../images/down_arrow.svg'
+import './dropdown.scss'
+
+export interface DropdownProps {
+ title: string | JSX.Element
+ children: any
+ className?: string
+}
+
+// TODO: Add useId after upgrading to react@18 to populate id on .dropdown-menu and aria-controlled by on .dropdown-toggle
+/**
+ * A simple dropdown that has auto closing
+ *
+ * @param title The value in the toggle
+ * @param children The contents of the menu. DropdownItem is the preferred child component
+ * @param className
+ * @constructor
+ *
+ * @example
+ *
+ * alert('hello')}>Option 1
+ * Option 2
+ *
+ */
+export const Dropdown = ({ title, children, className }: DropdownProps) => {
+ const [expanded, setExpanded] = useState(false)
+ const dropdownRef = useRef(null)
+
+ const globalClickListener = useCallback((nativeEvent) => {
+ // ignore click event happened inside the dropdown menu
+ if (dropdownRef.current && dropdownRef.current.contains(nativeEvent.target))
+ return
+ // else hide dropdown menu
+ setExpanded(false)
+ document.removeEventListener('click', globalClickListener)
+ }, [])
+
+ useEffect(
+ (): (() => void) => () =>
+ // remove listener when cleaning up component
+ document.removeEventListener('click', globalClickListener),
+ [globalClickListener],
+ )
+
+ const toggleExpand = () => {
+ // don't de-expand if clicking in the textbox
+ setExpanded((prevExpanded) => !prevExpanded)
+ document.addEventListener('click', globalClickListener)
+ }
+
+ return (
+
+
+
+ {children}
+
+
+ )
+}
diff --git a/src/containers/shared/components/Dropdown/DropdownItem.tsx b/src/containers/shared/components/Dropdown/DropdownItem.tsx
new file mode 100644
index 000000000..2e79bee8a
--- /dev/null
+++ b/src/containers/shared/components/Dropdown/DropdownItem.tsx
@@ -0,0 +1,30 @@
+import { PropsWithChildren } from 'react'
+import classnames from 'classnames'
+
+export type DropdownItemProps = PropsWithChildren<{
+ className?: string
+ handler?: (event) => void
+ href?: string
+}>
+
+export const DropdownItem = ({
+ children,
+ className,
+ handler,
+ href,
+}: DropdownItemProps) => {
+ const Tag = handler || href ? `a` : `div`
+
+ return (
+
+ {children}
+
+ )
+}
diff --git a/src/containers/shared/components/Dropdown/dropdown.scss b/src/containers/shared/components/Dropdown/dropdown.scss
new file mode 100644
index 000000000..3df19eaf5
--- /dev/null
+++ b/src/containers/shared/components/Dropdown/dropdown.scss
@@ -0,0 +1,91 @@
+@import '../../css/variables';
+
+.dropdown {
+ position: relative;
+ display: inline-block;
+ font-size: 14px;
+ white-space: nowrap;
+}
+
+.dropdown-toggle {
+ display: flex;
+ align-items: center;
+ padding: 8px;
+ border: solid 1px $white;
+ border-radius: 100px;
+ cursor: pointer;
+ font-weight: 700;
+ gap: 0 24px;
+
+ .arrow {
+ height: 1em;
+ margin-left: auto;
+ }
+}
+
+.dropdown-menu {
+ position: absolute;
+ z-index: 100;
+ display: none;
+ min-width: max(100%, 160px);
+ padding: 8px;
+ border: 1px solid $black-80;
+ border-radius: 8px;
+ margin-top: 5px;
+ background: rgba($black, 0.96);
+}
+
+.dropdown-item {
+ padding: 12px 8px;
+ border-radius: 4px;
+ font-weight: normal;
+
+ @at-root {
+ a#{&} {
+ display: flex;
+ align-items: center;
+ color: $white;
+ gap: 0 12px;
+
+ &::after {
+ display: none;
+ }
+
+ &:hover {
+ background: $black-80;
+ cursor: pointer;
+ }
+ }
+ }
+
+ input {
+ width: 100%;
+ padding: 8px;
+ border: none;
+ border-radius: 4px;
+ background: $black-80;
+ color: $white;
+ font-size: inherit;
+
+ &::placeholder {
+ color: $black-40;
+ }
+ }
+
+ .btn-remove {
+ padding: 8px;
+ margin-left: auto;
+ background: url('../../images/close.png') center no-repeat;
+ background-size: 8px;
+ }
+}
+
+.dropdown-expanded {
+ .arrow {
+ transform: rotate(180deg);
+ }
+
+ .dropdown-menu {
+ display: block;
+ }
+}
diff --git a/src/containers/shared/components/Dropdown/index.ts b/src/containers/shared/components/Dropdown/index.ts
new file mode 100644
index 000000000..c57e9ce86
--- /dev/null
+++ b/src/containers/shared/components/Dropdown/index.ts
@@ -0,0 +1,2 @@
+export * from './Dropdown'
+export * from './DropdownItem'
diff --git a/src/containers/shared/components/Dropdown/test/Dropdown.test.tsx b/src/containers/shared/components/Dropdown/test/Dropdown.test.tsx
new file mode 100644
index 000000000..431a213b5
--- /dev/null
+++ b/src/containers/shared/components/Dropdown/test/Dropdown.test.tsx
@@ -0,0 +1,91 @@
+import { mount } from 'enzyme'
+import { Dropdown } from '../Dropdown'
+
+describe('Dropdown', () => {
+ let sandbox
+
+ beforeAll(() => {
+ sandbox = document.createElement('div')
+ document.body.appendChild(sandbox)
+ })
+
+ afterAll(() => {
+ if (sandbox) {
+ document.body.removeChild(sandbox)
+ }
+ })
+
+ describe('prop: title', () => {
+ it('renders when it is jsx', () => {
+ const title = Woo
+ const wrapper = mount(Menu Contents)
+ expect(wrapper.find('.title-component')).toExist()
+ expect(wrapper.find('.title-component')).toHaveText('Woo')
+ wrapper.unmount()
+ })
+ it('renders when it is a string', () => {
+ const title = 'Woo'
+ const wrapper = mount(Menu Contents)
+ expect(wrapper.find('.dropdown-toggle')).toIncludeText(title)
+ wrapper.unmount()
+ })
+ })
+ describe(`prop: className`, () => {
+ it('renders with custom className', () => {
+ const wrapper = mount(
+
+ Menu Contents
+ ,
+ )
+ expect(wrapper.find('.dropdown')).toHaveClassName('dropdown-custom')
+ wrapper.unmount()
+ })
+ })
+
+ it('shows menu when clicking toggle', () => {
+ const wrapper = mount(Menu Contents)
+ expect(wrapper.find('.dropdown')).not.toHaveClassName('dropdown-expanded')
+ wrapper.find('.dropdown-toggle').simulate('click')
+ expect(wrapper.find('.dropdown')).toHaveClassName('dropdown-expanded')
+ wrapper.find('.dropdown-toggle').simulate('click')
+ expect(wrapper.find('.dropdown')).not.toHaveClassName('dropdown-expanded')
+ wrapper.unmount()
+ })
+
+ it('hides menu when clicking toggle outside the component', () => {
+ const wrapper = mount(
+
+
+ Menu Contents
+
+
+
,
+ { attachTo: sandbox },
+ )
+ expect(wrapper.find('.dropdown')).not.toHaveClassName('dropdown-expanded')
+ wrapper.find('.dropdown-toggle').simulate('click')
+ expect(wrapper.find('.dropdown')).toHaveClassName('dropdown-expanded')
+ wrapper.find('.child').getDOMNode().click() // simulate does not bubble
+ wrapper.update()
+ expect(wrapper.find('.dropdown')).toHaveClassName('dropdown-expanded')
+ wrapper.find('.outside').getDOMNode().click() // simulate does not bubble
+ wrapper.update()
+ expect(wrapper.find('.dropdown')).not.toHaveClassName('dropdown-expanded')
+ wrapper.unmount()
+ })
+
+ it('adds aria roles', () => {
+ const wrapper = mount(Menu Contents)
+ const toggle = wrapper.find('.dropdown-toggle')
+ const menu = wrapper.find('.dropdown-menu')
+ expect(toggle).toHaveProp('aria-haspopup', 'true')
+ expect(toggle).toHaveProp('tabIndex', 0)
+ expect(menu).toHaveProp('role', 'menu')
+ expect(menu).toHaveProp('tabIndex', 0)
+ toggle.simulate('click')
+ expect(wrapper.find('.dropdown-toggle')).toHaveProp('aria-expanded', true)
+ expect(wrapper.find('.dropdown-menu')).toHaveProp('aria-hidden', false)
+ })
+})
diff --git a/src/containers/shared/components/Dropdown/test/DropdownItem.test.tsx b/src/containers/shared/components/Dropdown/test/DropdownItem.test.tsx
new file mode 100644
index 000000000..66c3437df
--- /dev/null
+++ b/src/containers/shared/components/Dropdown/test/DropdownItem.test.tsx
@@ -0,0 +1,65 @@
+import { mount } from 'enzyme'
+import { DropdownItem } from '../DropdownItem'
+import createSpy = jasmine.createSpy
+
+describe('DropdownItem', () => {
+ describe(`prop: className`, () => {
+ it('renders with custom className', () => {
+ const wrapper = mount(
+ Hello,
+ )
+ expect(wrapper.find('.dropdown-item')).toHaveClassName('custom')
+ })
+ })
+
+ describe('prop: handler', () => {
+ let wrapper
+ const handler = createSpy('handler')
+
+ beforeEach(() => {
+ wrapper = mount(Hello)
+ })
+
+ it('renders as an anchor tag', () => {
+ expect(wrapper.find('.dropdown-item')).toHaveDisplayName('a')
+ })
+
+ it('executes handler on click', () => {
+ wrapper.find('.dropdown-item').simulate('click')
+ expect(handler).toHaveBeenCalled()
+ })
+
+ it('executes handler on keyup', () => {
+ wrapper.find('.dropdown-item').simulate('click')
+ expect(handler).toHaveBeenCalled()
+ })
+ })
+
+ describe('prop: href', () => {
+ let wrapper
+
+ beforeEach(() => {
+ wrapper = mount(
+ Hello,
+ )
+ })
+
+ it('renders as an anchor tag', () => {
+ expect(wrapper.find('.dropdown-item')).toHaveDisplayName('a')
+ })
+
+ it('renders href attribute on anchor', () => {
+ expect(wrapper.find('.dropdown-item')).toHaveProp('href')
+ })
+ })
+
+ it('renders as div without handler or href', () => {
+ const wrapper = mount(Hello)
+ expect(wrapper.find('.dropdown-item')).toHaveDisplayName('div')
+ })
+
+ it('adds aria roles', () => {
+ const wrapper = mount(Hello)
+ expect(wrapper.find('.dropdown-item')).toHaveProp('role', 'menuitem')
+ })
+})
diff --git a/src/containers/shared/css/nested-menu.scss b/src/containers/shared/css/nested-menu.scss
deleted file mode 100644
index fc68ac717..000000000
--- a/src/containers/shared/css/nested-menu.scss
+++ /dev/null
@@ -1,44 +0,0 @@
-@import './variables';
-
-.nested-menu {
- position: relative;
- display: inline-block;
-
- .title {
- margin-right: 10px;
- }
-
- .arrow {
- position: relative;
- top: 1px;
- }
-
- .nested-items {
- width: 100%;
- padding: 8px 0px;
- border-radius: 4px;
- background-color: $white;
- }
-
- .vertical {
- margin-bottom: 1px;
-
- &:hover,
- &:focus {
- background-color: $black-10;
- color: $black-80;
- @include bold;
- }
- }
-
- .menu-item {
- display: flex;
- justify-content: space-between;
- font-size: 16px;
- line-height: 16px;
-
- &:hover {
- background-color: $black-10;
- }
- }
-}