perf: Don't render SuggestionMenu contents until active
This commit is contained in:
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user