Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "fix: Use container window's resize observer",
"packageName": "@fluentui/priority-overflow",
"email": "lingfangao@hotmail.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "fix: use targetDocument resize observer",
"packageName": "@fluentui/react-table",
"email": "lingfangao@hotmail.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "fix: use targetDocument resize observer",
"packageName": "@fluentui/react-virtualizer",
"email": "lingfangao@hotmail.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* Helper function that creates a resize observer in the element's own window global
* @param elementToObserve - Uses the element's window global to create the resize observer
* @param callback
* @returns function to cleanup the resize observer
*/
export function observeResize(elementToObserve: HTMLElement, callback: ResizeObserverCallback) {
const GlobalResizeObsever = elementToObserve.ownerDocument.defaultView?.ResizeObserver;

if (!GlobalResizeObsever) {
if (process.env.NODE_ENV !== 'production') {
// eslint-disable-next-line no-console
console.error('@fluentui/priority-overflow', 'ResizeObserver does not exist on container window');
}
return () => null;
}

let resizeObserver: ResizeObserver | undefined = new GlobalResizeObsever(callback);
resizeObserver.observe(elementToObserve);

return () => {
resizeObserver?.disconnect();
resizeObserver = undefined;
};
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { DATA_OVERFLOWING, DATA_OVERFLOW_GROUP } from './consts';
import { observeResize } from './createResizeObserver';
import { debounce } from './debounce';
import { createPriorityQueue, PriorityQueue } from './priorityQueue';
import type {
Expand Down Expand Up @@ -35,13 +36,7 @@ export function createOverflowManager(): OverflowManager {

const overflowItems: Record<string, OverflowItemEntry> = {};
const overflowDividers: Record<string, OverflowDividerEntry> = {};
const resizeObserver = new ResizeObserver(entries => {
if (!entries[0] || !container) {
return;
}

update();
});
let disposeResizeObserver: () => void = () => null;

const getNextItem = (queueToDequeue: PriorityQueue<string>, queueToEnqueue: PriorityQueue<string>) => {
const nextItem = queueToDequeue.dequeue();
Expand Down Expand Up @@ -247,13 +242,19 @@ export function createOverflowManager(): OverflowManager {
Object.values(overflowItems).forEach(item => visibleItemQueue.enqueue(item.id));

container = observedContainer;
resizeObserver.observe(container);
disposeResizeObserver = observeResize(container, entries => {
if (!entries[0] || !container) {
return;
}

update();
});
};

const disconnect: OverflowManager['disconnect'] = () => {
observing = false;
sizeCache.clear();
resizeObserver.disconnect();
disposeResizeObserver();
};

const addItem: OverflowManager['addItem'] = item => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { canUseDOM } from '@fluentui/react-utilities';
import * as React from 'react';
import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';

Expand All @@ -21,7 +20,7 @@ export function useMeasureElement<TElement extends HTMLElement = HTMLElement>()
}, []);

// Keep the reference of ResizeObserver in the state, as it should live through renders
const [resizeObserver] = React.useState(canUseDOM() ? new ResizeObserver(handleResize) : undefined);
const [resizeObserver] = React.useState(() => createResizeObserverFromDocument(targetDocument, handleResize));
const measureElementRef = React.useCallback(
(el: TElement | null) => {
if (!targetDocument || !resizeObserver) {
Expand Down Expand Up @@ -49,3 +48,21 @@ export function useMeasureElement<TElement extends HTMLElement = HTMLElement>()

return { width, measureElementRef };
}

/**
* FIXME - TS 3.8/3.9 don't have ResizeObserver types by default, move this to a shared utility once we bump the minbar
* A utility method that creates a ResizeObserver from a target document
* @param targetDocument - document to use to create the ResizeObserver
* @param callback - https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver/ResizeObserver#callback
* @returns a ResizeObserver instance or null if the global does not exist on the document
*/
export function createResizeObserverFromDocument(
targetDocument: Document | null | undefined,
callback: ResizeObserverCallback,
) {
if (!targetDocument?.defaultView?.ResizeObserver) {
return null;
}

return new targetDocument.defaultView.ResizeObserver(callback);
}
1 change: 1 addition & 0 deletions packages/react-components/react-virtualizer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"dependencies": {
"@fluentui/react-jsx-runtime": "^9.0.18",
"@fluentui/react-utilities": "^9.15.1",
"@fluentui/react-shared-contexts": "^9.10.0",
"@griffel/react": "^1.5.14",
"@swc/helpers": "^0.5.1"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import * as React from 'react';
import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';
import { debounce } from '../utilities/debounce';
import { canUseDOM } from '@fluentui/react-utilities';
import { createResizeObserverFromDocument } from '../utilities/createResizeObserverFromDocument';
import { ResizeCallbackWithRef } from './hooks.types';

/**
* useResizeObserverRef_unstable simplifies resize observer connection and ensures debounce/cleanup
*/
export const useResizeObserverRef_unstable = (resizeCallback: ResizeCallbackWithRef) => {
const { targetDocument } = useFluent();
const container = React.useRef<HTMLElement | null>(null);
// the handler for resize observer
const handleResize = debounce((entries: ResizeObserverEntry[], observer: ResizeObserver) => {
Expand All @@ -15,16 +17,16 @@ export const useResizeObserverRef_unstable = (resizeCallback: ResizeCallbackWith

// Keep the reference of ResizeObserver in the state, as it should live through renders
const [resizeObserver, setResizeObserver] = React.useState(() =>
canUseDOM() ? new ResizeObserver(handleResize) : undefined,
createResizeObserverFromDocument(targetDocument, handleResize),
);

React.useEffect(() => {
// Update our state when resizeCallback changes
container.current = null;
resizeObserver?.disconnect();
setResizeObserver(canUseDOM() ? new ResizeObserver(handleResize) : undefined);
setResizeObserver(() => createResizeObserverFromDocument(targetDocument, handleResize));
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [resizeCallback]);
}, [resizeCallback, targetDocument]);

React.useEffect(() => {
return () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* FIXME - TS 3.8/3.9 don't have ResizeObserver types by default, move this to a shared utility once we bump the minbar
* A utility method that creates a ResizeObserver from a target document
* @param targetDocument - document to use to create the ResizeObserver
* @param callback - https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver/ResizeObserver#callback
* @returns a ResizeObserver instance or null if the global does not exist on the document
*/
export function createResizeObserverFromDocument(
targetDocument: Document | null | undefined,
callback: ResizeObserverCallback,
) {
if (!targetDocument?.defaultView?.ResizeObserver) {
return null;
}

return new targetDocument.defaultView.ResizeObserver(callback);
}