@fluentui/react-portal 9.7.2 → 9.8.0

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.
package/CHANGELOG.md CHANGED
@@ -1,12 +1,23 @@
1
1
  # Change Log - @fluentui/react-portal
2
2
 
3
- This log was last generated on Wed, 30 Jul 2025 08:41:07 GMT and should not be manually modified.
3
+ This log was last generated on Thu, 07 Aug 2025 09:59:06 GMT and should not be manually modified.
4
4
 
5
5
  <!-- Start content -->
6
6
 
7
+ ## [9.8.0](https://github.com/microsoft/fluentui/tree/@fluentui/react-portal_v9.8.0)
8
+
9
+ Thu, 07 Aug 2025 09:59:06 GMT
10
+ [Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-portal_v9.7.2..@fluentui/react-portal_v9.8.0)
11
+
12
+ ### Minor changes
13
+
14
+ - feat: support for react 19 ([PR #34916](https://github.com/microsoft/fluentui/pull/34916) by dmytrokirpa@microsoft.com)
15
+ - Bump @fluentui/react-tabster to v9.26.3 ([PR #34980](https://github.com/microsoft/fluentui/pull/34980) by beachball)
16
+ - Bump @fluentui/react-utilities to v9.23.2 ([PR #34980](https://github.com/microsoft/fluentui/pull/34980) by beachball)
17
+
7
18
  ## [9.7.2](https://github.com/microsoft/fluentui/tree/@fluentui/react-portal_v9.7.2)
8
19
 
9
- Wed, 30 Jul 2025 08:41:07 GMT
20
+ Wed, 30 Jul 2025 13:10:57 GMT
10
21
  [Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-portal_v9.7.1..@fluentui/react-portal_v9.7.2)
11
22
 
12
23
  ### Patches
@@ -6,5 +6,7 @@ import * as React from 'react';
6
6
  return /*#__PURE__*/ React.createElement("span", {
7
7
  hidden: true,
8
8
  ref: state.virtualParentRootRef
9
- }, state.mountNode && /*#__PURE__*/ ReactDOM.createPortal(state.children, state.mountNode));
9
+ }, state.mountNode && /*#__PURE__*/ ReactDOM.createPortal(/*#__PURE__*/ React.createElement(React.Fragment, null, state.children, /*#__PURE__*/ React.createElement("span", {
10
+ hidden: true
11
+ })), state.mountNode));
10
12
  };
@@ -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 && ReactDOM.createPortal(state.children, state.mountNode)}\n </span>\n );\n};\n"],"names":["ReactDOM","React","renderPortal_unstable","state","span","hidden","ref","virtualParentRootRef","mountNode","createPortal","children"],"mappings":"AAAA,YAAYA,cAAc,YAAY;AACtC,YAAYC,WAAW,QAAQ;AAG/B;;CAEC,GACD,OAAO,MAAMC,wBAAwB,CAACC;IACpC,qBACE,oBAACC;QAAKC,QAAAA;QAAOC,KAAKH,MAAMI,oBAAoB;OACzCJ,MAAMK,SAAS,kBAAIR,SAASS,YAAY,CAACN,MAAMO,QAAQ,EAAEP,MAAMK,SAAS;AAG/E,EAAE"}
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":"AAAA,YAAYA,cAAc,YAAY;AACtC,YAAYC,WAAW,QAAQ;AAG/B;;CAEC,GACD,OAAO,MAAMC,wBAAwB,CAACC;IACpC,qBACE,oBAACC;QAAKC,QAAAA;QAAOC,KAAKH,MAAMI,oBAAoB;OACzCJ,MAAMK,SAAS,kBACdR,SAASS,YAAY,eACnB,0CACGN,MAAMO,QAAQ,gBAKf,oBAACN;QAAKC,QAAAA;SAERF,MAAMK,SAAS;AAIzB,EAAE"}
@@ -2,9 +2,184 @@ import * as React from 'react';
2
2
  import { useThemeClassName_unstable as useThemeClassName, useFluent_unstable as useFluent, usePortalMountNode as usePortalMountNodeContext } from '@fluentui/react-shared-contexts';
3
3
  import { mergeClasses } from '@griffel/react';
4
4
  import { useFocusVisible } from '@fluentui/react-tabster';
5
- import { useDisposable } from 'use-disposable';
6
5
  import { usePortalMountNodeStylesStyles } from './usePortalMountNodeStyles.styles';
7
6
  const useInsertionEffect = React['useInsertion' + 'Effect'];
