@fluentui/react-portal 9.8.12 → 9.8.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. package/CHANGELOG.md +26 -4
  2. package/lib/components/Portal/usePortalMountNode.js +12 -11
  3. package/lib/components/Portal/usePortalMountNode.js.map +1 -1
  4. package/lib/components/Portal/usePortalMountNodeStyles.styles.js +14 -0
  5. package/lib/components/Portal/usePortalMountNodeStyles.styles.js.map +1 -0
  6. package/lib/components/Portal/usePortalMountNodeStyles.styles.raw.js +15 -0
  7. package/lib/components/Portal/usePortalMountNodeStyles.styles.raw.js.map +1 -0
  8. package/lib-commonjs/Portal.js.map +1 -1
  9. package/lib-commonjs/components/Portal/Portal.js.map +1 -1
  10. package/lib-commonjs/components/Portal/Portal.types.js.map +1 -1
  11. package/lib-commonjs/components/Portal/index.js.map +1 -1
  12. package/lib-commonjs/components/Portal/renderPortal.js.map +1 -1
  13. package/lib-commonjs/components/Portal/usePortal.js.map +1 -1
  14. package/lib-commonjs/components/Portal/usePortalMountNode.js +12 -11
  15. package/lib-commonjs/components/Portal/usePortalMountNode.js.map +1 -1
  16. package/lib-commonjs/components/Portal/usePortalMountNodeStyles.styles.js +35 -0
  17. package/lib-commonjs/components/Portal/usePortalMountNodeStyles.styles.js.map +1 -0
  18. package/lib-commonjs/components/Portal/usePortalMountNodeStyles.styles.raw.js +25 -0
  19. package/lib-commonjs/components/Portal/usePortalMountNodeStyles.styles.raw.js.map +1 -0
  20. package/lib-commonjs/index.js.map +1 -1
  21. package/lib-commonjs/utils/toMountNodeProps.js.map +1 -1
  22. package/package.json +3 -3
  23. package/lib/components/Portal/usePortalMountNodeStyles.js +0 -73
  24. package/lib/components/Portal/usePortalMountNodeStyles.js.map +0 -1
  25. package/lib-commonjs/components/Portal/usePortalMountNodeStyles.js +0 -93
  26. package/lib-commonjs/components/Portal/usePortalMountNodeStyles.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,19 +1,41 @@
1
1
  # Change Log - @fluentui/react-portal
2
2
 
3
- This log was last generated on Thu, 23 Apr 2026 11:59:29 GMT and should not be manually modified.
3
+ This log was last generated on Wed, 24 Jun 2026 11:03:41 GMT and should not be manually modified.
4
4
 
5
5
  <!-- Start content -->
6
6
 
