Skip to content

Commit

Permalink
feat: pdf embed view component
Browse files Browse the repository at this point in the history
  • Loading branch information
fundon committed Nov 14, 2024
1 parent c712e87 commit dc4fa3d
Show file tree
Hide file tree
Showing 17 changed files with 724 additions and 246 deletions.
1 change: 1 addition & 0 deletions packages/frontend/component/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './observe-intersection';
export * from './observe-resize';
export { startScopedViewTransition } from './view-transition';
export * from './with-unit';
83 changes: 83 additions & 0 deletions packages/frontend/component/src/utils/observe-intersection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
type ObserveIntersection = {
callback: (entity: IntersectionObserverEntry) => void;
dispose: () => void;
};

let _intersectionObserver: IntersectionObserver | null = null;
const elementsMap = new WeakMap<Element, Array<ObserveIntersection>>();

// for debugging
if (typeof window !== 'undefined') {
(window as any)._intersectionObserverElementsMap = elementsMap;
}

/**
* @internal get or initialize the IntersectionObserver instance
*/
const getIntersectionObserver = () =>
(_intersectionObserver ??= new IntersectionObserver(
entries => {
entries.forEach(entry => {
const listeners = elementsMap.get(entry.target) ?? [];
listeners.forEach(({ callback }) => callback(entry));
});
},
{
rootMargin: '20px 20px 20px 20px',
threshold: 0.233,
}
));

/**
* @internal remove element's specific listener
*/
const removeListener = (element: Element, listener: ObserveIntersection) => {
if (!element) return;
const listeners = elementsMap.get(element) ?? [];
const observer = getIntersectionObserver();
// remove the listener from the element
if (listeners.includes(listener)) {
elementsMap.set(
element,
listeners.filter(l => l !== listener)
);
}
// if no more listeners, unobserve the element
if (elementsMap.get(element)?.length === 0) {
observer.unobserve(element);
elementsMap.delete(element);
}
};

/**
* A function to observe the intersection of an element use global IntersectionObserver.
*
* ```ts
* useEffect(() => {
* const dispose1 = observeIntersection(elRef1.current, (entry) => {});
* const dispose2 = observeIntersection(elRef2.current, (entry) => {});
*
* return () => {
* dispose1();
* dispose2();
* };
* }, [])
* ```
* @return A function to dispose the observer.
*/
export const observeIntersection = (
element: Element,
callback: ObserveIntersection['callback']
) => {
const observer = getIntersectionObserver();
if (!elementsMap.has(element)) {
observer.observe(element);
}
const prevListeners = elementsMap.get(element) ?? [];
const listener = { callback, dispose: () => {} };
listener.dispose = () => removeListener(element, listener);

elementsMap.set(element, [...prevListeners, listener]);

return listener.dispose;
};
28 changes: 13 additions & 15 deletions packages/frontend/core/src/components/attachment-viewer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ViewBody, ViewHeader } from '@affine/core/modules/workbench';
import type { AttachmentBlockModel } from '@blocksuite/affine/blocks';

import { AttachmentPreviewErrorBoundary, Error } from './error';
import { PDFViewer } from './pdf-viewer';
import { PDFViewer, type PDFViewerProps } from './pdf-viewer';
import * as styles from './styles.css';
import { Titlebar } from './titlebar';
import { buildAttachmentProps } from './utils';
Expand All @@ -18,13 +18,7 @@ export const AttachmentViewer = ({ model }: AttachmentViewerProps) => {
return (
<div className={styles.viewerContainer}>
<Titlebar {...props} />
{model.type.endsWith('pdf') ? (
<AttachmentPreviewErrorBoundary>
<PDFViewer {...props} />
</AttachmentPreviewErrorBoundary>
) : (
<Error {...props} />
)}
<AttachmentViewerInner {...props} />
</div>
);
};
Expand All @@ -39,14 +33,18 @@ export const AttachmentViewerView = ({ model }: AttachmentViewerProps) => {
<Titlebar {...props} />
</ViewHeader>
<ViewBody>
{model.type.endsWith('pdf') ? (
<AttachmentPreviewErrorBoundary>
<PDFViewer {...props} />
</AttachmentPreviewErrorBoundary>
) : (
<Error {...props} />
)}
<AttachmentViewerInner {...props} />
</ViewBody>
</>
);
};

const AttachmentViewerInner = (props: PDFViewerProps) => {
return props.model.type.endsWith('pdf') ? (
<AttachmentPreviewErrorBoundary>
<PDFViewer {...props} />
</AttachmentPreviewErrorBoundary>
) : (
<Error {...props} />
);
};
Loading

0 comments on commit dc4fa3d

Please sign in to comment.