react#KeyboardEventHandler TypeScript Examples
The following examples show how to use
react#KeyboardEventHandler.
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.tsx From skin-react with MIT License | 6 votes |
Button = ({
onClick = () => {},
onEscape = () => {},
...props
}: ButtonProps<HTMLButtonElement | HTMLAnchorElement> & {
onEscape?: KeyboardEventHandler<HTMLButtonElement | HTMLAnchorElement>;
}) => {
const handleClick = (event) => !props.disabled && onClick(event);
const handleKeyDown = (event) => {
!props.disabled && event.key === 'Escape' && onEscape(event);
};
return <BasicButton {...props} onClick={handleClick} onKeyDown={handleKeyDown} />;
}
Example #2
Source File: AmountInput.tsx From mStable-apps with GNU Lesser General Public License v3.0 | 6 votes |
AmountInput: FC<Props> = ({
className,
error,
disabled = false,
placeholder = '0.0',
onChange,
value,
min = '0',
max,
step = '0.01',
decimals,
}) => {
const trimmedValue = useMemo(() => trimInput(value, decimals), [value, decimals])
const handleKeyPress = useCallback<KeyboardEventHandler<HTMLInputElement>>(event => {
// Prevent 'minus' key
if ((event.which || event.keyCode) === 45) {
event.preventDefault()
event.stopPropagation()
}
}, [])
const handleChange = useCallback<ChangeEventHandler<HTMLInputElement>>(event => onChange?.(event.target.value ?? undefined), [onChange])
return (
<Input
className={className}
error={error}
min={min}
max={max}
placeholder={placeholder}
step={step}
value={trimmedValue}
onKeyPress={handleKeyPress}
onChange={handleChange}
disabled={disabled}
/>
)
}
Example #3
Source File: AmountInputButton.tsx From mStable-apps with GNU Lesser General Public License v3.0 | 6 votes |
AmountInputButton: FC<Props> = ({ className, disabled = false, placeholder = '0.00', onChange, value, min = '0', max }) => {
const handleKeyPress = useCallback<KeyboardEventHandler<HTMLInputElement>>(event => {
// Prevent 'minus' key
if ((event.which || event.keyCode) === 45) {
event.preventDefault()
event.stopPropagation()
}
}, [])
const handleChange = useCallback<ChangeEventHandler<HTMLInputElement>>(
event => {
onChange?.(event.target.value ?? undefined)
},
[onChange],
)
return (
<StyledButton className={className}>
<input
type="number"
min={min}
max={max}
placeholder={placeholder}
step="0.01"
value={value || ''}
onKeyPress={handleKeyPress}
onChange={handleChange}
disabled={disabled}
/>
</StyledButton>
)
}
Example #4
Source File: CheckboxField.tsx From typescript-fun with MIT License | 6 votes |
CheckboxField: FC<{
field: Field<boolean, FormErrorID>;
label: string;
}> = ({ field, label, ...rest }) => {
const handleChange = useCallback<FormEventHandler<HTMLInputElement>>(
event => {
field.onChange(event.currentTarget.checked);
},
[field],
);
const handleKeyPress = useCallback<KeyboardEventHandler<HTMLInputElement>>(
event => {
if (event.key === 'Enter') field.submit();
},
[field],
);
return (
<FormControl {...rest}>
<Checkbox
isChecked={field.value}
onChange={handleChange}
onKeyPress={handleKeyPress}
ref={field.ref}
>
{label}
</Checkbox>
</FormControl>
);
}
Example #5
Source File: Items.tsx From backstage with Apache License 2.0 | 5 votes |
export function SidebarSearchField(props: SidebarSearchFieldProps) {
const { sidebarConfig } = useContext(SidebarConfigContext);
const [input, setInput] = useState('');
const classes = useMemoStyles(sidebarConfig);
const Icon = props.icon ? props.icon : SearchIcon;
const search = () => {
props.onSearch(input);
setInput('');
};
const handleEnter: KeyboardEventHandler = ev => {
if (ev.key === 'Enter') {
ev.preventDefault();
search();
}
};
const handleInput = (ev: React.ChangeEvent<HTMLInputElement>) => {
setInput(ev.target.value);
};
const handleInputClick = (ev: React.MouseEvent<HTMLInputElement>) => {
// Clicking into the search fields shouldn't navigate to the search page
ev.preventDefault();
ev.stopPropagation();
};
const handleItemClick = (ev: React.MouseEvent) => {
// Clicking on the search icon while should execute a query with the current field content
search();
ev.preventDefault();
};
return (
<div className={classes.searchRoot}>
<SidebarItem
icon={Icon}
to={props.to}
onClick={handleItemClick}
disableHighlight
>
<TextField
placeholder="Search"
value={input}
onClick={handleInputClick}
onChange={handleInput}
onKeyDown={handleEnter}
className={classes.searchContainer}
InputProps={{
disableUnderline: true,
className: classes.searchField,
}}
inputProps={{
className: classes.searchFieldHTMLInput,
}}
/>
</SidebarItem>
</div>
);
}
Example #6
Source File: index.tsx From xiaobi with MIT License | 5 votes |
handleKeydown: KeyboardEventHandler<HTMLInputElement> = (e) => {
if (e.key === '-') {
e.preventDefault();
}
}
Example #7
Source File: aria.ts From pybricks-code with MIT License | 5 votes |
/**
* React hook for creating toolbar item element props for focus management.
*
* Using this hook requires the current element to be inside of an
* {@link ToolbarStateContext} and to be inside of a {@link FocusScope}.
*/
export function useToolbarItemFocus(props: { id: string }): ToolbarItemFocusAria {
const { id } = props;
const state = useContext(ToolbarStateContext);
const focusManager = useFocusManager();
const onKeyDown = useCallback<KeyboardEventHandler<HTMLElement>>(
(e) => {
switch (e.key) {
case 'ArrowLeft':
focusManager.focusPrevious({ wrap: true });
break;
case 'ArrowRight':
focusManager.focusNext({ wrap: true });
break;
case 'Home':
focusManager.focusFirst();
break;
case 'End':
focusManager.focusLast();
break;
default:
return;
}
},
[focusManager],
);
const onFocus = useCallback<FocusEventHandler<HTMLElement>>(
(e) => {
state.setLastFocusedItem(e.target.id);
},
[state.setLastFocusedItem],
);
const excludeFromTabOrder = id !== state.lastFocusedItem;
return { toolbarItemFocusProps: { onKeyDown, onFocus }, excludeFromTabOrder };
}
Example #8
Source File: TextInputField.tsx From typescript-fun with MIT License | 5 votes |
TextInputField: FC<{
field: FieldMaybeOptional<string, FormErrorID>;
icon?: ReactNode;
label: string;
type: 'text' | 'email' | 'password' | 'tel';
}> = ({ field, icon, label, type, ...rest }) => {
const handleChange = useCallback<FormEventHandler<HTMLInputElement>>(
({ currentTarget: { value } }) => {
if (isOptionalField(field)) {
field.onChange(value.length === 0 ? O.none : O.some(value));
} else {
field.onChange(value);
}
},
[field],
);
const handleKeyPress = useCallback<KeyboardEventHandler<HTMLInputElement>>(
event => {
if (event.key === 'Enter') field.submit();
},
[field],
);
const value = isOptionalField(field)
? pipe(
field.value,
O.getOrElse(() => ''),
)
: field.value;
const input = (
<Input
id={field.key}
type={type}
value={value}
onChange={handleChange}
onKeyPress={handleKeyPress}
ref={field.ref}
/>
);
return (
<FormControl
isRequired={!isOptionalField(field)}
isInvalid={field.isInvalid}
{...rest}
>
<FormLabel htmlFor={field.key}>{label}</FormLabel>
{icon ? (
<InputGroup>
<InputLeftElement>{icon}</InputLeftElement>
{input}
</InputGroup>
) : (
input
)}
<FormErrorMessage error={field.firstError} />
</FormControl>
);
}
Example #9
Source File: NewCommentModal.tsx From apps with GNU Affero General Public License v3.0 | 4 votes |
export default function NewCommentModal({
onRequestClose,
editId,
onComment,
onInputChange,
...props
}: NewCommentModalProps): ReactElement {
const [input, setInput] = useState<string>(props.editContent || '');
const [showDiscardModal, setShowDiscardModal] = useState<boolean>(false);
const [activeTab, setActiveTab] = useState('Write');
const [sendingComment, setSendingComment] = useState<boolean>(false);
const [errorMessage, setErrorMessage] = useState<string>(null);
const isPreview = activeTab === 'Preview';
const { requestMethod } = useRequestProtocol();
const previewQueryKey = ['comment_preview', input];
const { data: previewContent } = useQuery<{ preview: string }>(
previewQueryKey,
() =>
requestMethod(
`${apiUrl}/graphql`,
PREVIEW_COMMENT_MUTATION,
{ content: input },
{ requestKey: JSON.stringify(previewQueryKey) },
),
{ enabled: isPreview && input?.length > 0 },
);
const confirmClose = (event: MouseEvent): void => {
if (
(!props.editContent && input?.length) ||
(props.editContent && props.editContent !== input)
) {
setShowDiscardModal(true);
} else {
onRequestClose(event);
}
};
const key = ['post_comments_mutations', props.post.id];
const { mutateAsync: comment } = useMutation<
CommentOnData,
unknown,
CommentVariables
>(
(variables) =>
requestMethod(
`${apiUrl}/graphql`,
props.commentId
? COMMENT_ON_COMMENT_MUTATION
: COMMENT_ON_POST_MUTATION,
variables,
{ requestKey: JSON.stringify(key) },
),
{ onSuccess: (data) => data && onComment(data.comment, true) },
);
const { mutateAsync: editComment } = useMutation<
CommentOnData,
unknown,
CommentVariables
>(
(variables) =>
requestMethod(`${apiUrl}/graphql`, EDIT_COMMENT_MUTATION, variables, {
requestKey: JSON.stringify(key),
}),
{ onSuccess: (data) => data && onComment(data.comment, false) },
);
const modalRef = (element: HTMLDivElement): void => {
if (element) {
// eslint-disable-next-line no-param-reassign
element.scrollTop = element.scrollHeight - element.clientHeight;
}
};
const sendComment = async (): Promise<void> => {
if (sendingComment || !input?.trim().length) {
return;
}
setErrorMessage(null);
setSendingComment(true);
try {
if (editId) {
await editComment({
id: editId,
content: input,
});
} else {
await comment({
id: props.commentId || props.post.id,
content: input,
});
}
} catch (err) {
setErrorMessage('Something went wrong, try again');
setSendingComment(false);
}
};
const onKeyDown = async (
event: KeyboardEvent<HTMLDivElement>,
defaultCallback?: KeyboardEventHandler<HTMLDivElement>,
): Promise<void> => {
// Ctrl / Command + Enter
if (
(event.ctrlKey || event.metaKey) &&
event.keyCode === 13 &&
input?.length
) {
await sendComment();
} else {
defaultCallback?.(event);
}
};
useEffect(() => {
onInputChange?.(input);
}, [input]);
return (
<ResponsiveModal
contentRef={modalRef}
onRequestClose={confirmClose}
overlayClassName="fixed-position"
padding={false}
{...props}
>
<ModalCloseButton onClick={confirmClose} className="top-2" />
<TabContainer
onActiveChange={(active: string) => setActiveTab(active)}
shouldMountInactive
className="tablet:max-h-[40rem] grow tablet:grow-0"
>
<Tab label="Write" className="flex flex-col flex-1">
<CommentBox
{...props}
onInput={setInput}
input={input}
editId={editId}
errorMessage={errorMessage}
sendingComment={sendingComment}
sendComment={sendComment}
onKeyDown={onKeyDown}
/>
</Tab>
<Tab label="Preview" className="flex overflow-y-auto flex-col flex-1">
{isPreview && previewContent?.preview && (
<Markdown
content={previewContent.preview}
appendTooltipTo={props.parentSelector}
/>
)}
{isPreview && (
<Button
disabled={!input?.trim().length || input === props.editContent}
loading={sendingComment}
onClick={sendComment}
className="mt-auto ml-auto btn-primary-avocado"
>
{editId ? 'Update' : 'Comment'}
</Button>
)}
</Tab>
</TabContainer>
<DiscardCommentModal
isOpen={showDiscardModal}
onRequestClose={() => setShowDiscardModal(false)}
onDeleteComment={onRequestClose}
shouldCloseOnOverlayClick={false}
parentSelector={props.parentSelector}
/>
</ResponsiveModal>
);
}
Example #10
Source File: index.tsx From xiaobi with MIT License | 4 votes |
Index: React.FC<Props> = ({ match }) => {
const id = match.params.id.split('?')[0];
const pair = getLocationQuery(window.location.href, 'pair');
const history = useHistory();
const [keywords, setKeyWords] = useState<string>();
const [enable, setEnable] = useState(false);
const [isFocus, setFocus] = useState(false);
const [times, setTimes] = useState(0);
const inputEl = useRef<HTMLInputElement>(null);
const { data } = useLoop({
fn: () => sendMessage({ command: CMDS.CMD_NOTICEINFO, data: id }),
updated: [times],
delay: 3000,
});
const handleCreate = useMemo(
() =>
debounce(() => {
if (!enable || !keywords) return;
const time = Date.now();
const params: NoticeType = {
id,
uid: `${id}_${time}`,
name: data.pair,
type: 'price',
rule: Number(keywords).toString(),
market: data.market,
create: time,
compare: Number(keywords) > data.usd,
};
sendMessage({ command: CMDS.CMD_ADDNOTICE, data: params })
.then((isSend) => {
setTimes(times + 1);
setEnable(false);
if (inputEl.current) {
inputEl.current.value = '';
}
message.info('通知创建成功');
})
.catch((error) => error);
}, 500),
[enable, keywords],
);
const goBack = () => history.replace({ pathname: StaticRoutes.Notify });
const handleFocus = () => setFocus(true);
const handleBlur = () => setFocus(false);
const handleKeyup: KeyboardEventHandler<HTMLInputElement> = (e) => {
if (e.key == 'Enter') {
handleCreate();
}
};
const handleChange: ChangeEventHandler<HTMLInputElement> = (e) => {
setEnable(!!e.target.value);
setKeyWords(e.target.value);
};
const handleDel = (uid: string) => {
sendMessage({ command: CMDS.CMD_DELNOTICE, data: uid });
setTimes(times + 1);
};
const renderDataJSX = () => {
if (data?.pair) {
const { usd, cny, percent } = data;
const className = percent > 0 ? 'increase' : 'decrease';
const p = percent > 0 ? `+${percent}%` : `${percent}%`;
return (
<DataUI>
<p className='usd'>{usd}</p>
<div className='desc'>
<p>¥{cny}</p>
<p className={className}>{p}</p>
</div>
</DataUI>
);
}
return (
<DataUI>
<DataLoading />
</DataUI>
);
};
const renderListJSX = () => {
if (data?.list.length) {
return (data.list as NoticeType[]).map((v) => (
<ListBlock {...v} key={v.uid} current={data.usd} delEvent={() => handleDel(v.uid)} />
));
}
return <Empty />;
};
return (
<WrapperUI>
<ContentUI>
<HeadUI>
<p className='name'>{pair}</p>
<p className='back' onClick={goBack}>
返回
</p>
</HeadUI>
{renderDataJSX()}
<InputBoxUI className={`${isFocus ? 'active' : ''}`}>
<input
ref={inputEl}
type='number'
placeholder='请输入价格'
onFocus={handleFocus}
onBlur={handleBlur}
onKeyDown={handleKeydown}
onKeyUp={handleKeyup}
onChange={handleChange}
/>
</InputBoxUI>
<BtnUI className={`${enable ? 'active' : ''}`} onClick={handleCreate}>
创建提醒
</BtnUI>
<DescUI>提示:插件通知需开启浏览器通知权限,插件会定时更新数据根据填入规则决定是否通知</DescUI>
</ContentUI>
<ListUI>
<TabUI>
<p>类型</p>
<p>提醒规则</p>
<p>操作</p>
</TabUI>
<ScrollUI>{renderListJSX()}</ScrollUI>
</ListUI>
</WrapperUI>
);
}
Example #11
Source File: NewConfigButton.tsx From xcloud-keyboard-mouse with GNU General Public License v3.0 | 4 votes |
export default function NewConfigButton({ disabled, allConfigs, onCreate, onImport }: NewConfigButtonProps) {
const buttonId = 'new-config-btn';
const [isOpen, setIsOpen] = useState(false);
const [name, setName] = useState('');
const isMounted = useIsMounted();
const isTaken = useMemo(() => {
return (
Object.keys(allConfigs)
.map((existing) => existing.toLowerCase())
.indexOf(name.toLowerCase()) !== -1
);
}, [name, allConfigs]);
const triggerRef = useRef<null | HTMLButtonElement>(null);
const handleToggleClick = useCallback(() => {
setIsOpen(!isOpen);
}, [isOpen]);
const handleClose = useCallback(() => {
setIsOpen(false);
}, []);
const handleImport = useCallback(() => {
importConfig()
.then((config) => {
onImport(name, config);
if (isMounted()) setName('');
alert('Preset imported from file successfully');
})
.catch((errorMsg) => {
console.error('Import failed', errorMsg);
alert(errorMsg);
});
}, [isMounted, name, onImport]);
const handleSubmit = useCallback(() => {
onCreate(name);
}, [onCreate, name]);
const handleKeyPress: KeyboardEventHandler<HTMLInputElement | HTMLTextAreaElement> = useCallback(
(e) => {
if (e.code === 'Enter') {
handleSubmit();
}
},
[handleSubmit],
);
return (
<>
<IconButton
id={buttonId}
elementRef={triggerRef}
onClick={handleToggleClick}
title="Add new preset"
ariaLabel="Add new preset"
disabled={disabled}
>
<PlusCircleIcon />
</IconButton>
{isOpen ? (
<Callout
setInitialFocus
gapSpace={0}
directionalHint={DirectionalHint.bottomRightEdge}
target={`#${buttonId}`}
onDismiss={handleClose}
// Needed to fix issue in Safari
preventDismissOnEvent={(e) => e.type === 'resize'}
>
<div style={{ width: 250 }} className="padding-full">
<TextField
placeholder="New preset name"
autoFocus={isOpen}
value={name}
maxLength={18}
onKeyPress={handleKeyPress}
onChange={(e) => setName(e.currentTarget.value)}
/>
{isTaken ? <div className="error margin-top-s">Config with that name already exists!</div> : null}
<div className="horizontal space-between margin-top-s">
<DefaultButton disabled={!name || isTaken} onClick={handleImport}>
Import File
</DefaultButton>
<PrimaryButton disabled={!name || isTaken} onClick={handleSubmit}>
Create New
</PrimaryButton>
</div>
</div>
</Callout>
) : null}
</>
);
}
Example #12
Source File: loginSimple.tsx From typescript-fun with MIT License | 4 votes |
LoginSimple = () => {
const [isPending, setIsPending] = useState(false);
const handleSubmit = (form: Form<typeof LoginForm['props']>) => {
const asyncLogin = (
data: LoginForm,
): TE.TaskEither<LoginError, LoginPayload> => {
if (data.email === '[email protected]' && data.password === 'aaaaaa')
return T.delay(500)(TE.right({ token: '123' }));
if (data.email === '[email protected]') return TE.left('suspendedEmail');
return TE.left({ password: ['VerifiedPassword'] });
};
const handleError = (error: LoginError) => {
setIsPending(false);
form.enable();
if (LoginFormAsyncErrors.is(error)) form.setAsyncErrors(error);
else {
switch (error) {
case 'suspendedEmail':
alert(error);
break;
case 'somethingElse':
alert(error);
break;
default:
// Absurd ensures all cases are handled.
absurd(error);
}
}
};
const handleSuccess = (payload: LoginPayload) => {
setIsPending(false);
form.reset();
alert(`payload: ${JSON.stringify(payload, null, 2)}`);
Router.push('/');
};
pipe(
form.validated,
E.fold(constVoid, data => {
setIsPending(true);
form.disable();
pipe(
asyncLogin(data),
TE.mapLeft(handleError),
TE.map(handleSuccess),
)();
}),
);
};
const form = useForm(
LoginForm,
{
email: '',
password: '',
},
{ handleSubmit },
);
const submitOnEnter: KeyboardEventHandler<HTMLInputElement> = event => {
if (event.key === 'Enter') form.submit();
};
return (
<>
<Head>
<title>Login</title>
</Head>
<Box m={8}>
<Text fontSize="xl">Login</Text>
<Box maxW="sm" borderWidth="1px" rounded="lg" p={4} my={4}>
<Stack spacing={4}>
<FormControl isRequired isInvalid={form.fields.email.isInvalid}>
<FormLabel htmlFor="email">Email</FormLabel>
<Input
id="email"
type="email"
value={form.fields.email.value}
onChange={form.fields.email.onHTMLInputValue}
onKeyPress={submitOnEnter}
ref={form.fields.email.ref}
/>
<FormErrorMessage error={form.fields.email.firstError} />
</FormControl>
<FormControl isRequired isInvalid={form.fields.password.isInvalid}>
<FormLabel htmlFor="password">Password</FormLabel>
<Input
id="password"
type="password"
value={form.fields.password.value}
onChange={form.fields.password.onHTMLInputValue}
onKeyPress={submitOnEnter}
ref={form.fields.password.ref}
/>
<FormErrorMessage error={form.fields.password.firstError} />
</FormControl>
<Button
isDisabled={isPending}
onClick={form.submit}
mt={4}
variantColor="green"
>
Login
</Button>
</Stack>
</Box>
<Stack>
<Text>
Try email <b>[email protected]</b> with passwords <b>aaaaaa</b>, <b>bbbbbb</b>
, or email <b>[email protected]</b>.
</Text>
</Stack>
</Box>
</>
);
}