7
+ ## [9.8.14](https://github.com/microsoft/fluentui/tree/@fluentui/react-portal_v9.8.14)
8
+
9
+ Wed, 24 Jun 2026 11:03:41 GMT
10
+ [Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-portal_v9.8.13..@fluentui/react-portal_v9.8.14)
11
+
12
+ ### Patches
13
+
14
+ - fix: remove redundant use no memo directives, and add justification to valid ones ([PR #36224](https://github.com/microsoft/fluentui/pull/36224) by martinhochel@microsoft.com)
15
+ - Bump @fluentui/react-tabster to v9.26.16 ([commit](https://github.com/microsoft/fluentui/commit/a4b871ca80c1f16f35ab4229def4fe02be7f30ea) by beachball)
16
+ - Bump @fluentui/react-utilities to v9.26.5 ([commit](https://github.com/microsoft/fluentui/commit/a4b871ca80c1f16f35ab4229def4fe02be7f30ea) by beachball)
17
+
18
+ ## [9.8.13](https://github.com/microsoft/fluentui/tree/@fluentui/react-portal_v9.8.13)
19
+
20
+ Tue, 26 May 2026 09:39:31 GMT
21
+ [Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-portal_v9.8.12..@fluentui/react-portal_v9.8.13)
22
+
23
+ ### Patches
24
+
25
+ - revert: revert removal of Griffel dependency from usePortalMount #35994 ([PR #36235](https://github.com/microsoft/fluentui/pull/36235) by dmytrokirpa@microsoft.com)
26
+ - Bump @fluentui/react-tabster to v9.26.15 ([PR #36246](https://github.com/microsoft/fluentui/pull/36246) by beachball)
27
+ - Bump @fluentui/react-utilities to v9.26.4 ([PR #36246](https://github.com/microsoft/fluentui/pull/36246) by beachball)
28
+
7
29
  ## [9.8.12](https://github.com/microsoft/fluentui/tree/@fluentui/react-portal_v9.8.12)
8
30
 
9
- Thu, 23 Apr 2026 11:59:29 GMT
31
+ Thu, 23 Apr 2026 14:21:09 GMT
10
32
  [Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-portal_v9.8.11..@fluentui/react-portal_v9.8.12)
11
33
 
12
34
  ### Patches
13
35
 
14
36
  - refactor: remove Griffel dependency from usePortalMountNode ([PR #35994](https://github.com/microsoft/fluentui/pull/35994) by dmytrokirpa@microsoft.com)
15
- - Bump @fluentui/react-tabster to v9.26.14 ([PR #35996](https://github.com/microsoft/fluentui/pull/35996) by beachball)
16
- - Bump @fluentui/react-utilities to v9.26.3 ([PR #35996](https://github.com/microsoft/fluentui/pull/35996) by beachball)
37
+ - Bump @fluentui/react-tabster to v9.26.14 ([PR #36035](https://github.com/microsoft/fluentui/pull/36035) by beachball)
38
+ - Bump @fluentui/react-utilities to v9.26.3 ([PR #36035](https://github.com/microsoft/fluentui/pull/36035) by beachball)
17
39
 
18
40
  ## [9.8.11](https://github.com/microsoft/fluentui/tree/@fluentui/react-portal_v9.8.11)
19
41
 
@@ -1,15 +1,15 @@
1
1
  'use client';
2
2
  import * as React from 'react';
3
3
  import { useThemeClassName_unstable as useThemeClassName, useFluent_unstable as useFluent, usePortalMountNode as usePortalMountNodeContext } from '@fluentui/react-shared-contexts';
4
+ import { mergeClasses } from '@griffel/react';
4
5
  import { useFocusVisible } from '@fluentui/react-tabster';
5
- import { usePortalMountNodeStyles } from './usePortalMountNodeStyles';
6
+ import { usePortalMountNodeStylesStyles } from './usePortalMountNodeStyles.styles';
6
7
  const useInsertionEffect = React['useInsertion' + 'Effect'];
7
8
  /**
8
9
  * Legacy element factory for React 17 and below. It's not safe for concurrent rendering.
9
10
  *
10
11
  * Creates a new element on a "document.body" to mount portals.
11
12
  */ const useLegacyElementFactory = (options)=>{
12
- 'use no memo';
13
13
  const { className, dir, focusVisibleRef, targetNode } = options;
14
14
  const targetElement = React.useMemo(()=>{
15
15
  if (targetNode === undefined || options.disabled) {
@@ -28,13 +28,16 @@ const useInsertionEffect = React['useInsertion' + 'Effect'];
28
28
  // We don't want to re-create the portal element when its attributes change. This also cannot not be done in an effect
29
29
  // because, changing the value of CSS variables after an initial mount will trigger interesting CSS side effects like
30
30
  // transitions.
31
+ // eslint-disable-next-line react-hooks/void-use-memo
31
32
  React.useMemo(()=>{
32
33
  if (!targetElement) {
33
34
  return;
34
35
  }
36
+ // eslint-disable-next-line react-hooks/immutability
35
37
  targetElement.className = className;
36
38
  targetElement.setAttribute('dir', dir);
37
39
  targetElement.setAttribute('data-portal-node', 'true');
40
+ // eslint-disable-next-line react-hooks/refs
38
41
  focusVisibleRef.current = targetElement;
39
42
  }, [
40
43
  className,
@@ -81,7 +84,7 @@ const initializeElementFactory = ()=>{
81
84
  * - the `remove()` method (we call it in `useEffect()`) and remove the element only when the portal is unmounted
82
85
  * - all other methods (and properties) will be called by React once a portal is mounted
83
86
  */ const useModernElementFactory = (options)=>{
84
- 'use no memo';
87
+ 'use no memo'; // justified: compiler would optimize dispose — manual opt-out to preserve runtime behavior
85
88
  const { className, dir, focusVisibleRef, targetNode } = options;
86
89
  const [elementFactory] = React.useState(initializeElementFactory);
87
90
  const elementProxy = React.useMemo(()=>{
@@ -148,12 +151,13 @@ const initializeElementFactory = ()=>{
148
151
  if (!elementProxy) {
149
152
  return;
150
153
  }
151
- elementProxy.setAttribute('class', className);
154
+ const classesToApply = className.split(' ').filter(Boolean);
155
+ elementProxy.classList.add(...classesToApply);
152
156
  elementProxy.setAttribute('dir', dir);
153
157
  elementProxy.setAttribute('data-portal-node', 'true');
154
158
  focusVisibleRef.current = elementProxy;
155
159
  return ()=>{
156
- elementProxy.removeAttribute('class');
160
+ elementProxy.classList.remove(...classesToApply);
157
161
  elementProxy.removeAttribute('dir');
158
162
  };
159
163
  }, [
@@ -183,22 +187,19 @@ const initializeElementFactory = ()=>{
183
187
  /**
184
188
  * Creates a new element on a "document.body" to mount portals.
185
189
  */ export const usePortalMountNode = (options)=>{
186
- 'use no memo';
190
+ 'use no memo'; // justified: compiler would optimize usePortalMountNode — manual opt-out to preserve runtime behavior
187
191
  const { targetDocument, dir } = useFluent();
188
192
  const mountNode = usePortalMountNodeContext();
189
193
  // eslint-disable-next-line @typescript-eslint/no-deprecated
190
194
  const focusVisibleRef = useFocusVisible();
195
+ const classes = usePortalMountNodeStylesStyles();
191
196
  const themeClassName = useThemeClassName();
192
197
  const factoryOptions = {
193
198
  dir,
194
199
  disabled: options.disabled,
195
200
  focusVisibleRef,
196
- className: [
197
- themeClassName,
198
- options.className
199
- ].filter(Boolean).join(' '),
201
+ className: mergeClasses(themeClassName, classes.root, options.className),
200
202
  targetNode: mountNode !== null && mountNode !== void 0 ? mountNode : targetDocument === null || targetDocument === void 0 ? void 0 : targetDocument.body
201
203
  };
202
- usePortalMountNodeStyles(options.disabled);
203
204
  return useElementFactory(factoryOptions);
204
205
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/Portal/usePortalMountNode.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport {\n useThemeClassName_unstable as useThemeClassName,\n useFluent_unstable as useFluent,\n usePortalMountNode as usePortalMountNodeContext,\n} from '@fluentui/react-shared-contexts';\nimport { useFocusVisible } from '@fluentui/react-tabster';\n\nimport { usePortalMountNodeStyles } from './usePortalMountNodeStyles';\n\nconst useInsertionEffect = (React as never)['useInsertion' + 'Effect'] as typeof React.useLayoutEffect | undefined;\n\nexport type UsePortalMountNodeOptions = {\n /**\n * Since hooks cannot be called conditionally use this flag to disable creating the node\n */\n disabled?: boolean;\n\n className?: string;\n};\n\ntype UseElementFactoryOptions = {\n className: string;\n dir: string;\n disabled: boolean | undefined;\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n focusVisibleRef: React.MutableRefObject<HTMLElement | null>;\n targetNode: HTMLElement | ShadowRoot | undefined;\n};\ntype UseElementFactory = (options: UseElementFactoryOptions) => HTMLDivElement | null;\n\n/**\n * Legacy element factory for React 17 and below. It's not safe for concurrent rendering.\n *\n * Creates a new element on a \"document.body\" to mount portals.\n */\nconst useLegacyElementFactory: UseElementFactory = options => {\n 'use no memo';\n\n const { className, dir, focusVisibleRef, targetNode } = options;\n\n const targetElement = React.useMemo(() => {\n if (targetNode === undefined || options.disabled) {\n return null;\n }\n\n const element = targetNode.ownerDocument.createElement('div');\n targetNode.appendChild(element);\n\n return element;\n }, [targetNode, options.disabled]);\n\n // Heads up!\n // This useMemo() call is intentional for React 17 & below.\n //\n // We don't want to re-create the portal element when its attributes change. This also cannot not be done in an effect\n // because, changing the value of CSS variables after an initial mount will trigger interesting CSS side effects like\n // transitions.\n React.useMemo(() => {\n if (!targetElement) {\n return;\n }\n\n targetElement.className = className;\n targetElement.setAttribute('dir', dir);\n targetElement.setAttribute('data-portal-node', 'true');\n\n focusVisibleRef.current = targetElement;\n }, [className, dir, targetElement, focusVisibleRef]);\n\n React.useEffect(() => {\n return () => {\n targetElement?.remove();\n };\n }, [targetElement]);\n\n return targetElement;\n};\n\nconst initializeElementFactory = () => {\n let currentElement: HTMLDivElement | undefined = undefined;\n\n function get(targetRoot: HTMLElement | ShadowRoot, forceCreation: boolean): HTMLDivElement | undefined {\n if (currentElement) {\n return currentElement;\n }\n\n if (forceCreation) {\n currentElement = targetRoot.ownerDocument.createElement('div');\n targetRoot.appendChild(currentElement);\n }\n\n return currentElement;\n }\n\n function dispose() {\n if (currentElement) {\n currentElement.remove();\n currentElement = undefined;\n }\n }\n\n return {\n get,\n dispose,\n };\n};\n\n/**\n * This is a modern element factory for React 18 and above. It is safe for concurrent rendering.\n *\n * It abuses the fact that React will mount DOM once (unlike hooks), so by using a proxy we can intercept:\n * - the `remove()` method (we call it in `useEffect()`) and remove the element only when the portal is unmounted\n * - all other methods (and properties) will be called by React once a portal is mounted\n */\nconst useModernElementFactory: UseElementFactory = options => {\n 'use no memo';\n\n const { className, dir, focusVisibleRef, targetNode } = options;\n\n const [elementFactory] = React.useState(initializeElementFactory);\n\n const elementProxy = React.useMemo(() => {\n if (targetNode === undefined || options.disabled) {\n return null;\n }\n\n return new Proxy({} as HTMLDivElement, {\n get(_, property: keyof HTMLDivElement) {\n // Heads up!\n // `createPortal()` performs a check for `nodeType` property to determine if the mount node is a valid DOM node\n // before mounting the portal. We hardcode the value to `Node.ELEMENT_NODE` to pass this check and avoid\n // premature node creation\n if (property === 'nodeType') {\n // Can't use the `Node.ELEMENT_NODE` as it's a browser API and not available in all environments, e.g SSR\n return 1; // `Node.ELEMENT_NODE`\n }\n\n // Heads up!\n // We intercept the `remove()` method to remove the mount node only when portal has been unmounted already.\n if (property === 'remove') {\n const targetElement = elementFactory.get(targetNode, false);\n\n if (targetElement) {\n // If the mountElement has children, the portal is still mounted, otherwise we can dispose of it\n const portalHasNoChildren = targetElement.childNodes.length === 0;\n\n if (portalHasNoChildren) {\n elementFactory.dispose();\n }\n }\n\n return () => {\n // Always return a no-op function to avoid errors in the code\n };\n }\n\n const targetElement = elementFactory.get(targetNode, true);\n const targetProperty = targetElement ? targetElement[property] : undefined;\n\n if (typeof targetProperty === 'function') {\n return targetProperty.bind(targetElement);\n }\n\n return targetProperty;\n },\n\n set(_, property: keyof HTMLDivElement | '_virtual' | 'focusVisible', value) {\n const ignoredProperty = property === '_virtual' || property === 'focusVisible';\n\n // We should use the `elementFactory.get(targetNode, !ignoredProperty)`,\n // but TypeScript requires a literal `true` or `false` for the overload signature.\n // This workaround ensures the correct overload is called and avoids TypeScript errors.\n const targetElement = ignoredProperty\n ? elementFactory.get(targetNode, false)\n : elementFactory.get(targetNode, true);\n\n if (ignoredProperty && !targetElement) {\n // We ignore the `_virtual` and `focusVisible` properties to avoid conflicts with the proxy\n return true;\n }\n\n if (targetElement) {\n Object.assign(targetElement, { [property]: value });\n return true;\n }\n\n return false;\n },\n });\n }, [elementFactory, targetNode, options.disabled]);\n\n useInsertionEffect!(() => {\n if (!elementProxy) {\n return;\n }\n\n elementProxy.setAttribute('class', className);\n elementProxy.setAttribute('dir', dir);\n elementProxy.setAttribute('data-portal-node', 'true');\n\n focusVisibleRef.current = elementProxy;\n\n return () => {\n elementProxy.removeAttribute('class');\n elementProxy.removeAttribute('dir');\n };\n }, [className, dir, elementProxy, focusVisibleRef]);\n\n React.useEffect(() => {\n return () => {\n elementProxy?.remove();\n };\n }, [elementProxy]);\n\n return elementProxy;\n};\n\n/**\n * Element factory based on the React version.\n *\n * React 17 and below:\n * - useLegacyElementFactory\n *\n * React 18 and above:\n * - useModernElementFactory\n */\nconst useElementFactory = useInsertionEffect ? useModernElementFactory : useLegacyElementFactory;\n\n/**\n * Creates a new element on a \"document.body\" to mount portals.\n */\nexport const usePortalMountNode = (options: UsePortalMountNodeOptions): HTMLElement | null => {\n ('use no memo');\n\n const { targetDocument, dir } = useFluent();\n const mountNode = usePortalMountNodeContext();\n\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n const focusVisibleRef = useFocusVisible<HTMLDivElement>() as React.MutableRefObject<HTMLElement | null>;\n const themeClassName = useThemeClassName();\n\n const factoryOptions: UseElementFactoryOptions = {\n dir,\n disabled: options.disabled,\n focusVisibleRef,\n\n className: [themeClassName, options.className].filter(Boolean).join(' '),\n targetNode: mountNode ?? targetDocument?.body,\n };\n\n usePortalMountNodeStyles(options.disabled);\n\n return useElementFactory(factoryOptions);\n};\n"],"names":["React","useThemeClassName_unstable","useThemeClassName","useFluent_unstable","useFluent","usePortalMountNode","usePortalMountNodeContext","useFocusVisible","usePortalMountNodeStyles","useInsertionEffect","useLegacyElementFactory","options","className","dir","focusVisibleRef","targetNode","targetElement","useMemo","undefined","disabled","element","ownerDocument","createElement","appendChild","setAttribute","current","useEffect","remove","initializeElementFactory","currentElement","get","targetRoot","forceCreation","dispose","useModernElementFactory","elementFactory","useState","elementProxy","Proxy","_","property","portalHasNoChildren","childNodes","length","targetProperty","bind","set","value","ignoredProperty","Object","assign","removeAttribute","useElementFactory","targetDocument","mountNode","themeClassName","factoryOptions","filter","Boolean","join","body"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/components/Portal/usePortalMountNode.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport {\n useThemeClassName_unstable as useThemeClassName,\n useFluent_unstable as useFluent,\n usePortalMountNode as usePortalMountNodeContext,\n} from '@fluentui/react-shared-contexts';\nimport { mergeClasses } from '@griffel/react';\nimport { useFocusVisible } from '@fluentui/react-tabster';\n\nimport { usePortalMountNodeStylesStyles } from './usePortalMountNodeStyles.styles';\n\nconst useInsertionEffect = (React as never)['useInsertion' + 'Effect'] as typeof React.useLayoutEffect | undefined;\n\nexport type UsePortalMountNodeOptions = {\n /**\n * Since hooks cannot be called conditionally use this flag to disable creating the node\n */\n disabled?: boolean;\n\n className?: string;\n};\n\ntype UseElementFactoryOptions = {\n className: string;\n dir: string;\n disabled: boolean | undefined;\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n focusVisibleRef: React.MutableRefObject<HTMLElement | null>;\n targetNode: HTMLElement | ShadowRoot | undefined;\n};\ntype UseElementFactory = (options: UseElementFactoryOptions) => HTMLDivElement | null;\n\n/**\n * Legacy element factory for React 17 and below. It's not safe for concurrent rendering.\n *\n * Creates a new element on a \"document.body\" to mount portals.\n */\nconst useLegacyElementFactory: UseElementFactory = options => {\n const { className, dir, focusVisibleRef, targetNode } = options;\n\n const targetElement = React.useMemo(() => {\n if (targetNode === undefined || options.disabled) {\n return null;\n }\n\n const element = targetNode.ownerDocument.createElement('div');\n targetNode.appendChild(element);\n\n return element;\n }, [targetNode, options.disabled]);\n\n // Heads up!\n // This useMemo() call is intentional for React 17 & below.\n //\n // We don't want to re-create the portal element when its attributes change. This also cannot not be done in an effect\n // because, changing the value of CSS variables after an initial mount will trigger interesting CSS side effects like\n // transitions.\n // eslint-disable-next-line react-hooks/void-use-memo\n React.useMemo(() => {\n if (!targetElement) {\n return;\n }\n\n // eslint-disable-next-line react-hooks/immutability\n targetElement.className = className;\n targetElement.setAttribute('dir', dir);\n targetElement.setAttribute('data-portal-node', 'true');\n\n // eslint-disable-next-line react-hooks/refs\n focusVisibleRef.current = targetElement;\n }, [className, dir, targetElement, focusVisibleRef]);\n\n React.useEffect(() => {\n return () => {\n targetElement?.remove();\n };\n }, [targetElement]);\n\n return targetElement;\n};\n\nconst initializeElementFactory = () => {\n let currentElement: HTMLDivElement | undefined = undefined;\n\n function get(targetRoot: HTMLElement | ShadowRoot, forceCreation: boolean): HTMLDivElement | undefined {\n if (currentElement) {\n return currentElement;\n }\n\n if (forceCreation) {\n currentElement = targetRoot.ownerDocument.createElement('div');\n targetRoot.appendChild(currentElement);\n }\n\n return currentElement;\n }\n\n function dispose() {\n if (currentElement) {\n currentElement.remove();\n currentElement = undefined;\n }\n }\n\n return {\n get,\n dispose,\n };\n};\n\n/**\n * This is a modern element factory for React 18 and above. It is safe for concurrent rendering.\n *\n * It abuses the fact that React will mount DOM once (unlike hooks), so by using a proxy we can intercept:\n * - the `remove()` method (we call it in `useEffect()`) and remove the element only when the portal is unmounted\n * - all other methods (and properties) will be called by React once a portal is mounted\n */\nconst useModernElementFactory: UseElementFactory = options => {\n 'use no memo'; // justified: compiler would optimize dispose — manual opt-out to preserve runtime behavior\n\n const { className, dir, focusVisibleRef, targetNode } = options;\n\n const [elementFactory] = React.useState(initializeElementFactory);\n\n const elementProxy = React.useMemo(() => {\n if (targetNode === undefined || options.disabled) {\n return null;\n }\n\n return new Proxy({} as HTMLDivElement, {\n get(_, property: keyof HTMLDivElement) {\n // Heads up!\n // `createPortal()` performs a check for `nodeType` property to determine if the mount node is a valid DOM node\n // before mounting the portal. We hardcode the value to `Node.ELEMENT_NODE` to pass this check and avoid\n // premature node creation\n if (property === 'nodeType') {\n // Can't use the `Node.ELEMENT_NODE` as it's a browser API and not available in all environments, e.g SSR\n return 1; // `Node.ELEMENT_NODE`\n }\n\n // Heads up!\n // We intercept the `remove()` method to remove the mount node only when portal has been unmounted already.\n if (property === 'remove') {\n const targetElement = elementFactory.get(targetNode, false);\n\n if (targetElement) {\n // If the mountElement has children, the portal is still mounted, otherwise we can dispose of it\n const portalHasNoChildren = targetElement.childNodes.length === 0;\n\n if (portalHasNoChildren) {\n elementFactory.dispose();\n }\n }\n\n return () => {\n // Always return a no-op function to avoid errors in the code\n };\n }\n\n const targetElement = elementFactory.get(targetNode, true);\n const targetProperty = targetElement ? targetElement[property] : undefined;\n\n if (typeof targetProperty === 'function') {\n return targetProperty.bind(targetElement);\n }\n\n return targetProperty;\n },\n\n set(_, property: keyof HTMLDivElement | '_virtual' | 'focusVisible', value) {\n const ignoredProperty = property === '_virtual' || property === 'focusVisible';\n\n // We should use the `elementFactory.get(targetNode, !ignoredProperty)`,\n // but TypeScript requires a literal `true` or `false` for the overload signature.\n // This workaround ensures the correct overload is called and avoids TypeScript errors.\n const targetElement = ignoredProperty\n ? elementFactory.get(targetNode, false)\n : elementFactory.get(targetNode, true);\n\n if (ignoredProperty && !targetElement) {\n // We ignore the `_virtual` and `focusVisible` properties to avoid conflicts with the proxy\n return true;\n }\n\n if (targetElement) {\n Object.assign(targetElement, { [property]: value });\n return true;\n }\n\n return false;\n },\n });\n }, [elementFactory, targetNode, options.disabled]);\n\n useInsertionEffect!(() => {\n if (!elementProxy) {\n return;\n }\n\n const classesToApply = className.split(' ').filter(Boolean);\n\n elementProxy.classList.add(...classesToApply);\n elementProxy.setAttribute('dir', dir);\n elementProxy.setAttribute('data-portal-node', 'true');\n\n focusVisibleRef.current = elementProxy;\n\n return () => {\n elementProxy.classList.remove(...classesToApply);\n elementProxy.removeAttribute('dir');\n };\n }, [className, dir, elementProxy, focusVisibleRef]);\n\n React.useEffect(() => {\n return () => {\n elementProxy?.remove();\n };\n }, [elementProxy]);\n\n return elementProxy;\n};\n\n/**\n * Element factory based on the React version.\n *\n * React 17 and below:\n * - useLegacyElementFactory\n *\n * React 18 and above:\n * - useModernElementFactory\n */\nconst useElementFactory = useInsertionEffect ? useModernElementFactory : useLegacyElementFactory;\n\n/**\n * Creates a new element on a \"document.body\" to mount portals.\n */\nexport const usePortalMountNode = (options: UsePortalMountNodeOptions): HTMLElement | null => {\n ('use no memo'); // justified: compiler would optimize usePortalMountNode — manual opt-out to preserve runtime behavior\n\n const { targetDocument, dir } = useFluent();\n const mountNode = usePortalMountNodeContext();\n\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n const focusVisibleRef = useFocusVisible<HTMLDivElement>() as React.MutableRefObject<HTMLElement | null>;\n const classes = usePortalMountNodeStylesStyles();\n const themeClassName = useThemeClassName();\n\n const factoryOptions: UseElementFactoryOptions = {\n dir,\n disabled: options.disabled,\n focusVisibleRef,\n\n className: mergeClasses(themeClassName, classes.root, options.className),\n targetNode: mountNode ?? targetDocument?.body,\n };\n\n return useElementFactory(factoryOptions);\n};\n"],"names":["React","useThemeClassName_unstable","useThemeClassName","useFluent_unstable","useFluent","usePortalMountNode","usePortalMountNodeContext","mergeClasses","useFocusVisible","usePortalMountNodeStylesStyles","useInsertionEffect","useLegacyElementFactory","options","className","dir","focusVisibleRef","targetNode","targetElement","useMemo","undefined","disabled","element","ownerDocument","createElement","appendChild","setAttribute","current","useEffect","remove","initializeElementFactory","currentElement","get","targetRoot","forceCreation","dispose","useModernElementFactory","elementFactory","useState","elementProxy","Proxy","_","property","portalHasNoChildren","childNodes","length","targetProperty","bind","set","value","ignoredProperty","Object","assign","classesToApply","split","filter","Boolean","classList","add","removeAttribute","useElementFactory","targetDocument","mountNode","classes","themeClassName","factoryOptions","root","body"],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ 'use client';
2
+
3
+ import { __styles } from '@griffel/react';
4
+ export const usePortalMountNodeStylesStyles = /*#__PURE__*/__styles({
5
+ root: {
6
+ qhf8xq: "f1euv43f",
7
+ Bhzewxz: "f15twtuk",
8
+ oyh7mz: ["f1vgc2s3", "f1e31b4d"],
9
+ j35jbq: ["f1e31b4d", "f1vgc2s3"],
10
+ Bj3rh1h: "f494woh"
11
+ }
12
+ }, {
13
+ d: [".f1euv43f{position:absolute;}", ".f15twtuk{top:0;}", ".f1vgc2s3{left:0;}", ".f1e31b4d{right:0;}", ".f494woh{z-index:1000000;}"]
14
+ });
@@ -0,0 +1 @@
1
+ {"version":3,"names":["__styles","usePortalMountNodeStylesStyles","root","qhf8xq","Bhzewxz","oyh7mz","j35jbq","Bj3rh1h","d"],"sources":["usePortalMountNodeStyles.styles.js"],"sourcesContent":["'use client';\nimport { makeStyles } from '@griffel/react';\nexport const usePortalMountNodeStylesStyles = makeStyles({\n root: {\n // Creates new stacking context to prevent z-index issues\n // https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_positioned_layout/Understanding_z-index/Stacking_context\n //\n // Also keeps a portal on top of a page to prevent scrollbars from appearing\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n zIndex: 1000000\n }\n});\n"],"mappings":"AAAA,YAAY;;AACZ,SAAAA,QAAA,QAA2B,gBAAgB;AAC3C,OAAO,MAAMC,8BAA8B,gBAAGD,QAAA;EAAAE,IAAA;IAAAC,MAAA;IAAAC,OAAA;IAAAC,MAAA;IAAAC,MAAA;IAAAC,OAAA;EAAA;AAAA;EAAAC,CAAA;AAAA,CAY7C,CAAC","ignoreList":[]}
@@ -0,0 +1,15 @@
1
+ 'use client';
2
+ import { makeStyles } from '@griffel/react';
3
+ export const usePortalMountNodeStylesStyles = makeStyles({
4
+ root: {
5
+ // Creates new stacking context to prevent z-index issues
6
+ // https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_positioned_layout/Understanding_z-index/Stacking_context
7
+ //
8
+ // Also keeps a portal on top of a page to prevent scrollbars from appearing
9
+ position: 'absolute',
10
+ top: 0,
11
+ left: 0,
12
+ right: 0,
13
+ zIndex: 1000000
14
+ }
15
+ });
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/Portal/usePortalMountNodeStyles.styles.ts"],"sourcesContent":["'use client';\n\nimport { makeStyles } from '@griffel/react';\n\nexport const usePortalMountNodeStylesStyles = makeStyles({\n root: {\n // Creates new stacking context to prevent z-index issues\n // https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_positioned_layout/Understanding_z-index/Stacking_context\n //\n // Also keeps a portal on top of a page to prevent scrollbars from appearing\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n\n zIndex: 1000000,\n },\n});\n"],"names":["makeStyles","usePortalMountNodeStylesStyles","root","position","top","left","right","zIndex"],"mappings":"AAAA;AAEA,SAASA,UAAU,QAAQ,iBAAiB;AAE5C,OAAO,MAAMC,iCAAiCD,WAAW;IACvDE,MAAM;QACJ,yDAAyD;QACzD,gHAAgH;QAChH,EAAE;QACF,4EAA4E;QAC5EC,UAAU;QACVC,KAAK;QACLC,MAAM;QACNC,OAAO;QAEPC,QAAQ;IACV;AACF,GAAG"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/Portal.ts"],"sourcesContent":["export type { PortalProps, PortalState } from './components/Portal/index';\nexport { Portal, renderPortal_unstable, usePortal_unstable } from './components/Portal/index';\n"],"names":["Portal","renderPortal_unstable","usePortal_unstable"],"mappings":";;;;;;;;;;;IACSA,MAAM;eAANA,aAAM;;IAAEC,qBAAqB;eAArBA,4BAAqB;;IAAEC,kBAAkB;eAAlBA,yBAAkB;;;uBAAQ"}
1
+ {"version":3,"sources":["../src/Portal.ts"],"sourcesContent":["export type { PortalProps, PortalState } from './components/Portal/index';\nexport { Portal, renderPortal_unstable, usePortal_unstable } from './components/Portal/index';\n"],"names":["Portal","renderPortal_unstable","usePortal_unstable"],"mappings":";;;;;;;;;;;;eACSA,aAAM;;;eAAEC,4BAAqB;;;eAAEC,yBAAkB;;;uBAAQ,4BAA4B"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/Portal/Portal.tsx"],"sourcesContent":["'use client';\n\nimport type * as React from 'react';\n\nimport { usePortal_unstable } from './usePortal';\nimport { renderPortal_unstable } from './renderPortal';\nimport type { PortalProps } from './Portal.types';\n\n/**\n * A portal provides a way to render children into a DOM node\n * that exists outside the DOM hierarchy of the parent component.\n */\nexport const Portal: React.FC<PortalProps> = props => {\n const state = usePortal_unstable(props);\n\n return renderPortal_unstable(state);\n};\n\nPortal.displayName = 'Portal';\n"],"names":["Portal","props","state","usePortal_unstable","renderPortal_unstable","displayName"],"mappings":"AAAA;;;;;+BAYaA;;;eAAAA;;;2BARsB;8BACG;AAO/B,MAAMA,SAAgCC,CAAAA;IAC3C,MAAMC,QAAQC,IAAAA,6BAAkB,EAACF;IAEjC,OAAOG,IAAAA,mCAAqB,EAACF;AAC/B;AAEAF,OAAOK,WAAW,GAAG"}
1
+ {"version":3,"sources":["../src/components/Portal/Portal.tsx"],"sourcesContent":["'use client';\n\nimport type * as React from 'react';\n\nimport { usePortal_unstable } from './usePortal';\nimport { renderPortal_unstable } from './renderPortal';\nimport type { PortalProps } from './Portal.types';\n\n/**\n * A portal provides a way to render children into a DOM node\n * that exists outside the DOM hierarchy of the parent component.\n */\nexport const Portal: React.FC<PortalProps> = props => {\n const state = usePortal_unstable(props);\n\n return renderPortal_unstable(state);\n};\n\nPortal.displayName = 'Portal';\n"],"names":["usePortal_unstable","renderPortal_unstable","Portal","props","state","displayName"],"mappings":"AAAA;;;;;;;;;;;2BAImC,cAAc;8BACX,iBAAiB;AAOhD,MAAME,SAAgCC,CAAAA;IAC3C,MAAMC,YAAQJ,6BAAAA,EAAmBG;IAEjC,WAAOF,mCAAAA,EAAsBG;AAC/B,EAAE;AAEFF,OAAOG,WAAW,GAAG"}
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":""}
1
+ {"version":3,"sources":["../src/components/Portal/Portal.types.ts"],"sourcesContent":["import type * as React from 'react';\n\nexport type PortalProps = {\n /**\n * React children\n */\n children?: React.ReactNode;\n\n /**\n * Where the portal children are mounted on DOM\n *\n * @default a new element on document.body without any styling\n */\n mountNode?: HTMLElement | null | { element?: HTMLElement | null; className?: string };\n};\n\nexport type PortalState = Pick<PortalProps, 'children'> & {\n mountNode: HTMLElement | null | undefined;\n\n /**\n * Ref to the root span element as virtual parent\n */\n virtualParentRootRef: // eslint-disable-next-line @typescript-eslint/no-deprecated\n React.MutableRefObject<HTMLSpanElement | null>;\n};\n"],"names":[],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/Portal/index.ts"],"sourcesContent":["export { Portal } from './Portal';\nexport type { PortalProps, PortalState } from './Portal.types';\nexport { renderPortal_unstable } from './renderPortal';\nexport { usePortal_unstable } from './usePortal';\n"],"names":["Portal","renderPortal_unstable","usePortal_unstable"],"mappings":";;;;;;;;;;;IAASA,MAAM;eAANA,cAAM;;IAENC,qBAAqB;eAArBA,mCAAqB;;IACrBC,kBAAkB;eAAlBA,6BAAkB;;;wBAHJ;8BAEe;2BACH"}
1
+ {"version":3,"sources":["../src/components/Portal/index.ts"],"sourcesContent":["export { Portal } from './Portal';\nexport type { PortalProps, PortalState } from './Portal.types';\nexport { renderPortal_unstable } from './renderPortal';\nexport { usePortal_unstable } from './usePortal';\n"],"names":["Portal","renderPortal_unstable","usePortal_unstable"],"mappings":";;;;;;;;;;;;eAASA,cAAM;;;eAENC,mCAAqB;;;eACrBC,6BAAkB;;;wBAHJ,WAAW;8BAEI,iBAAiB;2BACpB,cAAc"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/Portal/renderPortal.tsx"],"sourcesContent":["import * as ReactDOM from 'react-dom';\nimport * as React from 'react';\nimport type { PortalState } from './Portal.types';\n\n/**\n * Render the final JSX of Portal\n */\nexport const renderPortal_unstable = (state: PortalState): React.ReactElement => {\n return (\n <span hidden ref={state.virtualParentRootRef}>\n {state.mountNode &&\n ReactDOM.createPortal(\n <>\n {state.children}\n {/* Heads up!\n * This node exists only to ensure that the portal is not empty as we rely on that in `usePortalMountNode`\n * hook for React 18+.\n */}\n <span hidden />\n </>,\n state.mountNode,\n )}\n </span>\n );\n};\n"],"names":["renderPortal_unstable","state","span","hidden","ref","virtualParentRootRef","mountNode","ReactDOM","createPortal","children"],"mappings":";;;;+BAOaA;;;eAAAA;;;;oEAPa;iEACH;AAMhB,MAAMA,wBAAwB,CAACC;IACpC,qBACE,qBAACC;QAAKC,QAAAA;QAAOC,KAAKH,MAAMI,oBAAoB;OACzCJ,MAAMK,SAAS,kBACdC,UAASC,YAAY,eACnB,4CACGP,MAAMQ,QAAQ,gBAKf,qBAACP;QAAKC,QAAAA;SAERF,MAAMK,SAAS;AAIzB"}
1
+ {"version":3,"sources":["../src/components/Portal/renderPortal.tsx"],"sourcesContent":["import * as ReactDOM from 'react-dom';\nimport * as React from 'react';\nimport type { PortalState } from './Portal.types';\n\n/**\n * Render the final JSX of Portal\n */\nexport const renderPortal_unstable = (state: PortalState): React.ReactElement => {\n return (\n <span hidden ref={state.virtualParentRootRef}>\n {state.mountNode &&\n ReactDOM.createPortal(\n <>\n {state.children}\n {/* Heads up!\n * This node exists only to ensure that the portal is not empty as we rely on that in `usePortalMountNode`\n * hook for React 18+.\n */}\n <span hidden />\n </>,\n state.mountNode,\n )}\n </span>\n );\n};\n"],"names":["ReactDOM","React","renderPortal_unstable","state","span","hidden","ref","virtualParentRootRef","mountNode","createPortal","children"],"mappings":";;;;+BAOaE;;;;;;;oEAPa,YAAY;iEACf,QAAQ;AAMxB,8BAA8B,CAACC;IACpC,OAAA,WAAA,GACE,OAAA,aAAA,CAACC,QAAAA;QAAKC,QAAAA;QAAOC,KAAKH,MAAMI,oBAAoB;OACzCJ,MAAMK,SAAS,IAAA,WAAA,GACdR,UAASS,YAAY,CAAA,WAAA,GACnB,OAAA,aAAA,CAAA,OAAA,QAAA,EAAA,MACGN,MAAMO,QAAQ,EAAA,WAAA,GAKf,OAAA,aAAA,CAACN,QAAAA;QAAKC,QAAAA;SAERF,MAAMK,SAAS;AAIzB,EAAE"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/Portal/usePortal.ts"],"sourcesContent":["'use client';\n\nimport { setVirtualParent } from '@fluentui/react-utilities';\nimport * as React from 'react';\n\nimport { toMountNodeProps } from '../../utils/toMountNodeProps';\nimport { usePortalMountNode } from './usePortalMountNode';\nimport type { PortalProps, PortalState } from './Portal.types';\n\n/**\n * Create the state required to render Portal.\n *\n * The returned state can be modified with hooks such as usePortalStyles, before being passed to renderPortal_unstable.\n *\n * @param props - props from this instance of Portal\n */\nexport const usePortal_unstable = (props: PortalProps): PortalState => {\n const { element, className } = toMountNodeProps(props.mountNode);\n\n const virtualParentRootRef = React.useRef<HTMLSpanElement>(null);\n const fallbackElement = usePortalMountNode({ disabled: !!element, className });\n\n const mountNode = element ?? fallbackElement;\n const state: PortalState = {\n children: props.children,\n mountNode,\n virtualParentRootRef,\n };\n\n React.useEffect(() => {\n if (!mountNode) {\n return;\n }\n\n const virtualParent = virtualParentRootRef.current;\n\n // By default, we create a mount node for portal on `document.body` (see usePortalMountNode()) and have following structure:\n //\n // <body>\n // <!-- ⚛️ application root -->\n // <div id=\"root\">\n // <!-- ⬇️ portal node rendered in a tree to anchor (virtual parent node) -->\n // <span aria-hidden=\"true\"></span>\n // </div>\n // <div id=\"portal-mount-node\">\n // <!-- 🧩portal content -->\n // </div>\n // </body>\n //\n // To make sure that `.elementContains()` works correctly, we link a virtual parent to a portal node (a virtual parent node becomes a parent of mount node):\n // virtual.contains(mountNode) === false\n // (while we need ⬇️⬇️⬇️)\n // elementsContains(virtualParent, mountNode) === true\n // elementsContains(mountNode, virtualParent) === false\n //\n // For more details, check docs for virtual parent utils.\n //\n // However, if a user provides a custom mount node (via `props`) the structure could be different:\n //\n // <body>\n // <!-- application root -->\n // <div id=\"root\">\n // <div id=\"portal-mount-node\">\n // <!-- 🧩portal content -->\n //\n // <span aria-hidden=\"true\"></span>\n // </div>\n // </div>\n // </body>\n //\n // A mount node in this case contains portal's content and a virtual parent node. In this case nodes linking is redundant and the check below avoids it.\n //\n // Otherwise, there is a circular reference - both elements are parents of each other:\n // elementsContains(mountNode, virtualParent) === true\n // elementsContains(virtualParent, mountNode) === true\n const isVirtualParentInsideChild = mountNode.contains(virtualParent);\n\n if (virtualParent && !isVirtualParentInsideChild) {\n setVirtualParent(mountNode, virtualParent);\n\n return () => {\n setVirtualParent(mountNode, undefined);\n };\n }\n }, [virtualParentRootRef, mountNode]);\n\n return state;\n};\n"],"names":["usePortal_unstable","props","element","className","toMountNodeProps","mountNode","virtualParentRootRef","React","useRef","fallbackElement","usePortalMountNode","disabled","state","children","useEffect","virtualParent","current","isVirtualParentInsideChild","contains","setVirtualParent","undefined"],"mappings":"AAAA;;;;;+BAgBaA;;;eAAAA;;;;gCAdoB;iEACV;kCAEU;oCACE;AAU5B,MAAMA,qBAAqB,CAACC;IACjC,MAAM,EAAEC,OAAO,EAAEC,SAAS,EAAE,GAAGC,IAAAA,kCAAgB,EAACH,MAAMI,SAAS;IAE/D,MAAMC,uBAAuBC,OAAMC,MAAM,CAAkB;IAC3D,MAAMC,kBAAkBC,IAAAA,sCAAkB,EAAC;QAAEC,UAAU,CAAC,CAACT;QAASC;IAAU;IAE5E,MAAME,YAAYH,oBAAAA,qBAAAA,UAAWO;IAC7B,MAAMG,QAAqB;QACzBC,UAAUZ,MAAMY,QAAQ;QACxBR;QACAC;IACF;IAEAC,OAAMO,SAAS,CAAC;QACd,IAAI,CAACT,WAAW;YACd;QACF;QAEA,MAAMU,gBAAgBT,qBAAqBU,OAAO;QAElD,4HAA4H;QAC5H,EAAE;QACF,SAAS;QACT,iCAAiC;QACjC,oBAAoB;QACpB,iFAAiF;QACjF,uCAAuC;QACvC,WAAW;QACX,iCAAiC;QACjC,gCAAgC;QAChC,WAAW;QACX,UAAU;QACV,EAAE;QACF,4JAA4J;QAC5J,0CAA0C;QAC1C,2BAA2B;QAC3B,wDAAwD;QACxD,yDAAyD;QACzD,EAAE;QACF,yDAAyD;QACzD,EAAE;QACF,kGAAkG;QAClG,EAAE;QACF,SAAS;QACT,8BAA8B;QAC9B,oBAAoB;QACpB,mCAAmC;QACnC,kCAAkC;QAClC,EAAE;QACF,yCAAyC;QACzC,aAAa;QACb,WAAW;QACX,UAAU;QACV,EAAE;QACF,wJAAwJ;QACxJ,EAAE;QACF,sFAAsF;QACtF,wDAAwD;QACxD,wDAAwD;QACxD,MAAMC,6BAA6BZ,UAAUa,QAAQ,CAACH;QAEtD,IAAIA,iBAAiB,CAACE,4BAA4B;YAChDE,IAAAA,gCAAgB,EAACd,WAAWU;YAE5B,OAAO;gBACLI,IAAAA,gCAAgB,EAACd,WAAWe;YAC9B;QACF;IACF,GAAG;QAACd;QAAsBD;KAAU;IAEpC,OAAOO;AACT"}
1
+ {"version":3,"sources":["../src/components/Portal/usePortal.ts"],"sourcesContent":["'use client';\n\nimport { setVirtualParent } from '@fluentui/react-utilities';\nimport * as React from 'react';\n\nimport { toMountNodeProps } from '../../utils/toMountNodeProps';\nimport { usePortalMountNode } from './usePortalMountNode';\nimport type { PortalProps, PortalState } from './Portal.types';\n\n/**\n * Create the state required to render Portal.\n *\n * The returned state can be modified with hooks such as usePortalStyles, before being passed to renderPortal_unstable.\n *\n * @param props - props from this instance of Portal\n */\nexport const usePortal_unstable = (props: PortalProps): PortalState => {\n const { element, className } = toMountNodeProps(props.mountNode);\n\n const virtualParentRootRef = React.useRef<HTMLSpanElement>(null);\n const fallbackElement = usePortalMountNode({ disabled: !!element, className });\n\n const mountNode = element ?? fallbackElement;\n const state: PortalState = {\n children: props.children,\n mountNode,\n virtualParentRootRef,\n };\n\n React.useEffect(() => {\n if (!mountNode) {\n return;\n }\n\n const virtualParent = virtualParentRootRef.current;\n\n // By default, we create a mount node for portal on `document.body` (see usePortalMountNode()) and have following structure:\n //\n // <body>\n // <!-- ⚛️ application root -->\n // <div id=\"root\">\n // <!-- ⬇️ portal node rendered in a tree to anchor (virtual parent node) -->\n // <span aria-hidden=\"true\"></span>\n // </div>\n // <div id=\"portal-mount-node\">\n // <!-- 🧩portal content -->\n // </div>\n // </body>\n //\n // To make sure that `.elementContains()` works correctly, we link a virtual parent to a portal node (a virtual parent node becomes a parent of mount node):\n // virtual.contains(mountNode) === false\n // (while we need ⬇️⬇️⬇️)\n // elementsContains(virtualParent, mountNode) === true\n // elementsContains(mountNode, virtualParent) === false\n //\n // For more details, check docs for virtual parent utils.\n //\n // However, if a user provides a custom mount node (via `props`) the structure could be different:\n //\n // <body>\n // <!-- application root -->\n // <div id=\"root\">\n // <div id=\"portal-mount-node\">\n // <!-- 🧩portal content -->\n //\n // <span aria-hidden=\"true\"></span>\n // </div>\n // </div>\n // </body>\n //\n // A mount node in this case contains portal's content and a virtual parent node. In this case nodes linking is redundant and the check below avoids it.\n //\n // Otherwise, there is a circular reference - both elements are parents of each other:\n // elementsContains(mountNode, virtualParent) === true\n // elementsContains(virtualParent, mountNode) === true\n const isVirtualParentInsideChild = mountNode.contains(virtualParent);\n\n if (virtualParent && !isVirtualParentInsideChild) {\n setVirtualParent(mountNode, virtualParent);\n\n return () => {\n setVirtualParent(mountNode, undefined);\n };\n }\n }, [virtualParentRootRef, mountNode]);\n\n return state;\n};\n"],"names":["setVirtualParent","React","toMountNodeProps","usePortalMountNode","usePortal_unstable","props","element","className","mountNode","virtualParentRootRef","useRef","fallbackElement","disabled","state","children","useEffect","virtualParent","current","isVirtualParentInsideChild","contains","undefined"],"mappings":"AAAA;;;;;+BAgBaI;;;;;;;gCAdoB,4BAA4B;iEACtC,QAAQ;kCAEE,+BAA+B;oCAC7B,uBAAuB;AAUnD,2BAA2B,CAACC;IACjC,MAAM,EAAEC,OAAO,EAAEC,SAAS,EAAE,OAAGL,kCAAAA,EAAiBG,MAAMG,SAAS;IAE/D,MAAMC,uBAAuBR,OAAMS,MAAM,CAAkB;IAC3D,MAAMC,sBAAkBR,sCAAAA,EAAmB;QAAES,UAAU,CAAC,CAACN;QAASC;IAAU;IAE5E,MAAMC,YAAYF,YAAAA,QAAAA,YAAAA,KAAAA,IAAAA,UAAWK;IAC7B,MAAME,QAAqB;QACzBC,UAAUT,MAAMS,QAAQ;QACxBN;QACAC;IACF;IAEAR,OAAMc,SAAS,CAAC;QACd,IAAI,CAACP,WAAW;YACd;QACF;QAEA,MAAMQ,gBAAgBP,qBAAqBQ,OAAO;QAElD,4HAA4H;QAC5H,EAAE;QACF,SAAS;QACT,iCAAiC;QACjC,oBAAoB;QACpB,iFAAiF;QACjF,uCAAuC;QACvC,WAAW;QACX,iCAAiC;QACjC,gCAAgC;QAChC,WAAW;QACX,UAAU;QACV,EAAE;QACF,4JAA4J;QAC5J,0CAA0C;QAC1C,2BAA2B;QAC3B,wDAAwD;QACxD,yDAAyD;QACzD,EAAE;QACF,yDAAyD;QACzD,EAAE;QACF,kGAAkG;QAClG,EAAE;QACF,SAAS;QACT,8BAA8B;QAC9B,oBAAoB;QACpB,mCAAmC;QACnC,kCAAkC;QAClC,EAAE;QACF,yCAAyC;QACzC,aAAa;QACb,WAAW;QACX,UAAU;QACV,EAAE;QACF,wJAAwJ;QACxJ,EAAE;QACF,sFAAsF;QACtF,wDAAwD;QACxD,wDAAwD;QACxD,MAAMC,6BAA6BV,UAAUW,QAAQ,CAACH;QAEtD,IAAIA,iBAAiB,CAACE,4BAA4B;YAChDlB,oCAAAA,EAAiBQ,WAAWQ;YAE5B,OAAO;oBACLhB,gCAAAA,EAAiBQ,WAAWY;YAC9B;QACF;IACF,GAAG;QAACX;QAAsBD;KAAU;IAEpC,OAAOK;AACT,EAAE"}
@@ -12,15 +12,15 @@ Object.defineProperty(exports, "usePortalMountNode", {
12
12
  const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
13
13
  const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));
14
14
  const _reactsharedcontexts = require("@fluentui/react-shared-contexts");
15
+ const _react1 = require("@griffel/react");
15
16
  const _reacttabster = require("@fluentui/react-tabster");
16
- const _usePortalMountNodeStyles = require("./usePortalMountNodeStyles");
17
+ const _usePortalMountNodeStylesstyles = require("./usePortalMountNodeStyles.styles");
17
18
  const useInsertionEffect = _react['useInsertion' + 'Effect'];
18
19
  /**
19
20
  * Legacy element factory for React 17 and below. It's not safe for concurrent rendering.
20
21
  *
21
22
  * Creates a new element on a "document.body" to mount portals.
22
23
  */ const useLegacyElementFactory = (options)=>{
23
- 'use no memo';
24
24
  const { className, dir, focusVisibleRef, targetNode } = options;
25
25
  const targetElement = _react.useMemo(()=>{
26
26
  if (targetNode === undefined || options.disabled) {
@@ -39,13 +39,16 @@ const useInsertionEffect = _react['useInsertion' + 'Effect'];
39
39
  // We don't want to re-create the portal element when its attributes change. This also cannot not be done in an effect
40
40
  // because, changing the value of CSS variables after an initial mount will trigger interesting CSS side effects like
41
41
  // transitions.
42
+ // eslint-disable-next-line react-hooks/void-use-memo
42
43
  _react.useMemo(()=>{
43
44
  if (!targetElement) {
44
45
  return;
45
46
  }
47
+ // eslint-disable-next-line react-hooks/immutability
46
48
  targetElement.className = className;
47
49
  targetElement.setAttribute('dir', dir);
48
50
  targetElement.setAttribute('data-portal-node', 'true');
51
+ // eslint-disable-next-line react-hooks/refs
49
52
  focusVisibleRef.current = targetElement;
50
53
  }, [
51
54
  className,
@@ -92,7 +95,7 @@ const initializeElementFactory = ()=>{
92
95
  * - the `remove()` method (we call it in `useEffect()`) and remove the element only when the portal is unmounted
93
96
  * - all other methods (and properties) will be called by React once a portal is mounted
94
97
  */ const useModernElementFactory = (options)=>{
95
- 'use no memo';
98
+ 'use no memo'; // justified: compiler would optimize dispose — manual opt-out to preserve runtime behavior
96
99
  const { className, dir, focusVisibleRef, targetNode } = options;
97
100
  const [elementFactory] = _react.useState(initializeElementFactory);
98
101
  const elementProxy = _react.useMemo(()=>{
@@ -159,12 +162,13 @@ const initializeElementFactory = ()=>{
159
162
  if (!elementProxy) {
160
163
  return;
161
164
  }
162
- elementProxy.setAttribute('class', className);
165
+ const classesToApply = className.split(' ').filter(Boolean);
166
+ elementProxy.classList.add(...classesToApply);
163
167
  elementProxy.setAttribute('dir', dir);
164
168
  elementProxy.setAttribute('data-portal-node', 'true');
165
169
  focusVisibleRef.current = elementProxy;
166
170
  return ()=>{
167
- elementProxy.removeAttribute('class');
171
+ elementProxy.classList.remove(...classesToApply);
168
172
  elementProxy.removeAttribute('dir');
169
173
  };
170
174
  }, [
@@ -192,22 +196,19 @@ const initializeElementFactory = ()=>{
192
196
  * - useModernElementFactory
193
197
  */ const useElementFactory = useInsertionEffect ? useModernElementFactory : useLegacyElementFactory;
194
198
  const usePortalMountNode = (options)=>{
195
- 'use no memo';
199
+ 'use no memo'; // justified: compiler would optimize usePortalMountNode — manual opt-out to preserve runtime behavior
196
200
  const { targetDocument, dir } = (0, _reactsharedcontexts.useFluent_unstable)();
197
201
  const mountNode = (0, _reactsharedcontexts.usePortalMountNode)();
198
202
  // eslint-disable-next-line @typescript-eslint/no-deprecated
199
203
  const focusVisibleRef = (0, _reacttabster.useFocusVisible)();
204
+ const classes = (0, _usePortalMountNodeStylesstyles.usePortalMountNodeStylesStyles)();
200
205
  const themeClassName = (0, _reactsharedcontexts.useThemeClassName_unstable)();
201
206
  const factoryOptions = {
202
207
  dir,
203
208
  disabled: options.disabled,
204
209
  focusVisibleRef,
205
- className: [
206
- themeClassName,
207
- options.className
208
- ].filter(Boolean).join(' '),
210
+ className: (0, _react1.mergeClasses)(themeClassName, classes.root, options.className),
209
211
  targetNode: mountNode !== null && mountNode !== void 0 ? mountNode : targetDocument === null || targetDocument === void 0 ? void 0 : targetDocument.body
210
212
  };
211
- (0, _usePortalMountNodeStyles.usePortalMountNodeStyles)(options.disabled);
212
213
  return useElementFactory(factoryOptions);
213
214
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/Portal/usePortalMountNode.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport {\n useThemeClassName_unstable as useThemeClassName,\n useFluent_unstable as useFluent,\n usePortalMountNode as usePortalMountNodeContext,\n} from '@fluentui/react-shared-contexts';\nimport { useFocusVisible } from '@fluentui/react-tabster';\n\nimport { usePortalMountNodeStyles } from './usePortalMountNodeStyles';\n\nconst useInsertionEffect = (React as never)['useInsertion' + 'Effect'] as typeof React.useLayoutEffect | undefined;\n\nexport type UsePortalMountNodeOptions = {\n /**\n * Since hooks cannot be called conditionally use this flag to disable creating the node\n */\n disabled?: boolean;\n\n className?: string;\n};\n\ntype UseElementFactoryOptions = {\n className: string;\n dir: string;\n disabled: boolean | undefined;\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n focusVisibleRef: React.MutableRefObject<HTMLElement | null>;\n targetNode: HTMLElement | ShadowRoot | undefined;\n};\ntype UseElementFactory = (options: UseElementFactoryOptions) => HTMLDivElement | null;\n\n/**\n * Legacy element factory for React 17 and below. It's not safe for concurrent rendering.\n *\n * Creates a new element on a \"document.body\" to mount portals.\n */\nconst useLegacyElementFactory: UseElementFactory = options => {\n 'use no memo';\n\n const { className, dir, focusVisibleRef, targetNode } = options;\n\n const targetElement = React.useMemo(() => {\n if (targetNode === undefined || options.disabled) {\n return null;\n }\n\n const element = targetNode.ownerDocument.createElement('div');\n targetNode.appendChild(element);\n\n return element;\n }, [targetNode, options.disabled]);\n\n // Heads up!\n // This useMemo() call is intentional for React 17 & below.\n //\n // We don't want to re-create the portal element when its attributes change. This also cannot not be done in an effect\n // because, changing the value of CSS variables after an initial mount will trigger interesting CSS side effects like\n // transitions.\n React.useMemo(() => {\n if (!targetElement) {\n return;\n }\n\n targetElement.className = className;\n targetElement.setAttribute('dir', dir);\n targetElement.setAttribute('data-portal-node', 'true');\n\n focusVisibleRef.current = targetElement;\n }, [className, dir, targetElement, focusVisibleRef]);\n\n React.useEffect(() => {\n return () => {\n targetElement?.remove();\n };\n }, [targetElement]);\n\n return targetElement;\n};\n\nconst initializeElementFactory = () => {\n let currentElement: HTMLDivElement | undefined = undefined;\n\n function get(targetRoot: HTMLElement | ShadowRoot, forceCreation: boolean): HTMLDivElement | undefined {\n if (currentElement) {\n return currentElement;\n }\n\n if (forceCreation) {\n currentElement = targetRoot.ownerDocument.createElement('div');\n targetRoot.appendChild(currentElement);\n }\n\n return currentElement;\n }\n\n function dispose() {\n if (currentElement) {\n currentElement.remove();\n currentElement = undefined;\n }\n }\n\n return {\n get,\n dispose,\n };\n};\n\n/**\n * This is a modern element factory for React 18 and above. It is safe for concurrent rendering.\n *\n * It abuses the fact that React will mount DOM once (unlike hooks), so by using a proxy we can intercept:\n * - the `remove()` method (we call it in `useEffect()`) and remove the element only when the portal is unmounted\n * - all other methods (and properties) will be called by React once a portal is mounted\n */\nconst useModernElementFactory: UseElementFactory = options => {\n 'use no memo';\n\n const { className, dir, focusVisibleRef, targetNode } = options;\n\n const [elementFactory] = React.useState(initializeElementFactory);\n\n const elementProxy = React.useMemo(() => {\n if (targetNode === undefined || options.disabled) {\n return null;\n }\n\n return new Proxy({} as HTMLDivElement, {\n get(_, property: keyof HTMLDivElement) {\n // Heads up!\n // `createPortal()` performs a check for `nodeType` property to determine if the mount node is a valid DOM node\n // before mounting the portal. We hardcode the value to `Node.ELEMENT_NODE` to pass this check and avoid\n // premature node creation\n if (property === 'nodeType') {\n // Can't use the `Node.ELEMENT_NODE` as it's a browser API and not available in all environments, e.g SSR\n return 1; // `Node.ELEMENT_NODE`\n }\n\n // Heads up!\n // We intercept the `remove()` method to remove the mount node only when portal has been unmounted already.\n if (property === 'remove') {\n const targetElement = elementFactory.get(targetNode, false);\n\n if (targetElement) {\n // If the mountElement has children, the portal is still mounted, otherwise we can dispose of it\n const portalHasNoChildren = targetElement.childNodes.length === 0;\n\n if (portalHasNoChildren) {\n elementFactory.dispose();\n }\n }\n\n return () => {\n // Always return a no-op function to avoid errors in the code\n };\n }\n\n const targetElement = elementFactory.get(targetNode, true);\n const targetProperty = targetElement ? targetElement[property] : undefined;\n\n if (typeof targetProperty === 'function') {\n return targetProperty.bind(targetElement);\n }\n\n return targetProperty;\n },\n\n set(_, property: keyof HTMLDivElement | '_virtual' | 'focusVisible', value) {\n const ignoredProperty = property === '_virtual' || property === 'focusVisible';\n\n // We should use the `elementFactory.get(targetNode, !ignoredProperty)`,\n // but TypeScript requires a literal `true` or `false` for the overload signature.\n // This workaround ensures the correct overload is called and avoids TypeScript errors.\n const targetElement = ignoredProperty\n ? elementFactory.get(targetNode, false)\n : elementFactory.get(targetNode, true);\n\n if (ignoredProperty && !targetElement) {\n // We ignore the `_virtual` and `focusVisible` properties to avoid conflicts with the proxy\n return true;\n }\n\n if (targetElement) {\n Object.assign(targetElement, { [property]: value });\n return true;\n }\n\n return false;\n },\n });\n }, [elementFactory, targetNode, options.disabled]);\n\n useInsertionEffect!(() => {\n if (!elementProxy) {\n return;\n }\n\n elementProxy.setAttribute('class', className);\n elementProxy.setAttribute('dir', dir);\n elementProxy.setAttribute('data-portal-node', 'true');\n\n focusVisibleRef.current = elementProxy;\n\n return () => {\n elementProxy.removeAttribute('class');\n elementProxy.removeAttribute('dir');\n };\n }, [className, dir, elementProxy, focusVisibleRef]);\n\n React.useEffect(() => {\n return () => {\n elementProxy?.remove();\n };\n }, [elementProxy]);\n\n return elementProxy;\n};\n\n/**\n * Element factory based on the React version.\n *\n * React 17 and below:\n * - useLegacyElementFactory\n *\n * React 18 and above:\n * - useModernElementFactory\n */\nconst useElementFactory = useInsertionEffect ? useModernElementFactory : useLegacyElementFactory;\n\n/**\n * Creates a new element on a \"document.body\" to mount portals.\n */\nexport const usePortalMountNode = (options: UsePortalMountNodeOptions): HTMLElement | null => {\n ('use no memo');\n\n const { targetDocument, dir } = useFluent();\n const mountNode = usePortalMountNodeContext();\n\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n const focusVisibleRef = useFocusVisible<HTMLDivElement>() as React.MutableRefObject<HTMLElement | null>;\n const themeClassName = useThemeClassName();\n\n const factoryOptions: UseElementFactoryOptions = {\n dir,\n disabled: options.disabled,\n focusVisibleRef,\n\n className: [themeClassName, options.className].filter(Boolean).join(' '),\n targetNode: mountNode ?? targetDocument?.body,\n };\n\n usePortalMountNodeStyles(options.disabled);\n\n return useElementFactory(factoryOptions);\n};\n"],"names":["usePortalMountNode","useInsertionEffect","React","useLegacyElementFactory","options","className","dir","focusVisibleRef","targetNode","targetElement","useMemo","undefined","disabled","element","ownerDocument","createElement","appendChild","setAttribute","current","useEffect","remove","initializeElementFactory","currentElement","get","targetRoot","forceCreation","dispose","useModernElementFactory","elementFactory","useState","elementProxy","Proxy","_","property","portalHasNoChildren","childNodes","length","targetProperty","bind","set","value","ignoredProperty","Object","assign","removeAttribute","useElementFactory","targetDocument","useFluent","mountNode","usePortalMountNodeContext","useFocusVisible","themeClassName","useThemeClassName","factoryOptions","filter","Boolean","join","body","usePortalMountNodeStyles"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/components/Portal/usePortalMountNode.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport {\n useThemeClassName_unstable as useThemeClassName,\n useFluent_unstable as useFluent,\n usePortalMountNode as usePortalMountNodeContext,\n} from '@fluentui/react-shared-contexts';\nimport { mergeClasses } from '@griffel/react';\nimport { useFocusVisible } from '@fluentui/react-tabster';\n\nimport { usePortalMountNodeStylesStyles } from './usePortalMountNodeStyles.styles';\n\nconst useInsertionEffect = (React as never)['useInsertion' + 'Effect'] as typeof React.useLayoutEffect | undefined;\n\nexport type UsePortalMountNodeOptions = {\n /**\n * Since hooks cannot be called conditionally use this flag to disable creating the node\n */\n disabled?: boolean;\n\n className?: string;\n};\n\ntype UseElementFactoryOptions = {\n className: string;\n dir: string;\n disabled: boolean | undefined;\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n focusVisibleRef: React.MutableRefObject<HTMLElement | null>;\n targetNode: HTMLElement | ShadowRoot | undefined;\n};\ntype UseElementFactory = (options: UseElementFactoryOptions) => HTMLDivElement | null;\n\n/**\n * Legacy element factory for React 17 and below. It's not safe for concurrent rendering.\n *\n * Creates a new element on a \"document.body\" to mount portals.\n */\nconst useLegacyElementFactory: UseElementFactory = options => {\n const { className, dir, focusVisibleRef, targetNode } = options;\n\n const targetElement = React.useMemo(() => {\n if (targetNode === undefined || options.disabled) {\n return null;\n }\n\n const element = targetNode.ownerDocument.createElement('div');\n targetNode.appendChild(element);\n\n return element;\n }, [targetNode, options.disabled]);\n\n // Heads up!\n // This useMemo() call is intentional for React 17 & below.\n //\n // We don't want to re-create the portal element when its attributes change. This also cannot not be done in an effect\n // because, changing the value of CSS variables after an initial mount will trigger interesting CSS side effects like\n // transitions.\n // eslint-disable-next-line react-hooks/void-use-memo\n React.useMemo(() => {\n if (!targetElement) {\n return;\n }\n\n // eslint-disable-next-line react-hooks/immutability\n targetElement.className = className;\n targetElement.setAttribute('dir', dir);\n targetElement.setAttribute('data-portal-node', 'true');\n\n // eslint-disable-next-line react-hooks/refs\n focusVisibleRef.current = targetElement;\n }, [className, dir, targetElement, focusVisibleRef]);\n\n React.useEffect(() => {\n return () => {\n targetElement?.remove();\n };\n }, [targetElement]);\n\n return targetElement;\n};\n\nconst initializeElementFactory = () => {\n let currentElement: HTMLDivElement | undefined = undefined;\n\n function get(targetRoot: HTMLElement | ShadowRoot, forceCreation: boolean): HTMLDivElement | undefined {\n if (currentElement) {\n return currentElement;\n }\n\n if (forceCreation) {\n currentElement = targetRoot.ownerDocument.createElement('div');\n targetRoot.appendChild(currentElement);\n }\n\n return currentElement;\n }\n\n function dispose() {\n if (currentElement) {\n currentElement.remove();\n currentElement = undefined;\n }\n }\n\n return {\n get,\n dispose,\n };\n};\n\n/**\n * This is a modern element factory for React 18 and above. It is safe for concurrent rendering.\n *\n * It abuses the fact that React will mount DOM once (unlike hooks), so by using a proxy we can intercept:\n * - the `remove()` method (we call it in `useEffect()`) and remove the element only when the portal is unmounted\n * - all other methods (and properties) will be called by React once a portal is mounted\n */\nconst useModernElementFactory: UseElementFactory = options => {\n 'use no memo'; // justified: compiler would optimize dispose — manual opt-out to preserve runtime behavior\n\n const { className, dir, focusVisibleRef, targetNode } = options;\n\n const [elementFactory] = React.useState(initializeElementFactory);\n\n const elementProxy = React.useMemo(() => {\n if (targetNode === undefined || options.disabled) {\n return null;\n }\n\n return new Proxy({} as HTMLDivElement, {\n get(_, property: keyof HTMLDivElement) {\n // Heads up!\n // `createPortal()` performs a check for `nodeType` property to determine if the mount node is a valid DOM node\n // before mounting the portal. We hardcode the value to `Node.ELEMENT_NODE` to pass this check and avoid\n // premature node creation\n if (property === 'nodeType') {\n // Can't use the `Node.ELEMENT_NODE` as it's a browser API and not available in all environments, e.g SSR\n return 1; // `Node.ELEMENT_NODE`\n }\n\n // Heads up!\n // We intercept the `remove()` method to remove the mount node only when portal has been unmounted already.\n if (property === 'remove') {\n const targetElement = elementFactory.get(targetNode, false);\n\n if (targetElement) {\n // If the mountElement has children, the portal is still mounted, otherwise we can dispose of it\n const portalHasNoChildren = targetElement.childNodes.length === 0;\n\n if (portalHasNoChildren) {\n elementFactory.dispose();\n }\n }\n\n return () => {\n // Always return a no-op function to avoid errors in the code\n };\n }\n\n const targetElement = elementFactory.get(targetNode, true);\n const targetProperty = targetElement ? targetElement[property] : undefined;\n\n if (typeof targetProperty === 'function') {\n return targetProperty.bind(targetElement);\n }\n\n return targetProperty;\n },\n\n set(_, property: keyof HTMLDivElement | '_virtual' | 'focusVisible', value) {\n const ignoredProperty = property === '_virtual' || property === 'focusVisible';\n\n // We should use the `elementFactory.get(targetNode, !ignoredProperty)`,\n // but TypeScript requires a literal `true` or `false` for the overload signature.\n // This workaround ensures the correct overload is called and avoids TypeScript errors.\n const targetElement = ignoredProperty\n ? elementFactory.get(targetNode, false)\n : elementFactory.get(targetNode, true);\n\n if (ignoredProperty && !targetElement) {\n // We ignore the `_virtual` and `focusVisible` properties to avoid conflicts with the proxy\n return true;\n }\n\n if (targetElement) {\n Object.assign(targetElement, { [property]: value });\n return true;\n }\n\n return false;\n },\n });\n }, [elementFactory, targetNode, options.disabled]);\n\n useInsertionEffect!(() => {\n if (!elementProxy) {\n return;\n }\n\n const classesToApply = className.split(' ').filter(Boolean);\n\n elementProxy.classList.add(...classesToApply);\n elementProxy.setAttribute('dir', dir);\n elementProxy.setAttribute('data-portal-node', 'true');\n\n focusVisibleRef.current = elementProxy;\n\n return () => {\n elementProxy.classList.remove(...classesToApply);\n elementProxy.removeAttribute('dir');\n };\n }, [className, dir, elementProxy, focusVisibleRef]);\n\n React.useEffect(() => {\n return () => {\n elementProxy?.remove();\n };\n }, [elementProxy]);\n\n return elementProxy;\n};\n\n/**\n * Element factory based on the React version.\n *\n * React 17 and below:\n * - useLegacyElementFactory\n *\n * React 18 and above:\n * - useModernElementFactory\n */\nconst useElementFactory = useInsertionEffect ? useModernElementFactory : useLegacyElementFactory;\n\n/**\n * Creates a new element on a \"document.body\" to mount portals.\n */\nexport const usePortalMountNode = (options: UsePortalMountNodeOptions): HTMLElement | null => {\n ('use no memo'); // justified: compiler would optimize usePortalMountNode — manual opt-out to preserve runtime behavior\n\n const { targetDocument, dir } = useFluent();\n const mountNode = usePortalMountNodeContext();\n\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n const focusVisibleRef = useFocusVisible<HTMLDivElement>() as React.MutableRefObject<HTMLElement | null>;\n const classes = usePortalMountNodeStylesStyles();\n const themeClassName = useThemeClassName();\n\n const factoryOptions: UseElementFactoryOptions = {\n dir,\n disabled: options.disabled,\n focusVisibleRef,\n\n className: mergeClasses(themeClassName, classes.root, options.className),\n targetNode: mountNode ?? targetDocument?.body,\n };\n\n return useElementFactory(factoryOptions);\n};\n"],"names":["React","useThemeClassName_unstable","useThemeClassName","useFluent_unstable","useFluent","usePortalMountNode","usePortalMountNodeContext","mergeClasses","useFocusVisible","usePortalMountNodeStylesStyles","useInsertionEffect","useLegacyElementFactory","options","className","dir","focusVisibleRef","targetNode","targetElement","useMemo","undefined","disabled","element","ownerDocument","createElement","appendChild","setAttribute","current","useEffect","remove","initializeElementFactory","currentElement","get","targetRoot","forceCreation","dispose","useModernElementFactory","elementFactory","useState","elementProxy","Proxy","_","property","portalHasNoChildren","childNodes","length","targetProperty","bind","set","value","ignoredProperty","Object","assign","classesToApply","split","filter","Boolean","classList","add","removeAttribute","useElementFactory","targetDocument","mountNode","classes","themeClassName","factoryOptions","root","body"],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ 'use client';
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "usePortalMountNodeStylesStyles", {
7
+ enumerable: true,
8
+ get: function() {
9
+ return usePortalMountNodeStylesStyles;
10
+ }
11
+ });
12
+ const _react = require("@griffel/react");
13
+ const usePortalMountNodeStylesStyles = /*#__PURE__*/ (0, _react.__styles)({
14
+ root: {
15
+ qhf8xq: "f1euv43f",
16
+ Bhzewxz: "f15twtuk",
17
+ oyh7mz: [
18
+ "f1vgc2s3",
19
+ "f1e31b4d"
20
+ ],
21
+ j35jbq: [
22
+ "f1e31b4d",
23
+ "f1vgc2s3"
24
+ ],
25
+ Bj3rh1h: "f494woh"
26
+ }
27
+ }, {
28
+ d: [
29
+ ".f1euv43f{position:absolute;}",
30
+ ".f15twtuk{top:0;}",
31
+ ".f1vgc2s3{left:0;}",
32
+ ".f1e31b4d{right:0;}",
33
+ ".f494woh{z-index:1000000;}"
34
+ ]
35
+ });
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["usePortalMountNodeStyles.styles.js"],"sourcesContent":["'use client';\nimport { makeStyles } from '@griffel/react';\nexport const usePortalMountNodeStylesStyles = makeStyles({\n root: {\n // Creates new stacking context to prevent z-index issues\n // https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_positioned_layout/Understanding_z-index/Stacking_context\n //\n // Also keeps a portal on top of a page to prevent scrollbars from appearing\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n zIndex: 1000000\n }\n});\n"],"names":["__styles","usePortalMountNodeStylesStyles","root","qhf8xq","Bhzewxz","oyh7mz","j35jbq","Bj3rh1h","d"],"mappings":"AAAA,YAAY;;;;;;;;;;;uBACe,gBAAgB;AACpC,MAAMC,8BAA8B,GAAA,WAAA,OAAGD,eAAA,EAAA;IAAAE,IAAA,EAAA;QAAAC,MAAA,EAAA;QAAAC,OAAA,EAAA;QAAAC,MAAA,EAAA;YAAA;YAAA;SAAA;QAAAC,MAAA,EAAA;YAAA;YAAA;SAAA;QAAAC,OAAA,EAAA;IAAA;AAAA,GAAA;IAAAC,CAAA,EAAA;QAAA;QAAA;QAAA;QAAA;QAAA;KAAA;AAAA,CAY7C,CAAC"}
@@ -0,0 +1,25 @@
1
+ 'use client';
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "usePortalMountNodeStylesStyles", {
7
+ enumerable: true,
8
+ get: function() {
9
+ return usePortalMountNodeStylesStyles;
10
+ }
11
+ });
12
+ const _react = require("@griffel/react");
13
+ const usePortalMountNodeStylesStyles = (0, _react.makeStyles)({
14
+ root: {
15
+ // Creates new stacking context to prevent z-index issues
16
+ // https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_positioned_layout/Understanding_z-index/Stacking_context
17
+ //
18
+ // Also keeps a portal on top of a page to prevent scrollbars from appearing
19
+ position: 'absolute',
20
+ top: 0,
21
+ left: 0,
22
+ right: 0,
23
+ zIndex: 1000000
24
+ }
25
+ });
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/Portal/usePortalMountNodeStyles.styles.ts"],"sourcesContent":["'use client';\n\nimport { makeStyles } from '@griffel/react';\n\nexport const usePortalMountNodeStylesStyles = makeStyles({\n root: {\n // Creates new stacking context to prevent z-index issues\n // https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_positioned_layout/Understanding_z-index/Stacking_context\n //\n // Also keeps a portal on top of a page to prevent scrollbars from appearing\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n\n zIndex: 1000000,\n },\n});\n"],"names":["makeStyles","usePortalMountNodeStylesStyles","root","position","top","left","right","zIndex"],"mappings":"AAAA;;;;;;;;;;;uBAE2B,iBAAiB;AAErC,MAAMC,qCAAiCD,iBAAAA,EAAW;IACvDE,MAAM;QACJ,yDAAyD;QACzD,gHAAgH;QAChH,EAAE;QACF,4EAA4E;QAC5EC,UAAU;QACVC,KAAK;QACLC,MAAM;QACNC,OAAO;QAEPC,QAAQ;IACV;AACF,GAAG"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { elementContains, setVirtualParent } from '@fluentui/react-utilities';\nexport { Portal, renderPortal_unstable, usePortal_unstable } from './components/Portal/index';\nexport type { PortalProps, PortalState } from './components/Portal/index';\n\nexport { toMountNodeProps } from './utils/toMountNodeProps';\n"],"names":["Portal","elementContains","renderPortal_unstable","setVirtualParent","toMountNodeProps","usePortal_unstable"],"mappings":";;;;;;;;;;;IACSA,MAAM;eAANA,aAAM;;IADNC,eAAe;eAAfA,+BAAe;;IACPC,qBAAqB;eAArBA,4BAAqB;;IADZC,gBAAgB;eAAhBA,gCAAgB;;IAIjCC,gBAAgB;eAAhBA,kCAAgB;;IAHeC,kBAAkB;eAAlBA,yBAAkB;;;gCADR;uBACgB;kCAGjC"}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { elementContains, setVirtualParent } from '@fluentui/react-utilities';\nexport { Portal, renderPortal_unstable, usePortal_unstable } from './components/Portal/index';\nexport type { PortalProps, PortalState } from './components/Portal/index';\n\nexport { toMountNodeProps } from './utils/toMountNodeProps';\n"],"names":["elementContains","setVirtualParent","Portal","renderPortal_unstable","usePortal_unstable","toMountNodeProps"],"mappings":";;;;;;;;;;;;eACSE,aAAM;;;eADNF,+BAAe;;;eACPG,4BAAqB;;;eADZF,gCAAgB;;;eAIjCI,kCAAgB;;;eAHeD,yBAAkB;;;gCADR,4BAA4B;uBACZ,4BAA4B;kCAG7D,2BAA2B"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils/toMountNodeProps.ts"],"sourcesContent":["import { isHTMLElement } from '@fluentui/react-utilities';\nimport type { PortalProps } from '../Portal';\n\n/**\n * The function that normalizes the `mountNode` prop into an object with element and className props.\n *\n * @param mountNode - an HTML element or an object with props\n */\nexport function toMountNodeProps(mountNode: PortalProps['mountNode']): {\n element?: HTMLElement | null;\n className?: string;\n} {\n if (isHTMLElement(mountNode)) {\n return { element: mountNode };\n }\n\n if (typeof mountNode === 'object') {\n if (mountNode === null) {\n return { element: null };\n }\n\n return mountNode;\n }\n\n return {};\n}\n"],"names":["toMountNodeProps","mountNode","isHTMLElement","element"],"mappings":";;;;+BAQgBA;;;eAAAA;;;gCARc;AAQvB,SAASA,iBAAiBC,SAAmC;IAIlE,IAAIC,IAAAA,6BAAa,EAACD,YAAY;QAC5B,OAAO;YAAEE,SAASF;QAAU;IAC9B;IAEA,IAAI,OAAOA,cAAc,UAAU;QACjC,IAAIA,cAAc,MAAM;YACtB,OAAO;gBAAEE,SAAS;YAAK;QACzB;QAEA,OAAOF;IACT;IAEA,OAAO,CAAC;AACV"}
1
+ {"version":3,"sources":["../src/utils/toMountNodeProps.ts"],"sourcesContent":["import { isHTMLElement } from '@fluentui/react-utilities';\nimport type { PortalProps } from '../Portal';\n\n/**\n * The function that normalizes the `mountNode` prop into an object with element and className props.\n *\n * @param mountNode - an HTML element or an object with props\n */\nexport function toMountNodeProps(mountNode: PortalProps['mountNode']): {\n element?: HTMLElement | null;\n className?: string;\n} {\n if (isHTMLElement(mountNode)) {\n return { element: mountNode };\n }\n\n if (typeof mountNode === 'object') {\n if (mountNode === null) {\n return { element: null };\n }\n\n return mountNode;\n }\n\n return {};\n}\n"],"names":["isHTMLElement","toMountNodeProps","mountNode","element"],"mappings":";;;;+BAQgBC;;;;;;gCARc,4BAA4B;AAQnD,0BAA0BC,SAAmC;IAIlE,QAAIF,6BAAAA,EAAcE,YAAY;QAC5B,OAAO;YAAEC,SAASD;QAAU;IAC9B;IAEA,IAAI,OAAOA,cAAc,UAAU;QACjC,IAAIA,cAAc,MAAM;YACtB,OAAO;gBAAEC,SAAS;YAAK;QACzB;QAEA,OAAOD;IACT;IAEA,OAAO,CAAC;AACV"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluentui/react-portal",
3
- "version": "9.8.12",
3
+ "version": "9.8.14",
4
4
  "description": "A utility component that creates portals compatible with Fluent UI",
5
5
  "main": "lib-commonjs/index.js",
6
6
  "module": "lib/index.js",
@@ -13,8 +13,8 @@
13
13
  "license": "MIT",
14
14
  "dependencies": {
15
15
  "@fluentui/react-shared-contexts": "^9.26.2",
16
- "@fluentui/react-tabster": "^9.26.14",
17
- "@fluentui/react-utilities": "^9.26.3",
16
+ "@fluentui/react-tabster": "^9.26.16",
17
+ "@fluentui/react-utilities": "^9.26.5",
18
18
  "@griffel/react": "^1.5.32",
19
19
  "@swc/helpers": "^0.5.1"
20
20
  },
@@ -1,73 +0,0 @@
1
- 'use client';
2
- import * as React from 'react';
3
- import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';
4
- import { useIsomorphicLayoutEffect } from '@fluentui/react-utilities';
5
- // String concatenation is used to prevent bundlers to complain with older versions of React
6
- const useInsertionEffect = React['useInsertion' + 'Effect'] ? React['useInsertion' + 'Effect'] : useIsomorphicLayoutEffect;
7
- // Symbol used as a "private" property key on Document to store the active portal reference count.
8
- // Symbol.for() registers in the global Symbol registry so the same key is shared across bundles
9
- // (e.g. when multiple copies of this module are loaded in the same page).
10
- // Storing state directly on the document avoids any WeakMap cross-reference issues and is safe
11
- // across multiple documents (e.g. iframes) because each document object carries its own counter.
12
- const PORTAL_STYLE_REF_COUNT = Symbol.for('fui-portal-style-ref-count');
13
- // Creates new stacking context to prevent z-index issues
14
- // https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_positioned_layout/Understanding_z-index/Stacking_context
15
- //
16
- // Also keeps a portal on top of a page to prevent scrollbars from appearing
17
- const PORTAL_MOUNT_NODE_STYLE_RULE = `[data-portal-node]{position:absolute;top:0;left:0;right:0;z-index:1000000}`;
18
- // ID used to identify the injected portal mount node <style> element in a document.
19
- // Only one such element exists per document, so an id is appropriate.
20
- export const PORTAL_STYLE_ELEMENT_ID = 'fui-portal-styles';
21
- export function getPortalRefCount(targetDocument) {
22
- var _targetDocument_PORTAL_STYLE_REF_COUNT;
23
- return (_targetDocument_PORTAL_STYLE_REF_COUNT = targetDocument[PORTAL_STYLE_REF_COUNT]) !== null && _targetDocument_PORTAL_STYLE_REF_COUNT !== void 0 ? _targetDocument_PORTAL_STYLE_REF_COUNT : 0;
24
- }
25
- export function setPortalRefCount(targetDocument, count) {
26
- targetDocument[PORTAL_STYLE_REF_COUNT] = count;
27
- }
28
- function injectPortalMountNodeStyles(targetDocument) {
29
- var // sheet is available after the element is inserted into the document
30
- _style_sheet;
31
- const currentCount = getPortalRefCount(targetDocument);
32
- if (currentCount > 0) {
33
- setPortalRefCount(targetDocument, currentCount + 1);
34
- return;
35
- }
36
- const style = targetDocument.createElement('style');
37
- style.id = PORTAL_STYLE_ELEMENT_ID;
38
- // Prepend so that consumer class names (applied later in document order) can override these
39
- // defaults via CSS source order at equal specificity — the same cascade behaviour as before.
40
- // Both prepend and append trigger one style recalculation; position in <head> does not change
41
- // the number of recalcs.
42
- targetDocument.head.prepend(style);
43
- (_style_sheet = style.sheet) === null || _style_sheet === void 0 ? void 0 : _style_sheet.insertRule(PORTAL_MOUNT_NODE_STYLE_RULE);
44
- setPortalRefCount(targetDocument, 1);
45
- }
46
- function ejectPortalMountNodeStyles(targetDocument) {
47
- const currentCount = getPortalRefCount(targetDocument);
48
- if (currentCount === 0) {
49
- return;
50
- }
51
- const newCount = currentCount - 1;
52
- if (newCount === 0) {
53
- var _targetDocument_head_querySelector;
54
- (_targetDocument_head_querySelector = targetDocument.head.querySelector(`#${PORTAL_STYLE_ELEMENT_ID}`)) === null || _targetDocument_head_querySelector === void 0 ? void 0 : _targetDocument_head_querySelector.remove();
55
- }
56
- setPortalRefCount(targetDocument, newCount);
57
- }
58
- /**
59
- * Injects a shared <style> element for portal mount node styling into the target document,
60
- * and removes it when the last consumer unmounts (reference counted via a Symbol property on `document`).
61
- */ export function usePortalMountNodeStyles(disabled) {
62
- const { targetDocument } = useFluent();
63
- useInsertionEffect(()=>{
64
- if (disabled || !targetDocument) {
65
- return;
66
- }
67
- injectPortalMountNodeStyles(targetDocument);
68
- return ()=>ejectPortalMountNodeStyles(targetDocument);
69
- }, [
70
- disabled,
71
- targetDocument
72
- ]);
73
- }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/Portal/usePortalMountNodeStyles.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';\nimport { useIsomorphicLayoutEffect } from '@fluentui/react-utilities';\n\n// String concatenation is used to prevent bundlers to complain with older versions of React\nconst useInsertionEffect = (React as never)['useInsertion' + 'Effect']\n ? (React as never)['useInsertion' + 'Effect']\n : useIsomorphicLayoutEffect;\n\n// Symbol used as a \"private\" property key on Document to store the active portal reference count.\n// Symbol.for() registers in the global Symbol registry so the same key is shared across bundles\n// (e.g. when multiple copies of this module are loaded in the same page).\n// Storing state directly on the document avoids any WeakMap cross-reference issues and is safe\n// across multiple documents (e.g. iframes) because each document object carries its own counter.\nconst PORTAL_STYLE_REF_COUNT = Symbol.for('fui-portal-style-ref-count');\n\ntype DocumentWithPortalCounter = Document & { [PORTAL_STYLE_REF_COUNT]?: number };\n\n// Creates new stacking context to prevent z-index issues\n// https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_positioned_layout/Understanding_z-index/Stacking_context\n//\n// Also keeps a portal on top of a page to prevent scrollbars from appearing\nconst PORTAL_MOUNT_NODE_STYLE_RULE = `[data-portal-node]{position:absolute;top:0;left:0;right:0;z-index:1000000}`;\n\n// ID used to identify the injected portal mount node <style> element in a document.\n// Only one such element exists per document, so an id is appropriate.\nexport const PORTAL_STYLE_ELEMENT_ID = 'fui-portal-styles';\n\nexport function getPortalRefCount(targetDocument: Document): number {\n return (targetDocument as DocumentWithPortalCounter)[PORTAL_STYLE_REF_COUNT] ?? 0;\n}\n\nexport function setPortalRefCount(targetDocument: Document, count: number): void {\n (targetDocument as DocumentWithPortalCounter)[PORTAL_STYLE_REF_COUNT] = count;\n}\n\nfunction injectPortalMountNodeStyles(targetDocument: Document): void {\n const currentCount = getPortalRefCount(targetDocument);\n if (currentCount > 0) {\n setPortalRefCount(targetDocument, currentCount + 1);\n return;\n }\n const style = targetDocument.createElement('style');\n style.id = PORTAL_STYLE_ELEMENT_ID;\n // Prepend so that consumer class names (applied later in document order) can override these\n // defaults via CSS source order at equal specificity — the same cascade behaviour as before.\n // Both prepend and append trigger one style recalculation; position in <head> does not change\n // the number of recalcs.\n targetDocument.head.prepend(style);\n // sheet is available after the element is inserted into the document\n style.sheet?.insertRule(PORTAL_MOUNT_NODE_STYLE_RULE);\n setPortalRefCount(targetDocument, 1);\n}\n\nfunction ejectPortalMountNodeStyles(targetDocument: Document): void {\n const currentCount = getPortalRefCount(targetDocument);\n if (currentCount === 0) {\n return;\n }\n const newCount = currentCount - 1;\n if (newCount === 0) {\n targetDocument.head.querySelector(`#${PORTAL_STYLE_ELEMENT_ID}`)?.remove();\n }\n setPortalRefCount(targetDocument, newCount);\n}\n\n/**\n * Injects a shared <style> element for portal mount node styling into the target document,\n * and removes it when the last consumer unmounts (reference counted via a Symbol property on `document`).\n */\nexport function usePortalMountNodeStyles(disabled: boolean | undefined): void {\n const { targetDocument } = useFluent();\n\n useInsertionEffect!(() => {\n if (disabled || !targetDocument) {\n return;\n }\n injectPortalMountNodeStyles(targetDocument);\n return () => ejectPortalMountNodeStyles(targetDocument);\n }, [disabled, targetDocument]);\n}\n"],"names":["React","useFluent_unstable","useFluent","useIsomorphicLayoutEffect","useInsertionEffect","PORTAL_STYLE_REF_COUNT","Symbol","for","PORTAL_MOUNT_NODE_STYLE_RULE","PORTAL_STYLE_ELEMENT_ID","getPortalRefCount","targetDocument","setPortalRefCount","count","injectPortalMountNodeStyles","style","currentCount","createElement","id","head","prepend","sheet","insertRule","ejectPortalMountNodeStyles","newCount","querySelector","remove","usePortalMountNodeStyles","disabled"],"mappings":"AAAA;AAEA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,sBAAsBC,SAAS,QAAQ,kCAAkC;AAClF,SAASC,yBAAyB,QAAQ,4BAA4B;AAEtE,4FAA4F;AAC5F,MAAMC,qBAAqB,AAACJ,KAAe,CAAC,iBAAiB,SAAS,GAClE,AAACA,KAAe,CAAC,iBAAiB,SAAS,GAC3CG;AAEJ,kGAAkG;AAClG,gGAAgG;AAChG,0EAA0E;AAC1E,+FAA+F;AAC/F,iGAAiG;AACjG,MAAME,yBAAyBC,OAAOC,GAAG,CAAC;AAI1C,yDAAyD;AACzD,gHAAgH;AAChH,EAAE;AACF,4EAA4E;AAC5E,MAAMC,+BAA+B,CAAC,0EAA0E,CAAC;AAEjH,oFAAoF;AACpF,sEAAsE;AACtE,OAAO,MAAMC,0BAA0B,oBAAoB;AAE3D,OAAO,SAASC,kBAAkBC,cAAwB;QACjD;IAAP,OAAO,CAAA,yCAAA,AAACA,cAA4C,CAACN,uBAAuB,cAArE,oDAAA,yCAAyE;AAClF;AAEA,OAAO,SAASO,kBAAkBD,cAAwB,EAAEE,KAAa;IACtEF,cAA4C,CAACN,uBAAuB,GAAGQ;AAC1E;AAEA,SAASC,4BAA4BH,cAAwB;QAa3D,qEAAqE;IACrEI;IAbA,MAAMC,eAAeN,kBAAkBC;IACvC,IAAIK,eAAe,GAAG;QACpBJ,kBAAkBD,gBAAgBK,eAAe;QACjD;IACF;IACA,MAAMD,QAAQJ,eAAeM,aAAa,CAAC;IAC3CF,MAAMG,EAAE,GAAGT;IACX,4FAA4F;IAC5F,6FAA6F;IAC7F,8FAA8F;IAC9F,yBAAyB;IACzBE,eAAeQ,IAAI,CAACC,OAAO,CAACL;KAE5BA,eAAAA,MAAMM,KAAK,cAAXN,mCAAAA,aAAaO,UAAU,CAACd;IACxBI,kBAAkBD,gBAAgB;AACpC;AAEA,SAASY,2BAA2BZ,cAAwB;IAC1D,MAAMK,eAAeN,kBAAkBC;IACvC,IAAIK,iBAAiB,GAAG;QACtB;IACF;IACA,MAAMQ,WAAWR,eAAe;IAChC,IAAIQ,aAAa,GAAG;YAClBb;SAAAA,qCAAAA,eAAeQ,IAAI,CAACM,aAAa,CAAC,CAAC,CAAC,EAAEhB,yBAAyB,eAA/DE,yDAAAA,mCAAkEe,MAAM;IAC1E;IACAd,kBAAkBD,gBAAgBa;AACpC;AAEA;;;CAGC,GACD,OAAO,SAASG,yBAAyBC,QAA6B;IACpE,MAAM,EAAEjB,cAAc,EAAE,GAAGT;IAE3BE,mBAAoB;QAClB,IAAIwB,YAAY,CAACjB,gBAAgB;YAC/B;QACF;QACAG,4BAA4BH;QAC5B,OAAO,IAAMY,2BAA2BZ;IAC1C,GAAG;QAACiB;QAAUjB;KAAe;AAC/B"}
@@ -1,93 +0,0 @@
1
- 'use client';
2
- "use strict";
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- function _export(target, all) {
7
- for(var name in all)Object.defineProperty(target, name, {
8
- enumerable: true,
9
- get: all[name]
10
- });
11
- }
12
- _export(exports, {
13
- PORTAL_STYLE_ELEMENT_ID: function() {
14
- return PORTAL_STYLE_ELEMENT_ID;
15
- },
16
- getPortalRefCount: function() {
17
- return getPortalRefCount;
18
- },
19
- setPortalRefCount: function() {
20
- return setPortalRefCount;
21
- },
22
- usePortalMountNodeStyles: function() {
23
- return usePortalMountNodeStyles;
24
- }
25
- });
26
- const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
27
- const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));
28
- const _reactsharedcontexts = require("@fluentui/react-shared-contexts");
29
- const _reactutilities = require("@fluentui/react-utilities");
30
- // String concatenation is used to prevent bundlers to complain with older versions of React
31
- const useInsertionEffect = _react['useInsertion' + 'Effect'] ? _react['useInsertion' + 'Effect'] : _reactutilities.useIsomorphicLayoutEffect;
32
- // Symbol used as a "private" property key on Document to store the active portal reference count.
33
- // Symbol.for() registers in the global Symbol registry so the same key is shared across bundles
34
- // (e.g. when multiple copies of this module are loaded in the same page).
35
- // Storing state directly on the document avoids any WeakMap cross-reference issues and is safe
36
- // across multiple documents (e.g. iframes) because each document object carries its own counter.
37
- const PORTAL_STYLE_REF_COUNT = Symbol.for('fui-portal-style-ref-count');
38
- // Creates new stacking context to prevent z-index issues
39
- // https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_positioned_layout/Understanding_z-index/Stacking_context
40
- //
41
- // Also keeps a portal on top of a page to prevent scrollbars from appearing
42
- const PORTAL_MOUNT_NODE_STYLE_RULE = `[data-portal-node]{position:absolute;top:0;left:0;right:0;z-index:1000000}`;
43
- const PORTAL_STYLE_ELEMENT_ID = 'fui-portal-styles';
44
- function getPortalRefCount(targetDocument) {
45
- var _targetDocument_PORTAL_STYLE_REF_COUNT;
46
- return (_targetDocument_PORTAL_STYLE_REF_COUNT = targetDocument[PORTAL_STYLE_REF_COUNT]) !== null && _targetDocument_PORTAL_STYLE_REF_COUNT !== void 0 ? _targetDocument_PORTAL_STYLE_REF_COUNT : 0;
47
- }
48
- function setPortalRefCount(targetDocument, count) {
49
- targetDocument[PORTAL_STYLE_REF_COUNT] = count;
50
- }
51
- function injectPortalMountNodeStyles(targetDocument) {
52
- var // sheet is available after the element is inserted into the document
53
- _style_sheet;
54
- const currentCount = getPortalRefCount(targetDocument);
55
- if (currentCount > 0) {
56
- setPortalRefCount(targetDocument, currentCount + 1);
57
- return;
58
- }
59
- const style = targetDocument.createElement('style');
60
- style.id = PORTAL_STYLE_ELEMENT_ID;
61
- // Prepend so that consumer class names (applied later in document order) can override these
62
- // defaults via CSS source order at equal specificity — the same cascade behaviour as before.
63
- // Both prepend and append trigger one style recalculation; position in <head> does not change
64
- // the number of recalcs.
65
- targetDocument.head.prepend(style);
66
- (_style_sheet = style.sheet) === null || _style_sheet === void 0 ? void 0 : _style_sheet.insertRule(PORTAL_MOUNT_NODE_STYLE_RULE);
67
- setPortalRefCount(targetDocument, 1);
68
- }
69
- function ejectPortalMountNodeStyles(targetDocument) {
70
- const currentCount = getPortalRefCount(targetDocument);
71
- if (currentCount === 0) {
72
- return;
73
- }
74
- const newCount = currentCount - 1;
75
- if (newCount === 0) {
76
- var _targetDocument_head_querySelector;
77
- (_targetDocument_head_querySelector = targetDocument.head.querySelector(`#${PORTAL_STYLE_ELEMENT_ID}`)) === null || _targetDocument_head_querySelector === void 0 ? void 0 : _targetDocument_head_querySelector.remove();
78
- }
79
- setPortalRefCount(targetDocument, newCount);
80
- }
81
- function usePortalMountNodeStyles(disabled) {
82
- const { targetDocument } = (0, _reactsharedcontexts.useFluent_unstable)();
83
- useInsertionEffect(()=>{
84
- if (disabled || !targetDocument) {
85
- return;
86
- }
87
- injectPortalMountNodeStyles(targetDocument);
88
- return ()=>ejectPortalMountNodeStyles(targetDocument);
89
- }, [
90
- disabled,
91
- targetDocument
92
- ]);
93
- }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/Portal/usePortalMountNodeStyles.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';\nimport { useIsomorphicLayoutEffect } from '@fluentui/react-utilities';\n\n// String concatenation is used to prevent bundlers to complain with older versions of React\nconst useInsertionEffect = (React as never)['useInsertion' + 'Effect']\n ? (React as never)['useInsertion' + 'Effect']\n : useIsomorphicLayoutEffect;\n\n// Symbol used as a \"private\" property key on Document to store the active portal reference count.\n// Symbol.for() registers in the global Symbol registry so the same key is shared across bundles\n// (e.g. when multiple copies of this module are loaded in the same page).\n// Storing state directly on the document avoids any WeakMap cross-reference issues and is safe\n// across multiple documents (e.g. iframes) because each document object carries its own counter.\nconst PORTAL_STYLE_REF_COUNT = Symbol.for('fui-portal-style-ref-count');\n\ntype DocumentWithPortalCounter = Document & { [PORTAL_STYLE_REF_COUNT]?: number };\n\n// Creates new stacking context to prevent z-index issues\n// https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_positioned_layout/Understanding_z-index/Stacking_context\n//\n// Also keeps a portal on top of a page to prevent scrollbars from appearing\nconst PORTAL_MOUNT_NODE_STYLE_RULE = `[data-portal-node]{position:absolute;top:0;left:0;right:0;z-index:1000000}`;\n\n// ID used to identify the injected portal mount node <style> element in a document.\n// Only one such element exists per document, so an id is appropriate.\nexport const PORTAL_STYLE_ELEMENT_ID = 'fui-portal-styles';\n\nexport function getPortalRefCount(targetDocument: Document): number {\n return (targetDocument as DocumentWithPortalCounter)[PORTAL_STYLE_REF_COUNT] ?? 0;\n}\n\nexport function setPortalRefCount(targetDocument: Document, count: number): void {\n (targetDocument as DocumentWithPortalCounter)[PORTAL_STYLE_REF_COUNT] = count;\n}\n\nfunction injectPortalMountNodeStyles(targetDocument: Document): void {\n const currentCount = getPortalRefCount(targetDocument);\n if (currentCount > 0) {\n setPortalRefCount(targetDocument, currentCount + 1);\n return;\n }\n const style = targetDocument.createElement('style');\n style.id = PORTAL_STYLE_ELEMENT_ID;\n // Prepend so that consumer class names (applied later in document order) can override these\n // defaults via CSS source order at equal specificity — the same cascade behaviour as before.\n // Both prepend and append trigger one style recalculation; position in <head> does not change\n // the number of recalcs.\n targetDocument.head.prepend(style);\n // sheet is available after the element is inserted into the document\n style.sheet?.insertRule(PORTAL_MOUNT_NODE_STYLE_RULE);\n setPortalRefCount(targetDocument, 1);\n}\n\nfunction ejectPortalMountNodeStyles(targetDocument: Document): void {\n const currentCount = getPortalRefCount(targetDocument);\n if (currentCount === 0) {\n return;\n }\n const newCount = currentCount - 1;\n if (newCount === 0) {\n targetDocument.head.querySelector(`#${PORTAL_STYLE_ELEMENT_ID}`)?.remove();\n }\n setPortalRefCount(targetDocument, newCount);\n}\n\n/**\n * Injects a shared <style> element for portal mount node styling into the target document,\n * and removes it when the last consumer unmounts (reference counted via a Symbol property on `document`).\n */\nexport function usePortalMountNodeStyles(disabled: boolean | undefined): void {\n const { targetDocument } = useFluent();\n\n useInsertionEffect!(() => {\n if (disabled || !targetDocument) {\n return;\n }\n injectPortalMountNodeStyles(targetDocument);\n return () => ejectPortalMountNodeStyles(targetDocument);\n }, [disabled, targetDocument]);\n}\n"],"names":["PORTAL_STYLE_ELEMENT_ID","getPortalRefCount","setPortalRefCount","usePortalMountNodeStyles","useInsertionEffect","React","useIsomorphicLayoutEffect","PORTAL_STYLE_REF_COUNT","Symbol","for","PORTAL_MOUNT_NODE_STYLE_RULE","targetDocument","count","injectPortalMountNodeStyles","style","currentCount","createElement","id","head","prepend","sheet","insertRule","ejectPortalMountNodeStyles","newCount","querySelector","remove","disabled","useFluent"],"mappings":"AAAA;;;;;;;;;;;;IA4BaA,uBAAuB;eAAvBA;;IAEGC,iBAAiB;eAAjBA;;IAIAC,iBAAiB;eAAjBA;;IAsCAC,wBAAwB;eAAxBA;;;;iEAtEO;qCACyB;gCACN;AAE1C,4FAA4F;AAC5F,MAAMC,qBAAqB,AAACC,MAAe,CAAC,iBAAiB,SAAS,GAClE,AAACA,MAAe,CAAC,iBAAiB,SAAS,GAC3CC,yCAAyB;AAE7B,kGAAkG;AAClG,gGAAgG;AAChG,0EAA0E;AAC1E,+FAA+F;AAC/F,iGAAiG;AACjG,MAAMC,yBAAyBC,OAAOC,GAAG,CAAC;AAI1C,yDAAyD;AACzD,gHAAgH;AAChH,EAAE;AACF,4EAA4E;AAC5E,MAAMC,+BAA+B,CAAC,0EAA0E,CAAC;AAI1G,MAAMV,0BAA0B;AAEhC,SAASC,kBAAkBU,cAAwB;QACjD;IAAP,OAAO,CAAA,yCAAA,AAACA,cAA4C,CAACJ,uBAAuB,cAArE,oDAAA,yCAAyE;AAClF;AAEO,SAASL,kBAAkBS,cAAwB,EAAEC,KAAa;IACtED,cAA4C,CAACJ,uBAAuB,GAAGK;AAC1E;AAEA,SAASC,4BAA4BF,cAAwB;QAa3D,qEAAqE;IACrEG;IAbA,MAAMC,eAAed,kBAAkBU;IACvC,IAAII,eAAe,GAAG;QACpBb,kBAAkBS,gBAAgBI,eAAe;QACjD;IACF;IACA,MAAMD,QAAQH,eAAeK,aAAa,CAAC;IAC3CF,MAAMG,EAAE,GAAGjB;IACX,4FAA4F;IAC5F,6FAA6F;IAC7F,8FAA8F;IAC9F,yBAAyB;IACzBW,eAAeO,IAAI,CAACC,OAAO,CAACL;KAE5BA,eAAAA,MAAMM,KAAK,cAAXN,mCAAAA,aAAaO,UAAU,CAACX;IACxBR,kBAAkBS,gBAAgB;AACpC;AAEA,SAASW,2BAA2BX,cAAwB;IAC1D,MAAMI,eAAed,kBAAkBU;IACvC,IAAII,iBAAiB,GAAG;QACtB;IACF;IACA,MAAMQ,WAAWR,eAAe;IAChC,IAAIQ,aAAa,GAAG;YAClBZ;SAAAA,qCAAAA,eAAeO,IAAI,CAACM,aAAa,CAAC,CAAC,CAAC,EAAExB,yBAAyB,eAA/DW,yDAAAA,mCAAkEc,MAAM;IAC1E;IACAvB,kBAAkBS,gBAAgBY;AACpC;AAMO,SAASpB,yBAAyBuB,QAA6B;IACpE,MAAM,EAAEf,cAAc,EAAE,GAAGgB,IAAAA,uCAAS;IAEpCvB,mBAAoB;QAClB,IAAIsB,YAAY,CAACf,gBAAgB;YAC/B;QACF;QACAE,4BAA4BF;QAC5B,OAAO,IAAMW,2BAA2BX;IAC1C,GAAG;QAACe;QAAUf;KAAe;AAC/B"}