refactor(core): better block link (#8082)
This commit is contained in:
@@ -6,7 +6,6 @@ import {
|
|||||||
} from '@affine/core/modules/peek-view';
|
} from '@affine/core/modules/peek-view';
|
||||||
import { WorkbenchLink } from '@affine/core/modules/workbench';
|
import { WorkbenchLink } from '@affine/core/modules/workbench';
|
||||||
import { useI18n } from '@affine/i18n';
|
import { useI18n } from '@affine/i18n';
|
||||||
import type { BlockStdScope } from '@blocksuite/block-std';
|
|
||||||
import type { DocMode } from '@blocksuite/blocks';
|
import type { DocMode } from '@blocksuite/blocks';
|
||||||
import {
|
import {
|
||||||
BlockLinkIcon,
|
BlockLinkIcon,
|
||||||
@@ -17,16 +16,16 @@ import {
|
|||||||
} from '@blocksuite/icons/rc';
|
} from '@blocksuite/icons/rc';
|
||||||
import type { DocCollection } from '@blocksuite/store';
|
import type { DocCollection } from '@blocksuite/store';
|
||||||
import { useService } from '@toeverything/infra';
|
import { useService } from '@toeverything/infra';
|
||||||
|
import { nanoid } from 'nanoid';
|
||||||
import {
|
import {
|
||||||
type PropsWithChildren,
|
type PropsWithChildren,
|
||||||
useCallback,
|
useCallback,
|
||||||
useEffect,
|
useMemo,
|
||||||
useRef,
|
useRef,
|
||||||
useState,
|
useState,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
|
|
||||||
import * as styles from './styles.css';
|
import * as styles from './styles.css';
|
||||||
import { scrollAnchoring } from './utils';
|
|
||||||
|
|
||||||
export interface PageReferenceRendererOptions {
|
export interface PageReferenceRendererOptions {
|
||||||
pageId: string;
|
pageId: string;
|
||||||
@@ -90,8 +89,6 @@ export function AffinePageReference({
|
|||||||
wrapper: Wrapper,
|
wrapper: Wrapper,
|
||||||
mode = 'page',
|
mode = 'page',
|
||||||
params = {},
|
params = {},
|
||||||
isSameDoc = false,
|
|
||||||
std,
|
|
||||||
}: {
|
}: {
|
||||||
pageId: string;
|
pageId: string;
|
||||||
docCollection: DocCollection;
|
docCollection: DocCollection;
|
||||||
@@ -102,16 +99,10 @@ export function AffinePageReference({
|
|||||||
blockIds?: string[];
|
blockIds?: string[];
|
||||||
elementIds?: string[];
|
elementIds?: string[];
|
||||||
};
|
};
|
||||||
isSameDoc?: boolean;
|
|
||||||
std?: BlockStdScope;
|
|
||||||
}) {
|
}) {
|
||||||
const pageMetaHelper = useDocMetaHelper(docCollection);
|
const pageMetaHelper = useDocMetaHelper(docCollection);
|
||||||
const journalHelper = useJournalHelper(docCollection);
|
const journalHelper = useJournalHelper(docCollection);
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
const [anchor, setAnchor] = useState<{
|
|
||||||
mode: DocMode;
|
|
||||||
id: string;
|
|
||||||
} | null>(null);
|
|
||||||
|
|
||||||
const { mode: linkedWithMode, blockIds, elementIds } = params;
|
const { mode: linkedWithMode, blockIds, elementIds } = params;
|
||||||
|
|
||||||
@@ -128,21 +119,11 @@ export function AffinePageReference({
|
|||||||
|
|
||||||
const ref = useRef<HTMLAnchorElement>(null);
|
const ref = useRef<HTMLAnchorElement>(null);
|
||||||
|
|
||||||
|
const [refreshKey, setRefreshKey] = useState<string>(() => nanoid());
|
||||||
|
|
||||||
const peekView = useService(PeekViewService).peekView;
|
const peekView = useService(PeekViewService).peekView;
|
||||||
const isInPeekView = useInsidePeekView();
|
const isInPeekView = useInsidePeekView();
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (isSameDoc) {
|
|
||||||
if (mode === 'edgeless' && elementIds?.length) {
|
|
||||||
setAnchor({ mode, id: elementIds[0] });
|
|
||||||
} else if (blockIds?.length) {
|
|
||||||
setAnchor({ mode, id: blockIds[0] });
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setAnchor(null);
|
|
||||||
}
|
|
||||||
}, [std, isSameDoc, mode, blockIds, elementIds]);
|
|
||||||
|
|
||||||
const onClick = useCallback(
|
const onClick = useCallback(
|
||||||
(e: React.MouseEvent) => {
|
(e: React.MouseEvent) => {
|
||||||
if (e.shiftKey && ref.current) {
|
if (e.shiftKey && ref.current) {
|
||||||
@@ -151,33 +132,34 @@ export function AffinePageReference({
|
|||||||
peekView.open(ref.current).catch(console.error);
|
peekView.open(ref.current).catch(console.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std && anchor) {
|
if (isInPeekView) {
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
const { mode, id } = anchor;
|
|
||||||
scrollAnchoring(std, mode, id);
|
|
||||||
} else if (isInPeekView) {
|
|
||||||
peekView.close();
|
peekView.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update refresh key
|
||||||
|
setRefreshKey(nanoid());
|
||||||
|
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
[isInPeekView, peekView, anchor, std]
|
[isInPeekView, peekView]
|
||||||
);
|
);
|
||||||
|
|
||||||
// A block/element reference link
|
const query = useMemo(() => {
|
||||||
const search = new URLSearchParams();
|
// A block/element reference link
|
||||||
if (linkedWithMode) {
|
const search = new URLSearchParams();
|
||||||
search.set('mode', linkedWithMode);
|
if (linkedWithMode) {
|
||||||
}
|
search.set('mode', linkedWithMode);
|
||||||
if (blockIds?.length) {
|
}
|
||||||
search.set('blockIds', blockIds.join(','));
|
if (blockIds?.length) {
|
||||||
}
|
search.set('blockIds', blockIds.join(','));
|
||||||
if (elementIds?.length) {
|
}
|
||||||
search.set('elementIds', elementIds.join(','));
|
if (elementIds?.length) {
|
||||||
}
|
search.set('elementIds', elementIds.join(','));
|
||||||
|
}
|
||||||
|
search.set('refreshKey', refreshKey);
|
||||||
|
|
||||||
const query = search.size > 0 ? `?${search.toString()}` : '';
|
return search.size > 0 ? `?${search.toString()}` : '';
|
||||||
|
}, [blockIds, elementIds, linkedWithMode, refreshKey]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<WorkbenchLink
|
<WorkbenchLink
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import type { EditorSelector } from '@affine/core/modules/editor';
|
import { EditorService } from '@affine/core/modules/editor';
|
||||||
import type { ReferenceInfo } from '@blocksuite/affine-model';
|
import type { ReferenceInfo } from '@blocksuite/affine-model';
|
||||||
import type { DocMode } from '@blocksuite/blocks';
|
import type { DocMode } from '@blocksuite/blocks';
|
||||||
import type { InlineEditor } from '@blocksuite/inline/inline-editor';
|
|
||||||
import type {
|
import type {
|
||||||
AffineEditorContainer,
|
AffineEditorContainer,
|
||||||
DocTitle,
|
DocTitle,
|
||||||
@@ -9,6 +8,7 @@ import type {
|
|||||||
PageEditor,
|
PageEditor,
|
||||||
} from '@blocksuite/presets';
|
} from '@blocksuite/presets';
|
||||||
import { type Doc, Slot } from '@blocksuite/store';
|
import { type Doc, Slot } from '@blocksuite/store';
|
||||||
|
import { useService } from '@toeverything/infra';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import type React from 'react';
|
import type React from 'react';
|
||||||
import {
|
import {
|
||||||
@@ -18,10 +18,8 @@ import {
|
|||||||
useLayoutEffect,
|
useLayoutEffect,
|
||||||
useMemo,
|
useMemo,
|
||||||
useRef,
|
useRef,
|
||||||
useState,
|
|
||||||
} from 'react';
|
} from 'react';
|
||||||
|
|
||||||
import { scrollAnchoring } from '../../affine/reference-link/utils';
|
|
||||||
import { BlocksuiteDocEditor, BlocksuiteEdgelessEditor } from './lit-adaper';
|
import { BlocksuiteDocEditor, BlocksuiteEdgelessEditor } from './lit-adaper';
|
||||||
import * as styles from './styles.css';
|
import * as styles from './styles.css';
|
||||||
|
|
||||||
@@ -46,7 +44,6 @@ interface BlocksuiteEditorContainerProps {
|
|||||||
shared?: boolean;
|
shared?: boolean;
|
||||||
className?: string;
|
className?: string;
|
||||||
style?: React.CSSProperties;
|
style?: React.CSSProperties;
|
||||||
defaultEditorSelector?: EditorSelector;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// mimic the interface of the webcomponent and expose slots & host
|
// mimic the interface of the webcomponent and expose slots & host
|
||||||
@@ -60,21 +57,14 @@ export const BlocksuiteEditorContainer = forwardRef<
|
|||||||
AffineEditorContainer,
|
AffineEditorContainer,
|
||||||
BlocksuiteEditorContainerProps
|
BlocksuiteEditorContainerProps
|
||||||
>(function AffineEditorContainer(
|
>(function AffineEditorContainer(
|
||||||
{ page, mode, className, style, shared, defaultEditorSelector },
|
{ page, mode, className, style, shared },
|
||||||
ref
|
ref
|
||||||
) {
|
) {
|
||||||
|
const editorService = useService(EditorService);
|
||||||
const rootRef = useRef<HTMLDivElement>(null);
|
const rootRef = useRef<HTMLDivElement>(null);
|
||||||
const docRef = useRef<PageEditor>(null);
|
const docRef = useRef<PageEditor>(null);
|
||||||
const docTitleRef = useRef<DocTitle>(null);
|
const docTitleRef = useRef<DocTitle>(null);
|
||||||
const edgelessRef = useRef<EdgelessEditor>(null);
|
const edgelessRef = useRef<EdgelessEditor>(null);
|
||||||
const [anchor] = useState<string | null>(() => {
|
|
||||||
if (mode === 'edgeless' && defaultEditorSelector?.elementIds?.length) {
|
|
||||||
return defaultEditorSelector.elementIds[0];
|
|
||||||
} else if (defaultEditorSelector?.blockIds?.length) {
|
|
||||||
return defaultEditorSelector.blockIds[0];
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
|
|
||||||
const slots: BlocksuiteEditorContainerRef['slots'] = useMemo(() => {
|
const slots: BlocksuiteEditorContainerRef['slots'] = useMemo(() => {
|
||||||
return {
|
return {
|
||||||
@@ -180,40 +170,24 @@ export const BlocksuiteEditorContainer = forwardRef<
|
|||||||
}, [affineEditorContainerProxy, ref]);
|
}, [affineEditorContainerProxy, ref]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (anchor) {
|
let canceled = false;
|
||||||
let canceled = false;
|
let unsubscribe: () => void = () => {};
|
||||||
affineEditorContainerProxy.updateComplete
|
|
||||||
.then(() => {
|
|
||||||
if (!canceled) {
|
|
||||||
const std = affineEditorContainerProxy.host?.std;
|
|
||||||
if (std) {
|
|
||||||
scrollAnchoring(std, mode, anchor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(console.error);
|
|
||||||
return () => {
|
|
||||||
canceled = true;
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
// if no anchor, focus the title
|
|
||||||
let canceled = false;
|
|
||||||
|
|
||||||
affineEditorContainerProxy.updateComplete
|
affineEditorContainerProxy.updateComplete
|
||||||
.then(() => {
|
.then(() => {
|
||||||
if (!canceled) {
|
if (!canceled) {
|
||||||
const title = docTitleRef.current?.querySelector<
|
unsubscribe = editorService.editor.bindEditorContainer(
|
||||||
HTMLElement & { inlineEditor: InlineEditor }
|
affineEditorContainerProxy,
|
||||||
>('rich-text');
|
docTitleRef.current as DocTitle
|
||||||
title?.inlineEditor.focusEnd();
|
);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(console.error);
|
.catch(console.error);
|
||||||
return () => {
|
return () => {
|
||||||
canceled = true;
|
canceled = true;
|
||||||
};
|
unsubscribe();
|
||||||
}
|
};
|
||||||
}, [anchor, affineEditorContainerProxy, mode]);
|
}, [affineEditorContainerProxy, mode, editorService]);
|
||||||
|
|
||||||
const handleClickPageModeBlank = useCallback(() => {
|
const handleClickPageModeBlank = useCallback(() => {
|
||||||
affineEditorContainerProxy.host?.std.command.exec(
|
affineEditorContainerProxy.host?.std.command.exec(
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { EditorLoading } from '@affine/component/page-detail-skeleton';
|
import { EditorLoading } from '@affine/component/page-detail-skeleton';
|
||||||
import type { EditorSelector } from '@affine/core/modules/editor';
|
|
||||||
import type { DocMode } from '@blocksuite/blocks';
|
import type { DocMode } from '@blocksuite/blocks';
|
||||||
import { assertExists } from '@blocksuite/global/utils';
|
import { assertExists } from '@blocksuite/global/utils';
|
||||||
import type { AffineEditorContainer } from '@blocksuite/presets';
|
import type { AffineEditorContainer } from '@blocksuite/presets';
|
||||||
@@ -30,7 +29,6 @@ export type EditorProps = {
|
|||||||
onLoadEditor?: (editor: AffineEditorContainer) => () => void;
|
onLoadEditor?: (editor: AffineEditorContainer) => () => void;
|
||||||
style?: CSSProperties;
|
style?: CSSProperties;
|
||||||
className?: string;
|
className?: string;
|
||||||
defaultEditorSelector?: EditorSelector;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function usePageRoot(page: Doc) {
|
function usePageRoot(page: Doc) {
|
||||||
@@ -57,15 +55,7 @@ function usePageRoot(page: Doc) {
|
|||||||
|
|
||||||
const BlockSuiteEditorImpl = forwardRef<AffineEditorContainer, EditorProps>(
|
const BlockSuiteEditorImpl = forwardRef<AffineEditorContainer, EditorProps>(
|
||||||
function BlockSuiteEditorImpl(
|
function BlockSuiteEditorImpl(
|
||||||
{
|
{ mode, page, className, onLoadEditor, shared, style },
|
||||||
mode,
|
|
||||||
page,
|
|
||||||
className,
|
|
||||||
onLoadEditor,
|
|
||||||
shared,
|
|
||||||
style,
|
|
||||||
defaultEditorSelector,
|
|
||||||
},
|
|
||||||
ref
|
ref
|
||||||
) {
|
) {
|
||||||
usePageRoot(page);
|
usePageRoot(page);
|
||||||
@@ -115,7 +105,6 @@ const BlockSuiteEditorImpl = forwardRef<AffineEditorContainer, EditorProps>(
|
|||||||
ref={onRefChange}
|
ref={onRefChange}
|
||||||
className={className}
|
className={className}
|
||||||
style={style}
|
style={style}
|
||||||
defaultEditorSelector={defaultEditorSelector}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,20 +77,16 @@ const usePatchSpecs = (page: Doc, shared: boolean, mode: DocMode) => {
|
|||||||
const pageId = data.pageId;
|
const pageId = data.pageId;
|
||||||
if (!pageId) return <span />;
|
if (!pageId) return <span />;
|
||||||
|
|
||||||
const isSameDoc = pageId === page.id;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AffinePageReference
|
<AffinePageReference
|
||||||
docCollection={page.collection}
|
docCollection={page.collection}
|
||||||
pageId={pageId}
|
pageId={pageId}
|
||||||
mode={mode}
|
mode={mode}
|
||||||
params={data.params}
|
params={data.params}
|
||||||
std={reference.std}
|
|
||||||
isSameDoc={isSameDoc}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
}, [mode, page.collection, page.id]);
|
}, [mode, page.collection]);
|
||||||
|
|
||||||
const specs = useMemo(() => {
|
const specs = useMemo(() => {
|
||||||
return mode === 'edgeless'
|
return mode === 'edgeless'
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ export const EditorModeSwitch = () => {
|
|||||||
const togglePage = useCallback(() => {
|
const togglePage = useCallback(() => {
|
||||||
if (currentMode === 'page' || isSharedMode || trash) return;
|
if (currentMode === 'page' || isSharedMode || trash) return;
|
||||||
editor.setMode('page');
|
editor.setMode('page');
|
||||||
|
editor.setSelector(undefined);
|
||||||
editor.doc.setPrimaryMode('page');
|
editor.doc.setPrimaryMode('page');
|
||||||
toast(t['com.affine.toastMessage.pageMode']());
|
toast(t['com.affine.toastMessage.pageMode']());
|
||||||
track.$.header.actions.switchPageMode({ mode: 'page' });
|
track.$.header.actions.switchPageMode({ mode: 'page' });
|
||||||
@@ -48,6 +49,7 @@ export const EditorModeSwitch = () => {
|
|||||||
const toggleEdgeless = useCallback(() => {
|
const toggleEdgeless = useCallback(() => {
|
||||||
if (currentMode === 'edgeless' || isSharedMode || trash) return;
|
if (currentMode === 'edgeless' || isSharedMode || trash) return;
|
||||||
editor.setMode('edgeless');
|
editor.setMode('edgeless');
|
||||||
|
editor.setSelector(undefined);
|
||||||
editor.doc.setPrimaryMode('edgeless');
|
editor.doc.setPrimaryMode('edgeless');
|
||||||
toast(t['com.affine.toastMessage.edgelessMode']());
|
toast(t['com.affine.toastMessage.edgelessMode']());
|
||||||
track.$.header.actions.switchPageMode({ mode: 'edgeless' });
|
track.$.header.actions.switchPageMode({ mode: 'edgeless' });
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import clsx from 'clsx';
|
|||||||
import type { CSSProperties } from 'react';
|
import type { CSSProperties } from 'react';
|
||||||
import { memo, useCallback, useMemo } from 'react';
|
import { memo, useCallback, useMemo } from 'react';
|
||||||
|
|
||||||
import { type EditorSelector, EditorService } from '../modules/editor';
|
import { EditorService } from '../modules/editor';
|
||||||
import {
|
import {
|
||||||
EditorSettingService,
|
EditorSettingService,
|
||||||
fontStyleOptions,
|
fontStyleOptions,
|
||||||
@@ -35,13 +35,11 @@ export interface PageDetailEditorProps {
|
|||||||
docCollection: DocCollection;
|
docCollection: DocCollection;
|
||||||
pageId: string;
|
pageId: string;
|
||||||
onLoad?: OnLoadEditor;
|
onLoad?: OnLoadEditor;
|
||||||
defaultEditorSelector?: EditorSelector;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const PageDetailEditorMain = memo(function PageDetailEditorMain({
|
const PageDetailEditorMain = memo(function PageDetailEditorMain({
|
||||||
page,
|
page,
|
||||||
onLoad,
|
onLoad,
|
||||||
defaultEditorSelector,
|
|
||||||
}: PageDetailEditorProps & { page: BlockSuiteDoc }) {
|
}: PageDetailEditorProps & { page: BlockSuiteDoc }) {
|
||||||
const editor = useService(EditorService).editor;
|
const editor = useService(EditorService).editor;
|
||||||
const mode = useLiveData(editor.mode$);
|
const mode = useLiveData(editor.mode$);
|
||||||
@@ -108,7 +106,6 @@ const PageDetailEditorMain = memo(function PageDetailEditorMain({
|
|||||||
mode={mode}
|
mode={mode}
|
||||||
page={page}
|
page={page}
|
||||||
shared={isSharedMode}
|
shared={isSharedMode}
|
||||||
defaultEditorSelector={defaultEditorSelector}
|
|
||||||
onLoadEditor={onLoadEditor}
|
onLoadEditor={onLoadEditor}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,29 +1,32 @@
|
|||||||
import type { DocMode } from '@blocksuite/blocks';
|
import type { DocMode } from '@blocksuite/blocks';
|
||||||
import type { AffineEditorContainer } from '@blocksuite/presets';
|
import type { InlineEditor } from '@blocksuite/inline/inline-editor';
|
||||||
|
import type { AffineEditorContainer, DocTitle } from '@blocksuite/presets';
|
||||||
import type { DocService, WorkspaceService } from '@toeverything/infra';
|
import type { DocService, WorkspaceService } from '@toeverything/infra';
|
||||||
import { Entity, LiveData } from '@toeverything/infra';
|
import { Entity, LiveData } from '@toeverything/infra';
|
||||||
|
import { isEqual } from 'lodash-es';
|
||||||
|
|
||||||
|
import type { WorkbenchView } from '../../workbench';
|
||||||
import { EditorScope } from '../scopes/editor';
|
import { EditorScope } from '../scopes/editor';
|
||||||
import type { EditorSelector } from '../types';
|
import type { EditorSelector } from '../types';
|
||||||
|
import { scrollAnchoring } from '../utils/scroll-anchoring';
|
||||||
|
|
||||||
export class Editor extends Entity<{
|
export class Editor extends Entity {
|
||||||
defaultMode: DocMode;
|
|
||||||
defaultEditorSelector?: EditorSelector;
|
|
||||||
}> {
|
|
||||||
readonly scope = this.framework.createScope(EditorScope, {
|
readonly scope = this.framework.createScope(EditorScope, {
|
||||||
editor: this as Editor,
|
editor: this as Editor,
|
||||||
});
|
});
|
||||||
|
|
||||||
readonly mode$ = new LiveData(this.props.defaultMode);
|
readonly mode$ = new LiveData<DocMode>('page');
|
||||||
readonly selector$ = new LiveData<EditorSelector | undefined>(
|
readonly selector$ = new LiveData<EditorSelector | undefined>(undefined);
|
||||||
this.props.defaultEditorSelector
|
|
||||||
);
|
|
||||||
readonly doc = this.docService.doc;
|
readonly doc = this.docService.doc;
|
||||||
readonly isSharedMode =
|
readonly isSharedMode =
|
||||||
this.workspaceService.workspace.openOptions.isSharedMode;
|
this.workspaceService.workspace.openOptions.isSharedMode;
|
||||||
|
|
||||||
readonly editorContainer$ = new LiveData<AffineEditorContainer | null>(null);
|
readonly editorContainer$ = new LiveData<AffineEditorContainer | null>(null);
|
||||||
|
|
||||||
|
setSelector(selector: EditorSelector | undefined) {
|
||||||
|
this.selector$.next(selector);
|
||||||
|
}
|
||||||
|
|
||||||
toggleMode() {
|
toggleMode() {
|
||||||
this.mode$.next(this.mode$.value === 'edgeless' ? 'page' : 'edgeless');
|
this.mode$.next(this.mode$.value === 'edgeless' ? 'page' : 'edgeless');
|
||||||
}
|
}
|
||||||
@@ -36,6 +39,149 @@ export class Editor extends Entity<{
|
|||||||
this.editorContainer$.next(editorContainer);
|
this.editorContainer$.next(editorContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sync editor params with view query string
|
||||||
|
*/
|
||||||
|
bindWorkbenchView(view: WorkbenchView) {
|
||||||
|
// eslint-disable-next-line rxjs/finnish
|
||||||
|
const viewParams$ = view.queryString$<{
|
||||||
|
mode?: DocMode;
|
||||||
|
blockIds?: string[];
|
||||||
|
elementIds?: string[];
|
||||||
|
refreshKey?: string;
|
||||||
|
}>({
|
||||||
|
// Cannot handle single id situation correctly: `blockIds=xxx`
|
||||||
|
arrayFormat: 'none',
|
||||||
|
types: {
|
||||||
|
mode: value =>
|
||||||
|
value === 'page' || value === 'edgeless' ? value : undefined,
|
||||||
|
blockIds: value => (value.length ? value.split(',') : []),
|
||||||
|
elementIds: value => (value.length ? value.split(',') : []),
|
||||||
|
refreshKey: 'string',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const stablePrimaryMode = this.doc.getPrimaryMode();
|
||||||
|
|
||||||
|
const editorParams$ = LiveData.computed(get => {
|
||||||
|
const selector = get(this.selector$);
|
||||||
|
return {
|
||||||
|
mode: get(this.mode$),
|
||||||
|
blockIds: selector?.blockIds,
|
||||||
|
elementIds: selector?.elementIds,
|
||||||
|
refreshKey: selector?.refreshKey,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// prevent infinite loop
|
||||||
|
let updating = false;
|
||||||
|
|
||||||
|
const unsubscribeViewParams = viewParams$.subscribe(params => {
|
||||||
|
if (updating) return;
|
||||||
|
updating = true;
|
||||||
|
// when view params changed, sync to editor
|
||||||
|
try {
|
||||||
|
const mode =
|
||||||
|
viewParams$.value.mode || stablePrimaryMode || ('page' as DocMode);
|
||||||
|
if (mode !== editorParams$.value.mode) {
|
||||||
|
this.setMode(mode);
|
||||||
|
}
|
||||||
|
const newSelector = {
|
||||||
|
blockIds: params.blockIds,
|
||||||
|
elementIds: params.elementIds,
|
||||||
|
refreshKey: params.refreshKey,
|
||||||
|
};
|
||||||
|
if (!isEqual(newSelector, editorParams$.value)) {
|
||||||
|
this.setSelector({
|
||||||
|
blockIds: params.blockIds,
|
||||||
|
elementIds: params.elementIds,
|
||||||
|
refreshKey: params.refreshKey,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
updating = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const unsubscribeEditorParams = editorParams$.subscribe(params => {
|
||||||
|
if (updating) return;
|
||||||
|
updating = true;
|
||||||
|
try {
|
||||||
|
// when editor params changed, sync to view
|
||||||
|
const newQueryString: any = {};
|
||||||
|
let updated = false;
|
||||||
|
if (params.mode !== viewParams$.value.mode) {
|
||||||
|
newQueryString.mode = params.mode;
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
|
const stringBlockIds = params.blockIds?.join(',');
|
||||||
|
const stringElementIds = params.elementIds?.join(',');
|
||||||
|
const stringViewBlockIds = viewParams$.value.blockIds?.join(',');
|
||||||
|
const stringViewElementIds = viewParams$.value.elementIds?.join(',');
|
||||||
|
if (
|
||||||
|
stringBlockIds !== stringViewBlockIds ||
|
||||||
|
stringElementIds !== stringViewElementIds ||
|
||||||
|
params.refreshKey !== viewParams$.value.refreshKey
|
||||||
|
) {
|
||||||
|
newQueryString.blockIds = stringBlockIds;
|
||||||
|
newQueryString.elementIds = stringElementIds;
|
||||||
|
newQueryString.refreshKey = params.refreshKey;
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updated) {
|
||||||
|
view.updateQueryString(newQueryString, { replace: true });
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
updating = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
unsubscribeEditorParams.unsubscribe();
|
||||||
|
unsubscribeViewParams.unsubscribe();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
bindEditorContainer(
|
||||||
|
editorContainer: AffineEditorContainer,
|
||||||
|
docTitle: DocTitle
|
||||||
|
) {
|
||||||
|
const focusAt$ = LiveData.computed(get => {
|
||||||
|
const selector = get(this.selector$);
|
||||||
|
const id =
|
||||||
|
get(this.mode$) === 'edgeless' && selector?.elementIds?.length
|
||||||
|
? selector?.elementIds?.[0]
|
||||||
|
: selector?.blockIds?.[0];
|
||||||
|
if (id) {
|
||||||
|
return { id, refreshKey: selector?.refreshKey };
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (focusAt$.value === null) {
|
||||||
|
const title = docTitle.querySelector<
|
||||||
|
HTMLElement & { inlineEditor: InlineEditor }
|
||||||
|
>('rich-text');
|
||||||
|
title?.inlineEditor.focusEnd();
|
||||||
|
}
|
||||||
|
const unsubscribe = focusAt$
|
||||||
|
.distinctUntilChanged(
|
||||||
|
(a, b) => a?.id === b?.id && a?.refreshKey === b?.refreshKey
|
||||||
|
)
|
||||||
|
.subscribe(params => {
|
||||||
|
if (params?.id) {
|
||||||
|
const std = editorContainer.host?.std;
|
||||||
|
if (std) {
|
||||||
|
scrollAnchoring(std, this.mode$.value, params.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return () => {
|
||||||
|
unsubscribe.unsubscribe();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly docService: DocService,
|
private readonly docService: DocService,
|
||||||
private readonly workspaceService: WorkspaceService
|
private readonly workspaceService: WorkspaceService
|
||||||
|
|||||||
@@ -1,14 +1,9 @@
|
|||||||
import type { DocMode } from '@blocksuite/blocks';
|
|
||||||
import { Service } from '@toeverything/infra';
|
import { Service } from '@toeverything/infra';
|
||||||
|
|
||||||
import { Editor } from '../entities/editor';
|
import { Editor } from '../entities/editor';
|
||||||
import type { EditorSelector } from '../types';
|
|
||||||
|
|
||||||
export class EditorsService extends Service {
|
export class EditorsService extends Service {
|
||||||
createEditor(defaultMode: DocMode, defaultEditorSelector?: EditorSelector) {
|
createEditor() {
|
||||||
return this.framework.createEntity(Editor, {
|
return this.framework.createEntity(Editor);
|
||||||
defaultMode,
|
|
||||||
defaultEditorSelector,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
export type EditorSelector = {
|
export type EditorSelector = {
|
||||||
blockIds?: string[];
|
blockIds?: string[];
|
||||||
elementIds?: string[];
|
elementIds?: string[];
|
||||||
|
refreshKey?: string;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ function scrollAnchoringInEdgelessMode(
|
|||||||
h / service.viewport.zoom
|
h / service.viewport.zoom
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
if (!service.getElementById) return;
|
||||||
const model = service.getElementById(id);
|
const model = service.getElementById(id);
|
||||||
if (!model) return;
|
if (!model) return;
|
||||||
|
|
||||||
@@ -5,16 +5,17 @@ import { AffineErrorBoundary } from '@affine/core/components/affine/affine-error
|
|||||||
import { BlockSuiteEditor } from '@affine/core/components/blocksuite/block-suite-editor';
|
import { BlockSuiteEditor } from '@affine/core/components/blocksuite/block-suite-editor';
|
||||||
import { EditorOutlineViewer } from '@affine/core/components/blocksuite/outline-viewer';
|
import { EditorOutlineViewer } from '@affine/core/components/blocksuite/outline-viewer';
|
||||||
import { useNavigateHelper } from '@affine/core/hooks/use-navigate-helper';
|
import { useNavigateHelper } from '@affine/core/hooks/use-navigate-helper';
|
||||||
|
import { EditorService } from '@affine/core/modules/editor';
|
||||||
import { PageNotFound } from '@affine/core/pages/404';
|
import { PageNotFound } from '@affine/core/pages/404';
|
||||||
import { DebugLogger } from '@affine/debug';
|
import { DebugLogger } from '@affine/debug';
|
||||||
import type { DocMode, EdgelessRootService } from '@blocksuite/blocks';
|
import type { DocMode, EdgelessRootService } from '@blocksuite/blocks';
|
||||||
import { Bound, DisposableGroup } from '@blocksuite/global/utils';
|
import { Bound, DisposableGroup } from '@blocksuite/global/utils';
|
||||||
import type { AffineEditorContainer } from '@blocksuite/presets';
|
import type { AffineEditorContainer } from '@blocksuite/presets';
|
||||||
import {
|
import {
|
||||||
DocsService,
|
|
||||||
FrameworkScope,
|
FrameworkScope,
|
||||||
useLiveData,
|
useLiveData,
|
||||||
useService,
|
useService,
|
||||||
|
useServices,
|
||||||
} from '@toeverything/infra';
|
} from '@toeverything/infra';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
@@ -62,27 +63,21 @@ function fitViewport(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DocPeekPreview({
|
function DocPeekPreviewEditor({
|
||||||
docId,
|
|
||||||
blockIds,
|
|
||||||
elementIds,
|
|
||||||
mode,
|
|
||||||
xywh,
|
xywh,
|
||||||
}: {
|
}: {
|
||||||
docId: string;
|
|
||||||
blockIds?: string[];
|
|
||||||
elementIds?: string[];
|
|
||||||
mode?: DocMode;
|
|
||||||
xywh?: `[${number},${number},${number},${number}]`;
|
xywh?: `[${number},${number},${number},${number}]`;
|
||||||
}) {
|
}) {
|
||||||
const { doc, workspace, editor, loading } = useEditor(docId, mode, {
|
const { editorService } = useServices({
|
||||||
blockIds,
|
EditorService,
|
||||||
elementIds,
|
|
||||||
});
|
});
|
||||||
|
const editor = editorService.editor;
|
||||||
|
const doc = editor.doc;
|
||||||
|
const workspace = editor.doc.workspace;
|
||||||
|
const mode = useLiveData(editor.mode$);
|
||||||
const { jumpToTag } = useNavigateHelper();
|
const { jumpToTag } = useNavigateHelper();
|
||||||
const workbench = useService(WorkbenchService).workbench;
|
const workbench = useService(WorkbenchService).workbench;
|
||||||
const peekView = useService(PeekViewService).peekView;
|
const peekView = useService(PeekViewService).peekView;
|
||||||
const defaultEditorSelector = useLiveData(editor?.selector$);
|
|
||||||
const [editorElement, setEditorElement] =
|
const [editorElement, setEditorElement] =
|
||||||
useState<AffineEditorContainer | null>(null);
|
useState<AffineEditorContainer | null>(null);
|
||||||
|
|
||||||
@@ -90,27 +85,16 @@ export function DocPeekPreview({
|
|||||||
setEditorElement(editor);
|
setEditorElement(editor);
|
||||||
};
|
};
|
||||||
|
|
||||||
const docs = useService(DocsService);
|
|
||||||
const [resolvedMode, setResolvedMode] = useState<DocMode | undefined>(mode);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
editorElement?.updateComplete
|
editorElement?.updateComplete
|
||||||
.then(() => {
|
.then(() => {
|
||||||
if (resolvedMode === 'edgeless') {
|
if (mode === 'edgeless') {
|
||||||
fitViewport(editorElement, xywh);
|
fitViewport(editorElement, xywh);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(console.error);
|
.catch(console.error);
|
||||||
return;
|
return;
|
||||||
}, [editorElement, resolvedMode, xywh]);
|
}, [editorElement, mode, xywh]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!mode || !resolvedMode) {
|
|
||||||
setResolvedMode(
|
|
||||||
docs.list.doc$(docId).value?.primaryMode$.value || 'page'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}, [docId, docs.list, resolvedMode, mode]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const disposable = AIProvider.slots.requestOpenWithChat.on(() => {
|
const disposable = AIProvider.slots.requestOpenWithChat.on(() => {
|
||||||
@@ -164,20 +148,11 @@ export function DocPeekPreview({
|
|||||||
}, [editorElement, jumpToTag, peekView, workspace.id]);
|
}, [editorElement, jumpToTag, peekView, workspace.id]);
|
||||||
|
|
||||||
const openOutlinePanel = useCallback(() => {
|
const openOutlinePanel = useCallback(() => {
|
||||||
workbench.openDoc(docId);
|
workbench.openDoc(doc.id);
|
||||||
workbench.openSidebar();
|
workbench.openSidebar();
|
||||||
workbench.activeView$.value.activeSidebarTab('outline');
|
workbench.activeView$.value.activeSidebarTab('outline');
|
||||||
peekView.close();
|
peekView.close();
|
||||||
}, [docId, peekView, workbench]);
|
}, [doc, peekView, workbench]);
|
||||||
|
|
||||||
// if sync engine has been synced and the page is null, show 404 page.
|
|
||||||
if (!doc || !resolvedMode || !editor) {
|
|
||||||
return loading || !resolvedMode ? (
|
|
||||||
<PageDetailSkeleton key="current-page-is-null" />
|
|
||||||
) : (
|
|
||||||
<PageNotFound noPermission />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AffineErrorBoundary>
|
<AffineErrorBoundary>
|
||||||
@@ -185,20 +160,15 @@ export function DocPeekPreview({
|
|||||||
<Scrollable.Viewport
|
<Scrollable.Viewport
|
||||||
className={clsx('affine-page-viewport', styles.affineDocViewport)}
|
className={clsx('affine-page-viewport', styles.affineDocViewport)}
|
||||||
>
|
>
|
||||||
<FrameworkScope scope={doc.scope}>
|
<BlockSuiteEditor
|
||||||
<FrameworkScope scope={editor.scope}>
|
ref={onRef}
|
||||||
<BlockSuiteEditor
|
className={styles.editor}
|
||||||
ref={onRef}
|
mode={mode}
|
||||||
className={styles.editor}
|
page={doc.blockSuiteDoc}
|
||||||
mode={resolvedMode}
|
/>
|
||||||
defaultEditorSelector={defaultEditorSelector}
|
|
||||||
page={doc.blockSuiteDoc}
|
|
||||||
/>
|
|
||||||
</FrameworkScope>
|
|
||||||
</FrameworkScope>
|
|
||||||
<EditorOutlineViewer
|
<EditorOutlineViewer
|
||||||
editor={editorElement}
|
editor={editorElement}
|
||||||
show={resolvedMode === 'page'}
|
show={mode === 'page'}
|
||||||
openOutlinePanel={openOutlinePanel}
|
openOutlinePanel={openOutlinePanel}
|
||||||
/>
|
/>
|
||||||
</Scrollable.Viewport>
|
</Scrollable.Viewport>
|
||||||
@@ -208,3 +178,39 @@ export function DocPeekPreview({
|
|||||||
</AffineErrorBoundary>
|
</AffineErrorBoundary>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function DocPeekPreview({
|
||||||
|
docId,
|
||||||
|
blockIds,
|
||||||
|
elementIds,
|
||||||
|
mode,
|
||||||
|
xywh,
|
||||||
|
}: {
|
||||||
|
docId: string;
|
||||||
|
blockIds?: string[];
|
||||||
|
elementIds?: string[];
|
||||||
|
mode?: DocMode;
|
||||||
|
xywh?: `[${number},${number},${number},${number}]`;
|
||||||
|
}) {
|
||||||
|
const { doc, editor, loading } = useEditor(docId, mode, {
|
||||||
|
blockIds,
|
||||||
|
elementIds,
|
||||||
|
});
|
||||||
|
|
||||||
|
// if sync engine has been synced and the page is null, show 404 page.
|
||||||
|
if (!doc || !editor) {
|
||||||
|
return loading ? (
|
||||||
|
<PageDetailSkeleton key="current-page-is-null" />
|
||||||
|
) : (
|
||||||
|
<PageNotFound noPermission />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FrameworkScope scope={doc.scope}>
|
||||||
|
<FrameworkScope scope={editor.scope}>
|
||||||
|
<DocPeekPreviewEditor xywh={xywh} />
|
||||||
|
</FrameworkScope>
|
||||||
|
</FrameworkScope>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -41,12 +41,9 @@ export const useEditor = (
|
|||||||
if (!doc) {
|
if (!doc) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const editor = doc.scope
|
const editor = doc.scope.get(EditorsService).createEditor();
|
||||||
.get(EditorsService)
|
editor.setMode(preferModeRef.current || doc.primaryMode$.value);
|
||||||
.createEditor(
|
editor.setSelector(preferSelectorRef.current);
|
||||||
preferModeRef.current || doc.primaryMode$.value,
|
|
||||||
preferSelectorRef.current
|
|
||||||
);
|
|
||||||
setEditor(editor);
|
setEditor(editor);
|
||||||
return () => {
|
return () => {
|
||||||
editor.dispose();
|
editor.dispose();
|
||||||
|
|||||||
@@ -86,9 +86,9 @@ export class View extends Entity<{
|
|||||||
parseBooleans: true,
|
parseBooleans: true,
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
return this.location$.map(
|
return this.location$
|
||||||
location => queryString.parse(location.search, options) as Partial<T>
|
.selector(v => v.search)
|
||||||
);
|
.map(search => queryString.parse(search, options) as Partial<T>);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateQueryString<T extends Record<string, unknown>>(
|
updateQueryString<T extends Record<string, unknown>>(
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
export { View as WorkbenchView } from './entities/view';
|
||||||
export { Workbench } from './entities/workbench';
|
export { Workbench } from './entities/workbench';
|
||||||
export { ViewScope } from './scopes/view';
|
export { ViewScope } from './scopes/view';
|
||||||
export { WorkbenchService } from './services/workbench';
|
export { WorkbenchService } from './services/workbench';
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import type { Editor } from '@affine/core/modules/editor';
|
import type { Editor } from '@affine/core/modules/editor';
|
||||||
import { EditorsService } from '@affine/core/modules/editor';
|
import { EditorsService } from '@affine/core/modules/editor';
|
||||||
import { ViewService } from '@affine/core/modules/workbench/services/view';
|
import { ViewService } from '@affine/core/modules/workbench/services/view';
|
||||||
import { type DocMode, DocModes } from '@blocksuite/blocks';
|
|
||||||
import type { Doc } from '@toeverything/infra';
|
import type { Doc } from '@toeverything/infra';
|
||||||
import {
|
import {
|
||||||
DocsService,
|
DocsService,
|
||||||
@@ -26,80 +25,24 @@ const useLoadDoc = (pageId: string) => {
|
|||||||
const docRecord = useLiveData(docRecordList.doc$(pageId));
|
const docRecord = useLiveData(docRecordList.doc$(pageId));
|
||||||
const viewService = useService(ViewService);
|
const viewService = useService(ViewService);
|
||||||
|
|
||||||
const queryString$ = viewService.view.queryString$<{
|
|
||||||
mode?: string;
|
|
||||||
blockIds?: string[];
|
|
||||||
elementIds?: string[];
|
|
||||||
}>({
|
|
||||||
// Cannot handle single id situation correctly: `blockIds=xxx`
|
|
||||||
arrayFormat: 'none',
|
|
||||||
types: {
|
|
||||||
mode: 'string',
|
|
||||||
blockIds: value => (value.length ? value.split(',') : []),
|
|
||||||
elementIds: value => (value.length ? value.split(',') : []),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const modeInQuery = useLiveData(
|
|
||||||
queryString$.map(q => {
|
|
||||||
if (q.mode && DocModes.includes(q.mode as DocMode)) {
|
|
||||||
return q.mode as DocMode;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
// We only read the querystring mode when entering, so use useState here.
|
|
||||||
const [initialQueryStringSelector] = useState(() => {
|
|
||||||
const { blockIds, elementIds } = queryString$.value;
|
|
||||||
return { blockIds, elementIds };
|
|
||||||
});
|
|
||||||
|
|
||||||
const [doc, setDoc] = useState<Doc | null>(null);
|
const [doc, setDoc] = useState<Doc | null>(null);
|
||||||
const [editor, setEditor] = useState<Editor | null>(null);
|
const [editor, setEditor] = useState<Editor | null>(null);
|
||||||
const editorMode = useLiveData(editor?.mode$);
|
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
if (!docRecord) {
|
if (!docRecord) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { doc: opened, release } = docsService.open(pageId);
|
const { doc, release } = docsService.open(pageId);
|
||||||
setDoc(opened);
|
setDoc(doc);
|
||||||
return () => {
|
const editor = doc.scope.get(EditorsService).createEditor();
|
||||||
release();
|
const unbind = editor.bindWorkbenchView(viewService.view);
|
||||||
};
|
|
||||||
}, [docRecord, docsService, pageId]);
|
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
|
||||||
if (!doc) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const editor = doc.scope
|
|
||||||
.get(EditorsService)
|
|
||||||
.createEditor(
|
|
||||||
modeInQuery || doc.getPrimaryMode() || ('page' as DocMode),
|
|
||||||
initialQueryStringSelector
|
|
||||||
);
|
|
||||||
setEditor(editor);
|
setEditor(editor);
|
||||||
return () => {
|
return () => {
|
||||||
|
unbind();
|
||||||
editor.dispose();
|
editor.dispose();
|
||||||
|
release();
|
||||||
};
|
};
|
||||||
}, [doc, modeInQuery, initialQueryStringSelector]);
|
}, [docRecord, docsService, pageId, viewService.view]);
|
||||||
|
|
||||||
// update editor mode to queryString
|
|
||||||
useEffect(() => {
|
|
||||||
if (editorMode) {
|
|
||||||
viewService.view.updateQueryString(
|
|
||||||
{
|
|
||||||
mode: editorMode,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
replace: true,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}, [editorMode, viewService.view]);
|
|
||||||
|
|
||||||
// set sync engine priority target
|
// set sync engine priority target
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ import {
|
|||||||
WorkspaceService,
|
WorkspaceService,
|
||||||
} from '@toeverything/infra';
|
} from '@toeverything/infra';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { memo, useCallback, useEffect, useRef, useState } from 'react';
|
import { memo, useCallback, useEffect, useRef } from 'react';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import type { Map as YMap } from 'yjs';
|
import type { Map as YMap } from 'yjs';
|
||||||
|
|
||||||
@@ -93,7 +93,6 @@ const DetailPageImpl = memo(function DetailPageImpl() {
|
|||||||
const isInTrash = useLiveData(doc.meta$.map(meta => meta.trash));
|
const isInTrash = useLiveData(doc.meta$.map(meta => meta.trash));
|
||||||
const { openPage, jumpToPageBlock, jumpToTag } = useNavigateHelper();
|
const { openPage, jumpToPageBlock, jumpToTag } = useNavigateHelper();
|
||||||
const editorContainer = useLiveData(editor.editorContainer$);
|
const editorContainer = useLiveData(editor.editorContainer$);
|
||||||
const [defaultSelector] = useState(() => editor.selector$.value);
|
|
||||||
|
|
||||||
const isSideBarOpen = useLiveData(workbench.sidebarOpen$);
|
const isSideBarOpen = useLiveData(workbench.sidebarOpen$);
|
||||||
const { appSettings } = useAppSettingHelper();
|
const { appSettings } = useAppSettingHelper();
|
||||||
@@ -290,7 +289,6 @@ const DetailPageImpl = memo(function DetailPageImpl() {
|
|||||||
pageId={doc.id}
|
pageId={doc.id}
|
||||||
onLoad={onLoad}
|
onLoad={onLoad}
|
||||||
docCollection={docCollection}
|
docCollection={docCollection}
|
||||||
defaultEditorSelector={defaultSelector}
|
|
||||||
/>
|
/>
|
||||||
</Scrollable.Viewport>
|
</Scrollable.Viewport>
|
||||||
<Scrollable.Scrollbar
|
<Scrollable.Scrollbar
|
||||||
|
|||||||
@@ -159,7 +159,8 @@ const SharePageInner = ({
|
|||||||
|
|
||||||
setPage(doc);
|
setPage(doc);
|
||||||
|
|
||||||
const editor = doc.scope.get(EditorsService).createEditor(publishMode);
|
const editor = doc.scope.get(EditorsService).createEditor();
|
||||||
|
editor.setMode(publishMode);
|
||||||
|
|
||||||
setEditor(editor);
|
setEditor(editor);
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user