@fluentui/react-portal 9.4.2 → 9.4.4

Sign up to get free protection for your applications and to get access to all the features.
package/CHANGELOG.md CHANGED
@@ -1,12 +1,33 @@
1
1
  # Change Log - @fluentui/react-portal
2
2
 
3
- This log was last generated on Mon, 20 Nov 2023 09:51:22 GMT and should not be manually modified.
3
+ This log was last generated on Thu, 14 Dec 2023 09:51:35 GMT and should not be manually modified.
4
4
 
5
5
  <!-- Start content -->
6
6
 
7
+ ## [9.4.4](https://github.com/microsoft/fluentui/tree/@fluentui/react-portal_v9.4.4)
8
+
9
+ Thu, 14 Dec 2023 09:51:35 GMT
10
+ [Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-portal_v9.4.3..@fluentui/react-portal_v9.4.4)
11
+
12
+ ### Patches
13
+
14
+ - fix: Virtual parent cannot be the DOM child of mount node ([PR #29990](https://github.com/microsoft/fluentui/pull/29990) by lingfangao@hotmail.com)
15
+ - Bump @fluentui/react-shared-contexts to v9.13.1 ([commit](https://github.com/microsoft/fluentui/commit/80a1b02be2fbbdde916ac87fbf760e442a2295c4) by beachball)
16
+ - Bump @fluentui/react-tabster to v9.15.1 ([commit](https://github.com/microsoft/fluentui/commit/80a1b02be2fbbdde916ac87fbf760e442a2295c4) by beachball)
17
+ - Bump @fluentui/react-utilities to v9.15.3 ([commit](https://github.com/microsoft/fluentui/commit/80a1b02be2fbbdde916ac87fbf760e442a2295c4) by beachball)
18
+
19
+ ## [9.4.3](https://github.com/microsoft/fluentui/tree/@fluentui/react-portal_v9.4.3)
20
+
21
+ Thu, 30 Nov 2023 13:42:06 GMT
22
+ [Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-portal_v9.4.2..@fluentui/react-portal_v9.4.3)
23
+
24
+ ### Patches
25
+
26
+ - Bump @fluentui/react-tabster to v9.15.0 ([PR #29929](https://github.com/microsoft/fluentui/pull/29929) by beachball)
27
+
7
28
  ## [9.4.2](https://github.com/microsoft/fluentui/tree/@fluentui/react-portal_v9.4.2)
8
29
 
9
- Mon, 20 Nov 2023 09:51:22 GMT
30
+ Mon, 20 Nov 2023 09:55:10 GMT
10
31
  [Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-portal_v9.4.1..@fluentui/react-portal_v9.4.2)
11
32
 
12
33
  ### Patches
package/dist/index.d.ts CHANGED
@@ -41,6 +41,11 @@ export declare const renderPortal_unstable: (state: PortalState) => React_2.Reac
41
41
 
42
42
  export { setVirtualParent }
43
43
 
44
+ /**
45
+ * The function that normalizes the `mountNode` prop into an object with element and className props.
46
+ *
47
+ * @param mountNode - an HTML element or an object with props
48
+ */
44
49
  export declare function toMountNodeProps(mountNode: PortalProps['mountNode']): {
45
50
  element?: HTMLElement | null;
46
51
  className?: string;
@@ -1,22 +1,7 @@
1
- import { isHTMLElement, setVirtualParent } from '@fluentui/react-utilities';
1
+ import { setVirtualParent } from '@fluentui/react-utilities';
2
2
  import * as React from 'react';
3
+ import { toMountNodeProps } from '../../utils/toMountNodeProps';
3
4
  import { usePortalMountNode } from './usePortalMountNode';
4
- export function toMountNodeProps(mountNode) {
5
- if (isHTMLElement(mountNode)) {
6
- return {
7
- element: mountNode
8
- };
9
- }
10
- if (typeof mountNode === 'object') {
11
- if (mountNode === null) {
12
- return {
13
- element: null
14
- };
15
- }
16
- return mountNode;
17
- }
18
- return {};
19
- }
20
5
  /**
21
6
  * Create the state required to render Portal.
22
7
  *
@@ -30,23 +15,66 @@ export function toMountNodeProps(mountNode) {
30
15
  disabled: !!element,
31
16
  className
32
17
  });
18
+ const mountNode = element !== null && element !== void 0 ? element : fallbackElement;
33
19
  const state = {
34
20
  children: props.children,
35
- mountNode: element !== null && element !== void 0 ? element : fallbackElement,
21
+ mountNode,
36
22
  virtualParentRootRef
37
23
  };
38
24
  React.useEffect(()=>{
39
- if (state.virtualParentRootRef.current && state.mountNode) {
40
- setVirtualParent(state.mountNode, state.virtualParentRootRef.current);
25
+ if (!mountNode) {
26
+ return;
27
+ }
28
+ const virtualParent = virtualParentRootRef.current;
29
+ // By default, we create a mount node for portal on `document.body` (see usePortalMountNode()) and have following structure:
30
+ //
31
+ // <body>
32
+ // <!-- ⚛️ application root -->
33
+ // <div id="root">
34
+ // <!-- ⬇️ portal node rendered in a tree to anchor (virtual parent node) -->
35
+ // <span aria-hidden="true"></span>
36
+ // </div>
37
+ // <div id="portal-mount-node">
38
+ // <!-- 🧩portal content -->
39
+ // </div>
40
+ // </body>
41
+ //
42
+ // 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):
43
+ // virtual.contains(mountNode) === false
44
+ // (while we need ⬇️⬇️⬇️)
45
+ // elementsContains(virtualParent, mountNode) === true
46
+ // elementsContains(mountNode, virtualParent) === false
47
+ //
48
+ // For more details, check docs for virtual parent utils.
49
+ //
50
+ // However, if a user provides a custom mount node (via `props`) the structure could be different:
51
+ //
52
+ // <body>
53
+ // <!-- application root -->
54
+ // <div id="root">
55
+ // <div id="portal-mount-node">
56
+ // <!-- 🧩portal content -->
57
+ //
58
+ // <span aria-hidden="true"></span>
59
+ // </div>
60
+ // </div>
61
+ // </body>
62
+ //
63
+ // 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.
64
+ //
65
+ // Otherwise, there is a circular reference - both elements are parents of each other:
66
+ // elementsContains(mountNode, virtualParent) === true
67
+ // elementsContains(virtualParent, mountNode) === true
68
+ const isVirtualParentInsideChild = mountNode.contains(virtualParent);
69
+ if (virtualParent && !isVirtualParentInsideChild) {
70
+ setVirtualParent(mountNode, virtualParent);
71
+ return ()=>{
72
+ setVirtualParent(mountNode, undefined);
73
+ };
41
74
  }
42
- return ()=>{
43
- if (state.mountNode) {
44
- setVirtualParent(state.mountNode, undefined);
45
- }
46
- };
47
75
  }, [
48
- state.virtualParentRootRef,
49
- state.mountNode
76
+ virtualParentRootRef,
77
+ mountNode
50
78
  ]);
51
79
  return state;
52
80
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["usePortal.ts"],"sourcesContent":["import { isHTMLElement, setVirtualParent } from '@fluentui/react-utilities';\nimport * as React from 'react';\n\nimport { usePortalMountNode } from './usePortalMountNode';\nimport type { PortalProps, PortalState } from './Portal.types';\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\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 state: PortalState = {\n children: props.children,\n mountNode: element ?? fallbackElement,\n virtualParentRootRef,\n };\n\n React.useEffect(() => {\n if (state.virtualParentRootRef.current && state.mountNode) {\n setVirtualParent(state.mountNode, state.virtualParentRootRef.current);\n }\n return () => {\n if (state.mountNode) {\n setVirtualParent(state.mountNode, undefined);\n }\n };\n }, [state.virtualParentRootRef, state.mountNode]);\n\n return state;\n};\n"],"names":["isHTMLElement","setVirtualParent","React","usePortalMountNode","toMountNodeProps","mountNode","element","usePortal_unstable","props","className","virtualParentRootRef","useRef","fallbackElement","disabled","state","children","useEffect","current","undefined"],"mappings":"AAAA,SAASA,aAAa,EAAEC,gBAAgB,QAAQ,4BAA4B;AAC5E,YAAYC,WAAW,QAAQ;AAE/B,SAASC,kBAAkB,QAAQ,uBAAuB;AAG1D,OAAO,SAASC,iBAAiBC,SAAmC;IAIlE,IAAIL,cAAcK,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;AAEA;;;;;;CAMC,GACD,OAAO,MAAME,qBAAqB,CAACC;IACjC,MAAM,EAAEF,OAAO,EAAEG,SAAS,EAAE,GAAGL,iBAAiBI,MAAMH,SAAS;IAE/D,MAAMK,uBAAuBR,MAAMS,MAAM,CAAkB;IAC3D,MAAMC,kBAAkBT,mBAAmB;QAAEU,UAAU,CAAC,CAACP;QAASG;IAAU;IAE5E,MAAMK,QAAqB;QACzBC,UAAUP,MAAMO,QAAQ;QACxBV,WAAWC,oBAAAA,qBAAAA,UAAWM;QACtBF;IACF;IAEAR,MAAMc,SAAS,CAAC;QACd,IAAIF,MAAMJ,oBAAoB,CAACO,OAAO,IAAIH,MAAMT,SAAS,EAAE;YACzDJ,iBAAiBa,MAAMT,SAAS,EAAES,MAAMJ,oBAAoB,CAACO,OAAO;QACtE;QACA,OAAO;YACL,IAAIH,MAAMT,SAAS,EAAE;gBACnBJ,iBAAiBa,MAAMT,SAAS,EAAEa;YACpC;QACF;IACF,GAAG;QAACJ,MAAMJ,oBAAoB;QAAEI,MAAMT,SAAS;KAAC;IAEhD,OAAOS;AACT,EAAE"}
1
+ {"version":3,"sources":["usePortal.ts"],"sourcesContent":["import { 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,SAASA,gBAAgB,QAAQ,4BAA4B;AAC7D,YAAYC,WAAW,QAAQ;AAE/B,SAASC,gBAAgB,QAAQ,+BAA+B;AAChE,SAASC,kBAAkB,QAAQ,uBAAuB;AAG1D;;;;;;CAMC,GACD,OAAO,MAAMC,qBAAqB,CAACC;IACjC,MAAM,EAAEC,OAAO,EAAEC,SAAS,EAAE,GAAGL,iBAAiBG,MAAMG,SAAS;IAE/D,MAAMC,uBAAuBR,MAAMS,MAAM,CAAkB;IAC3D,MAAMC,kBAAkBR,mBAAmB;QAAES,UAAU,CAAC,CAACN;QAASC;IAAU;IAE5E,MAAMC,YAAYF,oBAAAA,qBAAAA,UAAWK;IAC7B,MAAME,QAAqB;QACzBC,UAAUT,MAAMS,QAAQ;QACxBN;QACAC;IACF;IAEAR,MAAMc,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,iBAAiBQ,WAAWQ;YAE5B,OAAO;gBACLhB,iBAAiBQ,WAAWY;YAC9B;QACF;IACF,GAAG;QAACX;QAAsBD;KAAU;IAEpC,OAAOK;AACT,EAAE"}
package/lib/index.js CHANGED
@@ -1,2 +1,3 @@
1
1
  export { elementContains, setVirtualParent } from '@fluentui/react-utilities';
2
- export { Portal, renderPortal_unstable, toMountNodeProps, usePortal_unstable } from './components/Portal/index';
2
+ export { Portal, renderPortal_unstable, usePortal_unstable } from './components/Portal/index';
3
+ export { toMountNodeProps } from './utils/toMountNodeProps';
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["index.ts"],"sourcesContent":["export { elementContains, setVirtualParent } from '@fluentui/react-utilities';\nexport { Portal, renderPortal_unstable, toMountNodeProps, usePortal_unstable } from './components/Portal/index';\nexport type { PortalProps, PortalState } from './components/Portal/index';\n"],"names":["elementContains","setVirtualParent","Portal","renderPortal_unstable","toMountNodeProps","usePortal_unstable"],"mappings":"AAAA,SAASA,eAAe,EAAEC,gBAAgB,QAAQ,4BAA4B;AAC9E,SAASC,MAAM,EAAEC,qBAAqB,EAAEC,gBAAgB,EAAEC,kBAAkB,QAAQ,4BAA4B"}
1
+ {"version":3,"sources":["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":"AAAA,SAASA,eAAe,EAAEC,gBAAgB,QAAQ,4BAA4B;AAC9E,SAASC,MAAM,EAAEC,qBAAqB,EAAEC,kBAAkB,QAAQ,4BAA4B;AAG9F,SAASC,gBAAgB,QAAQ,2BAA2B"}
@@ -0,0 +1,21 @@
1
+ import { isHTMLElement } from '@fluentui/react-utilities';
2
+ /**
3
+ * The function that normalizes the `mountNode` prop into an object with element and className props.
4
+ *
5
+ * @param mountNode - an HTML element or an object with props
6
+ */ export function toMountNodeProps(mountNode) {
7
+ if (isHTMLElement(mountNode)) {
8
+ return {
9
+ element: mountNode
10
+ };
11
+ }
12
+ if (typeof mountNode === 'object') {
13
+ if (mountNode === null) {
14
+ return {
15
+ element: null
16
+ };
17
+ }
18
+ return mountNode;
19
+ }
20
+ return {};
21
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["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":"AAAA,SAASA,aAAa,QAAQ,4BAA4B;AAG1D;;;;CAIC,GACD,OAAO,SAASC,iBAAiBC,SAAmC;IAIlE,IAAIF,cAAcE,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"}
@@ -2,64 +2,84 @@
2
2
  Object.defineProperty(exports, "__esModule", {
3
3
  value: true
4
4
  });
5
- function _export(target, all) {
6
- for(var name in all)Object.defineProperty(target, name, {
7
- enumerable: true,
8
- get: all[name]
9
- });
10
- }
11
- _export(exports, {
12
- toMountNodeProps: function() {
13
- return toMountNodeProps;
14
- },
15
- usePortal_unstable: function() {
5
+ Object.defineProperty(exports, "usePortal_unstable", {
6
+ enumerable: true,
7
+ get: function() {
16
8
  return usePortal_unstable;
17
9
  }
18
10
  });
19
11
  const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
20
12
  const _reactutilities = require("@fluentui/react-utilities");
21
13
  const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));
14
+ const _toMountNodeProps = require("../../utils/toMountNodeProps");
22
15
  const _usePortalMountNode = require("./usePortalMountNode");
23
- function toMountNodeProps(mountNode) {
24
- if ((0, _reactutilities.isHTMLElement)(mountNode)) {
25
- return {
26
- element: mountNode
27
- };
28
- }
29
- if (typeof mountNode === 'object') {
30
- if (mountNode === null) {
31
- return {
32
- element: null
33
- };
34
- }
35
- return mountNode;
36
- }
37
- return {};
38
- }
39
16
  const usePortal_unstable = (props)=>{
40
- const { element, className } = toMountNodeProps(props.mountNode);
17
+ const { element, className } = (0, _toMountNodeProps.toMountNodeProps)(props.mountNode);
41
18
  const virtualParentRootRef = _react.useRef(null);
42
19
  const fallbackElement = (0, _usePortalMountNode.usePortalMountNode)({
43
20
  disabled: !!element,
44
21
  className
45
22
  });
23
+ const mountNode = element !== null && element !== void 0 ? element : fallbackElement;
46
24
  const state = {
47
25
  children: props.children,
48
- mountNode: element !== null && element !== void 0 ? element : fallbackElement,
26
+ mountNode,
49
27
  virtualParentRootRef
50
28
  };
51
29
  _react.useEffect(()=>{
52
- if (state.virtualParentRootRef.current && state.mountNode) {
53
- (0, _reactutilities.setVirtualParent)(state.mountNode, state.virtualParentRootRef.current);
30
+ if (!mountNode) {
31
+ return;
32
+ }
33
+ const virtualParent = virtualParentRootRef.current;
34
+ // By default, we create a mount node for portal on `document.body` (see usePortalMountNode()) and have following structure:
35
+ //
36
+ // <body>
37
+ // <!-- ⚛️ application root -->
38
+ // <div id="root">
39
+ // <!-- ⬇️ portal node rendered in a tree to anchor (virtual parent node) -->
40
+ // <span aria-hidden="true"></span>
41
+ // </div>
42
+ // <div id="portal-mount-node">
43
+ // <!-- 🧩portal content -->
44
+ // </div>
45
+ // </body>
46
+ //
47
+ // 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):
48
+ // virtual.contains(mountNode) === false
49
+ // (while we need ⬇️⬇️⬇️)
50
+ // elementsContains(virtualParent, mountNode) === true
51
+ // elementsContains(mountNode, virtualParent) === false
52
+ //
53
+ // For more details, check docs for virtual parent utils.
54
+ //
55
+ // However, if a user provides a custom mount node (via `props`) the structure could be different:
56
+ //
57
+ // <body>
58
+ // <!-- application root -->
59
+ // <div id="root">
60
+ // <div id="portal-mount-node">
61
+ // <!-- 🧩portal content -->
62
+ //
63
+ // <span aria-hidden="true"></span>
64
+ // </div>
65
+ // </div>
66
+ // </body>
67
+ //
68
+ // 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.
69
+ //
70
+ // Otherwise, there is a circular reference - both elements are parents of each other:
71
+ // elementsContains(mountNode, virtualParent) === true
72
+ // elementsContains(virtualParent, mountNode) === true
73
+ const isVirtualParentInsideChild = mountNode.contains(virtualParent);
74
+ if (virtualParent && !isVirtualParentInsideChild) {
75
+ (0, _reactutilities.setVirtualParent)(mountNode, virtualParent);
76
+ return ()=>{
77
+ (0, _reactutilities.setVirtualParent)(mountNode, undefined);
78
+ };
54
79
  }
55
- return ()=>{
56
- if (state.mountNode) {
57
- (0, _reactutilities.setVirtualParent)(state.mountNode, undefined);
58
- }
59
- };
60
80
  }, [
61
- state.virtualParentRootRef,
62
- state.mountNode
81
+ virtualParentRootRef,
82
+ mountNode
63
83
  ]);
64
84
  return state;
65
85
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["usePortal.js"],"sourcesContent":["import { isHTMLElement, setVirtualParent } from '@fluentui/react-utilities';\nimport * as React from 'react';\nimport { usePortalMountNode } from './usePortalMountNode';\nexport function toMountNodeProps(mountNode) {\n if (isHTMLElement(mountNode)) {\n return {\n element: mountNode\n };\n }\n if (typeof mountNode === 'object') {\n if (mountNode === null) {\n return {\n element: null\n };\n }\n return mountNode;\n }\n return {};\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 */ export const usePortal_unstable = (props)=>{\n const { element, className } = toMountNodeProps(props.mountNode);\n const virtualParentRootRef = React.useRef(null);\n const fallbackElement = usePortalMountNode({\n disabled: !!element,\n className\n });\n const state = {\n children: props.children,\n mountNode: element !== null && element !== void 0 ? element : fallbackElement,\n virtualParentRootRef\n };\n React.useEffect(()=>{\n if (state.virtualParentRootRef.current && state.mountNode) {\n setVirtualParent(state.mountNode, state.virtualParentRootRef.current);\n }\n return ()=>{\n if (state.mountNode) {\n setVirtualParent(state.mountNode, undefined);\n }\n };\n }, [\n state.virtualParentRootRef,\n state.mountNode\n ]);\n return state;\n};\n"],"names":["toMountNodeProps","usePortal_unstable","mountNode","isHTMLElement","element","props","className","virtualParentRootRef","React","useRef","fallbackElement","usePortalMountNode","disabled","state","children","useEffect","current","setVirtualParent","undefined"],"mappings":";;;;;;;;;;;IAGgBA,gBAAgB;eAAhBA;;IAsBCC,kBAAkB;eAAlBA;;;;gCAzB+B;iEACzB;oCACY;AAC5B,SAASD,iBAAiBE,SAAS;IACtC,IAAIC,IAAAA,6BAAa,EAACD,YAAY;QAC1B,OAAO;YACHE,SAASF;QACb;IACJ;IACA,IAAI,OAAOA,cAAc,UAAU;QAC/B,IAAIA,cAAc,MAAM;YACpB,OAAO;gBACHE,SAAS;YACb;QACJ;QACA,OAAOF;IACX;IACA,OAAO,CAAC;AACZ;AAOW,MAAMD,qBAAqB,CAACI;IACnC,MAAM,EAAED,OAAO,EAAEE,SAAS,EAAE,GAAGN,iBAAiBK,MAAMH,SAAS;IAC/D,MAAMK,uBAAuBC,OAAMC,MAAM,CAAC;IAC1C,MAAMC,kBAAkBC,IAAAA,sCAAkB,EAAC;QACvCC,UAAU,CAAC,CAACR;QACZE;IACJ;IACA,MAAMO,QAAQ;QACVC,UAAUT,MAAMS,QAAQ;QACxBZ,WAAWE,YAAY,QAAQA,YAAY,KAAK,IAAIA,UAAUM;QAC9DH;IACJ;IACAC,OAAMO,SAAS,CAAC;QACZ,IAAIF,MAAMN,oBAAoB,CAACS,OAAO,IAAIH,MAAMX,SAAS,EAAE;YACvDe,IAAAA,gCAAgB,EAACJ,MAAMX,SAAS,EAAEW,MAAMN,oBAAoB,CAACS,OAAO;QACxE;QACA,OAAO;YACH,IAAIH,MAAMX,SAAS,EAAE;gBACjBe,IAAAA,gCAAgB,EAACJ,MAAMX,SAAS,EAAEgB;YACtC;QACJ;IACJ,GAAG;QACCL,MAAMN,oBAAoB;QAC1BM,MAAMX,SAAS;KAClB;IACD,OAAOW;AACX"}
1
+ {"version":3,"sources":["usePortal.js"],"sourcesContent":["import { setVirtualParent } from '@fluentui/react-utilities';\nimport * as React from 'react';\nimport { toMountNodeProps } from '../../utils/toMountNodeProps';\nimport { usePortalMountNode } from './usePortalMountNode';\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 */ export const usePortal_unstable = (props)=>{\n const { element, className } = toMountNodeProps(props.mountNode);\n const virtualParentRootRef = React.useRef(null);\n const fallbackElement = usePortalMountNode({\n disabled: !!element,\n className\n });\n const mountNode = element !== null && element !== void 0 ? element : fallbackElement;\n const state = {\n children: props.children,\n mountNode,\n virtualParentRootRef\n };\n React.useEffect(()=>{\n if (!mountNode) {\n return;\n }\n const virtualParent = virtualParentRootRef.current;\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 if (virtualParent && !isVirtualParentInsideChild) {\n setVirtualParent(mountNode, virtualParent);\n return ()=>{\n setVirtualParent(mountNode, undefined);\n };\n }\n }, [\n virtualParentRootRef,\n 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":";;;;+BAUiBA;;;eAAAA;;;;gCAVgB;iEACV;kCACU;oCACE;AAOxB,MAAMA,qBAAqB,CAACC;IACnC,MAAM,EAAEC,OAAO,EAAEC,SAAS,EAAE,GAAGC,IAAAA,kCAAgB,EAACH,MAAMI,SAAS;IAC/D,MAAMC,uBAAuBC,OAAMC,MAAM,CAAC;IAC1C,MAAMC,kBAAkBC,IAAAA,sCAAkB,EAAC;QACvCC,UAAU,CAAC,CAACT;QACZC;IACJ;IACA,MAAME,YAAYH,YAAY,QAAQA,YAAY,KAAK,IAAIA,UAAUO;IACrE,MAAMG,QAAQ;QACVC,UAAUZ,MAAMY,QAAQ;QACxBR;QACAC;IACJ;IACAC,OAAMO,SAAS,CAAC;QACZ,IAAI,CAACT,WAAW;YACZ;QACJ;QACA,MAAMU,gBAAgBT,qBAAqBU,OAAO;QAClD,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;QACtD,IAAIA,iBAAiB,CAACE,4BAA4B;YAC9CE,IAAAA,gCAAgB,EAACd,WAAWU;YAC5B,OAAO;gBACHI,IAAAA,gCAAgB,EAACd,WAAWe;YAChC;QACJ;IACJ,GAAG;QACCd;QACAD;KACH;IACD,OAAOO;AACX"}
@@ -21,12 +21,13 @@ _export(exports, {
21
21
  renderPortal_unstable: function() {
22
22
  return _index.renderPortal_unstable;
23
23
  },
24
- toMountNodeProps: function() {
25
- return _index.toMountNodeProps;
26
- },
27
24
  usePortal_unstable: function() {
28
25
  return _index.usePortal_unstable;
26
+ },
27
+ toMountNodeProps: function() {
28
+ return _toMountNodeProps.toMountNodeProps;
29
29
  }
30
30
  });
31
31
  const _reactutilities = require("@fluentui/react-utilities");
32
32
  const _index = require("./components/Portal/index");
33
+ const _toMountNodeProps = require("./utils/toMountNodeProps");
@@ -1 +1 @@
1
- {"version":3,"sources":["index.js"],"sourcesContent":["export { elementContains, setVirtualParent } from '@fluentui/react-utilities';\nexport { Portal, renderPortal_unstable, toMountNodeProps, usePortal_unstable } from './components/Portal/index';\n"],"names":["elementContains","setVirtualParent","Portal","renderPortal_unstable","toMountNodeProps","usePortal_unstable"],"mappings":";;;;;;;;;;;IAASA,eAAe;eAAfA,+BAAe;;IAAEC,gBAAgB;eAAhBA,gCAAgB;;IACjCC,MAAM;eAANA,aAAM;;IAAEC,qBAAqB;eAArBA,4BAAqB;;IAAEC,gBAAgB;eAAhBA,uBAAgB;;IAAEC,kBAAkB;eAAlBA,yBAAkB;;;gCAD1B;uBACkC"}
1
+ {"version":3,"sources":["index.js"],"sourcesContent":["export { elementContains, setVirtualParent } from '@fluentui/react-utilities';\nexport { Portal, renderPortal_unstable, usePortal_unstable } from './components/Portal/index';\nexport { toMountNodeProps } from './utils/toMountNodeProps';\n"],"names":["elementContains","setVirtualParent","Portal","renderPortal_unstable","usePortal_unstable","toMountNodeProps"],"mappings":";;;;;;;;;;;IAASA,eAAe;eAAfA,+BAAe;;IAAEC,gBAAgB;eAAhBA,gCAAgB;;IACjCC,MAAM;eAANA,aAAM;;IAAEC,qBAAqB;eAArBA,4BAAqB;;IAAEC,kBAAkB;eAAlBA,yBAAkB;;IACjDC,gBAAgB;eAAhBA,kCAAgB;;;gCAFyB;uBACgB;kCACjC"}
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "toMountNodeProps", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return toMountNodeProps;
9
+ }
10
+ });
11
+ const _reactutilities = require("@fluentui/react-utilities");
12
+ function toMountNodeProps(mountNode) {
13
+ if ((0, _reactutilities.isHTMLElement)(mountNode)) {
14
+ return {
15
+ element: mountNode
16
+ };
17
+ }
18
+ if (typeof mountNode === 'object') {
19
+ if (mountNode === null) {
20
+ return {
21
+ element: null
22
+ };
23
+ }
24
+ return mountNode;
25
+ }
26
+ return {};
27
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["toMountNodeProps.js"],"sourcesContent":["import { isHTMLElement } from '@fluentui/react-utilities';\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 */ export function toMountNodeProps(mountNode) {\n if (isHTMLElement(mountNode)) {\n return {\n element: mountNode\n };\n }\n if (typeof mountNode === 'object') {\n if (mountNode === null) {\n return {\n element: null\n };\n }\n return mountNode;\n }\n return {};\n}\n"],"names":["toMountNodeProps","mountNode","isHTMLElement","element"],"mappings":";;;;+BAKoBA;;;eAAAA;;;gCALU;AAKnB,SAASA,iBAAiBC,SAAS;IAC1C,IAAIC,IAAAA,6BAAa,EAACD,YAAY;QAC1B,OAAO;YACHE,SAASF;QACb;IACJ;IACA,IAAI,OAAOA,cAAc,UAAU;QAC/B,IAAIA,cAAc,MAAM;YACpB,OAAO;gBACHE,SAAS;YACb;QACJ;QACA,OAAOF;IACX;IACA,OAAO,CAAC;AACZ"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluentui/react-portal",
3
- "version": "9.4.2",
3
+ "version": "9.4.4",
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",
@@ -32,9 +32,9 @@
32
32
  "@fluentui/scripts-tasks": "*"
33
33
  },
34
34
  "dependencies": {
35
- "@fluentui/react-shared-contexts": "^9.13.0",
36
- "@fluentui/react-tabster": "^9.14.6",
37
- "@fluentui/react-utilities": "^9.15.2",
35
+ "@fluentui/react-shared-contexts": "^9.13.1",
36
+ "@fluentui/react-tabster": "^9.15.1",
37
+ "@fluentui/react-utilities": "^9.15.3",
38
38
  "@griffel/react": "^1.5.14",
39
39
  "@swc/helpers": "^0.5.1",
40
40
  "use-disposable": "^1.0.1"