1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 09:52:26 +01:00

Rewrite checkbox component (#8305)

This new checkbox component uses a plain `input` component internally,
so the browser treats it like a native checkbox. It is styled by hiding
the native checkbox and replacing it with Font Awesome icons (the same
that we are using in Figma).

Support for a 'disabled' state and an indeterminate state has been
added as well. The `onClick` prop has been made optional, as it may not
be required if the parent component is intercepting the click instead.

The `regular` Font Awesome font style needed to be added so that we
could use the `far fa-square` icon for the unchecked checkbox.
This commit is contained in:
Mark Stacey 2020-04-09 18:51:12 -03:00 committed by GitHub
parent b0b99fa748
commit b628ff05d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 114 additions and 57 deletions

View File

@ -1,36 +1,60 @@
import React, { PureComponent } from 'react'
import React, { useLayoutEffect, useRef } from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
export default class CheckBox extends PureComponent {
static propTypes = {
className: PropTypes.string,
checked: PropTypes.bool,
onClick: PropTypes.func.isRequired,
}
static defaultProps = {
className: '',
checked: false,
}
render () {
const { className, checked, onClick } = this.props
return (
<div
onClick={ () => onClick() }
className={classnames('check-box', className, {
'check-box--checked': checked,
'check-box--un-checked': !checked,
})}
>
{
checked
? <i className="fa fa-check" />
: null
}
</div>
)
}
const CHECKBOX_STATE = {
CHECKED: 'CHECKED',
INDETERMINATE: 'INDETERMINATE',
UNCHECKED: 'UNCHECKED',
}
export const { CHECKED, INDETERMINATE, UNCHECKED } = CHECKBOX_STATE
const CheckBox = ({ className, disabled, onClick, checked }) => {
if (typeof checked === 'boolean') {
checked = checked
? CHECKBOX_STATE.CHECKED
: CHECKBOX_STATE.UNCHECKED
}
const ref = useRef(null)
useLayoutEffect(() => {
ref.current.indeterminate = checked === CHECKBOX_STATE.INDETERMINATE
}, [checked])
return (
<input
checked={checked === CHECKBOX_STATE.CHECKED}
className={classnames('check-box', className, {
'far fa-square': checked === CHECKBOX_STATE.UNCHECKED,
'fa fa-check-square': checked === CHECKBOX_STATE.CHECKED,
'fa fa-minus-square': checked === CHECKBOX_STATE.INDETERMINATE,
})}
disabled={disabled}
onClick={
onClick
? (event) => {
event.preventDefault()
onClick()
}
: null
}
readOnly
ref={ref}
type="checkbox"
/>
)
}
CheckBox.propTypes = {
className: PropTypes.string,
disabled: PropTypes.bool,
onClick: PropTypes.func,
checked: PropTypes.oneOf([...Object.keys(CHECKBOX_STATE), true, false]).isRequired,
}
CheckBox.defaultProps = {
className: undefined,
disabled: false,
}
export default CheckBox

View File

@ -0,0 +1,24 @@
import React from 'react'
import { action } from '@storybook/addon-actions'
import CheckBox, { CHECKED, INDETERMINATE, UNCHECKED } from './check-box.component'
import { boolean, select } from '@storybook/addon-knobs/react'
export default {
title: 'Check Box',
}
const checkboxOptions = {
[CHECKED]: CHECKED,
[INDETERMINATE]: INDETERMINATE,
[UNCHECKED]: UNCHECKED,
True: true,
False: false,
}
export const primaryType = () => (
<CheckBox
checked={select('checked state', checkboxOptions, UNCHECKED)}
disabled={boolean('Disabled', false)}
onClick={action('checkbox clicked')}
/>
)

View File

@ -1 +1 @@
export { default } from './check-box.component'
export { default, CHECKED, INDETERMINATE, UNCHECKED } from './check-box.component'

View File

@ -1,26 +1,23 @@
.check-box {
cursor: pointer;
-webkit-appearance: none;
appearance: none;
background: $white;
color: $Grey-100;
width: 18px;
height: 18px;
font-size: 21px;
line-height: 0.9;
border-radius: 2px;
display: flex;
&--checked {
background: $curious-blue;
border: 2px solid $curious-blue;
border-radius: 2px;
width: 18px;
height: 18px;
display: flex;
justify-content: center;
align-items: center;
i {
color: $white;
}
&:checked, &:indeterminate {
color: $curious-blue;
border-color: $curious-blue;
}
&--un-checked {
background: $white;
border: 2px solid $Grey-100;
border-radius: 2px;
width: 18px;
height: 18px;
&:disabled {
color: $Grey-100;
cursor: not-allowed;
opacity: 0.5;
}
}
}

View File

@ -2,6 +2,7 @@ $fa-font-path: 'fonts/fontawesome';
@import '../../../../../node_modules/@fortawesome/fontawesome-free/scss/fontawesome.scss';
@import '../../../../../node_modules/@fortawesome/fontawesome-free/scss/solid.scss';
@import '../../../../../node_modules/@fortawesome/fontawesome-free/scss/regular.scss';
@font-face {
font-family: 'Roboto';

View File

@ -3,7 +3,7 @@ import React, { Component } from 'react'
import classnames from 'classnames'
import Identicon from '../../../components/ui/identicon'
import Button from '../../../components/ui/button'
import CheckBox from '../../../components/ui/check-box'
import CheckBox, { CHECKED, INDETERMINATE, UNCHECKED } from '../../../components/ui/check-box'
import Tooltip from '../../../components/ui/tooltip-v2'
import { PRIMARY } from '../../../helpers/constants/common'
import UserPreferencedCurrencyDisplay from '../../../components/app/user-preferenced-currency-display'
@ -90,7 +90,7 @@ export default class ChooseAccount extends Component {
<div className="permissions-connect-choose-account__account-info-wrapper">
<CheckBox
className="permissions-connect-choose-account__list-check-box"
checked={ selectedAccounts.has(address) }
checked={selectedAccounts.has(address)}
/>
<Identicon
diameter={34}
@ -128,6 +128,17 @@ export default class ChooseAccount extends Component {
renderAccountsListHeader () {
const { t } = this.context
const { selectNewAccountViaModal, accounts } = this.props
const { selectedAccounts } = this.state
let checked
if (this.allAreSelected()) {
checked = CHECKED
} else if (selectedAccounts.size === 0) {
checked = UNCHECKED
} else {
checked = INDETERMINATE
}
return (
<div
className={classnames({
@ -140,7 +151,7 @@ export default class ChooseAccount extends Component {
<div className="permissions-connect-choose-account__select-all">
<CheckBox
className="permissions-connect-choose-account__header-check-box"
checked={this.allAreSelected()}
checked={checked}
onClick={() => (this.allAreSelected() ? this.deselectAll() : this.selectAll())}
/>
<div className="permissions-connect-choose-account__text-grey">{ this.context.t('selectAll') }</div>