@radix-ui/react-focus-scope 0.1.5-rc.1 → 0.1.5-rc.12

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.
@@ -1 +1 @@
1
- {"mappings":"A;A;A;AAoBA,yBAAyB,MAAM,wBAAwB,CAAC,OAAO,UAAU,GAAG,CAAC,CAAC;AAC9E,gCAA0B,SAAQ,iBAAiB;IACjD;A;A;A;OAIG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IAEf;A;A;A;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;A;A;OAGG;IACH,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAE1C;A;A;OAGG;IACH,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAC7C;AAED,OAAA,MAAM,kGA+HJ,CAAC;AA2IH,OAAA,MAAM,4FAAiB,CAAC","sources":["./packages/react/focus-scope/src/packages/react/focus-scope/src/FocusScope.tsx","./packages/react/focus-scope/src/packages/react/focus-scope/src/index.ts"],"sourcesContent":[null,null],"names":[],"version":3,"file":"index.d.ts.map"}
1
+ {"mappings":";;;AAoBA,yBAAyB,MAAM,wBAAwB,CAAC,OAAO,UAAU,GAAG,CAAC,CAAC;AAC9E,gCAA0B,SAAQ,iBAAiB;IACjD;;;;OAIG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IAEf;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAE1C;;;OAGG;IACH,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAC7C;AAED,OAAA,MAAM,kGA+HJ,CAAC;AA2IH,OAAA,MAAM,4FAAiB,CAAC","sources":["packages/react/focus-scope/src/packages/react/focus-scope/src/FocusScope.tsx","packages/react/focus-scope/src/packages/react/focus-scope/src/index.ts","packages/react/focus-scope/src/index.ts"],"sourcesContent":[null,null,"export * from './FocusScope';\n"],"names":[],"version":3,"file":"index.d.ts.map"}
package/dist/index.js CHANGED
@@ -1,2 +1,293 @@
1
- var e,t,n,o=require("@radix-ui/react-use-callback-ref").useCallbackRef,u=require("@radix-ui/react-primitive").Primitive,r=require("@radix-ui/react-compose-refs").useComposedRefs,c=(e={},t=require("react"),Object.keys(t).forEach((function(n){"default"!==n&&"__esModule"!==n&&Object.defineProperty(e,n,{enumerable:!0,get:function(){return t[n]}})})),e),s=(n=require("@babel/runtime/helpers/extends"))&&n.__esModule?n.default:n;const i={bubbles:!1,cancelable:!0},a=/*#__PURE__*/c.forwardRef(((e,t)=>{const{loop:n=!1,trapped:a=!1,onMountAutoFocus:l,onUnmountAutoFocus:v,...E}=e,[b,F]=c.useState(null),y=o(l),S=o(v),T=c.useRef(null),h=r(t,(e=>F(e))),L=c.useRef({paused:!1,pause(){this.paused=!0},resume(){this.paused=!1}}).current;c.useEffect((()=>{if(a){function e(e){if(L.paused||!b)return;const t=e.target;b.contains(t)?T.current=t:m(T.current,{select:!0})}function t(e){!L.paused&&b&&(b.contains(e.relatedTarget)||m(T.current,{select:!0}))}return document.addEventListener("focusin",e),document.addEventListener("focusout",t),()=>{document.removeEventListener("focusin",e),document.removeEventListener("focusout",t)}}}),[a,b,L.paused]),c.useEffect((()=>{if(b){p.add(L);const t=document.activeElement;if(!b.contains(t)){const n=new Event("focusScope.autoFocusOnMount",i);b.addEventListener("focusScope.autoFocusOnMount",y),b.dispatchEvent(n),n.defaultPrevented||(!function(e,{select:t=!1}={}){const n=document.activeElement;for(const o of e)if(m(o,{select:t}),document.activeElement!==n)return}((e=d(b),e.filter((e=>"A"!==e.tagName))),{select:!0}),document.activeElement===t&&m(b))}return()=>{b.removeEventListener("focusScope.autoFocusOnMount",y),setTimeout((()=>{const e=new Event("focusScope.autoFocusOnUnmount",i);b.addEventListener("focusScope.autoFocusOnUnmount",S),b.dispatchEvent(e),e.defaultPrevented||m(null!=t?t:document.body,{select:!0}),b.removeEventListener("focusScope.autoFocusOnUnmount",S),p.remove(L)}),0)}}var e}),[b,y,S,L]);const N=c.useCallback((e=>{if(!n&&!a)return;if(L.paused)return;const t="Tab"===e.key&&!e.altKey&&!e.ctrlKey&&!e.metaKey,o=document.activeElement;if(t&&o){const t=e.currentTarget,[u,r]=function(e){const t=d(e),n=f(t,e),o=f(t.reverse(),e);return[n,o]}(t);u&&r?e.shiftKey||o!==r?e.shiftKey&&o===u&&(e.preventDefault(),n&&m(r,{select:!0})):(e.preventDefault(),n&&m(u,{select:!0})):o===t&&e.preventDefault()}}),[n,a,L.paused]);/*#__PURE__*/return c.createElement(u.div,s({tabIndex:-1},E,{ref:h,onKeyDown:N}))}));function d(e){const t=[],n=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT,{acceptNode:e=>{const t="INPUT"===e.tagName&&"hidden"===e.type;return e.disabled||e.hidden||t?NodeFilter.FILTER_SKIP:e.tabIndex>=0?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP}});for(;n.nextNode();)t.push(n.currentNode);return t}function f(e,t){for(const n of e)if(!l(n,{upTo:t}))return n}function l(e,{upTo:t}){if("hidden"===getComputedStyle(e).visibility)return!0;for(;e;){if(void 0!==t&&e===t)return!1;if("none"===getComputedStyle(e).display)return!0;e=e.parentElement}return!1}function m(e,{select:t=!1}={}){if(e&&e.focus){const n=document.activeElement;e.focus({preventScroll:!0}),e!==n&&function(e){return e instanceof HTMLInputElement&&"select"in e}(e)&&t&&e.select()}}exports.FocusScope=a;const p=function(){let e=[];return{add(t){const n=e[0];t!==n&&(null==n||n.pause()),e=v(e,t),e.unshift(t)},remove(t){var n;e=v(e,t),null===(n=e[0])||void 0===n||n.resume()}}}();function v(e,t){const n=[...e],o=n.indexOf(t);return-1!==o&&n.splice(o,1),n}const E=a;exports.Root=E;
1
+ var $buum9$babelruntimehelpersextends = require("@babel/runtime/helpers/extends");
2
+ var $buum9$react = require("react");
3
+ var $buum9$radixuireactcomposerefs = require("@radix-ui/react-compose-refs");
4
+ var $buum9$radixuireactprimitive = require("@radix-ui/react-primitive");
5
+ var $buum9$radixuireactusecallbackref = require("@radix-ui/react-use-callback-ref");
6
+
7
+ function $parcel$exportWildcard(dest, source) {
8
+ Object.keys(source).forEach(function(key) {
9
+ if (key === 'default' || key === '__esModule' || dest.hasOwnProperty(key)) {
10
+ return;
11
+ }
12
+
13
+ Object.defineProperty(dest, key, {
14
+ enumerable: true,
15
+ get: function get() {
16
+ return source[key];
17
+ }
18
+ });
19
+ });
20
+
21
+ return dest;
22
+ }
23
+ function $parcel$interopDefault(a) {
24
+ return a && a.__esModule ? a.default : a;
25
+ }
26
+ function $parcel$export(e, n, v, s) {
27
+ Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});
28
+ }
29
+ var $2bc01e66e04aa9ed$exports = {};
30
+
31
+ $parcel$export($2bc01e66e04aa9ed$exports, "FocusScope", () => $2bc01e66e04aa9ed$export$20e40289641fbbb6);
32
+ $parcel$export($2bc01e66e04aa9ed$exports, "Root", () => $2bc01e66e04aa9ed$export$be92b6f5f03c0fe9);
33
+
34
+
35
+
36
+
37
+
38
+ const $2bc01e66e04aa9ed$var$AUTOFOCUS_ON_MOUNT = 'focusScope.autoFocusOnMount';
39
+ const $2bc01e66e04aa9ed$var$AUTOFOCUS_ON_UNMOUNT = 'focusScope.autoFocusOnUnmount';
40
+ const $2bc01e66e04aa9ed$var$EVENT_OPTIONS = {
41
+ bubbles: false,
42
+ cancelable: true
43
+ };
44
+ /* -------------------------------------------------------------------------------------------------
45
+ * FocusScope
46
+ * -----------------------------------------------------------------------------------------------*/ const $2bc01e66e04aa9ed$var$FOCUS_SCOPE_NAME = 'FocusScope';
47
+ const $2bc01e66e04aa9ed$export$20e40289641fbbb6 = /*#__PURE__*/ $buum9$react.forwardRef((props, forwardedRef)=>{
48
+ const { loop: loop = false , trapped: trapped = false , onMountAutoFocus: onMountAutoFocusProp , onUnmountAutoFocus: onUnmountAutoFocusProp , ...scopeProps } = props;
49
+ const [container1, setContainer] = $buum9$react.useState(null);
50
+ const onMountAutoFocus = $buum9$radixuireactusecallbackref.useCallbackRef(onMountAutoFocusProp);
51
+ const onUnmountAutoFocus = $buum9$radixuireactusecallbackref.useCallbackRef(onUnmountAutoFocusProp);
52
+ const lastFocusedElementRef = $buum9$react.useRef(null);
53
+ const composedRefs = $buum9$radixuireactcomposerefs.useComposedRefs(forwardedRef, (node)=>setContainer(node)
54
+ );
55
+ const focusScope = $buum9$react.useRef({
56
+ paused: false,
57
+ pause () {
58
+ this.paused = true;
59
+ },
60
+ resume () {
61
+ this.paused = false;
62
+ }
63
+ }).current; // Takes care of trapping focus if focus is moved outside programmatically for example
64
+ $buum9$react.useEffect(()=>{
65
+ if (trapped) {
66
+ function handleFocusIn(event) {
67
+ if (focusScope.paused || !container1) return;
68
+ const target = event.target;
69
+ if (container1.contains(target)) lastFocusedElementRef.current = target;
70
+ else $2bc01e66e04aa9ed$var$focus(lastFocusedElementRef.current, {
71
+ select: true
72
+ });
73
+ }
74
+ function handleFocusOut(event) {
75
+ if (focusScope.paused || !container1) return;
76
+ if (!container1.contains(event.relatedTarget)) $2bc01e66e04aa9ed$var$focus(lastFocusedElementRef.current, {
77
+ select: true
78
+ });
79
+ }
80
+ document.addEventListener('focusin', handleFocusIn);
81
+ document.addEventListener('focusout', handleFocusOut);
82
+ return ()=>{
83
+ document.removeEventListener('focusin', handleFocusIn);
84
+ document.removeEventListener('focusout', handleFocusOut);
85
+ };
86
+ }
87
+ }, [
88
+ trapped,
89
+ container1,
90
+ focusScope.paused
91
+ ]);
92
+ $buum9$react.useEffect(()=>{
93
+ if (container1) {
94
+ $2bc01e66e04aa9ed$var$focusScopesStack.add(focusScope);
95
+ const previouslyFocusedElement = document.activeElement;
96
+ const hasFocusedCandidate = container1.contains(previouslyFocusedElement);
97
+ if (!hasFocusedCandidate) {
98
+ const mountEvent = new Event($2bc01e66e04aa9ed$var$AUTOFOCUS_ON_MOUNT, $2bc01e66e04aa9ed$var$EVENT_OPTIONS);
99
+ container1.addEventListener($2bc01e66e04aa9ed$var$AUTOFOCUS_ON_MOUNT, onMountAutoFocus);
100
+ container1.dispatchEvent(mountEvent);
101
+ if (!mountEvent.defaultPrevented) {
102
+ $2bc01e66e04aa9ed$var$focusFirst($2bc01e66e04aa9ed$var$removeLinks($2bc01e66e04aa9ed$var$getTabbableCandidates(container1)), {
103
+ select: true
104
+ });
105
+ if (document.activeElement === previouslyFocusedElement) $2bc01e66e04aa9ed$var$focus(container1);
106
+ }
107
+ }
108
+ return ()=>{
109
+ container1.removeEventListener($2bc01e66e04aa9ed$var$AUTOFOCUS_ON_MOUNT, onMountAutoFocus); // We hit a react bug (fixed in v17) with focusing in unmount.
110
+ // We need to delay the focus a little to get around it for now.
111
+ // See: https://github.com/facebook/react/issues/17894
112
+ setTimeout(()=>{
113
+ const unmountEvent = new Event($2bc01e66e04aa9ed$var$AUTOFOCUS_ON_UNMOUNT, $2bc01e66e04aa9ed$var$EVENT_OPTIONS);
114
+ container1.addEventListener($2bc01e66e04aa9ed$var$AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus);
115
+ container1.dispatchEvent(unmountEvent);
116
+ if (!unmountEvent.defaultPrevented) $2bc01e66e04aa9ed$var$focus(previouslyFocusedElement !== null && previouslyFocusedElement !== void 0 ? previouslyFocusedElement : document.body, {
117
+ select: true
118
+ });
119
+ // we need to remove the listener after we `dispatchEvent`
120
+ container1.removeEventListener($2bc01e66e04aa9ed$var$AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus);
121
+ $2bc01e66e04aa9ed$var$focusScopesStack.remove(focusScope);
122
+ }, 0);
123
+ };
124
+ }
125
+ }, [
126
+ container1,
127
+ onMountAutoFocus,
128
+ onUnmountAutoFocus,
129
+ focusScope
130
+ ]); // Takes care of looping focus (when tabbing whilst at the edges)
131
+ const handleKeyDown = $buum9$react.useCallback((event)=>{
132
+ if (!loop && !trapped) return;
133
+ if (focusScope.paused) return;
134
+ const isTabKey = event.key === 'Tab' && !event.altKey && !event.ctrlKey && !event.metaKey;
135
+ const focusedElement = document.activeElement;
136
+ if (isTabKey && focusedElement) {
137
+ const container = event.currentTarget;
138
+ const [first, last] = $2bc01e66e04aa9ed$var$getTabbableEdges(container);
139
+ const hasTabbableElementsInside = first && last; // we can only wrap focus if we have tabbable edges
140
+ if (!hasTabbableElementsInside) {
141
+ if (focusedElement === container) event.preventDefault();
142
+ } else {
143
+ if (!event.shiftKey && focusedElement === last) {
144
+ event.preventDefault();
145
+ if (loop) $2bc01e66e04aa9ed$var$focus(first, {
146
+ select: true
147
+ });
148
+ } else if (event.shiftKey && focusedElement === first) {
149
+ event.preventDefault();
150
+ if (loop) $2bc01e66e04aa9ed$var$focus(last, {
151
+ select: true
152
+ });
153
+ }
154
+ }
155
+ }
156
+ }, [
157
+ loop,
158
+ trapped,
159
+ focusScope.paused
160
+ ]);
161
+ return /*#__PURE__*/ $buum9$react.createElement($buum9$radixuireactprimitive.Primitive.div, ($parcel$interopDefault($buum9$babelruntimehelpersextends))({
162
+ tabIndex: -1
163
+ }, scopeProps, {
164
+ ref: composedRefs,
165
+ onKeyDown: handleKeyDown
166
+ }));
167
+ });
168
+ /*#__PURE__*/ Object.assign($2bc01e66e04aa9ed$export$20e40289641fbbb6, {
169
+ displayName: $2bc01e66e04aa9ed$var$FOCUS_SCOPE_NAME
170
+ });
171
+ /* -------------------------------------------------------------------------------------------------
172
+ * Utils
173
+ * -----------------------------------------------------------------------------------------------*/ /**
174
+ * Attempts focusing the first element in a list of candidates.
175
+ * Stops when focus has actually moved.
176
+ */ function $2bc01e66e04aa9ed$var$focusFirst(candidates, { select: select = false } = {}) {
177
+ const previouslyFocusedElement = document.activeElement;
178
+ for (const candidate of candidates){
179
+ $2bc01e66e04aa9ed$var$focus(candidate, {
180
+ select: select
181
+ });
182
+ if (document.activeElement !== previouslyFocusedElement) return;
183
+ }
184
+ }
185
+ /**
186
+ * Returns the first and last tabbable elements inside a container.
187
+ */ function $2bc01e66e04aa9ed$var$getTabbableEdges(container) {
188
+ const candidates = $2bc01e66e04aa9ed$var$getTabbableCandidates(container);
189
+ const first = $2bc01e66e04aa9ed$var$findVisible(candidates, container);
190
+ const last = $2bc01e66e04aa9ed$var$findVisible(candidates.reverse(), container);
191
+ return [
192
+ first,
193
+ last
194
+ ];
195
+ }
196
+ /**
197
+ * Returns a list of potential tabbable candidates.
198
+ *
199
+ * NOTE: This is only a close approximation. For example it doesn't take into account cases like when
200
+ * elements are not visible. This cannot be worked out easily by just reading a property, but rather
201
+ * necessitate runtime knowledge (computed styles, etc). We deal with these cases separately.
202
+ *
203
+ * See: https://developer.mozilla.org/en-US/docs/Web/API/TreeWalker
204
+ * Credit: https://github.com/discord/focus-layers/blob/master/src/util/wrapFocus.tsx#L1
205
+ */ function $2bc01e66e04aa9ed$var$getTabbableCandidates(container) {
206
+ const nodes = [];
207
+ const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {
208
+ acceptNode: (node)=>{
209
+ const isHiddenInput = node.tagName === 'INPUT' && node.type === 'hidden';
210
+ if (node.disabled || node.hidden || isHiddenInput) return NodeFilter.FILTER_SKIP; // `.tabIndex` is not the same as the `tabindex` attribute. It works on the
211
+ // runtime's understanding of tabbability, so this automatically accounts
212
+ // for any kind of element that could be tabbed to.
213
+ return node.tabIndex >= 0 ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
214
+ }
215
+ });
216
+ while(walker.nextNode())nodes.push(walker.currentNode); // we do not take into account the order of nodes with positive `tabIndex` as it
217
+ // hinders accessibility to have tab order different from visual order.
218
+ return nodes;
219
+ }
220
+ /**
221
+ * Returns the first visible element in a list.
222
+ * NOTE: Only checks visibility up to the `container`.
223
+ */ function $2bc01e66e04aa9ed$var$findVisible(elements, container) {
224
+ for (const element of elements){
225
+ // we stop checking if it's hidden at the `container` level (excluding)
226
+ if (!$2bc01e66e04aa9ed$var$isHidden(element, {
227
+ upTo: container
228
+ })) return element;
229
+ }
230
+ }
231
+ function $2bc01e66e04aa9ed$var$isHidden(node, { upTo: upTo }) {
232
+ if (getComputedStyle(node).visibility === 'hidden') return true;
233
+ while(node){
234
+ // we stop at `upTo` (excluding it)
235
+ if (upTo !== undefined && node === upTo) return false;
236
+ if (getComputedStyle(node).display === 'none') return true;
237
+ node = node.parentElement;
238
+ }
239
+ return false;
240
+ }
241
+ function $2bc01e66e04aa9ed$var$isSelectableInput(element) {
242
+ return element instanceof HTMLInputElement && 'select' in element;
243
+ }
244
+ function $2bc01e66e04aa9ed$var$focus(element, { select: select = false } = {}) {
245
+ // only focus if that element is focusable
246
+ if (element && element.focus) {
247
+ const previouslyFocusedElement = document.activeElement; // NOTE: we prevent scrolling on focus, to minimize jarring transitions for users
248
+ element.focus({
249
+ preventScroll: true
250
+ }); // only select if its not the same element, it supports selection and we need to select
251
+ if (element !== previouslyFocusedElement && $2bc01e66e04aa9ed$var$isSelectableInput(element) && select) element.select();
252
+ }
253
+ }
254
+ /* -------------------------------------------------------------------------------------------------
255
+ * FocusScope stack
256
+ * -----------------------------------------------------------------------------------------------*/ const $2bc01e66e04aa9ed$var$focusScopesStack = $2bc01e66e04aa9ed$var$createFocusScopesStack();
257
+ function $2bc01e66e04aa9ed$var$createFocusScopesStack() {
258
+ /** A stack of focus scopes, with the active one at the top */ let stack = [];
259
+ return {
260
+ add (focusScope) {
261
+ // pause the currently active focus scope (at the top of the stack)
262
+ const activeFocusScope = stack[0];
263
+ if (focusScope !== activeFocusScope) activeFocusScope === null || activeFocusScope === void 0 || activeFocusScope.pause();
264
+ // remove in case it already exists (because we'll re-add it at the top of the stack)
265
+ stack = $2bc01e66e04aa9ed$var$arrayRemove(stack, focusScope);
266
+ stack.unshift(focusScope);
267
+ },
268
+ remove (focusScope) {
269
+ var _stack$;
270
+ stack = $2bc01e66e04aa9ed$var$arrayRemove(stack, focusScope);
271
+ (_stack$ = stack[0]) === null || _stack$ === void 0 || _stack$.resume();
272
+ }
273
+ };
274
+ }
275
+ function $2bc01e66e04aa9ed$var$arrayRemove(array, item) {
276
+ const updatedArray = [
277
+ ...array
278
+ ];
279
+ const index = updatedArray.indexOf(item);
280
+ if (index !== -1) updatedArray.splice(index, 1);
281
+ return updatedArray;
282
+ }
283
+ function $2bc01e66e04aa9ed$var$removeLinks(items) {
284
+ return items.filter((item)=>item.tagName !== 'A'
285
+ );
286
+ }
287
+ const $2bc01e66e04aa9ed$export$be92b6f5f03c0fe9 = $2bc01e66e04aa9ed$export$20e40289641fbbb6;
288
+
289
+
290
+ $parcel$exportWildcard(module.exports, $2bc01e66e04aa9ed$exports);
291
+
292
+
2
293
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"mappings":"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","sources":["./node_modules/@parcel/scope-hoisting/lib/helpers.js","./packages/react/focus-scope/src/FocusScope.tsx"],"sourcesContent":["function $parcel$interopDefault(a) {\n return a && a.__esModule ? a.default : a;\n}\n\nfunction $parcel$defineInteropFlag(a) {\n Object.defineProperty(a, '__esModule', {value: true});\n}\n\nfunction $parcel$reexport(e, n, v) {\n Object.defineProperty(e, n, {get: v, enumerable: true});\n}\n\nfunction $parcel$exportWildcard(dest, source) {\n Object.keys(source).forEach(function(key) {\n if (key === 'default' || key === '__esModule') {\n return;\n }\n\n Object.defineProperty(dest, key, {\n enumerable: true,\n get: function get() {\n return source[key];\n },\n });\n });\n\n return dest;\n}\n\nfunction $parcel$missingModule(name) {\n var err = new Error(\"Cannot find module '\" + name + \"'\");\n err.code = 'MODULE_NOT_FOUND';\n throw err;\n}\n\nvar $parcel$global =\n typeof globalThis !== 'undefined'\n ? globalThis\n : typeof self !== 'undefined'\n ? self\n : typeof window !== 'undefined'\n ? window\n : typeof global !== 'undefined'\n ? global\n : {};\n","import * as React from 'react';\nimport { useComposedRefs } from '@radix-ui/react-compose-refs';\nimport { Primitive } from '@radix-ui/react-primitive';\nimport { useCallbackRef } from '@radix-ui/react-use-callback-ref';\n\nimport type * as Radix from '@radix-ui/react-primitive';\n\nconst AUTOFOCUS_ON_MOUNT = 'focusScope.autoFocusOnMount';\nconst AUTOFOCUS_ON_UNMOUNT = 'focusScope.autoFocusOnUnmount';\nconst EVENT_OPTIONS = { bubbles: false, cancelable: true };\n\ntype FocusableTarget = HTMLElement | { focus(): void };\n\n/* -------------------------------------------------------------------------------------------------\n * FocusScope\n * -----------------------------------------------------------------------------------------------*/\n\nconst FOCUS_SCOPE_NAME = 'FocusScope';\n\ntype FocusScopeElement = React.ElementRef<typeof Primitive.div>;\ntype PrimitiveDivProps = Radix.ComponentPropsWithoutRef<typeof Primitive.div>;\ninterface FocusScopeProps extends PrimitiveDivProps {\n /**\n * When `true`, tabbing from last item will focus first tabbable\n * and shift+tab from first item will focus last tababble.\n * @defaultValue false\n */\n loop?: boolean;\n\n /**\n * When `true`, focus cannot escape the focus scope via keyboard,\n * pointer, or a programmatic focus.\n * @defaultValue false\n */\n trapped?: boolean;\n\n /**\n * Event handler called when auto-focusing on mount.\n * Can be prevented.\n */\n onMountAutoFocus?: (event: Event) => void;\n\n /**\n * Event handler called when auto-focusing on unmount.\n * Can be prevented.\n */\n onUnmountAutoFocus?: (event: Event) => void;\n}\n\nconst FocusScope = React.forwardRef<FocusScopeElement, FocusScopeProps>((props, forwardedRef) => {\n const {\n loop = false,\n trapped = false,\n onMountAutoFocus: onMountAutoFocusProp,\n onUnmountAutoFocus: onUnmountAutoFocusProp,\n ...scopeProps\n } = props;\n const [container, setContainer] = React.useState<HTMLElement | null>(null);\n const onMountAutoFocus = useCallbackRef(onMountAutoFocusProp);\n const onUnmountAutoFocus = useCallbackRef(onUnmountAutoFocusProp);\n const lastFocusedElementRef = React.useRef<HTMLElement | null>(null);\n const composedRefs = useComposedRefs(forwardedRef, (node) => setContainer(node));\n\n const focusScope = React.useRef({\n paused: false,\n pause() {\n this.paused = true;\n },\n resume() {\n this.paused = false;\n },\n }).current;\n\n // Takes care of trapping focus if focus is moved outside programmatically for example\n React.useEffect(() => {\n if (trapped) {\n function handleFocusIn(event: FocusEvent) {\n if (focusScope.paused || !container) return;\n const target = event.target as HTMLElement | null;\n if (container.contains(target)) {\n lastFocusedElementRef.current = target;\n } else {\n focus(lastFocusedElementRef.current, { select: true });\n }\n }\n\n function handleFocusOut(event: FocusEvent) {\n if (focusScope.paused || !container) return;\n if (!container.contains(event.relatedTarget as HTMLElement | null)) {\n focus(lastFocusedElementRef.current, { select: true });\n }\n }\n\n document.addEventListener('focusin', handleFocusIn);\n document.addEventListener('focusout', handleFocusOut);\n return () => {\n document.removeEventListener('focusin', handleFocusIn);\n document.removeEventListener('focusout', handleFocusOut);\n };\n }\n }, [trapped, container, focusScope.paused]);\n\n React.useEffect(() => {\n if (container) {\n focusScopesStack.add(focusScope);\n const previouslyFocusedElement = document.activeElement as HTMLElement | null;\n const hasFocusedCandidate = container.contains(previouslyFocusedElement);\n\n if (!hasFocusedCandidate) {\n const mountEvent = new Event(AUTOFOCUS_ON_MOUNT, EVENT_OPTIONS);\n container.addEventListener(AUTOFOCUS_ON_MOUNT, onMountAutoFocus);\n container.dispatchEvent(mountEvent);\n if (!mountEvent.defaultPrevented) {\n focusFirst(removeLinks(getTabbableCandidates(container)), { select: true });\n if (document.activeElement === previouslyFocusedElement) {\n focus(container);\n }\n }\n }\n\n return () => {\n container.removeEventListener(AUTOFOCUS_ON_MOUNT, onMountAutoFocus);\n\n // We hit a react bug (fixed in v17) with focusing in unmount.\n // We need to delay the focus a little to get around it for now.\n // See: https://github.com/facebook/react/issues/17894\n setTimeout(() => {\n const unmountEvent = new Event(AUTOFOCUS_ON_UNMOUNT, EVENT_OPTIONS);\n container.addEventListener(AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus);\n container.dispatchEvent(unmountEvent);\n if (!unmountEvent.defaultPrevented) {\n focus(previouslyFocusedElement ?? document.body, { select: true });\n }\n // we need to remove the listener after we `dispatchEvent`\n container.removeEventListener(AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus);\n\n focusScopesStack.remove(focusScope);\n }, 0);\n };\n }\n }, [container, onMountAutoFocus, onUnmountAutoFocus, focusScope]);\n\n // Takes care of looping focus (when tabbing whilst at the edges)\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent) => {\n if (!loop && !trapped) return;\n if (focusScope.paused) return;\n\n const isTabKey = event.key === 'Tab' && !event.altKey && !event.ctrlKey && !event.metaKey;\n const focusedElement = document.activeElement as HTMLElement | null;\n\n if (isTabKey && focusedElement) {\n const container = event.currentTarget as HTMLElement;\n const [first, last] = getTabbableEdges(container);\n const hasTabbableElementsInside = first && last;\n\n // we can only wrap focus if we have tabbable edges\n if (!hasTabbableElementsInside) {\n if (focusedElement === container) event.preventDefault();\n } else {\n if (!event.shiftKey && focusedElement === last) {\n event.preventDefault();\n if (loop) focus(first, { select: true });\n } else if (event.shiftKey && focusedElement === first) {\n event.preventDefault();\n if (loop) focus(last, { select: true });\n }\n }\n }\n },\n [loop, trapped, focusScope.paused]\n );\n\n return (\n <Primitive.div tabIndex={-1} {...scopeProps} ref={composedRefs} onKeyDown={handleKeyDown} />\n );\n});\n\nFocusScope.displayName = FOCUS_SCOPE_NAME;\n\n/* -------------------------------------------------------------------------------------------------\n * Utils\n * -----------------------------------------------------------------------------------------------*/\n\n/**\n * Attempts focusing the first element in a list of candidates.\n * Stops when focus has actually moved.\n */\nfunction focusFirst(candidates: HTMLElement[], { select = false } = {}) {\n const previouslyFocusedElement = document.activeElement;\n for (const candidate of candidates) {\n focus(candidate, { select });\n if (document.activeElement !== previouslyFocusedElement) return;\n }\n}\n\n/**\n * Returns the first and last tabbable elements inside a container.\n */\nfunction getTabbableEdges(container: HTMLElement) {\n const candidates = getTabbableCandidates(container);\n const first = findVisible(candidates, container);\n const last = findVisible(candidates.reverse(), container);\n return [first, last] as const;\n}\n\n/**\n * Returns a list of potential tabbable candidates.\n *\n * NOTE: This is only a close approximation. For example it doesn't take into account cases like when\n * elements are not visible. This cannot be worked out easily by just reading a property, but rather\n * necessitate runtime knowledge (computed styles, etc). We deal with these cases separately.\n *\n * See: https://developer.mozilla.org/en-US/docs/Web/API/TreeWalker\n * Credit: https://github.com/discord/focus-layers/blob/master/src/util/wrapFocus.tsx#L1\n */\nfunction getTabbableCandidates(container: HTMLElement) {\n const nodes: HTMLElement[] = [];\n const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {\n acceptNode: (node: any) => {\n const isHiddenInput = node.tagName === 'INPUT' && node.type === 'hidden';\n if (node.disabled || node.hidden || isHiddenInput) return NodeFilter.FILTER_SKIP;\n // `.tabIndex` is not the same as the `tabindex` attribute. It works on the\n // runtime's understanding of tabbability, so this automatically accounts\n // for any kind of element that could be tabbed to.\n return node.tabIndex >= 0 ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;\n },\n });\n while (walker.nextNode()) nodes.push(walker.currentNode as HTMLElement);\n // we do not take into account the order of nodes with positive `tabIndex` as it\n // hinders accessibility to have tab order different from visual order.\n return nodes;\n}\n\n/**\n * Returns the first visible element in a list.\n * NOTE: Only checks visibility up to the `container`.\n */\nfunction findVisible(elements: HTMLElement[], container: HTMLElement) {\n for (const element of elements) {\n // we stop checking if it's hidden at the `container` level (excluding)\n if (!isHidden(element, { upTo: container })) return element;\n }\n}\n\nfunction isHidden(node: HTMLElement, { upTo }: { upTo?: HTMLElement }) {\n if (getComputedStyle(node).visibility === 'hidden') return true;\n while (node) {\n // we stop at `upTo` (excluding it)\n if (upTo !== undefined && node === upTo) return false;\n if (getComputedStyle(node).display === 'none') return true;\n node = node.parentElement as HTMLElement;\n }\n return false;\n}\n\nfunction isSelectableInput(element: any): element is FocusableTarget & { select: () => void } {\n return element instanceof HTMLInputElement && 'select' in element;\n}\n\nfunction focus(element?: FocusableTarget | null, { select = false } = {}) {\n // only focus if that element is focusable\n if (element && element.focus) {\n const previouslyFocusedElement = document.activeElement;\n // NOTE: we prevent scrolling on focus, to minimize jarring transitions for users\n element.focus({ preventScroll: true });\n // only select if its not the same element, it supports selection and we need to select\n if (element !== previouslyFocusedElement && isSelectableInput(element) && select)\n element.select();\n }\n}\n\n/* -------------------------------------------------------------------------------------------------\n * FocusScope stack\n * -----------------------------------------------------------------------------------------------*/\n\ntype FocusScopeAPI = { paused: boolean; pause(): void; resume(): void };\nconst focusScopesStack = createFocusScopesStack();\n\nfunction createFocusScopesStack() {\n /** A stack of focus scopes, with the active one at the top */\n let stack: FocusScopeAPI[] = [];\n\n return {\n add(focusScope: FocusScopeAPI) {\n // pause the currently active focus scope (at the top of the stack)\n const activeFocusScope = stack[0];\n if (focusScope !== activeFocusScope) {\n activeFocusScope?.pause();\n }\n // remove in case it already exists (because we'll re-add it at the top of the stack)\n stack = arrayRemove(stack, focusScope);\n stack.unshift(focusScope);\n },\n\n remove(focusScope: FocusScopeAPI) {\n stack = arrayRemove(stack, focusScope);\n stack[0]?.resume();\n },\n };\n}\n\nfunction arrayRemove<T>(array: T[], item: T) {\n const updatedArray = [...array];\n const index = updatedArray.indexOf(item);\n if (index !== -1) {\n updatedArray.splice(index, 1);\n }\n return updatedArray;\n}\n\nfunction removeLinks(items: HTMLElement[]) {\n return items.filter((item) => item.tagName !== 'A');\n}\n\nconst Root = FocusScope;\n\nexport {\n FocusScope,\n //\n Root,\n};\nexport type { FocusScopeProps };\n"],"names":["dest","source","a","Object","keys","forEach","key","defineProperty","enumerable","get","__esModule","default","EVENT_OPTIONS","bubbles","cancelable","FocusScope","React","forwardRef","props","forwardedRef","loop","trapped","onMountAutoFocus","onMountAutoFocusProp","onUnmountAutoFocus","onUnmountAutoFocusProp","scopeProps","container","setContainer","useState","useCallbackRef","lastFocusedElementRef","useRef","composedRefs","useComposedRefs","node","focusScope","paused","pause","this","resume","current","useEffect","handleFocusIn","event","target","contains","focus","select","handleFocusOut","relatedTarget","document","addEventListener","removeEventListener","focusScopesStack","add","previouslyFocusedElement","activeElement","mountEvent","Event","dispatchEvent","defaultPrevented","candidates","candidate","focusFirst","items","getTabbableCandidates","filter","item","tagName","setTimeout","unmountEvent","body","remove","handleKeyDown","useCallback","isTabKey","altKey","ctrlKey","metaKey","focusedElement","currentTarget","first","last","findVisible","reverse","getTabbableEdges","shiftKey","preventDefault","_react","createElement","Primitive","div","_babelRuntimeHelpersExtends","tabIndex","ref","onKeyDown","nodes","walker","createTreeWalker","NodeFilter","SHOW_ELEMENT","acceptNode","isHiddenInput","type","disabled","hidden","FILTER_SKIP","FILTER_ACCEPT","nextNode","push","currentNode","elements","element","isHidden","upTo","getComputedStyle","visibility","undefined","display","parentElement","preventScroll","HTMLInputElement","isSelectableInput","stack","activeFocusScope","arrayRemove","unshift","_stack$","createFocusScopesStack","array","updatedArray","index","indexOf","splice","Root"],"version":3,"file":"index.js.map"}
1
+ {"mappings":"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","sources":["packages/react/focus-scope/src/index.ts","packages/react/focus-scope/src/FocusScope.tsx"],"sourcesContent":["export * from './FocusScope';\n","import * as React from 'react';\nimport { useComposedRefs } from '@radix-ui/react-compose-refs';\nimport { Primitive } from '@radix-ui/react-primitive';\nimport { useCallbackRef } from '@radix-ui/react-use-callback-ref';\n\nimport type * as Radix from '@radix-ui/react-primitive';\n\nconst AUTOFOCUS_ON_MOUNT = 'focusScope.autoFocusOnMount';\nconst AUTOFOCUS_ON_UNMOUNT = 'focusScope.autoFocusOnUnmount';\nconst EVENT_OPTIONS = { bubbles: false, cancelable: true };\n\ntype FocusableTarget = HTMLElement | { focus(): void };\n\n/* -------------------------------------------------------------------------------------------------\n * FocusScope\n * -----------------------------------------------------------------------------------------------*/\n\nconst FOCUS_SCOPE_NAME = 'FocusScope';\n\ntype FocusScopeElement = React.ElementRef<typeof Primitive.div>;\ntype PrimitiveDivProps = Radix.ComponentPropsWithoutRef<typeof Primitive.div>;\ninterface FocusScopeProps extends PrimitiveDivProps {\n /**\n * When `true`, tabbing from last item will focus first tabbable\n * and shift+tab from first item will focus last tababble.\n * @defaultValue false\n */\n loop?: boolean;\n\n /**\n * When `true`, focus cannot escape the focus scope via keyboard,\n * pointer, or a programmatic focus.\n * @defaultValue false\n */\n trapped?: boolean;\n\n /**\n * Event handler called when auto-focusing on mount.\n * Can be prevented.\n */\n onMountAutoFocus?: (event: Event) => void;\n\n /**\n * Event handler called when auto-focusing on unmount.\n * Can be prevented.\n */\n onUnmountAutoFocus?: (event: Event) => void;\n}\n\nconst FocusScope = React.forwardRef<FocusScopeElement, FocusScopeProps>((props, forwardedRef) => {\n const {\n loop = false,\n trapped = false,\n onMountAutoFocus: onMountAutoFocusProp,\n onUnmountAutoFocus: onUnmountAutoFocusProp,\n ...scopeProps\n } = props;\n const [container, setContainer] = React.useState<HTMLElement | null>(null);\n const onMountAutoFocus = useCallbackRef(onMountAutoFocusProp);\n const onUnmountAutoFocus = useCallbackRef(onUnmountAutoFocusProp);\n const lastFocusedElementRef = React.useRef<HTMLElement | null>(null);\n const composedRefs = useComposedRefs(forwardedRef, (node) => setContainer(node));\n\n const focusScope = React.useRef({\n paused: false,\n pause() {\n this.paused = true;\n },\n resume() {\n this.paused = false;\n },\n }).current;\n\n // Takes care of trapping focus if focus is moved outside programmatically for example\n React.useEffect(() => {\n if (trapped) {\n function handleFocusIn(event: FocusEvent) {\n if (focusScope.paused || !container) return;\n const target = event.target as HTMLElement | null;\n if (container.contains(target)) {\n lastFocusedElementRef.current = target;\n } else {\n focus(lastFocusedElementRef.current, { select: true });\n }\n }\n\n function handleFocusOut(event: FocusEvent) {\n if (focusScope.paused || !container) return;\n if (!container.contains(event.relatedTarget as HTMLElement | null)) {\n focus(lastFocusedElementRef.current, { select: true });\n }\n }\n\n document.addEventListener('focusin', handleFocusIn);\n document.addEventListener('focusout', handleFocusOut);\n return () => {\n document.removeEventListener('focusin', handleFocusIn);\n document.removeEventListener('focusout', handleFocusOut);\n };\n }\n }, [trapped, container, focusScope.paused]);\n\n React.useEffect(() => {\n if (container) {\n focusScopesStack.add(focusScope);\n const previouslyFocusedElement = document.activeElement as HTMLElement | null;\n const hasFocusedCandidate = container.contains(previouslyFocusedElement);\n\n if (!hasFocusedCandidate) {\n const mountEvent = new Event(AUTOFOCUS_ON_MOUNT, EVENT_OPTIONS);\n container.addEventListener(AUTOFOCUS_ON_MOUNT, onMountAutoFocus);\n container.dispatchEvent(mountEvent);\n if (!mountEvent.defaultPrevented) {\n focusFirst(removeLinks(getTabbableCandidates(container)), { select: true });\n if (document.activeElement === previouslyFocusedElement) {\n focus(container);\n }\n }\n }\n\n return () => {\n container.removeEventListener(AUTOFOCUS_ON_MOUNT, onMountAutoFocus);\n\n // We hit a react bug (fixed in v17) with focusing in unmount.\n // We need to delay the focus a little to get around it for now.\n // See: https://github.com/facebook/react/issues/17894\n setTimeout(() => {\n const unmountEvent = new Event(AUTOFOCUS_ON_UNMOUNT, EVENT_OPTIONS);\n container.addEventListener(AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus);\n container.dispatchEvent(unmountEvent);\n if (!unmountEvent.defaultPrevented) {\n focus(previouslyFocusedElement ?? document.body, { select: true });\n }\n // we need to remove the listener after we `dispatchEvent`\n container.removeEventListener(AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus);\n\n focusScopesStack.remove(focusScope);\n }, 0);\n };\n }\n }, [container, onMountAutoFocus, onUnmountAutoFocus, focusScope]);\n\n // Takes care of looping focus (when tabbing whilst at the edges)\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent) => {\n if (!loop && !trapped) return;\n if (focusScope.paused) return;\n\n const isTabKey = event.key === 'Tab' && !event.altKey && !event.ctrlKey && !event.metaKey;\n const focusedElement = document.activeElement as HTMLElement | null;\n\n if (isTabKey && focusedElement) {\n const container = event.currentTarget as HTMLElement;\n const [first, last] = getTabbableEdges(container);\n const hasTabbableElementsInside = first && last;\n\n // we can only wrap focus if we have tabbable edges\n if (!hasTabbableElementsInside) {\n if (focusedElement === container) event.preventDefault();\n } else {\n if (!event.shiftKey && focusedElement === last) {\n event.preventDefault();\n if (loop) focus(first, { select: true });\n } else if (event.shiftKey && focusedElement === first) {\n event.preventDefault();\n if (loop) focus(last, { select: true });\n }\n }\n }\n },\n [loop, trapped, focusScope.paused]\n );\n\n return (\n <Primitive.div tabIndex={-1} {...scopeProps} ref={composedRefs} onKeyDown={handleKeyDown} />\n );\n});\n\nFocusScope.displayName = FOCUS_SCOPE_NAME;\n\n/* -------------------------------------------------------------------------------------------------\n * Utils\n * -----------------------------------------------------------------------------------------------*/\n\n/**\n * Attempts focusing the first element in a list of candidates.\n * Stops when focus has actually moved.\n */\nfunction focusFirst(candidates: HTMLElement[], { select = false } = {}) {\n const previouslyFocusedElement = document.activeElement;\n for (const candidate of candidates) {\n focus(candidate, { select });\n if (document.activeElement !== previouslyFocusedElement) return;\n }\n}\n\n/**\n * Returns the first and last tabbable elements inside a container.\n */\nfunction getTabbableEdges(container: HTMLElement) {\n const candidates = getTabbableCandidates(container);\n const first = findVisible(candidates, container);\n const last = findVisible(candidates.reverse(), container);\n return [first, last] as const;\n}\n\n/**\n * Returns a list of potential tabbable candidates.\n *\n * NOTE: This is only a close approximation. For example it doesn't take into account cases like when\n * elements are not visible. This cannot be worked out easily by just reading a property, but rather\n * necessitate runtime knowledge (computed styles, etc). We deal with these cases separately.\n *\n * See: https://developer.mozilla.org/en-US/docs/Web/API/TreeWalker\n * Credit: https://github.com/discord/focus-layers/blob/master/src/util/wrapFocus.tsx#L1\n */\nfunction getTabbableCandidates(container: HTMLElement) {\n const nodes: HTMLElement[] = [];\n const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {\n acceptNode: (node: any) => {\n const isHiddenInput = node.tagName === 'INPUT' && node.type === 'hidden';\n if (node.disabled || node.hidden || isHiddenInput) return NodeFilter.FILTER_SKIP;\n // `.tabIndex` is not the same as the `tabindex` attribute. It works on the\n // runtime's understanding of tabbability, so this automatically accounts\n // for any kind of element that could be tabbed to.\n return node.tabIndex >= 0 ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;\n },\n });\n while (walker.nextNode()) nodes.push(walker.currentNode as HTMLElement);\n // we do not take into account the order of nodes with positive `tabIndex` as it\n // hinders accessibility to have tab order different from visual order.\n return nodes;\n}\n\n/**\n * Returns the first visible element in a list.\n * NOTE: Only checks visibility up to the `container`.\n */\nfunction findVisible(elements: HTMLElement[], container: HTMLElement) {\n for (const element of elements) {\n // we stop checking if it's hidden at the `container` level (excluding)\n if (!isHidden(element, { upTo: container })) return element;\n }\n}\n\nfunction isHidden(node: HTMLElement, { upTo }: { upTo?: HTMLElement }) {\n if (getComputedStyle(node).visibility === 'hidden') return true;\n while (node) {\n // we stop at `upTo` (excluding it)\n if (upTo !== undefined && node === upTo) return false;\n if (getComputedStyle(node).display === 'none') return true;\n node = node.parentElement as HTMLElement;\n }\n return false;\n}\n\nfunction isSelectableInput(element: any): element is FocusableTarget & { select: () => void } {\n return element instanceof HTMLInputElement && 'select' in element;\n}\n\nfunction focus(element?: FocusableTarget | null, { select = false } = {}) {\n // only focus if that element is focusable\n if (element && element.focus) {\n const previouslyFocusedElement = document.activeElement;\n // NOTE: we prevent scrolling on focus, to minimize jarring transitions for users\n element.focus({ preventScroll: true });\n // only select if its not the same element, it supports selection and we need to select\n if (element !== previouslyFocusedElement && isSelectableInput(element) && select)\n element.select();\n }\n}\n\n/* -------------------------------------------------------------------------------------------------\n * FocusScope stack\n * -----------------------------------------------------------------------------------------------*/\n\ntype FocusScopeAPI = { paused: boolean; pause(): void; resume(): void };\nconst focusScopesStack = createFocusScopesStack();\n\nfunction createFocusScopesStack() {\n /** A stack of focus scopes, with the active one at the top */\n let stack: FocusScopeAPI[] = [];\n\n return {\n add(focusScope: FocusScopeAPI) {\n // pause the currently active focus scope (at the top of the stack)\n const activeFocusScope = stack[0];\n if (focusScope !== activeFocusScope) {\n activeFocusScope?.pause();\n }\n // remove in case it already exists (because we'll re-add it at the top of the stack)\n stack = arrayRemove(stack, focusScope);\n stack.unshift(focusScope);\n },\n\n remove(focusScope: FocusScopeAPI) {\n stack = arrayRemove(stack, focusScope);\n stack[0]?.resume();\n },\n };\n}\n\nfunction arrayRemove<T>(array: T[], item: T) {\n const updatedArray = [...array];\n const index = updatedArray.indexOf(item);\n if (index !== -1) {\n updatedArray.splice(index, 1);\n }\n return updatedArray;\n}\n\nfunction removeLinks(items: HTMLElement[]) {\n return items.filter((item) => item.tagName !== 'A');\n}\n\nconst Root = FocusScope;\n\nexport {\n FocusScope,\n //\n Root,\n};\nexport type { FocusScopeProps };\n"],"names":["React","useComposedRefs","Primitive","useCallbackRef","AUTOFOCUS_ON_MOUNT","AUTOFOCUS_ON_UNMOUNT","EVENT_OPTIONS","bubbles","cancelable","FOCUS_SCOPE_NAME","FocusScope","forwardRef","props","forwardedRef","loop","trapped","onMountAutoFocus","onMountAutoFocusProp","onUnmountAutoFocus","onUnmountAutoFocusProp","scopeProps","container","setContainer","useState","lastFocusedElementRef","useRef","composedRefs","node","focusScope","paused","pause","resume","current","useEffect","handleFocusIn","event","target","contains","focus","select","handleFocusOut","relatedTarget","document","addEventListener","removeEventListener","focusScopesStack","add","previouslyFocusedElement","activeElement","hasFocusedCandidate","mountEvent","Event","dispatchEvent","defaultPrevented","focusFirst","removeLinks","getTabbableCandidates","setTimeout","unmountEvent","body","remove","handleKeyDown","useCallback","isTabKey","key","altKey","ctrlKey","metaKey","focusedElement","currentTarget","first","last","getTabbableEdges","hasTabbableElementsInside","preventDefault","shiftKey","candidates","candidate","findVisible","reverse","nodes","walker","createTreeWalker","NodeFilter","SHOW_ELEMENT","acceptNode","isHiddenInput","tagName","type","disabled","hidden","FILTER_SKIP","tabIndex","FILTER_ACCEPT","nextNode","push","currentNode","elements","element","isHidden","upTo","getComputedStyle","visibility","undefined","display","parentElement","isSelectableInput","HTMLInputElement","preventScroll","createFocusScopesStack","stack","activeFocusScope","arrayRemove","unshift","array","item","updatedArray","index","indexOf","splice","items","filter","Root"],"version":3,"file":"index.js.map"}
@@ -1,2 +1,274 @@
1
- import{useCallbackRef as e}from"@radix-ui/react-use-callback-ref";import{Primitive as t}from"@radix-ui/react-primitive";import{useComposedRefs as n}from"@radix-ui/react-compose-refs";import*as o from"react";import u from"@babel/runtime/helpers/esm/extends";const c={bubbles:!1,cancelable:!0};export const FocusScope=/*#__PURE__*/o.forwardRef(((i,f)=>{const{loop:l=!1,trapped:m=!1,onMountAutoFocus:p,onUnmountAutoFocus:v,...E}=i,[F,S]=o.useState(null),b=e(p),T=e(v),y=o.useRef(null),L=n(f,(e=>S(e))),h=o.useRef({paused:!1,pause(){this.paused=!0},resume(){this.paused=!1}}).current;o.useEffect((()=>{if(m){function e(e){if(h.paused||!F)return;const t=e.target;F.contains(t)?y.current=t:a(y.current,{select:!0})}function t(e){!h.paused&&F&&(F.contains(e.relatedTarget)||a(y.current,{select:!0}))}return document.addEventListener("focusin",e),document.addEventListener("focusout",t),()=>{document.removeEventListener("focusin",e),document.removeEventListener("focusout",t)}}}),[m,F,h.paused]),o.useEffect((()=>{if(F){d.add(h);const t=document.activeElement;if(!F.contains(t)){const n=new Event("focusScope.autoFocusOnMount",c);F.addEventListener("focusScope.autoFocusOnMount",b),F.dispatchEvent(n),n.defaultPrevented||(!function(e,{select:t=!1}={}){const n=document.activeElement;for(const o of e)if(a(o,{select:t}),document.activeElement!==n)return}((e=r(F),e.filter((e=>"A"!==e.tagName))),{select:!0}),document.activeElement===t&&a(F))}return()=>{F.removeEventListener("focusScope.autoFocusOnMount",b),setTimeout((()=>{const e=new Event("focusScope.autoFocusOnUnmount",c);F.addEventListener("focusScope.autoFocusOnUnmount",T),F.dispatchEvent(e),e.defaultPrevented||a(null!=t?t:document.body,{select:!0}),F.removeEventListener("focusScope.autoFocusOnUnmount",T),d.remove(h)}),0)}}var e}),[F,b,T,h]);const N=o.useCallback((e=>{if(!l&&!m)return;if(h.paused)return;const t="Tab"===e.key&&!e.altKey&&!e.ctrlKey&&!e.metaKey,n=document.activeElement;if(t&&n){const t=e.currentTarget,[o,u]=function(e){const t=r(e),n=s(t,e),o=s(t.reverse(),e);return[n,o]}(t);o&&u?e.shiftKey||n!==u?e.shiftKey&&n===o&&(e.preventDefault(),l&&a(u,{select:!0})):(e.preventDefault(),l&&a(o,{select:!0})):n===t&&e.preventDefault()}}),[l,m,h.paused]);/*#__PURE__*/return o.createElement(t.div,u({tabIndex:-1},E,{ref:L,onKeyDown:N}))}));/*#__PURE__*/function r(e){const t=[],n=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT,{acceptNode:e=>{const t="INPUT"===e.tagName&&"hidden"===e.type;return e.disabled||e.hidden||t?NodeFilter.FILTER_SKIP:e.tabIndex>=0?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP}});for(;n.nextNode();)t.push(n.currentNode);return t}function s(e,t){for(const n of e)if(!i(n,{upTo:t}))return n}function i(e,{upTo:t}){if("hidden"===getComputedStyle(e).visibility)return!0;for(;e;){if(void 0!==t&&e===t)return!1;if("none"===getComputedStyle(e).display)return!0;e=e.parentElement}return!1}function a(e,{select:t=!1}={}){if(e&&e.focus){const n=document.activeElement;e.focus({preventScroll:!0}),e!==n&&function(e){return e instanceof HTMLInputElement&&"select"in e}(e)&&t&&e.select()}}const d=function(){let e=[];return{add(t){const n=e[0];t!==n&&(null==n||n.pause()),e=f(e,t),e.unshift(t)},remove(t){var n;e=f(e,t),null===(n=e[0])||void 0===n||n.resume()}}}();function f(e,t){const n=[...e],o=n.indexOf(t);return-1!==o&&n.splice(o,1),n}export const Root=FocusScope;
1
+ import $45QHv$babelruntimehelpersesmextends from "@babel/runtime/helpers/esm/extends";
2
+ import {forwardRef as $45QHv$forwardRef, useState as $45QHv$useState, useRef as $45QHv$useRef, useEffect as $45QHv$useEffect, useCallback as $45QHv$useCallback, createElement as $45QHv$createElement} from "react";
3
+ import {useComposedRefs as $45QHv$useComposedRefs} from "@radix-ui/react-compose-refs";
4
+ import {Primitive as $45QHv$Primitive} from "@radix-ui/react-primitive";
5
+ import {useCallbackRef as $45QHv$useCallbackRef} from "@radix-ui/react-use-callback-ref";
6
+
7
+ function $parcel$export(e, n, v, s) {
8
+ Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});
9
+ }
10
+ var $d3863c46a17e8a28$exports = {};
11
+
12
+ $parcel$export($d3863c46a17e8a28$exports, "FocusScope", () => $d3863c46a17e8a28$export$20e40289641fbbb6);
13
+ $parcel$export($d3863c46a17e8a28$exports, "Root", () => $d3863c46a17e8a28$export$be92b6f5f03c0fe9);
14
+
15
+
16
+
17
+
18
+
19
+ const $d3863c46a17e8a28$var$AUTOFOCUS_ON_MOUNT = 'focusScope.autoFocusOnMount';
20
+ const $d3863c46a17e8a28$var$AUTOFOCUS_ON_UNMOUNT = 'focusScope.autoFocusOnUnmount';
21
+ const $d3863c46a17e8a28$var$EVENT_OPTIONS = {
22
+ bubbles: false,
23
+ cancelable: true
24
+ };
25
+ /* -------------------------------------------------------------------------------------------------
26
+ * FocusScope
27
+ * -----------------------------------------------------------------------------------------------*/ const $d3863c46a17e8a28$var$FOCUS_SCOPE_NAME = 'FocusScope';
28
+ const $d3863c46a17e8a28$export$20e40289641fbbb6 = /*#__PURE__*/ $45QHv$forwardRef((props, forwardedRef)=>{
29
+ const { loop: loop = false , trapped: trapped = false , onMountAutoFocus: onMountAutoFocusProp , onUnmountAutoFocus: onUnmountAutoFocusProp , ...scopeProps } = props;
30
+ const [container1, setContainer] = $45QHv$useState(null);
31
+ const onMountAutoFocus = $45QHv$useCallbackRef(onMountAutoFocusProp);
32
+ const onUnmountAutoFocus = $45QHv$useCallbackRef(onUnmountAutoFocusProp);
33
+ const lastFocusedElementRef = $45QHv$useRef(null);
34
+ const composedRefs = $45QHv$useComposedRefs(forwardedRef, (node)=>setContainer(node)
35
+ );
36
+ const focusScope = $45QHv$useRef({
37
+ paused: false,
38
+ pause () {
39
+ this.paused = true;
40
+ },
41
+ resume () {
42
+ this.paused = false;
43
+ }
44
+ }).current; // Takes care of trapping focus if focus is moved outside programmatically for example
45
+ $45QHv$useEffect(()=>{
46
+ if (trapped) {
47
+ function handleFocusIn(event) {
48
+ if (focusScope.paused || !container1) return;
49
+ const target = event.target;
50
+ if (container1.contains(target)) lastFocusedElementRef.current = target;
51
+ else $d3863c46a17e8a28$var$focus(lastFocusedElementRef.current, {
52
+ select: true
53
+ });
54
+ }
55
+ function handleFocusOut(event) {
56
+ if (focusScope.paused || !container1) return;
57
+ if (!container1.contains(event.relatedTarget)) $d3863c46a17e8a28$var$focus(lastFocusedElementRef.current, {
58
+ select: true
59
+ });
60
+ }
61
+ document.addEventListener('focusin', handleFocusIn);
62
+ document.addEventListener('focusout', handleFocusOut);
63
+ return ()=>{
64
+ document.removeEventListener('focusin', handleFocusIn);
65
+ document.removeEventListener('focusout', handleFocusOut);
66
+ };
67
+ }
68
+ }, [
69
+ trapped,
70
+ container1,
71
+ focusScope.paused
72
+ ]);
73
+ $45QHv$useEffect(()=>{
74
+ if (container1) {
75
+ $d3863c46a17e8a28$var$focusScopesStack.add(focusScope);
76
+ const previouslyFocusedElement = document.activeElement;
77
+ const hasFocusedCandidate = container1.contains(previouslyFocusedElement);
78
+ if (!hasFocusedCandidate) {
79
+ const mountEvent = new Event($d3863c46a17e8a28$var$AUTOFOCUS_ON_MOUNT, $d3863c46a17e8a28$var$EVENT_OPTIONS);
80
+ container1.addEventListener($d3863c46a17e8a28$var$AUTOFOCUS_ON_MOUNT, onMountAutoFocus);
81
+ container1.dispatchEvent(mountEvent);
82
+ if (!mountEvent.defaultPrevented) {
83
+ $d3863c46a17e8a28$var$focusFirst($d3863c46a17e8a28$var$removeLinks($d3863c46a17e8a28$var$getTabbableCandidates(container1)), {
84
+ select: true
85
+ });
86
+ if (document.activeElement === previouslyFocusedElement) $d3863c46a17e8a28$var$focus(container1);
87
+ }
88
+ }
89
+ return ()=>{
90
+ container1.removeEventListener($d3863c46a17e8a28$var$AUTOFOCUS_ON_MOUNT, onMountAutoFocus); // We hit a react bug (fixed in v17) with focusing in unmount.
91
+ // We need to delay the focus a little to get around it for now.
92
+ // See: https://github.com/facebook/react/issues/17894
93
+ setTimeout(()=>{
94
+ const unmountEvent = new Event($d3863c46a17e8a28$var$AUTOFOCUS_ON_UNMOUNT, $d3863c46a17e8a28$var$EVENT_OPTIONS);
95
+ container1.addEventListener($d3863c46a17e8a28$var$AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus);
96
+ container1.dispatchEvent(unmountEvent);
97
+ if (!unmountEvent.defaultPrevented) $d3863c46a17e8a28$var$focus(previouslyFocusedElement !== null && previouslyFocusedElement !== void 0 ? previouslyFocusedElement : document.body, {
98
+ select: true
99
+ });
100
+ // we need to remove the listener after we `dispatchEvent`
101
+ container1.removeEventListener($d3863c46a17e8a28$var$AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus);
102
+ $d3863c46a17e8a28$var$focusScopesStack.remove(focusScope);
103
+ }, 0);
104
+ };
105
+ }
106
+ }, [
107
+ container1,
108
+ onMountAutoFocus,
109
+ onUnmountAutoFocus,
110
+ focusScope
111
+ ]); // Takes care of looping focus (when tabbing whilst at the edges)
112
+ const handleKeyDown = $45QHv$useCallback((event)=>{
113
+ if (!loop && !trapped) return;
114
+ if (focusScope.paused) return;
115
+ const isTabKey = event.key === 'Tab' && !event.altKey && !event.ctrlKey && !event.metaKey;
116
+ const focusedElement = document.activeElement;
117
+ if (isTabKey && focusedElement) {
118
+ const container = event.currentTarget;
119
+ const [first, last] = $d3863c46a17e8a28$var$getTabbableEdges(container);
120
+ const hasTabbableElementsInside = first && last; // we can only wrap focus if we have tabbable edges
121
+ if (!hasTabbableElementsInside) {
122
+ if (focusedElement === container) event.preventDefault();
123
+ } else {
124
+ if (!event.shiftKey && focusedElement === last) {
125
+ event.preventDefault();
126
+ if (loop) $d3863c46a17e8a28$var$focus(first, {
127
+ select: true
128
+ });
129
+ } else if (event.shiftKey && focusedElement === first) {
130
+ event.preventDefault();
131
+ if (loop) $d3863c46a17e8a28$var$focus(last, {
132
+ select: true
133
+ });
134
+ }
135
+ }
136
+ }
137
+ }, [
138
+ loop,
139
+ trapped,
140
+ focusScope.paused
141
+ ]);
142
+ return /*#__PURE__*/ $45QHv$createElement($45QHv$Primitive.div, $45QHv$babelruntimehelpersesmextends({
143
+ tabIndex: -1
144
+ }, scopeProps, {
145
+ ref: composedRefs,
146
+ onKeyDown: handleKeyDown
147
+ }));
148
+ });
149
+ /*#__PURE__*/ Object.assign($d3863c46a17e8a28$export$20e40289641fbbb6, {
150
+ displayName: $d3863c46a17e8a28$var$FOCUS_SCOPE_NAME
151
+ });
152
+ /* -------------------------------------------------------------------------------------------------
153
+ * Utils
154
+ * -----------------------------------------------------------------------------------------------*/ /**
155
+ * Attempts focusing the first element in a list of candidates.
156
+ * Stops when focus has actually moved.
157
+ */ function $d3863c46a17e8a28$var$focusFirst(candidates, { select: select = false } = {}) {
158
+ const previouslyFocusedElement = document.activeElement;
159
+ for (const candidate of candidates){
160
+ $d3863c46a17e8a28$var$focus(candidate, {
161
+ select: select
162
+ });
163
+ if (document.activeElement !== previouslyFocusedElement) return;
164
+ }
165
+ }
166
+ /**
167
+ * Returns the first and last tabbable elements inside a container.
168
+ */ function $d3863c46a17e8a28$var$getTabbableEdges(container) {
169
+ const candidates = $d3863c46a17e8a28$var$getTabbableCandidates(container);
170
+ const first = $d3863c46a17e8a28$var$findVisible(candidates, container);
171
+ const last = $d3863c46a17e8a28$var$findVisible(candidates.reverse(), container);
172
+ return [
173
+ first,
174
+ last
175
+ ];
176
+ }
177
+ /**
178
+ * Returns a list of potential tabbable candidates.
179
+ *
180
+ * NOTE: This is only a close approximation. For example it doesn't take into account cases like when
181
+ * elements are not visible. This cannot be worked out easily by just reading a property, but rather
182
+ * necessitate runtime knowledge (computed styles, etc). We deal with these cases separately.
183
+ *
184
+ * See: https://developer.mozilla.org/en-US/docs/Web/API/TreeWalker
185
+ * Credit: https://github.com/discord/focus-layers/blob/master/src/util/wrapFocus.tsx#L1
186
+ */ function $d3863c46a17e8a28$var$getTabbableCandidates(container) {
187
+ const nodes = [];
188
+ const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {
189
+ acceptNode: (node)=>{
190
+ const isHiddenInput = node.tagName === 'INPUT' && node.type === 'hidden';
191
+ if (node.disabled || node.hidden || isHiddenInput) return NodeFilter.FILTER_SKIP; // `.tabIndex` is not the same as the `tabindex` attribute. It works on the
192
+ // runtime's understanding of tabbability, so this automatically accounts
193
+ // for any kind of element that could be tabbed to.
194
+ return node.tabIndex >= 0 ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
195
+ }
196
+ });
197
+ while(walker.nextNode())nodes.push(walker.currentNode); // we do not take into account the order of nodes with positive `tabIndex` as it
198
+ // hinders accessibility to have tab order different from visual order.
199
+ return nodes;
200
+ }
201
+ /**
202
+ * Returns the first visible element in a list.
203
+ * NOTE: Only checks visibility up to the `container`.
204
+ */ function $d3863c46a17e8a28$var$findVisible(elements, container) {
205
+ for (const element of elements){
206
+ // we stop checking if it's hidden at the `container` level (excluding)
207
+ if (!$d3863c46a17e8a28$var$isHidden(element, {
208
+ upTo: container
209
+ })) return element;
210
+ }
211
+ }
212
+ function $d3863c46a17e8a28$var$isHidden(node, { upTo: upTo }) {
213
+ if (getComputedStyle(node).visibility === 'hidden') return true;
214
+ while(node){
215
+ // we stop at `upTo` (excluding it)
216
+ if (upTo !== undefined && node === upTo) return false;
217
+ if (getComputedStyle(node).display === 'none') return true;
218
+ node = node.parentElement;
219
+ }
220
+ return false;
221
+ }
222
+ function $d3863c46a17e8a28$var$isSelectableInput(element) {
223
+ return element instanceof HTMLInputElement && 'select' in element;
224
+ }
225
+ function $d3863c46a17e8a28$var$focus(element, { select: select = false } = {}) {
226
+ // only focus if that element is focusable
227
+ if (element && element.focus) {
228
+ const previouslyFocusedElement = document.activeElement; // NOTE: we prevent scrolling on focus, to minimize jarring transitions for users
229
+ element.focus({
230
+ preventScroll: true
231
+ }); // only select if its not the same element, it supports selection and we need to select
232
+ if (element !== previouslyFocusedElement && $d3863c46a17e8a28$var$isSelectableInput(element) && select) element.select();
233
+ }
234
+ }
235
+ /* -------------------------------------------------------------------------------------------------
236
+ * FocusScope stack
237
+ * -----------------------------------------------------------------------------------------------*/ const $d3863c46a17e8a28$var$focusScopesStack = $d3863c46a17e8a28$var$createFocusScopesStack();
238
+ function $d3863c46a17e8a28$var$createFocusScopesStack() {
239
+ /** A stack of focus scopes, with the active one at the top */ let stack = [];
240
+ return {
241
+ add (focusScope) {
242
+ // pause the currently active focus scope (at the top of the stack)
243
+ const activeFocusScope = stack[0];
244
+ if (focusScope !== activeFocusScope) activeFocusScope === null || activeFocusScope === void 0 || activeFocusScope.pause();
245
+ // remove in case it already exists (because we'll re-add it at the top of the stack)
246
+ stack = $d3863c46a17e8a28$var$arrayRemove(stack, focusScope);
247
+ stack.unshift(focusScope);
248
+ },
249
+ remove (focusScope) {
250
+ var _stack$;
251
+ stack = $d3863c46a17e8a28$var$arrayRemove(stack, focusScope);
252
+ (_stack$ = stack[0]) === null || _stack$ === void 0 || _stack$.resume();
253
+ }
254
+ };
255
+ }
256
+ function $d3863c46a17e8a28$var$arrayRemove(array, item) {
257
+ const updatedArray = [
258
+ ...array
259
+ ];
260
+ const index = updatedArray.indexOf(item);
261
+ if (index !== -1) updatedArray.splice(index, 1);
262
+ return updatedArray;
263
+ }
264
+ function $d3863c46a17e8a28$var$removeLinks(items) {
265
+ return items.filter((item)=>item.tagName !== 'A'
266
+ );
267
+ }
268
+ const $d3863c46a17e8a28$export$be92b6f5f03c0fe9 = $d3863c46a17e8a28$export$20e40289641fbbb6;
269
+
270
+
271
+
272
+
273
+ export {$d3863c46a17e8a28$export$20e40289641fbbb6 as FocusScope, $d3863c46a17e8a28$export$be92b6f5f03c0fe9 as Root};
2
274
  //# sourceMappingURL=index.module.js.map
