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.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
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