@kobalte/core
Version:
Unstyled components and primitives for building accessible web apps and design systems with SolidJS.
425 lines (409 loc) • 11.4 kB
JSX
import {
Popper,
PopperArrow
} from "./2CTBMVJ4.jsx";
import {
createFocusScope
} from "./7A3GDF4Y.jsx";
import {
createHideOutside
} from "./FBCYWU27.jsx";
import {
DismissableLayer
} from "./3VFJM5NZ.jsx";
import {
createDisclosureState
} from "./E53DB7BS.jsx";
import {
ButtonRoot
} from "./UKTBL2JL.jsx";
import {
createRegisterId
} from "./JNCCF6MP.jsx";
import {
Polymorphic
} from "./FLVHQV4A.jsx";
import {
__export
} from "./5WXHJDCZ.jsx";
// src/popover/index.tsx
var popover_exports = {};
__export(popover_exports, {
Anchor: () => PopoverAnchor,
Arrow: () => PopperArrow,
CloseButton: () => PopoverCloseButton,
Content: () => PopoverContent,
Description: () => PopoverDescription,
Popover: () => Popover,
Portal: () => PopoverPortal,
Root: () => PopoverRoot,
Title: () => PopoverTitle,
Trigger: () => PopoverTrigger,
usePopoverContext: () => usePopoverContext
});
// src/popover/popover-anchor.tsx
import { mergeRefs } from "@kobalte/utils";
import { splitProps } from "solid-js";
// src/popover/popover-context.tsx
import { createContext, useContext } from "solid-js";
var PopoverContext = createContext();
function usePopoverContext() {
const context = useContext(PopoverContext);
if (context === void 0) {
throw new Error(
"[kobalte]: `usePopoverContext` must be used within a `Popover` component"
);
}
return context;
}
// src/popover/popover-anchor.tsx
function PopoverAnchor(props) {
const context = usePopoverContext();
const [local, others] = splitProps(props, ["ref"]);
return <Polymorphic
as="div"
ref={mergeRefs(context.setDefaultAnchorRef, local.ref)}
{...context.dataset()}
{...others}
/>;
}
// src/popover/popover-close-button.tsx
import { callHandler } from "@kobalte/utils";
import {
splitProps as splitProps2
} from "solid-js";
function PopoverCloseButton(props) {
const context = usePopoverContext();
const [local, others] = splitProps2(props, [
"aria-label",
"onClick"
]);
const onClick = (e) => {
callHandler(e, local.onClick);
context.close();
};
return <ButtonRoot
aria-label={local["aria-label"] || context.translations().dismiss}
onClick={onClick}
{...context.dataset()}
{...others}
/>;
}
// src/popover/popover-content.tsx
import {
contains,
focusWithoutScrolling,
mergeDefaultProps,
mergeRefs as mergeRefs2
} from "@kobalte/utils";
import {
Show,
createEffect,
onCleanup,
splitProps as splitProps3
} from "solid-js";
import { combineStyle } from "@solid-primitives/props";
import createPreventScroll from "solid-prevent-scroll";
function PopoverContent(props) {
let ref;
const context = usePopoverContext();
const mergedProps = mergeDefaultProps(
{
id: context.generateId("content")
},
props
);
const [local, others] = splitProps3(mergedProps, [
"ref",
"style",
"onOpenAutoFocus",
"onCloseAutoFocus",
"onPointerDownOutside",
"onFocusOutside",
"onInteractOutside"
]);
let isRightClickOutside = false;
let hasInteractedOutside = false;
let hasPointerDownOutside = false;
const onCloseAutoFocus = (e) => {
local.onCloseAutoFocus?.(e);
if (context.isModal()) {
e.preventDefault();
if (!isRightClickOutside) {
focusWithoutScrolling(context.triggerRef());
}
} else {
if (!e.defaultPrevented) {
if (!hasInteractedOutside) {
focusWithoutScrolling(context.triggerRef());
}
e.preventDefault();
}
hasInteractedOutside = false;
hasPointerDownOutside = false;
}
};
const onPointerDownOutside = (e) => {
local.onPointerDownOutside?.(e);
if (context.isModal()) {
isRightClickOutside = e.detail.isContextMenu;
}
};
const onFocusOutside = (e) => {
local.onFocusOutside?.(e);
if (context.isOpen() && context.isModal()) {
e.preventDefault();
}
};
const onInteractOutside = (e) => {
local.onInteractOutside?.(e);
if (context.isModal()) {
return;
}
if (!e.defaultPrevented) {
hasInteractedOutside = true;
if (e.detail.originalEvent.type === "pointerdown") {
hasPointerDownOutside = true;
}
}
if (contains(context.triggerRef(), e.target)) {
e.preventDefault();
}
if (e.detail.originalEvent.type === "focusin" && hasPointerDownOutside) {
e.preventDefault();
}
};
createHideOutside({
isDisabled: () => !(context.isOpen() && context.isModal()),
targets: () => ref ? [ref] : []
});
createPreventScroll({
element: () => ref ?? null,
enabled: () => context.contentPresent() && context.preventScroll()
});
createFocusScope(
{
trapFocus: () => context.isOpen() && context.isModal(),
onMountAutoFocus: local.onOpenAutoFocus,
onUnmountAutoFocus: onCloseAutoFocus
},
() => ref
);
createEffect(() => onCleanup(context.registerContentId(others.id)));
return <Show when={context.contentPresent()}><Popper.Positioner><DismissableLayer
ref={mergeRefs2((el) => {
context.setContentRef(el);
ref = el;
}, local.ref)}
role="dialog"
tabIndex={-1}
disableOutsidePointerEvents={context.isOpen() && context.isModal()}
excludedElements={[context.triggerRef]}
style={combineStyle(
{
"--kb-popover-content-transform-origin": "var(--kb-popper-content-transform-origin)",
position: "relative"
},
local.style
)}
aria-labelledby={context.titleId()}
aria-describedby={context.descriptionId()}
onPointerDownOutside={onPointerDownOutside}
onFocusOutside={onFocusOutside}
onInteractOutside={onInteractOutside}
onDismiss={context.close}
{...context.dataset()}
{...others}
/></Popper.Positioner></Show>;
}
// src/popover/popover-description.tsx
import { mergeDefaultProps as mergeDefaultProps2 } from "@kobalte/utils";
import {
createEffect as createEffect2,
onCleanup as onCleanup2,
splitProps as splitProps4
} from "solid-js";
function PopoverDescription(props) {
const context = usePopoverContext();
const mergedProps = mergeDefaultProps2(
{
id: context.generateId("description")
},
props
);
const [local, others] = splitProps4(mergedProps, ["id"]);
createEffect2(() => onCleanup2(context.registerDescriptionId(local.id)));
return <Polymorphic
as="p"
id={local.id}
{...context.dataset()}
{...others}
/>;
}
// src/popover/popover-portal.tsx
import { Show as Show2 } from "solid-js";
import { Portal } from "solid-js/web";
function PopoverPortal(props) {
const context = usePopoverContext();
return <Show2 when={context.contentPresent()}><Portal {...props} /></Show2>;
}
// src/popover/popover-root.tsx
import { createGenerateId, mergeDefaultProps as mergeDefaultProps3 } from "@kobalte/utils";
import {
createMemo,
createSignal,
createUniqueId,
splitProps as splitProps5
} from "solid-js";
import createPresence from "solid-presence";
// src/popover/popover.intl.ts
var POPOVER_INTL_TRANSLATIONS = {
// `aria-label` of Popover.CloseButton.
dismiss: "Dismiss"
};
// src/popover/popover-root.tsx
function PopoverRoot(props) {
const defaultId = `popover-${createUniqueId()}`;
const mergedProps = mergeDefaultProps3(
{
id: defaultId,
modal: false,
translations: POPOVER_INTL_TRANSLATIONS
},
props
);
const [local, others] = splitProps5(mergedProps, [
"translations",
"id",
"open",
"defaultOpen",
"onOpenChange",
"modal",
"preventScroll",
"forceMount",
"anchorRef"
]);
const [defaultAnchorRef, setDefaultAnchorRef] = createSignal();
const [triggerRef, setTriggerRef] = createSignal();
const [contentRef, setContentRef] = createSignal();
const [contentId, setContentId] = createSignal();
const [titleId, setTitleId] = createSignal();
const [descriptionId, setDescriptionId] = createSignal();
const disclosureState = createDisclosureState({
open: () => local.open,
defaultOpen: () => local.defaultOpen,
onOpenChange: (isOpen) => local.onOpenChange?.(isOpen)
});
const anchorRef = () => {
return local.anchorRef?.() ?? defaultAnchorRef() ?? triggerRef();
};
const { present: contentPresent } = createPresence({
show: () => local.forceMount || disclosureState.isOpen(),
element: () => contentRef() ?? null
});
const dataset = createMemo(() => ({
"data-expanded": disclosureState.isOpen() ? "" : void 0,
"data-closed": !disclosureState.isOpen() ? "" : void 0
}));
const context = {
translations: () => local.translations ?? POPOVER_INTL_TRANSLATIONS,
dataset,
isOpen: disclosureState.isOpen,
isModal: () => local.modal ?? false,
preventScroll: () => local.preventScroll ?? context.isModal(),
contentPresent,
triggerRef,
contentId,
titleId,
descriptionId,
setDefaultAnchorRef,
setTriggerRef,
setContentRef,
close: disclosureState.close,
toggle: disclosureState.toggle,
generateId: createGenerateId(() => local.id),
registerContentId: createRegisterId(setContentId),
registerTitleId: createRegisterId(setTitleId),
registerDescriptionId: createRegisterId(setDescriptionId)
};
return <PopoverContext.Provider value={context}><Popper anchorRef={anchorRef} contentRef={contentRef} {...others} /></PopoverContext.Provider>;
}
// src/popover/popover-title.tsx
import { mergeDefaultProps as mergeDefaultProps4 } from "@kobalte/utils";
import {
createEffect as createEffect3,
onCleanup as onCleanup3,
splitProps as splitProps6
} from "solid-js";
function PopoverTitle(props) {
const context = usePopoverContext();
const mergedProps = mergeDefaultProps4(
{
id: context.generateId("title")
},
props
);
const [local, others] = splitProps6(mergedProps, ["id"]);
createEffect3(() => onCleanup3(context.registerTitleId(local.id)));
return <Polymorphic
as="h2"
id={local.id}
{...context.dataset()}
{...others}
/>;
}
// src/popover/popover-trigger.tsx
import { callHandler as callHandler2, mergeRefs as mergeRefs3 } from "@kobalte/utils";
import {
splitProps as splitProps7
} from "solid-js";
function PopoverTrigger(props) {
const context = usePopoverContext();
const [local, others] = splitProps7(props, [
"ref",
"onClick",
"onPointerDown"
]);
const onPointerDown = (e) => {
callHandler2(e, local.onPointerDown);
e.preventDefault();
};
const onClick = (e) => {
callHandler2(e, local.onClick);
context.toggle();
};
return <ButtonRoot
ref={mergeRefs3(context.setTriggerRef, local.ref)}
aria-haspopup="dialog"
aria-expanded={context.isOpen()}
aria-controls={context.isOpen() ? context.contentId() : void 0}
onPointerDown={onPointerDown}
onClick={onClick}
{...context.dataset()}
{...others}
/>;
}
// src/popover/index.tsx
var Popover = Object.assign(PopoverRoot, {
Anchor: PopoverAnchor,
Arrow: PopperArrow,
CloseButton: PopoverCloseButton,
Content: PopoverContent,
Description: PopoverDescription,
Portal: PopoverPortal,
Title: PopoverTitle,
Trigger: PopoverTrigger
});
export {
usePopoverContext,
PopoverAnchor,
PopoverCloseButton,
PopoverContent,
PopoverDescription,
PopoverPortal,
PopoverRoot,
PopoverTitle,
PopoverTrigger,
Popover,
popover_exports
};