feat(Popover): add controlled in PopoverContext to disable outside click on controlled

This commit is contained in:
p-sw 2024-06-30 22:48:52 +09:00
parent c52a8843e8
commit 7aa0618ae3

View File

@ -2,6 +2,7 @@ import { type AsChild, Slot, type VariantProps, vcn } from "@pswui-lib";
import React, { useContext, useEffect, useRef } from "react"; import React, { useContext, useEffect, useRef } from "react";
interface IPopoverContext { interface IPopoverContext {
controlled: boolean;
opened: boolean; opened: boolean;
} }
@ -10,6 +11,7 @@ const PopoverContext = React.createContext<
>([ >([
{ {
opened: false, opened: false,
controlled: false,
}, },
() => { () => {
if (process.env.NODE_ENV && process.env.NODE_ENV === "development") { if (process.env.NODE_ENV && process.env.NODE_ENV === "development") {
@ -28,12 +30,15 @@ interface PopoverProps extends AsChild {
const Popover = ({ children, opened, asChild }: PopoverProps) => { const Popover = ({ children, opened, asChild }: PopoverProps) => {
const [state, setState] = React.useState<IPopoverContext>({ const [state, setState] = React.useState<IPopoverContext>({
opened: opened ?? false, opened: opened ?? false,
controlled: opened !== undefined,
}); });
useEffect(() => { useEffect(() => {
if (opened !== undefined) { setState((p) => ({
setState((p) => ({ ...p, opened: opened })); ...p,
} controlled: opened !== undefined,
opened: opened !== undefined ? opened : p.opened,
}));
}, [opened]); }, [opened]);
const Comp = asChild ? Slot : "div"; const Comp = asChild ? Slot : "div";
@ -209,11 +214,12 @@ const PopoverContent = React.forwardRef<HTMLDivElement, PopoverContentProps>(
setState((prev) => ({ ...prev, opened: false })); setState((prev) => ({ ...prev, opened: false }));
} }
} }
document.addEventListener("mousedown", handleOutsideClick); !state.controlled &&
document.addEventListener("mousedown", handleOutsideClick);
return () => { return () => {
document.removeEventListener("mousedown", handleOutsideClick); document.removeEventListener("mousedown", handleOutsideClick);
}; };
}, [setState]); }, [state.controlled, setState]);
return ( return (
<div <div