react#KeyboardEvent TypeScript Examples
The following examples show how to use
react#KeyboardEvent.
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: index.ts From anchor-web-app with Apache License 2.0 | 6 votes |
/**
* @param availableCharacters 'abc', 'a-z', 'a-z0-9'
*/
export function useRestrictedInput(
availableCharacters: ((character: string) => boolean) | string,
): RestrictedInputReturn {
const test: (character: string) => boolean = useMemo(() => {
if (typeof availableCharacters === 'string') {
const pattern: RegExp = new RegExp(`[${availableCharacters}]`);
return (character: string) => pattern.test(character);
} else if (typeof availableCharacters === 'function') {
return availableCharacters;
}
throw new Error('availableCharacters must be string or function');
}, [availableCharacters]);
const onKeyPress: (event: KeyboardEvent<HTMLInputElement>) => void =
useCallback(
(event: KeyboardEvent<HTMLInputElement>) => {
if (!test(event.key)) {
// prevent key press
event.preventDefault();
event.stopPropagation();
}
},
[test],
);
return {
onKeyPress,
};
}
Example #2
Source File: plugin.ts From brilliant with MIT License | 6 votes |
onTab = (
e: KeyboardEvent,
{ getEditorState, setEditorState }: PluginFunctions
): void => {
const editorState = getEditorState();
const selection = editorState.getSelection();
const content = editorState.getCurrentContent();
const type = content.getBlockForKey(selection.getStartKey()).getType();
if (type === 'unordered-list-item' || type === 'ordered-list-item') {
setEditorState(RichUtils.onTab(e as any, editorState, 4));
e.preventDefault();
return;
}
const newContentState = Modifier.insertText(
content,
selection,
' ',
editorState.getCurrentInlineStyle()
);
setEditorState(
EditorState.push(editorState, newContentState, 'insert-fragment')
);
e.preventDefault();
};
Example #3
Source File: index.tsx From reskript with MIT License | 6 votes |
export default function Create({onSubmit}: Props) {
const [value, setValue] = useState('');
const updateValue = useCallback(
(e: ChangeEvent<HTMLInputElement>) => setValue(e.target.value),
[]
);
const submit = useCallback(
(e: KeyboardEvent<HTMLInputElement>) => {
const description = value.trim();
if (description && e.key === 'Enter') {
e.preventDefault();
onSubmit({description});
setValue('');
}
},
[onSubmit, value]
);
return (
<div id="create">
<Input
className={c.input}
placeholder="What needs to be done?"
value={value}
onChange={updateValue}
onKeyDown={submit}
/>
</div>
);
}
Example #4
Source File: CalculatorInputs.tsx From po8klasie with GNU General Public License v3.0 | 6 votes |
GradeInput: FC<CalculatorInputProps> = ({ inputId, ...props }) => {
const { watch, setValue: setValueOriginal, setError } = useFormContext();
const value = watch(inputId);
const setValue = (updatedValue: number | null) => setValueOriginal(inputId, updatedValue);
const handleKeyDown = (e: KeyboardEvent) => {
if (['Backspace', 'Delete'].includes(e.key)) {
e.preventDefault();
setValue(null);
}
};
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
const len = e.target.value.length;
const updatedValue = len > 0 ? e.target.value[len - 1] : '';
const parsedValue = parseInt(updatedValue, 10);
if (isGradeValid(parsedValue)) setValue(parsedValue);
else {
setValue(null);
setError(inputId, { message: 'Invalid value' });
}
};
const inputProps: Partial<HTMLProps<HTMLInputElement>> = {
...props,
placeholder: '5',
'aria-label': 'Ocena',
inputMode: 'numeric',
value: value ?? '',
onKeyDown: handleKeyDown,
onChange: handleChange,
autoComplete: 'off',
};
return <input {...inputProps} data-testid="input" />;
}
Example #5
Source File: ChildrenControl.tsx From openchakra with MIT License | 6 votes |
ChildrenControl: React.FC = () => {
const dispatch = useDispatch()
const textInput = useRef<HTMLInputElement>(null)
const focusInput = useSelector(getInputTextFocused)
const { setValueFromEvent } = useForm()
const children = usePropsSelector('children')
const onKeyUp = (event: KeyboardEvent) => {
if (event.keyCode === 13 && textInput.current) {
textInput.current.blur()
}
}
useEffect(() => {
if (focusInput && textInput.current) {
textInput.current.focus()
} else if (focusInput === false && textInput.current) {
textInput.current.blur()
}
}, [focusInput])
return (
<FormControl htmlFor="children" label="Text">
<Input
id="children"
name="children"
size="sm"
value={children}
type="text"
onChange={setValueFromEvent}
ref={textInput}
onKeyUp={onKeyUp}
onBlur={() => {
dispatch.app.toggleInputText(false)
}}
/>
</FormControl>
)
}
Example #6
Source File: TorrentFilterStore.ts From flood with GNU General Public License v3.0 | 6 votes |
setTagFilters(filter: string, event: KeyboardEvent | MouseEvent | TouchEvent) {
const tags = Object.keys(this.taxonomy.tagCounts).sort((a, b) => {
if (a === 'untagged') return -1;
else if (b === 'untagged') return 1;
else return a.localeCompare(b);
});
// Put 'untagged' in the correct second position for shift click ordering
tags.splice(tags.indexOf('untagged'), 1);
tags.splice(1, 0, 'untagged');
this.computeFilters(tags, this.tagFilter, filter, event);
this.filterTrigger = !this.filterTrigger;
}
Example #7
Source File: useDatePicker.ts From use-platform with MIT License | 6 votes |
export function useDatePicker(
props: UseDatePickerProps,
state: UseDatePickerStateResult<Date | DateRangeValue | null>,
): UseDatePickerResult {
const { disabled, readOnly } = props
const onKeyDown = (event: KeyboardEvent) => {
if (disabled || readOnly) {
return
}
if (event.key === ' ') {
event.preventDefault()
event.stopPropagation()
state.setOpen(true)
}
}
const onPress = () => {
state.setOpen(!state.isOpen)
}
return {
groupProps: {
role: 'group',
onKeyDown,
},
triggerProps: {
tabIndex: -1,
onPress,
},
}
}
Example #8
Source File: TorrentListRow.tsx From flood with GNU General Public License v3.0 | 6 votes |
onKeyPress = (hash: string, e: KeyboardEvent) => {
if (e.key === ' ' || e.key === 'Enter' || e.key === 'ContextMenu') {
e.preventDefault();
if (TorrentStore.selectedTorrents.includes(hash)) {
if (e.key === 'Enter') {
displayTorrentDetails(hash);
} else if (e.key === 'ContextMenu') {
displayContextMenu(hash, e);
}
} else {
selectTorrent(hash, e);
}
}
}
Example #9
Source File: MessageFormatEditor.tsx From project-loved-web with MIT License | 5 votes |
function onKeyDown(event: KeyboardEvent): void {
if (event.key === 'Enter') {
event.preventDefault();
}
}
Example #10
Source File: plugin.ts From brilliant with MIT License | 5 votes |
keyBindingFn = (e: React.KeyboardEvent<{}>): string | null =>
handleMyKeyBindingFn(e, getDefaultKeyBinding);
Example #11
Source File: TorrentFilterStore.ts From flood with GNU General Public License v3.0 | 5 votes |
private computeFilters<T extends TorrentStatus | string>(
keys: readonly T[],
currentFilters: Array<T>,
newFilter: T,
event: KeyboardEvent | MouseEvent | TouchEvent,
) {
if (newFilter === ('' as T)) {
currentFilters.splice(0);
} else if (event.shiftKey) {
if (currentFilters.length) {
const lastKey = currentFilters[currentFilters.length - 1];
const lastKeyIndex = keys.indexOf(lastKey);
let currentKeyIndex = keys.indexOf(newFilter);
if (!~currentKeyIndex || !~lastKeyIndex) {
return;
}
// from the previously selected index to the currently selected index,
// add all filters to the selected array.
// if the newly selected index is larger than the previous, start from
// the newly selected index and work backwards. otherwise go forwards.
const increment = currentKeyIndex > lastKeyIndex ? -1 : 1;
for (; currentKeyIndex !== lastKeyIndex; currentKeyIndex += increment) {
const foundKey = keys[currentKeyIndex] as T;
// if the filter isn't already selected, add the filter to the array.
if (!currentFilters.includes(foundKey)) {
currentFilters.push(foundKey);
}
}
} else {
currentFilters.splice(0, currentFilters.length, newFilter);
}
} else if (event.metaKey || event.ctrlKey) {
if (currentFilters.includes(newFilter)) {
currentFilters.splice(currentFilters.indexOf(newFilter), 1);
} else {
currentFilters.push(newFilter);
}
} else {
currentFilters.splice(0, currentFilters.length, newFilter);
}
}
Example #12
Source File: index.tsx From anchor-web-app with Apache License 2.0 | 5 votes |
function RestoreBase(props: UIElementProps) {
const { className } = props;
const [input, state] = useRestoreTxForm();
const [restoreTx, txResult] = useRestoreTx();
const submit = useCallback(() => {
if (restoreTx) {
restoreTx({ txHash: state.txHash });
}
}, [state, restoreTx]);
if (
txResult?.status === StreamStatus.IN_PROGRESS ||
txResult?.status === StreamStatus.DONE
) {
return <TxRendering className={className} txResult={txResult} />;
}
return (
<CenteredLayout className={className} maxWidth={800}>
<Section>
<h1>Restore</h1>
<p className="text">
Below you may attempt to restore a stuck transaction. In order to
proceed with restoration, transaction hash is required.
</p>
<TextInput
className="tx-hash"
fullWidth
placeholder="TRANSACTION HASH"
value={state.txHash}
onChange={({ target }: ChangeEvent<HTMLInputElement>) =>
input({ txHash: target.value })
}
onKeyPress={({ key }: KeyboardEvent<HTMLInputElement>) => {
if (key === 'Enter') {
submit();
}
}}
/>
<ActionButton className="submit" onClick={submit}>
Restore
</ActionButton>
</Section>
</CenteredLayout>
);
}
Example #13
Source File: UserBox.tsx From tobira with Apache License 2.0 | 5 votes |
MenuItem: React.FC<MenuItemProps> = ({
icon,
children,
linkTo,
onClick = () => {},
className,
htmlLink = false,
borderBottom = false,
borderTop = false,
}) => {
const inner = <>
{icon ?? <svg />}
<div>{children}</div>
</>;
const css = {
display: "flex",
gap: 16,
alignItems: "center",
height: 40,
paddingLeft: "12px",
paddingRight: "16px",
cursor: "pointer",
whiteSpace: "nowrap",
color: "black",
...borderBottom && {
borderBottom: "1px solid var(--grey80)",
},
...borderTop && {
borderTop: "1px solid var(--grey80)",
},
"& > svg": {
fontSize: 22,
width: 24,
strokeWidth: 1.5,
"& > path": {
strokeWidth: "inherit",
},
},
"&:hover": {
backgroundColor: "var(--grey97)",
},
...FOCUS_STYLE_INSET,
} as const;
// One should be able to use the menu with keyboard only. So if the item is
// focussed, pressing enter should have the same effect as clicking it.
// Thats already true automatically for links.
const onKeyDown = (e: KeyboardEvent<HTMLLIElement>) => {
if (document.activeElement === e.currentTarget && e.key === "Enter") {
onClick();
}
};
return linkTo
? <li {... { className }}>
<Link to={linkTo} css={css} {...{ htmlLink, onClick, className }}>{inner}</Link>
</li>
: <li tabIndex={0} css={css} {...{ onClick, className, onKeyDown }}>
{inner}
</li>;
}
Example #14
Source File: FileLocation.tsx From firebase-tools-ui with Apache License 2.0 | 5 votes |
FileLocation: React.FC<
React.PropsWithChildren<FileLocationProps>
> = ({ fullPath }) => {
const { tokens, createToken, deleteToken } = useTokens(fullPath);
const { getLocation } = useStorageFiles();
const { writeText } = useClipboard();
return (
<Accordion title="File location">
<dl className={styles.metadata}>
<Typography use="body2" tag="dt" theme="secondary">
File location
</Typography>
<Typography use="body2" tag="dd" className={styles.location}>
{getLocation(fullPath)}
</Typography>
{tokens.map((token) => (
<div key={token}>
<Typography use="body2" tag="dt" theme="secondary">
Access token
<SimpleMenu
handle={<IconButton icon="more_vert" label="Open menu" />}
renderToPortal
>
<MenuItem
onKeyDown={(e: KeyboardEvent<HTMLElement>) => {
if (e.key === 'Enter' || e.key === ' ') {
deleteToken(token);
}
}}
onClick={() => deleteToken(token)}
>
Revoke
</MenuItem>
</SimpleMenu>
</Typography>
<Typography use="body2" tag="dd">
<Tooltip content="Click to copy the token to clipboard">
<input
aria-label="Token, press Enter to copy"
className={styles.token}
readOnly
value={token}
onClick={() => writeText(token)}
onKeyDown={(e: KeyboardEvent<HTMLElement>) => {
if (e.key === 'Enter' || e.key === ' ') {
writeText(token);
}
}}
/>
</Tooltip>
</Typography>
</div>
))}
</dl>
<Button unelevated onClick={createToken}>
Create new access token
</Button>
</Accordion>
);
}
Example #15
Source File: TorrentFilterStore.ts From flood with GNU General Public License v3.0 | 5 votes |
setTrackerFilters(filter: string, event: KeyboardEvent | MouseEvent | TouchEvent) {
const trackers = Object.keys(this.taxonomy.trackerCounts).sort((a, b) => a.localeCompare(b));
this.computeFilters(trackers, this.trackerFilter, filter, event);
this.filterTrigger = !this.filterTrigger;
}
Example #16
Source File: TagsInput.tsx From grafana-chinese with Apache License 2.0 | 5 votes |
onKeyboardAdd = (event: KeyboardEvent) => {
event.preventDefault();
if (event.key === 'Enter' && this.state.newTag !== '') {
this.setNewTags();
}
};
Example #17
Source File: CurrencySearch.tsx From goose-frontend-amm with GNU General Public License v3.0 | 5 votes |
export function CurrencySearch({
selectedCurrency,
onCurrencySelect,
otherSelectedCurrency,
showCommonBases,
onDismiss,
isOpen,
onChangeList,
}: CurrencySearchProps) {
const { t } = useTranslation()
const { chainId } = useActiveWeb3React()
const theme = useContext(ThemeContext)
const fixedList = useRef<FixedSizeList>()
const [searchQuery, setSearchQuery] = useState<string>('')
const [invertSearchOrder, setInvertSearchOrder] = useState<boolean>(false)
const allTokens = useAllTokens()
// if they input an address, use it
const isAddressSearch = isAddress(searchQuery)
const searchToken = useToken(searchQuery)
const showETH: boolean = useMemo(() => {
const s = searchQuery.toLowerCase().trim()
return s === '' || s === 'e' || s === 'et' || s === 'eth'
}, [searchQuery])
const tokenComparator = useTokenComparator(invertSearchOrder)
const audioPlay = useSelector<AppState, AppState['user']['audioPlay']>((state) => state.user.audioPlay)
const filteredTokens: Token[] = useMemo(() => {
if (isAddressSearch) return searchToken ? [searchToken] : []
return filterTokens(Object.values(allTokens), searchQuery)
}, [isAddressSearch, searchToken, allTokens, searchQuery])
const filteredSortedTokens: Token[] = useMemo(() => {
if (searchToken) return [searchToken]
const sorted = filteredTokens.sort(tokenComparator)
const symbolMatch = searchQuery
.toLowerCase()
.split(/\s+/)
.filter((s) => s.length > 0)
if (symbolMatch.length > 1) return sorted
return [
...(searchToken ? [searchToken] : []),
// sort any exact symbol matches first
...sorted.filter((token) => token.symbol?.toLowerCase() === symbolMatch[0]),
...sorted.filter((token) => token.symbol?.toLowerCase() !== symbolMatch[0]),
]
}, [filteredTokens, searchQuery, searchToken, tokenComparator])
const handleCurrencySelect = useCallback(
(currency: Currency) => {
onCurrencySelect(currency)
onDismiss()
if (audioPlay) {
const audio = document.getElementById('bgMusic') as HTMLAudioElement
if (audio) {
audio.play()
}
}
},
[onDismiss, onCurrencySelect, audioPlay]
)
// 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]
)
const selectedListInfo = useSelectedListInfo()
return (
<Column style={{ width: '100%', flex: '1 1' }}>
<PaddedColumn gap="14px">
<RowBetween>
<Text>
<TranslatedText translationId={82}>Select a token</TranslatedText>
<QuestionHelper
text={TranslateString(
130,
'Find a token by searching for its name or symbol or by pasting its address below.'
)}
/>
</Text>
<CloseIcon onClick={onDismiss} />
</RowBetween>
<SearchInput
type="text"
id="token-search-input"
placeholder={t('tokenSearchPlaceholder')}
value={searchQuery}
ref={inputRef as RefObject<HTMLInputElement>}
onChange={handleInput}
onKeyDown={handleEnter}
/>
{showCommonBases && (
<CommonBases chainId={chainId} onSelect={handleCurrencySelect} selectedCurrency={selectedCurrency} />
)}
<RowBetween>
<Text fontSize="14px">
<TranslatedText translationId={126}>Token name</TranslatedText>
</Text>
<SortButton ascending={invertSearchOrder} toggleSortOrder={() => setInvertSearchOrder((iso) => !iso)} />
</RowBetween>
</PaddedColumn>
<Separator />
<div style={{ flex: '1' }}>
<AutoSizer disableWidth>
{({ height }) => (
<CurrencyList
height={height}
showETH={showETH}
currencies={filteredSortedTokens}
onCurrencySelect={handleCurrencySelect}
otherCurrency={otherSelectedCurrency}
selectedCurrency={selectedCurrency}
fixedListRef={fixedList}
/>
)}
</AutoSizer>
</div>
{null && (
<>
<Separator />
<Card>
<RowBetween>
{selectedListInfo.current ? (
<Row>
{selectedListInfo.current.logoURI ? (
<ListLogo
style={{ marginRight: 12 }}
logoURI={selectedListInfo.current.logoURI}
alt={`${selectedListInfo.current.name} list logo`}
/>
) : null}
<Main id="currency-search-selected-list-name">{selectedListInfo.current.name}</Main>
</Row>
) : null}
<LinkStyledButton
style={{ fontWeight: 500, color: theme.colors.textSubtle, fontSize: 16 }}
onClick={onChangeList}
id="currency-search-change-list-button"
>
{selectedListInfo.current ? 'Change' : 'Select a list'}
</LinkStyledButton>
</RowBetween>
</Card>
</>
)}
</Column>
)
}
Example #18
Source File: InputChip.tsx From frontegg-react with MIT License | 5 votes |
InputChip: FC<InputChipProps> = ({ onChange, validate, value = [], ...props }) => {
const inputRef = useRef<HTMLInputElement>(null);
const onSave = useCallback(async () => {
const inputValue = inputRef.current?.value ?? '';
if (!inputValue) return;
if (validate && !(await validate([...value, inputValue]))) {
return;
}
if (inputRef.current) {
inputRef.current.value = '';
}
const ev2 = new Event('input', { bubbles: true });
inputRef.current?.dispatchEvent(ev2);
onChange && onChange([...value, inputValue]);
return;
}, [inputRef, value, validate]);
const onKeyPress = useCallback(
async (e: KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter') {
await onSave();
}
return;
},
[onSave]
);
const onDelete = useCallback(
(idx: number) => {
onChange && onChange([...value.slice(0, idx), ...value.slice(idx + 1)]);
},
[onChange, value]
);
const onBlur = useCallback(
async (e: ChangeEvent<HTMLInputElement>) => {
if (!e.currentTarget.value.trim()) {
e.currentTarget.value = '';
return;
}
await onSave();
return;
},
[onSave]
);
return React.createElement(ElementsFactory.getElement('InputChip'), {
...props,
onBlur,
onKeyPress,
onDelete,
chips: value,
ref: inputRef,
});
}
Example #19
Source File: index.tsx From dockerstats with Apache License 2.0 | 5 votes |
onKeyPress = (e: KeyboardEvent) => {
if (e.key === 'Enter') {
e.preventDefault()
this.go()
}
}
Example #20
Source File: TorrentFilterStore.ts From flood with GNU General Public License v3.0 | 5 votes |
setStatusFilters(filter: TorrentStatus | '', event: KeyboardEvent | MouseEvent | TouchEvent) {
this.computeFilters(torrentStatusMap, this.statusFilter, filter, event);
this.filterTrigger = !this.filterTrigger;
}
Example #21
Source File: NativeList.tsx From GTAV-NativeDB with MIT License | 5 votes |
export default function NativeList() {
const [filter, setFilter] = useState('')
const namespaces = useNativeSearch(filter)
const inputRef = useRef<HTMLInputElement>(null)
const history = useHistory()
const query = useQuery()
useEffect(() => {
const search = query.get('search')
setFilter(search ?? '')
}, [query, setFilter])
const handleSearchKeyDown = useCallback((e: KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter') {
inputRef.current?.blur()
e.preventDefault()
}
}, [inputRef])
const handleSearchBlur = useCallback(() => {
if (filter) {
history.replace(`${history.location.pathname}?search=${encodeURIComponent(filter)}`)
}
else {
history.replace(history.location.pathname)
}
}, [history, filter])
const handleFilterChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
setFilter(e.target.value)
}, [setFilter])
useSetAppBarSettings('NativeList', {
search: {
onChange: handleFilterChange,
onKeyDown: handleSearchKeyDown,
onBlur: handleSearchBlur,
ref: inputRef,
value: filter
}
})
useHotkeys('ctrl+k', () => {
inputRef.current?.focus()
}, {
filter: (event: globalThis.KeyboardEvent) => {
event.preventDefault()
return true
},
}, [inputRef])
return (
<Fragment>
<NativeListComponent
sx={{ height: '100%' }}
namespaces={namespaces}
/>
</Fragment>
)
}
Example #22
Source File: index.tsx From hive with MIT License | 5 votes |
button = (e: KeyboardEvent<HTMLInputElement>) => {
const { authService } = this.props;
if (e.key === constants.keys.enter) {
authService.loginWan();
}
};
Example #23
Source File: TextArea.tsx From Notepad with MIT License | 5 votes |
function TextArea() {
const [linesNum, setLineNum] = useState(1);
const [columnIndex, setColumnIndex] = useState(0);
const [textAreaContent, setTextAreaContent] = useState(() => {
return getFromLocalStorage("notepad_textarea_content") || "";
});
function handleTextAreaChange(
event:
| ChangeEvent<HTMLTextAreaElement>
| KeyboardEvent<HTMLTextAreaElement>
| MouseEvent<HTMLTextAreaElement>
) {
setLineNum(getLineNumber(event.target as HTMLTextAreaElement));
setColumnIndex(getColumnIndex(event.target as HTMLTextAreaElement));
setTextAreaContent((event.target as HTMLTextAreaElement).value);
setToLocalStorage(
"notepad_textarea_content",
event.target as HTMLTextAreaElement
);
}
useEffect(() => {
let textAreaElem: HTMLTextAreaElement = document.getElementById(
"text-area"
) as HTMLTextAreaElement;
enableTabIndentation(textAreaElem);
new UserPreference().setFontSettings();
}, []);
return (
<>
<textarea
name="text-area"
id="text-area"
autoFocus
spellCheck="false"
value={textAreaContent}
onKeyUp={handleTextAreaChange}
onKeyDown={handleTextAreaChange}
onKeyPress={handleTextAreaChange}
onChange={handleTextAreaChange}
onFocus={handleTextAreaChange}
onMouseUp={handleTextAreaChange}
data-testid="text-area"
/>
<div className="details-tab">
<div className="line-number">
<p data-testid="line-index">
Ln {linesNum}, Col {columnIndex}
</p>
</div>
<div className="extra-details"></div>
</div>
</>
);
}
Example #24
Source File: Input.tsx From avalon.ist with MIT License | 5 votes |
tabComplete = (event: KeyboardEvent<HTMLInputElement>) => {
// Only tab complete if we have stuff to complete on and we are at the end of the input.
if (
event.key === 'Tab' &&
event.currentTarget &&
this.props.autoComplete.length > 0 &&
event.currentTarget.selectionStart === this.state.content.length
) {
event.preventDefault();
// Get the word being completed.
const t = event.currentTarget;
let start = t.value.lastIndexOf(' ');
// If no space, then start at the beginning, and if there is a space, skip it...
start = start === -1 ? 0 : start + 1;
// If we are already tabbing, get the word we were tabbing on since the
// content will have been auto-completed already. Otherwise, fetch it.
let word = this.state.tabbing ? this.state.autoCompleteWord : '';
if (word.length === 0) {
word = t.value.substring(start).toLowerCase();
}
const matches = this.props.autoComplete.filter((player) =>
player.toLowerCase().startsWith(word)
);
// No matches...bail.
if (matches.length === 0) {
this.setState({ tabbing: true });
return;
}
// Find the index of the last item, if there is no past item, it will return -1.
// However, we increment that to 0 below, so it will return the first result.
const autoCompleteIndex = matches.indexOf(this.state.lastAutoCompleteWord);
const newIndex = (autoCompleteIndex + 1) % matches.length;
// Perform the completion and save the tab completion state.
const content = t.value.substring(0, start) + matches[newIndex];
this.setState({
content: content,
autoCompleteWord: word,
lastAutoCompleteWord: matches[newIndex],
tabbing: true,
});
} else if (this.state.tabbing) {
// Once we stop tabbing, wipe the state so we don't taint future tabs.
this.setState({
autoCompleteWord: '',
lastAutoCompleteWord: '',
tabbing: false,
});
}
};
Example #25
Source File: CurrencySearch.tsx From pancakeswap-testnet with GNU General Public License v3.0 | 4 votes |
export function CurrencySearch({
selectedCurrency,
onCurrencySelect,
otherSelectedCurrency,
showCommonBases,
onDismiss,
isOpen,
onChangeList,
}: CurrencySearchProps) {
const { t } = useTranslation()
const { chainId } = useActiveWeb3React()
const theme = useContext(ThemeContext)
const fixedList = useRef<FixedSizeList>()
const [searchQuery, setSearchQuery] = useState<string>('')
const [invertSearchOrder, setInvertSearchOrder] = useState<boolean>(false)
const allTokens = useAllTokens()
// if they input an address, use it
const isAddressSearch = isAddress(searchQuery)
const searchToken = useToken(searchQuery)
const showETH: boolean = useMemo(() => {
const s = searchQuery.toLowerCase().trim()
return s === '' || s === 'b' || s === 'bn' || s === 'bnb'
}, [searchQuery])
const tokenComparator = useTokenComparator(invertSearchOrder)
const audioPlay = useSelector<AppState, AppState['user']['audioPlay']>((state) => state.user.audioPlay)
const filteredTokens: Token[] = useMemo(() => {
if (isAddressSearch) return searchToken ? [searchToken] : []
return filterTokens(Object.values(allTokens), searchQuery)
}, [isAddressSearch, searchToken, allTokens, searchQuery])
const filteredSortedTokens: Token[] = useMemo(() => {
if (searchToken) return [searchToken]
const sorted = filteredTokens.sort(tokenComparator)
const symbolMatch = searchQuery
.toLowerCase()
.split(/\s+/)
.filter((s) => s.length > 0)
if (symbolMatch.length > 1) return sorted
return [
...(searchToken ? [searchToken] : []),
// sort any exact symbol matches first
...sorted.filter((token) => token.symbol?.toLowerCase() === symbolMatch[0]),
...sorted.filter((token) => token.symbol?.toLowerCase() !== symbolMatch[0]),
]
}, [filteredTokens, searchQuery, searchToken, tokenComparator])
const handleCurrencySelect = useCallback(
(currency: Currency) => {
onCurrencySelect(currency)
onDismiss()
if (audioPlay) {
const audio = document.getElementById('bgMusic') as HTMLAudioElement
if (audio) {
audio.play()
}
}
},
[onDismiss, onCurrencySelect, audioPlay]
)
// 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 === 'bnb') {
handleCurrencySelect(ETHER)
} else if (filteredSortedTokens.length > 0) {
if (
filteredSortedTokens[0].symbol?.toLowerCase() === searchQuery.trim().toLowerCase() ||
filteredSortedTokens.length === 1
) {
handleCurrencySelect(filteredSortedTokens[0])
}
}
}
},
[filteredSortedTokens, handleCurrencySelect, searchQuery]
)
const selectedListInfo = useSelectedListInfo()
const TranslateString = useI18n()
return (
<Column style={{ width: '100%', flex: '1 1' }}>
<PaddedColumn gap="14px">
<RowBetween>
<Text>
{TranslateString(82, 'Select a token')}
<QuestionHelper
text={TranslateString(
128,
'Find a token by searching for its name or symbol or by pasting its address below.'
)}
/>
</Text>
<CloseIcon onClick={onDismiss} />
</RowBetween>
<SearchInput
type="text"
id="token-search-input"
placeholder={t('tokenSearchPlaceholder')}
value={searchQuery}
ref={inputRef as RefObject<HTMLInputElement>}
onChange={handleInput}
onKeyDown={handleEnter}
/>
{showCommonBases && (
<CommonBases chainId={chainId} onSelect={handleCurrencySelect} selectedCurrency={selectedCurrency} />
)}
<RowBetween>
<Text fontSize="14px">{TranslateString(126, 'Token name')}</Text>
<SortButton ascending={invertSearchOrder} toggleSortOrder={() => setInvertSearchOrder((iso) => !iso)} />
</RowBetween>
</PaddedColumn>
<Separator />
<div style={{ flex: '1' }}>
<AutoSizer disableWidth>
{({ height }) => (
<CurrencyList
height={height}
showETH={showETH}
currencies={filteredSortedTokens}
onCurrencySelect={handleCurrencySelect}
otherCurrency={otherSelectedCurrency}
selectedCurrency={selectedCurrency}
fixedListRef={fixedList}
/>
)}
</AutoSizer>
</div>
{null && (
<>
<Separator />
<Card>
<RowBetween>
{selectedListInfo.current ? (
<Row>
{selectedListInfo.current.logoURI ? (
<ListLogo
style={{ marginRight: 12 }}
logoURI={selectedListInfo.current.logoURI}
alt={`${selectedListInfo.current.name} list logo`}
/>
) : null}
<Text id="currency-search-selected-list-name">{selectedListInfo.current.name}</Text>
</Row>
) : null}
<LinkStyledButton
style={{ fontWeight: 500, color: theme.colors.textSubtle, fontSize: 16 }}
onClick={onChangeList}
id="currency-search-change-list-button"
>
{selectedListInfo.current ? TranslateString(180, 'Change') : TranslateString(1152, 'Select a list')}
</LinkStyledButton>
</RowBetween>
</Card>
</>
)}
</Column>
)
}
Example #26
Source File: index.tsx From react-terminal-ui with MIT License | 4 votes |
Terminal = ({name, prompt, colorMode, lineData, onInput, startingInputValue = ""}: Props) => {
const [currentLineInput, setCurrentLineInput] = useState('');
const lastLineRef = useRef<null | HTMLElement>(null)
const updateCurrentLineInput = (event: ChangeEvent<HTMLInputElement>) => {
setCurrentLineInput(event.target.value);
}
const handleEnter = (event: KeyboardEvent<HTMLInputElement>) => {
if (onInput != null && event.key === 'Enter') {
onInput(currentLineInput);
setCurrentLineInput('');
}
}
useEffect(() => {
setCurrentLineInput(startingInputValue.trim());
}, [startingInputValue]);
// An effect that handles scrolling into view the last line of terminal input or output
const performScrolldown = useRef(false);
useEffect(() => {
if (performScrolldown.current) { // skip scrolldown when the component first loads
setTimeout(() => lastLineRef?.current?.scrollIntoView({ behavior: "smooth", block: "nearest" }), 500);
}
performScrolldown.current = true;
}, [lineData.length]);
// We use a hidden input to capture terminal input; make sure the hidden input is focused when clicking anywhere on the terminal
useEffect(() => {
if (onInput == null) {
return;
}
// keep reference to listeners so we can perform cleanup
const elListeners: { terminalEl: Element; listener: EventListenerOrEventListenerObject }[] = [];
for (const terminalEl of document.getElementsByClassName('react-terminal-wrapper')) {
const listener = () => (terminalEl?.querySelector('.terminal-hidden-input') as HTMLElement)?.focus();
terminalEl?.addEventListener('click', listener);
elListeners.push({ terminalEl, listener });
}
return function cleanup () {
elListeners.forEach(elListener => {
elListener.terminalEl.removeEventListener('click', elListener.listener);
});
}
}, [onInput]);
const renderedLineData = lineData.map((ld, i) => {
const classes = ['react-terminal-line'];
if (ld.type === LineType.Input) {
classes.push('react-terminal-input');
}
// `lastLineRef` is used to ensure the terminal scrolls into view to the last line; make sure to add the ref to the last
// redendered line if input prompt is not shown, i.e. `onInput` is not declared; see 'render prompt' below
if (lineData.length === i + 1 && onInput == null) {
return (
<span className={ classes.join(' ') } key={ i } ref={ lastLineRef }>{ ld.value }</span>
);
} else {
return (
<span className={ classes.join(' ') } key={ i }>{ ld.value }</span>
);
}
});
// render prompt
if (onInput != null) {
renderedLineData.push(
<span className="react-terminal-line react-terminal-input react-terminal-active-input" data-terminal-prompt={ prompt || '$' } key={ lineData.length } ref={ lastLineRef }>{ currentLineInput }</span>,
);
}
const classes = ['react-terminal-wrapper'];
if (colorMode === ColorMode.Light) {
classes.push('react-terminal-light');
}
return (
<div className={ classes.join(' ') } data-terminal-name={ name }>
<div className="react-terminal">
{ renderedLineData }
</div>
<input className="terminal-hidden-input" placeholder="Terminal Hidden Input" value={ currentLineInput } autoFocus={ onInput != null } onChange={ updateCurrentLineInput } onKeyDown={ handleEnter } />
</div>
);
}
Example #27
Source File: TorrentList.tsx From flood with GNU General Public License v3.0 | 4 votes |
TorrentList: FC = observer(() => {
const listHeaderRef = useRef<HTMLDivElement>(null);
const listViewportRef = useRef<FixedSizeList>(null);
const listViewportOuterRef = useRef<HTMLDivElement | null>(null);
useEffect(() => {
const dispose = reaction(
() => TorrentFilterStore.filterTrigger,
() => {
if (listViewportRef.current != null) {
listViewportRef.current.scrollTo(0);
}
},
);
return dispose;
}, []);
useEvent('keydown', (e: KeyboardEvent) => {
const {ctrlKey, key, metaKey, repeat, target} = e;
const tagName = (target as HTMLElement)?.tagName.toUpperCase();
if (tagName === 'INPUT' || tagName === 'TEXTAREA') {
return;
}
if (repeat) {
return;
}
if ((metaKey || ctrlKey) && key === 'a') {
e.preventDefault();
TorrentStore.selectAllTorrents();
}
});
const torrents = TorrentStore.filteredTorrents;
const {torrentListViewSize = 'condensed'} = SettingStore.floodSettings;
const isCondensed = torrentListViewSize === 'condensed';
const isListEmpty = torrents == null || torrents.length === 0;
let content: ReactNode = null;
let torrentListHeading: ReactNode = null;
if (!ClientStatusStore.isConnected) {
content = (
<div className="torrents__alert__wrapper">
<div className="torrents__alert">
<Trans id="torrents.list.cannot.connect" />
</div>
</div>
);
} else if (isListEmpty || torrents == null) {
content = (
<div className="torrents__alert__wrapper">
<div className="torrents__alert">
<Trans id="torrents.list.no.torrents" />
</div>
{TorrentFilterStore.isFilterActive ? (
<div className="torrents__alert__action">
<Button
onClick={() => {
TorrentFilterStore.clearAllFilters();
}}
priority="tertiary"
>
<Trans id="torrents.list.clear.filters" />
</Button>
</div>
) : null}
</div>
);
} else {
if (isCondensed) {
torrentListHeading = (
<TableHeading
onCellFocus={() => {
if (listViewportOuterRef.current != null && listHeaderRef.current != null) {
listViewportOuterRef.current.scrollLeft = listHeaderRef.current.scrollLeft;
}
}}
onCellClick={(property: TorrentListColumn) => {
const currentSort = SettingStore.floodSettings.sortTorrents;
let nextDirection = SortDirections[property] ?? 'asc';
if (currentSort.property === property) {
nextDirection = currentSort.direction === 'asc' ? 'desc' : 'asc';
}
const sortBy = {
property,
direction: nextDirection,
};
SettingActions.saveSetting('sortTorrents', sortBy);
}}
onWidthsChange={(column: TorrentListColumn, width: number) => {
const {torrentListColumnWidths = defaultFloodSettings.torrentListColumnWidths} = SettingStore.floodSettings;
SettingActions.saveSetting('torrentListColumnWidths', {
...torrentListColumnWidths,
[column]: width,
});
}}
ref={listHeaderRef}
/>
);
}
// itemSize must sync with styles &--is-condensed and &--is-expanded
content = (
<ListViewport
className="torrent__list__viewport"
itemCount={torrents.length}
itemKey={(index) => TorrentStore.filteredTorrents[index].hash}
itemRenderer={TorrentListRowRenderer}
itemSize={isCondensed ? 30 : 70}
ref={listViewportRef}
outerRef={(ref) => {
const viewportDiv = ref;
if (viewportDiv != null && viewportDiv.onscroll == null) {
viewportDiv.onscroll = () => {
if (listHeaderRef.current != null) {
listHeaderRef.current.scrollLeft = viewportDiv.scrollLeft;
}
};
}
listViewportOuterRef.current = viewportDiv;
}}
/>
);
}
return (
<TorrentListDropzone>
<div className="torrent__list__wrapper" role="table">
<ContextMenuMountPoint id="torrent-list-item" />
{torrentListHeading}
{content}
</div>
<div className="dropzone__overlay">
<div className="dropzone__copy">
<div className="dropzone__icon">
<Files />
</div>
<Trans id="torrents.list.drop" />
</div>
</div>
</TorrentListDropzone>
);
})
Example #28
Source File: AuthForm.tsx From ksana.in with Apache License 2.0 | 4 votes |
export function AuthForm({ state }: IAuthFormProps) {
const router = useRouter()
const { showAlert, hideAlert } = useAlertContext()
const bgBox = useColorModeValue('white', 'gray.700')
const [internalState, setInternalState] = useState<any>(state)
const [isLogin, setIsLogin] = useState<any>(state === 'login')
const [loading, setLoading] = useState<boolean>(false)
const [errorForm, setErrorForm] = useState<string>('')
const [email, setEmail] = useState<string>('')
const [password, setPassword] = useState<string>('')
const toggleState = () => {
if (internalState === 'login') {
setInternalState('register')
setIsLogin(false)
} else {
setInternalState('login')
setIsLogin(true)
}
}
const handleChangeEmail = (e: ChangeEvent<HTMLInputElement>) => {
const value = e.target.value
setEmail(value)
}
const handleChangePassword = (e: ChangeEvent<HTMLInputElement>) => {
const value = e.target.value
setPassword(value)
}
const checkIsEmpty = () => {
if (email === '' || password === '') {
setErrorForm('Email dan password tidak boleh dikosongkan.')
return true
}
setErrorForm('')
return false
}
const handleSubmit = async () => {
setLoading(true)
const isEmpty = checkIsEmpty()
if (!isEmpty) {
if (isLogin) {
await handleLogin()
} else {
await handleRegister()
}
}
setLoading(false)
}
const handleLoginGoogle = async () => {
setLoading(true)
await loginWithGoogle()
setLoading(false)
}
const handleLoginGithub = async () => {
setLoading(true)
await loginWithGithub()
setLoading(false)
}
const handleLoginTwitter = async () => {
setLoading(true)
await loginWithTwitter()
setLoading(false)
}
const processResponse = async ({ session, error, stateType = 'login' }: IProcessResponse) => {
if (error) {
setErrorForm(error.message)
return false
}
if (session && !error) {
if (stateType === 'login') {
// only set for the login flow
await setSessionToServer(EVENT_SIGN_IN, session)
}
showAlert({
title: `${stateType === 'login' ? 'Login' : 'Register'} success`,
message: `${
stateType === 'login'
? 'Selamat datang kembali!'
: 'Terima kasih telah mendaftar. Silahkan melakukan verifikasi dengan mengklik tautan yang kami kirimkan melalui email.'
}`,
onClose: () => {
hideAlert()
if (stateType === 'login') {
setTimeout(() => {
// trigger hard redirect to dashboard page
// TODO: mutate SWR to reload the user data
window.location.assign(dashboard)
}, 500)
} else {
router.push('/')
}
}
})
}
}
const handleLogin = async () => {
const { session, error } = await login({
email: email,
password: password
})
processResponse({ session, error, stateType: 'login' })
}
const handleRegister = async () => {
const { session, error } = await register({
email: email,
password: password
})
processResponse({ session, error, stateType: 'register' })
if (!error) {
showAlert({
title: 'Registrasi Berhasil!',
message:
'Terima kasih telah mendaftar. Silahkan melakukan verifikasi dengan mengklik tautan yang kami kirimkan melalui email.'
})
} else {
showAlert({
title: 'Registrasi Gagal!',
message: 'Silahkan ulangi proses registrasi!'
})
}
}
const handleKeyPress = (e: KeyboardEvent) => {
if (e.code === '13') {
handleSubmit()
}
}
return (
<Stack spacing={8} mx={'auto'} mt="20" maxW={'lg'} py={12} px={6}>
<Stack align={'center'}>
<Heading
fontWeight={700}
fontSize={{ base: '3xl', sm: '4xl', md: '5xl' }}
lineHeight={'110%'}
color="orange.400"
>
{isLogin ? 'Masuk ke akunmu' : 'Daftarkan akun baru'}
</Heading>
</Stack>
<Box rounded={'lg'} bg={bgBox} boxShadow={'lg'} p={8}>
<VStack
direction="row"
align={'center'}
justify={'center'}
borderBottom="1px"
borderColor="gray.200"
py="4"
>
{isEnableGoogleLogin && (
<Button
isLoading={loading}
loadingText="Memproses"
variant={'outline'}
w="full"
onClick={handleLoginGoogle}
leftIcon={<FcGoogle />}
>
{isLogin ? 'Masuk dengan Google' : 'Daftar dengan Google'}
</Button>
)}
{isEnableTwitterLogin && (
<Button
isLoading={loading}
loadingText="Memproses"
variant={'outline'}
w="full"
onClick={handleLoginTwitter}
leftIcon={<SiTwitter fill="#1DA1F2" />}
>
{isLogin ? 'Masuk dengan Twitter' : 'Daftar dengan Twitter'}
</Button>
)}
{isEnableGithubLogin && (
<Button
isLoading={loading}
loadingText="Memproses"
variant={'outline'}
w="full"
onClick={handleLoginGithub}
leftIcon={<SiGithub />}
>
{isLogin ? 'Masuk dengan Github' : 'Daftar dengan Github'}
</Button>
)}
</VStack>
<Stack spacing={4} mt="4">
<FormControl id="email" isRequired>
<FormLabel>Email</FormLabel>
<Input
isInvalid={Boolean(errorForm)}
type="email"
name="email"
value={email}
onChange={handleChangeEmail}
onKeyPress={handleKeyPress}
autoComplete="username"
/>
</FormControl>
<FormControl id="password" isRequired>
<FormLabel>Password</FormLabel>
<Input
isInvalid={Boolean(errorForm)}
type="password"
name="password"
value={password}
onChange={handleChangePassword}
onKeyPress={handleKeyPress}
autoComplete={isLogin ? 'current-password' : 'new-password'}
/>
</FormControl>
{errorForm && (
<Text color="red.300" fontSize="xs">
Galat: {errorForm}
</Text>
)}
<Stack spacing={10}>
{isLogin ? (
<Stack
direction={{ base: 'column', sm: 'row' }}
align={'start'}
justify={'space-between'}
>
<Button variant="link" as={Link} color={'orange.400'} href={forgetPasword}>
Lupa password?
</Button>
</Stack>
) : null}
<Button
isLoading={loading}
loadingText="Memproses"
w="full"
bg="orange.400"
_hover={{
bg: 'orange.500'
}}
color="white"
onClick={handleSubmit}
>
{isLogin ? 'Masuk' : 'Daftar Sekarang'}
</Button>
</Stack>
{isLogin ? (
<Stack direction="row" align={'center'} justify={'center'}>
<Text>Belum punya akun? </Text>
<Button variant="link" as={Link} color={'orange.400'} onClick={toggleState}>
Daftar sekarang
</Button>
</Stack>
) : (
<Stack direction="row" align={'center'} justify={'center'}>
<Text>Sudah punya akun? </Text>
<Button variant="link" as={Link} color={'orange.400'} onClick={toggleState}>
Masuk
</Button>
</Stack>
)}
</Stack>
</Box>
</Stack>
)
}
Example #29
Source File: ClueList.tsx From crosshare with GNU Affero General Public License v3.0 | 4 votes |
ClueListItem = memo(function ClueListItem({
isActive,
isCross,
...props
}: ClueListItemProps) {
const ref = useRef<HTMLLIElement>(null);
if (ref.current && props.listRef.current) {
if (
(isActive && !props.wasEntryClick) ||
(props.scrollToCross && isCross)
) {
props.listRef.current.scrollTop =
ref.current.offsetTop - props.listRef.current.offsetTop;
}
}
function click(e: MouseEvent | KeyboardEvent) {
e.preventDefault();
if (isActive) {
props.dispatch({ type: 'CHANGEDIRECTION' });
return;
}
const ca: ClickedEntryAction = {
type: 'CLICKEDENTRY',
entryIndex: props.entry.index,
};
props.dispatch(ca);
}
return (
<li
css={{
display: isActive || props.showEntry ? 'list-item' : 'none',
[SMALL_AND_UP]: {
display: 'list-item',
},
backgroundColor: isActive
? 'var(--lighter)'
: props.isRefed
? 'var(--secondary)'
: 'var(--bg)',
listStyleType: 'none',
cursor: 'pointer',
'&:hover': {
backgroundColor: isActive
? 'var(--lighter)'
: props.isRefed
? 'var(--secondary-hover)'
: 'var(--bg-hover)',
},
width: '100%',
}}
ref={ref}
key={props.entry.index}
>
<div
css={{
outline: 'none',
width: '100%',
paddingLeft: '0.4em',
}}
role="button"
tabIndex={0}
onClick={click}
onKeyPress={click}
>
<div
css={{
width: '100%',
display: 'flex',
flexDirection: 'row',
flexWrap: 'nowrap',
alignItems: 'center',
borderLeft: isCross
? '0.6em solid var(--lighter)'
: '0.6em solid transparent',
padding: '0.5em 0.5em 0.5em 0',
}}
>
<div
css={{
display: props.showEntry ? 'block' : 'none',
[SMALL_AND_UP]: {
display: 'block',
},
flexShrink: 0,
width: '2.5em',
height: '100%',
fontWeight: 'bold',
textAlign: 'right',
paddingRight: '0.5em',
}}
>
{props.entry.labelNumber}
<span
css={{
[SMALL_AND_UP]: { display: 'none' },
}}
>
{props.entry.direction === Direction.Across ? 'A' : 'D'}
</span>
</div>
<div
css={{
flex: '1 1 auto',
height: '100%',
color: props.conceal
? 'transparent'
: props.entry.completedWord && props.dimCompleted
? 'var(--completed-clue)'
: 'var(--text)',
textShadow: props.conceal ? '0 0 1em var(--conceal-text)' : '',
}}
>
{props.allEntries && props.refPositions ? (
<div>
<ClueText
refPositions={props.refPositions}
entryIndex={props.entry.index}
allEntries={props.allEntries}
grid={props.grid}
downsOnly={props.downsOnly}
/>
</div>
) : (
<div>{getClueText(props.entry)}</div>
)}
{props.showEntry ? (
<div>
{props.entry.cells.map((a) => {
const isActiveCell =
props.active &&
a.row === props.active.row &&
a.col === props.active.col;
return (
<span
key={a.col + '-' + a.row}
css={{
display: 'inline-block',
textAlign: 'center',
fontWeight: 'bold',
minWidth: '1em',
border: isActiveCell
? props.isEnteringRebus
? '1px solid var(--primary)'
: '1px solid var(--black)'
: '1px solid transparent',
}}
>
{props.isEnteringRebus && isActiveCell
? props.rebusValue || '|'
: valAt(props.grid, a).trim() || '-'}
</span>
);
})}
</div>
) : (
''
)}
</div>
</div>
</div>
</li>
);
})