7
+ /**
8
+ * Legacy element factory for React 17 and below. It's not safe for concurrent rendering.
9
+ *
10
+ * Creates a new element on a "document.body" to mount portals.
11
+ */ const useLegacyElementFactory = (options)=>{
12
+ 'use no memo';
13
+ const { className, dir, focusVisibleRef, targetNode } = options;
14
+ const targetElement = React.useMemo(()=>{
15
+ if (targetNode === undefined || options.disabled) {
16
+ return null;
17
+ }
18
+ const element = targetNode.ownerDocument.createElement('div');
19
+ targetNode.appendChild(element);
20
+ return element;
21
+ }, [
22
+ targetNode,
23
+ options.disabled
24
+ ]);
25
+ // Heads up!
26
+ // This useMemo() call is intentional for React 17 & below.
27
+ //
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
+ // because, changing the value of CSS variables after an initial mount will trigger interesting CSS side effects like
30
+ // transitions.
31
+ React.useMemo(()=>{
32
+ if (!targetElement) {
33
+ return;
34
+ }
35
+ targetElement.className = className;
36
+ targetElement.setAttribute('dir', dir);
37
+ targetElement.setAttribute('data-portal-node', 'true');
38
+ focusVisibleRef.current = targetElement;
39
+ }, [
40
+ className,
41
+ dir,
42
+ targetElement,
43
+ focusVisibleRef
44
+ ]);
45
+ React.useEffect(()=>{
46
+ return ()=>{
47
+ targetElement === null || targetElement === void 0 ? void 0 : targetElement.remove();
48
+ };
49
+ }, [
50
+ targetElement
51
+ ]);
52
+ return targetElement;
53
+ };
54
+ const initializeElementFactory = ()=>{
55
+ let currentElement = undefined;
56
+ function get(targetRoot, forceCreation) {
57
+ if (currentElement) {
58
+ return currentElement;
59
+ }
60
+ if (forceCreation) {
61
+ currentElement = targetRoot.ownerDocument.createElement('div');
62
+ targetRoot.appendChild(currentElement);
63
+ }
64
+ return currentElement;
65
+ }
66
+ function dispose() {
67
+ if (currentElement) {
68
+ currentElement.remove();
69
+ currentElement = undefined;
70
+ }
71
+ }
72
+ return {
73
+ get,
74
+ dispose
75
+ };
76
+ };
77
+ /**
78
+ * This is a modern element factory for React 18 and above. It is safe for concurrent rendering.
79
+ *
80
+ * It abuses the fact that React will mount DOM once (unlike hooks), so by using a proxy we can intercept:
81
+ * - the `remove()` method (we call it in `useEffect()`) and remove the element only when the portal is unmounted
82
+ * - all other methods (and properties) will be called by React once a portal is mounted
83
+ */ const useModernElementFactory = (options)=>{
84
+ 'use no memo';
85
+ const { className, dir, focusVisibleRef, targetNode } = options;
86
+ const [elementFactory] = React.useState(initializeElementFactory);
87
+ const elementProxy = React.useMemo(()=>{
88
+ if (targetNode === undefined || options.disabled) {
89
+ return null;
90
+ }
91
+ return new Proxy({}, {
92
+ get (_, property) {
93
+ // Heads up!
94
+ // `createPortal()` performs a check for `nodeType` property to determine if the mount node is a valid DOM node
95
+ // before mounting the portal. We hardcode the value to `Node.ELEMENT_NODE` to pass this check and avoid
96
+ // premature node creation
97
+ if (property === 'nodeType') {
98
+ return Node.ELEMENT_NODE;
99
+ }
100
+ // Heads up!
101
+ // We intercept the `remove()` method to remove the mount node only when portal has been unmounted already.
102
+ if (property === 'remove') {
103
+ const targetElement = elementFactory.get(targetNode, false);
104
+ if (targetElement) {
105
+ // If the mountElement has children, the portal is still mounted, otherwise we can dispose of it
106
+ const portalHasNoChildren = targetElement.childNodes.length === 0;
107
+ if (portalHasNoChildren) {
108
+ elementFactory.dispose();
109
+ }
110
+ }
111
+ return ()=>{
112
+ // Always return a no-op function to avoid errors in the code
113
+ };
114
+ }
115
+ const targetElement = elementFactory.get(targetNode, true);
116
+ const targetProperty = targetElement ? targetElement[property] : undefined;
117
+ if (typeof targetProperty === 'function') {
118
+ return targetProperty.bind(targetElement);
119
+ }
120
+ return targetProperty;
121
+ },
122
+ set (_, property, value) {
123
+ const ignoredProperty = property === '_virtual' || property === 'focusVisible';
124
+ // We should use the `elementFactory.get(targetNode, !ignoredProperty)`,
125
+ // but TypeScript requires a literal `true` or `false` for the overload signature.
126
+ // This workaround ensures the correct overload is called and avoids TypeScript errors.
127
+ const targetElement = ignoredProperty ? elementFactory.get(targetNode, false) : elementFactory.get(targetNode, true);
128
+ if (ignoredProperty && !targetElement) {
129
+ // We ignore the `_virtual` and `focusVisible` properties to avoid conflicts with the proxy
130
+ return true;
131
+ }
132
+ if (targetElement) {
133
+ Object.assign(targetElement, {
134
+ [property]: value
135
+ });
136
+ return true;
137
+ }
138
+ return false;
139
+ }
140
+ });
141
+ }, [
142
+ elementFactory,
143
+ targetNode,
144
+ options.disabled
145
+ ]);
146
+ useInsertionEffect(()=>{
147
+ if (!elementProxy) {
148
+ return;
149
+ }
150
+ const classesToApply = className.split(' ').filter(Boolean);
151
+ elementProxy.classList.add(...classesToApply);
152
+ elementProxy.setAttribute('dir', dir);
153
+ elementProxy.setAttribute('data-portal-node', 'true');
154
+ focusVisibleRef.current = elementProxy;
155
+ return ()=>{
156
+ elementProxy.classList.remove(...classesToApply);
157
+ elementProxy.removeAttribute('dir');
158
+ };
159
+ }, [
160
+ className,
161
+ dir,
162
+ elementProxy,
163
+ focusVisibleRef
164
+ ]);
165
+ React.useEffect(()=>{
166
+ return ()=>{
167
+ elementProxy === null || elementProxy === void 0 ? void 0 : elementProxy.remove();
168
+ };
169
+ }, [
170
+ elementProxy
171
+ ]);
172
+ return elementProxy;
173
+ };
174
+ /**
175
+ * Element factory based on the React version.
176
+ *
177
+ * React 17 and below:
178
+ * - useLegacyElementFactory
179
+ *
180
+ * React 18 and above:
181
+ * - useModernElementFactory
182
+ */ const useElementFactory = useInsertionEffect ? useModernElementFactory : useLegacyElementFactory;
8
183
  /**
9
184
  * Creates a new element on a "document.body" to mount portals.
10
185
  */ export const usePortalMountNode = (options)=>{
@@ -14,66 +189,12 @@ const useInsertionEffect = React['useInsertion' + 'Effect'];
14
189
  const focusVisibleRef = useFocusVisible();
15
190
  const classes = usePortalMountNodeStylesStyles();
16
191
  const themeClassName = useThemeClassName();
17
- const className = mergeClasses(themeClassName, classes.root, options.className);
18
- const targetNode = mountNode !== null && mountNode !== void 0 ? mountNode : targetDocument === null || targetDocument === void 0 ? void 0 : targetDocument.body;
19
- const element = useDisposable(()=>{
20
- if (targetNode === undefined || options.disabled) {
21
- return [
22
- null,
23
- ()=>null
24
- ];
25
- }
26
- const newElement = targetNode.ownerDocument.createElement('div');
27
- targetNode.appendChild(newElement);
28
- return [
29
- newElement,
30
- ()=>newElement.remove()
31
- ];
32
- }, [
33
- targetNode
34
- ]);
35
- if (useInsertionEffect) {
36
- // eslint-disable-next-line react-hooks/rules-of-hooks
37
- useInsertionEffect(()=>{
38
- if (!element) {
39
- return;
40
- }
41
- const classesToApply = className.split(' ').filter(Boolean);
42
- element.classList.add(...classesToApply);
43
- element.setAttribute('dir', dir);
44
- element.setAttribute('data-portal-node', 'true');
45
- focusVisibleRef.current = element;
46
- return ()=>{
47
- element.classList.remove(...classesToApply);
48
- element.removeAttribute('dir');
49
- };
50
- }, [
51
- className,
52
- dir,
53
- element,
54
- focusVisibleRef
55
- ]);
56
- } else {
57
- // This useMemo call is intentional for React 17
58
- // We don't want to re-create the portal element when its attributes change.
59
- // This also should not be done in an effect because, changing the value of css variables
60
- // after initial mount can trigger interesting CSS side effects like transitions.
61
- // eslint-disable-next-line react-hooks/rules-of-hooks
62
- React.useMemo(()=>{
63
- if (!element) {
64
- return;
65
- }
66
- // Force replace all classes
67
- element.className = className;
68
- element.setAttribute('dir', dir);
69
- element.setAttribute('data-portal-node', 'true');
70
- focusVisibleRef.current = element;
71
- }, [
72
- className,
73
- dir,
74
- element,
75
- focusVisibleRef
76
- ]);
77
- }
78
- return element;
192
+ const factoryOptions = {
193
+ dir,
194
+ disabled: options.disabled,
195
+ focusVisibleRef,
196
+ className: mergeClasses(themeClassName, classes.root, options.className),
197
+ targetNode: mountNode !== null && mountNode !== void 0 ? mountNode : targetDocument === null || targetDocument === void 0 ? void 0 : targetDocument.body
198
+ };
199
+ return useElementFactory(factoryOptions);
79
200
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/Portal/usePortalMountNode.ts"],"sourcesContent":["import * 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';\nimport { useDisposable } from 'use-disposable';\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\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 const focusVisibleRef = useFocusVisible<HTMLDivElement>() as React.MutableRefObject<HTMLElement | null>;\n const classes = usePortalMountNodeStylesStyles();\n const themeClassName = useThemeClassName();\n\n const className = mergeClasses(themeClassName, classes.root, options.className);\n const targetNode: HTMLElement | ShadowRoot | undefined = mountNode ?? targetDocument?.body;\n\n const element = useDisposable(() => {\n if (targetNode === undefined || options.disabled) {\n return [null, () => null];\n }\n\n const newElement = targetNode.ownerDocument.createElement('div');\n targetNode.appendChild(newElement);\n return [newElement, () => newElement.remove()];\n }, [targetNode]);\n\n if (useInsertionEffect) {\n // eslint-disable-next-line react-hooks/rules-of-hooks\n useInsertionEffect(() => {\n if (!element) {\n return;\n }\n\n const classesToApply = className.split(' ').filter(Boolean);\n\n element.classList.add(...classesToApply);\n element.setAttribute('dir', dir);\n element.setAttribute('data-portal-node', 'true');\n\n focusVisibleRef.current = element;\n\n return () => {\n element.classList.remove(...classesToApply);\n element.removeAttribute('dir');\n };\n }, [className, dir, element, focusVisibleRef]);\n } else {\n // This useMemo call is intentional for React 17\n // We don't want to re-create the portal element when its attributes change.\n // This also should not be done in an effect because, changing the value of css variables\n // after initial mount can trigger interesting CSS side effects like transitions.\n // eslint-disable-next-line react-hooks/rules-of-hooks\n React.useMemo(() => {\n if (!element) {\n return;\n }\n\n // Force replace all classes\n element.className = className;\n element.setAttribute('dir', dir);\n element.setAttribute('data-portal-node', 'true');\n\n focusVisibleRef.current = element;\n }, [className, dir, element, focusVisibleRef]);\n }\n\n return element;\n};\n"],"names":["React","useThemeClassName_unstable","useThemeClassName","useFluent_unstable","useFluent","usePortalMountNode","usePortalMountNodeContext","mergeClasses","useFocusVisible","useDisposable","usePortalMountNodeStylesStyles","useInsertionEffect","options","targetDocument","dir","mountNode","focusVisibleRef","classes","themeClassName","className","root","targetNode","body","element","undefined","disabled","newElement","ownerDocument","createElement","appendChild","remove","classesToApply","split","filter","Boolean","classList","add","setAttribute","current","removeAttribute","useMemo"],"mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B,SACEC,8BAA8BC,iBAAiB,EAC/CC,sBAAsBC,SAAS,EAC/BC,sBAAsBC,yBAAyB,QAC1C,kCAAkC;AACzC,SAASC,YAAY,QAAQ,iBAAiB;AAC9C,SAASC,eAAe,QAAQ,0BAA0B;AAC1D,SAASC,aAAa,QAAQ,iBAAiB;AAE/C,SAASC,8BAA8B,QAAQ,oCAAoC;AAEnF,MAAMC,qBAAqB,AAACX,KAAe,CAAC,iBAAiB,SAAS;AAWtE;;CAEC,GACD,OAAO,MAAMK,qBAAqB,CAACO;IACjC;IAEA,MAAM,EAAEC,cAAc,EAAEC,GAAG,EAAE,GAAGV;IAChC,MAAMW,YAAYT;IAElB,MAAMU,kBAAkBR;IACxB,MAAMS,UAAUP;IAChB,MAAMQ,iBAAiBhB;IAEvB,MAAMiB,YAAYZ,aAAaW,gBAAgBD,QAAQG,IAAI,EAAER,QAAQO,SAAS;IAC9E,MAAME,aAAmDN,sBAAAA,uBAAAA,YAAaF,2BAAAA,qCAAAA,eAAgBS,IAAI;IAE1F,MAAMC,UAAUd,cAAc;QAC5B,IAAIY,eAAeG,aAAaZ,QAAQa,QAAQ,EAAE;YAChD,OAAO;gBAAC;gBAAM,IAAM;aAAK;QAC3B;QAEA,MAAMC,aAAaL,WAAWM,aAAa,CAACC,aAAa,CAAC;QAC1DP,WAAWQ,WAAW,CAACH;QACvB,OAAO;YAACA;YAAY,IAAMA,WAAWI,MAAM;SAAG;IAChD,GAAG;QAACT;KAAW;IAEf,IAAIV,oBAAoB;QACtB,sDAAsD;QACtDA,mBAAmB;YACjB,IAAI,CAACY,SAAS;gBACZ;YACF;YAEA,MAAMQ,iBAAiBZ,UAAUa,KAAK,CAAC,KAAKC,MAAM,CAACC;YAEnDX,QAAQY,SAAS,CAACC,GAAG,IAAIL;YACzBR,QAAQc,YAAY,CAAC,OAAOvB;YAC5BS,QAAQc,YAAY,CAAC,oBAAoB;YAEzCrB,gBAAgBsB,OAAO,GAAGf;YAE1B,OAAO;gBACLA,QAAQY,SAAS,CAACL,MAAM,IAAIC;gBAC5BR,QAAQgB,eAAe,CAAC;YAC1B;QACF,GAAG;YAACpB;YAAWL;YAAKS;YAASP;SAAgB;IAC/C,OAAO;QACL,gDAAgD;QAChD,4EAA4E;QAC5E,yFAAyF;QACzF,iFAAiF;QACjF,sDAAsD;QACtDhB,MAAMwC,OAAO,CAAC;YACZ,IAAI,CAACjB,SAAS;gBACZ;YACF;YAEA,4BAA4B;YAC5BA,QAAQJ,SAAS,GAAGA;YACpBI,QAAQc,YAAY,CAAC,OAAOvB;YAC5BS,QAAQc,YAAY,CAAC,oBAAoB;YAEzCrB,gBAAgBsB,OAAO,GAAGf;QAC5B,GAAG;YAACJ;YAAWL;YAAKS;YAASP;SAAgB;IAC/C;IAEA,OAAOO;AACT,EAAE"}
1
+ {"version":3,"sources":["../src/components/Portal/usePortalMountNode.ts"],"sourcesContent":["import * 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 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 return 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';\n\n const { targetDocument, dir } = useFluent();\n const mountNode = usePortalMountNodeContext();\n\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","Node","ELEMENT_NODE","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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"}
@@ -15,5 +15,7 @@ const renderPortal_unstable = (state)=>{
15
15
  return /*#__PURE__*/ _react.createElement("span", {
16
16
  hidden: true,
17
17
  ref: state.virtualParentRootRef
18
- }, state.mountNode && /*#__PURE__*/ _reactdom.createPortal(state.children, state.mountNode));
18
+ }, state.mountNode && /*#__PURE__*/ _reactdom.createPortal(/*#__PURE__*/ _react.createElement(_react.Fragment, null, state.children, /*#__PURE__*/ _react.createElement("span", {
19
+ hidden: true
20
+ })), state.mountNode));
19
21
  };
