mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
add Callout component (#10309)
This commit is contained in:
parent
f9b5b7ee37
commit
12161bb0c6
65
ui/app/components/ui/callout/callout.js
Normal file
65
ui/app/components/ui/callout/callout.js
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import React, { useEffect, useState } from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import classnames from 'classnames'
|
||||||
|
import InfoIconInverted from '../icon/info-icon-inverted.component'
|
||||||
|
import { SEVERITIES } from '../../../helpers/constants/design-system'
|
||||||
|
|
||||||
|
export default function Callout({
|
||||||
|
severity,
|
||||||
|
children,
|
||||||
|
dismiss,
|
||||||
|
isFirst,
|
||||||
|
isLast,
|
||||||
|
isMultiple,
|
||||||
|
}) {
|
||||||
|
const [removed, setRemoved] = useState(false)
|
||||||
|
const calloutClassName = classnames('callout', `callout--${severity}`, {
|
||||||
|
'callout--dismissed': removed === true,
|
||||||
|
'callout--multiple': isMultiple === true,
|
||||||
|
'callout--dismissible': Boolean(dismiss),
|
||||||
|
'callout--first': isFirst === true || isMultiple !== true,
|
||||||
|
'callout--last': isLast === true || isMultiple !== true,
|
||||||
|
})
|
||||||
|
// Clicking the close button will set removed state, which will trigger this
|
||||||
|
// effect to refire due to changing dependencies. When that happens, after a
|
||||||
|
// half of a second we fire the dismiss method from the parent. The
|
||||||
|
// consuming component is responsible for modifying state and then removing
|
||||||
|
// the element from the DOM.
|
||||||
|
useEffect(() => {
|
||||||
|
if (removed) {
|
||||||
|
setTimeout(() => {
|
||||||
|
dismiss()
|
||||||
|
}, 500)
|
||||||
|
}
|
||||||
|
}, [removed, dismiss])
|
||||||
|
return (
|
||||||
|
<div className={calloutClassName}>
|
||||||
|
<InfoIconInverted severity={severity} />
|
||||||
|
<div className="callout__content">{children}</div>
|
||||||
|
{dismiss && (
|
||||||
|
<i
|
||||||
|
onClick={() => {
|
||||||
|
setRemoved(true)
|
||||||
|
}}
|
||||||
|
onKeyUp={(event) => {
|
||||||
|
if (event.key === 'Enter') {
|
||||||
|
setRemoved(true)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
role="button"
|
||||||
|
tabIndex={0}
|
||||||
|
className="fas fa-times callout__close-button"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Callout.propTypes = {
|
||||||
|
severity: PropTypes.oneOf(Object.values(SEVERITIES)).isRequired,
|
||||||
|
children: PropTypes.node.isRequired,
|
||||||
|
dismiss: PropTypes.func,
|
||||||
|
isFirst: PropTypes.bool,
|
||||||
|
isLast: PropTypes.bool,
|
||||||
|
isMultiple: PropTypes.bool,
|
||||||
|
}
|
61
ui/app/components/ui/callout/callout.scss
Normal file
61
ui/app/components/ui/callout/callout.scss
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
.callout {
|
||||||
|
$self: &;
|
||||||
|
|
||||||
|
@include H7;
|
||||||
|
|
||||||
|
padding: 16px;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, auto) 1fr minmax(0, auto);
|
||||||
|
grid-template-rows: 1fr;
|
||||||
|
transition: opacity 0.75s 0s;
|
||||||
|
|
||||||
|
&--dismissible {
|
||||||
|
&#{$self}--first {
|
||||||
|
box-shadow: 0 -5px 5px -5px rgba(0, 0, 0, 0.18);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--multiple {
|
||||||
|
padding-top: 8px;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
|
||||||
|
&#{$self}--first {
|
||||||
|
padding-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&#{$self}--last {
|
||||||
|
padding-bottom: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--dismissed {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--warning {
|
||||||
|
border-left: 2px solid $alert-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--danger {
|
||||||
|
border-left: 2px solid $error-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--info {
|
||||||
|
border-left: 2px solid $primary-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--success {
|
||||||
|
border-left: 2px solid $success-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .info-icon {
|
||||||
|
margin: unset;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__close-button {
|
||||||
|
margin-left: 8px;
|
||||||
|
background: unset;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
107
ui/app/components/ui/callout/callout.stories.js
Normal file
107
ui/app/components/ui/callout/callout.stories.js
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
import { select } from '@storybook/addon-knobs'
|
||||||
|
import React, { useState } from 'react'
|
||||||
|
import {
|
||||||
|
COLORS,
|
||||||
|
SEVERITIES,
|
||||||
|
TYPOGRAPHY,
|
||||||
|
} from '../../../helpers/constants/design-system'
|
||||||
|
import Box from '../box'
|
||||||
|
import Typography from '../typography'
|
||||||
|
import Callout from './callout'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Callout',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const persistentCallout = () => (
|
||||||
|
<Box borderColor={COLORS.UI2} padding={[8, 0, 0, 0]}>
|
||||||
|
<Box margin={2}>
|
||||||
|
<Typography variant={TYPOGRAPHY.H4}>This is your private key:</Typography>
|
||||||
|
<Typography variant={TYPOGRAPHY.H6}>
|
||||||
|
some seed words that are super important and probably deserve a callout
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
<Callout severity={select('severity', SEVERITIES, SEVERITIES.WARNING)}>
|
||||||
|
Always back up your private key!
|
||||||
|
</Callout>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const DismissibleCallout = () => {
|
||||||
|
const [dismissed, setDismissed] = useState(false)
|
||||||
|
return (
|
||||||
|
<Box borderColor={COLORS.UI2} padding={[8, 0, 0, 0]}>
|
||||||
|
<Box margin={2}>
|
||||||
|
<Typography variant={TYPOGRAPHY.H4}>
|
||||||
|
This is your private key:
|
||||||
|
</Typography>
|
||||||
|
<Typography variant={TYPOGRAPHY.H6}>
|
||||||
|
some seed words that are super important and probably deserve a
|
||||||
|
callout
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
{!dismissed && (
|
||||||
|
<Callout
|
||||||
|
severity={select('severity', SEVERITIES, SEVERITIES.WARNING)}
|
||||||
|
dismiss={() => setDismissed(true)}
|
||||||
|
>
|
||||||
|
Always back up your private key!
|
||||||
|
</Callout>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const MULTIPLE_CALLOUTS = {
|
||||||
|
WARN: {
|
||||||
|
severity: SEVERITIES.WARNING,
|
||||||
|
content: 'Always back up your private key!',
|
||||||
|
dismissed: false,
|
||||||
|
},
|
||||||
|
DANGER: {
|
||||||
|
severity: SEVERITIES.DANGER,
|
||||||
|
content: 'Never give your private key out, it will lead to loss of funds!',
|
||||||
|
dismissed: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const MultipleDismissibleCallouts = () => {
|
||||||
|
const [calloutState, setCalloutState] = useState(MULTIPLE_CALLOUTS)
|
||||||
|
const dismiss = (id) => {
|
||||||
|
setCalloutState((prevState) => ({
|
||||||
|
...prevState,
|
||||||
|
[id]: {
|
||||||
|
...prevState[id],
|
||||||
|
dismissed: true,
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box borderColor={COLORS.UI2} padding={[8, 0, 0, 0]}>
|
||||||
|
<Box margin={2}>
|
||||||
|
<Typography variant={TYPOGRAPHY.H4}>
|
||||||
|
This is your private key:
|
||||||
|
</Typography>
|
||||||
|
<Typography variant={TYPOGRAPHY.H6}>
|
||||||
|
some seed words that are super important and probably deserve a
|
||||||
|
callout
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
{Object.entries(calloutState)
|
||||||
|
.filter(([_, callout]) => callout.dismissed === false)
|
||||||
|
.map(([id, callout], idx, filtered) => (
|
||||||
|
<Callout
|
||||||
|
key={id}
|
||||||
|
severity={callout.severity}
|
||||||
|
dismiss={() => dismiss(id)}
|
||||||
|
isFirst={idx === 0}
|
||||||
|
isLast={idx + 1 === filtered.length}
|
||||||
|
isMultiple={filtered.length > 1}
|
||||||
|
>
|
||||||
|
{callout.content}
|
||||||
|
</Callout>
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
1
ui/app/components/ui/callout/index.js
Normal file
1
ui/app/components/ui/callout/index.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default } from './callout'
|
@ -6,6 +6,7 @@
|
|||||||
@import 'breadcrumbs/index';
|
@import 'breadcrumbs/index';
|
||||||
@import 'button-group/index';
|
@import 'button-group/index';
|
||||||
@import 'button/buttons';
|
@import 'button/buttons';
|
||||||
|
@import 'callout/callout';
|
||||||
@import 'card/index';
|
@import 'card/index';
|
||||||
@import 'check-box/index';
|
@import 'check-box/index';
|
||||||
@import 'chip/chip';
|
@import 'chip/chip';
|
||||||
|
Loading…
x
Reference in New Issue
Block a user