import {
SideNavigation as SideNavigationPrimitive,
SideNavigationItemProvider as ItemProviderPrimitive,
useCollapsibleContext,
useSideNavigationContext,
useSideNavigationItem,
useSideNavigationItemContext,
type UseSideNavigationItemProps,
type SideNavigationProviderProps as SideNavigationProviderPrimitiveProps,
} from "@seed-design/react-side-navigation";
import {
sideNavigation,
type SideNavigationVariantProps,
} from "@seed-design/css/recipes/side-navigation";
import {
sideNavigationInset,
type SideNavigationInsetVariantProps,
} from "@seed-design/css/recipes/side-navigation-inset";
import {
sideNavigationMenuItem,
type SideNavigationMenuItemVariantProps,
} from "@seed-design/css/recipes/side-navigation-menu-item";
import { Primitive, type PrimitiveProps } from "@seed-design/react-primitive";
import { createSlotRecipeContext } from "../../utils/createSlotRecipeContext";
import { createRecipeContext } from "../../utils/createRecipeContext";
import { InternalIcon, type InternalIconProps } from "../private/Icon";
import { createWithStateProps } from "../../utils/createWithStateProps";
import { mediaQueries } from "@seed-design/css/breakpoints";
import { composeRefs } from "@radix-ui/react-compose-refs";
import React from "react";
import clsx from "clsx";
import { dataAttr } from "@seed-design/dom-utils";
const { withProvider, withContext, useClassNames } = createSlotRecipeContext(sideNavigation);
const { ClassNamesProvider: ItemClassNamesProvider, withContext: withItemContext } =
createSlotRecipeContext(sideNavigationMenuItem);
const { withContext: withInsetContext } = createRecipeContext(sideNavigationInset);
const withSideNavigationStateProps = createWithStateProps([useSideNavigationContext]);
const withItemStateProps = createWithStateProps([
useSideNavigationContext,
{ useContext: useSideNavigationItemContext, strict: false },
]);
const withItemSlotCollapsibleStateProps = createWithStateProps([
useSideNavigationContext,
{ useContext: useSideNavigationItemContext, strict: false },
{ useContext: useCollapsibleContext, strict: false },
]);
////////////////////////////////////////////////////////////////////////////////////
function ResponsiveCollapseEffect() {
const { setCollapsed } = useSideNavigationContext();
React.useEffect(() => {
const mql = window.matchMedia(mediaQueries.lg);
const handler = (e: MediaQueryListEvent) => {
setCollapsed(!e.matches);
};
mql.addEventListener("change", handler);
return () => mql.removeEventListener("change", handler);
}, [setCollapsed]);
return null;
}
export interface SideNavigationProviderProps extends SideNavigationProviderPrimitiveProps {}
export function SideNavigationProvider(props: SideNavigationProviderProps) {
return (
{props.children}
);
}
SideNavigationProvider.displayName = "SideNavigationProvider";
////////////////////////////////////////////////////////////////////////////////////
export interface SideNavigationRootProps
extends SideNavigationVariantProps,
SideNavigationPrimitive.RootProps {}
export const SideNavigationRoot = withProvider(
SideNavigationPrimitive.Root,
"root",
);
SideNavigationRoot.displayName = "SideNavigationRoot";
////////////////////////////////////////////////////////////////////////////////////
export interface SideNavigationHeaderProps
extends PrimitiveProps,
React.HTMLAttributes {}
export const SideNavigationHeader = withContext(
withSideNavigationStateProps(Primitive.div),
"header",
);
SideNavigationHeader.displayName = "SideNavigationHeader";
////////////////////////////////////////////////////////////////////////////////////
export interface SideNavigationContentProps
extends PrimitiveProps,
React.HTMLAttributes {}
export const SideNavigationContent = React.forwardRef(
({ className, ...props }, forwardedRef) => {
const classNames = useClassNames();
const { stateProps } = useSideNavigationContext();
const ref = React.useRef(null);
const [scrolled, setScrolled] = React.useState(false);
React.useEffect(() => {
const element = ref.current;
if (!element) return;
const check = () => setScrolled(element.scrollTop > 0);
check();
element.addEventListener("scroll", check);
const observer = new ResizeObserver(check);
observer.observe(element);
return () => {
element.removeEventListener("scroll", check);
observer.disconnect();
};
}, []);
return (
);
},
);
SideNavigationContent.displayName = "SideNavigationContent";
////////////////////////////////////////////////////////////////////////////////////
export interface SideNavigationFooterProps
extends PrimitiveProps,
React.HTMLAttributes {}
export const SideNavigationFooter = withContext(
withSideNavigationStateProps(Primitive.div),
"footer",
);
SideNavigationFooter.displayName = "SideNavigationFooter";
////////////////////////////////////////////////////////////////////////////////////
export interface SideNavigationGroupProps
extends PrimitiveProps,
React.HTMLAttributes {}
export const SideNavigationGroup = withContext(
withSideNavigationStateProps(Primitive.div),
"group",
);
SideNavigationGroup.displayName = "SideNavigationGroup";
////////////////////////////////////////////////////////////////////////////////////
export interface SideNavigationGroupLabelProps
extends PrimitiveProps,
React.HTMLAttributes {}
export const SideNavigationGroupLabel = withContext(
withSideNavigationStateProps(Primitive.div),
"groupLabel",
);
SideNavigationGroupLabel.displayName = "SideNavigationGroupLabel";
////////////////////////////////////////////////////////////////////////////////////
export interface SideNavigationItemProps
extends SideNavigationMenuItemVariantProps,
UseSideNavigationItemProps,
PrimitiveProps,
React.HTMLAttributes {}
export const SideNavigationItem = React.forwardRef(
({ current, disabled, className, ...props }, ref) => {
const [variantProps, restProps] = sideNavigationMenuItem.splitVariantProps(props);
const classNames = sideNavigationMenuItem(variantProps);
const { stateProps: sideNavStateProps } = useSideNavigationContext();
const api = useSideNavigationItem({ current, disabled });
return (
);
},
);
SideNavigationItem.displayName = "SideNavigationItem";
////////////////////////////////////////////////////////////////////////////////////
export interface SideNavigationItemLabelProps
extends PrimitiveProps,
React.HTMLAttributes {}
export const SideNavigationItemLabel = withItemContext<
HTMLSpanElement,
SideNavigationItemLabelProps
>(withItemStateProps(Primitive.span), "label");
SideNavigationItemLabel.displayName = "SideNavigationItemLabel";
////////////////////////////////////////////////////////////////////////////////////
export interface SideNavigationItemPrefixIconProps extends InternalIconProps {}
export const SideNavigationItemPrefixIcon = withItemContext<
SVGSVGElement,
SideNavigationItemPrefixIconProps
>(withItemStateProps(InternalIcon), "prefixIcon");
////////////////////////////////////////////////////////////////////////////////////
export interface SideNavigationItemSuffixIconProps extends InternalIconProps {}
export const SideNavigationItemSuffixIcon = withItemContext<
SVGSVGElement,
SideNavigationItemSuffixIconProps
>(withItemSlotCollapsibleStateProps(InternalIcon), "suffixIcon");
////////////////////////////////////////////////////////////////////////////////////
export interface SideNavigationItemCollapsibleRootProps
extends SideNavigationMenuItemVariantProps,
SideNavigationPrimitive.ItemCollapsibleRootProps {}
export const SideNavigationItemCollapsibleRoot = React.forwardRef<
HTMLDivElement,
SideNavigationItemCollapsibleRootProps
>(({ children, ...props }, ref) => {
const [variantProps, restProps] = sideNavigationMenuItem.splitVariantProps(props);
const classNames = sideNavigationMenuItem(variantProps);
return (
{children}
);
});
SideNavigationItemCollapsibleRoot.displayName = "SideNavigationItemCollapsibleRoot";
////////////////////////////////////////////////////////////////////////////////////
export interface SideNavigationItemCollapsibleTriggerProps
extends UseSideNavigationItemProps,
SideNavigationPrimitive.ItemCollapsibleTriggerProps {}
export const SideNavigationItemCollapsibleTrigger = React.forwardRef<
HTMLButtonElement,
SideNavigationItemCollapsibleTriggerProps
>(({ current, disabled, className, ...props }, ref) => {
const classNames = sideNavigationMenuItem();
const { stateProps: sideNavStateProps } = useSideNavigationContext();
const api = useSideNavigationItem({ current, disabled });
return (
);
});
SideNavigationItemCollapsibleTrigger.displayName = "SideNavigationItemCollapsibleTrigger";
////////////////////////////////////////////////////////////////////////////////////
export interface SideNavigationItemCollapsibleContentProps
extends SideNavigationPrimitive.ItemCollapsibleContentProps {}
export const SideNavigationItemCollapsibleContent = withItemContext<
HTMLDivElement,
SideNavigationItemCollapsibleContentProps
>(SideNavigationPrimitive.ItemCollapsibleContent, "panel");
SideNavigationItemCollapsibleContent.displayName = "SideNavigationItemCollapsibleContent";
////////////////////////////////////////////////////////////////////////////////////
export interface SideNavigationTriggerProps extends SideNavigationPrimitive.TriggerProps {}
export const SideNavigationTrigger = withContext(
SideNavigationPrimitive.Trigger,
"trigger",
);
SideNavigationTrigger.displayName = "SideNavigationTrigger";
////////////////////////////////////////////////////////////////////////////////////
export interface SideNavigationInsetProps
extends SideNavigationInsetVariantProps,
PrimitiveProps,
React.HTMLAttributes {}
export const SideNavigationInset = withInsetContext(
Primitive.div,
);