@kobalte/core
Version:
Unstyled components and primitives for building accessible web apps and design systems with SolidJS.
226 lines (221 loc) • 6.13 kB
JSX
import {
MenuRoot,
MenuTrigger,
MenubarContext,
useMenubarContext,
useOptionalMenuContext
} from "./LEK3K6R3.jsx";
import {
createInteractOutside
} from "./MGQGUY64.jsx";
import {
createControllableSignal
} from "./FN6EICGO.jsx";
import {
Polymorphic
} from "./FLVHQV4A.jsx";
// src/menubar/menubar-menu.tsx
import { mergeDefaultProps } from "@kobalte/utils";
import { createUniqueId, splitProps } from "solid-js";
function MenubarMenu(props) {
const menubarContext = useMenubarContext();
const mergedProps = mergeDefaultProps(
{
modal: false
},
props
);
const [local, others] = splitProps(mergedProps, ["value"]);
const uniqueid = createUniqueId();
const defaultId = menubarContext.generateId(`menubar-menu-${uniqueid}`);
const mergedPropsWithId = mergeDefaultProps({ id: defaultId }, others);
return <MenuRoot value={local.value ?? uniqueid} {...mergedPropsWithId} />;
}
// src/menubar/menubar-root.tsx
import {
contains,
createGenerateId,
mergeDefaultProps as mergeDefaultProps2,
mergeRefs
} from "@kobalte/utils";
import {
createEffect,
createMemo,
createSignal,
createUniqueId as createUniqueId2,
onCleanup,
splitProps as splitProps2
} from "solid-js";
import { isServer } from "solid-js/web";
function MenubarRoot(props) {
let ref;
const defaultId = `menubar-${createUniqueId2()}`;
const mergedProps = mergeDefaultProps2(
{ id: defaultId, loop: true, orientation: "horizontal" },
props
);
const [local, others] = splitProps2(
mergedProps,
[
"ref",
"value",
"defaultValue",
"onValueChange",
"loop",
"focusOnAlt",
"autoFocusMenu",
"onAutoFocusMenuChange",
"orientation"
]
);
const [value, setValue] = createControllableSignal(
{
value: () => local.value,
defaultValue: () => local.defaultValue,
onChange: (value2) => local.onValueChange?.(value2)
}
);
const [lastValue, setLastValue] = createSignal();
const [menuRefs, setMenuRefs] = createSignal(
/* @__PURE__ */ new Map()
);
const [autoFocusMenu, setAutoFocusMenu] = createControllableSignal({
value: () => local.autoFocusMenu,
defaultValue: () => false,
onChange: local.onAutoFocusMenuChange
});
const expanded = () => {
return value() && autoFocusMenu() && !value()?.includes("link-trigger-");
};
const dataset = createMemo(() => ({
"data-expanded": expanded() ? "" : void 0,
"data-closed": !expanded() ? "" : void 0
}));
const context = {
dataset,
value,
setValue,
lastValue,
setLastValue,
menus: () => /* @__PURE__ */ new Set([...menuRefs().keys()]),
menuRefs: () => [...menuRefs().values()].flat(),
menuRefMap: () => menuRefs(),
registerMenu: (value2, refs) => {
setMenuRefs((prev) => {
const map = /* @__PURE__ */ new Map();
prev.forEach((value3, key) => map.set(key, value3));
map.set(value2, refs);
return map;
});
},
unregisterMenu: (value2) => {
setMenuRefs((prev) => {
prev.delete(value2);
const map = /* @__PURE__ */ new Map();
prev.forEach((value3, key) => map.set(key, value3));
return map;
});
},
nextMenu: () => {
const menusArray = [...menuRefs().keys()];
if (value() == null) {
setValue(menusArray[0]);
return;
}
const currentIndex = menusArray.indexOf(value());
if (currentIndex === menusArray.length - 1) {
if (local.loop)
setValue(menusArray[0]);
return;
}
setValue(menusArray[currentIndex + 1]);
},
previousMenu: () => {
const menusArray = [...menuRefs().keys()];
if (value() == null) {
setValue(menusArray[0]);
return;
}
const currentIndex = menusArray.indexOf(value());
if (currentIndex === 0) {
if (local.loop)
setValue(menusArray[menusArray.length - 1]);
return;
}
setValue(menusArray[currentIndex - 1]);
},
closeMenu: () => {
setAutoFocusMenu(false);
setValue(void 0);
},
autoFocusMenu: () => autoFocusMenu(),
setAutoFocusMenu,
generateId: createGenerateId(() => others.id),
orientation: () => local.orientation
};
createEffect(() => {
if (value() == null)
setAutoFocusMenu(false);
});
createInteractOutside(
{
onInteractOutside: () => {
context.closeMenu();
setTimeout(() => context.closeMenu());
},
shouldExcludeElement: (element) => {
return [ref, ...menuRefs().values()].flat().some((ref2) => contains(ref2, element));
}
},
() => ref
);
const keydownHandler = (e) => {
if (e.key === "Alt") {
e.preventDefault();
e.stopPropagation();
if (context.value() === void 0)
context.nextMenu();
else
context.closeMenu();
}
};
createEffect(() => {
if (isServer)
return;
if (local.focusOnAlt)
window.addEventListener("keydown", keydownHandler);
else
window.removeEventListener("keydown", keydownHandler);
onCleanup(() => {
window.removeEventListener("keydown", keydownHandler);
});
});
createEffect(() => {
if (value() != null)
setLastValue(value());
});
return <MenubarContext.Provider value={context}><Polymorphic
as="div"
ref={mergeRefs((el) => ref = el, local.ref)}
role="menubar"
data-orientation={local.orientation}
aria-orientation={local.orientation}
{...others}
/></MenubarContext.Provider>;
}
// src/menubar/menubar-trigger.tsx
import { createUniqueId as createUniqueId3 } from "solid-js";
function MenubarTrigger(props) {
const menubarContext = useMenubarContext();
const menuContext = useOptionalMenuContext();
if (menuContext === void 0 && Object.hasOwn(props, "href")) {
const id = menubarContext.generateId("link-trigger-") + createUniqueId3();
return <MenubarMenu value={id}><MenuTrigger {...props} /></MenubarMenu>;
}
return MenuTrigger(props);
}
export {
MenubarMenu,
MenubarRoot,
MenubarTrigger
};