@stratakit/structures
Version:
Medium-sized component structures for the Strata design system
294 lines (293 loc) • 8.88 kB
JavaScript
import { c as _c } from "react-compiler-runtime";
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
import * as React from "react";
import { Button as ButtonAk } from "@ariakit/react/button";
import { Menu, MenuButton, MenuGroup, MenuGroupLabel, MenuItem, MenuItemCheckbox, MenuProvider, useMenuContext, useMenuStore } from "@ariakit/react/menu";
import { useStoreState } from "@ariakit/react/store";
import { Button, Kbd, Text } from "@stratakit/bricks";
import { DisclosureArrow, Dot, predefinedSymbols } from "@stratakit/bricks/secret-internals";
import { Icon } from "@stratakit/foundations";
import { forwardRef, usePopoverApi, useSafeContext, useUnreactiveCallback } from "@stratakit/foundations/secret-internals";
import cx from "classnames";
import { Checkmark, ChevronRight } from "./~utils.icons.js";
import * as ListItem from "./~utils.ListItem.js";
import { useInit } from "./~utils.useInit.js";
function DropdownMenuProvider(props) {
const $ = _c(6);
useInit();
const {
children,
placement,
open,
setOpen,
defaultOpen
} = props;
let t0;
if ($[0] !== children || $[1] !== defaultOpen || $[2] !== open || $[3] !== placement || $[4] !== setOpen) {
t0 = jsx(MenuProvider, {
defaultOpen,
open,
placement,
setOpen,
children
});
$[0] = children;
$[1] = defaultOpen;
$[2] = open;
$[3] = placement;
$[4] = setOpen;
$[5] = t0;
} else {
t0 = $[5];
}
return t0;
}
const DropdownMenuContent = forwardRef((props, forwardedRef) => {
const context = useMenuContext();
const open = useStoreState(context, "open");
const popoverElement = useStoreState(context, "popoverElement");
const setOpen = useUnreactiveCallback(context?.setOpen);
const popoverProps = usePopoverApi({
element: popoverElement,
open,
setOpen
});
return /* @__PURE__ */ jsx(Menu, {
portal: true,
unmountOnHide: true,
...props,
gutter: 4,
style: {
...popoverProps.style,
...props.style
},
wrapperProps: {
popover: popoverProps.popover
},
className: cx("\u{1F95D}DropdownMenu", props.className),
ref: forwardedRef
});
});
const DropdownMenuButton = forwardRef((props, forwardedRef) => {
const {
accessibleWhenDisabled = true,
children,
...rest
} = props;
const open = useStoreState(useMenuContext(), "open");
return /* @__PURE__ */ jsx(MenuButton, {
accessibleWhenDisabled: true,
...rest,
render: props.render ?? /* @__PURE__ */ jsxs(Button, {
accessibleWhenDisabled,
children: [children, /* @__PURE__ */ jsx(DisclosureArrow, {})]
}),
className: cx("\u{1F95D}DropdownMenuButton", props.className),
"data-has-popover-open": open || void 0,
ref: forwardedRef
});
});
const DropdownMenuItem = forwardRef((props, forwardedRef) => {
const {
label,
shortcuts,
icon,
unstable_dot,
submenu,
...rest
} = props;
const dotId = React.useId();
const defaultSubmenuStore = useMenuStore();
const [submenuStore, setSubmenuStore] = React.useState();
const store = submenuStore ?? defaultSubmenuStore;
const open = useStoreState(store, "open");
return /* @__PURE__ */ jsxs(Fragment, {
children: [/* @__PURE__ */ jsxs(MenuItem, {
accessibleWhenDisabled: true,
render: /* @__PURE__ */ jsx(ListItem.Root, {
render: /* @__PURE__ */ jsx(ButtonAk, {
accessibleWhenDisabled: true,
"aria-describedby": dotId,
...rest,
render: submenu ? /* @__PURE__ */ jsx(MenuButton, {
render: props.render ?? /* @__PURE__ */ jsx("button", {}),
store
}) : props.render,
className: cx("\u{1F95D}DropdownMenuItem", props.className),
"data-has-popover-open": open || void 0,
ref: forwardedRef
})
}),
children: [icon ? /* @__PURE__ */ jsx(DropdownMenuIcon, {
icon
}) : null, /* @__PURE__ */ jsx(ListItem.Content, {
render: /* @__PURE__ */ jsx("span", {}),
children: label
}), shortcuts ? /* @__PURE__ */ jsx(DropdownMenuItemShortcuts, {
shortcuts
}) : null, unstable_dot ? /* @__PURE__ */ jsx(ListItem.Decoration, {
render: /* @__PURE__ */ jsx(Dot, {
id: dotId,
className: "\u{1F95D}DropdownMenuItemDot",
children: unstable_dot
})
}) : null, submenu ? /* @__PURE__ */ jsx(ListItem.Decoration, {
className: "\u{1F95D}DropdownMenuItemChevron",
render: /* @__PURE__ */ jsx(ChevronRight, {})
}) : null]
}), /* @__PURE__ */ jsx(DropdownMenuSubmenuContext.Provider, {
value: React.useMemo(() => ({
setStore: setSubmenuStore
}), []),
children: submenu
})]
});
});
const DropdownMenuItemShortcuts = forwardRef((props, forwardedRef) => {
const {
shortcuts,
...rest
} = props;
const shortcutKeys = React.useMemo(() => {
return shortcuts.split("+").map((key) => ({
key: key.trim(),
isSymbol: key in predefinedSymbols
}));
}, [shortcuts]);
return /* @__PURE__ */ jsx(ListItem.Decoration, {
render: /* @__PURE__ */ jsx("span", {}),
...rest,
className: cx("\u{1F95D}DropdownMenuItemShortcuts", props.className),
ref: forwardedRef,
children: shortcutKeys.map(({
key: key_0,
isSymbol
}, index) => {
if (isSymbol) {
return /* @__PURE__ */ jsx(Kbd, {
variant: "ghost",
symbol: key_0
}, `${key_0 + index}`);
}
return (
// biome-ignore lint/suspicious/noArrayIndexKey: The is likely to remain stable.
/* @__PURE__ */ jsx(Kbd, {
variant: "ghost",
children: key_0
}, `${key_0 + index}`)
);
})
});
});
const DropdownMenuIcon = forwardRef((props, forwardedRef) => {
const {
icon,
...rest
} = props;
return /* @__PURE__ */ jsx(ListItem.Decoration, {
render: /* @__PURE__ */ jsx(Icon, {
href: typeof icon === "string" ? icon : void 0,
render: React.isValidElement(icon) ? icon : void 0,
...rest,
ref: forwardedRef
})
});
});
const DropdownMenuCheckboxItem = forwardRef((props, forwardedRef) => {
const {
label,
icon,
defaultChecked,
checked,
onChange,
name,
value = defaultChecked ? "on" : void 0,
// For defaultChecked to work
...rest
} = props;
return /* @__PURE__ */ jsxs(MenuItemCheckbox, {
accessibleWhenDisabled: true,
defaultChecked,
checked,
name,
value,
onChange,
render: /* @__PURE__ */ jsx(ListItem.Root, {
render: /* @__PURE__ */ jsx(ButtonAk, {
accessibleWhenDisabled: true,
...rest,
className: cx("\u{1F95D}DropdownMenuItem", props.className),
ref: forwardedRef
})
}),
children: [icon ? /* @__PURE__ */ jsx(DropdownMenuIcon, {
icon
}) : null, /* @__PURE__ */ jsx(ListItem.Content, {
render: /* @__PURE__ */ jsx("span", {}),
children: label
}), /* @__PURE__ */ jsx(ListItem.Decoration, {
render: /* @__PURE__ */ jsx(Checkmark, {
className: "\u{1F95D}DropdownMenuCheckmark"
})
})]
});
});
const DropdownMenuSubmenuContext = React.createContext(void 0);
const DropdownMenuSubmenu = forwardRef((props, forwardedRef) => {
const {
setStore
} = useSafeContext(DropdownMenuSubmenuContext);
const store = useMenuStore();
React.useEffect(() => {
setStore(store);
return () => setStore(void 0);
}, [store, setStore]);
const parent = useMenuContext();
const popoverElement = useStoreState(parent, "popoverElement");
const portalElement = React.useCallback(() => {
if (!popoverElement?.isConnected) return null;
return popoverElement;
}, [popoverElement]);
return /* @__PURE__ */ jsx(MenuProvider, {
store,
children: /* @__PURE__ */ jsx(Menu, {
store,
portal: true,
portalElement,
preserveTabOrder: false,
...props,
gutter: 2,
shift: -4,
className: cx("\u{1F95D}DropdownMenu", props.className),
ref: forwardedRef
})
});
});
const DropdownMenuGroup = forwardRef((props, forwardedRef) => {
const {
label,
items,
...rest
} = props;
return /* @__PURE__ */ jsxs(MenuGroup, {
...rest,
className: cx("\u{1F95D}DropdownMenuGroup", props.className),
ref: forwardedRef,
children: [/* @__PURE__ */ jsx(MenuGroupLabel, {
className: "\u{1F95D}DropdownMenuGroupLabel",
render: /* @__PURE__ */ jsx(Text, {
variant: "body-sm"
}),
children: label
}), items]
});
});
export {
DropdownMenuButton as Button,
DropdownMenuCheckboxItem as CheckboxItem,
DropdownMenuContent as Content,
DropdownMenuGroup as Group,
DropdownMenuItem as Item,
DropdownMenuProvider as Provider,
DropdownMenuSubmenu as Submenu
};