import { bottomSheetHandle } from "@seed-design/css/recipes/bottom-sheet-handle";
import { menuSheet, type MenuSheetVariantProps } from "@seed-design/css/recipes/menu-sheet";
import {
menuSheetItem,
type MenuSheetItemVariantProps,
} from "@seed-design/css/recipes/menu-sheet-item";
import { Drawer } from "@seed-design/react-drawer";
import { Primitive, type PrimitiveProps } from "@seed-design/react-primitive";
import clsx from "clsx";
import * as React from "react";
import { createSlotRecipeContext } from "../../utils/createSlotRecipeContext";
const { withContext, useClassNames, ClassNamesProvider } = createSlotRecipeContext(menuSheet);
const {
PropsProvider: ItemPropsProvider,
useProps: useItemProps,
withContext: withItemContext,
ClassNamesProvider: ItemClassNamesProvider,
} = createSlotRecipeContext(menuSheetItem);
////////////////////////////////////////////////////////////////////////////////////
// Allowlist only the Drawer props that fit a bottom menu sheet, so the public surface
// stays stable if Drawer changes or its implementation is swapped later. Intentionally
// left out: `direction` (forced "bottom" below so the bottom-only recipe transform holds),
// `dismissible` (no default close button → would trap users), and `modal` (omitted so it
// stays at Drawer's default `true`, keeping the focus trap and aria-modal contract on the
// action list).
export interface SwipeableMenuSheetRootProps
extends MenuSheetVariantProps,
Pick<
Drawer.RootProps,
| "children"
| "open"
| "defaultOpen"
| "onOpenChange"
| "closeOnEscape"
| "closeOnInteractOutside"
| "lazyMount"
| "unmountOnExit"
| "onAnimationEnd"
> {}
// Forces `direction="bottom"` so the bottom-only recipe transform isn't broken.
export function SwipeableMenuSheetRoot(props: SwipeableMenuSheetRootProps) {
const [variantProps, otherProps] = menuSheet.splitVariantProps({
lazyMount: true,
unmountOnExit: true,
...props,
});
const classNames = menuSheet(variantProps);
return (
);
}
////////////////////////////////////////////////////////////////////////////////////
export interface SwipeableMenuSheetTriggerProps extends Drawer.TriggerProps {}
export const SwipeableMenuSheetTrigger = Drawer.Trigger;
////////////////////////////////////////////////////////////////////////////////////
export interface SwipeableMenuSheetPositionerProps extends Drawer.PositionerProps {}
export const SwipeableMenuSheetPositioner = withContext<
HTMLDivElement,
SwipeableMenuSheetPositionerProps
>(Drawer.Positioner, "positioner");
////////////////////////////////////////////////////////////////////////////////////
export interface SwipeableMenuSheetBackdropProps extends Drawer.BackdropProps {}
export const SwipeableMenuSheetBackdrop = withContext<
HTMLDivElement,
SwipeableMenuSheetBackdropProps
>(Drawer.Backdrop, "backdrop");
////////////////////////////////////////////////////////////////////////////////////
export interface SwipeableMenuSheetContentProps
extends Drawer.ContentProps,
Pick {}
export const SwipeableMenuSheetContent = React.forwardRef<
HTMLDivElement,
SwipeableMenuSheetContentProps
>(({ className, ...props }, ref) => {
const [variantProps, otherProps] = menuSheetItem.splitVariantProps(props);
const classNames = useClassNames();
return (
);
});
SwipeableMenuSheetContent.displayName = "SwipeableMenuSheetContent";
////////////////////////////////////////////////////////////////////////////////////
// `preventCycle` only applies when snap points are configured, and
// SwipeableMenuSheet omits snap points from its Root API.
export interface SwipeableMenuSheetHandleProps
extends PrimitiveProps,
Omit {}
export const SwipeableMenuSheetHandle = React.forwardRef<
HTMLDivElement,
SwipeableMenuSheetHandleProps
>(({ className, ...props }, ref) => {
const classNames = bottomSheetHandle();
return (
);
});
SwipeableMenuSheetHandle.displayName = "SwipeableMenuSheetHandle";
////////////////////////////////////////////////////////////////////////////////////
export interface SwipeableMenuSheetHeaderProps extends Drawer.HeaderProps {}
export const SwipeableMenuSheetHeader = withContext(
Drawer.Header,
"header",
);
////////////////////////////////////////////////////////////////////////////////////
export interface SwipeableMenuSheetTitleProps extends Drawer.TitleProps {}
export const SwipeableMenuSheetTitle = withContext<
HTMLHeadingElement,
SwipeableMenuSheetTitleProps
>(Drawer.Title, "title");
SwipeableMenuSheetTitle.displayName = "SwipeableMenuSheetTitle";
////////////////////////////////////////////////////////////////////////////////////
export interface SwipeableMenuSheetDescriptionProps extends Drawer.DescriptionProps {}
export const SwipeableMenuSheetDescription = withContext<
HTMLParagraphElement,
SwipeableMenuSheetDescriptionProps
>(Drawer.Description, "description");
////////////////////////////////////////////////////////////////////////////////////
export interface SwipeableMenuSheetListProps
extends PrimitiveProps,
React.HTMLAttributes {}
export const SwipeableMenuSheetList = withContext(
Primitive.div,
"list",
);
////////////////////////////////////////////////////////////////////////////////////
export interface SwipeableMenuSheetGroupProps
extends PrimitiveProps,
React.HTMLAttributes,
Pick {}
export const SwipeableMenuSheetGroup = React.forwardRef<
HTMLDivElement,
SwipeableMenuSheetGroupProps
>(({ className, ...props }, ref) => {
const [variantProps, otherProps] = menuSheetItem.splitVariantProps(props);
const parentProps = useItemProps();
const classNames = useClassNames();
return (
);
});
SwipeableMenuSheetGroup.displayName = "SwipeableMenuSheetGroup";
////////////////////////////////////////////////////////////////////////////////////
export interface SwipeableMenuSheetItemProps
extends PrimitiveProps,
MenuSheetItemVariantProps,
React.HTMLAttributes {}
export const SwipeableMenuSheetItem = React.forwardRef<
HTMLButtonElement,
SwipeableMenuSheetItemProps
>(({ className: propClassName, ...props }, ref) => {
const [variantProps, otherProps] = menuSheetItem.splitVariantProps(props);
const parentProps = useItemProps();
const classNames = menuSheetItem({ ...parentProps, ...variantProps });
return (
);
});
SwipeableMenuSheetItem.displayName = "SwipeableMenuSheetItem";
export interface SwipeableMenuSheetItemContentProps
extends PrimitiveProps,
React.HTMLAttributes {}
export const SwipeableMenuSheetItemContent = withItemContext<
HTMLDivElement,
SwipeableMenuSheetItemContentProps
>(Primitive.div, "content");
export interface SwipeableMenuSheetItemLabelProps
extends PrimitiveProps,
React.HTMLAttributes {}
export const SwipeableMenuSheetItemLabel = withItemContext<
HTMLSpanElement,
SwipeableMenuSheetItemLabelProps
>(Primitive.span, "label");
export interface SwipeableMenuSheetItemDescriptionProps
extends PrimitiveProps,
React.HTMLAttributes {}
export const SwipeableMenuSheetItemDescription = withItemContext<
HTMLSpanElement,
SwipeableMenuSheetItemDescriptionProps
>(Primitive.span, "description");
////////////////////////////////////////////////////////////////////////////////////
export interface SwipeableMenuSheetFooterProps
extends PrimitiveProps,
React.HTMLAttributes {}
export const SwipeableMenuSheetFooter = withContext(
Primitive.div,
"footer",
);
////////////////////////////////////////////////////////////////////////////////////
export interface SwipeableMenuSheetCloseButtonProps extends Drawer.CloseButtonProps {}
/**
* Visible button that closes the swipeable menu sheet.
*/
export const SwipeableMenuSheetCloseButton = withContext<
HTMLButtonElement,
SwipeableMenuSheetCloseButtonProps
>(Drawer.CloseButton, "closeButton");