From 7d35303395e9154a29de8f6586aabd5b7352b8af Mon Sep 17 00:00:00 2001 From: xiaodong zuo Date: Tue, 23 Aug 2022 10:37:14 +0800 Subject: [PATCH 01/11] feat: Inlinemenu double link interaction --- README.md | 2 +- .../src/lib/text/plugins/DoubleLink.tsx | 1 + .../menu/double-link-menu/DoubleLinkMenu.tsx | 101 ++++++++++-------- .../menu/inline-menu/menu-item/IconItem.tsx | 7 +- .../src/menu/inline-menu/types.ts | 4 +- .../src/menu/inline-menu/utils.ts | 5 + 6 files changed, 73 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index 718d32c94d..19e0db1307 100644 --- a/README.md +++ b/README.md @@ -141,7 +141,7 @@ Our latest news can be found on [Twitter](https://twitter.com/AffineOfficial), [ # Contact Us -You may contact us by emailing to: contact@toeverything.info +You may contact us by emailing to: contact@toeverything.info # The Philosophy of AFFiNE diff --git a/libs/components/common/src/lib/text/plugins/DoubleLink.tsx b/libs/components/common/src/lib/text/plugins/DoubleLink.tsx index e4bcb9bec2..5b819e4212 100644 --- a/libs/components/common/src/lib/text/plugins/DoubleLink.tsx +++ b/libs/components/common/src/lib/text/plugins/DoubleLink.tsx @@ -6,6 +6,7 @@ import { RenderElementProps } from 'slate-react'; export type DoubleLinkElement = { type: 'link'; + linkType: 'doubleLink'; workspaceId: string; blockId: string; children: Descendant[]; diff --git a/libs/components/editor-plugins/src/menu/double-link-menu/DoubleLinkMenu.tsx b/libs/components/editor-plugins/src/menu/double-link-menu/DoubleLinkMenu.tsx index a81e8b3122..3540ba0ba1 100644 --- a/libs/components/editor-plugins/src/menu/double-link-menu/DoubleLinkMenu.tsx +++ b/libs/components/editor-plugins/src/menu/double-link-menu/DoubleLinkMenu.tsx @@ -137,7 +137,8 @@ export const DoubleLinkMenu = ({ const resetState = useCallback( (preNodeId: string, nextNodeId: string) => { - editor.blockHelper.removeDoubleLinkSearchSlash(preNodeId); + preNodeId && + editor.blockHelper.removeDoubleLinkSearchSlash(preNodeId); setCurBlockId(nextNodeId); setSearchText(''); setIsOpen(true); @@ -206,7 +207,7 @@ export const DoubleLinkMenu = ({ } } }, - [editor, isOpen, curBlockId, hideMenu] + [editor, isOpen, curBlockId, hideMenu, resetState] ); const handleKeyup = useCallback( @@ -251,6 +252,20 @@ export const DoubleLinkMenu = ({ }; }, [handleKeyup, handleKeyDown, hooks]); + useEffect(() => { + const showDoubleLink = () => { + const { anchorNode } = editor.selection.currentSelectInfo; + editor.blockHelper.insertNodes(anchorNode.id, [{ text: '[[' }], { + select: true, + }); + setTimeout(() => { + resetState('', anchorNode.id); + }, 0); + }; + editor.plugins.observe('showDoubleLink', showDoubleLink); + return () => editor.plugins.unobserve('showDoubleLink', showDoubleLink); + }, [editor, resetState]); + const insertDoubleLink = useCallback( async (pageId: string) => { editor.blockHelper.setSelectDoubleLinkSearchSlash(curBlockId); @@ -328,46 +343,48 @@ export const DoubleLinkMenu = ({ ...doubleLinkMenuStyle, }} > - hideMenu()}> - - {({ TransitionProps }) => ( - - - {inAddNewPage && ( - - - - )} - - - - )} - - + {isOpen && ( + hideMenu()}> + + {({ TransitionProps }) => ( + + + {inAddNewPage && ( + + + + )} + + + + )} + + + )} ); }; diff --git a/libs/components/editor-plugins/src/menu/inline-menu/menu-item/IconItem.tsx b/libs/components/editor-plugins/src/menu/inline-menu/menu-item/IconItem.tsx index 5e97b4f746..6d6f6384bd 100644 --- a/libs/components/editor-plugins/src/menu/inline-menu/menu-item/IconItem.tsx +++ b/libs/components/editor-plugins/src/menu/inline-menu/menu-item/IconItem.tsx @@ -1,9 +1,9 @@ +import { Tooltip } from '@toeverything/components/ui'; import React, { useCallback } from 'react'; import style9 from 'style9'; - -import type { IconItemType, WithEditorSelectionType } from '../types'; import { inlineMenuNamesKeys, inlineMenuShortcuts } from '../config'; -import { Tooltip } from '@toeverything/components/ui'; +import type { IconItemType, WithEditorSelectionType } from '../types'; + type MenuIconItemProps = IconItemType & WithEditorSelectionType; export const MenuIconItem = ({ @@ -22,6 +22,7 @@ export const MenuIconItem = ({ editor, type: nameKey, anchorNodeId: selectionInfo?.anchorNode?.id, + setShow, }); } if ([inlineMenuNamesKeys.comment].includes(nameKey)) { diff --git a/libs/components/editor-plugins/src/menu/inline-menu/types.ts b/libs/components/editor-plugins/src/menu/inline-menu/types.ts index bdd7bee447..124c7a03ee 100644 --- a/libs/components/editor-plugins/src/menu/inline-menu/types.ts +++ b/libs/components/editor-plugins/src/menu/inline-menu/types.ts @@ -1,5 +1,5 @@ import type { SvgIconProps } from '@toeverything/components/ui'; -import type { Virgo, SelectionInfo } from '@toeverything/framework/virgo'; +import type { SelectionInfo, Virgo } from '@toeverything/framework/virgo'; import { inlineMenuNames, INLINE_MENU_UI_TYPES } from './config'; export type WithEditorSelectionType = { @@ -14,10 +14,12 @@ export type ClickItemHandler = ({ type, editor, anchorNodeId, + setShow, }: { type: InlineMenuNamesType; editor: Virgo; anchorNodeId: string; + setShow?: React.Dispatch>; }) => void; export type IconItemType = { diff --git a/libs/components/editor-plugins/src/menu/inline-menu/utils.ts b/libs/components/editor-plugins/src/menu/inline-menu/utils.ts index 78f03fbcf9..a6595b3bc9 100644 --- a/libs/components/editor-plugins/src/menu/inline-menu/utils.ts +++ b/libs/components/editor-plugins/src/menu/inline-menu/utils.ts @@ -107,6 +107,7 @@ const common_handler_for_inline_menu: ClickItemHandler = ({ editor, anchorNodeId, type, + setShow, }) => { switch (type) { case inlineMenuNamesKeys.text: @@ -438,6 +439,10 @@ const common_handler_for_inline_menu: ClickItemHandler = ({ blockType: Protocol.Block.Type.file, }); break; + case inlineMenuNamesKeys.backlinks: + editor.plugins.emit('showDoubleLink'); + setShow(false); + break; default: // do nothing } }; From 91694214607c532e0ea10a032c434d8dc5b15b61 Mon Sep 17 00:00:00 2001 From: xiaodong zuo Date: Wed, 24 Aug 2022 15:26:27 +0800 Subject: [PATCH 02/11] feat: Double-link: Search interaction --- .../pages/workspace/WorkspaceContainer.tsx | 6 +- .../common/src/lib/text/slate-utils.ts | 5 +- .../editor-core/src/editor/types.ts | 4 +- .../menu/double-link-menu/DoubleLinkMenu.tsx | 7 ++- .../editor-plugins/src/search/Search.tsx | 60 ++++++++++++------- .../editor-plugins/src/search/index.tsx | 47 +++++---------- .../layout/src/header/LayoutHeader.tsx | 16 +++-- 7 files changed, 77 insertions(+), 68 deletions(-) diff --git a/apps/ligo-virgo/src/pages/workspace/WorkspaceContainer.tsx b/apps/ligo-virgo/src/pages/workspace/WorkspaceContainer.tsx index 8e83c601a0..8d470671ef 100644 --- a/apps/ligo-virgo/src/pages/workspace/WorkspaceContainer.tsx +++ b/apps/ligo-virgo/src/pages/workspace/WorkspaceContainer.tsx @@ -1,7 +1,5 @@ -import { Route, Routes, useParams } from 'react-router'; - import { useUserAndSpaces } from '@toeverything/datasource/state'; - +import { Route, Routes, useParams } from 'react-router'; import { WorkspaceRootContainer } from './Container'; import { Page } from './docs'; import { Edgeless } from './Edgeless'; @@ -10,7 +8,7 @@ import Labels from './labels'; import Pages from './pages'; export function WorkspaceContainer() { - const { workspace_id } = useParams(); + const { workspace_id, page_id } = useParams(); const { user, currentSpaceId } = useUserAndSpaces(); if ( diff --git a/libs/components/common/src/lib/text/slate-utils.ts b/libs/components/common/src/lib/text/slate-utils.ts index fd1de5f674..29639c3e05 100644 --- a/libs/components/common/src/lib/text/slate-utils.ts +++ b/libs/components/common/src/lib/text/slate-utils.ts @@ -713,7 +713,10 @@ class SlateUtils { if (!this.editor) { return undefined; } - const { selectionEnd } = this.getSelectionStartAndEnd(); + const selectionEnd = this.getSelectionStartAndEnd()?.selectionEnd; + if (!selectionEnd) { + return undefined; + } return this.getStringBetween(this.getStart(), selectionEnd); } diff --git a/libs/components/editor-core/src/editor/types.ts b/libs/components/editor-core/src/editor/types.ts index 1b97cf0f86..25c37b5172 100644 --- a/libs/components/editor-core/src/editor/types.ts +++ b/libs/components/editor-core/src/editor/types.ts @@ -10,8 +10,6 @@ */ import type { PatchNode } from '@toeverything/components/ui'; import type { BlockFlavors } from '@toeverything/datasource/db-service'; -import type { IdList, SelectionInfo, SelectionManager } from './selection'; - import { Point } from '@toeverything/utils'; import { Observable } from 'rxjs'; import type { AsyncBlock } from './block'; @@ -20,6 +18,7 @@ import type { BlockCommands } from './commands/block-commands'; import type { DragDropManager } from './drag-drop'; import { MouseManager } from './mouse'; import { ScrollManager } from './scroll'; +import type { IdList, SelectionInfo, SelectionManager } from './selection'; // import { BrowserClipboard } from './clipboard/browser-clipboard'; @@ -109,6 +108,7 @@ export interface Virgo { getGroupBlockByPoint: (point: Point) => Promise; isEdgeless: boolean; mouseManager: MouseManager; + getHooks: () => HooksRunner & PluginHooks; } export interface Plugin { diff --git a/libs/components/editor-plugins/src/menu/double-link-menu/DoubleLinkMenu.tsx b/libs/components/editor-plugins/src/menu/double-link-menu/DoubleLinkMenu.tsx index 3540ba0ba1..4650a07c70 100644 --- a/libs/components/editor-plugins/src/menu/double-link-menu/DoubleLinkMenu.tsx +++ b/libs/components/editor-plugins/src/menu/double-link-menu/DoubleLinkMenu.tsx @@ -192,9 +192,10 @@ export const DoubleLinkMenu = ({ anchorNode.id !== curBlockId && editor.blockHelper.isSelectionCollapsed(anchorNode.id)) ) { - const text = editor.blockHelper.getBlockTextBeforeSelection( - anchorNode.id - ); + const text = + editor.blockHelper.getBlockTextBeforeSelection( + anchorNode.id + ) || ''; if (text.endsWith('[[')) { resetState(curBlockId, anchorNode.id); } diff --git a/libs/components/editor-plugins/src/search/Search.tsx b/libs/components/editor-plugins/src/search/Search.tsx index b689345f64..23a3f46c2c 100644 --- a/libs/components/editor-plugins/src/search/Search.tsx +++ b/libs/components/editor-plugins/src/search/Search.tsx @@ -5,7 +5,12 @@ import { styled, TransitionsModal, } from '@toeverything/components/ui'; -import { BlockEditor, Virgo } from '@toeverything/framework/virgo'; +import { + BlockEditor, + HookType, + PluginHooks, + Virgo, +} from '@toeverything/framework/virgo'; import { throttle } from '@toeverything/utils'; import { useCallback, useEffect, useState } from 'react'; import { useNavigate, useParams } from 'react-router'; @@ -31,7 +36,7 @@ const styles = style9.create({ export type QueryResult = Awaited>; -const query_blocks = ( +const queryBlocksExec = ( editor: Virgo, search: string, callback: (result: QueryResult) => void @@ -39,45 +44,58 @@ const query_blocks = ( (editor as BlockEditor).search(search).then(pages => callback(pages)); }; -export const QueryBlocks = throttle(query_blocks, 500); +export const QueryBlocks = throttle(queryBlocksExec, 500); type SearchProps = { - onClose: () => void; editor: Virgo; + hooks: PluginHooks; }; export const Search = (props: SearchProps) => { - const { workspace_id } = useParams(); + const { workspace_id: workspaceId } = useParams(); const navigate = useNavigate(); - const [open, set_open] = useState(true); - const [search, set_search] = useState(''); - const [result, set_result] = useState([]); + const [open, setOpen] = useState(false); + const [search, setSearch] = useState(); + const [result, setResult] = useState([]); useEffect(() => { - QueryBlocks(props.editor, search, result => { - set_result(result); - }); + search !== undefined && + QueryBlocks(props.editor, search, result => { + setResult(result); + }); }, [props.editor, search]); - const handle_navigate = useCallback( - (id: string) => navigate(`/${workspace_id}/${id}`), - [navigate, workspace_id] + const handleNavigate = useCallback( + (id: string) => navigate(`/${workspaceId}/${id}`), + [navigate, workspaceId] ); + const handleSearch = useCallback(() => { + setOpen(true); + setSearch(''); + }, []); + + useEffect(() => { + const sub = props.hooks.get(HookType.ON_SEARCH).subscribe(handleSearch); + + return () => { + sub.unsubscribe(); + }; + }, [props, handleSearch]); + return ( { - set_open(false); - props.onClose(); + setOpen(false); }} > set_search(e.target.value)} + onChange={e => setSearch(e.target.value)} /> { { - handle_navigate(block.id); - props.onClose(); + handleNavigate(block.id); }} /> ))} diff --git a/libs/components/editor-plugins/src/search/index.tsx b/libs/components/editor-plugins/src/search/index.tsx index 41a13695c4..b74e3572a8 100644 --- a/libs/components/editor-plugins/src/search/index.tsx +++ b/libs/components/editor-plugins/src/search/index.tsx @@ -1,59 +1,40 @@ import { StrictMode } from 'react'; - -import { HookType } from '@toeverything/framework/virgo'; - import { BasePlugin } from '../base-plugin'; import { PluginRenderRoot } from '../utils'; import { Search } from './Search'; export class FullTextSearchPlugin extends BasePlugin { - #root?: PluginRenderRoot; + private root?: PluginRenderRoot; public static override get pluginName(): string { return 'search'; } - public override init(): void { - this.sub.add( - this.hooks.get(HookType.ON_SEARCH).subscribe(this._handleSearch) - ); - } - protected override _onRender(): void { - this.#root = new PluginRenderRoot({ + this.root = new PluginRenderRoot({ name: FullTextSearchPlugin.pluginName, render: this.editor.reactRenderRoot.render, }); + this._renderSearch(); } - private unmount() { - if (this.#root) { - this.editor.setHotKeysScope(); - this.#root.unmount(); - // this.#root = undefined; - } - this.sub.unsubscribe(); - } - - private _handleSearch = () => { - this.editor.setHotKeysScope('search'); - this.render_search(); - }; - private render_search() { - if (this.#root) { - this.#root.mount(); - this.#root.render( + private _renderSearch() { + if (this.root) { + this.root.mount(); + this.root.render( - this.unmount()} - editor={this.editor} - /> + ); } } public renderSearch() { - this.render_search(); + this._renderSearch(); + } + + public override dispose() { + this.root?.unmount(); + super.dispose(); } } diff --git a/libs/components/layout/src/header/LayoutHeader.tsx b/libs/components/layout/src/header/LayoutHeader.tsx index 2d6913ac60..efef6116b1 100644 --- a/libs/components/layout/src/header/LayoutHeader.tsx +++ b/libs/components/layout/src/header/LayoutHeader.tsx @@ -1,5 +1,3 @@ -import { useMemo } from 'react'; - import { LogoIcon, SearchIcon, @@ -8,10 +6,11 @@ import { } from '@toeverything/components/icons'; import { IconButton, styled } from '@toeverything/components/ui'; import { + useCurrentEditors, useLocalTrigger, useShowSettingsSidebar, } from '@toeverything/datasource/state'; - +import { useCallback, useMemo } from 'react'; import { EditorBoardSwitcher } from './EditorBoardSwitcher'; import { FileSystem, fsApiSupported } from './FileSystem'; import { CurrentPageTitle } from './Title'; @@ -31,6 +30,14 @@ export const LayoutHeader = () => { } }, [isLocalWorkspace]); + const { currentEditors } = useCurrentEditors(); + + const handleSearch = useCallback(() => { + for (const key in currentEditors || {}) { + currentEditors[key].getHooks().onSearch(); + } + }, [currentEditors]); + return ( @@ -48,8 +55,7 @@ export const LayoutHeader = () => { From 6d770dbfa67b4a0a81a1554ad1edf7c28b527b45 Mon Sep 17 00:00:00 2001 From: xiaodong zuo Date: Fri, 26 Aug 2022 09:13:19 +0800 Subject: [PATCH 03/11] feat: Double-link: In-line cursor handling, e.g., up, down, left,right, backspace keys --- .../common/src/lib/text/EditableText.tsx | 19 +++++- .../common/src/lib/text/slate-utils.ts | 13 +++- .../src/components/text-manage/TextManage.tsx | 59 ++++++++++++++++++- 3 files changed, 86 insertions(+), 5 deletions(-) diff --git a/libs/components/common/src/lib/text/EditableText.tsx b/libs/components/common/src/lib/text/EditableText.tsx index 8637246d7d..3722b90c3b 100644 --- a/libs/components/common/src/lib/text/EditableText.tsx +++ b/libs/components/common/src/lib/text/EditableText.tsx @@ -41,7 +41,12 @@ import { InlineDate, withDate } from './plugins/date'; import { DoubleLinkComponent } from './plugins/DoubleLink'; import { LinkComponent, LinkModal, withLinks, wrapLink } from './plugins/link'; import { InlineRefLink } from './plugins/reflink'; -import { Contents, isSelectAll, SlateUtils } from './slate-utils'; +import { + Contents, + isSelectAll, + SelectionStartAndEnd, + SlateUtils, +} from './slate-utils'; import { getCommentsIdsOnTextNode, getExtraPropertiesFromEditorOutmostNode, @@ -88,8 +93,12 @@ export interface TextProps { /** Backspace event */ handleBackSpace?: ({ isCollAndStart, + splitContents, + selection, }: { isCollAndStart: boolean; + splitContents: Contents; + selection: SelectionStartAndEnd; }) => boolean | undefined | Promise; /** Whether markdown is supported */ supportMarkdown?: boolean; @@ -464,7 +473,13 @@ export const Text = forwardRef((props, ref) => { if (!isCool) { hideInlineMenu && hideInlineMenu(); } - preventBindIfNeeded(handleBackSpace)(e, { isCollAndStart }); + const selection = utils.current.getSelectionStartAndEnd(); + const splitContents = utils.current.getSplitContentsBySelection(); + preventBindIfNeeded(handleBackSpace)(e, { + isCollAndStart, + selection, + splitContents, + }); }; const onTab = (e: KeyboardEvent) => { diff --git a/libs/components/common/src/lib/text/slate-utils.ts b/libs/components/common/src/lib/text/slate-utils.ts index 29639c3e05..cbe9a24ed3 100644 --- a/libs/components/common/src/lib/text/slate-utils.ts +++ b/libs/components/common/src/lib/text/slate-utils.ts @@ -503,7 +503,7 @@ Editor.after = function ( return target; }; -type SelectionStartAndEnd = { +export type SelectionStartAndEnd = { selectionStart: Point; selectionEnd: Point; }; @@ -517,6 +517,10 @@ export type Contents = { content: Descendant[]; isEmpty: boolean; }; + contentSelection: { + content: Descendant[]; + isEmpty: boolean; + }; }; class SlateUtils { @@ -572,6 +576,7 @@ class SlateUtils { anchor: point1, focus: point2, }); + if (!fragment.length) { console.error('Debug information:', point1, point2, fragment); throw new Error('Failed to get content between!'); @@ -602,7 +607,7 @@ class SlateUtils { for (let i = 0; i < fragmentChildren.length; i++) { const child = fragmentChildren[i]; if ('type' in child && child.type === 'link') { - i !== fragmentChildren.length - 1 && textChildren.push(child); + textChildren.push(child); continue; } if (!('text' in child)) { @@ -638,6 +643,10 @@ class SlateUtils { content: this.getContentBetween(selectionEnd, end), isEmpty: Point.equals(end, selectionEnd), }, + contentSelection: { + content: this.getContentBetween(selectionStart, selectionEnd), + isEmpty: false, + }, } as Contents; } diff --git a/libs/components/editor-blocks/src/components/text-manage/TextManage.tsx b/libs/components/editor-blocks/src/components/text-manage/TextManage.tsx index e42a85c5ed..fa15639172 100644 --- a/libs/components/editor-blocks/src/components/text-manage/TextManage.tsx +++ b/libs/components/editor-blocks/src/components/text-manage/TextManage.tsx @@ -1,5 +1,6 @@ /* eslint-disable max-lines */ import { + CustomText, Text, type SlateUtils, type TextProps, @@ -108,7 +109,7 @@ const findLowestCommonAncestor = async ( export const TextManage = forwardRef( (props, ref) => { - const { block, editor, ...otherOptions } = props; + const { block, editor, handleBackSpace, ...otherOptions } = props; const defaultRef = useRef(null); // Maybe there is a better way const textRef = @@ -446,6 +447,61 @@ export const TextManage = forwardRef( } } }; + + const onBackspace: TextProps['handleBackSpace'] = async props => { + const { isCollAndStart, splitContents, selection } = props; + if (!isCollAndStart) { + const { + contentBeforeSelection, + contentAfterSelection, + contentSelection, + } = splitContents; + const { selectionStart, selectionEnd } = selection; + let hasDeleteDoubleLink = false; + + const beforeContent = [...contentBeforeSelection.content]; + const lastItem = beforeContent[beforeContent.length - 1]; + if ( + 'linkType' in lastItem && + lastItem.linkType === 'doubleLink' + ) { + if ( + selectionStart === selectionEnd || + selectionStart.offset + ) { + beforeContent.splice(beforeContent.length - 1, 1); + hasDeleteDoubleLink = true; + } + } + + const afterContent = [...contentAfterSelection.content]; + const beginItem = afterContent[0]; + const lastSel = contentSelection.content[0]; + if ( + selectionEnd.offset && + 'linkType' in beginItem && + beginItem.linkType === 'doubleLink' && + 'linkType' in lastSel && + lastSel.linkType === 'doubleLink' + ) { + afterContent.splice(0, 1); + hasDeleteDoubleLink = true; + } + + if (hasDeleteDoubleLink) { + await block.setProperty('text', { + value: [ + ...beforeContent, + ...afterContent, + ] as CustomText[], + }); + return true; + } + } + + return (handleBackSpace && handleBackSpace(props)) || false; + }; + if (!properties || !properties.text) { return <>; } @@ -467,6 +523,7 @@ export const TextManage = forwardRef( handleUndo={onUndo} handleRedo={onRedo} handleEsc={onKeyboardEsc} + handleBackSpace={onBackspace} {...otherOptions} /> ); From 73d6e34c5dead3d3439dc23836f1c7e091593143 Mon Sep 17 00:00:00 2001 From: xiaodong zuo Date: Mon, 29 Aug 2022 18:10:26 +0800 Subject: [PATCH 04/11] feat: Double-link: In-line cursor handling, e.g., up, down, left,right, backspace keys --- .../src/lib/text/plugins/DoubleLink.tsx | 21 +++-- .../common/src/lib/text/plugins/link.tsx | 65 ++++++++-------- .../common/src/lib/text/slate-utils.ts | 10 +-- .../src/components/text-manage/TextManage.tsx | 76 +++++++------------ .../editor-core/src/editor/views/base-view.ts | 9 ++- 5 files changed, 85 insertions(+), 96 deletions(-) diff --git a/libs/components/common/src/lib/text/plugins/DoubleLink.tsx b/libs/components/common/src/lib/text/plugins/DoubleLink.tsx index 5b819e4212..42f50740f3 100644 --- a/libs/components/common/src/lib/text/plugins/DoubleLink.tsx +++ b/libs/components/common/src/lib/text/plugins/DoubleLink.tsx @@ -26,15 +26,20 @@ export const DoubleLinkComponent = (props: RenderElementProps) => { [doubleLinkElement, navigate] ); + const displayValue = doubleLinkElement.children + .map((item: any) => item.text) + .join(''); + return ( - - - - {children} + + + + + {children} + {displayValue} + ); diff --git a/libs/components/common/src/lib/text/plugins/link.tsx b/libs/components/common/src/lib/text/plugins/link.tsx index 619239c64d..971d8dc62b 100644 --- a/libs/components/common/src/lib/text/plugins/link.tsx +++ b/libs/components/common/src/lib/text/plugins/link.tsx @@ -1,44 +1,42 @@ -import React, { - useEffect, - useMemo, - useRef, - useState, - useCallback, - KeyboardEvent, - MouseEvent, - memo, -} from 'react'; -import { createPortal } from 'react-dom'; -import { useNavigate } from 'react-router-dom'; - -import isUrl from 'is-url'; -import style9 from 'style9'; -import { - Editor, - Transforms, - Element as SlateElement, - Descendant, - Range as SlateRange, - Node, -} from 'slate'; -import { ReactEditor } from 'slate-react'; -import OpenInNewIcon from '@mui/icons-material/OpenInNew'; import EditIcon from '@mui/icons-material/Edit'; import LinkOffIcon from '@mui/icons-material/LinkOff'; +import OpenInNewIcon from '@mui/icons-material/OpenInNew'; +import { LinkIcon } from '@toeverything/components/icons'; import { MuiTooltip as Tooltip, - styled, muiTooltipClasses, + styled, type MuiTooltipProps, } from '@toeverything/components/ui'; import { getRelativeUrlForInternalPageUrl, isInternalPageUrl, } from '@toeverything/utils'; - +import isUrl from 'is-url'; +import React, { + KeyboardEvent, + memo, + MouseEvent, + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from 'react'; +import { createPortal } from 'react-dom'; +import { useNavigate } from 'react-router-dom'; +import { + Descendant, + Editor, + Element as SlateElement, + Node, + Range as SlateRange, + Transforms, +} from 'slate'; +import { ReactEditor } from 'slate-react'; +import style9 from 'style9'; import { getRandomString } from '../utils'; -import { colors } from '../../colors'; -import { LinkIcon } from '@toeverything/components/icons'; + export type LinkElement = { type: 'link'; url: string; @@ -47,13 +45,20 @@ export type LinkElement = { }; export const withLinks = (editor: ReactEditor) => { - const { isInline } = editor; + const { isInline, isVoid } = editor; editor.isInline = element => { // @ts-ignore return element.type === 'link' ? true : isInline(element); }; + editor.isVoid = element => { + // @ts-ignore + return element.type === 'link' && element.linkType === 'doubleLink' + ? true + : isVoid(element); + }; + return editor; }; diff --git a/libs/components/common/src/lib/text/slate-utils.ts b/libs/components/common/src/lib/text/slate-utils.ts index cbe9a24ed3..03701d0646 100644 --- a/libs/components/common/src/lib/text/slate-utils.ts +++ b/libs/components/common/src/lib/text/slate-utils.ts @@ -405,11 +405,11 @@ Editor.before = function ( if (element) { if (isInlineAndVoid(editor, element)) { // Inline entities need to be drilled out - // target = Editor.before(editor, target); - target = { - path: [0, path[1] - 1], - offset: 0, - }; + target = Editor.before(editor, target); + // target = { + // path: [0, path[1] - 1], + // offset: 0, + // }; } else if (editor.isInline(element) && !editor.isVoid(element)) { // Inline styles such as hyperlinks need to drill directly into it const inlineTextLength = element?.children?.[0]?.text?.length; diff --git a/libs/components/editor-blocks/src/components/text-manage/TextManage.tsx b/libs/components/editor-blocks/src/components/text-manage/TextManage.tsx index fa15639172..72faaef8a7 100644 --- a/libs/components/editor-blocks/src/components/text-manage/TextManage.tsx +++ b/libs/components/editor-blocks/src/components/text-manage/TextManage.tsx @@ -1,6 +1,5 @@ /* eslint-disable max-lines */ import { - CustomText, Text, type SlateUtils, type TextProps, @@ -109,7 +108,7 @@ const findLowestCommonAncestor = async ( export const TextManage = forwardRef( (props, ref) => { - const { block, editor, handleBackSpace, ...otherOptions } = props; + const { block, editor, handleEnter, ...otherOptions } = props; const defaultRef = useRef(null); // Maybe there is a better way const textRef = @@ -448,58 +447,35 @@ export const TextManage = forwardRef( } }; - const onBackspace: TextProps['handleBackSpace'] = async props => { - const { isCollAndStart, splitContents, selection } = props; - if (!isCollAndStart) { - const { - contentBeforeSelection, - contentAfterSelection, - contentSelection, - } = splitContents; - const { selectionStart, selectionEnd } = selection; - let hasDeleteDoubleLink = false; - - const beforeContent = [...contentBeforeSelection.content]; - const lastItem = beforeContent[beforeContent.length - 1]; - if ( - 'linkType' in lastItem && - lastItem.linkType === 'doubleLink' - ) { - if ( - selectionStart === selectionEnd || - selectionStart.offset - ) { - beforeContent.splice(beforeContent.length - 1, 1); - hasDeleteDoubleLink = true; + const onTextEnter: TextProps['handleEnter'] = async props => { + const { splitContents } = props; + if (splitContents) { + const { contentBeforeSelection, contentAfterSelection } = + splitContents; + // after[after.length - 1]; + if (!contentBeforeSelection.isEmpty) { + const beforeSelection = contentBeforeSelection.content; + const lastItem: any = + beforeSelection.length > 0 + ? beforeSelection[beforeSelection.length - 1] + : null; + if (lastItem?.linkType === 'doubleLink') { + contentBeforeSelection.content.push({ text: '' }); } } - - const afterContent = [...contentAfterSelection.content]; - const beginItem = afterContent[0]; - const lastSel = contentSelection.content[0]; - if ( - selectionEnd.offset && - 'linkType' in beginItem && - beginItem.linkType === 'doubleLink' && - 'linkType' in lastSel && - lastSel.linkType === 'doubleLink' - ) { - afterContent.splice(0, 1); - hasDeleteDoubleLink = true; - } - - if (hasDeleteDoubleLink) { - await block.setProperty('text', { - value: [ - ...beforeContent, - ...afterContent, - ] as CustomText[], - }); - return true; + if (!contentAfterSelection.isEmpty) { + const afterSelection = contentAfterSelection.content; + const firstItem: any = + afterSelection.length > 0 ? afterSelection[0] : null; + if (firstItem?.linkType === 'doubleLink') { + contentAfterSelection.content.splice(0, 0, { + text: '', + }); + } } } - return (handleBackSpace && handleBackSpace(props)) || false; + return handleEnter && handleEnter(props); }; if (!properties || !properties.text) { @@ -523,7 +499,7 @@ export const TextManage = forwardRef( handleUndo={onUndo} handleRedo={onRedo} handleEsc={onKeyboardEsc} - handleBackSpace={onBackspace} + handleEnter={onTextEnter} {...otherOptions} /> ); diff --git a/libs/components/editor-core/src/editor/views/base-view.ts b/libs/components/editor-core/src/editor/views/base-view.ts index 2b3002f500..df110cf87c 100644 --- a/libs/components/editor-core/src/editor/views/base-view.ts +++ b/libs/components/editor-core/src/editor/views/base-view.ts @@ -1,5 +1,3 @@ -import { ComponentType, ReactElement } from 'react'; - import type { Column, DefaultColumnsValue, @@ -10,6 +8,7 @@ import { MapOperation, } from '@toeverything/datasource/jwt'; import { cloneDeep } from '@toeverything/utils'; +import { ComponentType, ReactElement } from 'react'; import type { EventData } from '../block'; import { AsyncBlock } from '../block'; import type { Editor } from '../editor'; @@ -113,7 +112,11 @@ export abstract class BaseView { // Whether the component is empty isEmpty(block: AsyncBlock): boolean { const text = block.getProperty('text'); - const result = !text?.value?.[0]?.text; + // const result = !text?.value?.[0]?.text; + const result = + text?.value?.findIndex( + (item: any) => item.text || item.children?.length + ) === -1; // Assert that the text is really empty if ( From e18a35989f0307e04a1ea735043331679f2dd832 Mon Sep 17 00:00:00 2001 From: xiaodong zuo Date: Thu, 1 Sep 2022 10:44:21 +0800 Subject: [PATCH 05/11] feat: Link feature add search function --- libs/components/common/src/lib/index.ts | 1 + .../common/src/lib/text/slate-utils.ts | 52 ++++ .../src/editor/block/block-helper.ts | 13 +- libs/components/editor-plugins/src/index.ts | 3 +- .../editor-plugins/src/menu/index.ts | 1 + .../src/menu/inline-menu/utils.ts | 2 + .../src/menu/link-menu/LinkMenu.tsx | 263 ++++++++++++++++++ .../src/menu/link-menu/Plugin.tsx | 33 +++ .../src/menu/link-menu/index.ts | 1 + 9 files changed, 367 insertions(+), 2 deletions(-) create mode 100644 libs/components/editor-plugins/src/menu/link-menu/LinkMenu.tsx create mode 100644 libs/components/editor-plugins/src/menu/link-menu/Plugin.tsx create mode 100644 libs/components/editor-plugins/src/menu/link-menu/index.ts diff --git a/libs/components/common/src/lib/index.ts b/libs/components/common/src/lib/index.ts index f42927223e..cc94e2a4b4 100644 --- a/libs/components/common/src/lib/index.ts +++ b/libs/components/common/src/lib/index.ts @@ -19,6 +19,7 @@ declare module 'slate' { } } +export { default as isUrl } from 'is-url'; export { BlockPreview, StyledBlockPreview } from './block-preview'; export { default as Button } from './button'; export { CollapsibleTitle } from './collapsible-title'; diff --git a/libs/components/common/src/lib/text/slate-utils.ts b/libs/components/common/src/lib/text/slate-utils.ts index 03701d0646..1dc10e8042 100644 --- a/libs/components/common/src/lib/text/slate-utils.ts +++ b/libs/components/common/src/lib/text/slate-utils.ts @@ -2,6 +2,7 @@ import { Descendant, Editor, + Element as SlateElement, Location, Node as SlateNode, Path, @@ -1230,6 +1231,57 @@ class SlateUtils { }); } + public wrapLink(url: string, preSelection?: Location) { + if (!ReactEditor.isFocused(this.editor) && preSelection) { + Transforms.select(this.editor, preSelection); + } + if (this.isLinkActive()) { + this.unwrapLink(); + } + const { selection } = this.editor; + const isCollapsed = selection && this.isCollapsed(); + const link = { + type: 'link', + url: url, + children: isCollapsed ? [{ text: url }] : [], + id: getRandomString('link'), + }; + + if (isCollapsed) { + Transforms.insertNodes(this.editor, link); + } else { + Transforms.wrapNodes(this.editor, link, { split: true }); + Transforms.collapse(this.editor, { edge: 'end' }); + } + requestAnimationFrame(() => { + ReactEditor.focus(this.editor); + }); + } + + public isLinkActive() { + const [link] = Editor.nodes(this.editor, { + match: n => + !Editor.isEditor(n) && + SlateElement.isElement(n) && + // @ts-expect-error + n.type === 'link', + }); + return !!link; + } + + public unwrapLink() { + Transforms.unwrapNodes(this.editor, { + match: n => { + return ( + !Editor.isEditor(n) && + SlateElement.isElement(n) && + // @ts-expect-error + n.type === 'link' + ); + }, + }); + } + /** todo improve if selection is collapsed */ public getCommentsIdsBySelection() { const commentedTextNodes = Editor.nodes(this.editor, { diff --git a/libs/components/editor-core/src/editor/block/block-helper.ts b/libs/components/editor-core/src/editor/block/block-helper.ts index 012633b813..032f496050 100644 --- a/libs/components/editor-core/src/editor/block/block-helper.ts +++ b/libs/components/editor-core/src/editor/block/block-helper.ts @@ -5,6 +5,7 @@ import type { } from '@toeverything/components/common'; import { BaseRange, + Location, Node, Path, Point, @@ -41,7 +42,8 @@ type TextUtilsFunctions = | 'blur' | 'setSelection' | 'insertNodes' - | 'getNodeByPath'; + | 'getNodeByPath' + | 'wrapLink'; type ExtendedTextUtils = SlateUtils & { setLinkModalVisible: (visible: boolean) => void; @@ -412,4 +414,13 @@ export class BlockHelper { console.warn('Could find the block text utils'); return undefined; } + + public wrapLink(blockId: string, url: string, preSelection?: Location) { + const text_utils = this._blockTextUtilsMap[blockId]; + if (text_utils) { + return text_utils.wrapLink(url, preSelection); + } + console.warn('Could find the block text utils'); + return undefined; + } } diff --git a/libs/components/editor-plugins/src/index.ts b/libs/components/editor-plugins/src/index.ts index 4c6ce9a1e1..568031f5a3 100644 --- a/libs/components/editor-plugins/src/index.ts +++ b/libs/components/editor-plugins/src/index.ts @@ -6,7 +6,7 @@ import { GroupMenuPlugin, InlineMenuPlugin, LeftMenuPlugin, - SelectionGroupPlugin, + LinkMenuPlugin, } from './menu'; import { FullTextSearchPlugin } from './search'; import { TemplatePlugin } from './template'; @@ -24,4 +24,5 @@ export const plugins: PluginCreator[] = [ // SelectionGroupPlugin, AddCommentPlugin, GroupMenuPlugin, + LinkMenuPlugin, ]; diff --git a/libs/components/editor-plugins/src/menu/index.ts b/libs/components/editor-plugins/src/menu/index.ts index 190e3a5109..5c67719c87 100644 --- a/libs/components/editor-plugins/src/menu/index.ts +++ b/libs/components/editor-plugins/src/menu/index.ts @@ -4,4 +4,5 @@ export { GroupMenuPlugin } from './group-menu'; export { InlineMenuPlugin } from './inline-menu'; export { LeftMenuPlugin } from './left-menu/LeftMenuPlugin'; export { MENU_WIDTH as menuWidth } from './left-menu/menu-config'; +export { LinkMenuPlugin } from './link-menu'; export { SelectionGroupPlugin } from './selection-group-menu'; diff --git a/libs/components/editor-plugins/src/menu/inline-menu/utils.ts b/libs/components/editor-plugins/src/menu/inline-menu/utils.ts index a6595b3bc9..a086905da5 100644 --- a/libs/components/editor-plugins/src/menu/inline-menu/utils.ts +++ b/libs/components/editor-plugins/src/menu/inline-menu/utils.ts @@ -185,6 +185,8 @@ const common_handler_for_inline_menu: ClickItemHandler = ({ editor, blockId: anchorNodeId, }); + editor.plugins.emit('showAddLink'); + setShow(false); break; case inlineMenuNamesKeys.code: toggle_text_format({ diff --git a/libs/components/editor-plugins/src/menu/link-menu/LinkMenu.tsx b/libs/components/editor-plugins/src/menu/link-menu/LinkMenu.tsx new file mode 100644 index 0000000000..f2d2af19fe --- /dev/null +++ b/libs/components/editor-plugins/src/menu/link-menu/LinkMenu.tsx @@ -0,0 +1,263 @@ +import { CommonListItem, isUrl } from '@toeverything/components/common'; +import { LinkIcon } from '@toeverything/components/icons'; +import { + ListButton, + MuiClickAwayListener, + MuiGrow as Grow, + MuiPaper as Paper, + MuiPopper as Popper, + styled, +} from '@toeverything/components/ui'; +import { PluginHooks, Virgo } from '@toeverything/framework/virgo'; +import { + ChangeEvent, + KeyboardEvent, + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from 'react'; +import { useParams } from 'react-router-dom'; +import { QueryBlocks, QueryResult } from '../../search'; +import { DoubleLinkMenuContainer } from '../double-link-menu/Container'; + +const ADD_NEW_SUB_PAGE = 'AddNewSubPage'; +const ADD_NEW_PAGE = 'AddNewPage'; + +export type LinkMenuProps = { + editor: Virgo; + hooks: PluginHooks; +}; + +type LinkMenuStyle = { + left: number; + top: number; + height: number; +}; + +const normalizeUrl = (url: string) => { + // eslint-disable-next-line no-restricted-globals + return /^https?/.test(url) ? url : `${location.protocol}//${url}`; +}; + +export const LinkMenu = ({ editor, hooks }: LinkMenuProps) => { + const { page_id: curPageId } = useParams(); + const [isOpen, setIsOpen] = useState(false); + const [anchorEl, setAnchorEl] = useState(null); + const dialogRef = useRef(); + const inputEl = useRef(); + const [linkMenuStyle, setLinkMenuStyle] = useState({ + left: 0, + top: 0, + height: 0, + }); + const url = ''; + + const [curBlockId, setCurBlockId] = useState(); + const [searchText, setSearchText] = useState(); + const [searchResultBlocks, setSearchResultBlocks] = useState( + [] + ); + + const menuTypes = useMemo(() => { + return Object.values(searchResultBlocks) + .map(({ id }) => id) + .concat([ADD_NEW_SUB_PAGE, ADD_NEW_PAGE]); + }, [searchResultBlocks]); + + const menuItems: CommonListItem[] = useMemo(() => { + const items: CommonListItem[] = []; + if (searchResultBlocks?.length > 0) { + items.push({ + renderCustom: () => { + return ; + }, + }); + items.push( + ...(searchResultBlocks?.map( + block => + ({ + block: { + ...block, + content: block.content || 'Untitled', + }, + } as CommonListItem) + ) || []) + ); + } + return items; + }, [searchResultBlocks]); + + useEffect(() => { + const text = searchText; + QueryBlocks(editor, text, result => { + result = result.filter(item => item.id !== curPageId); + setSearchResultBlocks(result); + }); + }, [editor, searchText, curPageId]); + + const hideMenu = useCallback(() => { + setIsOpen(false); + editor.blockHelper.removeDoubleLinkSearchSlash(curBlockId); + editor.scrollManager.unLock(); + }, [curBlockId, editor]); + + const resetState = useCallback( + (preNodeId: string, nextNodeId: string) => { + setCurBlockId(nextNodeId); + setSearchText(''); + setIsOpen(true); + editor.scrollManager.lock(); + const clientRect = + editor.selection.currentSelectInfo?.browserSelection + ?.getRangeAt(0) + ?.getBoundingClientRect(); + if (clientRect) { + const rectTop = clientRect.top; + const { top, left } = editor.container.getBoundingClientRect(); + setLinkMenuStyle({ + top: rectTop - top, + left: clientRect.left - left, + height: clientRect.height, + }); + setAnchorEl(dialogRef.current); + } + }, + [editor] + ); + + useEffect(() => { + const showDoubleLink = () => { + const { anchorNode } = editor.selection.currentSelectInfo; + resetState('', anchorNode.id); + }; + editor.plugins.observe('showAddLink', showDoubleLink); + return () => editor.plugins.unobserve('showAddLink', showDoubleLink); + }, [editor, resetState]); + + const handleSelected = async (id: string) => { + if (curBlockId) { + } + }; + + const handleFilterChange = useCallback( + async (e: ChangeEvent) => { + const text = e.target.value; + + await setSearchText(text); + }, + [] + ); + + const addLinkUrlToText = () => { + const newUrl = inputEl.current.value; + if (newUrl && newUrl !== url && isUrl(normalizeUrl(newUrl))) { + editor.blockHelper.wrapLink(curBlockId, newUrl); + hideMenu(); + return; + } + }; + + const handleKeyDown = (e: KeyboardEvent) => { + if (e.key === 'Enter') { + addLinkUrlToText(); + } + if (e.key === 'Escape') { + hideMenu(); + } + }; + + return ( +
+ {isOpen && ( + hideMenu()}> + + {({ TransitionProps }) => ( + + + + + + + + + + {menuItems.length > 0 && ( + + )} + + + )} + + + )} +
+ ); +}; + +const LinkModalContainer = styled('div')(({ theme }) => ({ + display: 'flex', + borderRadius: '4px', + boxShadow: theme.affine.shadows.shadow1, + backgroundColor: '#fff', + alignItems: 'center', + zIndex: '1', + width: '354px', +})); + +const LinkModalContainerIcon = styled('div')(({ theme }) => ({ + display: 'flex', + width: '16px', + margin: '0 16px 0 4px', + color: '#4C6275', +})); + +const LinkModalContainerInput = styled('input')(({ theme }) => ({ + flex: '1', + outline: 'none', + border: 'none', + padding: '8px', + fontFamily: 'Helvetica,Arial,"Microsoft Yahei",SimHei,sans-serif', + '::-webkit-input-placeholder': { + color: '#98acbd', + }, + color: '#4C6275', +})); diff --git a/libs/components/editor-plugins/src/menu/link-menu/Plugin.tsx b/libs/components/editor-plugins/src/menu/link-menu/Plugin.tsx new file mode 100644 index 0000000000..e0f7140985 --- /dev/null +++ b/libs/components/editor-plugins/src/menu/link-menu/Plugin.tsx @@ -0,0 +1,33 @@ +import { StrictMode } from 'react'; +import { BasePlugin } from '../../base-plugin'; +import { PluginRenderRoot } from '../../utils'; +import { LinkMenu } from './LinkMenu'; + +const PLUGIN_NAME = 'reference-menu'; + +export class LinkMenuPlugin extends BasePlugin { + private _root?: PluginRenderRoot; + + public static override get pluginName(): string { + return PLUGIN_NAME; + } + + protected override _onRender(): void { + this._root = new PluginRenderRoot({ + name: PLUGIN_NAME, + render: this.editor.reactRenderRoot.render, + }); + this._root.mount(); + + this._root?.render( + + + + ); + } + + public override dispose() { + this._root?.unmount(); + super.dispose(); + } +} diff --git a/libs/components/editor-plugins/src/menu/link-menu/index.ts b/libs/components/editor-plugins/src/menu/link-menu/index.ts new file mode 100644 index 0000000000..1b3746630c --- /dev/null +++ b/libs/components/editor-plugins/src/menu/link-menu/index.ts @@ -0,0 +1 @@ +export { LinkMenuPlugin } from './Plugin'; From a89d5847dfc5f18fe1612c1f04a2391697471d6a Mon Sep 17 00:00:00 2001 From: xiaodong zuo Date: Sat, 3 Sep 2022 09:24:03 +0800 Subject: [PATCH 06/11] feat: Link feature add search function --- libs/components/common/src/lib/text/slate-utils.ts | 5 +---- .../src/menu/double-link-menu/DoubleLinkMenu.tsx | 4 +++- .../editor-plugins/src/menu/double-link-menu/Plugin.tsx | 2 +- .../editor-plugins/src/menu/inline-menu/utils.ts | 8 ++++---- .../editor-plugins/src/menu/link-menu/LinkMenu.tsx | 3 +-- 5 files changed, 10 insertions(+), 12 deletions(-) diff --git a/libs/components/common/src/lib/text/slate-utils.ts b/libs/components/common/src/lib/text/slate-utils.ts index 1dc10e8042..0b35877974 100644 --- a/libs/components/common/src/lib/text/slate-utils.ts +++ b/libs/components/common/src/lib/text/slate-utils.ts @@ -690,10 +690,7 @@ class SlateUtils { } public getStart() { - return Editor.start(this.editor, { - path: [0, 0], - offset: 0, - }); + return Editor.start(this.editor, [0]); } public getEnd() { diff --git a/libs/components/editor-plugins/src/menu/double-link-menu/DoubleLinkMenu.tsx b/libs/components/editor-plugins/src/menu/double-link-menu/DoubleLinkMenu.tsx index 4650a07c70..37fd4699d3 100644 --- a/libs/components/editor-plugins/src/menu/double-link-menu/DoubleLinkMenu.tsx +++ b/libs/components/editor-plugins/src/menu/double-link-menu/DoubleLinkMenu.tsx @@ -185,10 +185,12 @@ export const DoubleLinkMenu = ({ } } const { type, anchorNode } = editor.selection.currentSelectInfo; + if (!anchorNode) { + return; + } if ( !isOpen || (type === 'Range' && - anchorNode && anchorNode.id !== curBlockId && editor.blockHelper.isSelectionCollapsed(anchorNode.id)) ) { diff --git a/libs/components/editor-plugins/src/menu/double-link-menu/Plugin.tsx b/libs/components/editor-plugins/src/menu/double-link-menu/Plugin.tsx index 3933bf5f1c..cb1a6e29df 100644 --- a/libs/components/editor-plugins/src/menu/double-link-menu/Plugin.tsx +++ b/libs/components/editor-plugins/src/menu/double-link-menu/Plugin.tsx @@ -3,7 +3,7 @@ import { BasePlugin } from '../../base-plugin'; import { PluginRenderRoot } from '../../utils'; import { DoubleLinkMenu } from './DoubleLinkMenu'; -const PLUGIN_NAME = 'reference-menu'; +const PLUGIN_NAME = 'doublelink-menu'; export class DoubleLinkMenuPlugin extends BasePlugin { private _root?: PluginRenderRoot; diff --git a/libs/components/editor-plugins/src/menu/inline-menu/utils.ts b/libs/components/editor-plugins/src/menu/inline-menu/utils.ts index a086905da5..3afbb57de3 100644 --- a/libs/components/editor-plugins/src/menu/inline-menu/utils.ts +++ b/libs/components/editor-plugins/src/menu/inline-menu/utils.ts @@ -181,10 +181,10 @@ const common_handler_for_inline_menu: ClickItemHandler = ({ }); break; case inlineMenuNamesKeys.link: - add_link({ - editor, - blockId: anchorNodeId, - }); + // add_link({ + // editor, + // blockId: anchorNodeId, + // }); editor.plugins.emit('showAddLink'); setShow(false); break; diff --git a/libs/components/editor-plugins/src/menu/link-menu/LinkMenu.tsx b/libs/components/editor-plugins/src/menu/link-menu/LinkMenu.tsx index f2d2af19fe..6e0eb6322e 100644 --- a/libs/components/editor-plugins/src/menu/link-menu/LinkMenu.tsx +++ b/libs/components/editor-plugins/src/menu/link-menu/LinkMenu.tsx @@ -204,7 +204,7 @@ export const LinkMenu = ({ editor, hooks }: LinkMenuProps) => { ({ backgroundColor: '#fff', alignItems: 'center', zIndex: '1', - width: '354px', })); const LinkModalContainerIcon = styled('div')(({ theme }) => ({ From 560a5dce42f4c66c6860a0d1976e34707353a3c6 Mon Sep 17 00:00:00 2001 From: xiaodong zuo Date: Mon, 5 Sep 2022 11:39:31 +0800 Subject: [PATCH 07/11] feat: Link feature add search function --- .../editor-plugins/src/menu/inline-menu/utils.ts | 12 ++++++------ .../editor-plugins/src/menu/link-menu/LinkMenu.tsx | 11 ++++------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/libs/components/editor-plugins/src/menu/inline-menu/utils.ts b/libs/components/editor-plugins/src/menu/inline-menu/utils.ts index 3afbb57de3..bb35d31f5a 100644 --- a/libs/components/editor-plugins/src/menu/inline-menu/utils.ts +++ b/libs/components/editor-plugins/src/menu/inline-menu/utils.ts @@ -181,12 +181,12 @@ const common_handler_for_inline_menu: ClickItemHandler = ({ }); break; case inlineMenuNamesKeys.link: - // add_link({ - // editor, - // blockId: anchorNodeId, - // }); - editor.plugins.emit('showAddLink'); - setShow(false); + add_link({ + editor, + blockId: anchorNodeId, + }); + // editor.plugins.emit('showAddLink'); + // setShow(false); break; case inlineMenuNamesKeys.code: toggle_text_format({ diff --git a/libs/components/editor-plugins/src/menu/link-menu/LinkMenu.tsx b/libs/components/editor-plugins/src/menu/link-menu/LinkMenu.tsx index 6e0eb6322e..ddd178e449 100644 --- a/libs/components/editor-plugins/src/menu/link-menu/LinkMenu.tsx +++ b/libs/components/editor-plugins/src/menu/link-menu/LinkMenu.tsx @@ -128,18 +128,15 @@ export const LinkMenu = ({ editor, hooks }: LinkMenuProps) => { ); useEffect(() => { - const showDoubleLink = () => { + const showLinkMenu = () => { const { anchorNode } = editor.selection.currentSelectInfo; resetState('', anchorNode.id); }; - editor.plugins.observe('showAddLink', showDoubleLink); - return () => editor.plugins.unobserve('showAddLink', showDoubleLink); + editor.plugins.observe('showAddLink', showLinkMenu); + return () => editor.plugins.unobserve('showAddLink', showLinkMenu); }, [editor, resetState]); - const handleSelected = async (id: string) => { - if (curBlockId) { - } - }; + const handleSelected = async (id: string) => {}; const handleFilterChange = useCallback( async (e: ChangeEvent) => { From 97007f3bb5dbda8a0f4ffe2d96a51a7333e5a237 Mon Sep 17 00:00:00 2001 From: xiaodong zuo Date: Mon, 5 Sep 2022 15:06:06 +0800 Subject: [PATCH 08/11] unuse code --- apps/ligo-virgo/src/pages/workspace/WorkspaceContainer.tsx | 2 +- libs/datasource/jwt-rpc/src/broadcast.ts | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/ligo-virgo/src/pages/workspace/WorkspaceContainer.tsx b/apps/ligo-virgo/src/pages/workspace/WorkspaceContainer.tsx index 8d470671ef..d1b3f3444f 100644 --- a/apps/ligo-virgo/src/pages/workspace/WorkspaceContainer.tsx +++ b/apps/ligo-virgo/src/pages/workspace/WorkspaceContainer.tsx @@ -8,7 +8,7 @@ import Labels from './labels'; import Pages from './pages'; export function WorkspaceContainer() { - const { workspace_id, page_id } = useParams(); + const { workspace_id } = useParams(); const { user, currentSpaceId } = useUserAndSpaces(); if ( diff --git a/libs/datasource/jwt-rpc/src/broadcast.ts b/libs/datasource/jwt-rpc/src/broadcast.ts index b0f344aad7..59c974bf0c 100644 --- a/libs/datasource/jwt-rpc/src/broadcast.ts +++ b/libs/datasource/jwt-rpc/src/broadcast.ts @@ -3,7 +3,6 @@ import * as encoding from 'lib0/encoding'; import * as awarenessProtocol from 'y-protocols/awareness'; import * as syncProtocol from 'y-protocols/sync'; import * as Y from 'yjs'; - import { Message } from './handler'; import { readMessage } from './processor'; import { WebsocketProvider } from './provider'; @@ -14,7 +13,7 @@ export const registerBroadcastSubscriber = ( document: Y.Doc ) => { const channel = provider.broadcastChannel; - + // eslint-disable-next-line @typescript-eslint/no-explicit-any const subscriber = (data: ArrayBuffer, origin: any) => { if (origin !== provider) { const encoder = readMessage(provider, new Uint8Array(data), false); From 08ec766353a1069507b9acf3ed530e5e3355c2ca Mon Sep 17 00:00:00 2001 From: xiaodong zuo Date: Tue, 6 Sep 2022 14:20:07 +0800 Subject: [PATCH 09/11] feat: disable search feature --- .../editor-plugins/src/search/Search.tsx | 19 +++++++------------ .../layout/src/header/LayoutHeader.tsx | 1 + 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/libs/components/editor-plugins/src/search/Search.tsx b/libs/components/editor-plugins/src/search/Search.tsx index 23a3f46c2c..6092862416 100644 --- a/libs/components/editor-plugins/src/search/Search.tsx +++ b/libs/components/editor-plugins/src/search/Search.tsx @@ -5,12 +5,7 @@ import { styled, TransitionsModal, } from '@toeverything/components/ui'; -import { - BlockEditor, - HookType, - PluginHooks, - Virgo, -} from '@toeverything/framework/virgo'; +import { BlockEditor, PluginHooks, Virgo } from '@toeverything/framework/virgo'; import { throttle } from '@toeverything/utils'; import { useCallback, useEffect, useState } from 'react'; import { useNavigate, useParams } from 'react-router'; @@ -76,13 +71,13 @@ export const Search = (props: SearchProps) => { setSearch(''); }, []); - useEffect(() => { - const sub = props.hooks.get(HookType.ON_SEARCH).subscribe(handleSearch); + // useEffect(() => { + // const sub = props.hooks.get(HookType.ON_SEARCH).subscribe(handleSearch); - return () => { - sub.unsubscribe(); - }; - }, [props, handleSearch]); + // return () => { + // sub.unsubscribe(); + // }; + // }, [props, handleSearch]); return ( { size="large" hoverColor={'transparent'} onClick={handleSearch} + disabled={true} > From 7c28ebe91469af946d35ff4acdab4254db9fa452 Mon Sep 17 00:00:00 2001 From: xiaodong zuo Date: Tue, 6 Sep 2022 14:23:51 +0800 Subject: [PATCH 10/11] feat: disable add-sub-page double-link feature --- .../menu/double-link-menu/DoubleLinkMenu.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/libs/components/editor-plugins/src/menu/double-link-menu/DoubleLinkMenu.tsx b/libs/components/editor-plugins/src/menu/double-link-menu/DoubleLinkMenu.tsx index 37fd4699d3..ea9b4dc224 100644 --- a/libs/components/editor-plugins/src/menu/double-link-menu/DoubleLinkMenu.tsx +++ b/libs/components/editor-plugins/src/menu/double-link-menu/DoubleLinkMenu.tsx @@ -103,18 +103,18 @@ export const DoubleLinkMenu = ({ items.push({ content: { id: ADD_NEW_SUB_PAGE, - content: 'Add new sub-page', + content: 'Add new page', icon: AddIcon, }, }); - !inAddNewPage && - items.push({ - content: { - id: ADD_NEW_PAGE, - content: 'Add new page in...', - icon: AddIcon, - }, - }); + // !inAddNewPage && + // items.push({ + // content: { + // id: ADD_NEW_PAGE, + // content: 'Add new page in...', + // icon: AddIcon, + // }, + // }); return items; }, [searchResultBlocks, inAddNewPage]); From 956727bc3bb4d12b52615d4cc5c9a631f3d0346f Mon Sep 17 00:00:00 2001 From: xiaodong zuo Date: Tue, 6 Sep 2022 14:33:32 +0800 Subject: [PATCH 11/11] modify double-link feature --- .../editor-plugins/src/menu/double-link-menu/DoubleLinkMenu.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/components/editor-plugins/src/menu/double-link-menu/DoubleLinkMenu.tsx b/libs/components/editor-plugins/src/menu/double-link-menu/DoubleLinkMenu.tsx index ea9b4dc224..90f5e10c43 100644 --- a/libs/components/editor-plugins/src/menu/double-link-menu/DoubleLinkMenu.tsx +++ b/libs/components/editor-plugins/src/menu/double-link-menu/DoubleLinkMenu.tsx @@ -103,7 +103,7 @@ export const DoubleLinkMenu = ({ items.push({ content: { id: ADD_NEW_SUB_PAGE, - content: 'Add new page', + content: 'Add new sub-page', icon: AddIcon, }, });