Skip to content

Commit

Permalink
Merge pull request #637 from wellyshen/fix/multiple-refs-option-not-w…
Browse files Browse the repository at this point in the history
…orking

Fix: set refs via options triggers callback
  • Loading branch information
wellyshen authored Mar 8, 2021
2 parents ec2c98f + d397c8d commit c78b346
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 10 deletions.
21 changes: 19 additions & 2 deletions src/__tests__/useOnclickoutside.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FC, useRef } from "react";
import { FC, useState, useRef } from "react";
import { render, fireEvent, screen } from "@testing-library/react";

import useOnclickOutside, { DEFAULT_IGNORE_CLASS, Callback, Options } from "..";
Expand All @@ -15,12 +15,14 @@ const Compo: FC<Props> = ({
callback,
...options
}: Props) => {
const [show, setShow] = useState(false);
const ref1 = useRef<HTMLDivElement>();
const ref2 = useRef<HTMLDivElement>();
const ref3 = useRef<HTMLDivElement>();
const ref = useOnclickOutside(callback, {
...options,
// @ts-expect-error
refs: refOpt && [ref1, ref2],
refs: refOpt && [ref1, ref2, ref3],
});

return (
Expand All @@ -31,6 +33,11 @@ const Compo: FC<Props> = ({
<div data-testid="ref-2" ref={refOpt ? ref2 : ref}>
<div data-testid="in-1" />
</div>
{/* @ts-expect-error */}
{show && <div data-testid="ref-3" ref={ref3} />}
<button data-testid="btn" type="button" onClick={() => setShow(!show)}>
Toggle
</button>
<div data-testid="out-1" />
<div data-testid="out-2" className={className || DEFAULT_IGNORE_CLASS}>
<div data-testid="out-3" />
Expand Down Expand Up @@ -121,6 +128,16 @@ describe("useOnclickOutside", () => {
}
);

it("should not trigger callback when clicking/touching inside of the dynamic ref", () => {
const cb = renderHelper({ refOpt: true });

fireEvent.click(getByTestId("btn"));
fireEvent.mouseDown(getByTestId("ref-3"));
fireEvent.touchStart(getByTestId("ref-3"));

expect(cb).not.toHaveBeenCalled();
});

it("should trigger callback when clicking/touching outside of the targets", () => {
const cb = renderHelper();
const out = getByTestId("out-1");
Expand Down
19 changes: 11 additions & 8 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ const useOnclickOutside = (
callback: Callback,
{
refs: refsOpt,
disabled = false,
disabled,
eventTypes = ["mousedown", "touchstart"],
excludeScrollbar = false,
excludeScrollbar,
ignoreClass = DEFAULT_IGNORE_CLASS,
detectIFrame = true,
}: Options = {}
Expand All @@ -66,16 +66,19 @@ const useOnclickOutside = (
() => {
if (!refsOpt?.length && !refsState.length) return;

const els: El[] = [];
(refsOpt || refsState).forEach(
({ current }) => current && els.push(current)
);
const getEls = () => {
const els: El[] = [];
(refsOpt || refsState).forEach(
({ current }) => current && els.push(current)
);
return els;
};

const handler = (e: any) => {
if (
!hasIgnoreClass(e, ignoreClass) &&
!(excludeScrollbar && clickedOnScrollbar(e)) &&
els.every((el) => !el.contains(e.target))
getEls().every((el) => !el.contains(e.target))
)
callbackRef.current(e);
};
Expand All @@ -88,7 +91,7 @@ const useOnclickOutside = (
if (
activeElement?.tagName === "IFRAME" &&
!hasIgnoreClass(activeElement, ignoreClass) &&
!els.includes(activeElement as HTMLIFrameElement)
!getEls().includes(activeElement as HTMLIFrameElement)
)
callbackRef.current(e);
}, 0);
Expand Down

0 comments on commit c78b346

Please sign in to comment.