mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-21 16:26:58 +08:00
feat: allow peek view to be closed by the caller && bump bs (#8542)
depends on https://github.com/toeverything/blocksuite/pull/8558 fix BS-1570
This commit is contained in:
@@ -21,7 +21,7 @@ import {
|
||||
} from '@blocksuite/affine/blocks';
|
||||
import {
|
||||
Bound,
|
||||
getElementsBound,
|
||||
getCommonBoundWithRotation,
|
||||
type SerializedXYWH,
|
||||
} from '@blocksuite/affine/global/utils';
|
||||
import type { Doc } from '@blocksuite/affine/store';
|
||||
@@ -398,7 +398,7 @@ const ADD_TO_EDGELESS_AS_NOTE = {
|
||||
};
|
||||
|
||||
if (elements.length > 0) {
|
||||
const bound = getElementsBound(
|
||||
const bound = getCommonBoundWithRotation(
|
||||
elements.map(e => Bound.deserialize(e.xywh))
|
||||
);
|
||||
const newBound = new Bound(bound.x, bound.maxY + 10, bound.w);
|
||||
@@ -494,7 +494,7 @@ const CREATE_AS_LINKED_DOC = {
|
||||
let y = 0;
|
||||
if (elements.length) {
|
||||
// Calculate the bound of the selected elements first
|
||||
const bound = getElementsBound(
|
||||
const bound = getCommonBoundWithRotation(
|
||||
elements.map(e => Bound.deserialize(e.xywh))
|
||||
);
|
||||
x = bound.x;
|
||||
|
||||
@@ -6,7 +6,7 @@ import type {
|
||||
import {
|
||||
type AIItemGroupConfig,
|
||||
type AISubItemConfig,
|
||||
type CopilotSelectionController,
|
||||
type CopilotTool,
|
||||
EDGELESS_ELEMENT_TOOLBAR_WIDGET,
|
||||
type EdgelessElementToolbarWidget,
|
||||
matchFlavours,
|
||||
@@ -251,10 +251,9 @@ function edgelessHandler<T extends keyof BlockSuitePresets.AIActions>(
|
||||
if (!edgeless) {
|
||||
AIProvider.slots.requestRunInEdgeless.emit({ host });
|
||||
} else {
|
||||
edgeless.tools.setEdgelessTool({ type: 'copilot' });
|
||||
const currentController = edgeless.tools.controllers[
|
||||
'copilot'
|
||||
] as CopilotSelectionController;
|
||||
edgeless.gfx.tool.setTool({ type: 'copilot' });
|
||||
const currentController =
|
||||
edgeless.gfx.tool.currentTool$.peek() as CopilotTool;
|
||||
const selectedElements = edgeless.service.selection.selectedElements;
|
||||
currentController.updateDragPointsWith(selectedElements, 10);
|
||||
currentController.draggingAreaUpdated.emit(false); // do not show edgeless panel
|
||||
|
||||
@@ -388,7 +388,8 @@ function updateEdgelessAIPanelConfig<
|
||||
config.hideCallback = () => {
|
||||
aiPanel.updateComplete
|
||||
.finally(() => {
|
||||
edgelessCopilot.edgeless.service.tool.switchToDefaultMode({
|
||||
edgelessCopilot.edgeless.gfx.tool.setTool('default');
|
||||
edgelessCopilot.edgeless.gfx.selection.set({
|
||||
elements: [],
|
||||
editing: false,
|
||||
});
|
||||
|
||||
@@ -10,6 +10,7 @@ import type {
|
||||
SurfaceBlockModel,
|
||||
} from '@blocksuite/affine/blocks';
|
||||
import {
|
||||
addImages,
|
||||
DeleteIcon,
|
||||
EDGELESS_ELEMENT_TOOLBAR_WIDGET,
|
||||
EDGELESS_TEXT_BLOCK_MIN_HEIGHT,
|
||||
@@ -312,8 +313,7 @@ const imageHandler = (host: EditorHost) => {
|
||||
const [x, y] = edgelessRoot.service.viewport.toViewCoord(minX, minY);
|
||||
|
||||
host.doc.transact(() => {
|
||||
edgelessRoot
|
||||
.addImages([img], [x, y])
|
||||
addImages(edgelessRoot.std, [img], [x, y])
|
||||
.then(blockIds => {
|
||||
const imageBlockId = blockIds[0];
|
||||
const imageBlock = host.doc.getBlock(imageBlockId);
|
||||
@@ -413,7 +413,7 @@ export const responses: {
|
||||
const mindmap = elements[0].group as MindmapElementModel;
|
||||
const xywh = mindmap.tree.element.xywh;
|
||||
|
||||
surface.removeElement(mindmap.id);
|
||||
surface.deleteElement(mindmap.id);
|
||||
|
||||
if (data.node) {
|
||||
data.node.xywh = xywh;
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
EdgelessCopilotWidget,
|
||||
EdgelessElementToolbarWidget,
|
||||
EdgelessRootBlockSpec,
|
||||
edgelessRootWigetViewMap,
|
||||
edgelessRootWidgetViewMap,
|
||||
ImageBlockSpec,
|
||||
PageRootBlockSpec,
|
||||
pageRootWidgetViewMap,
|
||||
@@ -114,7 +114,7 @@ export const AIEdgelessRootBlockSpec: ExtensionType[] = [
|
||||
setup: di => {
|
||||
di.override(WidgetViewMapIdentifier('affine:page'), () => {
|
||||
return {
|
||||
...edgelessRootWigetViewMap,
|
||||
...edgelessRootWidgetViewMap,
|
||||
[AFFINE_EDGELESS_COPILOT_WIDGET]: literal`${unsafeStatic(
|
||||
AFFINE_EDGELESS_COPILOT_WIDGET
|
||||
)}`,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { EditorHost } from '@blocksuite/affine/block-std';
|
||||
import {
|
||||
type CopilotSelectionController,
|
||||
type CopilotTool,
|
||||
type FrameBlockModel,
|
||||
ImageBlockModel,
|
||||
type SurfaceBlockComponent,
|
||||
@@ -279,7 +279,7 @@ export function getCopilotSelectedElems(
|
||||
const copilotWidget = getEdgelessCopilotWidget(host);
|
||||
|
||||
if (copilotWidget.visible) {
|
||||
return (service.tool.controllers['copilot'] as CopilotSelectionController)
|
||||
return (service.gfx.tool.currentTool$.peek() as CopilotTool)
|
||||
.selectedElements;
|
||||
}
|
||||
|
||||
|
||||
@@ -83,7 +83,11 @@ export function AffinePageReference({
|
||||
if (e.shiftKey && ref.current) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
peekView.open(ref.current).catch(console.error);
|
||||
peekView
|
||||
.open({
|
||||
element: ref.current,
|
||||
})
|
||||
.catch(console.error);
|
||||
}
|
||||
|
||||
if (isInPeekView) {
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
useRef,
|
||||
} from 'react';
|
||||
|
||||
import type { DefaultOpenProperty } from '../../doc-properties';
|
||||
import { BlocksuiteDocEditor, BlocksuiteEdgelessEditor } from './lit-adaper';
|
||||
import * as styles from './styles.css';
|
||||
|
||||
@@ -29,6 +30,7 @@ interface BlocksuiteEditorContainerProps {
|
||||
mode: DocMode;
|
||||
shared?: boolean;
|
||||
className?: string;
|
||||
defaultOpenProperty?: DefaultOpenProperty;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
|
||||
@@ -43,7 +45,7 @@ export const BlocksuiteEditorContainer = forwardRef<
|
||||
AffineEditorContainer,
|
||||
BlocksuiteEditorContainerProps
|
||||
>(function AffineEditorContainer(
|
||||
{ page, mode, className, style, shared },
|
||||
{ page, mode, className, style, shared, defaultOpenProperty },
|
||||
ref
|
||||
) {
|
||||
const rootRef = useRef<HTMLDivElement>(null);
|
||||
@@ -171,6 +173,7 @@ export const BlocksuiteEditorContainer = forwardRef<
|
||||
ref={docRef}
|
||||
titleRef={docTitleRef}
|
||||
onClickBlank={handleClickPageModeBlank}
|
||||
defaultOpenProperty={defaultOpenProperty}
|
||||
/>
|
||||
) : (
|
||||
<BlocksuiteEdgelessEditor
|
||||
|
||||
@@ -16,6 +16,7 @@ import { use } from 'foxact/use';
|
||||
import type { CSSProperties } from 'react';
|
||||
import { Suspense, useEffect } from 'react';
|
||||
|
||||
import type { DefaultOpenProperty } from '../../doc-properties';
|
||||
import { BlocksuiteEditorContainer } from './blocksuite-editor-container';
|
||||
import { NoPageRootError } from './no-page-error';
|
||||
|
||||
@@ -23,6 +24,7 @@ export type EditorProps = {
|
||||
page: Doc;
|
||||
mode: DocMode;
|
||||
shared?: boolean;
|
||||
defaultOpenProperty?: DefaultOpenProperty;
|
||||
// on Editor ready
|
||||
onEditorReady?: (editor: AffineEditorContainer) => (() => void) | void;
|
||||
style?: CSSProperties;
|
||||
@@ -58,6 +60,7 @@ const BlockSuiteEditorImpl = ({
|
||||
shared,
|
||||
style,
|
||||
onEditorReady,
|
||||
defaultOpenProperty,
|
||||
}: EditorProps) => {
|
||||
usePageRoot(page);
|
||||
|
||||
@@ -134,6 +137,7 @@ const BlockSuiteEditorImpl = ({
|
||||
mode={mode}
|
||||
page={page}
|
||||
shared={shared}
|
||||
defaultOpenProperty={defaultOpenProperty}
|
||||
ref={editorRef}
|
||||
className={className}
|
||||
style={style}
|
||||
|
||||
@@ -39,7 +39,10 @@ import {
|
||||
AffinePageReference,
|
||||
AffineSharedPageReference,
|
||||
} from '../../affine/reference-link';
|
||||
import { DocPropertiesTable } from '../../doc-properties';
|
||||
import {
|
||||
type DefaultOpenProperty,
|
||||
DocPropertiesTable,
|
||||
} from '../../doc-properties';
|
||||
import { BiDirectionalLinkPanel } from './bi-directional-link-panel';
|
||||
import { BlocksuiteEditorJournalDocTitle } from './journal-doc-title';
|
||||
import {
|
||||
@@ -76,6 +79,7 @@ const adapted = {
|
||||
interface BlocksuiteEditorProps {
|
||||
page: Doc;
|
||||
shared?: boolean;
|
||||
defaultOpenProperty?: DefaultOpenProperty;
|
||||
}
|
||||
|
||||
const usePatchSpecs = (shared: boolean, mode: DocMode) => {
|
||||
@@ -191,7 +195,13 @@ export const BlocksuiteDocEditor = forwardRef<
|
||||
titleRef?: React.Ref<DocTitle>;
|
||||
}
|
||||
>(function BlocksuiteDocEditor(
|
||||
{ page, shared, onClickBlank, titleRef: externalTitleRef },
|
||||
{
|
||||
page,
|
||||
shared,
|
||||
onClickBlank,
|
||||
titleRef: externalTitleRef,
|
||||
defaultOpenProperty,
|
||||
},
|
||||
ref
|
||||
) {
|
||||
const titleRef = useRef<DocTitle | null>(null);
|
||||
@@ -245,7 +255,9 @@ export const BlocksuiteDocEditor = forwardRef<
|
||||
) : (
|
||||
<BlocksuiteEditorJournalDocTitle page={page} />
|
||||
)}
|
||||
{!shared ? <DocPropertiesTable /> : null}
|
||||
{!shared ? (
|
||||
<DocPropertiesTable defaultOpenProperty={defaultOpenProperty} />
|
||||
) : null}
|
||||
<adapted.DocEditor
|
||||
className={styles.docContainer}
|
||||
ref={onDocRef}
|
||||
|
||||
@@ -9,7 +9,9 @@ import {
|
||||
type ExtensionType,
|
||||
} from '@blocksuite/affine/block-std';
|
||||
import {
|
||||
EdgelessBuiltInManager,
|
||||
EdgelessRootBlockSpec,
|
||||
EdgelessToolExtension,
|
||||
EditorSettingExtension,
|
||||
FontLoaderService,
|
||||
PageRootBlockSpec,
|
||||
@@ -74,6 +76,8 @@ export function createEdgelessRootBlockSpec(
|
||||
return [
|
||||
enableAI ? AIEdgelessRootBlockSpec : EdgelessRootBlockSpec,
|
||||
FontLoaderService,
|
||||
EdgelessToolExtension,
|
||||
EdgelessBuiltInManager,
|
||||
getFontConfigExtension(),
|
||||
getTelemetryExtension(),
|
||||
getEditorConfigExtension(framework),
|
||||
|
||||
@@ -11,7 +11,6 @@ import type { EditorService } from '@affine/core/modules/editor';
|
||||
import { EditorSettingService } from '@affine/core/modules/editor-settting';
|
||||
import { resolveLinkToDoc } from '@affine/core/modules/navigation';
|
||||
import type { PeekViewService } from '@affine/core/modules/peek-view';
|
||||
import type { ActivePeekView } from '@affine/core/modules/peek-view/entities/peek-view';
|
||||
import {
|
||||
CreationQuickSearchSession,
|
||||
DocsQuickSearchSession,
|
||||
@@ -35,6 +34,8 @@ import type {
|
||||
AffineReference,
|
||||
DocMode,
|
||||
DocModeProvider,
|
||||
PeekOptions,
|
||||
PeekViewService as BSPeekViewService,
|
||||
QuickSearchResult,
|
||||
RootService,
|
||||
} from '@blocksuite/affine/blocks';
|
||||
@@ -243,11 +244,28 @@ export function patchEmbedLinkedDocBlockConfig(framework: FrameworkProvider) {
|
||||
|
||||
export function patchPeekViewService(service: PeekViewService) {
|
||||
return PeekViewExtension({
|
||||
peek: (target: ActivePeekView['target'], template?: TemplateResult) => {
|
||||
logger.debug('center peek', target, template);
|
||||
return service.peekView.open(target, template);
|
||||
peek: (
|
||||
element: {
|
||||
target: HTMLElement;
|
||||
docId: string;
|
||||
blockIds?: string[];
|
||||
template?: TemplateResult;
|
||||
},
|
||||
options?: PeekOptions
|
||||
) => {
|
||||
logger.debug('center peek', element);
|
||||
const { template, target, ...props } = element;
|
||||
|
||||
return service.peekView.open(
|
||||
{
|
||||
element: target,
|
||||
docRef: props,
|
||||
},
|
||||
template,
|
||||
options?.abortSignal
|
||||
);
|
||||
},
|
||||
});
|
||||
} satisfies BSPeekViewService);
|
||||
}
|
||||
|
||||
export function patchDocModeService(
|
||||
|
||||
@@ -41,6 +41,20 @@ type DocBacklinksPopupProps = PropsWithChildren<{
|
||||
backlinks: { docId: string; blockId: string; title: string }[];
|
||||
}>;
|
||||
|
||||
export type DefaultOpenProperty =
|
||||
| {
|
||||
type: 'workspace';
|
||||
}
|
||||
| {
|
||||
type: 'database';
|
||||
databaseId: string;
|
||||
databaseRowId: string;
|
||||
};
|
||||
|
||||
export interface DocPropertiesTableProps {
|
||||
defaultOpenProperty?: DefaultOpenProperty;
|
||||
}
|
||||
|
||||
export const DocBacklinksPopup = ({
|
||||
backlinks,
|
||||
children,
|
||||
@@ -231,18 +245,19 @@ export const DocPropertyRow = ({
|
||||
);
|
||||
};
|
||||
|
||||
interface DocPropertiesTableBodyProps {
|
||||
interface DocWorkspacePropertiesTableBodyProps {
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
defaultOpen?: boolean;
|
||||
}
|
||||
|
||||
// 🏷️ Tags (⋅ xxx) (⋅ yyy)
|
||||
// #️⃣ Number 123456
|
||||
// + Add a property
|
||||
export const DocPropertiesTableBody = forwardRef<
|
||||
const DocWorkspacePropertiesTableBody = forwardRef<
|
||||
HTMLDivElement,
|
||||
DocPropertiesTableBodyProps & HTMLProps<HTMLDivElement>
|
||||
>(({ className, style, ...props }, ref) => {
|
||||
DocWorkspacePropertiesTableBodyProps & HTMLProps<HTMLDivElement>
|
||||
>(({ className, style, defaultOpen, ...props }, ref) => {
|
||||
const t = useI18n();
|
||||
const docsService = useService(DocsService);
|
||||
const workbenchService = useService(WorkbenchService);
|
||||
@@ -258,6 +273,7 @@ export const DocPropertiesTableBody = forwardRef<
|
||||
className={clsx(styles.tableBodyRoot, className)}
|
||||
style={style}
|
||||
title={t.t('com.affine.workspace.properties')}
|
||||
defaultCollapsed={!defaultOpen}
|
||||
{...props}
|
||||
>
|
||||
<PropertyCollapsibleContent
|
||||
@@ -334,10 +350,12 @@ export const DocPropertiesTableBody = forwardRef<
|
||||
</PropertyCollapsibleSection>
|
||||
);
|
||||
});
|
||||
DocPropertiesTableBody.displayName = 'PagePropertiesTableBody';
|
||||
DocWorkspacePropertiesTableBody.displayName = 'PagePropertiesTableBody';
|
||||
|
||||
const DocPropertiesTableInner = () => {
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
const DocPropertiesTableInner = ({
|
||||
defaultOpenProperty,
|
||||
}: DocPropertiesTableProps) => {
|
||||
const [expanded, setExpanded] = useState(!!defaultOpenProperty);
|
||||
return (
|
||||
<div className={styles.root}>
|
||||
<Collapsible.Root
|
||||
@@ -347,9 +365,24 @@ const DocPropertiesTableInner = () => {
|
||||
>
|
||||
<DocPropertiesTableHeader open={expanded} onOpenChange={setExpanded} />
|
||||
<Collapsible.Content>
|
||||
<DocPropertiesTableBody />
|
||||
<DocWorkspacePropertiesTableBody
|
||||
defaultOpen={
|
||||
!defaultOpenProperty || defaultOpenProperty.type === 'workspace'
|
||||
}
|
||||
/>
|
||||
<div className={styles.tableHeaderDivider} />
|
||||
<DocDatabaseBacklinkInfo />
|
||||
<DocDatabaseBacklinkInfo
|
||||
defaultOpen={
|
||||
defaultOpenProperty?.type === 'database'
|
||||
? [
|
||||
{
|
||||
databaseId: defaultOpenProperty.databaseId,
|
||||
rowId: defaultOpenProperty.databaseRowId,
|
||||
},
|
||||
]
|
||||
: []
|
||||
}
|
||||
/>
|
||||
</Collapsible.Content>
|
||||
</Collapsible.Root>
|
||||
</div>
|
||||
@@ -358,6 +391,8 @@ const DocPropertiesTableInner = () => {
|
||||
|
||||
// this is the main component that renders the page properties table at the top of the page below
|
||||
// the page title
|
||||
export const DocPropertiesTable = () => {
|
||||
return <DocPropertiesTableInner />;
|
||||
export const DocPropertiesTable = ({
|
||||
defaultOpenProperty,
|
||||
}: DocPropertiesTableProps) => {
|
||||
return <DocPropertiesTableInner defaultOpenProperty={defaultOpenProperty} />;
|
||||
};
|
||||
|
||||
@@ -31,6 +31,7 @@ export interface PageDetailEditorProps {
|
||||
export const PageDetailEditor = ({ onLoad }: PageDetailEditorProps) => {
|
||||
const editor = useService(EditorService).editor;
|
||||
const mode = useLiveData(editor.mode$);
|
||||
const defaultOpenProperty = useLiveData(editor.defaultOpenProperty$);
|
||||
|
||||
const isSharedMode = editor.isSharedMode;
|
||||
const editorSetting = useService(EditorSettingService).editorSetting;
|
||||
@@ -68,6 +69,7 @@ export const PageDetailEditor = ({ onLoad }: PageDetailEditorProps) => {
|
||||
} as CSSProperties
|
||||
}
|
||||
mode={mode}
|
||||
defaultOpenProperty={defaultOpenProperty}
|
||||
page={editor.doc.blockSuiteDoc}
|
||||
shared={isSharedMode}
|
||||
onEditorReady={onLoad}
|
||||
|
||||
@@ -152,19 +152,12 @@ const WorkspacePage = ({ meta }: { meta: WorkspaceMetadata }) => {
|
||||
})
|
||||
);
|
||||
window.exportWorkspaceSnapshot = async (docs?: string[]) => {
|
||||
const zip = await ZipTransformer.exportDocs(
|
||||
await ZipTransformer.exportDocs(
|
||||
workspace.docCollection,
|
||||
Array.from(workspace.docCollection.docs.values())
|
||||
.filter(doc => (docs ? docs.includes(doc.id) : true))
|
||||
.map(doc => doc.getDoc())
|
||||
);
|
||||
const url = URL.createObjectURL(zip);
|
||||
// download url
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = `${workspace.docCollection.meta.name}.zip`;
|
||||
a.click();
|
||||
URL.revokeObjectURL(url);
|
||||
};
|
||||
window.importWorkspaceSnapshot = async () => {
|
||||
const input = document.createElement('input');
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { Divider, Scrollable } from '@affine/component';
|
||||
import { DocPropertiesTable } from '@affine/core/components/doc-properties';
|
||||
import {
|
||||
type DefaultOpenProperty,
|
||||
DocPropertiesTable,
|
||||
} from '@affine/core/components/doc-properties';
|
||||
import { LinksRow } from '@affine/core/components/doc-properties/info-modal/links-row';
|
||||
import { TimeRow } from '@affine/core/components/doc-properties/info-modal/time-row';
|
||||
import { DocsSearchService } from '@affine/core/modules/docs-search';
|
||||
@@ -9,7 +12,13 @@ import { Suspense, useMemo } from 'react';
|
||||
|
||||
import * as styles from './doc-info.css';
|
||||
|
||||
export const DocInfoSheet = ({ docId }: { docId: string }) => {
|
||||
export const DocInfoSheet = ({
|
||||
docId,
|
||||
defaultOpenProperty,
|
||||
}: {
|
||||
docId: string;
|
||||
defaultOpenProperty?: DefaultOpenProperty;
|
||||
}) => {
|
||||
const docsSearchService = useService(DocsSearchService);
|
||||
const t = useI18n();
|
||||
|
||||
@@ -52,7 +61,7 @@ export const DocInfoSheet = ({ docId }: { docId: string }) => {
|
||||
<Divider size="thinner" />
|
||||
</>
|
||||
) : null}
|
||||
<DocPropertiesTable />
|
||||
<DocPropertiesTable defaultOpenProperty={defaultOpenProperty} />
|
||||
</Suspense>
|
||||
</Scrollable.Viewport>
|
||||
<Scrollable.Scrollbar className={styles.scrollBar} />
|
||||
|
||||
@@ -95,6 +95,14 @@ const DatabaseBacklinkRow = ({
|
||||
}, [row?.cells]);
|
||||
const t = useI18n();
|
||||
|
||||
const pageRefParams = useMemo(() => {
|
||||
const params = new URLSearchParams();
|
||||
if (row?.id) {
|
||||
params.set('blockIds', row.databaseId);
|
||||
}
|
||||
return params;
|
||||
}, [row]);
|
||||
|
||||
if (!row || !sortedCells) {
|
||||
return null;
|
||||
}
|
||||
@@ -105,7 +113,11 @@ const DatabaseBacklinkRow = ({
|
||||
defaultCollapsed={!defaultOpen}
|
||||
icon={<DatabaseTableViewIcon />}
|
||||
suffix={
|
||||
<AffinePageReference className={styles.docRefLink} pageId={row.docId} />
|
||||
<AffinePageReference
|
||||
className={styles.docRefLink}
|
||||
pageId={row.docId}
|
||||
params={pageRefParams}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<PropertyCollapsibleContent
|
||||
@@ -131,8 +143,8 @@ export const DocDatabaseBacklinkInfo = ({
|
||||
defaultOpen = [],
|
||||
}: {
|
||||
defaultOpen?: {
|
||||
docId: string;
|
||||
blockId: string;
|
||||
databaseId: string;
|
||||
rowId: string;
|
||||
}[];
|
||||
}) => {
|
||||
const doc = useService(DocService).doc;
|
||||
@@ -151,11 +163,13 @@ export const DocDatabaseBacklinkInfo = ({
|
||||
|
||||
return (
|
||||
<div className={styles.root}>
|
||||
{rows.map(({ docId, rowId, row$ }) => (
|
||||
{rows.map(({ docId, databaseBlockId, rowId, row$ }) => (
|
||||
<Fragment key={`${docId}-${rowId}`}>
|
||||
<DatabaseBacklinkRow
|
||||
defaultOpen={defaultOpen?.some(
|
||||
backlink => backlink.docId === docId && backlink.blockId === rowId
|
||||
backlink =>
|
||||
backlink.databaseId === databaseBlockId &&
|
||||
backlink.rowId === rowId
|
||||
)}
|
||||
row$={row$}
|
||||
/>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { DefaultOpenProperty } from '@affine/core/components/doc-properties';
|
||||
import type {
|
||||
DocMode,
|
||||
EdgelessRootService,
|
||||
@@ -8,6 +9,7 @@ import type {
|
||||
DocTitle,
|
||||
} from '@blocksuite/affine/presets';
|
||||
import type { InlineEditor } from '@blocksuite/inline';
|
||||
import { effect } from '@preact/signals-core';
|
||||
import type { DocService, WorkspaceService } from '@toeverything/infra';
|
||||
import { Entity, LiveData } from '@toeverything/infra';
|
||||
import { defaults, isEqual, omit } from 'lodash-es';
|
||||
@@ -29,6 +31,9 @@ export class Editor extends Entity {
|
||||
this.workspaceService.workspace.openOptions.isSharedMode;
|
||||
|
||||
readonly editorContainer$ = new LiveData<AffineEditorContainer | null>(null);
|
||||
readonly defaultOpenProperty$ = new LiveData<DefaultOpenProperty | undefined>(
|
||||
undefined
|
||||
);
|
||||
|
||||
isPresenting$ = new LiveData<boolean>(false);
|
||||
|
||||
@@ -39,7 +44,7 @@ export class Editor extends Entity {
|
||||
) as EdgelessRootService;
|
||||
if (!edgelessRootService) return;
|
||||
|
||||
edgelessRootService.tool.setEdgelessTool({
|
||||
edgelessRootService.gfx.tool.setTool({
|
||||
type: !this.isPresenting$.value ? 'frameNavigator' : 'default',
|
||||
});
|
||||
}
|
||||
@@ -60,6 +65,10 @@ export class Editor extends Entity {
|
||||
this.editorContainer$.next(editorContainer);
|
||||
}
|
||||
|
||||
setDefaultOpenProperty(defaultOpenProperty: DefaultOpenProperty | undefined) {
|
||||
this.defaultOpenProperty$.next(defaultOpenProperty);
|
||||
}
|
||||
|
||||
/**
|
||||
* sync editor params with view query string
|
||||
*/
|
||||
@@ -102,6 +111,17 @@ export class Editor extends Entity {
|
||||
if (!isEqual(selector, omit(editorParams, ['mode']))) {
|
||||
this.setSelector(selector);
|
||||
}
|
||||
|
||||
if (params.databaseId && params.databaseRowId) {
|
||||
const defaultOpenProperty: DefaultOpenProperty = {
|
||||
type: 'database',
|
||||
databaseId: params.databaseId,
|
||||
databaseRowId: params.databaseRowId,
|
||||
};
|
||||
if (!isEqual(defaultOpenProperty, this.defaultOpenProperty$.value)) {
|
||||
this.setDefaultOpenProperty(defaultOpenProperty);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
updating = false;
|
||||
}
|
||||
@@ -194,15 +214,15 @@ export class Editor extends Entity {
|
||||
this.isPresenting$.next(false);
|
||||
} else {
|
||||
this.isPresenting$.next(
|
||||
edgelessPage.edgelessTool.type === 'frameNavigator'
|
||||
edgelessPage.gfx.tool.currentToolName$.peek() === 'frameNavigator'
|
||||
);
|
||||
|
||||
const disposable = edgelessPage.slots.edgelessToolUpdated.on(() => {
|
||||
const disposable = effect(() => {
|
||||
this.isPresenting$.next(
|
||||
edgelessPage.edgelessTool.type === 'frameNavigator'
|
||||
edgelessPage.gfx.tool.currentToolName$.value === 'frameNavigator'
|
||||
);
|
||||
});
|
||||
unsubs.push(disposable.dispose.bind(disposable));
|
||||
unsubs.push(disposable);
|
||||
}
|
||||
|
||||
return () => {
|
||||
|
||||
@@ -129,7 +129,14 @@ export const preprocessParams = (
|
||||
result.elementIds = result.elementIds.filter(v => v.length);
|
||||
}
|
||||
|
||||
return pick(result, ['mode', 'blockIds', 'elementIds', 'refreshKey']);
|
||||
return pick(result, [
|
||||
'mode',
|
||||
'blockIds',
|
||||
'elementIds',
|
||||
'databaseId',
|
||||
'databaseRowId',
|
||||
'refreshKey',
|
||||
]);
|
||||
};
|
||||
|
||||
export const paramsParseOptions: ParseOptions = {
|
||||
@@ -142,6 +149,8 @@ export const paramsParseOptions: ParseOptions = {
|
||||
value.length ? value.split(',').filter(v => v.length) : [],
|
||||
elementIds: value =>
|
||||
value.length ? value.split(',').filter(v => v.length) : [],
|
||||
databaseId: 'string',
|
||||
databaseRowId: 'string',
|
||||
refreshKey: 'string',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -17,31 +17,43 @@ import { firstValueFrom, map, race } from 'rxjs';
|
||||
import { resolveLinkToDoc } from '../../navigation';
|
||||
import type { WorkbenchService } from '../../workbench';
|
||||
|
||||
export type PeekViewTarget =
|
||||
| HTMLElement
|
||||
| BlockComponent
|
||||
| AffineReference
|
||||
| HTMLAnchorElement
|
||||
| { docId: string; blockIds?: string[] };
|
||||
|
||||
export interface DocPeekViewInfo {
|
||||
type: 'doc';
|
||||
export type DocReferenceInfo = {
|
||||
docId: string;
|
||||
mode?: DocMode;
|
||||
blockIds?: string[];
|
||||
elementIds?: string[];
|
||||
databaseId?: string;
|
||||
databaseRowId?: string;
|
||||
/**
|
||||
* viewport in edgeless mode
|
||||
*/
|
||||
xywh?: `[${number},${number},${number},${number}]`;
|
||||
};
|
||||
|
||||
export type PeekViewElement =
|
||||
| HTMLElement
|
||||
| BlockComponent
|
||||
| AffineReference
|
||||
| HTMLAnchorElement;
|
||||
|
||||
export interface PeekViewTarget {
|
||||
element?: PeekViewElement;
|
||||
docRef?: DocReferenceInfo;
|
||||
}
|
||||
|
||||
export interface DocPeekViewInfo {
|
||||
type: 'doc';
|
||||
docRef: DocReferenceInfo;
|
||||
}
|
||||
|
||||
export type ImagePeekViewInfo = {
|
||||
type: 'image';
|
||||
docId: string;
|
||||
blockIds: [string];
|
||||
docRef: DocReferenceInfo;
|
||||
};
|
||||
|
||||
export type AIChatBlockPeekViewInfo = {
|
||||
type: 'ai-chat-block';
|
||||
docId: string;
|
||||
docRef: DocReferenceInfo;
|
||||
host: EditorHost;
|
||||
model: AIChatBlockModel;
|
||||
};
|
||||
@@ -101,83 +113,90 @@ function resolvePeekInfoFromPeekTarget(
|
||||
};
|
||||
}
|
||||
|
||||
if (peekTarget instanceof AffineReference) {
|
||||
const referenceInfo = peekTarget.referenceInfo;
|
||||
if (referenceInfo) {
|
||||
const { pageId: docId } = referenceInfo;
|
||||
const info: DocPeekViewInfo = {
|
||||
type: 'doc',
|
||||
docId,
|
||||
};
|
||||
Object.assign(info, referenceInfo.params);
|
||||
return info;
|
||||
}
|
||||
} else if ('model' in peekTarget) {
|
||||
const blockModel = peekTarget.model;
|
||||
if (isEmbedLinkedDocModel(blockModel)) {
|
||||
const info: DocPeekViewInfo = {
|
||||
type: 'doc',
|
||||
docId: blockModel.pageId,
|
||||
};
|
||||
Object.assign(info, blockModel.params);
|
||||
return info;
|
||||
} else if (isEmbedSyncedDocModel(blockModel)) {
|
||||
return {
|
||||
type: 'doc',
|
||||
docId: blockModel.pageId,
|
||||
};
|
||||
} else if (isSurfaceRefModel(blockModel)) {
|
||||
const refModel = (peekTarget as SurfaceRefBlockComponent).referenceModel;
|
||||
// refModel can be null if the reference is invalid
|
||||
if (refModel) {
|
||||
const docId =
|
||||
'doc' in refModel ? refModel.doc.id : refModel.surface.doc.id;
|
||||
const element = peekTarget.element;
|
||||
|
||||
if (element) {
|
||||
if (element instanceof AffineReference) {
|
||||
const referenceInfo = element.referenceInfo;
|
||||
if (referenceInfo) {
|
||||
const { pageId: docId } = referenceInfo;
|
||||
const info: DocPeekViewInfo = {
|
||||
type: 'doc',
|
||||
docRef: {
|
||||
docId,
|
||||
},
|
||||
};
|
||||
Object.assign(info, referenceInfo.params);
|
||||
return info;
|
||||
}
|
||||
} else if ('model' in element) {
|
||||
const blockModel = element.model;
|
||||
if (isEmbedLinkedDocModel(blockModel)) {
|
||||
const info: DocPeekViewInfo = {
|
||||
type: 'doc',
|
||||
docRef: {
|
||||
docId: blockModel.pageId,
|
||||
},
|
||||
};
|
||||
Object.assign(info, blockModel.params);
|
||||
return info;
|
||||
} else if (isEmbedSyncedDocModel(blockModel)) {
|
||||
return {
|
||||
type: 'doc',
|
||||
docId,
|
||||
mode: 'edgeless',
|
||||
xywh: refModel.xywh,
|
||||
docRef: {
|
||||
docId: blockModel.pageId,
|
||||
},
|
||||
};
|
||||
} else if (isSurfaceRefModel(blockModel)) {
|
||||
const refModel = (element as SurfaceRefBlockComponent).referenceModel;
|
||||
// refModel can be null if the reference is invalid
|
||||
if (refModel) {
|
||||
const docId =
|
||||
'doc' in refModel ? refModel.doc.id : refModel.surface.doc.id;
|
||||
return {
|
||||
type: 'doc',
|
||||
docRef: {
|
||||
docId,
|
||||
mode: 'edgeless',
|
||||
xywh: refModel.xywh,
|
||||
},
|
||||
};
|
||||
}
|
||||
} else if (isImageBlockModel(blockModel)) {
|
||||
return {
|
||||
type: 'image',
|
||||
docRef: {
|
||||
docId: blockModel.doc.id,
|
||||
blockIds: [blockModel.id],
|
||||
},
|
||||
};
|
||||
} else if (isAIChatBlockModel(blockModel)) {
|
||||
return {
|
||||
type: 'ai-chat-block',
|
||||
docRef: {
|
||||
docId: blockModel.doc.id,
|
||||
blockIds: [blockModel.id],
|
||||
},
|
||||
model: blockModel,
|
||||
host: element.host,
|
||||
};
|
||||
}
|
||||
} else if (isImageBlockModel(blockModel)) {
|
||||
return {
|
||||
type: 'image',
|
||||
docId: blockModel.doc.id,
|
||||
blockIds: [blockModel.id],
|
||||
};
|
||||
} else if (isAIChatBlockModel(blockModel)) {
|
||||
return {
|
||||
type: 'ai-chat-block',
|
||||
docId: blockModel.doc.id,
|
||||
model: blockModel,
|
||||
host: peekTarget.host,
|
||||
};
|
||||
} else if (element instanceof HTMLAnchorElement) {
|
||||
const maybeDoc = resolveLinkToDoc(element.href);
|
||||
if (maybeDoc) {
|
||||
const info: DocPeekViewInfo = {
|
||||
type: 'doc',
|
||||
docRef: maybeDoc,
|
||||
};
|
||||
return info;
|
||||
}
|
||||
}
|
||||
} else if (peekTarget instanceof HTMLAnchorElement) {
|
||||
const maybeDoc = resolveLinkToDoc(peekTarget.href);
|
||||
if (maybeDoc) {
|
||||
const info: DocPeekViewInfo = {
|
||||
type: 'doc',
|
||||
docId: maybeDoc.docId,
|
||||
};
|
||||
}
|
||||
|
||||
if (maybeDoc.mode) {
|
||||
info.mode = maybeDoc.mode;
|
||||
}
|
||||
if (maybeDoc.blockIds?.length) {
|
||||
info.blockIds = maybeDoc.blockIds;
|
||||
}
|
||||
if (maybeDoc.elementIds?.length) {
|
||||
info.elementIds = maybeDoc.elementIds;
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
} else if ('docId' in peekTarget) {
|
||||
if ('docRef' in peekTarget && peekTarget.docRef) {
|
||||
return {
|
||||
type: 'doc',
|
||||
docId: peekTarget.docId,
|
||||
blockIds: peekTarget.blockIds,
|
||||
docRef: peekTarget.docRef,
|
||||
};
|
||||
}
|
||||
return;
|
||||
@@ -208,7 +227,8 @@ export class PeekViewEntity extends Entity {
|
||||
// return true if the peek view will be handled
|
||||
open = async (
|
||||
target: ActivePeekView['target'],
|
||||
template?: TemplateResult
|
||||
template?: TemplateResult,
|
||||
abortSignal?: AbortSignal
|
||||
) => {
|
||||
const resolvedInfo = resolvePeekInfoFromPeekTarget(target, template);
|
||||
if (!resolvedInfo) {
|
||||
@@ -220,7 +240,7 @@ export class PeekViewEntity extends Entity {
|
||||
// if there is an active peek view and it is a doc peek view, we will navigate it first
|
||||
if (active?.info.type === 'doc' && this.show$.value?.value) {
|
||||
// TODO(@pengx17): scroll to the viewing position?
|
||||
this.workbenchService.workbench.openDoc(active.info.docId);
|
||||
this.workbenchService.workbench.openDoc(active.info.docRef);
|
||||
}
|
||||
|
||||
this._active$.next({ target, info: resolvedInfo });
|
||||
@@ -231,6 +251,24 @@ export class PeekViewEntity extends Entity {
|
||||
? 'zoom'
|
||||
: 'fade',
|
||||
});
|
||||
|
||||
if (abortSignal) {
|
||||
const abortListener = () => {
|
||||
if (this.active$.value?.target === target) {
|
||||
this.close();
|
||||
}
|
||||
};
|
||||
|
||||
abortSignal.addEventListener('abort', abortListener);
|
||||
|
||||
const showSubscription = this.show$.subscribe(v => {
|
||||
if (!v && !abortSignal.aborted) {
|
||||
abortSignal.removeEventListener('abort', abortListener);
|
||||
showSubscription.unsubscribe();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return firstValueFrom(race(this._active$, this.show$).pipe(map(() => {})));
|
||||
};
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ import { PageNotFound } from '@affine/core/desktop/pages/404';
|
||||
import { EditorService } from '@affine/core/modules/editor';
|
||||
import { DebugLogger } from '@affine/debug';
|
||||
import {
|
||||
type DocMode,
|
||||
type EdgelessRootService,
|
||||
RefNodeSlotsProvider,
|
||||
} from '@blocksuite/affine/blocks';
|
||||
@@ -24,6 +23,7 @@ import clsx from 'clsx';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
|
||||
import { WorkbenchService } from '../../../workbench';
|
||||
import type { DocReferenceInfo } from '../../entities/peek-view';
|
||||
import { PeekViewService } from '../../services/peek-view';
|
||||
import { useEditor } from '../utils';
|
||||
import * as styles from './doc-peek-view.css';
|
||||
@@ -81,6 +81,7 @@ function DocPeekPreviewEditor({
|
||||
const doc = editor.doc;
|
||||
const workspace = editor.doc.workspace;
|
||||
const mode = useLiveData(editor.mode$);
|
||||
const defaultOpenProperty = useLiveData(editor.defaultOpenProperty$);
|
||||
const workbench = useService(WorkbenchService).workbench;
|
||||
const peekView = useService(PeekViewService).peekView;
|
||||
const editorElement = useLiveData(editor.editorContainer$);
|
||||
@@ -96,11 +97,11 @@ function DocPeekPreviewEditor({
|
||||
if (!refNodeSlots) return;
|
||||
// doc change event inside peek view should be handled by peek view
|
||||
disposableGroup.add(
|
||||
// todo(@pengx17): seems not working
|
||||
refNodeSlots.docLinkClicked.on(options => {
|
||||
peekView
|
||||
.open({
|
||||
type: 'doc',
|
||||
docId: options.pageId,
|
||||
docRef: { docId: options.pageId },
|
||||
...options.params,
|
||||
})
|
||||
.catch(console.error);
|
||||
@@ -158,6 +159,7 @@ function DocPeekPreviewEditor({
|
||||
mode={mode}
|
||||
page={doc.blockSuiteDoc}
|
||||
onEditorReady={handleOnEditorReady}
|
||||
defaultOpenProperty={defaultOpenProperty}
|
||||
/>
|
||||
</Scrollable.Viewport>
|
||||
<Scrollable.Scrollbar />
|
||||
@@ -171,23 +173,24 @@ function DocPeekPreviewEditor({
|
||||
);
|
||||
}
|
||||
|
||||
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,
|
||||
});
|
||||
export function DocPeekPreview({ docRef }: { docRef: DocReferenceInfo }) {
|
||||
const { docId, blockIds, elementIds, mode, xywh, databaseId, databaseRowId } =
|
||||
docRef;
|
||||
const { doc, editor, loading } = useEditor(
|
||||
docId,
|
||||
mode,
|
||||
{
|
||||
blockIds,
|
||||
elementIds,
|
||||
},
|
||||
databaseId && databaseRowId
|
||||
? {
|
||||
databaseId,
|
||||
databaseRowId,
|
||||
type: 'database',
|
||||
}
|
||||
: undefined
|
||||
);
|
||||
|
||||
// if sync engine has been synced and the page is null, show 404 page.
|
||||
if (!doc || !editor) {
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
|
||||
import { DocInfoService } from '../../doc-info';
|
||||
import { WorkbenchService } from '../../workbench';
|
||||
import type { DocReferenceInfo } from '../entities/peek-view';
|
||||
import { PeekViewService } from '../services/peek-view';
|
||||
import * as styles from './peek-view-controls.css';
|
||||
|
||||
@@ -60,10 +61,8 @@ export const ControlButton = ({
|
||||
};
|
||||
|
||||
type DocPeekViewControlsProps = HTMLAttributes<HTMLDivElement> & {
|
||||
docId: string;
|
||||
mode?: DocMode;
|
||||
blockIds?: string[];
|
||||
elementIds?: string[];
|
||||
docRef: DocReferenceInfo;
|
||||
};
|
||||
|
||||
export const DefaultPeekViewControls = ({
|
||||
@@ -92,10 +91,7 @@ export const DefaultPeekViewControls = ({
|
||||
};
|
||||
|
||||
export const DocPeekViewControls = ({
|
||||
docId,
|
||||
mode,
|
||||
blockIds,
|
||||
elementIds,
|
||||
docRef,
|
||||
className,
|
||||
...rest
|
||||
}: DocPeekViewControlsProps) => {
|
||||
@@ -116,7 +112,7 @@ export const DocPeekViewControls = ({
|
||||
name: t['com.affine.peek-view-controls.open-doc'](),
|
||||
nameKey: 'open',
|
||||
onClick: () => {
|
||||
workbench.openDoc({ docId, mode, blockIds, elementIds });
|
||||
workbench.openDoc(docRef);
|
||||
peekView.close('none');
|
||||
},
|
||||
},
|
||||
@@ -125,10 +121,7 @@ export const DocPeekViewControls = ({
|
||||
nameKey: 'new-tab',
|
||||
name: t['com.affine.peek-view-controls.open-doc-in-new-tab'](),
|
||||
onClick: () => {
|
||||
workbench.openDoc(
|
||||
{ docId, mode, blockIds, elementIds },
|
||||
{ at: 'new-tab' }
|
||||
);
|
||||
workbench.openDoc(docRef, { at: 'new-tab' });
|
||||
peekView.close('none');
|
||||
},
|
||||
},
|
||||
@@ -137,7 +130,7 @@ export const DocPeekViewControls = ({
|
||||
nameKey: 'split-view',
|
||||
name: t['com.affine.peek-view-controls.open-doc-in-split-view'](),
|
||||
onClick: () => {
|
||||
workbench.openDoc({ docId, mode }, { at: 'beside' });
|
||||
workbench.openDoc(docRef, { at: 'beside' });
|
||||
peekView.close('none');
|
||||
},
|
||||
},
|
||||
@@ -146,20 +139,13 @@ export const DocPeekViewControls = ({
|
||||
nameKey: 'info',
|
||||
name: t['com.affine.peek-view-controls.open-info'](),
|
||||
onClick: () => {
|
||||
docInfoService.modal.open(docId);
|
||||
docInfoService.modal.open(
|
||||
typeof docRef === 'string' ? docRef : docRef.docId
|
||||
);
|
||||
},
|
||||
},
|
||||
].filter((opt): opt is ControlButtonProps => Boolean(opt));
|
||||
}, [
|
||||
t,
|
||||
peekView,
|
||||
workbench,
|
||||
docId,
|
||||
mode,
|
||||
blockIds,
|
||||
elementIds,
|
||||
docInfoService.modal,
|
||||
]);
|
||||
}, [t, peekView, workbench, docRef, docInfoService.modal]);
|
||||
return (
|
||||
<div {...rest} className={clsx(styles.root, className)}>
|
||||
{controls.map(option => (
|
||||
|
||||
@@ -22,20 +22,15 @@ function renderPeekView({ info }: ActivePeekView) {
|
||||
return toReactNode(info.template);
|
||||
}
|
||||
if (info.type === 'doc') {
|
||||
return (
|
||||
<DocPeekPreview
|
||||
mode={info.mode}
|
||||
xywh={info.xywh}
|
||||
docId={info.docId}
|
||||
blockIds={info.blockIds}
|
||||
elementIds={info.elementIds}
|
||||
/>
|
||||
);
|
||||
return <DocPeekPreview docRef={info.docRef} />;
|
||||
}
|
||||
|
||||
if (info.type === 'image') {
|
||||
if (info.type === 'image' && info.docRef.blockIds?.[0]) {
|
||||
return (
|
||||
<ImagePreviewPeekView docId={info.docId} blockId={info.blockIds[0]} />
|
||||
<ImagePreviewPeekView
|
||||
docId={info.docRef.docId}
|
||||
blockId={info.docRef.blockIds?.[0]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -49,14 +44,7 @@ function renderPeekView({ info }: ActivePeekView) {
|
||||
|
||||
const renderControls = ({ info }: ActivePeekView) => {
|
||||
if (info.type === 'doc') {
|
||||
return (
|
||||
<DocPeekViewControls
|
||||
mode={info.mode}
|
||||
docId={info.docId}
|
||||
blockIds={info.blockIds}
|
||||
elementIds={info.elementIds}
|
||||
/>
|
||||
);
|
||||
return <DocPeekViewControls docRef={info.docRef} />;
|
||||
}
|
||||
|
||||
if (info.type === 'image') {
|
||||
@@ -86,8 +74,8 @@ const getRendererProps = (
|
||||
children: preview,
|
||||
controls,
|
||||
target:
|
||||
activePeekView?.target instanceof HTMLElement
|
||||
? activePeekView.target
|
||||
activePeekView?.target.element instanceof HTMLElement
|
||||
? activePeekView.target.element
|
||||
: undefined,
|
||||
mode: getMode(activePeekView.info),
|
||||
dialogFrame: activePeekView.info.type !== 'image',
|
||||
@@ -108,8 +96,8 @@ export const PeekViewManagerModal = () => {
|
||||
|
||||
useEffect(() => {
|
||||
const subscription = peekViewEntity.show$.subscribe(() => {
|
||||
if (activePeekView?.target instanceof BlockComponent) {
|
||||
activePeekView.target.requestUpdate();
|
||||
if (activePeekView?.target.element instanceof BlockComponent) {
|
||||
activePeekView.target.element.requestUpdate();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { DefaultOpenProperty } from '@affine/core/components/doc-properties';
|
||||
import type { DocMode } from '@blocksuite/affine/blocks';
|
||||
import type { Doc } from '@toeverything/infra';
|
||||
import {
|
||||
@@ -13,7 +14,8 @@ import { type Editor, type EditorSelector, EditorsService } from '../../editor';
|
||||
export const useEditor = (
|
||||
pageId: string,
|
||||
preferMode?: DocMode,
|
||||
preferSelector?: EditorSelector
|
||||
preferSelector?: EditorSelector,
|
||||
defaultOpenProperty?: DefaultOpenProperty
|
||||
) => {
|
||||
const currentWorkspace = useService(WorkspaceService).workspace;
|
||||
const docsService = useService(DocsService);
|
||||
@@ -22,7 +24,7 @@ export const useEditor = (
|
||||
const docRecord = docRecordList.doc$(pageId).value;
|
||||
const preferModeRef = useRef(preferMode);
|
||||
const preferSelectorRef = useRef(preferSelector);
|
||||
|
||||
const defaultOpenPropertyRef = useRef(defaultOpenProperty);
|
||||
const [doc, setDoc] = useState<Doc | null>(null);
|
||||
const [editor, setEditor] = useState<Editor | null>(null);
|
||||
|
||||
@@ -44,6 +46,7 @@ export const useEditor = (
|
||||
const editor = doc.scope.get(EditorsService).createEditor();
|
||||
editor.setMode(preferModeRef.current || doc.primaryMode$.value);
|
||||
editor.setSelector(preferSelectorRef.current);
|
||||
editor.setDefaultOpenProperty(defaultOpenPropertyRef.current);
|
||||
setEditor(editor);
|
||||
return () => {
|
||||
editor.dispose();
|
||||
|
||||
Reference in New Issue
Block a user