Files
svelte-headlessui/src/lib/components/popover/PopoverGroup.svelte
Ryan Gossiaux cfe1aaa55e Switch Popover to <Render>
Also fix a bug where PopoverPanel was missing an id
2021-12-20 22:28:46 -08:00

79 lines
2.4 KiB
Svelte

<script lang="ts" context="module">
export interface PopoverGroupContext {
registerPopover(registerbag: PopoverRegisterBag): void;
unregisterPopover(registerbag: PopoverRegisterBag): void;
isFocusWithinPopoverGroup(): boolean;
closeOthers(buttonId: string): void;
}
const POPOVER_GROUP_CONTEXT_NAME = "headlessui-popover-group-context";
export function usePopoverGroupContext(): PopoverGroupContext | undefined {
return getContext(POPOVER_GROUP_CONTEXT_NAME);
}
</script>
<script lang="ts">
import type { PopoverRegisterBag } from "./Popover.svelte";
import { getContext, setContext } from "svelte";
import { forwardEventsBuilder } from "$lib/internal/forwardEventsBuilder";
import { get_current_component } from "svelte/internal";
import type { SupportedAs } from "$lib/internal/elements";
import type { HTMLActionArray } from "$lib/hooks/use-actions";
import Render from "$lib/utils/Render.svelte";
const forwardEvents = forwardEventsBuilder(get_current_component());
export let as: SupportedAs = "div";
export let use: HTMLActionArray = [];
let groupRef: HTMLDivElement | undefined;
let popovers: PopoverRegisterBag[] = [];
function unregisterPopover(registerBag: PopoverRegisterBag) {
popovers = popovers.filter((bag) => bag != registerBag);
}
function registerPopover(registerBag: PopoverRegisterBag) {
popovers = [...popovers, registerBag];
return () => {
unregisterPopover(registerBag);
};
}
function isFocusWithinPopoverGroup() {
let element = document.activeElement as HTMLElement;
if (groupRef?.contains(element)) return true;
// Check if the focus is in one of the button or panel elements. This is important in case you are rendering inside a Portal.
return popovers.some((bag) => {
return (
document.getElementById(bag.buttonId)?.contains(element) ||
document.getElementById(bag.panelId)?.contains(element)
);
});
}
function closeOthers(buttonId: string) {
for (let popover of popovers) {
if (popover.buttonId !== buttonId) popover.close();
}
}
setContext(POPOVER_GROUP_CONTEXT_NAME, {
unregisterPopover,
registerPopover,
isFocusWithinPopoverGroup,
closeOthers,
});
</script>
<Render
{...$$restProps}
{as}
use={[...use, forwardEvents]}
name={"PopoverGroup"}
bind:el={groupRef}
>
<slot />
</Render>