If you think its ok, you can add hook like this in examples. #225
Replies: 4 comments
-
or Hook:
Component:
|
Beta Was this translation helpful? Give feedback.
-
@kamilduleba Thanks for the nice hook suggestions! 😄 In your first example, I'm a little confused by this: ...
if (element) {
if (!containerElements.includes(element)) {
setContainerElements([element]);
}
} else if (element) {
... It seems like there's a typo there because if I like your second suggestion better, though it only seems to work with a single container element. But I suppose it's elegant that way. I would be nice to enhance I feel like the second example is on the right track. If we could refine/enhance it by passing-in the trap options and figure out a way to provide multi-container support, we could add this to the library as the functional component "way"! We might also want to check that useEffect(() => {
if (!focusTrap.current) {
prevContainer.current = containerRef.current;
if (containerRef.current) {
focusTrap.current = ...
... |
Beta Was this translation helpful? Give feedback.
-
We can provide options by passing object to useFocuseTrap function. Example in code:
|
Beta Was this translation helpful? Give feedback.
-
Thanks for giving it a shot with options and multiple containers. Multiple containers is a challenge. In this solution, there's a limit to the number of containers. I'm not sure how we could make it support an arbitrary number of containers. I'm not sure React supports declaring refs in a loop (i.e. one for each selector you provide). 🤔 Unless we used a single ref with multiple "refs" inside of it: //
// useFocusTrap.js
//
import { useRef, useEffect } from 'react';
import { createFocusTrap } from 'focus-trap';
import { difference } from 'lodash'; // NOTE: it should be easy enough to implement a cheap version of this here to avoid the import
// convert Array<string> to { [string]: { current: null } } map
const mapSelectors = (selectors) => selectors.reduce((ref, sel) => {
ref[sel] = { current: null };
return ref;
}, {});
const useFocusTrap = (options, selectors = []) => {
const trapSelectors = useRef(selectors.concat());
const prevContainer = useRef(null);
const focusTrap = useRef(null);
useEffect(() => {
if (!focusTrap.current) {
focusTrap.current = createFocusTrap(
trapSelectors.current,
options,
);
focusTrap.current.activate();
} else if (trapSelectors.current.length != selectors.length || difference(trapSelectors.current, selectors).length > 0) {
trapSelectors.current = selectors.concat();
focusTrap.current.updateContainerElements(trapSelectors.current);
}
});
useEffect(() => {
return () => {
if (focusTrap.current) {
focusTrap.current.deactivate();
focusTrap.current = null;
}
};
}, []);
return focusTrap.current;
};
export default useFocusTrap; //
// Component.js
//
import useFocusTrap from './useFocusTrap';
export default function Component() {
useFocusTrap(
{
allowOutsideClick() {
return true;
},
},
['#container1', '#container2'],
);
return (
<>
<div id="container1">
<button type="button">Click id 1</button>
</div>
<div>
<button type="button">Im not working</button>
</div>
<div id="container2">
<button type="button">Click id 2</button>
</div>
</>
) WDYT? It does only use selectors, though, but that seems easier to manage in this case. I haven't tested this as live code, though, so it may not work. Not 100% sure. |
Beta Was this translation helpful? Give feedback.
-
Hello, using trap like this seems clean. So if you think its good idea you can add it to examples or sth.
Hook:
In component:
cheers, great lib :)
Beta Was this translation helpful? Give feedback.
All reactions