@@ -1 +1 @@
1
- {"mappings":"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","sources":["./packages/react/focus-scope/src/FocusScope.tsx"],"sourcesContent":["import * as React from 'react';\nimport { useComposedRefs } from '@radix-ui/react-compose-refs';\nimport { Primitive } from '@radix-ui/react-primitive';\nimport { useCallbackRef } from '@radix-ui/react-use-callback-ref';\n\nimport type * as Radix from '@radix-ui/react-primitive';\n\nconst AUTOFOCUS_ON_MOUNT = 'focusScope.autoFocusOnMount';\nconst AUTOFOCUS_ON_UNMOUNT = 'focusScope.autoFocusOnUnmount';\nconst EVENT_OPTIONS = { bubbles: false, cancelable: true };\n\ntype FocusableTarget = HTMLElement | { focus(): void };\n\n/* -------------------------------------------------------------------------------------------------\n * FocusScope\n * -----------------------------------------------------------------------------------------------*/\n\nconst FOCUS_SCOPE_NAME = 'FocusScope';\n\ntype FocusScopeElement = React.ElementRef<typeof Primitive.div>;\ntype PrimitiveDivProps = Radix.ComponentPropsWithoutRef<typeof Primitive.div>;\ninterface FocusScopeProps extends PrimitiveDivProps {\n /**\n * When `true`, tabbing from last item will focus first tabbable\n * and shift+tab from first item will focus last tababble.\n * @defaultValue false\n */\n loop?: boolean;\n\n /**\n * When `true`, focus cannot escape the focus scope via keyboard,\n * pointer, or a programmatic focus.\n * @defaultValue false\n */\n trapped?: boolean;\n\n /**\n * Event handler called when auto-focusing on mount.\n * Can be prevented.\n */\n onMountAutoFocus?: (event: Event) => void;\n\n /**\n * Event handler called when auto-focusing on unmount.\n * Can be prevented.\n */\n onUnmountAutoFocus?: (event: Event) => void;\n}\n\nconst FocusScope = React.forwardRef<FocusScopeElement, FocusScopeProps>((props, forwardedRef) => {\n const {\n loop = false,\n trapped = false,\n onMountAutoFocus: onMountAutoFocusProp,\n onUnmountAutoFocus: onUnmountAutoFocusProp,\n ...scopeProps\n } = props;\n const [container, setContainer] = React.useState<HTMLElement | null>(null);\n const onMountAutoFocus = useCallbackRef(onMountAutoFocusProp);\n const onUnmountAutoFocus = useCallbackRef(onUnmountAutoFocusProp);\n const lastFocusedElementRef = React.useRef<HTMLElement | null>(null);\n const composedRefs = useComposedRefs(forwardedRef, (node) => setContainer(node));\n\n const focusScope = React.useRef({\n paused: false,\n pause() {\n this.paused = true;\n },\n resume() {\n this.paused = false;\n },\n }).current;\n\n // Takes care of trapping focus if focus is moved outside programmatically for example\n React.useEffect(() => {\n if (trapped) {\n function handleFocusIn(event: FocusEvent) {\n if (focusScope.paused || !container) return;\n const target = event.target as HTMLElement | null;\n if (container.contains(target)) {\n lastFocusedElementRef.current = target;\n } else {\n focus(lastFocusedElementRef.current, { select: true });\n }\n }\n\n function handleFocusOut(event: FocusEvent) {\n if (focusScope.paused || !container) return;\n if (!container.contains(event.relatedTarget as HTMLElement | null)) {\n focus(lastFocusedElementRef.current, { select: true });\n }\n }\n\n document.addEventListener('focusin', handleFocusIn);\n document.addEventListener('focusout', handleFocusOut);\n return () => {\n document.removeEventListener('focusin', handleFocusIn);\n document.removeEventListener('focusout', handleFocusOut);\n };\n }\n }, [trapped, container, focusScope.paused]);\n\n React.useEffect(() => {\n if (container) {\n focusScopesStack.add(focusScope);\n const previouslyFocusedElement = document.activeElement as HTMLElement | null;\n const hasFocusedCandidate = container.contains(previouslyFocusedElement);\n\n if (!hasFocusedCandidate) {\n const mountEvent = new Event(AUTOFOCUS_ON_MOUNT, EVENT_OPTIONS);\n container.addEventListener(AUTOFOCUS_ON_MOUNT, onMountAutoFocus);\n container.dispatchEvent(mountEvent);\n if (!mountEvent.defaultPrevented) {\n focusFirst(removeLinks(getTabbableCandidates(container)), { select: true });\n if (document.activeElement === previouslyFocusedElement) {\n focus(container);\n }\n }\n }\n\n return () => {\n container.removeEventListener(AUTOFOCUS_ON_MOUNT, onMountAutoFocus);\n\n // We hit a react bug (fixed in v17) with focusing in unmount.\n // We need to delay the focus a little to get around it for now.\n // See: https://github.com/facebook/react/issues/17894\n setTimeout(() => {\n const unmountEvent = new Event(AUTOFOCUS_ON_UNMOUNT, EVENT_OPTIONS);\n container.addEventListener(AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus);\n container.dispatchEvent(unmountEvent);\n if (!unmountEvent.defaultPrevented) {\n focus(previouslyFocusedElement ?? document.body, { select: true });\n }\n // we need to remove the listener after we `dispatchEvent`\n container.removeEventListener(AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus);\n\n focusScopesStack.remove(focusScope);\n }, 0);\n };\n }\n }, [container, onMountAutoFocus, onUnmountAutoFocus, focusScope]);\n\n // Takes care of looping focus (when tabbing whilst at the edges)\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent) => {\n if (!loop && !trapped) return;\n if (focusScope.paused) return;\n\n const isTabKey = event.key === 'Tab' && !event.altKey && !event.ctrlKey && !event.metaKey;\n const focusedElement = document.activeElement as HTMLElement | null;\n\n if (isTabKey && focusedElement) {\n const container = event.currentTarget as HTMLElement;\n const [first, last] = getTabbableEdges(container);\n const hasTabbableElementsInside = first && last;\n\n // we can only wrap focus if we have tabbable edges\n if (!hasTabbableElementsInside) {\n if (focusedElement === container) event.preventDefault();\n } else {\n if (!event.shiftKey && focusedElement === last) {\n event.preventDefault();\n if (loop) focus(first, { select: true });\n } else if (event.shiftKey && focusedElement === first) {\n event.preventDefault();\n if (loop) focus(last, { select: true });\n }\n }\n }\n },\n [loop, trapped, focusScope.paused]\n );\n\n return (\n <Primitive.div tabIndex={-1} {...scopeProps} ref={composedRefs} onKeyDown={handleKeyDown} />\n );\n});\n\nFocusScope.displayName = FOCUS_SCOPE_NAME;\n\n/* -------------------------------------------------------------------------------------------------\n * Utils\n * -----------------------------------------------------------------------------------------------*/\n\n/**\n * Attempts focusing the first element in a list of candidates.\n * Stops when focus has actually moved.\n */\nfunction focusFirst(candidates: HTMLElement[], { select = false } = {}) {\n const previouslyFocusedElement = document.activeElement;\n for (const candidate of candidates) {\n focus(candidate, { select });\n if (document.activeElement !== previouslyFocusedElement) return;\n }\n}\n\n/**\n * Returns the first and last tabbable elements inside a container.\n */\nfunction getTabbableEdges(container: HTMLElement) {\n const candidates = getTabbableCandidates(container);\n const first = findVisible(candidates, container);\n const last = findVisible(candidates.reverse(), container);\n return [first, last] as const;\n}\n\n/**\n * Returns a list of potential tabbable candidates.\n *\n * NOTE: This is only a close approximation. For example it doesn't take into account cases like when\n * elements are not visible. This cannot be worked out easily by just reading a property, but rather\n * necessitate runtime knowledge (computed styles, etc). We deal with these cases separately.\n *\n * See: https://developer.mozilla.org/en-US/docs/Web/API/TreeWalker\n * Credit: https://github.com/discord/focus-layers/blob/master/src/util/wrapFocus.tsx#L1\n */\nfunction getTabbableCandidates(container: HTMLElement) {\n const nodes: HTMLElement[] = [];\n const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {\n acceptNode: (node: any) => {\n const isHiddenInput = node.tagName === 'INPUT' && node.type === 'hidden';\n if (node.disabled || node.hidden || isHiddenInput) return NodeFilter.FILTER_SKIP;\n // `.tabIndex` is not the same as the `tabindex` attribute. It works on the\n // runtime's understanding of tabbability, so this automatically accounts\n // for any kind of element that could be tabbed to.\n return node.tabIndex >= 0 ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;\n },\n });\n while (walker.nextNode()) nodes.push(walker.currentNode as HTMLElement);\n // we do not take into account the order of nodes with positive `tabIndex` as it\n // hinders accessibility to have tab order different from visual order.\n return nodes;\n}\n\n/**\n * Returns the first visible element in a list.\n * NOTE: Only checks visibility up to the `container`.\n */\nfunction findVisible(elements: HTMLElement[], container: HTMLElement) {\n for (const element of elements) {\n // we stop checking if it's hidden at the `container` level (excluding)\n if (!isHidden(element, { upTo: container })) return element;\n }\n}\n\nfunction isHidden(node: HTMLElement, { upTo }: { upTo?: HTMLElement }) {\n if (getComputedStyle(node).visibility === 'hidden') return true;\n while (node) {\n // we stop at `upTo` (excluding it)\n if (upTo !== undefined && node === upTo) return false;\n if (getComputedStyle(node).display === 'none') return true;\n node = node.parentElement as HTMLElement;\n }\n return false;\n}\n\nfunction isSelectableInput(element: any): element is FocusableTarget & { select: () => void } {\n return element instanceof HTMLInputElement && 'select' in element;\n}\n\nfunction focus(element?: FocusableTarget | null, { select = false } = {}) {\n // only focus if that element is focusable\n if (element && element.focus) {\n const previouslyFocusedElement = document.activeElement;\n // NOTE: we prevent scrolling on focus, to minimize jarring transitions for users\n element.focus({ preventScroll: true });\n // only select if its not the same element, it supports selection and we need to select\n if (element !== previouslyFocusedElement && isSelectableInput(element) && select)\n element.select();\n }\n}\n\n/* -------------------------------------------------------------------------------------------------\n * FocusScope stack\n * -----------------------------------------------------------------------------------------------*/\n\ntype FocusScopeAPI = { paused: boolean; pause(): void; resume(): void };\nconst focusScopesStack = createFocusScopesStack();\n\nfunction createFocusScopesStack() {\n /** A stack of focus scopes, with the active one at the top */\n let stack: FocusScopeAPI[] = [];\n\n return {\n add(focusScope: FocusScopeAPI) {\n // pause the currently active focus scope (at the top of the stack)\n const activeFocusScope = stack[0];\n if (focusScope !== activeFocusScope) {\n activeFocusScope?.pause();\n }\n // remove in case it already exists (because we'll re-add it at the top of the stack)\n stack = arrayRemove(stack, focusScope);\n stack.unshift(focusScope);\n },\n\n remove(focusScope: FocusScopeAPI) {\n stack = arrayRemove(stack, focusScope);\n stack[0]?.resume();\n },\n };\n}\n\nfunction arrayRemove<T>(array: T[], item: T) {\n const updatedArray = [...array];\n const index = updatedArray.indexOf(item);\n if (index !== -1) {\n updatedArray.splice(index, 1);\n }\n return updatedArray;\n}\n\nfunction removeLinks(items: HTMLElement[]) {\n return items.filter((item) => item.tagName !== 'A');\n}\n\nconst Root = FocusScope;\n\nexport {\n FocusScope,\n //\n Root,\n};\nexport type { FocusScopeProps };\n"],"names":["EVENT_OPTIONS","bubbles","cancelable","FocusScope","React","forwardRef","props","forwardedRef","loop","trapped","onMountAutoFocus","onMountAutoFocusProp","onUnmountAutoFocus","onUnmountAutoFocusProp","scopeProps","container","setContainer","useState","useCallbackRef","lastFocusedElementRef","useRef","composedRefs","useComposedRefs","node","focusScope","paused","pause","this","resume","current","useEffect","handleFocusIn","event","target","contains","focus","select","handleFocusOut","relatedTarget","document","addEventListener","removeEventListener","focusScopesStack","add","previouslyFocusedElement","activeElement","mountEvent","Event","dispatchEvent","defaultPrevented","candidates","candidate","focusFirst","items","getTabbableCandidates","filter","item","tagName","setTimeout","unmountEvent","body","remove","handleKeyDown","useCallback","isTabKey","key","altKey","ctrlKey","metaKey","focusedElement","currentTarget","first","last","findVisible","reverse","getTabbableEdges","shiftKey","preventDefault","_react","createElement","Primitive","div","_babelRuntimeHelpersEsmExtends","tabIndex","ref","onKeyDown","nodes","walker","createTreeWalker","NodeFilter","SHOW_ELEMENT","acceptNode","isHiddenInput","type","disabled","hidden","FILTER_SKIP","FILTER_ACCEPT","nextNode","push","currentNode","elements","element","isHidden","upTo","getComputedStyle","visibility","undefined","display","parentElement","preventScroll","HTMLInputElement","isSelectableInput","stack","activeFocusScope","arrayRemove","unshift","_stack$","createFocusScopesStack","array","updatedArray","index","indexOf","splice","Root"],"version":3,"file":"index.module.js.map"}
1
+ {"mappings":"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","sources":["packages/react/focus-scope/src/index.ts","packages/react/focus-scope/src/FocusScope.tsx"],"sourcesContent":["export * from './FocusScope';\n","import * as React from 'react';\nimport { useComposedRefs } from '@radix-ui/react-compose-refs';\nimport { Primitive } from '@radix-ui/react-primitive';\nimport { useCallbackRef } from '@radix-ui/react-use-callback-ref';\n\nimport type * as Radix from '@radix-ui/react-primitive';\n\nconst AUTOFOCUS_ON_MOUNT = 'focusScope.autoFocusOnMount';\nconst AUTOFOCUS_ON_UNMOUNT = 'focusScope.autoFocusOnUnmount';\nconst EVENT_OPTIONS = { bubbles: false, cancelable: true };\n\ntype FocusableTarget = HTMLElement | { focus(): void };\n\n/* -------------------------------------------------------------------------------------------------\n * FocusScope\n * -----------------------------------------------------------------------------------------------*/\n\nconst FOCUS_SCOPE_NAME = 'FocusScope';\n\ntype FocusScopeElement = React.ElementRef<typeof Primitive.div>;\ntype PrimitiveDivProps = Radix.ComponentPropsWithoutRef<typeof Primitive.div>;\ninterface FocusScopeProps extends PrimitiveDivProps {\n /**\n * When `true`, tabbing from last item will focus first tabbable\n * and shift+tab from first item will focus last tababble.\n * @defaultValue false\n */\n loop?: boolean;\n\n /**\n * When `true`, focus cannot escape the focus scope via keyboard,\n * pointer, or a programmatic focus.\n * @defaultValue false\n */\n trapped?: boolean;\n\n /**\n * Event handler called when auto-focusing on mount.\n * Can be prevented.\n */\n onMountAutoFocus?: (event: Event) => void;\n\n /**\n * Event handler called when auto-focusing on unmount.\n * Can be prevented.\n */\n onUnmountAutoFocus?: (event: Event) => void;\n}\n\nconst FocusScope = React.forwardRef<FocusScopeElement, FocusScopeProps>((props, forwardedRef) => {\n const {\n loop = false,\n trapped = false,\n onMountAutoFocus: onMountAutoFocusProp,\n onUnmountAutoFocus: onUnmountAutoFocusProp,\n ...scopeProps\n } = props;\n const [container, setContainer] = React.useState<HTMLElement | null>(null);\n const onMountAutoFocus = useCallbackRef(onMountAutoFocusProp);\n const onUnmountAutoFocus = useCallbackRef(onUnmountAutoFocusProp);\n const lastFocusedElementRef = React.useRef<HTMLElement | null>(null);\n const composedRefs = useComposedRefs(forwardedRef, (node) => setContainer(node));\n\n const focusScope = React.useRef({\n paused: false,\n pause() {\n this.paused = true;\n },\n resume() {\n this.paused = false;\n },\n }).current;\n\n // Takes care of trapping focus if focus is moved outside programmatically for example\n React.useEffect(() => {\n if (trapped) {\n function handleFocusIn(event: FocusEvent) {\n if (focusScope.paused || !container) return;\n const target = event.target as HTMLElement | null;\n if (container.contains(target)) {\n lastFocusedElementRef.current = target;\n } else {\n focus(lastFocusedElementRef.current, { select: true });\n }\n }\n\n function handleFocusOut(event: FocusEvent) {\n if (focusScope.paused || !container) return;\n if (!container.contains(event.relatedTarget as HTMLElement | null)) {\n focus(lastFocusedElementRef.current, { select: true });\n }\n }\n\n document.addEventListener('focusin', handleFocusIn);\n document.addEventListener('focusout', handleFocusOut);\n return () => {\n document.removeEventListener('focusin', handleFocusIn);\n document.removeEventListener('focusout', handleFocusOut);\n };\n }\n }, [trapped, container, focusScope.paused]);\n\n React.useEffect(() => {\n if (container) {\n focusScopesStack.add(focusScope);\n const previouslyFocusedElement = document.activeElement as HTMLElement | null;\n const hasFocusedCandidate = container.contains(previouslyFocusedElement);\n\n if (!hasFocusedCandidate) {\n const mountEvent = new Event(AUTOFOCUS_ON_MOUNT, EVENT_OPTIONS);\n container.addEventListener(AUTOFOCUS_ON_MOUNT, onMountAutoFocus);\n container.dispatchEvent(mountEvent);\n if (!mountEvent.defaultPrevented) {\n focusFirst(removeLinks(getTabbableCandidates(container)), { select: true });\n if (document.activeElement === previouslyFocusedElement) {\n focus(container);\n }\n }\n }\n\n return () => {\n container.removeEventListener(AUTOFOCUS_ON_MOUNT, onMountAutoFocus);\n\n // We hit a react bug (fixed in v17) with focusing in unmount.\n // We need to delay the focus a little to get around it for now.\n // See: https://github.com/facebook/react/issues/17894\n setTimeout(() => {\n const unmountEvent = new Event(AUTOFOCUS_ON_UNMOUNT, EVENT_OPTIONS);\n container.addEventListener(AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus);\n container.dispatchEvent(unmountEvent);\n if (!unmountEvent.defaultPrevented) {\n focus(previouslyFocusedElement ?? document.body, { select: true });\n }\n // we need to remove the listener after we `dispatchEvent`\n container.removeEventListener(AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus);\n\n focusScopesStack.remove(focusScope);\n }, 0);\n };\n }\n }, [container, onMountAutoFocus, onUnmountAutoFocus, focusScope]);\n\n // Takes care of looping focus (when tabbing whilst at the edges)\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent) => {\n if (!loop && !trapped) return;\n if (focusScope.paused) return;\n\n const isTabKey = event.key === 'Tab' && !event.altKey && !event.ctrlKey && !event.metaKey;\n const focusedElement = document.activeElement as HTMLElement | null;\n\n if (isTabKey && focusedElement) {\n const container = event.currentTarget as HTMLElement;\n const [first, last] = getTabbableEdges(container);\n const hasTabbableElementsInside = first && last;\n\n // we can only wrap focus if we have tabbable edges\n if (!hasTabbableElementsInside) {\n if (focusedElement === container) event.preventDefault();\n } else {\n if (!event.shiftKey && focusedElement === last) {\n event.preventDefault();\n if (loop) focus(first, { select: true });\n } else if (event.shiftKey && focusedElement === first) {\n event.preventDefault();\n if (loop) focus(last, { select: true });\n }\n }\n }\n },\n [loop, trapped, focusScope.paused]\n );\n\n return (\n <Primitive.div tabIndex={-1} {...scopeProps} ref={composedRefs} onKeyDown={handleKeyDown} />\n );\n});\n\nFocusScope.displayName = FOCUS_SCOPE_NAME;\n\n/* -------------------------------------------------------------------------------------------------\n * Utils\n * -----------------------------------------------------------------------------------------------*/\n\n/**\n * Attempts focusing the first element in a list of candidates.\n * Stops when focus has actually moved.\n */\nfunction focusFirst(candidates: HTMLElement[], { select = false } = {}) {\n const previouslyFocusedElement = document.activeElement;\n for (const candidate of candidates) {\n focus(candidate, { select });\n if (document.activeElement !== previouslyFocusedElement) return;\n }\n}\n\n/**\n * Returns the first and last tabbable elements inside a container.\n */\nfunction getTabbableEdges(container: HTMLElement) {\n const candidates = getTabbableCandidates(container);\n const first = findVisible(candidates, container);\n const last = findVisible(candidates.reverse(), container);\n return [first, last] as const;\n}\n\n/**\n * Returns a list of potential tabbable candidates.\n *\n * NOTE: This is only a close approximation. For example it doesn't take into account cases like when\n * elements are not visible. This cannot be worked out easily by just reading a property, but rather\n * necessitate runtime knowledge (computed styles, etc). We deal with these cases separately.\n *\n * See: https://developer.mozilla.org/en-US/docs/Web/API/TreeWalker\n * Credit: https://github.com/discord/focus-layers/blob/master/src/util/wrapFocus.tsx#L1\n */\nfunction getTabbableCandidates(container: HTMLElement) {\n const nodes: HTMLElement[] = [];\n const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {\n acceptNode: (node: any) => {\n const isHiddenInput = node.tagName === 'INPUT' && node.type === 'hidden';\n if (node.disabled || node.hidden || isHiddenInput) return NodeFilter.FILTER_SKIP;\n // `.tabIndex` is not the same as the `tabindex` attribute. It works on the\n // runtime's understanding of tabbability, so this automatically accounts\n // for any kind of element that could be tabbed to.\n return node.tabIndex >= 0 ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;\n },\n });\n while (walker.nextNode()) nodes.push(walker.currentNode as HTMLElement);\n // we do not take into account the order of nodes with positive `tabIndex` as it\n // hinders accessibility to have tab order different from visual order.\n return nodes;\n}\n\n/**\n * Returns the first visible element in a list.\n * NOTE: Only checks visibility up to the `container`.\n */\nfunction findVisible(elements: HTMLElement[], container: HTMLElement) {\n for (const element of elements) {\n // we stop checking if it's hidden at the `container` level (excluding)\n if (!isHidden(element, { upTo: container })) return element;\n }\n}\n\nfunction isHidden(node: HTMLElement, { upTo }: { upTo?: HTMLElement }) {\n if (getComputedStyle(node).visibility === 'hidden') return true;\n while (node) {\n // we stop at `upTo` (excluding it)\n if (upTo !== undefined && node === upTo) return false;\n if (getComputedStyle(node).display === 'none') return true;\n node = node.parentElement as HTMLElement;\n }\n return false;\n}\n\nfunction isSelectableInput(element: any): element is FocusableTarget & { select: () => void } {\n return element instanceof HTMLInputElement && 'select' in element;\n}\n\nfunction focus(element?: FocusableTarget | null, { select = false } = {}) {\n // only focus if that element is focusable\n if (element && element.focus) {\n const previouslyFocusedElement = document.activeElement;\n // NOTE: we prevent scrolling on focus, to minimize jarring transitions for users\n element.focus({ preventScroll: true });\n // only select if its not the same element, it supports selection and we need to select\n if (element !== previouslyFocusedElement && isSelectableInput(element) && select)\n element.select();\n }\n}\n\n/* -------------------------------------------------------------------------------------------------\n * FocusScope stack\n * -----------------------------------------------------------------------------------------------*/\n\ntype FocusScopeAPI = { paused: boolean; pause(): void; resume(): void };\nconst focusScopesStack = createFocusScopesStack();\n\nfunction createFocusScopesStack() {\n /** A stack of focus scopes, with the active one at the top */\n let stack: FocusScopeAPI[] = [];\n\n return {\n add(focusScope: FocusScopeAPI) {\n // pause the currently active focus scope (at the top of the stack)\n const activeFocusScope = stack[0];\n if (focusScope !== activeFocusScope) {\n activeFocusScope?.pause();\n }\n // remove in case it already exists (because we'll re-add it at the top of the stack)\n stack = arrayRemove(stack, focusScope);\n stack.unshift(focusScope);\n },\n\n remove(focusScope: FocusScopeAPI) {\n stack = arrayRemove(stack, focusScope);\n stack[0]?.resume();\n },\n };\n}\n\nfunction arrayRemove<T>(array: T[], item: T) {\n const updatedArray = [...array];\n const index = updatedArray.indexOf(item);\n if (index !== -1) {\n updatedArray.splice(index, 1);\n }\n return updatedArray;\n}\n\nfunction removeLinks(items: HTMLElement[]) {\n return items.filter((item) => item.tagName !== 'A');\n}\n\nconst Root = FocusScope;\n\nexport {\n FocusScope,\n //\n Root,\n};\nexport type { FocusScopeProps };\n"],"names":["React","useComposedRefs","Primitive","useCallbackRef","AUTOFOCUS_ON_MOUNT","AUTOFOCUS_ON_UNMOUNT","EVENT_OPTIONS","bubbles","cancelable","FOCUS_SCOPE_NAME","FocusScope","forwardRef","props","forwardedRef","loop","trapped","onMountAutoFocus","onMountAutoFocusProp","onUnmountAutoFocus","onUnmountAutoFocusProp","scopeProps","container","setContainer","useState","lastFocusedElementRef","useRef","composedRefs","node","focusScope","paused","pause","resume","current","useEffect","handleFocusIn","event","target","contains","focus","select","handleFocusOut","relatedTarget","document","addEventListener","removeEventListener","focusScopesStack","add","previouslyFocusedElement","activeElement","hasFocusedCandidate","mountEvent","Event","dispatchEvent","defaultPrevented","focusFirst","removeLinks","getTabbableCandidates","setTimeout","unmountEvent","body","remove","handleKeyDown","useCallback","isTabKey","key","altKey","ctrlKey","metaKey","focusedElement","currentTarget","first","last","getTabbableEdges","hasTabbableElementsInside","preventDefault","shiftKey","candidates","candidate","findVisible","reverse","nodes","walker","createTreeWalker","NodeFilter","SHOW_ELEMENT","acceptNode","isHiddenInput","tagName","type","disabled","hidden","FILTER_SKIP","tabIndex","FILTER_ACCEPT","nextNode","push","currentNode","elements","element","isHidden","upTo","getComputedStyle","visibility","undefined","display","parentElement","isSelectableInput","HTMLInputElement","preventScroll","createFocusScopesStack","stack","activeFocusScope","arrayRemove","unshift","array","item","updatedArray","index","indexOf","splice","items","filter","Root"],"version":3,"file":"index.module.js.map"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@radix-ui/react-focus-scope",
3
- "version": "0.1.5-rc.1",
3
+ "version": "0.1.5-rc.12",
4
4
  "license": "MIT",
5
5
  "source": "src/index.ts",
6
6
  "main": "dist/index.js",
@@ -17,9 +17,9 @@
17
17
  },
18
18
  "dependencies": {
19
19
  "@babel/runtime": "^7.13.10",
20
- "@radix-ui/react-compose-refs": "0.1.1-rc.1",
21
- "@radix-ui/react-primitive": "0.1.5-rc.1",
22
- "@radix-ui/react-use-callback-ref": "0.1.1-rc.1"
20
+ "@radix-ui/react-compose-refs": "0.1.1-rc.12",
21
+ "@radix-ui/react-primitive": "0.1.5-rc.12",
22
+ "@radix-ui/react-use-callback-ref": "0.1.1-rc.12"
23
23
  },
24
24
  "peerDependencies": {
25
25
  "react": "^16.8 || ^17.0 || ^18.0"