react-magic-portal 1.1.1 → 1.1.2
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,3 +1,11 @@
|
|
|
1
|
+
## [1.1.2](https://github.com/molvqingtai/react-magic-portal/compare/v1.1.1...v1.1.2) (2025-09-24)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Performance Improvements
|
|
5
|
+
|
|
6
|
+
* add data-magic-portal attribute ([3c3143b](https://github.com/molvqingtai/react-magic-portal/commit/3c3143be2b5d539fdbbba6bb73a006bfd133e679))
|
|
7
|
+
* add data-magic-portal attribute ([74c132e](https://github.com/molvqingtai/react-magic-portal/commit/74c132ecfc37b56102623e75ad2351b167cad7a0))
|
|
8
|
+
|
|
1
9
|
## [1.1.1](https://github.com/molvqingtai/react-magic-portal/compare/v1.1.0...v1.1.1) (2025-09-24)
|
|
2
10
|
|
|
3
11
|
|
package/package.json
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{useCallback as e,useEffect as t,useRef as n,useState as r}from"react";import i from"react-dom";const a=({anchor:a,position:o=`append`,children:s,onMount:c,onUnmount:l,ref:u,key:d})=>{let[f,p]=r(null),m=n(null),h=e(e=>{u&&(typeof u==`function`?u(e):u.current=e)},[u]),g=e(e=>{let t=document.createElement(`div`);return t.style=`display: contents !important;`,e.insertAdjacentElement({before:`beforebegin`,prepend:`afterbegin`,append:`beforeend`,after:`afterend`}[o],t)},[o]),_=e(()=>typeof a==`string`?document.querySelector(a):typeof a==`function`?a():a&&`current`in a?a.current:a,[a]),v=e(()=>{let e=_();p(t=>{t?.remove(),m.current=e;let n=e?g(e):null;return h(n),n})},[_,g,h]);return t(()=>{v();let e=new MutationObserver(e=>{e.some(e=>{let{addedNodes:t,removedNodes:n}=e;return m.current&&Array.from(n).includes(m.current)?!0:typeof a==`string`?Array.from(t).some(e=>e.nodeType===Node.ELEMENT_NODE&&e instanceof Element&&e.matches?.(a)):!1})&&v()});return e.observe(document.body,{childList:!0,subtree:!0}),()=>e.disconnect()},[v,a]),t(()=>{if(m.current&&f)return c?.(m.current,f),()=>{l?.(m.current,f)}},[f,c,l]),f?i.createPortal(s,f,d):null};a.displayName=`MagicPortal`;var o=a;export{o as default};
|
|
1
|
+
import{useCallback as e,useEffect as t,useRef as n,useState as r}from"react";import i from"react-dom";const a=({anchor:a,position:o=`append`,children:s,onMount:c,onUnmount:l,ref:u,key:d})=>{let[f,p]=r(null),m=n(null),h=e(e=>{u&&(typeof u==`function`?u(e):u.current=e)},[u]),g=e(e=>{let t=document.createElement(`div`);return t.style=`display: contents !important;`,t.dataset.magicPortal=`true`,e.insertAdjacentElement({before:`beforebegin`,prepend:`afterbegin`,append:`beforeend`,after:`afterend`}[o],t)},[o]),_=e(()=>typeof a==`string`?document.querySelector(a):typeof a==`function`?a():a&&`current`in a?a.current:a,[a]),v=e(()=>{let e=_();p(t=>{t?.remove(),m.current=e;let n=e?g(e):null;return h(n),n})},[_,g,h]);return t(()=>{v();let e=new MutationObserver(e=>{e.some(e=>{let{addedNodes:t,removedNodes:n}=e;return m.current&&Array.from(n).includes(m.current)?!0:typeof a==`string`?Array.from(t).some(e=>e.nodeType===Node.ELEMENT_NODE&&e instanceof Element&&e.matches?.(a)):!1})&&v()});return e.observe(document.body,{childList:!0,subtree:!0}),()=>e.disconnect()},[v,a]),t(()=>{if(m.current&&f)return c?.(m.current,f),()=>{l?.(m.current,f)}},[f,c,l]),f?i.createPortal(s,f,d):null};a.displayName=`MagicPortal`;var o=a;export{o as default};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["container"],"sources":["../src/index.ts"],"sourcesContent":["import React, { useEffect, useState, useRef, useCallback } from 'react'\nimport ReactDOM from 'react-dom'\n\nexport interface MagicPortalProps {\n anchor: string | (() => Element | null) | Element | React.RefObject<Element | null> | null\n position?: 'append' | 'prepend' | 'before' | 'after'\n children: React.ReactNode\n onMount?: (anchor: Element, container: HTMLDivElement) => void\n onUnmount?: (anchor: Element, container: HTMLDivElement) => void\n ref?: React.Ref<HTMLDivElement | null>\n key?: React.Key\n}\n\nconst MagicPortal = ({ anchor, position = 'append', children, onMount, onUnmount, ref, key }: MagicPortalProps) => {\n const [container, setContainer] = useState<HTMLDivElement | null>(null)\n const anchorRef = useRef<Element | null>(null)\n\n const updateRef = useCallback(\n (element: HTMLDivElement | null) => {\n if (ref) {\n if (typeof ref === 'function') {\n ref(element)\n } else {\n ref.current = element\n }\n }\n },\n [ref]\n )\n\n const createContainer = useCallback(\n (anchorElement: Element): HTMLDivElement | null => {\n const container = document.createElement('div')\n container.style = 'display: contents !important;'\n\n const positionMap = {\n before: 'beforebegin',\n prepend: 'afterbegin',\n append: 'beforeend',\n after: 'afterend'\n } as const\n\n const result = anchorElement.insertAdjacentElement(positionMap[position], container)\n\n return result as HTMLDivElement | null\n },\n [position]\n )\n\n const resolveAnchor = useCallback((): Element | null => {\n if (typeof anchor === 'string') {\n return document.querySelector(anchor)\n } else if (typeof anchor === 'function') {\n return anchor()\n } else if (anchor && 'current' in anchor) {\n return anchor.current\n } else {\n return anchor\n }\n }, [anchor])\n\n const updateAnchor = useCallback(() => {\n const newAnchor = resolveAnchor()\n\n setContainer((prevContainer) => {\n prevContainer?.remove()\n anchorRef.current = newAnchor\n const newContainer = newAnchor ? createContainer(newAnchor) : null\n updateRef(newContainer)\n return newContainer\n })\n }, [resolveAnchor, createContainer, updateRef])\n\n useEffect(() => {\n updateAnchor()\n\n const observer = new MutationObserver((mutations) => {\n const shouldUpdate = mutations.some((mutation) => {\n const { addedNodes, removedNodes } = mutation\n\n // Check if current anchor is removed\n if (anchorRef.current && Array.from(removedNodes).includes(anchorRef.current)) {\n return true\n }\n\n // Only check added nodes when anchor is a string selector\n if (typeof anchor === 'string') {\n return Array.from(addedNodes).some(\n (node) => node.nodeType === Node.ELEMENT_NODE && node instanceof Element && node.matches?.(anchor)\n )\n }\n\n return false\n })\n\n if (shouldUpdate) {\n updateAnchor()\n }\n })\n\n observer.observe(document.body, {\n childList: true,\n subtree: true\n })\n\n return () => observer.disconnect()\n }, [updateAnchor, anchor])\n\n useEffect(() => {\n if (anchorRef.current && container) {\n onMount?.(anchorRef.current, container)\n return () => {\n onUnmount?.(anchorRef.current!, container)\n }\n }\n }, [container, onMount, onUnmount])\n\n return container ? ReactDOM.createPortal(children, container, key) : null\n}\n\nMagicPortal.displayName = 'MagicPortal'\n\nexport default MagicPortal\n"],"mappings":"sGAaA,MAAM,GAAe,CAAE,SAAQ,WAAW,SAAU,WAAU,UAAS,YAAW,MAAK,SAA4B,CACjH,GAAM,CAAC,EAAW,GAAgB,EAAgC,KAAK,CACjE,EAAY,EAAuB,KAAK,CAExC,EAAY,EACf,GAAmC,CAC9B,IACE,OAAO,GAAQ,WACjB,EAAI,EAAQ,CAEZ,EAAI,QAAU,IAIpB,CAAC,EAAI,CACN,CAEK,EAAkB,EACrB,GAAkD,CACjD,IAAMA,EAAY,SAAS,cAAc,MAAM,CAY/C,MAXA,GAAU,MAAQ,
|
|
1
|
+
{"version":3,"file":"index.js","names":["container"],"sources":["../src/index.ts"],"sourcesContent":["import React, { useEffect, useState, useRef, useCallback } from 'react'\nimport ReactDOM from 'react-dom'\n\nexport interface MagicPortalProps {\n anchor: string | (() => Element | null) | Element | React.RefObject<Element | null> | null\n position?: 'append' | 'prepend' | 'before' | 'after'\n children: React.ReactNode\n onMount?: (anchor: Element, container: HTMLDivElement) => void\n onUnmount?: (anchor: Element, container: HTMLDivElement) => void\n ref?: React.Ref<HTMLDivElement | null>\n key?: React.Key\n}\n\nconst MagicPortal = ({ anchor, position = 'append', children, onMount, onUnmount, ref, key }: MagicPortalProps) => {\n const [container, setContainer] = useState<HTMLDivElement | null>(null)\n const anchorRef = useRef<Element | null>(null)\n\n const updateRef = useCallback(\n (element: HTMLDivElement | null) => {\n if (ref) {\n if (typeof ref === 'function') {\n ref(element)\n } else {\n ref.current = element\n }\n }\n },\n [ref]\n )\n\n const createContainer = useCallback(\n (anchorElement: Element): HTMLDivElement | null => {\n const container = document.createElement('div')\n container.style = 'display: contents !important;'\n container.dataset.magicPortal = 'true'\n const positionMap = {\n before: 'beforebegin',\n prepend: 'afterbegin',\n append: 'beforeend',\n after: 'afterend'\n } as const\n\n const result = anchorElement.insertAdjacentElement(positionMap[position], container)\n\n return result as HTMLDivElement | null\n },\n [position]\n )\n\n const resolveAnchor = useCallback((): Element | null => {\n if (typeof anchor === 'string') {\n return document.querySelector(anchor)\n } else if (typeof anchor === 'function') {\n return anchor()\n } else if (anchor && 'current' in anchor) {\n return anchor.current\n } else {\n return anchor\n }\n }, [anchor])\n\n const updateAnchor = useCallback(() => {\n const newAnchor = resolveAnchor()\n\n setContainer((prevContainer) => {\n prevContainer?.remove()\n anchorRef.current = newAnchor\n const newContainer = newAnchor ? createContainer(newAnchor) : null\n updateRef(newContainer)\n return newContainer\n })\n }, [resolveAnchor, createContainer, updateRef])\n\n useEffect(() => {\n updateAnchor()\n\n const observer = new MutationObserver((mutations) => {\n const shouldUpdate = mutations.some((mutation) => {\n const { addedNodes, removedNodes } = mutation\n\n // Check if current anchor is removed\n if (anchorRef.current && Array.from(removedNodes).includes(anchorRef.current)) {\n return true\n }\n\n // Only check added nodes when anchor is a string selector\n if (typeof anchor === 'string') {\n return Array.from(addedNodes).some(\n (node) => node.nodeType === Node.ELEMENT_NODE && node instanceof Element && node.matches?.(anchor)\n )\n }\n\n return false\n })\n\n if (shouldUpdate) {\n updateAnchor()\n }\n })\n\n observer.observe(document.body, {\n childList: true,\n subtree: true\n })\n\n return () => observer.disconnect()\n }, [updateAnchor, anchor])\n\n useEffect(() => {\n if (anchorRef.current && container) {\n onMount?.(anchorRef.current, container)\n return () => {\n onUnmount?.(anchorRef.current!, container)\n }\n }\n }, [container, onMount, onUnmount])\n\n return container ? ReactDOM.createPortal(children, container, key) : null\n}\n\nMagicPortal.displayName = 'MagicPortal'\n\nexport default MagicPortal\n"],"mappings":"sGAaA,MAAM,GAAe,CAAE,SAAQ,WAAW,SAAU,WAAU,UAAS,YAAW,MAAK,SAA4B,CACjH,GAAM,CAAC,EAAW,GAAgB,EAAgC,KAAK,CACjE,EAAY,EAAuB,KAAK,CAExC,EAAY,EACf,GAAmC,CAC9B,IACE,OAAO,GAAQ,WACjB,EAAI,EAAQ,CAEZ,EAAI,QAAU,IAIpB,CAAC,EAAI,CACN,CAEK,EAAkB,EACrB,GAAkD,CACjD,IAAMA,EAAY,SAAS,cAAc,MAAM,CAY/C,MAXA,GAAU,MAAQ,gCAClB,EAAU,QAAQ,YAAc,OAQjB,EAAc,sBAPT,CAClB,OAAQ,cACR,QAAS,aACT,OAAQ,YACR,MAAO,WACR,CAE8D,GAAWA,EAAU,EAItF,CAAC,EAAS,CACX,CAEK,EAAgB,MAChB,OAAO,GAAW,SACb,SAAS,cAAc,EAAO,CAC5B,OAAO,GAAW,WACpB,GAAQ,CACN,GAAU,YAAa,EACzB,EAAO,QAEP,EAER,CAAC,EAAO,CAAC,CAEN,EAAe,MAAkB,CACrC,IAAM,EAAY,GAAe,CAEjC,EAAc,GAAkB,CAC9B,GAAe,QAAQ,CACvB,EAAU,QAAU,EACpB,IAAM,EAAe,EAAY,EAAgB,EAAU,CAAG,KAE9D,OADA,EAAU,EAAa,CAChB,GACP,EACD,CAAC,EAAe,EAAiB,EAAU,CAAC,CA8C/C,OA5CA,MAAgB,CACd,GAAc,CAEd,IAAM,EAAW,IAAI,iBAAkB,GAAc,CAC9B,EAAU,KAAM,GAAa,CAChD,GAAM,CAAE,aAAY,gBAAiB,EAcrC,OAXI,EAAU,SAAW,MAAM,KAAK,EAAa,CAAC,SAAS,EAAU,QAAQ,CACpE,GAIL,OAAO,GAAW,SACb,MAAM,KAAK,EAAW,CAAC,KAC3B,GAAS,EAAK,WAAa,KAAK,cAAgB,aAAgB,SAAW,EAAK,UAAU,EAAO,CACnG,CAGI,IACP,EAGA,GAAc,EAEhB,CAOF,OALA,EAAS,QAAQ,SAAS,KAAM,CAC9B,UAAW,GACX,QAAS,GACV,CAAC,KAEW,EAAS,YAAY,EACjC,CAAC,EAAc,EAAO,CAAC,CAE1B,MAAgB,CACd,GAAI,EAAU,SAAW,EAEvB,OADA,IAAU,EAAU,QAAS,EAAU,KAC1B,CACX,IAAY,EAAU,QAAU,EAAU,GAG7C,CAAC,EAAW,EAAS,EAAU,CAAC,CAE5B,EAAY,EAAS,aAAa,EAAU,EAAW,EAAI,CAAG,MAGvE,EAAY,YAAc,cAE1B,IAAA,EAAe"}
|
|
@@ -32,7 +32,7 @@ const MagicPortal = ({ anchor, position = 'append', children, onMount, onUnmount
|
|
|
32
32
|
(anchorElement: Element): HTMLDivElement | null => {
|
|
33
33
|
const container = document.createElement('div')
|
|
34
34
|
container.style = 'display: contents !important;'
|
|
35
|
-
|
|
35
|
+
container.dataset.magicPortal = 'true'
|
|
36
36
|
const positionMap = {
|
|
37
37
|
before: 'beforebegin',
|
|
38
38
|
prepend: 'afterbegin',
|