refactor(web): remove typescript
This commit is contained in:
@@ -1,17 +1,6 @@
|
||||
import * as React from 'react';
|
||||
import { Controller as RHFController, useFormContext } from 'react-hook-form';
|
||||
|
||||
interface ControllerProps {
|
||||
defaultValue?: string;
|
||||
name: string;
|
||||
required?: boolean;
|
||||
shouldUnregister?: boolean;
|
||||
children: React.ReactElement;
|
||||
}
|
||||
|
||||
function Controller(
|
||||
props: ControllerProps
|
||||
): React.ReactElement {
|
||||
function Controller(props) {
|
||||
const { control } = useFormContext();
|
||||
const {
|
||||
defaultValue = '',
|
||||
@@ -20,7 +9,6 @@ function Controller(
|
||||
shouldUnregister,
|
||||
children,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<RHFController
|
||||
rules={{ required }}
|
||||
@@ -28,11 +16,8 @@ function Controller(
|
||||
control={control}
|
||||
defaultValue={defaultValue}
|
||||
shouldUnregister={shouldUnregister ?? false}
|
||||
render={({
|
||||
field,
|
||||
}) => React.cloneElement(children, { field })}
|
||||
render={({ field }) => React.cloneElement(children, { field })}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default Controller;
|
@@ -2,27 +2,11 @@ import Paper from '@mui/material/Paper';
|
||||
import Popper from '@mui/material/Popper';
|
||||
import Tab from '@mui/material/Tab';
|
||||
import * as React from 'react';
|
||||
|
||||
import type { IFieldDropdownOption } from 'types';
|
||||
import Suggestions from 'components/PowerInput/Suggestions';
|
||||
import TabPanel from 'components/TabPanel';
|
||||
|
||||
import Options from './Options';
|
||||
import { Tabs } from './style';
|
||||
|
||||
interface CustomOptionsProps {
|
||||
open: boolean;
|
||||
anchorEl: any;
|
||||
data: any;
|
||||
options: readonly IFieldDropdownOption[];
|
||||
onSuggestionClick: any;
|
||||
onOptionClick: (event: React.MouseEvent, option: any) => void;
|
||||
onTabChange: (tabIndex: 0 | 1) => void;
|
||||
label?: string;
|
||||
initialTabIndex?: 0 | 1;
|
||||
}
|
||||
|
||||
const CustomOptions = (props: CustomOptionsProps) => {
|
||||
const CustomOptions = (props) => {
|
||||
const {
|
||||
open,
|
||||
anchorEl,
|
||||
@@ -34,24 +18,18 @@ const CustomOptions = (props: CustomOptionsProps) => {
|
||||
label,
|
||||
initialTabIndex,
|
||||
} = props;
|
||||
|
||||
const [activeTabIndex, setActiveTabIndex] = React.useState<
|
||||
number | undefined
|
||||
>(undefined);
|
||||
|
||||
const [activeTabIndex, setActiveTabIndex] = React.useState(undefined);
|
||||
React.useEffect(
|
||||
function applyInitialActiveTabIndex() {
|
||||
setActiveTabIndex((currentActiveTabIndex) => {
|
||||
if (currentActiveTabIndex === undefined) {
|
||||
return initialTabIndex;
|
||||
}
|
||||
|
||||
return currentActiveTabIndex;
|
||||
});
|
||||
},
|
||||
[initialTabIndex]
|
||||
[initialTabIndex],
|
||||
);
|
||||
|
||||
return (
|
||||
<Popper
|
||||
open={open}
|
||||
@@ -91,5 +69,4 @@ const CustomOptions = (props: CustomOptionsProps) => {
|
||||
</Popper>
|
||||
);
|
||||
};
|
||||
|
||||
export default CustomOptions;
|
@@ -1,35 +1,23 @@
|
||||
import type { IFieldDropdownOption } from 'types';
|
||||
import ListItemButton from '@mui/material/ListItemButton';
|
||||
import ListItemText from '@mui/material/ListItemText';
|
||||
import throttle from 'lodash/throttle';
|
||||
import * as React from 'react';
|
||||
import { FixedSizeList, ListChildComponentProps } from 'react-window';
|
||||
|
||||
import { FixedSizeList } from 'react-window';
|
||||
import { Typography } from '@mui/material';
|
||||
import SearchInput from 'components/SearchInput';
|
||||
import useFormatMessage from 'hooks/useFormatMessage';
|
||||
import { SearchInputWrapper } from './style';
|
||||
|
||||
interface OptionsProps {
|
||||
data: readonly IFieldDropdownOption[];
|
||||
onOptionClick: (event: React.MouseEvent, option: any) => void;
|
||||
}
|
||||
|
||||
const SHORT_LIST_LENGTH = 4;
|
||||
const LIST_ITEM_HEIGHT = 64;
|
||||
|
||||
const computeListHeight = (currentLength: number) => {
|
||||
const computeListHeight = (currentLength) => {
|
||||
const numberOfRenderedItems = Math.min(SHORT_LIST_LENGTH, currentLength);
|
||||
return LIST_ITEM_HEIGHT * numberOfRenderedItems;
|
||||
};
|
||||
|
||||
const renderItemFactory =
|
||||
({ onOptionClick }: Pick<OptionsProps, 'onOptionClick'>) =>
|
||||
(props: ListChildComponentProps) => {
|
||||
({ onOptionClick }) =>
|
||||
(props) => {
|
||||
const { index, style, data } = props;
|
||||
|
||||
const suboption = data[index];
|
||||
|
||||
return (
|
||||
<ListItemButton
|
||||
sx={{ pl: 4 }}
|
||||
@@ -56,55 +44,45 @@ const renderItemFactory =
|
||||
</ListItemButton>
|
||||
);
|
||||
};
|
||||
|
||||
const Options = (props: OptionsProps) => {
|
||||
const Options = (props) => {
|
||||
const formatMessage = useFormatMessage();
|
||||
const { data, onOptionClick } = props;
|
||||
const [filteredData, setFilteredData] =
|
||||
React.useState<readonly IFieldDropdownOption[]>(data);
|
||||
|
||||
const [filteredData, setFilteredData] = React.useState(data);
|
||||
React.useEffect(
|
||||
function syncOptions() {
|
||||
setFilteredData((filteredData) => {
|
||||
if (filteredData.length === 0 && filteredData.length !== data.length) {
|
||||
return data;
|
||||
}
|
||||
|
||||
return filteredData;
|
||||
});
|
||||
},
|
||||
[data]
|
||||
[data],
|
||||
);
|
||||
|
||||
const renderItem = React.useMemo(
|
||||
() =>
|
||||
renderItemFactory({
|
||||
onOptionClick,
|
||||
}),
|
||||
[onOptionClick]
|
||||
[onOptionClick],
|
||||
);
|
||||
|
||||
const onSearchChange = React.useMemo(
|
||||
() =>
|
||||
throttle((event: React.ChangeEvent) => {
|
||||
const search = (event.target as HTMLInputElement).value.toLowerCase();
|
||||
|
||||
throttle((event) => {
|
||||
const search = event.target.value.toLowerCase();
|
||||
if (!search) {
|
||||
setFilteredData(data);
|
||||
return;
|
||||
}
|
||||
|
||||
const newFilteredData = data.filter((option) =>
|
||||
`${option.label}\n${option.value}`
|
||||
.toLowerCase()
|
||||
.includes(search.toLowerCase())
|
||||
.includes(search.toLowerCase()),
|
||||
);
|
||||
|
||||
setFilteredData(newFilteredData);
|
||||
}, 400),
|
||||
[data]
|
||||
[data],
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchInputWrapper>
|
||||
@@ -130,5 +108,4 @@ const Options = (props: OptionsProps) => {
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Options;
|
@@ -2,20 +2,15 @@ import * as React from 'react';
|
||||
import { useController, useFormContext } from 'react-hook-form';
|
||||
import { IconButton } from '@mui/material';
|
||||
import FormHelperText from '@mui/material/FormHelperText';
|
||||
import { AutocompleteProps } from '@mui/material/Autocomplete';
|
||||
import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
|
||||
import ClearIcon from '@mui/icons-material/Clear';
|
||||
import type { IFieldDropdownOption } from 'types';
|
||||
import { ActionButtonsWrapper } from './style';
|
||||
|
||||
import ClickAwayListener from '@mui/base/ClickAwayListener';
|
||||
import InputLabel from '@mui/material/InputLabel';
|
||||
import { createEditor } from 'slate';
|
||||
import { Editable, ReactEditor } from 'slate-react';
|
||||
|
||||
import Slate from 'components/Slate';
|
||||
import Element from 'components/Slate/Element';
|
||||
|
||||
import {
|
||||
serialize,
|
||||
deserialize,
|
||||
@@ -30,32 +25,10 @@ import {
|
||||
InputLabelWrapper,
|
||||
ChildrenWrapper,
|
||||
} from 'components/PowerInput/style';
|
||||
import { VariableElement } from 'components/Slate/types';
|
||||
import CustomOptions from './CustomOptions';
|
||||
import { processStepWithExecutions } from 'components/PowerInput/data';
|
||||
import { StepExecutionsContext } from 'contexts/StepExecutions';
|
||||
|
||||
interface ControlledCustomAutocompleteProps
|
||||
extends AutocompleteProps<IFieldDropdownOption, boolean, boolean, boolean> {
|
||||
showOptionValue?: boolean;
|
||||
dependsOn?: string[];
|
||||
|
||||
defaultValue?: string;
|
||||
name: string;
|
||||
label?: string;
|
||||
type?: string;
|
||||
required?: boolean;
|
||||
readOnly?: boolean;
|
||||
description?: string;
|
||||
docUrl?: string;
|
||||
clickToCopy?: boolean;
|
||||
disabled?: boolean;
|
||||
shouldUnregister?: boolean;
|
||||
}
|
||||
|
||||
function ControlledCustomAutocomplete(
|
||||
props: ControlledCustomAutocompleteProps
|
||||
): React.ReactElement {
|
||||
function ControlledCustomAutocomplete(props) {
|
||||
const {
|
||||
defaultValue = '',
|
||||
name,
|
||||
@@ -83,63 +56,48 @@ function ControlledCustomAutocomplete(
|
||||
} = field;
|
||||
const [, forceUpdate] = React.useReducer((x) => x + 1, 0);
|
||||
const [isInitialValueSet, setInitialValue] = React.useState(false);
|
||||
const [isSingleChoice, setSingleChoice] = React.useState<boolean | undefined>(
|
||||
undefined
|
||||
);
|
||||
const [isSingleChoice, setSingleChoice] = React.useState(undefined);
|
||||
const priorStepsWithExecutions = React.useContext(StepExecutionsContext);
|
||||
const editorRef = React.useRef<HTMLDivElement | null>(null);
|
||||
const editorRef = React.useRef(null);
|
||||
const renderElement = React.useCallback(
|
||||
(props) => <Element {...props} disabled={disabled} />,
|
||||
[disabled]
|
||||
[disabled],
|
||||
);
|
||||
const [editor] = React.useState(() => customizeEditor(createEditor()));
|
||||
const [showVariableSuggestions, setShowVariableSuggestions] =
|
||||
React.useState(false);
|
||||
|
||||
let dependsOnValues: unknown[] = [];
|
||||
let dependsOnValues = [];
|
||||
if (dependsOn?.length) {
|
||||
dependsOnValues = watch(dependsOn);
|
||||
}
|
||||
|
||||
React.useEffect(() => {
|
||||
const ref = ReactEditor.toDOMNode(editor, editor);
|
||||
|
||||
resizeObserver.observe(ref);
|
||||
|
||||
return () => resizeObserver.unobserve(ref);
|
||||
}, []);
|
||||
|
||||
const promoteValue = () => {
|
||||
const serializedValue = serialize(editor.children);
|
||||
controllerOnChange(serializedValue);
|
||||
};
|
||||
|
||||
const resizeObserver = React.useMemo(function syncCustomOptionsPosition() {
|
||||
return new ResizeObserver(() => {
|
||||
forceUpdate();
|
||||
});
|
||||
}, []);
|
||||
|
||||
React.useEffect(() => {
|
||||
const hasDependencies = dependsOnValues.length;
|
||||
|
||||
if (hasDependencies) {
|
||||
// Reset the field when a dependent has been updated
|
||||
resetEditor(editor);
|
||||
}
|
||||
}, dependsOnValues);
|
||||
|
||||
React.useEffect(
|
||||
function updateInitialValue() {
|
||||
const hasOptions = options.length;
|
||||
const isOptionsLoaded = loading === false;
|
||||
if (!isInitialValueSet && hasOptions && isOptionsLoaded) {
|
||||
setInitialValue(true);
|
||||
|
||||
const option: IFieldDropdownOption | undefined = options.find(
|
||||
(option) => option.value === value
|
||||
);
|
||||
|
||||
const option = options.find((option) => option.value === value);
|
||||
if (option) {
|
||||
overrideEditorValue(editor, { option, focus: false });
|
||||
setSingleChoice(true);
|
||||
@@ -148,70 +106,56 @@ function ControlledCustomAutocomplete(
|
||||
}
|
||||
}
|
||||
},
|
||||
[isInitialValueSet, options, loading]
|
||||
[isInitialValueSet, options, loading],
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!showVariableSuggestions && value !== serialize(editor.children)) {
|
||||
promoteValue();
|
||||
}
|
||||
}, [showVariableSuggestions]);
|
||||
|
||||
const hideSuggestionsOnShift = (
|
||||
event: React.KeyboardEvent<HTMLInputElement>
|
||||
) => {
|
||||
const hideSuggestionsOnShift = (event) => {
|
||||
if (event.code === 'Tab') {
|
||||
setShowVariableSuggestions(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
const handleKeyDown = (event) => {
|
||||
hideSuggestionsOnShift(event);
|
||||
if (event.code === 'Tab') {
|
||||
promoteValue();
|
||||
}
|
||||
|
||||
if (isSingleChoice && event.code !== 'Tab') {
|
||||
event.preventDefault();
|
||||
}
|
||||
};
|
||||
|
||||
const stepsWithVariables = React.useMemo(() => {
|
||||
return processStepWithExecutions(priorStepsWithExecutions);
|
||||
}, [priorStepsWithExecutions]);
|
||||
|
||||
const handleVariableSuggestionClick = React.useCallback(
|
||||
(variable: Pick<VariableElement, 'name' | 'value'>) => {
|
||||
(variable) => {
|
||||
insertVariable(editor, variable, stepsWithVariables);
|
||||
},
|
||||
[stepsWithVariables]
|
||||
[stepsWithVariables],
|
||||
);
|
||||
|
||||
const handleOptionClick = React.useCallback(
|
||||
(event: React.MouseEvent, option: IFieldDropdownOption) => {
|
||||
(event, option) => {
|
||||
event.stopPropagation();
|
||||
overrideEditorValue(editor, { option, focus: false });
|
||||
setShowVariableSuggestions(false);
|
||||
setSingleChoice(true);
|
||||
},
|
||||
[stepsWithVariables]
|
||||
[stepsWithVariables],
|
||||
);
|
||||
|
||||
const handleClearButtonClick = (event: React.MouseEvent) => {
|
||||
const handleClearButtonClick = (event) => {
|
||||
event.stopPropagation();
|
||||
resetEditor(editor);
|
||||
promoteValue();
|
||||
setSingleChoice(undefined);
|
||||
};
|
||||
|
||||
const reset = (tabIndex: 0 | 1) => {
|
||||
const reset = (tabIndex) => {
|
||||
const isOptions = tabIndex === 0;
|
||||
|
||||
setSingleChoice(isOptions);
|
||||
|
||||
resetEditor(editor, { focus: true });
|
||||
};
|
||||
|
||||
return (
|
||||
<Slate
|
||||
editor={editor}
|
||||
@@ -313,5 +257,4 @@ function ControlledCustomAutocomplete(
|
||||
</Slate>
|
||||
);
|
||||
}
|
||||
|
||||
export default ControlledCustomAutocomplete;
|
@@ -1,18 +1,15 @@
|
||||
import { styled } from '@mui/material/styles';
|
||||
import Stack from '@mui/material/Stack';
|
||||
import MuiTabs from '@mui/material/Tabs';
|
||||
|
||||
export const ActionButtonsWrapper = styled(Stack)`
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
`;
|
||||
|
||||
export const Tabs = styled(MuiTabs)`
|
||||
border-bottom: 1px solid ${({ theme }) => theme.palette.divider};
|
||||
`;
|
||||
|
||||
export const SearchInputWrapper = styled('div')`
|
||||
padding: ${({ theme }) => theme.spacing(0, 2, 2, 2)};
|
||||
`;
|
Reference in New Issue
Block a user