Added Tag Url Component (#16159)
* added tag url file structure * added tag url component * updated args in tag url * updated avatar favicon and button link in Tag url * updated Text component in Tag URL * added tests to the tag url component * fixed typos * replaced buttonbase with button link * added lock icon to the tag-url component * updated typo * renamed style and prop names * updated prop name and tests * fixed name for tag in readme * fixed test statements * updated prop names * updated story * fixed typo in test file * updated lock icon rendering and icon color * updated lock icon prop * updated README * updated tests for tag url * added snapshot testing * updated Readme for tag url * updated label as per src Co-authored-by: Garrett Bear <gwhisten@gmail.com>feature/default_network_editable
parent
67e0b60dcf
commit
4a247a95cb
@ -0,0 +1,70 @@ |
||||
import { Story, Canvas, ArgsTable } from '@storybook/addon-docs'; |
||||
|
||||
import { TagUrl } from './tag-url'; |
||||
|
||||
# Tag Url |
||||
|
||||
The `TagUrl` is a component used to display dApp information within a container. |
||||
|
||||
<Canvas> |
||||
<Story id="ui-components-component-library-tag-url-tag-url-stories-js--default-story" /> |
||||
</Canvas> |
||||
|
||||
## Props |
||||
|
||||
The `TagUrl` accepts all props below as well as all [Box](/docs/ui-components-ui-box-box-stories-js--default-story#props) component props. |
||||
|
||||
<ArgsTable of={TagUrl} /> |
||||
|
||||
### Src |
||||
|
||||
Use the `src` prop with an image url to render the `AvatarFavicon`. |
||||
|
||||
<Canvas> |
||||
<Story id="ui-components-component-library-tag-url-tag-url-stories-js--src" /> |
||||
</Canvas> |
||||
|
||||
```jsx |
||||
|
||||
import { TagUrl } from '../../ui/component-library/tag-url'; |
||||
|
||||
<TagUrl src="https://peepeth.com/favicon-32x32.png" /> |
||||
<TagUrl src="https://1inch.exchange/assets/favicon/favicon-32x32.png"/> |
||||
<TagUrl src="https://uniswap.org/favicon.ico" /> |
||||
|
||||
``` |
||||
|
||||
### Label |
||||
|
||||
Use the `label` prop for the text content of the `TagUrl` component |
||||
|
||||
<Canvas> |
||||
<Story id="ui-components-component-library-tag-url-tag-url-stories-js--label" /> |
||||
</Canvas> |
||||
|
||||
```jsx |
||||
|
||||
import { TagUrl } from '../../ui/component-library/tag-url'; |
||||
|
||||
<TagUrl label="https://widget.getacute.io" /> |
||||
<TagUrl label="app.uniswap.org" /> |
||||
<TagUrl label="https://metamask.github.io" /> |
||||
|
||||
``` |
||||
|
||||
### Action Button Label |
||||
|
||||
If we want to have a button in `TagUrl` component. You can update the `ButtonLink` component props used for the action button using `actionButtonProps` |
||||
|
||||
<Canvas> |
||||
<Story id="ui-components-component-library-tag-url-tag-url-stories-js--action-button-label" /> |
||||
</Canvas> |
||||
|
||||
### Show Lock Icon |
||||
|
||||
Use the `showLockIcon` prop to render a lock icon next to the `label`. It's intended use is to display if the url uses `https`. Props for the lock icon can be changed using the `lockIconProps`. |
||||
|
||||
<Canvas> |
||||
<Story id="ui-components-component-library-tag-url-tag-url-stories-js--show-lock-icon" /> |
||||
</Canvas> |
||||
|
@ -0,0 +1,25 @@ |
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP |
||||
|
||||
exports[`TagUrl should render the label inside the TagUrl 1`] = ` |
||||
<div> |
||||
<div |
||||
class="box mm-tag-url box--padding-right-4 box--padding-left-2 box--display-inline-flex box--gap-2 box--flex-direction-row box--align-items-center box--background-color-background-default box--rounded-pill box--border-color-border-default box--border-width-1 box--border-style-solid" |
||||
data-testid="tag-url" |
||||
> |
||||
<div |
||||
class="box base-avatar base-avatar--size-md avatar-favicon 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--border-color-transparent box--border-style-solid box--border-width-1" |
||||
> |
||||
<div |
||||
aria-label="avatar-favicon" |
||||
class="box icon icon--size-md box--flex-direction-row box--color-icon-default" |
||||
style="mask-image: url('./images/icons/icon-undefined.svg;" |
||||
/> |
||||
</div> |
||||
<p |
||||
class="box text text--body-md text--ellipsis text--color-text-default box--flex-direction-row" |
||||
> |
||||
https://app.uniswap.org |
||||
</p> |
||||
</div> |
||||
</div> |
||||
`; |
@ -0,0 +1 @@ |
||||
export { TagUrl } from './tag-url'; |
@ -0,0 +1,115 @@ |
||||
import React from 'react'; |
||||
import PropTypes from 'prop-types'; |
||||
import classnames from 'classnames'; |
||||
import Box from '../../ui/box/box'; |
||||
import { Text } from '../text'; |
||||
import { |
||||
ALIGN_ITEMS, |
||||
BORDER_RADIUS, |
||||
COLORS, |
||||
DISPLAY, |
||||
SIZES, |
||||
TEXT, |
||||
} from '../../../helpers/constants/design-system'; |
||||
import { AvatarFavicon } from '../avatar-favicon'; |
||||
import { ButtonLink } from '../button-link'; |
||||
import { Icon, ICON_NAMES } from '../icon'; |
||||
|
||||
export const TagUrl = ({ |
||||
label, |
||||
labelProps, |
||||
actionButtonLabel, |
||||
actionButtonProps, |
||||
src, |
||||
showLockIcon, |
||||
avatarFaviconProps, |
||||
lockIconProps, |
||||
className, |
||||
...props |
||||
}) => { |
||||
return ( |
||||
<Box |
||||
className={classnames('mm-tag-url', className)} |
||||
backgroundColor={COLORS.BACKGROUND_DEFAULT} |
||||
borderColor={COLORS.BORDER_DEFAULT} |
||||
borderWidth={1} |
||||
alignItems={ALIGN_ITEMS.CENTER} |
||||
paddingLeft={2} |
||||
paddingRight={4} |
||||
gap={2} |
||||
borderRadius={BORDER_RADIUS.PILL} |
||||
display={DISPLAY.INLINE_FLEX} |
||||
{...props} |
||||
> |
||||
<AvatarFavicon imageSource={src} {...avatarFaviconProps} /> |
||||
{showLockIcon && ( |
||||
<Icon |
||||
className="tag-url__lock-icon" |
||||
name={ICON_NAMES.LOCK_FILLED} |
||||
color={COLORS.ICON_ALTERNATIVE} |
||||
size={SIZES.SM} |
||||
aria-label="https://" |
||||
{...lockIconProps} |
||||
/> |
||||
)} |
||||
<Text variant={TEXT.BODY_MD} ellipsis {...labelProps}> |
||||
{label} |
||||
</Text> |
||||
|
||||
{actionButtonLabel && ( |
||||
<ButtonLink |
||||
as="a" |
||||
size={SIZES.SM} |
||||
paddingLeft={0} |
||||
paddingRight={0} |
||||
marginLeft={2} |
||||
marginRight={2} |
||||
{...actionButtonProps} |
||||
> |
||||
{actionButtonLabel} |
||||
</ButtonLink> |
||||
)} |
||||
</Box> |
||||
); |
||||
}; |
||||
|
||||
TagUrl.propTypes = { |
||||
/** |
||||
* The src accepts the string of the image to be rendered |
||||
*/ |
||||
src: PropTypes.string, |
||||
/** |
||||
* The showLockIcon accepts a boolean prop to render the lock icon instead of https in label |
||||
*/ |
||||
showLockIcon: PropTypes.bool, |
||||
/** |
||||
* It accepts all the props from Avatar Favicon |
||||
*/ |
||||
avatarFaviconProps: PropTypes.shape(AvatarFavicon.PropTypes), |
||||
/** |
||||
* It accepts all the props from Icon |
||||
*/ |
||||
lockIconProps: PropTypes.shape(Icon.PropTypes), |
||||
/** |
||||
* The text content of the TagUrl component |
||||
*/ |
||||
label: PropTypes.string.isRequired, |
||||
/** |
||||
* It accepts all the props from Text Component |
||||
*/ |
||||
labelProps: PropTypes.shape(Text.PropTypes), |
||||
/** |
||||
* If we want a button in TagUrl component. |
||||
*/ |
||||
actionButtonLabel: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), |
||||
/** |
||||
* It accepts all the props from ButtonLink |
||||
*/ |
||||
actionButtonProps: PropTypes.shape(ButtonLink.PropTypes), |
||||
/** |
||||
* Additional classNames to be added to the TagUrl component |
||||
*/ |
||||
className: PropTypes.string, |
||||
}; |
||||
|
||||
export default TagUrl; |
@ -0,0 +1,4 @@ |
||||
.mm-tag-url { |
||||
height: 48px; |
||||
max-width: fit-content; |
||||
} |
@ -0,0 +1,82 @@ |
||||
import React from 'react'; |
||||
import { |
||||
DISPLAY, |
||||
FLEX_DIRECTION, |
||||
} from '../../../helpers/constants/design-system'; |
||||
|
||||
import Box from '../../ui/box'; |
||||
import README from './README.mdx'; |
||||
import { TagUrl } from './tag-url'; |
||||
|
||||
export default { |
||||
title: 'Components/ComponentLibrary/TagUrl', |
||||
id: __filename, |
||||
component: TagUrl, |
||||
parameters: { |
||||
docs: { |
||||
page: README, |
||||
}, |
||||
}, |
||||
argTypes: { |
||||
label: { |
||||
control: 'text', |
||||
}, |
||||
src: { |
||||
control: 'text', |
||||
}, |
||||
actionButtonLabel: { |
||||
control: 'text', |
||||
}, |
||||
showLockIcon: { |
||||
control: 'boolean', |
||||
}, |
||||
}, |
||||
args: { |
||||
label: 'app.uniswap.org', |
||||
src: 'https://uniswap.org/favicon.ico', |
||||
showLockIcon: false, |
||||
}, |
||||
}; |
||||
|
||||
const Template = (args) => <TagUrl {...args} />; |
||||
|
||||
export const DefaultStory = Template.bind({}); |
||||
DefaultStory.storyName = 'Default'; |
||||
|
||||
export const ActionButtonLabel = Template.bind({}); |
||||
ActionButtonLabel.args = { |
||||
actionButtonLabel: 'Permissions', |
||||
}; |
||||
|
||||
export const ShowLockIcon = Template.bind({}); |
||||
ShowLockIcon.args = { |
||||
showLockIcon: true, |
||||
}; |
||||
|
||||
export const Label = (args) => ( |
||||
<Box display={DISPLAY.FLEX} flexDirection={FLEX_DIRECTION.COLUMN} gap={2}> |
||||
<TagUrl {...args} label="https://widget.getacute.io" /> |
||||
<TagUrl {...args} label="app.uniswap.org" /> |
||||
<TagUrl {...args} label="https://metamask.github.io" /> |
||||
</Box> |
||||
); |
||||
|
||||
export const Src = (args) => ( |
||||
<Box display={DISPLAY.FLEX} flexDirection={FLEX_DIRECTION.COLUMN} gap={2}> |
||||
<TagUrl |
||||
{...args} |
||||
label="peepeth.com" |
||||
src="https://peepeth.com/favicon-32x32.png" |
||||
/> |
||||
<TagUrl |
||||
{...args} |
||||
label="https://1inch.exchange" |
||||
src="https://1inch.exchange/assets/favicon/favicon-32x32.png" |
||||
/> |
||||
<TagUrl |
||||
{...args} |
||||
label="app.uniswap.org" |
||||
src="https://uniswap.org/favicon.ico" |
||||
/> |
||||
</Box> |
||||
); |
@ -0,0 +1,108 @@ |
||||
/* eslint-disable jest/require-top-level-describe */ |
||||
import { render, screen } from '@testing-library/react'; |
||||
import React from 'react'; |
||||
|
||||
import { TagUrl } from './tag-url'; |
||||
|
||||
describe('TagUrl', () => { |
||||
it('should render the label inside the TagUrl', () => { |
||||
const { getByTestId, container } = render( |
||||
<TagUrl data-testid="tag-url" label="https://app.uniswap.org" />, |
||||
); |
||||
expect(getByTestId('tag-url')).toBeDefined(); |
||||
expect(container).toMatchSnapshot(); |
||||
}); |
||||
|
||||
it('should render the button if there is a actionButtonLabel inside the tag', () => { |
||||
render( |
||||
<TagUrl |
||||
data-testid="tag-url" |
||||
label="https://app.uniswap.org" |
||||
actionButtonLabel="Permissions" |
||||
/>, |
||||
); |
||||
|
||||
expect(screen.getByText('Permissions').closest('a')).toBeDefined(); |
||||
}); |
||||
|
||||
it('should render correct Avatar in TagUrl', () => { |
||||
render( |
||||
<TagUrl |
||||
data-testid="tag-url" |
||||
label="https://app.uniswap.org" |
||||
actionButtonLabel="Permissions" |
||||
src="https://1inch.exchange/assets/favicon/favicon-32x32.png" |
||||
/>, |
||||
); |
||||
const image = screen.getByRole('img'); |
||||
expect(image).toBeDefined(); |
||||
expect(image).toHaveAttribute( |
||||
'src', |
||||
'https://1inch.exchange/assets/favicon/favicon-32x32.png', |
||||
); |
||||
}); |
||||
|
||||
it('should render lock icon if showLockIcon is true', () => { |
||||
const { container } = render( |
||||
<TagUrl |
||||
data-testid="tag-url" |
||||
label="https://app.uniswap.org" |
||||
actionButtonLabel="Permissions" |
||||
showLockIcon |
||||
/>, |
||||
); |
||||
|
||||
expect(container.getElementsByClassName('tag-url__lock-icon')).toHaveLength( |
||||
1, |
||||
); |
||||
}); |
||||
|
||||
it('should render avatar with custom props', () => { |
||||
const container = ( |
||||
<TagUrl |
||||
data-testid="tag-url" |
||||
label="https://app.uniswap.org" |
||||
actionButtonLabel="Permissions" |
||||
avatarFaviconProps={{ |
||||
'data-testid': 'fallback avatar', |
||||
}} |
||||
/> |
||||
); |
||||
|
||||
expect(container.props.avatarFaviconProps['data-testid']).toStrictEqual( |
||||
'fallback avatar', |
||||
); |
||||
}); |
||||
|
||||
it('should render Text inside Tag url with custom label props', () => { |
||||
const container = ( |
||||
<TagUrl |
||||
data-testid="tag-url" |
||||
label="https://app.uniswap.org" |
||||
actionButtonLabel="Permissions" |
||||
labelProps={{ |
||||
className: 'tag-url label', |
||||
}} |
||||
/> |
||||
); |
||||
|
||||
expect(container.props.labelProps.className).toStrictEqual('tag-url label'); |
||||
}); |
||||
|
||||
it('should render Button with custom label props', () => { |
||||
const container = ( |
||||
<TagUrl |
||||
data-testid="tag-url" |
||||
label="https://app.uniswap.org" |
||||
actionButtonLabel="Permissions" |
||||
actionButtonProps={{ |
||||
className: 'tag-url button', |
||||
}} |
||||
/> |
||||
); |
||||
|
||||
expect(container.props.actionButtonProps.className).toStrictEqual( |
||||
'tag-url button', |
||||
); |
||||
}); |
||||
}); |
Loading…
Reference in new issue