mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Add dropdown component (#8524)
This new dropdown component uses a native `select` element, thus avoiding various issues encountered in attempting to reuse our existing dropdown components for the new permission system alert modal. The prefixed forms of `appearance` have been added temporarily so that the component can be used in Storybook, as our Storybook config isn't setup to do autoprefixing yet. Our real build system does handle autoprefixing for this rule correctly already.
This commit is contained in:
parent
351424df7d
commit
8a12257f8e
@ -100,6 +100,8 @@
|
||||
|
||||
@import '../ui/check-box/index';
|
||||
|
||||
@import '../ui/dropdown/dropdown';
|
||||
|
||||
@import 'permissions-connect-header/index';
|
||||
|
||||
@import 'permissions-connect-footer/index';
|
||||
|
63
ui/app/components/ui/dropdown/dropdown.js
Normal file
63
ui/app/components/ui/dropdown/dropdown.js
Normal file
@ -0,0 +1,63 @@
|
||||
import React, { useCallback } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import classnames from 'classnames'
|
||||
|
||||
const Dropdown = ({ className, disabled, onChange, options, selectedOption, style, title }) => {
|
||||
const _onChange = useCallback(
|
||||
(event) => {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
onChange(event.target.value)
|
||||
},
|
||||
[onChange],
|
||||
)
|
||||
|
||||
return (
|
||||
<select
|
||||
className={classnames('dropdown', className)}
|
||||
disabled={disabled}
|
||||
title={title}
|
||||
onChange={_onChange}
|
||||
style={style}
|
||||
value={selectedOption}
|
||||
>
|
||||
{
|
||||
options.map((option) => {
|
||||
return (
|
||||
<option
|
||||
key={option.value}
|
||||
value={option.value}
|
||||
>
|
||||
{ option.name || option.value }
|
||||
</option>
|
||||
)
|
||||
})
|
||||
}
|
||||
</select>
|
||||
)
|
||||
}
|
||||
|
||||
Dropdown.propTypes = {
|
||||
className: PropTypes.string,
|
||||
disabled: PropTypes.bool,
|
||||
title: PropTypes.string,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
options: PropTypes.arrayOf(
|
||||
PropTypes.exact({
|
||||
name: PropTypes.string,
|
||||
value: PropTypes.string.isRequired,
|
||||
})
|
||||
).isRequired,
|
||||
selectedOption: PropTypes.string,
|
||||
style: PropTypes.object,
|
||||
}
|
||||
|
||||
Dropdown.defaultProps = {
|
||||
className: undefined,
|
||||
disabled: false,
|
||||
title: undefined,
|
||||
selectedOption: null,
|
||||
style: undefined,
|
||||
}
|
||||
|
||||
export default Dropdown
|
22
ui/app/components/ui/dropdown/dropdown.scss
Normal file
22
ui/app/components/ui/dropdown/dropdown.scss
Normal file
@ -0,0 +1,22 @@
|
||||
.dropdown {
|
||||
appearance: none;
|
||||
|
||||
// TODO: remove these after getting autoprefixer working in Storybook
|
||||
-moz-appearance: none;
|
||||
-webkit-appearance: none;
|
||||
|
||||
border: 1px solid $Grey-500;
|
||||
border-radius: 6px;
|
||||
background-image: url('/images/icons/caret-down.svg');
|
||||
background-repeat: no-repeat, repeat;
|
||||
background-position: right 18px top 50%;
|
||||
background-color: white;
|
||||
padding: 8px 32px 8px 16px;
|
||||
font-family: Roboto, 'sans-serif';
|
||||
font-size: 14px;
|
||||
|
||||
[dir='rtl'] & {
|
||||
background-position: left 18px top 50%;
|
||||
padding: 8px 16px 8px 32px;
|
||||
}
|
||||
}
|
90
ui/app/components/ui/dropdown/dropdown.stories.js
Normal file
90
ui/app/components/ui/dropdown/dropdown.stories.js
Normal file
@ -0,0 +1,90 @@
|
||||
import React from 'react'
|
||||
import { action } from '@storybook/addon-actions'
|
||||
import Dropdown from '.'
|
||||
import { boolean, select, text } from '@storybook/addon-knobs/react'
|
||||
|
||||
export default {
|
||||
title: 'Dropdown',
|
||||
}
|
||||
|
||||
const unnamedOptions = [...Array(10).keys()].map((index) => {
|
||||
return { value: `option${index}` }
|
||||
})
|
||||
|
||||
const namedOptions = unnamedOptions.map((option, index) => {
|
||||
return Object.assign({}, option, { name: `Option ${index}` })
|
||||
})
|
||||
|
||||
const namedOptionsWithVeryLongNames = unnamedOptions.map((option, index) => {
|
||||
return Object.assign({}, option, { name: `Option ${index} with a very${', very'.repeat(index)} long name` })
|
||||
})
|
||||
|
||||
|
||||
export const simple = () => (
|
||||
<Dropdown
|
||||
disabled={boolean('Disabled', false)}
|
||||
title={text('Title', 'Test dropdown name')}
|
||||
onChange={action('Selection changed')}
|
||||
options={namedOptions}
|
||||
required={boolean('Required', false)}
|
||||
selectedOption={
|
||||
select(
|
||||
'Selected Option',
|
||||
namedOptions.map((option) => option.value),
|
||||
namedOptions[0].value
|
||||
)
|
||||
}
|
||||
/>
|
||||
)
|
||||
|
||||
export const optionsWithoutNames = () => (
|
||||
<Dropdown
|
||||
disabled={boolean('Disabled', false)}
|
||||
title={text('Title', 'Test dropdown name')}
|
||||
onChange={action('Selection changed')}
|
||||
options={unnamedOptions}
|
||||
required={boolean('Required', false)}
|
||||
selectedOption={
|
||||
select(
|
||||
'Selected Option',
|
||||
unnamedOptions.map((option) => option.value),
|
||||
unnamedOptions[0].value
|
||||
)
|
||||
}
|
||||
/>
|
||||
)
|
||||
|
||||
export const optionsWithLongNames = () => (
|
||||
<Dropdown
|
||||
disabled={boolean('Disabled', false)}
|
||||
title={text('Title', 'Test dropdown name')}
|
||||
onChange={action('Selection changed')}
|
||||
options={namedOptionsWithVeryLongNames}
|
||||
required={boolean('Required', false)}
|
||||
selectedOption={
|
||||
select(
|
||||
'Selected Option',
|
||||
namedOptionsWithVeryLongNames.map((option) => option.value),
|
||||
namedOptionsWithVeryLongNames[0].value
|
||||
)
|
||||
}
|
||||
/>
|
||||
)
|
||||
|
||||
export const optionsWithLongNamesAndShortWidth = () => (
|
||||
<Dropdown
|
||||
disabled={boolean('Disabled', false)}
|
||||
title={text('Title', 'Test dropdown name')}
|
||||
onChange={action('Selection changed')}
|
||||
options={namedOptionsWithVeryLongNames}
|
||||
required={boolean('Required', false)}
|
||||
selectedOption={
|
||||
select(
|
||||
'Selected Option',
|
||||
namedOptionsWithVeryLongNames.map((option) => option.value),
|
||||
namedOptionsWithVeryLongNames[0].value
|
||||
)
|
||||
}
|
||||
style={{ width: '200px' }}
|
||||
/>
|
||||
)
|
1
ui/app/components/ui/dropdown/index.js
Normal file
1
ui/app/components/ui/dropdown/index.js
Normal file
@ -0,0 +1 @@
|
||||
export { default } from './dropdown'
|
Loading…
Reference in New Issue
Block a user