feat: Intra-line double link interaction

This commit is contained in:
xiaodong zuo
2022-08-19 18:22:57 +08:00
parent 33d8b551d4
commit 3570aab4e8
4 changed files with 16 additions and 69 deletions
@@ -2,6 +2,7 @@ import { PagesIcon } from '@toeverything/components/icons';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { Descendant } from 'slate'; import { Descendant } from 'slate';
import { RenderElementProps } from 'slate-react';
export type DoubleLinkElement = { export type DoubleLinkElement = {
type: 'link'; type: 'link';
@@ -11,17 +12,17 @@ export type DoubleLinkElement = {
id: string; id: string;
}; };
export const DoubleLinkComponent = ({ attributes, children, element }: any) => { export const DoubleLinkComponent = (props: RenderElementProps) => {
const { attributes, children, element } = props;
const doubleLinkElement = element as DoubleLinkElement;
const navigate = useNavigate(); const navigate = useNavigate();
const handleClickLinkText = useCallback( const handleClickLinkText = useCallback(
(event: React.MouseEvent<HTMLAnchorElement>) => { (event: React.MouseEvent<HTMLAnchorElement>) => {
event.preventDefault(); const { workspaceId, blockId } = doubleLinkElement;
event.stopPropagation();
const { workspaceId, blockId } = element;
navigate(`/${workspaceId}/${blockId}`); navigate(`/${workspaceId}/${blockId}`);
}, },
[element, navigate] [doubleLinkElement, navigate]
); );
return ( return (
@@ -30,7 +31,7 @@ export const DoubleLinkComponent = ({ attributes, children, element }: any) => {
<a <a
{...attributes} {...attributes}
style={{ cursor: 'pointer' }} style={{ cursor: 'pointer' }}
href={`/${element.workspaceId}/${element.blockId}`} href={`/${doubleLinkElement.workspaceId}/${doubleLinkElement.blockId}`}
> >
<span onClick={handleClickLinkText}>{children}</span> <span onClick={handleClickLinkText}>{children}</span>
</a> </a>
@@ -162,7 +162,6 @@ export class AsyncBlock {
const oldData = this.raw_data; const oldData = this.raw_data;
this.raw_data = blockData; this.raw_data = blockData;
this.raw_data = await this.filterPageInvalidChildren(blockData); this.raw_data = await this.filterPageInvalidChildren(blockData);
this.raw_data = await this.updateDoubleLinkBlock(this.raw_data);
this.emit('update', { block: this, oldData }); this.emit('update', { block: this, oldData });
} }
); );
@@ -1,11 +1,6 @@
import { import { CommonList, CommonListItem } from '@toeverything/components/common';
CommonList,
commonListContainer,
CommonListItem,
} from '@toeverything/components/common';
import { styled } from '@toeverything/components/ui'; import { styled } from '@toeverything/components/ui';
import { HookType, PluginHooks, Virgo } from '@toeverything/framework/virgo'; import { HookType, PluginHooks, Virgo } from '@toeverything/framework/virgo';
import { domToRect } from '@toeverything/utils';
import React, { useCallback, useEffect, useRef, useState } from 'react'; import React, { useCallback, useEffect, useRef, useState } from 'react';
export type DoubleLinkMenuContainerProps = { export type DoubleLinkMenuContainerProps = {
@@ -25,35 +20,6 @@ export const DoubleLinkMenuContainer = (
const { hooks, onSelected, onClose, types, style, items } = props; const { hooks, onSelected, onClose, types, style, items } = props;
const menuRef = useRef<HTMLDivElement>(null); const menuRef = useRef<HTMLDivElement>(null);
const [currentItem, setCurrentItem] = useState<string | undefined>(); const [currentItem, setCurrentItem] = useState<string | undefined>();
const [needCheckIntoView, setNeedCheckIntoView] = useState<boolean>(false);
useEffect(() => {
if (needCheckIntoView) {
if (currentItem && menuRef.current) {
const itemElement =
menuRef.current.querySelector<HTMLButtonElement>(
`.item-${currentItem}`
);
const scrollElement =
menuRef.current.querySelector<HTMLButtonElement>(
`.${commonListContainer}`
);
if (itemElement) {
const itemRect = domToRect(itemElement);
const scrollRect = domToRect(scrollElement);
if (
itemRect.top < scrollRect.top ||
itemRect.bottom > scrollRect.bottom
) {
itemElement.scrollIntoView({
block: 'nearest',
});
}
}
}
setNeedCheckIntoView(false);
}
}, [needCheckIntoView, currentItem]);
useEffect(() => { useEffect(() => {
if (types && !currentItem) { if (types && !currentItem) {
@@ -61,19 +27,6 @@ export const DoubleLinkMenuContainer = (
} }
}, [currentItem, onClose, types]); }, [currentItem, onClose, types]);
useEffect(() => {
if (types) {
if (!types.includes(currentItem)) {
setNeedCheckIntoView(true);
if (types.length) {
setCurrentItem(types[0]);
} else {
setCurrentItem(undefined);
}
}
}
}, [types, currentItem]);
const handleUpDownKey = useCallback( const handleUpDownKey = useCallback(
(event: React.KeyboardEvent<HTMLDivElement>) => { (event: React.KeyboardEvent<HTMLDivElement>) => {
if (types && ['ArrowUp', 'ArrowDown'].includes(event.code)) { if (types && ['ArrowUp', 'ArrowDown'].includes(event.code)) {
@@ -85,7 +38,6 @@ export const DoubleLinkMenuContainer = (
if (currentItem) { if (currentItem) {
const idx = types.indexOf(currentItem); const idx = types.indexOf(currentItem);
if (isUpkey ? idx > 0 : idx < types.length - 1) { if (isUpkey ? idx > 0 : idx < types.length - 1) {
setNeedCheckIntoView(true);
setCurrentItem(types[isUpkey ? idx - 1 : idx + 1]); setCurrentItem(types[isUpkey ? idx - 1 : idx + 1]);
} }
} }
@@ -156,19 +156,14 @@ export const DoubleLinkMenu = ({
}); });
setAnchorEl(dialogRef.current); setAnchorEl(dialogRef.current);
} }
setTimeout(() => { const textSelection = editor.blockHelper.selectionToSlateRange(
const textSelection = editor.blockHelper.selectionToSlateRange( nextNodeId,
nextNodeId, editor.selection.currentSelectInfo?.browserSelection
editor.selection.currentSelectInfo.browserSelection );
); if (textSelection) {
if (textSelection) { const { anchor } = textSelection;
const { anchor } = textSelection; editor.blockHelper.setDoubleLinkSearchSlash(nextNodeId, anchor);
editor.blockHelper.setDoubleLinkSearchSlash( }
nextNodeId,
anchor
);
}
});
}, },
[editor] [editor]
); );