mirror of
https://github.com/pybricks/pybricks-code.git
synced 2026-09-14 18:46:17 +00:00
src: use prop unpacking pattern
This makes the code a bit shorter by not having to use `props.` all of the time. Also make everything VoidFunctionComponent while we are touching this.
This commit is contained in:
+20
-14
@@ -46,16 +46,22 @@ type ActionButtonProps = {
|
||||
onClick: () => void;
|
||||
};
|
||||
|
||||
const ActionButton: React.VoidFunctionComponent<ActionButtonProps> = (props) => {
|
||||
const ActionButton: React.VoidFunctionComponent<ActionButtonProps> = ({
|
||||
icon,
|
||||
toolTipId,
|
||||
toolTipReplacements,
|
||||
disabled,
|
||||
onClick,
|
||||
}) => {
|
||||
const [i18n] = useI18n({ id: 'explorer', translations: { en }, fallback: en });
|
||||
|
||||
return (
|
||||
<Button
|
||||
icon={props.icon}
|
||||
title={i18n.translate(props.toolTipId, props.toolTipReplacements)}
|
||||
disabled={props.disabled}
|
||||
icon={icon}
|
||||
title={i18n.translate(toolTipId, toolTipReplacements)}
|
||||
disabled={disabled}
|
||||
onMouseDown={preventFocusOnClick}
|
||||
onClick={props.onClick}
|
||||
onClick={onClick}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -73,7 +79,7 @@ type ActionButtonGroupProps = {
|
||||
const FileActionButtonGroup = forwardRef<
|
||||
FileActionButtonGroupRef,
|
||||
ActionButtonGroupProps
|
||||
>((props, ref) => {
|
||||
>(({ fileName }, ref) => {
|
||||
const dispatch = useDispatch();
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [isRenameDialogOpen, setIsRenameDialogOpen] = useState(false);
|
||||
@@ -85,10 +91,10 @@ const FileActionButtonGroup = forwardRef<
|
||||
// received.
|
||||
const fileNames = useSelector((s) => s.fileStorage.fileNames);
|
||||
useEffect(() => {
|
||||
if (!fileNames.includes(props.fileName)) {
|
||||
if (!fileNames.includes(fileName)) {
|
||||
setVisible(false);
|
||||
}
|
||||
}, [fileNames, props.fileName, setVisible]);
|
||||
}, [fileNames, fileName, setVisible]);
|
||||
|
||||
useImperativeHandle(ref, () => ({ setVisible }), [setVisible]);
|
||||
|
||||
@@ -97,11 +103,11 @@ const FileActionButtonGroup = forwardRef<
|
||||
<ActionButton
|
||||
icon="edit"
|
||||
toolTipId={ExplorerStringId.TreeItemRenameTooltip}
|
||||
toolTipReplacements={{ fileName: props.fileName }}
|
||||
toolTipReplacements={{ fileName: fileName }}
|
||||
onClick={() => setIsRenameDialogOpen(true)}
|
||||
/>
|
||||
<RenameFileDialog
|
||||
oldName={props.fileName}
|
||||
oldName={fileName}
|
||||
isOpen={isRenameDialogOpen}
|
||||
onClose={() => setIsRenameDialogOpen(false)}
|
||||
/>
|
||||
@@ -113,14 +119,14 @@ const FileActionButtonGroup = forwardRef<
|
||||
// download operation
|
||||
icon="import"
|
||||
toolTipId={ExplorerStringId.TreeItemExportTooltip}
|
||||
toolTipReplacements={{ fileName: props.fileName }}
|
||||
onClick={() => dispatch(fileStorageExportFile(props.fileName))}
|
||||
toolTipReplacements={{ fileName: fileName }}
|
||||
onClick={() => dispatch(fileStorageExportFile(fileName))}
|
||||
/>
|
||||
<ActionButton
|
||||
icon="trash"
|
||||
toolTipId={ExplorerStringId.TreeItemDeleteTooltip}
|
||||
toolTipReplacements={{ fileName: props.fileName }}
|
||||
onClick={() => dispatch(explorerDeleteFile(props.fileName))}
|
||||
toolTipReplacements={{ fileName: fileName }}
|
||||
onClick={() => dispatch(explorerDeleteFile(fileName))}
|
||||
/>
|
||||
</ButtonGroup>
|
||||
);
|
||||
|
||||
@@ -17,12 +17,12 @@ type FileNameHelpTextProps = {
|
||||
/**
|
||||
* Component that maps FileNameValidationResult to help message to display to user.
|
||||
*/
|
||||
const FileNameHelpText: React.VoidFunctionComponent<FileNameHelpTextProps> = (
|
||||
props,
|
||||
) => {
|
||||
const FileNameHelpText: React.VoidFunctionComponent<FileNameHelpTextProps> = ({
|
||||
validation,
|
||||
}) => {
|
||||
const [i18n] = useI18n({ id: 'explorer', translations: { en }, fallback: en });
|
||||
|
||||
switch (props.validation) {
|
||||
switch (validation) {
|
||||
case FileNameValidationResult.IsOk:
|
||||
return <>{i18n.translate(NewFileWizardStringId.FileNameHelpTextIsOk)}</>;
|
||||
case FileNameValidationResult.IsEmpty:
|
||||
@@ -92,23 +92,27 @@ type FileNameFormGroupProps = {
|
||||
/**
|
||||
* Component used to get a valid new file name.
|
||||
*/
|
||||
const FileNameFormGroup: React.VoidFunctionComponent<FileNameFormGroupProps> = (
|
||||
props,
|
||||
) => {
|
||||
const FileNameFormGroup: React.VoidFunctionComponent<FileNameFormGroupProps> = ({
|
||||
fileName,
|
||||
fileExtension,
|
||||
inputRef,
|
||||
onChange,
|
||||
onValidation,
|
||||
}) => {
|
||||
const [i18n] = useI18n({ id: 'explorer', translations: { en }, fallback: en });
|
||||
const fileNames = useSelector((s) => s.fileStorage.fileNames);
|
||||
|
||||
const [fileNameValidation, fileNameIntent] = useMemo(() => {
|
||||
const result = validateFileName(props.fileName, props.fileExtension, fileNames);
|
||||
const result = validateFileName(fileName, fileExtension, fileNames);
|
||||
|
||||
// can't call callback now because it would break react, so defer it
|
||||
setTimeout(() => props.onValidation(result), 0);
|
||||
setTimeout(() => onValidation(result), 0);
|
||||
|
||||
return [
|
||||
result,
|
||||
result === FileNameValidationResult.IsOk ? Intent.NONE : Intent.DANGER,
|
||||
];
|
||||
}, [props.fileName, props.fileExtension, fileNames]);
|
||||
}, [fileName, fileExtension, fileNames]);
|
||||
|
||||
return (
|
||||
<FormGroup
|
||||
@@ -118,11 +122,11 @@ const FileNameFormGroup: React.VoidFunctionComponent<FileNameFormGroupProps> = (
|
||||
>
|
||||
<InputGroup
|
||||
aria-label="File name"
|
||||
value={props.fileName}
|
||||
inputRef={props.inputRef}
|
||||
value={fileName}
|
||||
inputRef={inputRef}
|
||||
intent={fileNameIntent}
|
||||
rightElement={<Tag>{props.fileExtension}</Tag>}
|
||||
onChange={(e) => props.onChange(e.target.value)}
|
||||
rightElement={<Tag>{fileExtension}</Tag>}
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
/>
|
||||
</FormGroup>
|
||||
);
|
||||
|
||||
@@ -32,7 +32,10 @@ type NewFileWizardProps = {
|
||||
readonly onClose: () => void;
|
||||
};
|
||||
|
||||
const NewFileWizard: React.VoidFunctionComponent<NewFileWizardProps> = (props) => {
|
||||
const NewFileWizard: React.VoidFunctionComponent<NewFileWizardProps> = ({
|
||||
isOpen,
|
||||
onClose,
|
||||
}) => {
|
||||
const [i18n] = useI18n({ id: 'explorer', translations: { en }, fallback: en });
|
||||
const dispatch = useDispatch();
|
||||
|
||||
@@ -48,10 +51,10 @@ const NewFileWizard: React.VoidFunctionComponent<NewFileWizardProps> = (props) =
|
||||
<Dialog
|
||||
icon="plus"
|
||||
title={i18n.translate(NewFileWizardStringId.Title)}
|
||||
isOpen={props.isOpen}
|
||||
isOpen={isOpen}
|
||||
onOpening={() => setFileName('')}
|
||||
onOpened={() => fileNameInputRef.current?.focus()}
|
||||
onClose={props.onClose}
|
||||
onClose={onClose}
|
||||
>
|
||||
<div className={Classes.DIALOG_BODY}>
|
||||
<FileNameFormGroup
|
||||
@@ -83,7 +86,7 @@ const NewFileWizard: React.VoidFunctionComponent<NewFileWizardProps> = (props) =
|
||||
disabled={fileNameValidation !== FileNameValidationResult.IsOk}
|
||||
onMouseDown={preventFocusOnClick}
|
||||
onClick={() => {
|
||||
props.onClose();
|
||||
onClose();
|
||||
dispatch(
|
||||
explorerCreateNewFile(
|
||||
fileName,
|
||||
|
||||
@@ -21,13 +21,15 @@ type RenameFileDialogProps = {
|
||||
onClose: () => void;
|
||||
};
|
||||
|
||||
const RenameFileDialog: React.VoidFunctionComponent<RenameFileDialogProps> = (
|
||||
props,
|
||||
) => {
|
||||
const RenameFileDialog: React.VoidFunctionComponent<RenameFileDialogProps> = ({
|
||||
oldName,
|
||||
isOpen,
|
||||
onClose,
|
||||
}) => {
|
||||
const [i18n] = useI18n({ id: 'explorer', translations: { en }, fallback: en });
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const [baseName, extension] = props.oldName.split(/(\.\w+)$/);
|
||||
const [baseName, extension] = oldName.split(/(\.\w+)$/);
|
||||
|
||||
const [newName, setNewName] = useState(baseName);
|
||||
const [result, setResult] = useState(FileNameValidationResult.Unknown);
|
||||
@@ -37,15 +39,15 @@ const RenameFileDialog: React.VoidFunctionComponent<RenameFileDialogProps> = (
|
||||
return (
|
||||
<Dialog
|
||||
title={i18n.translate(RenameFileStringId.Title, {
|
||||
fileName: props.oldName,
|
||||
fileName: oldName,
|
||||
})}
|
||||
isOpen={props.isOpen}
|
||||
isOpen={isOpen}
|
||||
onOpening={() => setNewName(baseName)}
|
||||
onOpened={() => {
|
||||
inputRef.current?.select();
|
||||
inputRef.current?.focus();
|
||||
}}
|
||||
onClose={() => props.onClose()}
|
||||
onClose={() => onClose()}
|
||||
>
|
||||
<div className={Classes.DIALOG_BODY}>
|
||||
<FileNameFormGroup
|
||||
@@ -64,10 +66,10 @@ const RenameFileDialog: React.VoidFunctionComponent<RenameFileDialogProps> = (
|
||||
disabled={result !== FileNameValidationResult.IsOk}
|
||||
onMouseDown={preventFocusOnClick}
|
||||
onClick={() => {
|
||||
props.onClose();
|
||||
onClose();
|
||||
dispatch(
|
||||
fileStorageRenameFile(
|
||||
props.oldName,
|
||||
oldName,
|
||||
`${newName}${extension}`,
|
||||
),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user