-
Notifications
You must be signed in to change notification settings - Fork 4.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
UX: Multichain: Network Menu (#18229)
- Loading branch information
Showing
16 changed files
with
714 additions
and
0 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
41 changes: 41 additions & 0 deletions
41
ui/components/multichain/network-list-item/__snapshots__/network-list-item.test.js.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`NetworkListItem renders properly 1`] = ` | ||
<div> | ||
<div | ||
class="box multichain-network-list-item box--padding-4 box--gap-2 box--flex-direction-row box--justify-content-space-between box--align-items-center box--width-full box--background-color-transparent box--display-flex" | ||
> | ||
<div | ||
class="box mm-text mm-avatar-base mm-avatar-base--size-md mm-avatar-network mm-text--body-sm mm-text--text-transform-uppercase box--display-flex box--flex-direction-row box--justify-content-center box--align-items-center box--color-text-default box--background-color-background-alternative box--rounded-full box--border-color-transparent box--border-style-solid box--border-width-1" | ||
> | ||
<img | ||
alt="Polygon logo" | ||
class="mm-avatar-network__network-image" | ||
src="./images/matic-token.png" | ||
/> | ||
</div> | ||
<div | ||
class="box multichain-network-list-item__network-name box--flex-direction-row" | ||
> | ||
<button | ||
class="box mm-text mm-button-base mm-button-base--ellipsis mm-button-link mm-button-link--size-auto mm-text--body-md mm-text--ellipsis box--display-inline-flex box--flex-direction-row box--justify-content-center box--align-items-center box--color-text-default box--background-color-transparent" | ||
> | ||
<span | ||
class="box mm-text mm-text--inherit mm-text--ellipsis box--flex-direction-row box--color-text-default" | ||
> | ||
Polygon | ||
</span> | ||
</button> | ||
</div> | ||
<button | ||
aria-label="[deleteNetwork]" | ||
class="box mm-button-icon mm-button-icon--size-sm multichain-network-list-item__delete box--display-inline-flex box--flex-direction-row box--justify-content-center box--align-items-center box--color-error-default box--background-color-transparent box--rounded-lg" | ||
> | ||
<span | ||
class="box mm-icon mm-icon--size-sm box--display-inline-block box--flex-direction-row box--color-inherit" | ||
style="mask-image: url('./images/icons/trash.svg');" | ||
/> | ||
</button> | ||
</div> | ||
</div> | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { NetworkListItem } from './network-list-item'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
.multichain-network-list-item { | ||
position: relative; | ||
cursor: pointer; | ||
|
||
&:not(.multichain-network-list-item--selected) { | ||
&:hover, | ||
&:focus-within { | ||
background: var(--color-background-default-hover); | ||
} | ||
} | ||
|
||
a:hover, | ||
a:focus { | ||
color: inherit; | ||
} | ||
|
||
&:hover, | ||
&:focus, | ||
&:focus-within { | ||
.multichain-network-list-item__delete { | ||
visibility: visible; | ||
} | ||
} | ||
|
||
&__network-name { | ||
width: 100%; | ||
flex: 1; | ||
overflow: hidden; | ||
text-align: start; | ||
|
||
button:hover { | ||
opacity: 1; | ||
} | ||
} | ||
|
||
&__tooltip { | ||
display: inline; | ||
} | ||
|
||
&__selected-indicator { | ||
width: 4px; | ||
height: calc(100% - 8px); | ||
position: absolute; | ||
top: 4px; | ||
left: 4px; | ||
} | ||
|
||
&__delete { | ||
visibility: hidden; | ||
} | ||
} |
108 changes: 108 additions & 0 deletions
108
ui/components/multichain/network-list-item/network-list-item.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
import React from 'react'; | ||
import classnames from 'classnames'; | ||
import PropTypes from 'prop-types'; | ||
import Box from '../../ui/box/box'; | ||
import { | ||
AlignItems, | ||
IconColor, | ||
BorderRadius, | ||
Color, | ||
Size, | ||
JustifyContent, | ||
TextColor, | ||
BLOCK_SIZES, | ||
} from '../../../helpers/constants/design-system'; | ||
import { | ||
AvatarNetwork, | ||
ButtonIcon, | ||
ButtonLink, | ||
ICON_NAMES, | ||
} from '../../component-library'; | ||
import { useI18nContext } from '../../../hooks/useI18nContext'; | ||
import Tooltip from '../../ui/tooltip/tooltip'; | ||
|
||
const MAXIMUM_CHARACTERS_WITHOUT_TOOLTIP = 17; | ||
|
||
export const NetworkListItem = ({ | ||
name, | ||
iconSrc, | ||
selected = false, | ||
onClick, | ||
onDeleteClick, | ||
}) => { | ||
const t = useI18nContext(); | ||
return ( | ||
<Box | ||
onClick={onClick} | ||
padding={4} | ||
gap={2} | ||
backgroundColor={selected ? Color.primaryMuted : Color.transparent} | ||
className={classnames('multichain-network-list-item', { | ||
'multichain-network-list-item--selected': selected, | ||
})} | ||
alignItems={AlignItems.center} | ||
justifyContent={JustifyContent.spaceBetween} | ||
width={BLOCK_SIZES.FULL} | ||
> | ||
{selected && ( | ||
<Box | ||
className="multichain-network-list-item__selected-indicator" | ||
borderRadius={BorderRadius.pill} | ||
backgroundColor={Color.primaryDefault} | ||
/> | ||
)} | ||
<AvatarNetwork name={name} src={iconSrc} /> | ||
<Box className="multichain-network-list-item__network-name"> | ||
<ButtonLink onClick={onClick} color={TextColor.textDefault} ellipsis> | ||
{name.length > MAXIMUM_CHARACTERS_WITHOUT_TOOLTIP ? ( | ||
<Tooltip | ||
title={name} | ||
position="bottom" | ||
wrapperClassName="multichain-network-list-item__tooltip" | ||
> | ||
{name} | ||
</Tooltip> | ||
) : ( | ||
name | ||
)} | ||
</ButtonLink> | ||
</Box> | ||
{onDeleteClick ? ( | ||
<ButtonIcon | ||
className="multichain-network-list-item__delete" | ||
color={IconColor.errorDefault} | ||
iconName={ICON_NAMES.TRASH} | ||
ariaLabel={t('deleteNetwork')} | ||
size={Size.SM} | ||
onClick={(e) => { | ||
e.stopPropagation(); | ||
onDeleteClick(); | ||
}} | ||
/> | ||
) : null} | ||
</Box> | ||
); | ||
}; | ||
|
||
NetworkListItem.propTypes = { | ||
/** | ||
* The name of the network | ||
*/ | ||
name: PropTypes.string.isRequired, | ||
/** | ||
* Path to the Icon image | ||
*/ | ||
iconSrc: PropTypes.string, | ||
/** | ||
* Represents if the network item is selected | ||
*/ | ||
selected: PropTypes.bool, | ||
/** | ||
* Executes when the item is clicked | ||
*/ | ||
onClick: PropTypes.func.isRequired, | ||
/** | ||
* Executes when the delete icon is clicked | ||
*/ | ||
onDeleteClick: PropTypes.func, | ||
}; |
67 changes: 67 additions & 0 deletions
67
ui/components/multichain/network-list-item/network-list-item.stories.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import React from 'react'; | ||
import { NetworkListItem } from '.'; | ||
|
||
export default { | ||
title: 'Components/Multichain/NetworkListItem', | ||
component: NetworkListItem, | ||
argTypes: { | ||
name: { | ||
control: 'text', | ||
}, | ||
selected: { | ||
control: 'boolean', | ||
}, | ||
onClick: { | ||
action: 'onClick', | ||
}, | ||
onDeleteClick: { | ||
action: 'onDeleteClick', | ||
}, | ||
iconSrc: { | ||
action: 'text', | ||
}, | ||
}, | ||
args: { | ||
name: 'Ethereum', | ||
iconSrc: '', | ||
selected: false, | ||
}, | ||
}; | ||
|
||
export const DefaultStory = (args) => ( | ||
<div | ||
style={{ width: '328px', border: '1px solid var(--color-border-muted)' }} | ||
> | ||
<NetworkListItem {...args} /> | ||
</div> | ||
); | ||
|
||
export const IconStory = (args) => ( | ||
<div | ||
style={{ width: '328px', border: '1px solid var(--color-border-muted)' }} | ||
> | ||
<NetworkListItem {...args} /> | ||
</div> | ||
); | ||
IconStory.args = { iconSrc: './images/matic-token.png', name: 'Polygon' }; | ||
|
||
export const SelectedStory = (args) => ( | ||
<div | ||
style={{ width: '328px', border: '1px solid var(--color-border-muted)' }} | ||
> | ||
<NetworkListItem {...args} /> | ||
</div> | ||
); | ||
SelectedStory.args = { selected: true }; | ||
|
||
export const ChaosStory = (args) => ( | ||
<div | ||
style={{ width: '328px', border: '1px solid var(--color-border-muted)' }} | ||
> | ||
<NetworkListItem {...args} /> | ||
</div> | ||
); | ||
ChaosStory.args = { | ||
name: 'This is a super long network name that should be ellipsized', | ||
selected: true, | ||
}; |
81 changes: 81 additions & 0 deletions
81
ui/components/multichain/network-list-item/network-list-item.test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
/* eslint-disable jest/require-top-level-describe */ | ||
import React from 'react'; | ||
import { fireEvent, render } from '@testing-library/react'; | ||
import { | ||
MATIC_TOKEN_IMAGE_URL, | ||
POLYGON_DISPLAY_NAME, | ||
} from '../../../../shared/constants/network'; | ||
import { NetworkListItem } from '.'; | ||
|
||
const DEFAULT_PROPS = { | ||
name: POLYGON_DISPLAY_NAME, | ||
iconSrc: MATIC_TOKEN_IMAGE_URL, | ||
selected: false, | ||
onClick: () => undefined, | ||
onDeleteClick: () => undefined, | ||
}; | ||
|
||
describe('NetworkListItem', () => { | ||
it('renders properly', () => { | ||
const { container } = render(<NetworkListItem {...DEFAULT_PROPS} />); | ||
expect(container).toMatchSnapshot(); | ||
}); | ||
|
||
it('does not render the delete icon when no onDeleteClick is clicked', () => { | ||
const { container } = render( | ||
<NetworkListItem {...DEFAULT_PROPS} onDeleteClick={null} />, | ||
); | ||
expect( | ||
container.querySelector('.multichain-network-list-item__delete'), | ||
).toBeNull(); | ||
}); | ||
|
||
it('shows as selected when selected', () => { | ||
const { container } = render( | ||
<NetworkListItem {...DEFAULT_PROPS} selected />, | ||
); | ||
expect( | ||
container.querySelector( | ||
'.multichain-network-list-item__selected-indicator', | ||
), | ||
).toBeInTheDocument(); | ||
}); | ||
|
||
it('renders a tooltip when the network name is very long', () => { | ||
const { container } = render( | ||
<NetworkListItem | ||
{...DEFAULT_PROPS} | ||
name="This is a very long network name that will be truncated" | ||
/>, | ||
); | ||
expect( | ||
container.querySelector('.multichain-network-list-item__tooltip'), | ||
).toBeInTheDocument(); | ||
}); | ||
|
||
it('executes onClick when the item is clicked', () => { | ||
const onClick = jest.fn(); | ||
const { container } = render( | ||
<NetworkListItem {...DEFAULT_PROPS} onClick={onClick} />, | ||
); | ||
fireEvent.click(container.querySelector('.multichain-network-list-item')); | ||
expect(onClick).toHaveBeenCalled(); | ||
}); | ||
|
||
it('executes onDeleteClick when the delete button is clicked', () => { | ||
const onDeleteClick = jest.fn(); | ||
const onClick = jest.fn(); | ||
const { container } = render( | ||
<NetworkListItem | ||
{...DEFAULT_PROPS} | ||
onDeleteClick={onDeleteClick} | ||
onClick={onClick} | ||
/>, | ||
); | ||
fireEvent.click( | ||
container.querySelector('.multichain-network-list-item__delete'), | ||
); | ||
expect(onDeleteClick).toHaveBeenCalledTimes(1); | ||
expect(onClick).toHaveBeenCalledTimes(0); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { NetworkListMenu } from './network-list-menu'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
.multichain-network-list-menu { | ||
max-height: 200px; | ||
overflow: auto; | ||
} |
Oops, something went wrong.