@radix-ui/react-focus-guards
Advanced tools
+15
-5
@@ -43,2 +43,3 @@ "use strict"; | ||
| var count = 0; | ||
| var guards = null; | ||
| function FocusGuards(props) { | ||
@@ -50,11 +51,20 @@ useFocusGuards(); | ||
| React.useEffect(() => { | ||
| const edgeGuards = document.querySelectorAll("[data-radix-focus-guard]"); | ||
| document.body.insertAdjacentElement("afterbegin", edgeGuards[0] ?? createFocusGuard()); | ||
| document.body.insertAdjacentElement("beforeend", edgeGuards[1] ?? createFocusGuard()); | ||
| if (!guards) { | ||
| guards = { start: createFocusGuard(), end: createFocusGuard() }; | ||
| } | ||
| const { start, end } = guards; | ||
| if (document.body.firstElementChild !== start) { | ||
| document.body.insertAdjacentElement("afterbegin", start); | ||
| } | ||
| if (document.body.lastElementChild !== end) { | ||
| document.body.insertAdjacentElement("beforeend", end); | ||
| } | ||
| count++; | ||
| return () => { | ||
| if (count === 1) { | ||
| document.querySelectorAll("[data-radix-focus-guard]").forEach((node) => node.remove()); | ||
| guards?.start.remove(); | ||
| guards?.end.remove(); | ||
| guards = null; | ||
| } | ||
| count--; | ||
| count = Math.max(0, count - 1); | ||
| }; | ||
@@ -61,0 +71,0 @@ }, []); |
| { | ||
| "version": 3, | ||
| "sources": ["../src/index.ts", "../src/focus-guards.tsx"], | ||
| "sourcesContent": ["'use client';\nexport {\n FocusGuards,\n //\n Root,\n //\n useFocusGuards,\n} from './focus-guards';\n", "import * as React from 'react';\n\n/** Number of components which have requested interest to have focus guards */\nlet count = 0;\n\ninterface FocusGuardsProps {\n children?: React.ReactNode;\n}\n\nfunction FocusGuards(props: FocusGuardsProps) {\n useFocusGuards();\n return props.children;\n}\n\n/**\n * Injects a pair of focus guards at the edges of the whole DOM tree\n * to ensure `focusin` & `focusout` events can be caught consistently.\n */\nfunction useFocusGuards() {\n React.useEffect(() => {\n const edgeGuards = document.querySelectorAll('[data-radix-focus-guard]');\n document.body.insertAdjacentElement('afterbegin', edgeGuards[0] ?? createFocusGuard());\n document.body.insertAdjacentElement('beforeend', edgeGuards[1] ?? createFocusGuard());\n count++;\n\n return () => {\n if (count === 1) {\n document.querySelectorAll('[data-radix-focus-guard]').forEach((node) => node.remove());\n }\n count--;\n };\n }, []);\n}\n\nfunction createFocusGuard() {\n const element = document.createElement('span');\n element.setAttribute('data-radix-focus-guard', '');\n element.tabIndex = 0;\n element.style.outline = 'none';\n element.style.opacity = '0';\n element.style.position = 'fixed';\n element.style.pointerEvents = 'none';\n return element;\n}\n\nexport {\n FocusGuards,\n //\n FocusGuards as Root,\n //\n useFocusGuards,\n};\n"], | ||
| "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,YAAuB;AAGvB,IAAI,QAAQ;AAMZ,SAAS,YAAY,OAAyB;AAC5C,iBAAe;AACf,SAAO,MAAM;AACf;AAMA,SAAS,iBAAiB;AACxB,EAAM,gBAAU,MAAM;AACpB,UAAM,aAAa,SAAS,iBAAiB,0BAA0B;AACvE,aAAS,KAAK,sBAAsB,cAAc,WAAW,CAAC,KAAK,iBAAiB,CAAC;AACrF,aAAS,KAAK,sBAAsB,aAAa,WAAW,CAAC,KAAK,iBAAiB,CAAC;AACpF;AAEA,WAAO,MAAM;AACX,UAAI,UAAU,GAAG;AACf,iBAAS,iBAAiB,0BAA0B,EAAE,QAAQ,CAAC,SAAS,KAAK,OAAO,CAAC;AAAA,MACvF;AACA;AAAA,IACF;AAAA,EACF,GAAG,CAAC,CAAC;AACP;AAEA,SAAS,mBAAmB;AAC1B,QAAM,UAAU,SAAS,cAAc,MAAM;AAC7C,UAAQ,aAAa,0BAA0B,EAAE;AACjD,UAAQ,WAAW;AACnB,UAAQ,MAAM,UAAU;AACxB,UAAQ,MAAM,UAAU;AACxB,UAAQ,MAAM,WAAW;AACzB,UAAQ,MAAM,gBAAgB;AAC9B,SAAO;AACT;", | ||
| "sourcesContent": ["'use client';\nexport {\n FocusGuards,\n //\n Root,\n //\n useFocusGuards,\n} from './focus-guards';\n", "import * as React from 'react';\n\n/** Number of components which have requested interest to have focus guards */\nlet count = 0;\n\n/**\n * Cached references to the single shared pair of edge guards. Keeping these at\n * module scope lets us avoid scanning the whole document (`querySelectorAll`)\n * and re-inserting the guards on every overlay mount.\n */\nlet guards: { start: HTMLSpanElement; end: HTMLSpanElement } | null = null;\n\ninterface FocusGuardsProps {\n children?: React.ReactNode;\n}\n\nfunction FocusGuards(props: FocusGuardsProps) {\n useFocusGuards();\n return props.children;\n}\n\n/**\n * Injects a pair of focus guards at the edges of the whole DOM tree\n * to ensure `focusin` & `focusout` events can be caught consistently.\n */\nfunction useFocusGuards() {\n React.useEffect(() => {\n if (!guards) {\n guards = { start: createFocusGuard(), end: createFocusGuard() };\n }\n const { start, end } = guards;\n\n // Only mutate the DOM when the edge invariant is actually broken. Writing\n // to `document.body` dirties layout and forces a synchronous reflow once\n // sibling effects read layout (Popper measuring, react-remove-scroll,\n // aria-hidden, FocusScope), so skipping no-op moves avoids that cost on\n // every mount. The trailing guard still gets re-asserted to last whenever a\n // newly portaled node lands after it (portals append to the end of\n // `document.body`). See https://github.com/radix-ui/primitives/issues/2812\n if (document.body.firstElementChild !== start) {\n document.body.insertAdjacentElement('afterbegin', start);\n }\n if (document.body.lastElementChild !== end) {\n document.body.insertAdjacentElement('beforeend', end);\n }\n count++;\n\n return () => {\n if (count === 1) {\n guards?.start.remove();\n guards?.end.remove();\n guards = null;\n }\n count = Math.max(0, count - 1);\n };\n }, []);\n}\n\nfunction createFocusGuard() {\n const element = document.createElement('span');\n element.setAttribute('data-radix-focus-guard', '');\n element.tabIndex = 0;\n element.style.outline = 'none';\n element.style.opacity = '0';\n element.style.position = 'fixed';\n element.style.pointerEvents = 'none';\n return element;\n}\n\nexport {\n FocusGuards,\n //\n FocusGuards as Root,\n //\n useFocusGuards,\n};\n"], | ||
| "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,YAAuB;AAGvB,IAAI,QAAQ;AAOZ,IAAI,SAAkE;AAMtE,SAAS,YAAY,OAAyB;AAC5C,iBAAe;AACf,SAAO,MAAM;AACf;AAMA,SAAS,iBAAiB;AACxB,EAAM,gBAAU,MAAM;AACpB,QAAI,CAAC,QAAQ;AACX,eAAS,EAAE,OAAO,iBAAiB,GAAG,KAAK,iBAAiB,EAAE;AAAA,IAChE;AACA,UAAM,EAAE,OAAO,IAAI,IAAI;AASvB,QAAI,SAAS,KAAK,sBAAsB,OAAO;AAC7C,eAAS,KAAK,sBAAsB,cAAc,KAAK;AAAA,IACzD;AACA,QAAI,SAAS,KAAK,qBAAqB,KAAK;AAC1C,eAAS,KAAK,sBAAsB,aAAa,GAAG;AAAA,IACtD;AACA;AAEA,WAAO,MAAM;AACX,UAAI,UAAU,GAAG;AACf,gBAAQ,MAAM,OAAO;AACrB,gBAAQ,IAAI,OAAO;AACnB,iBAAS;AAAA,MACX;AACA,cAAQ,KAAK,IAAI,GAAG,QAAQ,CAAC;AAAA,IAC/B;AAAA,EACF,GAAG,CAAC,CAAC;AACP;AAEA,SAAS,mBAAmB;AAC1B,QAAM,UAAU,SAAS,cAAc,MAAM;AAC7C,UAAQ,aAAa,0BAA0B,EAAE;AACjD,UAAQ,WAAW;AACnB,UAAQ,MAAM,UAAU;AACxB,UAAQ,MAAM,UAAU;AACxB,UAAQ,MAAM,WAAW;AACzB,UAAQ,MAAM,gBAAgB;AAC9B,SAAO;AACT;", | ||
| "names": [] | ||
| } |
+15
-5
@@ -6,2 +6,3 @@ "use client"; | ||
| var count = 0; | ||
| var guards = null; | ||
| function FocusGuards(props) { | ||
@@ -13,11 +14,20 @@ useFocusGuards(); | ||
| React.useEffect(() => { | ||
| const edgeGuards = document.querySelectorAll("[data-radix-focus-guard]"); | ||
| document.body.insertAdjacentElement("afterbegin", edgeGuards[0] ?? createFocusGuard()); | ||
| document.body.insertAdjacentElement("beforeend", edgeGuards[1] ?? createFocusGuard()); | ||
| if (!guards) { | ||
| guards = { start: createFocusGuard(), end: createFocusGuard() }; | ||
| } | ||
| const { start, end } = guards; | ||
| if (document.body.firstElementChild !== start) { | ||
| document.body.insertAdjacentElement("afterbegin", start); | ||
| } | ||
| if (document.body.lastElementChild !== end) { | ||
| document.body.insertAdjacentElement("beforeend", end); | ||
| } | ||
| count++; | ||
| return () => { | ||
| if (count === 1) { | ||
| document.querySelectorAll("[data-radix-focus-guard]").forEach((node) => node.remove()); | ||
| guards?.start.remove(); | ||
| guards?.end.remove(); | ||
| guards = null; | ||
| } | ||
| count--; | ||
| count = Math.max(0, count - 1); | ||
| }; | ||
@@ -24,0 +34,0 @@ }, []); |
| { | ||
| "version": 3, | ||
| "sources": ["../src/focus-guards.tsx"], | ||
| "sourcesContent": ["import * as React from 'react';\n\n/** Number of components which have requested interest to have focus guards */\nlet count = 0;\n\ninterface FocusGuardsProps {\n children?: React.ReactNode;\n}\n\nfunction FocusGuards(props: FocusGuardsProps) {\n useFocusGuards();\n return props.children;\n}\n\n/**\n * Injects a pair of focus guards at the edges of the whole DOM tree\n * to ensure `focusin` & `focusout` events can be caught consistently.\n */\nfunction useFocusGuards() {\n React.useEffect(() => {\n const edgeGuards = document.querySelectorAll('[data-radix-focus-guard]');\n document.body.insertAdjacentElement('afterbegin', edgeGuards[0] ?? createFocusGuard());\n document.body.insertAdjacentElement('beforeend', edgeGuards[1] ?? createFocusGuard());\n count++;\n\n return () => {\n if (count === 1) {\n document.querySelectorAll('[data-radix-focus-guard]').forEach((node) => node.remove());\n }\n count--;\n };\n }, []);\n}\n\nfunction createFocusGuard() {\n const element = document.createElement('span');\n element.setAttribute('data-radix-focus-guard', '');\n element.tabIndex = 0;\n element.style.outline = 'none';\n element.style.opacity = '0';\n element.style.position = 'fixed';\n element.style.pointerEvents = 'none';\n return element;\n}\n\nexport {\n FocusGuards,\n //\n FocusGuards as Root,\n //\n useFocusGuards,\n};\n"], | ||
| "mappings": ";;;AAAA,YAAY,WAAW;AAGvB,IAAI,QAAQ;AAMZ,SAAS,YAAY,OAAyB;AAC5C,iBAAe;AACf,SAAO,MAAM;AACf;AAMA,SAAS,iBAAiB;AACxB,EAAM,gBAAU,MAAM;AACpB,UAAM,aAAa,SAAS,iBAAiB,0BAA0B;AACvE,aAAS,KAAK,sBAAsB,cAAc,WAAW,CAAC,KAAK,iBAAiB,CAAC;AACrF,aAAS,KAAK,sBAAsB,aAAa,WAAW,CAAC,KAAK,iBAAiB,CAAC;AACpF;AAEA,WAAO,MAAM;AACX,UAAI,UAAU,GAAG;AACf,iBAAS,iBAAiB,0BAA0B,EAAE,QAAQ,CAAC,SAAS,KAAK,OAAO,CAAC;AAAA,MACvF;AACA;AAAA,IACF;AAAA,EACF,GAAG,CAAC,CAAC;AACP;AAEA,SAAS,mBAAmB;AAC1B,QAAM,UAAU,SAAS,cAAc,MAAM;AAC7C,UAAQ,aAAa,0BAA0B,EAAE;AACjD,UAAQ,WAAW;AACnB,UAAQ,MAAM,UAAU;AACxB,UAAQ,MAAM,UAAU;AACxB,UAAQ,MAAM,WAAW;AACzB,UAAQ,MAAM,gBAAgB;AAC9B,SAAO;AACT;", | ||
| "sourcesContent": ["import * as React from 'react';\n\n/** Number of components which have requested interest to have focus guards */\nlet count = 0;\n\n/**\n * Cached references to the single shared pair of edge guards. Keeping these at\n * module scope lets us avoid scanning the whole document (`querySelectorAll`)\n * and re-inserting the guards on every overlay mount.\n */\nlet guards: { start: HTMLSpanElement; end: HTMLSpanElement } | null = null;\n\ninterface FocusGuardsProps {\n children?: React.ReactNode;\n}\n\nfunction FocusGuards(props: FocusGuardsProps) {\n useFocusGuards();\n return props.children;\n}\n\n/**\n * Injects a pair of focus guards at the edges of the whole DOM tree\n * to ensure `focusin` & `focusout` events can be caught consistently.\n */\nfunction useFocusGuards() {\n React.useEffect(() => {\n if (!guards) {\n guards = { start: createFocusGuard(), end: createFocusGuard() };\n }\n const { start, end } = guards;\n\n // Only mutate the DOM when the edge invariant is actually broken. Writing\n // to `document.body` dirties layout and forces a synchronous reflow once\n // sibling effects read layout (Popper measuring, react-remove-scroll,\n // aria-hidden, FocusScope), so skipping no-op moves avoids that cost on\n // every mount. The trailing guard still gets re-asserted to last whenever a\n // newly portaled node lands after it (portals append to the end of\n // `document.body`). See https://github.com/radix-ui/primitives/issues/2812\n if (document.body.firstElementChild !== start) {\n document.body.insertAdjacentElement('afterbegin', start);\n }\n if (document.body.lastElementChild !== end) {\n document.body.insertAdjacentElement('beforeend', end);\n }\n count++;\n\n return () => {\n if (count === 1) {\n guards?.start.remove();\n guards?.end.remove();\n guards = null;\n }\n count = Math.max(0, count - 1);\n };\n }, []);\n}\n\nfunction createFocusGuard() {\n const element = document.createElement('span');\n element.setAttribute('data-radix-focus-guard', '');\n element.tabIndex = 0;\n element.style.outline = 'none';\n element.style.opacity = '0';\n element.style.position = 'fixed';\n element.style.pointerEvents = 'none';\n return element;\n}\n\nexport {\n FocusGuards,\n //\n FocusGuards as Root,\n //\n useFocusGuards,\n};\n"], | ||
| "mappings": ";;;AAAA,YAAY,WAAW;AAGvB,IAAI,QAAQ;AAOZ,IAAI,SAAkE;AAMtE,SAAS,YAAY,OAAyB;AAC5C,iBAAe;AACf,SAAO,MAAM;AACf;AAMA,SAAS,iBAAiB;AACxB,EAAM,gBAAU,MAAM;AACpB,QAAI,CAAC,QAAQ;AACX,eAAS,EAAE,OAAO,iBAAiB,GAAG,KAAK,iBAAiB,EAAE;AAAA,IAChE;AACA,UAAM,EAAE,OAAO,IAAI,IAAI;AASvB,QAAI,SAAS,KAAK,sBAAsB,OAAO;AAC7C,eAAS,KAAK,sBAAsB,cAAc,KAAK;AAAA,IACzD;AACA,QAAI,SAAS,KAAK,qBAAqB,KAAK;AAC1C,eAAS,KAAK,sBAAsB,aAAa,GAAG;AAAA,IACtD;AACA;AAEA,WAAO,MAAM;AACX,UAAI,UAAU,GAAG;AACf,gBAAQ,MAAM,OAAO;AACrB,gBAAQ,IAAI,OAAO;AACnB,iBAAS;AAAA,MACX;AACA,cAAQ,KAAK,IAAI,GAAG,QAAQ,CAAC;AAAA,IAC/B;AAAA,EACF,GAAG,CAAC,CAAC;AACP;AAEA,SAAS,mBAAmB;AAC1B,QAAM,UAAU,SAAS,cAAc,MAAM;AAC7C,UAAQ,aAAa,0BAA0B,EAAE;AACjD,UAAQ,WAAW;AACnB,UAAQ,MAAM,UAAU;AACxB,UAAQ,MAAM,UAAU;AACxB,UAAQ,MAAM,WAAW;AACzB,UAAQ,MAAM,gBAAgB;AAC9B,SAAO;AACT;", | ||
| "names": [] | ||
| } |
+1
-1
| { | ||
| "name": "@radix-ui/react-focus-guards", | ||
| "version": "1.1.4-rc.1780677407053", | ||
| "version": "1.1.4", | ||
| "license": "MIT", | ||
@@ -5,0 +5,0 @@ "source": "./src/index.ts", |
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
14202
22%138
16.95%1
-50%