perf: Don't render SuggestionMenu contents until active

This commit is contained in:
Tom Moor
2023-09-27 21:19:55 -04:00
parent 318a1120d4
commit 6de96b1d9d

View File

@@ -79,6 +79,7 @@ function SuggestionsMenu<T extends MenuItem>(props: Props<T>) {
const { view, commands } = useEditor(); const { view, commands } = useEditor();
const { showToast: onShowToast } = useToasts(); const { showToast: onShowToast } = useToasts();
const dictionary = useDictionary(); const dictionary = useDictionary();
const hasActivated = React.useRef(false);
const menuRef = React.useRef<HTMLDivElement>(null); const menuRef = React.useRef<HTMLDivElement>(null);
const inputRef = React.useRef<HTMLInputElement>(null); const inputRef = React.useRef<HTMLInputElement>(null);
const [position, setPosition] = React.useState<Position>(defaultPosition); const [position, setPosition] = React.useState<Position>(defaultPosition);
@@ -87,6 +88,12 @@ function SuggestionsMenu<T extends MenuItem>(props: Props<T>) {
>(); >();
const [selectedIndex, setSelectedIndex] = React.useState(0); const [selectedIndex, setSelectedIndex] = React.useState(0);
React.useEffect(() => {
if (props.isActive) {
hasActivated.current = true;
}
}, [props.isActive]);
const calculatePosition = React.useCallback( const calculatePosition = React.useCallback(
(props: Props) => { (props: Props) => {
if (!props.isActive) { if (!props.isActive) {
@@ -534,73 +541,77 @@ function SuggestionsMenu<T extends MenuItem>(props: Props<T>) {
return ( return (
<Portal> <Portal>
<Wrapper active={isActive} ref={menuRef} hiddenScrollbars {...position}> <Wrapper active={isActive} ref={menuRef} hiddenScrollbars {...position}>
{insertItem ? ( {(isActive || hasActivated.current) && (
<LinkInputWrapper> <>
<LinkInput {insertItem ? (
type="text" <LinkInputWrapper>
placeholder={ <LinkInput
insertItem.title type="text"
? dictionary.pasteLinkWithTitle(insertItem.title) placeholder={
: dictionary.pasteLink insertItem.title
} ? dictionary.pasteLinkWithTitle(insertItem.title)
onKeyDown={handleLinkInputKeydown} : dictionary.pasteLink
onPaste={handleLinkInputPaste} }
autoFocus onKeyDown={handleLinkInputKeydown}
/> onPaste={handleLinkInputPaste}
</LinkInputWrapper> autoFocus
) : ( />
<List> </LinkInputWrapper>
{items.map((item, index) => { ) : (
if (item.name === "separator") { <List>
return ( {items.map((item, index) => {
<ListItem key={index}> if (item.name === "separator") {
<hr /> return (
<ListItem key={index}>
<hr />
</ListItem>
);
}
if (!item.title) {
return null;
}
const handlePointer = () => {
if (selectedIndex !== index) {
setSelectedIndex(index);
}
};
return (
<ListItem
key={index}
onPointerMove={handlePointer}
onPointerDown={handlePointer}
>
{props.renderMenuItem(item as any, index, {
selected: index === selectedIndex,
onClick: () => handleClickItem(item),
})}
</ListItem>
);
})}
{items.length === 0 && (
<ListItem>
<Empty>{dictionary.noResults}</Empty>
</ListItem> </ListItem>
); )}
} </List>
if (!item.title) {
return null;
}
const handlePointer = () => {
if (selectedIndex !== index) {
setSelectedIndex(index);
}
};
return (
<ListItem
key={index}
onPointerMove={handlePointer}
onPointerDown={handlePointer}
>
{props.renderMenuItem(item as any, index, {
selected: index === selectedIndex,
onClick: () => handleClickItem(item),
})}
</ListItem>
);
})}
{items.length === 0 && (
<ListItem>
<Empty>{dictionary.noResults}</Empty>
</ListItem>
)} )}
</List> {uploadFile && (
)} <VisuallyHidden>
{uploadFile && ( <label>
<VisuallyHidden> <Trans>Import document</Trans>
<label> <input
<Trans>Import document</Trans> type="file"
<input ref={inputRef}
type="file" onChange={handleFilesPicked}
ref={inputRef} multiple
onChange={handleFilesPicked} />
multiple </label>
/> </VisuallyHidden>
</label> )}
</VisuallyHidden> </>
)} )}
</Wrapper> </Wrapper>
</Portal> </Portal>