mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-09-06 08:50:50 +08:00
feat(core): peek view api enhancements (#7288)
upstream https://github.com/toeverything/blocksuite/pull/7390 fix AF-917
This commit is contained in:
@@ -1,2 +1,3 @@
|
|||||||
export { createComponent as createReactComponentFromLit } from './create-component';
|
export { createComponent as createReactComponentFromLit } from './create-component';
|
||||||
export * from './lit-portal';
|
export * from './lit-portal';
|
||||||
|
export { toReactNode } from './to-react-node';
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { LitElement, type TemplateResult } from 'lit';
|
||||||
|
import React, { createElement, type ReactNode } from 'react';
|
||||||
|
|
||||||
|
import { createComponent } from './create-component';
|
||||||
|
|
||||||
|
export class LitTemplateWrapper extends LitElement {
|
||||||
|
static override get properties() {
|
||||||
|
return {
|
||||||
|
template: { type: Object },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
template: TemplateResult | null = null;
|
||||||
|
// do not enable shadow root
|
||||||
|
override createRenderRoot() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
override render() {
|
||||||
|
return this.template;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.customElements.define('affine-lit-template-wrapper', LitTemplateWrapper);
|
||||||
|
|
||||||
|
const TemplateWrapper = createComponent({
|
||||||
|
elementClass: LitTemplateWrapper,
|
||||||
|
react: React,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const toReactNode = (template?: TemplateResult | string): ReactNode => {
|
||||||
|
if (!template) return null;
|
||||||
|
return typeof template === 'string'
|
||||||
|
? template
|
||||||
|
: createElement(TemplateWrapper, { template });
|
||||||
|
};
|
||||||
@@ -101,7 +101,7 @@ export function AffinePageReference({
|
|||||||
if (e.shiftKey && ref.current) {
|
if (e.shiftKey && ref.current) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
peekView.open(ref.current);
|
peekView.open(ref.current).catch(console.error);
|
||||||
return false; // means this click is handled
|
return false; // means this click is handled
|
||||||
}
|
}
|
||||||
if (isInPeekView) {
|
if (isInPeekView) {
|
||||||
|
|||||||
+6
-39
@@ -1,10 +1,10 @@
|
|||||||
import {
|
import {
|
||||||
createReactComponentFromLit,
|
|
||||||
type ElementOrFactory,
|
type ElementOrFactory,
|
||||||
Input,
|
Input,
|
||||||
notify,
|
notify,
|
||||||
toast,
|
toast,
|
||||||
type ToastOptions,
|
type ToastOptions,
|
||||||
|
toReactNode,
|
||||||
type useConfirmModal,
|
type useConfirmModal,
|
||||||
} from '@affine/component';
|
} from '@affine/component';
|
||||||
import type {
|
import type {
|
||||||
@@ -27,47 +27,15 @@ import {
|
|||||||
type RootService,
|
type RootService,
|
||||||
} from '@blocksuite/blocks';
|
} from '@blocksuite/blocks';
|
||||||
import type { DocMode, DocService, DocsService } from '@toeverything/infra';
|
import type { DocMode, DocService, DocsService } from '@toeverything/infra';
|
||||||
import { html, LitElement, type TemplateResult } from 'lit';
|
import { html, type TemplateResult } from 'lit';
|
||||||
import { customElement } from 'lit/decorators.js';
|
import { customElement } from 'lit/decorators.js';
|
||||||
import { literal } from 'lit/static-html.js';
|
import { literal } from 'lit/static-html.js';
|
||||||
import React, { createElement, type ReactNode } from 'react';
|
|
||||||
|
|
||||||
const logger = new DebugLogger('affine::spec-patchers');
|
|
||||||
|
|
||||||
export type ReferenceReactRenderer = (
|
export type ReferenceReactRenderer = (
|
||||||
reference: AffineReference
|
reference: AffineReference
|
||||||
) => React.ReactElement;
|
) => React.ReactElement;
|
||||||
|
|
||||||
export class LitTemplateWrapper extends LitElement {
|
const logger = new DebugLogger('affine::spec-patchers');
|
||||||
static override get properties() {
|
|
||||||
return {
|
|
||||||
template: { type: Object },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
template: TemplateResult | null = null;
|
|
||||||
// do not enable shadow root
|
|
||||||
override createRenderRoot() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
override render() {
|
|
||||||
return this.template;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
window.customElements.define('affine-lit-template-wrapper', LitTemplateWrapper);
|
|
||||||
|
|
||||||
const TemplateWrapper = createReactComponentFromLit({
|
|
||||||
elementClass: LitTemplateWrapper,
|
|
||||||
react: React,
|
|
||||||
});
|
|
||||||
|
|
||||||
const toReactNode = (template?: TemplateResult | string): ReactNode => {
|
|
||||||
if (!template) return null;
|
|
||||||
return typeof template === 'string'
|
|
||||||
? template
|
|
||||||
: createElement(TemplateWrapper, { template });
|
|
||||||
};
|
|
||||||
|
|
||||||
function patchSpecService<Spec extends BlockSpec>(
|
function patchSpecService<Spec extends BlockSpec>(
|
||||||
spec: Spec,
|
spec: Spec,
|
||||||
@@ -274,10 +242,9 @@ export function patchPeekViewService(
|
|||||||
|
|
||||||
patchSpecService(rootSpec, pageService => {
|
patchSpecService(rootSpec, pageService => {
|
||||||
pageService.peekViewService = {
|
pageService.peekViewService = {
|
||||||
peek: (target: ActivePeekView['target']) => {
|
peek: (target: ActivePeekView['target'], template?: TemplateResult) => {
|
||||||
logger.debug('center peek', target);
|
logger.debug('center peek', target, template);
|
||||||
service.peekView.open(target);
|
return service.peekView.open(target, template);
|
||||||
return Promise.resolve();
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,7 +6,12 @@ import {
|
|||||||
type SurfaceRefBlockComponent,
|
type SurfaceRefBlockComponent,
|
||||||
type SurfaceRefBlockModel,
|
type SurfaceRefBlockModel,
|
||||||
} from '@blocksuite/blocks';
|
} from '@blocksuite/blocks';
|
||||||
|
import type { BlockModel } from '@blocksuite/store';
|
||||||
import { type DocMode, Entity, LiveData } from '@toeverything/infra';
|
import { type DocMode, Entity, LiveData } from '@toeverything/infra';
|
||||||
|
import type { TemplateResult } from 'lit';
|
||||||
|
import { firstValueFrom, map, race } from 'rxjs';
|
||||||
|
|
||||||
|
import { resolveLinkToDoc } from '../../navigation';
|
||||||
|
|
||||||
export type PeekViewTarget =
|
export type PeekViewTarget =
|
||||||
| HTMLElement
|
| HTMLElement
|
||||||
@@ -24,13 +29,10 @@ export type DocPeekViewInfo = {
|
|||||||
|
|
||||||
export type ActivePeekView = {
|
export type ActivePeekView = {
|
||||||
target: PeekViewTarget;
|
target: PeekViewTarget;
|
||||||
info: DocPeekViewInfo;
|
info?: DocPeekViewInfo;
|
||||||
|
template?: TemplateResult;
|
||||||
};
|
};
|
||||||
|
|
||||||
import type { BlockModel } from '@blocksuite/store';
|
|
||||||
|
|
||||||
import { resolveLinkToDoc } from '../../navigation';
|
|
||||||
|
|
||||||
const EMBED_DOC_FLAVOURS = [
|
const EMBED_DOC_FLAVOURS = [
|
||||||
'affine:embed-linked-doc',
|
'affine:embed-linked-doc',
|
||||||
'affine:embed-synced-doc',
|
'affine:embed-synced-doc',
|
||||||
@@ -50,8 +52,8 @@ const isSurfaceRefModel = (
|
|||||||
|
|
||||||
function resolvePeekInfoFromPeekTarget(
|
function resolvePeekInfoFromPeekTarget(
|
||||||
peekTarget?: PeekViewTarget
|
peekTarget?: PeekViewTarget
|
||||||
): DocPeekViewInfo | null {
|
): DocPeekViewInfo | undefined {
|
||||||
if (!peekTarget) return null;
|
if (!peekTarget) return;
|
||||||
if (peekTarget instanceof AffineReference) {
|
if (peekTarget instanceof AffineReference) {
|
||||||
if (peekTarget.refMeta) {
|
if (peekTarget.refMeta) {
|
||||||
return {
|
return {
|
||||||
@@ -91,14 +93,10 @@ function resolvePeekInfoFromPeekTarget(
|
|||||||
blockId: peekTarget.blockId,
|
blockId: peekTarget.blockId,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return null;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PeekViewEntity extends Entity {
|
export class PeekViewEntity extends Entity {
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly _active$ = new LiveData<ActivePeekView | null>(null);
|
private readonly _active$ = new LiveData<ActivePeekView | null>(null);
|
||||||
private readonly _show$ = new LiveData<boolean>(false);
|
private readonly _show$ = new LiveData<boolean>(false);
|
||||||
|
|
||||||
@@ -108,14 +106,17 @@ export class PeekViewEntity extends Entity {
|
|||||||
.distinctUntilChanged();
|
.distinctUntilChanged();
|
||||||
|
|
||||||
// return true if the peek view will be handled
|
// return true if the peek view will be handled
|
||||||
open = (target: ActivePeekView['target']) => {
|
open = async (
|
||||||
|
target: ActivePeekView['target'],
|
||||||
|
template?: TemplateResult
|
||||||
|
) => {
|
||||||
const resolvedInfo = resolvePeekInfoFromPeekTarget(target);
|
const resolvedInfo = resolvePeekInfoFromPeekTarget(target);
|
||||||
if (!resolvedInfo) {
|
if (!resolvedInfo && !template) {
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
this._active$.next({ target, info: resolvedInfo });
|
this._active$.next({ target, info: resolvedInfo, template });
|
||||||
this._show$.next(true);
|
this._show$.next(true);
|
||||||
return true;
|
return firstValueFrom(race(this._active$, this.show$).pipe(map(() => {})));
|
||||||
};
|
};
|
||||||
|
|
||||||
close = () => {
|
close = () => {
|
||||||
|
|||||||
@@ -10,28 +10,52 @@ import { DisposableGroup } from '@blocksuite/global/utils';
|
|||||||
import type { AffineEditorContainer } from '@blocksuite/presets';
|
import type { AffineEditorContainer } from '@blocksuite/presets';
|
||||||
import type { DocMode } from '@toeverything/infra';
|
import type { DocMode } from '@toeverything/infra';
|
||||||
import { DocsService, FrameworkScope, useService } from '@toeverything/infra';
|
import { DocsService, FrameworkScope, useService } from '@toeverything/infra';
|
||||||
import {
|
import { useEffect, useState } from 'react';
|
||||||
forwardRef,
|
|
||||||
useCallback,
|
|
||||||
useEffect,
|
|
||||||
useImperativeHandle,
|
|
||||||
useState,
|
|
||||||
} from 'react';
|
|
||||||
|
|
||||||
import { WorkbenchService } from '../../workbench';
|
import { WorkbenchService } from '../../workbench';
|
||||||
import { PeekViewService } from '../services/peek-view';
|
import { PeekViewService } from '../services/peek-view';
|
||||||
import * as styles from './doc-peek-view.css';
|
import * as styles from './doc-peek-view.css';
|
||||||
import { useDoc } from './utils';
|
import { useDoc } from './utils';
|
||||||
|
|
||||||
export type DocPreviewRef = {
|
function fitViewport(
|
||||||
getEditor: () => AffineEditorContainer | null;
|
editor: AffineEditorContainer,
|
||||||
fitViewportToTarget: () => void;
|
xywh?: `[${number},${number},${number},${number}]`
|
||||||
};
|
) {
|
||||||
|
const rootService =
|
||||||
|
editor.host.std.spec.getService<EdgelessRootService>('affine:page');
|
||||||
|
rootService.viewport.onResize();
|
||||||
|
|
||||||
const DocPreview = forwardRef<
|
if (xywh) {
|
||||||
DocPreviewRef,
|
const viewport = {
|
||||||
{ docId: string; blockId?: string; mode?: DocMode }
|
xywh: xywh,
|
||||||
>(function DocPreview({ docId, blockId, mode }, ref) {
|
padding: [60, 20, 20, 20] as [number, number, number, number],
|
||||||
|
};
|
||||||
|
rootService.viewport.setViewportByBound(
|
||||||
|
Bound.deserialize(viewport.xywh),
|
||||||
|
viewport.padding,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const data = rootService.getFitToScreenData();
|
||||||
|
rootService.viewport.setViewport(
|
||||||
|
data.zoom,
|
||||||
|
[data.centerX, data.centerY],
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function DocPeekPreview({
|
||||||
|
docId,
|
||||||
|
blockId,
|
||||||
|
mode,
|
||||||
|
xywh,
|
||||||
|
}: {
|
||||||
|
docId: string;
|
||||||
|
blockId?: string;
|
||||||
|
mode?: DocMode;
|
||||||
|
xywh?: `[${number},${number},${number},${number}]`;
|
||||||
|
}) {
|
||||||
const { doc, workspace, loading } = useDoc(docId);
|
const { doc, workspace, loading } = useDoc(docId);
|
||||||
const { jumpToTag } = useNavigateHelper();
|
const { jumpToTag } = useNavigateHelper();
|
||||||
const workbench = useService(WorkbenchService).workbench;
|
const workbench = useService(WorkbenchService).workbench;
|
||||||
@@ -45,26 +69,22 @@ const DocPreview = forwardRef<
|
|||||||
const docs = useService(DocsService);
|
const docs = useService(DocsService);
|
||||||
const [resolvedMode, setResolvedMode] = useState<DocMode | undefined>(mode);
|
const [resolvedMode, setResolvedMode] = useState<DocMode | undefined>(mode);
|
||||||
|
|
||||||
useImperativeHandle(
|
useEffect(() => {
|
||||||
ref,
|
if (editor && resolvedMode === 'edgeless') {
|
||||||
() => ({
|
editor.host
|
||||||
getEditor: () => editor,
|
.closest('[data-testid="peek-view-modal-animation-container"]')
|
||||||
fitViewportToTarget: () => {
|
?.addEventListener(
|
||||||
if (editor && resolvedMode === 'edgeless') {
|
'animationend',
|
||||||
const rootService =
|
() => {
|
||||||
editor.host.std.spec.getService<EdgelessRootService>('affine:page');
|
fitViewport(editor, xywh);
|
||||||
rootService.viewport.onResize();
|
},
|
||||||
const data = rootService.getFitToScreenData();
|
{
|
||||||
rootService.viewport.setViewport(
|
once: true,
|
||||||
data.zoom,
|
}
|
||||||
[data.centerX, data.centerY],
|
);
|
||||||
false
|
}
|
||||||
);
|
return;
|
||||||
}
|
}, [editor, resolvedMode, xywh]);
|
||||||
},
|
|
||||||
}),
|
|
||||||
[editor, resolvedMode]
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!mode || !resolvedMode) {
|
if (!mode || !resolvedMode) {
|
||||||
@@ -95,7 +115,7 @@ const DocPreview = forwardRef<
|
|||||||
// doc change event inside peek view should be handled by peek view
|
// doc change event inside peek view should be handled by peek view
|
||||||
disposableGroup.add(
|
disposableGroup.add(
|
||||||
rootService.slots.docLinkClicked.on(({ docId, blockId }) => {
|
rootService.slots.docLinkClicked.on(({ docId, blockId }) => {
|
||||||
peekView.open({ docId, blockId });
|
peekView.open({ docId, blockId }).catch(console.error);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
// todo: no tag peek view yet
|
// todo: no tag peek view yet
|
||||||
@@ -140,86 +160,4 @@ const DocPreview = forwardRef<
|
|||||||
</Scrollable.Root>
|
</Scrollable.Root>
|
||||||
</AffineErrorBoundary>
|
</AffineErrorBoundary>
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
DocPreview.displayName = 'DocPreview';
|
|
||||||
|
|
||||||
export const DocPeekView = forwardRef<
|
|
||||||
DocPreviewRef,
|
|
||||||
{
|
|
||||||
docId: string;
|
|
||||||
blockId?: string;
|
|
||||||
mode?: DocMode;
|
|
||||||
}
|
|
||||||
>(function DocPeekView({ docId, blockId, mode }, ref) {
|
|
||||||
return <DocPreview ref={ref} mode={mode} docId={docId} blockId={blockId} />;
|
|
||||||
});
|
|
||||||
|
|
||||||
export type SurfaceRefPeekViewRef = {
|
|
||||||
fitViewportToTarget: () => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const SurfaceRefPeekView = forwardRef<
|
|
||||||
SurfaceRefPeekViewRef,
|
|
||||||
{ docId: string; xywh: `[${number},${number},${number},${number}]` }
|
|
||||||
>(function SurfaceRefPeekView({ docId, xywh }, ref) {
|
|
||||||
const [editorRef, setEditorRef] = useState<AffineEditorContainer | null>(
|
|
||||||
null
|
|
||||||
);
|
|
||||||
const onRef = (editor: AffineEditorContainer | null) => {
|
|
||||||
setEditorRef(editor);
|
|
||||||
};
|
|
||||||
const fitViewportToTarget = useCallback(() => {
|
|
||||||
if (!editorRef) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const viewport = {
|
|
||||||
xywh: xywh,
|
|
||||||
padding: [60, 20, 20, 20] as [number, number, number, number],
|
|
||||||
};
|
|
||||||
const rootService =
|
|
||||||
editorRef.host.std.spec.getService<EdgelessRootService>('affine:page');
|
|
||||||
rootService.viewport.onResize();
|
|
||||||
rootService.viewport.setViewportByBound(
|
|
||||||
Bound.deserialize(viewport.xywh),
|
|
||||||
viewport.padding
|
|
||||||
);
|
|
||||||
}, [editorRef, xywh]);
|
|
||||||
|
|
||||||
useImperativeHandle(
|
|
||||||
ref,
|
|
||||||
() => ({
|
|
||||||
fitViewportToTarget,
|
|
||||||
}),
|
|
||||||
[fitViewportToTarget]
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
let mounted = true;
|
|
||||||
if (editorRef) {
|
|
||||||
editorRef.host?.updateComplete
|
|
||||||
.then(() => {
|
|
||||||
if (mounted) {
|
|
||||||
fitViewportToTarget();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(e => {
|
|
||||||
console.error(e);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return () => {
|
|
||||||
mounted = false;
|
|
||||||
};
|
|
||||||
}, [editorRef, fitViewportToTarget]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<DocPreview
|
|
||||||
ref={ref => {
|
|
||||||
onRef(ref?.getEditor() ?? null);
|
|
||||||
}}
|
|
||||||
docId={docId}
|
|
||||||
mode={'edgeless'}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
SurfaceRefPeekView.displayName = 'SurfaceRefPeekView';
|
|
||||||
|
|||||||
@@ -112,7 +112,11 @@ export const PeekViewModalContainer = ({
|
|||||||
[styles.animationTimeout]: `${animationTimeout}ms`,
|
[styles.animationTimeout]: `${animationTimeout}ms`,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<div className={styles.modalContentContainer} data-state={status}>
|
<div
|
||||||
|
className={styles.modalContentContainer}
|
||||||
|
data-testid="peek-view-modal-animation-container"
|
||||||
|
data-state={status}
|
||||||
|
>
|
||||||
<Dialog.Content
|
<Dialog.Content
|
||||||
{...contentOptions}
|
{...contentOptions}
|
||||||
className={styles.modalContent}
|
className={styles.modalContent}
|
||||||
|
|||||||
+26
-1
@@ -19,7 +19,7 @@ import {
|
|||||||
|
|
||||||
import { WorkbenchService } from '../../workbench';
|
import { WorkbenchService } from '../../workbench';
|
||||||
import { PeekViewService } from '../services/peek-view';
|
import { PeekViewService } from '../services/peek-view';
|
||||||
import * as styles from './doc-peek-controls.css';
|
import * as styles from './peek-view-controls.css';
|
||||||
import { useDoc } from './utils';
|
import { useDoc } from './utils';
|
||||||
|
|
||||||
type ControlButtonProps = {
|
type ControlButtonProps = {
|
||||||
@@ -66,6 +66,31 @@ type DocPeekViewControlsProps = HTMLAttributes<HTMLDivElement> & {
|
|||||||
mode?: DocMode;
|
mode?: DocMode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const DefaultPeekViewControls = ({
|
||||||
|
className,
|
||||||
|
...rest
|
||||||
|
}: HTMLAttributes<HTMLDivElement>) => {
|
||||||
|
const peekView = useService(PeekViewService).peekView;
|
||||||
|
const t = useI18n();
|
||||||
|
const controls = useMemo(() => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
icon: <CloseIcon />,
|
||||||
|
nameKey: 'close',
|
||||||
|
name: t['com.affine.peek-view-controls.close'](),
|
||||||
|
onClick: peekView.close,
|
||||||
|
},
|
||||||
|
].filter((opt): opt is ControlButtonProps => Boolean(opt));
|
||||||
|
}, [peekView, t]);
|
||||||
|
return (
|
||||||
|
<div {...rest} className={clsx(styles.root, className)}>
|
||||||
|
{controls.map(option => (
|
||||||
|
<ControlButton key={option.nameKey} {...option} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const DocPeekViewControls = ({
|
export const DocPeekViewControls = ({
|
||||||
docId,
|
docId,
|
||||||
blockId,
|
blockId,
|
||||||
@@ -1,32 +1,30 @@
|
|||||||
|
import { toReactNode } from '@affine/component';
|
||||||
import { BlockElement } from '@blocksuite/block-std';
|
import { BlockElement } from '@blocksuite/block-std';
|
||||||
import { useLiveData, useService } from '@toeverything/infra';
|
import { useLiveData, useService } from '@toeverything/infra';
|
||||||
import { useEffect, useMemo, useRef } from 'react';
|
import { useEffect, useMemo } from 'react';
|
||||||
|
|
||||||
import type { ActivePeekView } from '../entities/peek-view';
|
import type { ActivePeekView } from '../entities/peek-view';
|
||||||
import { PeekViewService } from '../services/peek-view';
|
import { PeekViewService } from '../services/peek-view';
|
||||||
import { DocPeekViewControls } from './doc-peek-controls';
|
import { DocPeekPreview } from './doc-peek-view';
|
||||||
import type { DocPreviewRef, SurfaceRefPeekViewRef } from './doc-peek-view';
|
|
||||||
import { DocPeekView, SurfaceRefPeekView } from './doc-peek-view';
|
|
||||||
import { PeekViewModalContainer } from './modal-container';
|
import { PeekViewModalContainer } from './modal-container';
|
||||||
|
import {
|
||||||
|
DefaultPeekViewControls,
|
||||||
|
DocPeekViewControls,
|
||||||
|
} from './peek-view-controls';
|
||||||
|
|
||||||
function renderPeekView(
|
function renderPeekView({ info, template }: ActivePeekView) {
|
||||||
{ info }: ActivePeekView,
|
if (template) {
|
||||||
refCallback: (editor: SurfaceRefPeekViewRef | DocPreviewRef | null) => void
|
return toReactNode(template);
|
||||||
) {
|
}
|
||||||
if (info.mode === 'edgeless' && info.xywh) {
|
|
||||||
return (
|
if (!info) {
|
||||||
<SurfaceRefPeekView
|
return null;
|
||||||
ref={refCallback}
|
|
||||||
docId={info.docId}
|
|
||||||
xywh={info.xywh}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DocPeekView
|
<DocPeekPreview
|
||||||
ref={refCallback}
|
|
||||||
mode={info.mode}
|
mode={info.mode}
|
||||||
|
xywh={info.xywh}
|
||||||
docId={info.docId}
|
docId={info.docId}
|
||||||
blockId={info.blockId}
|
blockId={info.blockId}
|
||||||
/>
|
/>
|
||||||
@@ -34,29 +32,26 @@ function renderPeekView(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const renderControls = ({ info }: ActivePeekView) => {
|
const renderControls = ({ info }: ActivePeekView) => {
|
||||||
return (
|
if (info && 'docId' in info) {
|
||||||
<DocPeekViewControls
|
return (
|
||||||
mode={info.mode}
|
<DocPeekViewControls
|
||||||
docId={info.docId}
|
mode={info.mode}
|
||||||
blockId={info.docId}
|
docId={info.docId}
|
||||||
/>
|
blockId={info.docId}
|
||||||
);
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return <DefaultPeekViewControls />;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const PeekViewManagerModal = () => {
|
export const PeekViewManagerModal = () => {
|
||||||
const peekViewEntity = useService(PeekViewService).peekView;
|
const peekViewEntity = useService(PeekViewService).peekView;
|
||||||
const activePeekView = useLiveData(peekViewEntity.active$);
|
const activePeekView = useLiveData(peekViewEntity.active$);
|
||||||
const show = useLiveData(peekViewEntity.show$);
|
const show = useLiveData(peekViewEntity.show$);
|
||||||
const peekViewRef = useRef<SurfaceRefPeekViewRef | DocPreviewRef | null>(
|
|
||||||
null
|
|
||||||
);
|
|
||||||
|
|
||||||
const preview = useMemo(() => {
|
const preview = useMemo(() => {
|
||||||
return activePeekView
|
return activePeekView ? renderPeekView(activePeekView) : null;
|
||||||
? renderPeekView(activePeekView, editor => {
|
|
||||||
peekViewRef.current = editor;
|
|
||||||
})
|
|
||||||
: null;
|
|
||||||
}, [activePeekView]);
|
}, [activePeekView]);
|
||||||
|
|
||||||
const controls = useMemo(() => {
|
const controls = useMemo(() => {
|
||||||
@@ -89,9 +84,6 @@ export const PeekViewManagerModal = () => {
|
|||||||
peekViewEntity.close();
|
peekViewEntity.close();
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onAnimateEnd={() => {
|
|
||||||
peekViewRef.current?.fitViewportToTarget();
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{preview}
|
{preview}
|
||||||
</PeekViewModalContainer>
|
</PeekViewModalContainer>
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ export const AllPage = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const Component = () => {
|
export const Component = () => {
|
||||||
performanceRenderLogger.info('AllPage');
|
performanceRenderLogger.debug('AllPage');
|
||||||
|
|
||||||
return <AllPage />;
|
return <AllPage />;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -362,7 +362,7 @@ export const DetailPage = ({ pageId }: { pageId: string }): ReactElement => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const Component = () => {
|
export const Component = () => {
|
||||||
performanceRenderLogger.info('DetailPage');
|
performanceRenderLogger.debug('DetailPage');
|
||||||
|
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
const recentPages = useService(RecentPagesService);
|
const recentPages = useService(RecentPagesService);
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ declare global {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const Component = (): ReactElement => {
|
export const Component = (): ReactElement => {
|
||||||
performanceRenderLogger.info('WorkspaceLayout');
|
performanceRenderLogger.debug('WorkspaceLayout');
|
||||||
|
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
|
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ window.addEventListener('focus', () => {
|
|||||||
frameworkProvider.get(LifecycleService).applicationStart();
|
frameworkProvider.get(LifecycleService).applicationStart();
|
||||||
|
|
||||||
export function App() {
|
export function App() {
|
||||||
performanceRenderLogger.info('App');
|
performanceRenderLogger.debug('App');
|
||||||
|
|
||||||
if (!languageLoadingPromise) {
|
if (!languageLoadingPromise) {
|
||||||
languageLoadingPromise = loadLanguage().catch(console.error);
|
languageLoadingPromise = loadLanguage().catch(console.error);
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ window.addEventListener('focus', () => {
|
|||||||
frameworkProvider.get(LifecycleService).applicationStart();
|
frameworkProvider.get(LifecycleService).applicationStart();
|
||||||
|
|
||||||
export function App() {
|
export function App() {
|
||||||
performanceRenderLogger.info('App');
|
performanceRenderLogger.debug('App');
|
||||||
|
|
||||||
if (!languageLoadingPromise) {
|
if (!languageLoadingPromise) {
|
||||||
languageLoadingPromise = loadLanguage().catch(console.error);
|
languageLoadingPromise = loadLanguage().catch(console.error);
|
||||||
|
|||||||
Reference in New Issue
Block a user