react-feather#Edit TypeScript Examples
The following examples show how to use
react-feather#Edit.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: EditorTreeFileItem.tsx From gear-js with GNU General Public License v3.0 | 5 votes |
EditorTreeFileItem = ({ item, isActive }: ItemProps) => {
const { dispatch, onNodeClick, setCurrentFile } = useEditorTreeContext();
const [isEditing, setEditing] = useState(false);
function handleEdit() {
setEditing(true);
}
function handleDelete() {
// TODO: change to modal lib
// eslint-disable-next-line no-alert
if (window.confirm('Are you sure?') && dispatch) {
dispatch({ type: FILE.DELETE, payload: { parentId: item.parentId, nodeId: item.id } });
setCurrentFile(null);
}
}
const handleCancel = () => {
setEditing(false);
};
const handleSubmit = (name: string) => {
if (dispatch) {
dispatch({ type: FILE.UPDATE, payload: { parentId: item.parentId, nodeId: item.id, newName: name } });
setEditing(false);
}
};
const handleNodeClick = React.useCallback(() => {
onNodeClick(item);
}, [item, onNodeClick]);
return (
<div className={clsx('editor-tree__item', isActive && 'is-active')}>
<div className="editor-tree__line" onClick={handleNodeClick} role="button" tabIndex={0} aria-hidden="true">
<File size={12} />
{isEditing ? (
<EditorTreeInput onCancel={handleCancel} onSubmit={handleSubmit} value={item.name} type={EditorTypes.file} />
) : (
<>{`${item.name}`}</>
)}
</div>
<div className="tree-actions">
<button className="tree-actions__btn" onClick={handleEdit} type="button">
<Edit size={12} color="#fff" />
</button>
<button className="tree-actions__btn" onClick={handleDelete} type="button">
<Trash size={12} color="#fff" />
</button>
</div>
</div>
);
}
Example #2
Source File: getMenuOrDrawerItems.tsx From calories-in with MIT License | 5 votes |
EditStyled = chakra(Edit)
Example #3
Source File: getMenuOrDrawerItems.tsx From calories-in with MIT License | 5 votes |
EditStyled = chakra(Edit)
Example #4
Source File: getMenuOrDrawerItems.tsx From calories-in with MIT License | 5 votes |
EditStyled = chakra(Edit)
Example #5
Source File: ExpandableListItemInput.tsx From bee-dashboard with BSD 3-Clause "New" or "Revised" License | 4 votes |
export default function ExpandableListItemKey({
label,
value,
onConfirm,
onChange,
confirmLabel,
confirmLabelDisabled,
expandedOnly,
helperText,
placeholder,
loading,
mapperFn,
locked,
}: Props): ReactElement | null {
const classes = useStyles()
const [open, setOpen] = useState(Boolean(expandedOnly))
const [inputValue, setInputValue] = useState<string>(value || '')
const toggleOpen = () => setOpen(!open)
const handleChange = (e: ChangeEvent<HTMLTextAreaElement>) => {
if (mapperFn) {
e.target.value = mapperFn(e.target.value)
}
setInputValue(e.target.value)
if (onChange) onChange(e.target.value)
}
return (
<>
<ListItem className={`${classes.header} ${open ? classes.headerOpen : ''}`}>
<Grid container direction="column" justifyContent="space-between" alignItems="stretch">
<Grid container direction="row" justifyContent="space-between" alignItems="center">
{label && (
<Typography variant="body1" className={classes.unselectableLabel}>
{label}
</Typography>
)}
<Typography variant="body2">
<div>
{!open && value}
{!expandedOnly && !locked && (
<IconButton size="small" className={classes.copyValue}>
{open ? (
<Minus onClick={toggleOpen} strokeWidth={1} />
) : (
<Edit onClick={toggleOpen} strokeWidth={1} />
)}
</IconButton>
)}
</div>
</Typography>
</Grid>
<Collapse in={open} timeout="auto" unmountOnExit>
<InputBase
value={inputValue}
placeholder={placeholder}
onChange={handleChange}
fullWidth
className={classes.content}
autoFocus
hidden={locked}
/>
</Collapse>
</Grid>
</ListItem>
<Collapse in={open} timeout="auto" unmountOnExit>
{helperText && <ExpandableListItemNote>{helperText}</ExpandableListItemNote>}
<ExpandableListItemActions>
<SwarmButton
disabled={
loading ||
inputValue === value ||
Boolean(confirmLabelDisabled) || // Disable if external validation is provided
(inputValue === '' && value === undefined) // Disable if no initial value was not provided and the field is empty. The undefined check is improtant so that it is possible to submit with empty input in other cases
}
loading={loading}
iconType={Search}
onClick={() => {
if (onConfirm) onConfirm(inputValue)
}}
>
{confirmLabel || 'Save'}
</SwarmButton>
<SwarmButton
disabled={loading || inputValue === value || inputValue === ''}
iconType={X}
onClick={() => setInputValue(value || '')}
cancel
>
Cancel
</SwarmButton>
</ExpandableListItemActions>
</Collapse>
</>
)
}
Example #6
Source File: EditorTreeFolderItem.tsx From gear-js with GNU General Public License v3.0 | 4 votes |
EditorTreeFolderItem = ({ item, children }: ItemProps) => {
const { dispatch, setCurrentFile } = useEditorTreeContext();
const [isEditing, setEditing] = useState(false);
const [isOpen, setIsOpen] = useState(false);
const [childrenCopy, setChildrenCopy] = useState<ReactNode[]>([]);
useEffect(() => {
setChildrenCopy([children]);
}, [children]);
const commitAddFile = (name: string) => {
if (dispatch) {
dispatch({ type: FILE.CREATE, payload: { parentId: item.id, newName: name } });
setCurrentFile(null);
}
};
const commitUpdateFolderName = (name: string) => {
if (dispatch) {
dispatch({ type: FOLDER.UPDATE, payload: { parentId: item.parentId, nodeId: item.id, newName: name } });
setEditing(false);
}
};
const commitAddFolder = (name: string) => {
if (dispatch) {
dispatch({ type: FOLDER.CREATE, payload: { parentId: item.id, newName: name } });
}
};
const handleDelete = () => {
// TODO: change to modal lib
// eslint-disable-next-line no-alert
if (window.confirm('Are you sure?') && dispatch) {
dispatch({ type: FOLDER.DELETE, payload: { parentId: item.parentId, nodeId: item.id } });
setCurrentFile(null);
}
};
function handleClick() {
setIsOpen(!isOpen);
}
function handleEdit(event: React.SyntheticEvent) {
event.stopPropagation();
setEditing(true);
}
function handleCancel() {
setEditing(false);
setChildrenCopy([children]);
}
function handleAddFile(event: React.SyntheticEvent) {
event.stopPropagation();
setIsOpen(true);
/* eslint-disable react/jsx-no-bind */
setChildrenCopy([
...childrenCopy,
<EditorTreeInput
type={EditorTypes.file}
onSubmit={commitAddFile}
onCancel={handleCancel}
key={`editor-file-input-${item.id}`}
/>,
]);
}
function handleAddFolder(event: React.SyntheticEvent) {
event.stopPropagation();
setIsOpen(true);
/* eslint-disable react/jsx-no-bind */
setChildrenCopy([
...childrenCopy,
<EditorTreeInput
key={`editor-folder-input-${item.id}`}
type={EditorTypes.folder}
onSubmit={commitAddFolder}
onCancel={handleCancel}
/>,
]);
}
/* eslint-disable react/jsx-no-bind */
return (
<div className={clsx('editor-tree__folder', isOpen && 'is-open')}>
<div role="button" tabIndex={0} aria-hidden="true" className="editor-tree__item is-folder" onClick={handleClick}>
<div className="editor-tree__line">
<Folder size={12} />
{isEditing ? (
<EditorTreeInput
type={EditorTypes.folder}
onSubmit={commitUpdateFolderName}
onCancel={handleCancel}
value={item.name}
/>
) : (
<>
<span>{item.name}</span>
</>
)}
</div>
<div className="tree-actions">
<button className="tree-actions__btn" onClick={handleAddFolder} type="button">
<FolderPlus size={12} color="#fff" />
</button>
<button className="tree-actions__btn" onClick={handleAddFile} type="button">
<FilePlus size={12} color="#fff" />
</button>
<button className="tree-actions__btn" onClick={handleEdit} type="button">
<Edit size={12} color="#fff" />
</button>
<button className="tree-actions__btn" onClick={handleDelete} type="button">
<Trash size={12} color="#fff" />
</button>
</div>
</div>
<div className="editor-tree__folder-items">{childrenCopy}</div>
</div>
);
}
Example #7
Source File: CurrencySearch.tsx From limit-orders-lib with GNU General Public License v3.0 | 4 votes |
export function CurrencySearch({
selectedCurrency,
onCurrencySelect,
otherSelectedCurrency,
showCommonBases,
onDismiss,
isOpen,
showManageView,
showImportView,
setImportToken,
}: CurrencySearchProps) {
const { chainId } = useWeb3();
const theme = useTheme();
// refs for fixed size lists
const fixedList = useRef<FixedSizeList>();
const [searchQuery, setSearchQuery] = useState<string>("");
const debouncedQuery = useDebounce(searchQuery, 200);
const [invertSearchOrder] = useState<boolean>(false);
const allTokens = useAllTokens();
// if they input an address, use it
const isAddressSearch = isAddress(debouncedQuery);
const searchToken = useToken(debouncedQuery);
const searchTokenIsAdded = useIsUserAddedToken(searchToken);
const tokenComparator = useTokenComparator(invertSearchOrder);
const filteredTokens: Token[] = useMemo(() => {
return filterTokens(Object.values(allTokens), debouncedQuery);
}, [allTokens, debouncedQuery]);
const sortedTokens: Token[] = useMemo(() => {
return filteredTokens.sort(tokenComparator);
}, [filteredTokens, tokenComparator]);
const filteredSortedTokens = useSortedTokensByQuery(
sortedTokens,
debouncedQuery
);
const ether = useCurrency("NATIVE");
const filteredSortedTokensWithETH: Currency[] = useMemo(() => {
const s = debouncedQuery.toLowerCase().trim();
if (s === "" || s === "e" || s === "et" || s === "eth") {
return ether ? [ether, ...filteredSortedTokens] : filteredSortedTokens;
}
return filteredSortedTokens;
}, [debouncedQuery, ether, filteredSortedTokens]);
const handleCurrencySelect = useCallback(
(currency: Currency) => {
onCurrencySelect(currency);
onDismiss();
},
[onDismiss, onCurrencySelect]
);
// clear the input on open
useEffect(() => {
if (isOpen) setSearchQuery("");
}, [isOpen]);
// manage focus on modal show
const inputRef = useRef<HTMLInputElement>();
const handleInput = useCallback((event) => {
const input = event.target.value;
const checksummedInput = isAddress(input);
setSearchQuery(checksummedInput || input);
fixedList.current?.scrollTo(0);
}, []);
const handleEnter = useCallback(
(e: KeyboardEvent<HTMLInputElement>) => {
if (e.key === "Enter") {
const s = debouncedQuery.toLowerCase().trim();
if (s === "eth" && ether) {
handleCurrencySelect(ether);
} else if (filteredSortedTokensWithETH.length > 0) {
if (
filteredSortedTokensWithETH[0].symbol?.toLowerCase() ===
debouncedQuery.trim().toLowerCase() ||
filteredSortedTokensWithETH.length === 1
) {
handleCurrencySelect(filteredSortedTokensWithETH[0]);
}
}
}
},
[debouncedQuery, ether, filteredSortedTokensWithETH, handleCurrencySelect]
);
// menu ui
const [open, toggle] = useToggle(false);
const node = useRef<HTMLDivElement>();
useOnClickOutside(node, open ? toggle : undefined);
// if no results on main list, show option to expand into inactive
const filteredInactiveTokens = useSearchInactiveTokenLists(
filteredTokens.length === 0 ||
(debouncedQuery.length > 2 && !isAddressSearch)
? debouncedQuery
: undefined
);
return (
<ContentWrapper>
<PaddedColumn gap="16px">
<RowBetween>
<Text fontWeight={500} fontSize={16}>
Select a token
</Text>
<CloseIcon onClick={onDismiss} />
</RowBetween>
<Row>
<SearchInput
type="text"
id="token-search-input"
placeholder={"Search name or paste address"}
autoComplete="off"
value={searchQuery}
ref={inputRef as RefObject<HTMLInputElement>}
onChange={handleInput}
onKeyDown={handleEnter}
/>
</Row>
{showCommonBases && (
<CommonBases
chainId={chainId}
onSelect={handleCurrencySelect}
selectedCurrency={selectedCurrency}
/>
)}
</PaddedColumn>
<Separator />
{searchToken && !searchTokenIsAdded ? (
<Column style={{ padding: "20px 0", height: "100%" }}>
<ImportRow
token={searchToken}
showImportView={showImportView}
setImportToken={setImportToken}
/>
</Column>
) : filteredSortedTokens?.length > 0 ||
filteredInactiveTokens?.length > 0 ? (
<div style={{ flex: "1" }}>
<AutoSizer disableWidth>
{({ height }) => (
<CurrencyList
height={height}
currencies={filteredSortedTokensWithETH}
otherListTokens={filteredInactiveTokens}
onCurrencySelect={handleCurrencySelect}
otherCurrency={otherSelectedCurrency}
selectedCurrency={selectedCurrency}
fixedListRef={fixedList}
showImportView={showImportView}
setImportToken={setImportToken}
/>
)}
</AutoSizer>
</div>
) : (
<Column style={{ padding: "20px", height: "100%" }}>
<TYPE.main color={theme.text3} textAlign="center" mb="20px">
No results found.
</TYPE.main>
</Column>
)}
<Footer>
<Row justify="center">
<ButtonText
onClick={showManageView}
color={theme.blue1}
className="list-token-manage-button"
>
<RowFixed>
<IconWrapper size="16px" marginRight="6px">
<Edit />
</IconWrapper>
<TYPE.main color={theme.blue1}>Manage Token Lists</TYPE.main>
</RowFixed>
</ButtonText>
</Row>
</Footer>
</ContentWrapper>
);
}
Example #8
Source File: CurrencySearch.tsx From forward.swaps with GNU General Public License v3.0 | 4 votes |
export function CurrencySearch({
selectedCurrency,
onCurrencySelect,
otherSelectedCurrency,
showCommonBases,
onDismiss,
isOpen,
showManageView,
showImportView,
setImportToken
}: CurrencySearchProps) {
const { t } = useTranslation()
const { chainId } = useActiveWeb3React()
const theme = useTheme()
// refs for fixed size lists
const fixedList = useRef<FixedSizeList>()
const [searchQuery, setSearchQuery] = useState<string>('')
const [invertSearchOrder] = useState<boolean>(false)
const allTokens = useAllTokens()
// const inactiveTokens: Token[] | undefined = useFoundOnInactiveList(searchQuery)
// if they input an address, use it
const isAddressSearch = isAddress(searchQuery)
const searchToken = useToken(searchQuery)
const searchTokenIsAdded = useIsUserAddedToken(searchToken)
useEffect(() => {
if (isAddressSearch) {
ReactGA.event({
category: 'Currency Select',
action: 'Search by address',
label: isAddressSearch
})
}
}, [isAddressSearch])
const showETH: boolean = useMemo(() => {
const s = searchQuery.toLowerCase().trim()
return s === '' || s === 'e' || s === 'et' || s === 'eth'
}, [searchQuery])
const tokenComparator = useTokenComparator(invertSearchOrder)
const filteredTokens: Token[] = useMemo(() => {
return filterTokens(Object.values(allTokens), searchQuery)
}, [allTokens, searchQuery])
const filteredSortedTokens: Token[] = useMemo(() => {
const sorted = filteredTokens.sort(tokenComparator)
const symbolMatch = searchQuery
.toLowerCase()
.split(/\s+/)
.filter(s => s.length > 0)
if (symbolMatch.length > 1) {
return sorted
}
return [
// sort any exact symbol matches first
...sorted.filter(token => token.symbol?.toLowerCase() === symbolMatch[0]),
// sort by tokens whos symbols start with search substrng
...sorted.filter(
token =>
token.symbol?.toLowerCase().startsWith(searchQuery.toLowerCase().trim()) &&
token.symbol?.toLowerCase() !== symbolMatch[0]
),
// rest that dont match upove
...sorted.filter(
token =>
!token.symbol?.toLowerCase().startsWith(searchQuery.toLowerCase().trim()) &&
token.symbol?.toLowerCase() !== symbolMatch[0]
)
]
}, [filteredTokens, searchQuery, tokenComparator])
const handleCurrencySelect = useCallback(
(currency: Currency) => {
onCurrencySelect(currency)
onDismiss()
},
[onDismiss, onCurrencySelect]
)
// clear the input on open
useEffect(() => {
if (isOpen) setSearchQuery('')
}, [isOpen])
// manage focus on modal show
const inputRef = useRef<HTMLInputElement>()
const handleInput = useCallback(event => {
const input = event.target.value
const checksummedInput = isAddress(input)
setSearchQuery(checksummedInput || input)
fixedList.current?.scrollTo(0)
}, [])
const handleEnter = useCallback(
(e: KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter') {
const s = searchQuery.toLowerCase().trim()
if (s === 'eth') {
handleCurrencySelect(ETHER)
} else if (filteredSortedTokens.length > 0) {
if (
filteredSortedTokens[0].symbol?.toLowerCase() === searchQuery.trim().toLowerCase() ||
filteredSortedTokens.length === 1
) {
handleCurrencySelect(filteredSortedTokens[0])
}
}
}
},
[filteredSortedTokens, handleCurrencySelect, searchQuery]
)
// menu ui
const [open, toggle] = useToggle(false)
const node = useRef<HTMLDivElement>()
useOnClickOutside(node, open ? toggle : undefined)
// if no results on main list, show option to expand into inactive
const [showExpanded, setShowExpanded] = useState(false)
const inactiveTokens = useFoundOnInactiveList(searchQuery)
// reset expanded results on query reset
useEffect(() => {
if (searchQuery === '') {
setShowExpanded(false)
}
}, [setShowExpanded, searchQuery])
return (
<ContentWrapper>
<PaddedColumn gap="16px">
<RowBetween>
<Text fontWeight={500} fontSize={16}>
Select a token
</Text>
<CloseIcon onClick={onDismiss} />
</RowBetween>
<Row>
<SearchInput
type="text"
id="token-search-input"
placeholder={t('tokenSearchPlaceholder')}
autoComplete="off"
value={searchQuery}
ref={inputRef as RefObject<HTMLInputElement>}
onChange={handleInput}
onKeyDown={handleEnter}
/>
</Row>
{showCommonBases && (
<CommonBases chainId={chainId} onSelect={handleCurrencySelect} selectedCurrency={selectedCurrency} />
)}
</PaddedColumn>
<Separator />
{searchToken && !searchTokenIsAdded ? (
<Column style={{ padding: '20px 0', height: '100%' }}>
<ImportRow token={searchToken} showImportView={showImportView} setImportToken={setImportToken} />
</Column>
) : filteredSortedTokens?.length > 0 || (showExpanded && inactiveTokens && inactiveTokens.length > 0) ? (
<div style={{ flex: '1' }}>
<AutoSizer disableWidth>
{({ height }) => (
<CurrencyList
height={height}
showETH={showETH}
currencies={
showExpanded && inactiveTokens ? filteredSortedTokens.concat(inactiveTokens) : filteredSortedTokens
}
onCurrencySelect={handleCurrencySelect}
otherCurrency={otherSelectedCurrency}
selectedCurrency={selectedCurrency}
fixedListRef={fixedList}
showImportView={showImportView}
setImportToken={setImportToken}
/>
)}
</AutoSizer>
</div>
) : (
<Column style={{ padding: '20px', height: '100%' }}>
<TYPE.main color={theme.text3} textAlign="center" mb="20px">
No results found in active lists.
</TYPE.main>
{inactiveTokens &&
inactiveTokens.length > 0 &&
!(searchToken && !searchTokenIsAdded) &&
searchQuery.length > 1 &&
filteredSortedTokens?.length === 0 && (
// expand button in line with no results
<Row align="center" width="100%" justify="center">
<ButtonLight
width="fit-content"
borderRadius="12px"
padding="8px 12px"
onClick={() => setShowExpanded(!showExpanded)}
>
{!showExpanded
? `Show ${inactiveTokens.length} more inactive ${inactiveTokens.length === 1 ? 'token' : 'tokens'}`
: 'Hide expanded search'}
</ButtonLight>
</Row>
)}
</Column>
)}
{inactiveTokens &&
inactiveTokens.length > 0 &&
!(searchToken && !searchTokenIsAdded) &&
(searchQuery.length > 1 || showExpanded) &&
(filteredSortedTokens?.length !== 0 || showExpanded) && (
// button fixed to bottom
<Row align="center" width="100%" justify="center" style={{ position: 'absolute', bottom: '80px', left: 0 }}>
<ButtonLight
width="fit-content"
borderRadius="12px"
padding="8px 12px"
onClick={() => setShowExpanded(!showExpanded)}
>
{!showExpanded
? `Show ${inactiveTokens.length} more inactive ${inactiveTokens.length === 1 ? 'token' : 'tokens'}`
: 'Hide expanded search'}
</ButtonLight>
</Row>
)}
<Footer>
<Row justify="center">
<ButtonText onClick={showManageView} color={theme.blue1} className="list-token-manage-button">
<RowFixed>
<IconWrapper size="16px" marginRight="6px">
<Edit />
</IconWrapper>
<TYPE.main color={theme.blue1}>Manage</TYPE.main>
</RowFixed>
</ButtonText>
</Row>
</Footer>
</ContentWrapper>
)
}