mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 04:18:54 +00:00
feat(component): helper function observeResize to observe size change via global ResizeObserver (#7241)
```ts
import { observeResize } from "@affine/component";
useEffect(() => {
const dispose = observeResize(element entry => {
console.log(entry.contentRect);
});
return () => dispose();
}, []);
```
This commit is contained in:
@@ -24,3 +24,4 @@ export * from './ui/switch';
|
||||
export * from './ui/table';
|
||||
export * from './ui/toast';
|
||||
export * from './ui/tooltip';
|
||||
export * from './utils';
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
useState,
|
||||
} from 'react';
|
||||
|
||||
import { observeResize } from '../../utils';
|
||||
import { IconButton } from '../button';
|
||||
import * as styles from './week-date-picker.css';
|
||||
|
||||
@@ -116,8 +117,7 @@ export const WeekDatePicker = memo(function WeekDatePicker({
|
||||
const el = weekRef.current;
|
||||
if (!el) return;
|
||||
|
||||
const resizeObserver = new ResizeObserver(entries => {
|
||||
const rect = entries[0].contentRect;
|
||||
return observeResize(el, ({ contentRect: rect }) => {
|
||||
const width = rect.width;
|
||||
if (!width) return;
|
||||
|
||||
@@ -127,11 +127,6 @@ export const WeekDatePicker = memo(function WeekDatePicker({
|
||||
setViewPortSize(Math.max(1, Math.min(viewPortCount, 7)));
|
||||
setDense(width < 300);
|
||||
});
|
||||
resizeObserver.observe(el);
|
||||
|
||||
return () => {
|
||||
resizeObserver.disconnect();
|
||||
};
|
||||
}, []);
|
||||
|
||||
// when value changes, reset cursor
|
||||
|
||||
1
packages/frontend/component/src/utils/index.ts
Normal file
1
packages/frontend/component/src/utils/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './observe-resize';
|
||||
77
packages/frontend/component/src/utils/observe-resize.ts
Normal file
77
packages/frontend/component/src/utils/observe-resize.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import type { ResizeObserverEntry } from '@juggle/resize-observer';
|
||||
|
||||
type ObserveResize = {
|
||||
callback: (entity: ResizeObserverEntry) => void;
|
||||
dispose: () => void;
|
||||
};
|
||||
|
||||
let _resizeObserver: ResizeObserver | null = null;
|
||||
const elementsMap = new WeakMap<Element, Array<ObserveResize>>();
|
||||
|
||||
// for debugging
|
||||
(window as any)._resizeObserverElementsMap = elementsMap;
|
||||
|
||||
/**
|
||||
* @internal get or initialize the ResizeObserver instance
|
||||
*/
|
||||
const getResizeObserver = () =>
|
||||
(_resizeObserver ??= new ResizeObserver(entries => {
|
||||
entries.forEach(entry => {
|
||||
const listeners = elementsMap.get(entry.target) ?? [];
|
||||
listeners.forEach(({ callback }) => callback(entry));
|
||||
});
|
||||
}));
|
||||
|
||||
/**
|
||||
* @internal remove element's specific listener
|
||||
*/
|
||||
const removeListener = (element: Element, listener: ObserveResize) => {
|
||||
if (!element) return;
|
||||
const listeners = elementsMap.get(element) ?? [];
|
||||
const observer = getResizeObserver();
|
||||
// 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 resize of an element use global ResizeObserver.
|
||||
*
|
||||
* ```ts
|
||||
* useEffect(() => {
|
||||
* const dispose1 = observeResize(elRef1.current, (entry) => {});
|
||||
* const dispose2 = observeResize(elRef2.current, (entry) => {});
|
||||
*
|
||||
* return () => {
|
||||
* dispose1();
|
||||
* dispose2();
|
||||
* };
|
||||
* }, [])
|
||||
* ```
|
||||
* @return A function to dispose the observer.
|
||||
*/
|
||||
export const observeResize = (
|
||||
element: Element,
|
||||
callback: ObserveResize['callback']
|
||||
) => {
|
||||
const observer = getResizeObserver();
|
||||
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;
|
||||
};
|
||||
Reference in New Issue
Block a user