utils/react: add preventDefault helpers

These can be used instead of always having to add a comment explaining
what preventDefault does in a given context.
This commit is contained in:
David Lechner
2022-03-12 14:57:30 -06:00
parent d8f958d18e
commit c229d407cf
8 changed files with 36 additions and 20 deletions
+3 -3
View File
@@ -26,6 +26,7 @@ import {
fileStorageExportFile,
} from '../fileStorage/actions';
import { useSelector } from '../reducers';
import { preventBrowserNativeContextMenu, preventFocusOnClick } from '../utils/react';
import NewFileWizard from './NewFileWizard';
import RenameFileDialog from './RenameFileDialog';
import { explorerDeleteFile, explorerImportFiles } from './actions';
@@ -53,8 +54,7 @@ const ActionButton: React.VoidFunctionComponent<ActionButtonProps> = (props) =>
icon={props.icon}
title={i18n.translate(props.toolTipId, props.toolTipReplacements)}
disabled={props.disabled}
// prevent focus on click
onMouseDown={(e) => e.preventDefault()}
onMouseDown={preventFocusOnClick}
onClick={() => props.onClick()}
/>
);
@@ -208,7 +208,7 @@ const FileTree: React.VFC = () => {
const Explorer: React.VFC = () => {
return (
<div className="h-100" onContextMenu={(e) => e.preventDefault()}>
<div className="h-100" onContextMenu={preventBrowserNativeContextMenu}>
<Header />
<Divider />
<FileTree />
+2 -1
View File
@@ -16,6 +16,7 @@ import {
FileNameValidationResult,
pythonFileExtension,
} from '../pybricksMicropython/lib';
import { preventFocusOnClick } from '../utils/react';
import FileNameFormGroup from './FileNameFormGroup';
import { Hub, explorerCreateNewFile } from './actions';
import { NewFileWizardStringId } from './i18n';
@@ -80,7 +81,7 @@ const NewFileWizard: React.VoidFunctionComponent<NewFileWizardProps> = (props) =
aria-label="Create"
intent="primary"
disabled={fileNameValidation !== FileNameValidationResult.IsOk}
onMouseDown={(e) => e.preventDefault()}
onMouseDown={preventFocusOnClick}
onClick={() => {
props.onClose();
dispatch(
+2 -1
View File
@@ -7,6 +7,7 @@ import React, { useRef, useState } from 'react';
import { useDispatch } from 'react-redux';
import { fileStorageRenameFile } from '../fileStorage/actions';
import { FileNameValidationResult } from '../pybricksMicropython/lib';
import { preventFocusOnClick } from '../utils/react';
import FileNameFormGroup from './FileNameFormGroup';
import { RenameFileStringId } from './i18n';
import en from './i18n.en.json';
@@ -61,7 +62,7 @@ const RenameFileDialog: React.VoidFunctionComponent<RenameFileDialogProps> = (
aria-label="Rename"
intent="primary"
disabled={result !== FileNameValidationResult.IsOk}
onMouseDown={(e) => e.preventDefault()}
onMouseDown={preventFocusOnClick}
onClick={() => {
props.onClose();
dispatch(
+4 -3
View File
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2020-2021 The Pybricks Authors
// Copyright (c) 2020-2022 The Pybricks Authors
import { Button, Intent, ProgressBar } from '@blueprintjs/core';
import { Classes as Classes2, Popover2, Popover2Props } from '@blueprintjs/popover2';
@@ -7,6 +7,7 @@ import { useI18n } from '@shopify/react-i18n';
import React from 'react';
import { BleConnectionState } from '../ble/reducers';
import { useSelector } from '../reducers';
import { preventBrowserNativeContextMenu, preventFocusOnClick } from '../utils/react';
import { MessageId } from './i18n';
import en from './i18n.en.json';
@@ -61,7 +62,7 @@ const HubInfoButton: React.VFC = (_props) => {
<Button
title={i18n.translate(MessageId.HubInfoTitle)}
minimal={true}
onMouseDown={(e) => e.preventDefault()}
onMouseDown={preventFocusOnClick}
>
{deviceName}
</Button>
@@ -112,7 +113,7 @@ const StatusBar: React.VFC = (_props) => {
className="pb-status-bar"
role="status"
aria-live="off"
onContextMenu={(e): void => e.preventDefault()}
onContextMenu={preventBrowserNativeContextMenu}
>
{connection === BleConnectionState.Connected && (
<>
+3 -5
View File
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2020-2021 The Pybricks Authors
// Copyright (c) 2020-2022 The Pybricks Authors
import {
Button,
@@ -13,6 +13,7 @@ import { Tooltip2 } from '@blueprintjs/popover2';
import { useI18n } from '@shopify/react-i18n';
import React, { useEffect, useMemo, useState } from 'react';
import { tooltipDelay } from '../app/constants';
import { preventFocusOnClick } from '../utils/react';
import { TooltipId } from './i18n';
import en from './i18n.en.json';
@@ -104,10 +105,7 @@ const ActionButton: React.FC<ActionButtonProps> = (props) => {
elementRef={tooltipTargetRef as IRef<HTMLButtonElement>}
{...tooltipTargetProps}
intent={Intent.PRIMARY}
onMouseDown={(e) => {
// prevent focus from mouse click
e.preventDefault();
}}
onMouseDown={preventFocusOnClick}
onClick={() => props.onAction()}
disabled={props.enabled === false}
style={
+3 -5
View File
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2020-2021 The Pybricks Authors
// Copyright (c) 2020-2022 The Pybricks Authors
import { Button, IRef, Intent, Spinner, SpinnerSize } from '@blueprintjs/core';
import { Tooltip2 } from '@blueprintjs/popover2';
@@ -7,6 +7,7 @@ import { useI18n } from '@shopify/react-i18n';
import React, { useEffect, useState } from 'react';
import { useDropzone } from 'react-dropzone';
import { tooltipDelay } from '../app/constants';
import { preventFocusOnClick } from '../utils/react';
import { TooltipId } from './i18n';
import en from './i18n.en.json';
@@ -123,10 +124,7 @@ const OpenFileButton: React.FC<OpenFileButtonProps> = (props) => {
props.enabled === false
? { pointerEvents: 'none' }
: undefined,
onMouseDown: (e) => {
// prevent focus from mouse click
e.preventDefault();
},
onMouseDown: preventFocusOnClick,
onClick: props.onClick,
})}
>
+3 -2
View File
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2020-2021 The Pybricks Authors
// Copyright (c) 2020-2022 The Pybricks Authors
import { ButtonGroup } from '@blueprintjs/core';
import React, { useState } from 'react';
@@ -12,6 +12,7 @@ import RunButton from '../hub/RunButton';
import StopButton from '../hub/StopButton';
import SettingsButton from '../settings/SettingsButton';
import SettingsDrawer from '../settings/SettingsDrawer';
import { preventBrowserNativeContextMenu } from '../utils/react';
import './toolbar.scss';
@@ -21,7 +22,7 @@ const Toolbar: React.VFC = (_props) => {
return (
<div
role="toolbar"
onContextMenu={(e): void => e.preventDefault()}
onContextMenu={preventBrowserNativeContextMenu}
className="pb-toolbar"
>
<ButtonGroup className="pb-toolbar-group pb-align-left">
+16
View File
@@ -0,0 +1,16 @@
// helper functions for React components
import React from 'react';
/**
* Callback that can be passed to onMouseDown event handlers to prevent
* an element from becoming focused when clicked.
*/
export const preventFocusOnClick: React.MouseEventHandler = (e) => e.preventDefault();
/**
* Callback that can be passed to onContextMenu event handlers to prevent
* the native browser context menu from being shown.
*/
export const preventBrowserNativeContextMenu: React.MouseEventHandler = (e) =>
e.preventDefault();