@@ -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 && ReactDOM.createPortal(state.children, state.mountNode)}\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,GAAIR,UAASS,YAAY,CAACN,MAAMO,QAAQ,EAAEP,MAAMK,SAAS;AAG/E,EAAE"}
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"}
@@ -13,9 +13,184 @@ const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));
13
13
  const _reactsharedcontexts = require("@fluentui/react-shared-contexts");
14
14
  const _react1 = require("@griffel/react");
15
15
  const _reacttabster = require("@fluentui/react-tabster");
16
- const _usedisposable = require("use-disposable");
17
16
  const _usePortalMountNodeStylesstyles = require("./usePortalMountNodeStyles.styles");
18
17
  const useInsertionEffect = _react['useInsertion' + 'Effect'];
18
+ /**
19
+ * Legacy element factory for React 17 and below. It's not safe for concurrent rendering.
20
+ *
21
+ * Creates a new element on a "document.body" to mount portals.
22
+ */ const useLegacyElementFactory = (options)=>{
23
+ 'use no memo';
24
+ const { className, dir, focusVisibleRef, targetNode } = options;
25
+ const targetElement = _react.useMemo(()=>{
26
+ if (targetNode === undefined || options.disabled) {
27
+ return null;
28
+ }
29
+ const element = targetNode.ownerDocument.createElement('div');
30
+ targetNode.appendChild(element);
31
+ return element;
32
+ }, [
33
+ targetNode,
34
+ options.disabled
35
+ ]);
36
+ // Heads up!
37
+ // This useMemo() call is intentional for React 17 & below.
38
+ //
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
+ // because, changing the value of CSS variables after an initial mount will trigger interesting CSS side effects like
41
+ // transitions.
42
+ _react.useMemo(()=>{
43
+ if (!targetElement) {
44
+ return;
45
+ }
46
+ targetElement.className = className;
47
+ targetElement.setAttribute('dir', dir);
48
+ targetElement.setAttribute('data-portal-node', 'true');
49
+ focusVisibleRef.current = targetElement;
50
+ }, [
51
+ className,
52
+ dir,
53
+ targetElement,
54
+ focusVisibleRef
55
+ ]);
56
+ _react.useEffect(()=>{
57
+ return ()=>{
58
+ targetElement === null || targetElement === void 0 ? void 0 : targetElement.remove();
59
+ };
60
+ }, [
61
+ targetElement
62
+ ]);
63
+ return targetElement;
64
+ };
65
+ const initializeElementFactory = ()=>{
66
+ let currentElement = undefined;
67
+ function get(targetRoot, forceCreation) {
68
+ if (currentElement) {
69
+ return currentElement;
70
+ }
71
+ if (forceCreation) {
72
+ currentElement = targetRoot.ownerDocument.createElement('div');
73
+ targetRoot.appendChild(currentElement);
74
+ }
75
+ return currentElement;
76
+ }
77
+ function dispose() {
78
+ if (currentElement) {
79
+ currentElement.remove();
80
+ currentElement = undefined;
81
+ }
82
+ }
83
+ return {
84
+ get,
85
+ dispose
86
+ };
87
+ };
88
+ /**
89
+ * This is a modern element factory for React 18 and above. It is safe for concurrent rendering.
90
+ *
91
+ * It abuses the fact that React will mount DOM once (unlike hooks), so by using a proxy we can intercept:
92
+ * - the `remove()` method (we call it in `useEffect()`) and remove the element only when the portal is unmounted
93
+ * - all other methods (and properties) will be called by React once a portal is mounted
94
+ */ const useModernElementFactory = (options)=>{
95
+ 'use no memo';
96
+ const { className, dir, focusVisibleRef, targetNode } = options;
97
+ const [elementFactory] = _react.useState(initializeElementFactory);
98
+ const elementProxy = _react.useMemo(()=>{
99
+ if (targetNode === undefined || options.disabled) {
100
+ return null;
101
+ }
102
+ return new Proxy({}, {
103
+ get (_, property) {
104
+ // Heads up!
105
+ // `createPortal()` performs a check for `nodeType` property to determine if the mount node is a valid DOM node
106
+ // before mounting the portal. We hardcode the value to `Node.ELEMENT_NODE` to pass this check and avoid
107
+ // premature node creation
108
+ if (property === 'nodeType') {
109
+ return Node.ELEMENT_NODE;
110
+ }
111
+ // Heads up!
112
+ // We intercept the `remove()` method to remove the mount node only when portal has been unmounted already.
113
+ if (property === 'remove') {
114
+ const targetElement = elementFactory.get(targetNode, false);
115
+ if (targetElement) {
116
+ // If the mountElement has children, the portal is still mounted, otherwise we can dispose of it
117
+ const portalHasNoChildren = targetElement.childNodes.length === 0;
118
+ if (portalHasNoChildren) {
119
+ elementFactory.dispose();
120
+ }
121
+ }
122
+ return ()=>{
123
+ // Always return a no-op function to avoid errors in the code
124
+ };
125
+ }
126
+ const targetElement = elementFactory.get(targetNode, true);
127
+ const targetProperty = targetElement ? targetElement[property] : undefined;
128
+ if (typeof targetProperty === 'function') {
129
+ return targetProperty.bind(targetElement);
130
+ }
131
+ return targetProperty;
132
+ },
133
+ set (_, property, value) {
134
+ const ignoredProperty = property === '_virtual' || property === 'focusVisible';
135
+ // We should use the `elementFactory.get(targetNode, !ignoredProperty)`,
136
+ // but TypeScript requires a literal `true` or `false` for the overload signature.
137
+ // This workaround ensures the correct overload is called and avoids TypeScript errors.
138
+ const targetElement = ignoredProperty ? elementFactory.get(targetNode, false) : elementFactory.get(targetNode, true);
139
+ if (ignoredProperty && !targetElement) {
140
+ // We ignore the `_virtual` and `focusVisible` properties to avoid conflicts with the proxy
141
+ return true;
142
+ }
143
+ if (targetElement) {
144
+ Object.assign(targetElement, {
145
+ [property]: value
146
+ });
147
+ return true;
148
+ }
149
+ return false;
150
+ }
151
+ });
152
+ }, [
153
+ elementFactory,
154
+ targetNode,
155
+ options.disabled
156
+ ]);
157
+ useInsertionEffect(()=>{
158
+ if (!elementProxy) {
159
+ return;
160
+ }
161
+ const classesToApply = className.split(' ').filter(Boolean);
162
+ elementProxy.classList.add(...classesToApply);
163
+ elementProxy.setAttribute('dir', dir);
164
+ elementProxy.setAttribute('data-portal-node', 'true');
165
+ focusVisibleRef.current = elementProxy;
166
+ return ()=>{
167
+ elementProxy.classList.remove(...classesToApply);
168
+ elementProxy.removeAttribute('dir');
169
+ };
170
+ }, [
171
+ className,
172
+ dir,
173
+ elementProxy,
174
+ focusVisibleRef
175
+ ]);
176
+ _react.useEffect(()=>{
177
+ return ()=>{
178
+ elementProxy === null || elementProxy === void 0 ? void 0 : elementProxy.remove();
179
+ };
180
+ }, [
181
+ elementProxy
182
+ ]);
183
+ return elementProxy;
184
+ };
185
+ /**
186
+ * Element factory based on the React version.
187
+ *
188
+ * React 17 and below:
189
+ * - useLegacyElementFactory
190
+ *
191
+ * React 18 and above:
192
+ * - useModernElementFactory
193
+ */ const useElementFactory = useInsertionEffect ? useModernElementFactory : useLegacyElementFactory;
19
194
  const usePortalMountNode = (options)=>{
20
195
  'use no memo';
21
196
  const { targetDocument, dir } = (0, _reactsharedcontexts.useFluent_unstable)();
@@ -23,66 +198,12 @@ const usePortalMountNode = (options)=>{
23
198
  const focusVisibleRef = (0, _reacttabster.useFocusVisible)();
24
199
  const classes = (0, _usePortalMountNodeStylesstyles.usePortalMountNodeStylesStyles)();
25
200
  const themeClassName = (0, _reactsharedcontexts.useThemeClassName_unstable)();
26
- const className = (0, _react1.mergeClasses)(themeClassName, classes.root, options.className);
27
- const targetNode = mountNode !== null && mountNode !== void 0 ? mountNode : targetDocument === null || targetDocument === void 0 ? void 0 : targetDocument.body;
28
- const element = (0, _usedisposable.useDisposable)(()=>{
29
- if (targetNode === undefined || options.disabled) {
30
- return [
31
- null,
32
- ()=>null
33
- ];
34
- }
35
- const newElement = targetNode.ownerDocument.createElement('div');
36
- targetNode.appendChild(newElement);
37
- return [
38
- newElement,
39
- ()=>newElement.remove()
40
- ];
41
- }, [
42
- targetNode
43
- ]);
44
- if (useInsertionEffect) {
45
- // eslint-disable-next-line react-hooks/rules-of-hooks
46
- useInsertionEffect(()=>{
47
- if (!element) {
48
- return;
49
- }
50
- const classesToApply = className.split(' ').filter(Boolean);
51
- element.classList.add(...classesToApply);
52
- element.setAttribute('dir', dir);
53
- element.setAttribute('data-portal-node', 'true');
54
- focusVisibleRef.current = element;
55
- return ()=>{
56
- element.classList.remove(...classesToApply);
57
- element.removeAttribute('dir');
58
- };
59
- }, [
60
- className,
61
- dir,
62
- element,
63
- focusVisibleRef
64
- ]);
65
- } else {
66
- // This useMemo call is intentional for React 17
67
- // We don't want to re-create the portal element when its attributes change.
68
- // This also should not be done in an effect because, changing the value of css variables
69
- // after initial mount can trigger interesting CSS side effects like transitions.
70
- // eslint-disable-next-line react-hooks/rules-of-hooks
71
- _react.useMemo(()=>{
72
- if (!element) {
73
- return;
74
- }
75
- // Force replace all classes
76
- element.className = className;
77
- element.setAttribute('dir', dir);
78
- element.setAttribute('data-portal-node', 'true');
79
- focusVisibleRef.current = element;
80
- }, [
81
- className,
82
- dir,
83
- element,
84
- focusVisibleRef
85
- ]);
86
- }
87
- return element;
201
+ const factoryOptions = {
202
+ dir,
203
+ disabled: options.disabled,
204
+ focusVisibleRef,
205
+ className: (0, _react1.mergeClasses)(themeClassName, classes.root, options.className),
206
+ targetNode: mountNode !== null && mountNode !== void 0 ? mountNode : targetDocument === null || targetDocument === void 0 ? void 0 : targetDocument.body
207
+ };
208
+ return useElementFactory(factoryOptions);
88
209
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/Portal/usePortalMountNode.ts"],"sourcesContent":["import * 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';\nimport { useDisposable } from 'use-disposable';\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\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 const focusVisibleRef = useFocusVisible<HTMLDivElement>() as React.MutableRefObject<HTMLElement | null>;\n const classes = usePortalMountNodeStylesStyles();\n const themeClassName = useThemeClassName();\n\n const className = mergeClasses(themeClassName, classes.root, options.className);\n const targetNode: HTMLElement | ShadowRoot | undefined = mountNode ?? targetDocument?.body;\n\n const element = useDisposable(() => {\n if (targetNode === undefined || options.disabled) {\n return [null, () => null];\n }\n\n const newElement = targetNode.ownerDocument.createElement('div');\n targetNode.appendChild(newElement);\n return [newElement, () => newElement.remove()];\n }, [targetNode]);\n\n if (useInsertionEffect) {\n // eslint-disable-next-line react-hooks/rules-of-hooks\n useInsertionEffect(() => {\n if (!element) {\n return;\n }\n\n const classesToApply = className.split(' ').filter(Boolean);\n\n element.classList.add(...classesToApply);\n element.setAttribute('dir', dir);\n element.setAttribute('data-portal-node', 'true');\n\n focusVisibleRef.current = element;\n\n return () => {\n element.classList.remove(...classesToApply);\n element.removeAttribute('dir');\n };\n }, [className, dir, element, focusVisibleRef]);\n } else {\n // This useMemo call is intentional for React 17\n // We don't want to re-create the portal element when its attributes change.\n // This also should not be done in an effect because, changing the value of css variables\n // after initial mount can trigger interesting CSS side effects like transitions.\n // eslint-disable-next-line react-hooks/rules-of-hooks\n React.useMemo(() => {\n if (!element) {\n return;\n }\n\n // Force replace all classes\n element.className = className;\n element.setAttribute('dir', dir);\n element.setAttribute('data-portal-node', 'true');\n\n focusVisibleRef.current = element;\n }, [className, dir, element, focusVisibleRef]);\n }\n\n return element;\n};\n"],"names":["React","useThemeClassName_unstable","useThemeClassName","useFluent_unstable","useFluent","usePortalMountNode","usePortalMountNodeContext","mergeClasses","useFocusVisible","useDisposable","usePortalMountNodeStylesStyles","useInsertionEffect","options","targetDocument","dir","mountNode","focusVisibleRef","classes","themeClassName","className","root","targetNode","body","element","undefined","disabled","newElement","ownerDocument","createElement","appendChild","remove","classesToApply","split","filter","Boolean","classList","add","setAttribute","current","removeAttribute","useMemo"],"mappings":";;;;+BA0BaK;;;;;;;iEA1BU,QAAQ;qCAKxB,kCAAkC;wBACZ,iBAAiB;8BACd,0BAA0B;+BAC5B,iBAAiB;gDAEA,oCAAoC;AAEnF,MAAMM,qBAAsBX,MAAe,CAAC,iBAAiB,SAAS;AAc/D,2BAA2B,CAACY;IACjC;IAEA,MAAM,EAAEC,cAAc,EAAEC,GAAG,EAAE,OAAGV,uCAAAA;IAChC,MAAMW,gBAAYT,uCAAAA;IAElB,MAAMU,sBAAkBR,6BAAAA;IACxB,MAAMS,cAAUP,8DAAAA;IAChB,MAAMQ,qBAAiBhB,+CAAAA;IAEvB,MAAMiB,gBAAYZ,oBAAAA,EAAaW,gBAAgBD,QAAQG,IAAI,EAAER,QAAQO,SAAS;IAC9E,MAAME,aAAmDN,cAAAA,QAAAA,cAAAA,KAAAA,IAAAA,YAAaF,mBAAAA,QAAAA,mBAAAA,KAAAA,IAAAA,KAAAA,IAAAA,eAAgBS,IAAI;IAE1F,MAAMC,cAAUd,4BAAAA,EAAc;QAC5B,IAAIY,eAAeG,aAAaZ,QAAQa,QAAQ,EAAE;YAChD,OAAO;gBAAC;gBAAM,IAAM;aAAK;QAC3B;QAEA,MAAMC,aAAaL,WAAWM,aAAa,CAACC,aAAa,CAAC;QAC1DP,WAAWQ,WAAW,CAACH;QACvB,OAAO;YAACA;YAAY,IAAMA,WAAWI,MAAM;SAAG;IAChD,GAAG;QAACT;KAAW;IAEf,IAAIV,oBAAoB;QACtB,sDAAsD;QACtDA,mBAAmB;YACjB,IAAI,CAACY,SAAS;gBACZ;YACF;YAEA,MAAMQ,iBAAiBZ,UAAUa,KAAK,CAAC,KAAKC,MAAM,CAACC;YAEnDX,QAAQY,SAAS,CAACC,GAAG,IAAIL;YACzBR,QAAQc,YAAY,CAAC,OAAOvB;YAC5BS,QAAQc,YAAY,CAAC,oBAAoB;YAEzCrB,gBAAgBsB,OAAO,GAAGf;YAE1B,OAAO;gBACLA,QAAQY,SAAS,CAACL,MAAM,IAAIC;gBAC5BR,QAAQgB,eAAe,CAAC;YAC1B;QACF,GAAG;YAACpB;YAAWL;YAAKS;YAASP;SAAgB;IAC/C,OAAO;QACL,gDAAgD;QAChD,4EAA4E;QAC5E,yFAAyF;QACzF,iFAAiF;QACjF,sDAAsD;QACtDhB,OAAMwC,OAAO,CAAC;YACZ,IAAI,CAACjB,SAAS;gBACZ;YACF;YAEA,4BAA4B;YAC5BA,QAAQJ,SAAS,GAAGA;YACpBI,QAAQc,YAAY,CAAC,OAAOvB;YAC5BS,QAAQc,YAAY,CAAC,oBAAoB;YAEzCrB,gBAAgBsB,OAAO,GAAGf;QAC5B,GAAG;YAACJ;YAAWL;YAAKS;YAASP;SAAgB;IAC/C;IAEA,OAAOO;AACT,EAAE"}
1
+ {"version":3,"sources":["../src/components/Portal/usePortalMountNode.ts"],"sourcesContent":["import * 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 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 return 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';\n\n const { targetDocument, dir } = useFluent();\n const mountNode = usePortalMountNodeContext();\n\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","Node","ELEMENT_NODE","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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluentui/react-portal",
3
- "version": "9.7.2",
3
+ "version": "9.8.0",
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",
@@ -19,11 +19,10 @@
19
19
  },
20
20
  "dependencies": {
21
21
  "@fluentui/react-shared-contexts": "^9.24.1",
22
- "@fluentui/react-tabster": "^9.26.2",
23
- "@fluentui/react-utilities": "^9.23.1",
22
+ "@fluentui/react-tabster": "^9.26.3",
23
+ "@fluentui/react-utilities": "^9.23.2",
24
24
  "@griffel/react": "^1.5.22",
25
- "@swc/helpers": "^0.5.1",
26
- "use-disposable": "^1.0.1"
25
+ "@swc/helpers": "^0.5.1"
27
26
  },
28
27
  "peerDependencies": {
29
28
  "@types/react": ">=16.14.0 <19.0.0",