From 10dd23a63bc8dd7db718bd298290d8e542efd8eb Mon Sep 17 00:00:00 2001 From: Dmytro Kirpa Date: Thu, 21 May 2026 12:34:24 +0200 Subject: [PATCH 1/2] =?UTF-8?q?Revert=20"=20refactor(react-portal):=20remo?= =?UTF-8?q?ve=20Griffel=20dependency=20from=20usePortalMoun=E2=80=A6"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 48ff10fe4f0fe4c1ab9999a2544d6d49740728f3. --- .../components/Portal/usePortalMountNode.ts | 14 +-- .../Portal/usePortalMountNodeStyles.styles.ts | 18 ++++ .../Portal/usePortalMountNodeStyles.test.tsx | 97 ------------------- .../Portal/usePortalMountNodeStyles.ts | 83 ---------------- 4 files changed, 26 insertions(+), 186 deletions(-) create mode 100644 packages/react-components/react-portal/library/src/components/Portal/usePortalMountNodeStyles.styles.ts delete mode 100644 packages/react-components/react-portal/library/src/components/Portal/usePortalMountNodeStyles.test.tsx delete mode 100644 packages/react-components/react-portal/library/src/components/Portal/usePortalMountNodeStyles.ts diff --git a/packages/react-components/react-portal/library/src/components/Portal/usePortalMountNode.ts b/packages/react-components/react-portal/library/src/components/Portal/usePortalMountNode.ts index 8c260da5b0510..f62e4184c0570 100644 --- a/packages/react-components/react-portal/library/src/components/Portal/usePortalMountNode.ts +++ b/packages/react-components/react-portal/library/src/components/Portal/usePortalMountNode.ts @@ -6,9 +6,10 @@ import { useFluent_unstable as useFluent, usePortalMountNode as usePortalMountNodeContext, } from '@fluentui/react-shared-contexts'; +import { mergeClasses } from '@griffel/react'; import { useFocusVisible } from '@fluentui/react-tabster'; -import { usePortalMountNodeStyles } from './usePortalMountNodeStyles'; +import { usePortalMountNodeStylesStyles } from './usePortalMountNodeStyles.styles'; const useInsertionEffect = (React as never)['useInsertion' + 'Effect'] as typeof React.useLayoutEffect | undefined; @@ -200,14 +201,16 @@ const useModernElementFactory: UseElementFactory = options => { return; } - elementProxy.setAttribute('class', className); + const classesToApply = className.split(' ').filter(Boolean); + + elementProxy.classList.add(...classesToApply); elementProxy.setAttribute('dir', dir); elementProxy.setAttribute('data-portal-node', 'true'); focusVisibleRef.current = elementProxy; return () => { - elementProxy.removeAttribute('class'); + elementProxy.classList.remove(...classesToApply); elementProxy.removeAttribute('dir'); }; }, [className, dir, elementProxy, focusVisibleRef]); @@ -243,6 +246,7 @@ export const usePortalMountNode = (options: UsePortalMountNodeOptions): HTMLElem // eslint-disable-next-line @typescript-eslint/no-deprecated const focusVisibleRef = useFocusVisible() as React.MutableRefObject; + const classes = usePortalMountNodeStylesStyles(); const themeClassName = useThemeClassName(); const factoryOptions: UseElementFactoryOptions = { @@ -250,11 +254,9 @@ export const usePortalMountNode = (options: UsePortalMountNodeOptions): HTMLElem disabled: options.disabled, focusVisibleRef, - className: [themeClassName, options.className].filter(Boolean).join(' '), + className: mergeClasses(themeClassName, classes.root, options.className), targetNode: mountNode ?? targetDocument?.body, }; - usePortalMountNodeStyles(options.disabled); - return useElementFactory(factoryOptions); }; diff --git a/packages/react-components/react-portal/library/src/components/Portal/usePortalMountNodeStyles.styles.ts b/packages/react-components/react-portal/library/src/components/Portal/usePortalMountNodeStyles.styles.ts new file mode 100644 index 0000000000000..ed71de8078679 --- /dev/null +++ b/packages/react-components/react-portal/library/src/components/Portal/usePortalMountNodeStyles.styles.ts @@ -0,0 +1,18 @@ +'use client'; + +import { makeStyles } from '@griffel/react'; + +export const usePortalMountNodeStylesStyles = makeStyles({ + root: { + // Creates new stacking context to prevent z-index issues + // https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_positioned_layout/Understanding_z-index/Stacking_context + // + // Also keeps a portal on top of a page to prevent scrollbars from appearing + position: 'absolute', + top: 0, + left: 0, + right: 0, + + zIndex: 1000000, + }, +}); diff --git a/packages/react-components/react-portal/library/src/components/Portal/usePortalMountNodeStyles.test.tsx b/packages/react-components/react-portal/library/src/components/Portal/usePortalMountNodeStyles.test.tsx deleted file mode 100644 index af3093466b518..0000000000000 --- a/packages/react-components/react-portal/library/src/components/Portal/usePortalMountNodeStyles.test.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import { renderHook } from '@testing-library/react-hooks'; -import { Provider_unstable as Provider } from '@fluentui/react-shared-contexts'; -import * as React from 'react'; - -import { usePortalMountNodeStyles, PORTAL_STYLE_ELEMENT_ID, setPortalRefCount } from './usePortalMountNodeStyles'; - -function queryStyleElement(): HTMLStyleElement | null { - return document.head.querySelector(`#${PORTAL_STYLE_ELEMENT_ID}`); -} - -function createWrapper(targetDocument: Document | undefined) { - return (props: { children?: React.ReactNode }) => ( - {props.children} - ); -} - -describe('usePortalMountNodeStyles', () => { - afterEach(() => { - // Clean up any leftover style elements and reset the ref count - queryStyleElement()?.remove(); - setPortalRefCount(document, 0); - }); - - it('injects a