mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-27 21:00:13 +01:00
ba54a3d83b
The ESLint config has been updated to v8. The breaking changes are: * The Prettier rule `quoteProps` has been changed from `consistent` to `as-needed`, meaning that if one key requires quoting, only that key is quoted rather than all keys. * The ESLint rule `no-shadow` has been made more strict. It now prevents globals from being shadowed as well. Most of these changes were applied with `yarn lint:fix`. Only the shadowing changes required manual fixing (shadowing variable names were either replaced with destructuring or renamed). The dependency `globalThis` was added to the list of dynamic dependencies in the build system, where it should have been already. This was causing `depcheck` to fail because the new lint rules required removing the one place where `globalThis` had been erroneously imported previously. A rule requiring a newline between multiline blocks and expressions has been disabled temporarily to make this PR smaller and to avoid introducing conflicts with other PRs.
178 lines
4.7 KiB
JavaScript
178 lines
4.7 KiB
JavaScript
import React, { useState, useRef, useEffect } from 'react';
|
|
import PropTypes from 'prop-types';
|
|
import classnames from 'classnames';
|
|
import DropdownSearchList from '../dropdown-search-list';
|
|
import TextField from '../../../components/ui/text-field';
|
|
|
|
const characterWidthMap = {
|
|
1: 5.86,
|
|
2: 10.05,
|
|
3: 10.45,
|
|
4: 11.1,
|
|
5: 10,
|
|
6: 10.06,
|
|
7: 9.17,
|
|
8: 10.28,
|
|
9: 10.06,
|
|
0: 11.22,
|
|
'.': 4.55,
|
|
};
|
|
|
|
const getInputWidth = (value) => {
|
|
const valueString = String(value);
|
|
const charArray = valueString.split('');
|
|
return charArray.reduce(
|
|
(inputWidth, _char) => inputWidth + characterWidthMap[_char],
|
|
12,
|
|
);
|
|
};
|
|
export default function DropdownInputPair({
|
|
itemsToSearch = [],
|
|
onInputChange,
|
|
inputValue = '',
|
|
onSelect,
|
|
leftValue,
|
|
selectedItem,
|
|
SearchListPlaceholder,
|
|
maxListItems,
|
|
selectPlaceHolderText,
|
|
loading,
|
|
hideItemIf,
|
|
listContainerClassName,
|
|
autoFocus,
|
|
}) {
|
|
const [isOpen, setIsOpen] = useState(false);
|
|
const open = () => setIsOpen(true);
|
|
const close = () => setIsOpen(false);
|
|
const inputRef = useRef();
|
|
const onTextFieldChange = (event) => {
|
|
event.stopPropagation();
|
|
// Automatically prefix value with 0. if user begins typing .
|
|
const valueToUse = event.target.value === '.' ? '0.' : event.target.value;
|
|
|
|
// Regex that validates strings with only numbers, 'x.', '.x', and 'x.x'
|
|
const regexp = /^(\.\d+|\d+(\.\d+)?|\d+\.)$/u;
|
|
// If the value is either empty or contains only numbers and '.' and only has one '.', update input to match
|
|
if (valueToUse === '' || regexp.test(valueToUse)) {
|
|
onInputChange(valueToUse);
|
|
} else {
|
|
// otherwise, use the previously set inputValue (effectively denying the user from inputting the last char)
|
|
// or an empty string if we do not yet have an inputValue
|
|
onInputChange(inputValue || '');
|
|
}
|
|
};
|
|
const [applyTwoLineStyle, setApplyTwoLineStyle] = useState(null);
|
|
useEffect(() => {
|
|
setApplyTwoLineStyle(
|
|
(inputRef?.current?.getBoundingClientRect()?.width || 0) +
|
|
getInputWidth(inputValue || '') >
|
|
137,
|
|
);
|
|
}, [inputValue, inputRef]);
|
|
|
|
return (
|
|
<div className="dropdown-input-pair">
|
|
<DropdownSearchList
|
|
itemsToSearch={itemsToSearch}
|
|
SearchListPlaceholder={SearchListPlaceholder}
|
|
fuseSearchKeys={[
|
|
{ name: 'name', weight: 0.499 },
|
|
{ name: 'symbol', weight: 0.499 },
|
|
{ name: 'address', weight: 0.002 },
|
|
]}
|
|
maxListItems={maxListItems}
|
|
onOpen={open}
|
|
onClose={close}
|
|
onSelect={onSelect}
|
|
className={isOpen ? 'dropdown-input-pair__list--full-width' : ''}
|
|
externallySelectedItem={selectedItem}
|
|
selectPlaceHolderText={selectPlaceHolderText}
|
|
selectorClosedClassName="dropdown-input-pair__selector--closed"
|
|
listContainerClassName={listContainerClassName}
|
|
loading={loading}
|
|
hideItemIf={hideItemIf}
|
|
defaultToAll
|
|
/>
|
|
{!isOpen && (
|
|
<TextField
|
|
className={classnames('dropdown-input-pair__input', {
|
|
'dropdown-input-pair__two-line-input': applyTwoLineStyle,
|
|
})}
|
|
type="text"
|
|
placeholder="0"
|
|
onChange={onTextFieldChange}
|
|
fullWidth
|
|
margin="dense"
|
|
value={inputValue}
|
|
autoFocus={autoFocus}
|
|
/>
|
|
)}
|
|
{!isOpen && leftValue && (
|
|
<div
|
|
className={classnames('dropdown-input-pair__left-value', {
|
|
'dropdown-input-pair__left-value--two-lines': applyTwoLineStyle,
|
|
})}
|
|
ref={inputRef}
|
|
>
|
|
≈ {leftValue}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
DropdownInputPair.propTypes = {
|
|
/**
|
|
* Give items data for the component
|
|
*/
|
|
itemsToSearch: PropTypes.array,
|
|
/**
|
|
* Handler for input change
|
|
*/
|
|
onInputChange: PropTypes.func,
|
|
/**
|
|
* Show input value content
|
|
*/
|
|
inputValue: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
/**
|
|
* Handler for onSelect
|
|
*/
|
|
onSelect: PropTypes.func,
|
|
/**
|
|
* Set value to left
|
|
*/
|
|
leftValue: PropTypes.string,
|
|
/**
|
|
* Show selected item
|
|
*/
|
|
selectedItem: PropTypes.object,
|
|
/**
|
|
* Doesn't look like this is used
|
|
*/
|
|
SearchListPlaceholder: PropTypes.func,
|
|
/**
|
|
* Define maximum item per list
|
|
*/
|
|
maxListItems: PropTypes.number,
|
|
/**
|
|
* Show select placeholder text
|
|
*/
|
|
selectPlaceHolderText: PropTypes.string,
|
|
/**
|
|
* Check if the component is loading
|
|
*/
|
|
loading: PropTypes.bool,
|
|
/**
|
|
* Handler for hide item
|
|
*/
|
|
hideItemIf: PropTypes.func,
|
|
/**
|
|
* Add custom CSS class for list container
|
|
*/
|
|
listContainerClassName: PropTypes.string,
|
|
/**
|
|
* Check if the component is auto focus
|
|
*/
|
|
autoFocus: PropTypes.bool,
|
|
};
|