@yamada-ui/react
Version:
React UI components of the Yamada, by the Yamada, for the Yamada built with React and Emotion
308 lines (304 loc) • 10.5 kB
JavaScript
"use client";
import { utils_exports } from "../../utils/index.js";
import { styled } from "../../core/system/factory.js";
import { createSlotComponent } from "../../core/components/create-component.js";
import { CheckIcon } from "../icon/icons/check-icon.js";
import { ChevronRightIcon } from "../icon/icons/chevron-right-icon.js";
import { CircleSmallIcon } from "../icon/icons/circle-small-icon.js";
import { usePopoverProps } from "../popover/use-popover.js";
import { PopoverAnchor, PopoverContent, PopoverRoot, PopoverTrigger } from "../popover/popover.js";
import { menuStyle } from "./menu.style.js";
import { MainMenuContext, MenuContext, MenuDescendantsContext, MenuGroupContext, MenuOptionGroupContext, useMenu, useMenuContext, useMenuGroup, useMenuGroupContext, useMenuItem, useMenuOptionGroup, useMenuOptionItem } from "./use-menu.js";
import { Fragment, useMemo, useState } from "react";
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
//#region src/components/menu/menu.tsx
const { ComponentContext, PropsContext: MenuPropsContext, StyleContext, useComponentContext, usePropsContext: useMenuPropsContext, withContext, useRootComponentProps } = createSlotComponent("menu", menuStyle);
/**
* `Menu` is a component that displays a common dropdown menu.
*
* @see https://yamada-ui.com/docs/components/menu
*/
const MenuRoot = (props) => {
const [styleContext, mergedProps] = useRootComponentProps(props);
const [{ animationScheme, initialFocusRef, offset, placement,...popoverProps }, { children, disabled,...rest }] = usePopoverProps(mergedProps, [
"disabled",
"open",
"defaultOpen",
"onOpen",
"onClose"
]);
const { closeOnSelect, descendants, open, subMenu, subMenuDirection, updateRef, getContentProps, getContextTriggerProps, getSeparatorProps, getTriggerProps, onActiveDescendant, onClose, onCloseRef, onCloseSubMenu, onOpen, onSelect } = useMenu({
disabled,
...rest
});
const mergedPopoverProps = useMemo(() => ({
...popoverProps,
animationScheme: animationScheme ?? (subMenu ? "inline-start" : "block-start"),
autoFocus: !!initialFocusRef,
disabled,
initialFocusRef,
offset: offset ?? (subMenu ? [0, 0] : void 0),
open,
placement: placement ?? (subMenu ? `center-${subMenuDirection}` : "end-start"),
updateRef,
onClose,
onOpen
}), [
animationScheme,
disabled,
initialFocusRef,
offset,
onClose,
onOpen,
open,
placement,
popoverProps,
subMenu,
subMenuDirection,
updateRef
]);
return /* @__PURE__ */ jsx(StyleContext, {
value: styleContext,
children: /* @__PURE__ */ jsx(MenuDescendantsContext, {
value: descendants,
children: /* @__PURE__ */ jsx(MenuContext, {
value: useMemo(() => ({
subMenu,
subMenuDirection,
onActiveDescendant,
onClose,
onCloseSubMenu,
onOpen,
onSelect
}), [
onClose,
onOpen,
onSelect,
onActiveDescendant,
subMenu,
subMenuDirection,
onCloseSubMenu
]),
children: /* @__PURE__ */ jsx(MainMenuContext, {
value: useMemo(() => ({
closeOnSelect,
descendants,
onActiveDescendant,
onCloseRef,
onSelect
}), [
closeOnSelect,
descendants,
onActiveDescendant,
onCloseRef,
onSelect
]),
children: /* @__PURE__ */ jsx(ComponentContext, {
value: useMemo(() => ({
getContentProps,
getContextTriggerProps,
getSeparatorProps,
getTriggerProps
}), [
getContentProps,
getContextTriggerProps,
getSeparatorProps,
getTriggerProps
]),
children: /* @__PURE__ */ jsx(PopoverRoot, {
...mergedPopoverProps,
children
})
})
})
})
})
});
};
const MenuTrigger = withContext(PopoverTrigger, "trigger")(void 0, (props) => {
const { getTriggerProps } = useComponentContext();
return (0, utils_exports.cast)(getTriggerProps((0, utils_exports.cast)(props)));
});
const MenuContextTrigger = withContext(({ children, onContextMenu,...rest }) => {
const [rect, setRect] = useState({
left: 0,
top: 0
});
const { getContextTriggerProps } = useComponentContext();
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(MenuAnchor, { children: /* @__PURE__ */ jsx(styled.div, { style: {
position: "fixed",
...rect
} }) }), /* @__PURE__ */ jsx(styled.div, {
asChild: true,
...getContextTriggerProps({
onContextMenu: (0, utils_exports.handlerAll)(onContextMenu, (ev) => {
setRect({
left: ev.clientX,
top: ev.clientY
});
}),
...rest
}),
children
})] });
}, "contextTrigger")();
const MenuAnchor = withContext(PopoverAnchor, "anchor")();
const MenuContent = withContext(PopoverContent, "content")(void 0, ({ children, footer, header, items = [], footerProps, headerProps, portalProps,...rest }) => {
const { subMenu } = useMenuContext();
const { getContentProps } = useComponentContext();
const computedChildren = useMemo(() => {
if (children) return children;
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
header ? /* @__PURE__ */ jsx(MenuHeader, {
...headerProps,
children: header
}) : null,
items.map((props, index) => {
if ("type" in props) if (props.type === "radio") {
const { type, hasSeparator = true, hasEndSeparator = hasSeparator, hasStartSeparator = hasSeparator, items: items$1 = [],...rest$1 } = props;
return /* @__PURE__ */ jsxs(Fragment, { children: [
hasStartSeparator ? /* @__PURE__ */ jsx(MenuSeparator, {}) : null,
/* @__PURE__ */ jsx(MenuOptionGroup, {
type,
...rest$1,
children: items$1.map(({ label,...rest$2 }, index$1) => /* @__PURE__ */ jsx(MenuOptionItem, {
...rest$2,
children: label
}, index$1))
}),
hasEndSeparator ? /* @__PURE__ */ jsx(MenuSeparator, {}) : null
] }, index);
} else if (props.type === "checkbox") {
const { type, hasSeparator = true, hasEndSeparator = hasSeparator, hasStartSeparator = hasSeparator, items: items$1 = [],...rest$1 } = props;
return /* @__PURE__ */ jsxs(Fragment, { children: [
hasStartSeparator ? /* @__PURE__ */ jsx(MenuSeparator, {}) : null,
/* @__PURE__ */ jsx(MenuOptionGroup, {
type,
...rest$1,
children: items$1.map(({ label,...rest$2 }, index$1) => /* @__PURE__ */ jsx(MenuOptionItem, {
...rest$2,
children: label
}, index$1))
}),
hasEndSeparator ? /* @__PURE__ */ jsx(MenuSeparator, {}) : null
] }, index);
} else return /* @__PURE__ */ jsx(MenuSeparator, {}, index);
else if ("items" in props) {
const { hasSeparator = true, hasEndSeparator = hasSeparator, hasStartSeparator = hasSeparator, items: items$1 = [],...rest$1 } = props;
return /* @__PURE__ */ jsxs(Fragment, { children: [
hasStartSeparator ? /* @__PURE__ */ jsx(MenuSeparator, {}) : null,
/* @__PURE__ */ jsx(MenuGroup, {
...rest$1,
children: items$1.map(({ label,...rest$2 }, index$1) => /* @__PURE__ */ jsx(MenuItem, {
...rest$2,
children: label
}, index$1))
}),
hasEndSeparator ? /* @__PURE__ */ jsx(MenuSeparator, {}) : null
] }, index);
} else if ("value" in props) {
const { label,...rest$1 } = props;
return /* @__PURE__ */ jsx(MenuItem, {
...rest$1,
children: label
}, index);
}
}),
footer ? /* @__PURE__ */ jsx(MenuFooter, {
...footerProps,
children: footer
}) : null
] });
}, [
children,
footer,
footerProps,
header,
headerProps,
items
]);
return {
...getContentProps((0, utils_exports.cast)({
...rest,
children: computedChildren
})),
portalProps: subMenu ? {
...portalProps,
disabled: true
} : portalProps
};
});
const MenuHeader = withContext("div", "header")({ "data-header": "" });
const MenuFooter = withContext("div", "footer")({ "data-footer": "" });
const MenuLabel = withContext("span", "label")(void 0, (props) => {
const { getLabelProps } = useMenuGroupContext();
return getLabelProps(props);
});
const MenuGroup = withContext(({ children, label, labelProps,...rest }) => {
const { getGroupProps, getLabelProps } = useMenuGroup(rest);
return /* @__PURE__ */ jsx(MenuGroupContext, {
value: useMemo(() => ({ getLabelProps }), [getLabelProps]),
children: /* @__PURE__ */ jsxs(styled.div, {
...getGroupProps(),
children: [label ? /* @__PURE__ */ jsx(MenuLabel, {
...labelProps,
children: label
}) : null, children]
})
});
}, "group")();
const MenuOptionGroup = withContext(({ type: typeProp, defaultValue, value: valueProp, onChange: onChangeProp,...rest }) => {
const { type, value, onChange } = useMenuOptionGroup({
type: typeProp,
defaultValue,
value: valueProp,
onChange: onChangeProp
});
return /* @__PURE__ */ jsx(MenuOptionGroupContext, {
value: useMemo(() => ({
type,
value,
onChange
}), [
type,
value,
onChange
]),
children: /* @__PURE__ */ jsx(MenuGroup, { ...rest })
});
}, {
name: "optionGroup",
slot: ["group", "option"]
})();
const MenuItem = withContext(({ children,...rest }) => {
const { subMenuTrigger, getItemProps } = useMenuItem(rest);
return /* @__PURE__ */ jsxs(styled.div, {
...getItemProps(),
children: [children, subMenuTrigger ? /* @__PURE__ */ jsx(MenuIndicator, {
as: ChevronRightIcon,
ms: "auto"
}) : null]
});
}, "item")();
const MenuOptionItem = withContext(({ children, icon,...rest }) => {
const { type, getIndicatorProps, getOptionItemProps } = useMenuOptionItem(rest);
return /* @__PURE__ */ jsxs(styled.div, {
...getOptionItemProps(),
children: [/* @__PURE__ */ jsx(MenuIndicator, {
...getIndicatorProps(),
children: icon || (type === "radio" ? /* @__PURE__ */ jsx(CircleSmallIcon, { fill: "currentColor" }) : /* @__PURE__ */ jsx(CheckIcon, {}))
}), children]
});
}, {
name: "optionItem",
slot: ["item", "option"]
})();
const MenuIndicator = withContext("div", "indicator")();
const MenuCommand = withContext("kbd", "command")();
const MenuSeparator = withContext("hr", "separator")(void 0, (props) => {
const { getSeparatorProps } = useComponentContext();
return getSeparatorProps(props);
});
//#endregion
export { MenuAnchor, MenuCommand, MenuContent, MenuContextTrigger, MenuFooter, MenuGroup, MenuHeader, MenuIndicator, MenuItem, MenuLabel, MenuOptionGroup, MenuOptionItem, MenuPropsContext, MenuRoot, MenuSeparator, MenuTrigger, useMenuPropsContext };
//# sourceMappingURL=menu.js.map