{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "Sidebar",
  "dependencies": [
    "@base-ui/react",
    "cn",
    "lucide-react",
    "rescript-base-ui"
  ],
  "registryDependencies": [
    "@rescript-shadcn/Button",
    "@rescript-shadcn/Icons",
    "@rescript-shadcn/Sheet",
    "@rescript-shadcn/Skeleton",
    "@rescript-shadcn/Tooltip"
  ],
  "files": [
    {
      "path": "registry/base/ui/Sidebar.res",
      "content": "@@jsxConfig({version: 4, mode: \"automatic\", module_: \"BaseUi.BaseUiJsxDOM\"})\n\n@@directive(\"'use client'\")\n\nopen BaseUi.Types\n\n@module(\"cn\")\nexternal cn: (string, option<string>) => string = \"cn\"\n\n@module(\"cn\")\nexternal cn3: (string, string, option<string>) => string = \"cn\"\n\n@module(\"cn\")\nexternal cn4: (string, string, string, string) => string = \"cn\"\n\n@unboxed\ntype state =\n  | @as(\"expanded\") Expanded\n  | @as(\"collapsed\") Collapsed\n\ntype sidebar = {\n  state: state,\n  @as(\"open\") open_: bool,\n  setOpen: (bool => bool) => unit,\n  openMobile: bool,\n  setOpenMobile: (bool => bool) => unit,\n  isMobile: bool,\n  toggleSidebar: unit => unit,\n}\n\ntype browserWindow\ntype mediaQueryList\ntype windowKeyboardEvent\n\n@val external browserWindow: browserWindow = \"window\"\n@val external browserDocument: Dom.document = \"document\"\n@get external windowInnerWidth: browserWindow => int = \"innerWidth\"\n@send external windowMatchMedia: (browserWindow, string) => mediaQueryList = \"matchMedia\"\n@send\nexternal addMediaQueryListener: (mediaQueryList, string, unit => unit) => unit = \"addEventListener\"\n@send\nexternal removeMediaQueryListener: (mediaQueryList, string, unit => unit) => unit =\n  \"removeEventListener\"\n@send\nexternal addWindowListener: (browserWindow, string, windowKeyboardEvent => unit) => unit =\n  \"addEventListener\"\n@send\nexternal removeWindowListener: (browserWindow, string, windowKeyboardEvent => unit) => unit =\n  \"removeEventListener\"\n@get external keyboardEventKey: windowKeyboardEvent => string = \"key\"\n@get external keyboardEventMetaKey: windowKeyboardEvent => bool = \"metaKey\"\n@get external keyboardEventCtrlKey: windowKeyboardEvent => bool = \"ctrlKey\"\n@send external preventDefaultKeyboardEvent: windowKeyboardEvent => unit = \"preventDefault\"\n@set external setDocumentCookie: (Dom.document, string) => unit = \"cookie\"\n@val external mathRandom: unit => float = \"Math.random\"\n\nmodule RenderState = {\n  type t = {slot: string, sidebar: string}\n}\n\nlet sidebarCookieName = \"sidebar_state\"\nlet sidebarCookieMaxAge = 60 * 60 * 24 * 7\nlet sidebarWidth = \"16rem\"\nlet sidebarWidthMobile = \"18rem\"\nlet sidebarWidthIcon = \"3rem\"\nlet sidebarKeyboardShortcut = \"b\"\nlet mobileBreakpoint = 768\n\nlet context: React.Context.t<option<sidebar>> = React.createContext(None)\n\n@throws(JsExn)\nlet use = () =>\n  switch React.useContext(context) {\n  | Some(sidebar) => sidebar\n  | None => JsError.throwWithMessage(\"use must be used within a SidebarProvider.\")\n  }\n\nlet useIsMobile = () => {\n  let (isMobile, setIsMobile) = React.useState(() => false)\n  React.useEffect(() => {\n    let mediaQuery =\n      browserWindow->windowMatchMedia(`(max-width: ${Int.toString(mobileBreakpoint - 1)}px)`)\n    let onChange = () => {\n      let nextIsMobile = browserWindow->windowInnerWidth < mobileBreakpoint\n      setIsMobile(_ => nextIsMobile)\n    }\n\n    mediaQuery->addMediaQueryListener(\"change\", onChange)\n    onChange()\n\n    Some(() => mediaQuery->removeMediaQueryListener(\"change\", onChange))\n  }, [])\n  isMobile\n}\n\n@unboxed\ntype variant =\n  | @as(\"sidebar\") Sidebar\n  | @as(\"floating\") Floating\n  | @as(\"inset\") Inset\n\n@unboxed\ntype side =\n  | @as(\"left\") Left\n  | @as(\"right\") Right\n\n@unboxed\ntype collapsible =\n  | @as(\"offcanvas\") Offcanvas\n  | @as(\"icon\") Icon\n  | @as(\"none\") NotCollapsible\n\ntype props = {\n  ...BaseUi.Types.DomProps.t,\n  side?: side,\n  variant?: variant,\n  collapsible?: collapsible,\n}\n\nlet toDomProps: props => BaseUi.Types.DomProps.t = %raw(`({side, variant, collapsible, ...props}) => props`)\nexternal toSheetProps: BaseUi.Types.DomProps.t => BaseUi.Dialog.Root.props<'payload> = \"%identity\"\n\n@react.componentWithProps(props)\nlet make = (props: props) => {\n  let side = props.side->Option.getOr(Left)\n  let variant = props.variant->Option.getOr(Sidebar)\n  let collapsible = props.collapsible->Option.getOr(Offcanvas)\n  let domProps = toDomProps(props)\n\n  let {isMobile, state, openMobile, setOpenMobile} = use()\n\n  if collapsible == NotCollapsible {\n    <div\n      {...domProps}\n      dataSlot={props.dataSlot->Option.getOr(\"sidebar\")}\n      className={cn(\n        \"bg-sidebar text-sidebar-foreground flex h-full w-(--sidebar-width) flex-col\",\n        props.className,\n      )}\n    />\n  } else if isMobile {\n    let mobileStyle = ReactDOM.Style._dictToStyle(\n      dict{\n        \"--sidebar-width\": sidebarWidthMobile,\n      },\n    )\n    <Sheet\n      {...domProps->toSheetProps}\n      open_={openMobile}\n      onOpenChange={(nextOpen, _) => setOpenMobile(_ => nextOpen)}\n    >\n      <Sheet.Content\n        dir=?{props.dir}\n        dataSidebar=\"sidebar\"\n        dataSlot=\"sidebar\"\n        dataMobile=\"true\"\n        className=\"bg-sidebar text-sidebar-foreground w-(--sidebar-width) p-0 [&>button]:hidden\"\n        side={side == Right ? Sheet.Side.Right : Left}\n        style={mobileStyle}\n        showCloseButton={false}\n      >\n        <Sheet.Header className=\"sr-only\">\n          <Sheet.Title> {\"Sidebar\"->React.string} </Sheet.Title>\n          <Sheet.Description> {\"Displays the mobile sidebar.\"->React.string} </Sheet.Description>\n        </Sheet.Header>\n        <div className=\"flex h-full w-full flex-col\" children=?{props.children} />\n      </Sheet.Content>\n    </Sheet>\n  } else {\n    <div\n      dataState={(state :> string)}\n      dataCollapsible={switch state {\n      | Collapsed => (collapsible :> string)\n      | Expanded => \"\"\n      }}\n      dataSide={(side :> string)}\n      dataVariant={(variant :> string)}\n      dataSlot=\"sidebar\"\n      className=\"group peer text-sidebar-foreground hidden md:block\"\n    >\n      <div\n        dataSlot=\"sidebar-gap\"\n        className={cn4(\n          \"transition-[width] duration-200 ease-linear relative w-(--sidebar-width) bg-transparent\",\n          \"group-data-[collapsible=offcanvas]:w-0\",\n          \"group-data-[side=right]:rotate-180\",\n          switch variant {\n          | Floating\n          | Inset => \"group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]\"\n          | Sidebar => \"group-data-[collapsible=icon]:w-(--sidebar-width-icon)\"\n          },\n        )}\n      />\n      <div\n        {...domProps}\n        dataSlot={props.dataSlot->Option.getOr(\"sidebar-container\")}\n        dataSide={(side :> string)}\n        className={cn3(\n          \"fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear data-[side=left]:left-0 data-[side=left]:group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)] data-[side=right]:right-0 data-[side=right]:group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)] md:flex\",\n          // Adjust the padding for floating and inset variants.\n          switch variant {\n          | Floating\n          | Inset => \"p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]\"\n          | Sidebar => \"group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l\"\n          },\n          props.className,\n        )}\n      >\n        <div\n          dataSidebar=\"sidebar\"\n          dataSlot=\"sidebar-inner\"\n          className=\"bg-sidebar group-data-[variant=floating]:ring-sidebar-border group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:shadow-sm group-data-[variant=floating]:ring-1 flex size-full flex-col\"\n          children=?{props.children}\n        />\n      </div>\n    </div>\n  }\n}\n\nmodule Provider = {\n  type props = {\n    defaultOpen?: bool,\n    onOpenChange?: bool => unit,\n    ...BaseUi.Types.DomProps.t,\n  }\n\n  let toDomProps: props => BaseUi.Types.DomProps.t = %raw(`({defaultOpen, open, onOpenChange, ...props}) => props`)\n\n  @react.componentWithProps(props)\n  let make = (props: props) => {\n    let defaultOpen = props.defaultOpen->Option.getOr(true)\n\n    let isMobile = useIsMobile()\n    let (openMobile, setOpenMobile) = React.useState(() => false)\n    let (open_, setOpen) = React.useState(() => defaultOpen)\n    let open_ = props.open_->Option.getOr(open_)\n    let setOpen = React.useCallback(u => {\n      let nextOpen = u(open_)\n      switch props.onOpenChange {\n      | Some(setOpenProp) => setOpenProp(nextOpen)\n      | None => setOpen(_ => nextOpen)\n      }\n\n      // This sets the cookie to keep the sidebar state.\n      browserDocument->setDocumentCookie(\n        `${sidebarCookieName}=${nextOpen ? \"true\" : \"false\"}; path=/; max-age=${Int.toString(\n            sidebarCookieMaxAge,\n          )}`,\n      )\n    }, (props.onOpenChange, setOpen, open_))\n\n    // Helper to toggle the sidebar.\n    let toggleSidebar = React.useCallback(() => {\n      isMobile ? setOpenMobile(open_ => !open_) : setOpen(open_ => !open_)\n    }, (isMobile, setOpen, setOpenMobile))\n\n    React.useEffect(() => {\n      let handleKeyDown = (event: windowKeyboardEvent) => {\n        if (\n          event->keyboardEventKey == sidebarKeyboardShortcut &&\n            (event->keyboardEventMetaKey || event->keyboardEventCtrlKey)\n        ) {\n          event->preventDefaultKeyboardEvent\n          toggleSidebar()\n        }\n      }\n\n      browserWindow->addWindowListener(\"keydown\", handleKeyDown)\n      Some(() => browserWindow->removeWindowListener(\"keydown\", handleKeyDown))\n    }, [toggleSidebar])\n\n    let contextValue = React.useMemo(() => Some({\n      state: open_ ? Expanded : Collapsed,\n      open_,\n      setOpen,\n      openMobile,\n      setOpenMobile,\n      isMobile,\n      toggleSidebar,\n    }), (open_, setOpen, openMobile, setOpenMobile, isMobile, toggleSidebar))\n\n    let baseStyle = ReactDOM.Style._dictToStyle(\n      dict{\n        \"--sidebar-width\": sidebarWidth,\n        \"--sidebar-width-icon\": sidebarWidthIcon,\n      },\n    )\n    let style = switch props.style {\n    | Some(style) => ReactDOM.Style.combine(baseStyle, style)\n    | None => baseStyle\n    }\n    module ContextProvider = {\n      let make = React.Context.provider(context)\n    }\n    let props = toDomProps(props)\n\n    <ContextProvider value={contextValue}>\n      <div\n        {...props}\n        style\n        dataSlot={props.dataSlot->Option.getOr(\"sidebar-wrapper\")}\n        className={cn(\n          \"group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex min-h-svh w-full\",\n          props.className,\n        )}\n      />\n    </ContextProvider>\n  }\n}\n\nmodule Trigger = {\n  @react.componentWithProps(Button.props)\n  let make = (props: Button.props) => {\n    let {toggleSidebar} = use()\n    <Button\n      {...props}\n      dataSidebar={props.dataSidebar->Option.getOr(\"trigger\")}\n      dataSlot={props.dataSlot->Option.getOr(\"sidebar-trigger\")}\n      variant={props.variant->Option.getOr(Button.Variant.Ghost)}\n      size={props.size->Option.getOr(Button.Size.IconSm)}\n      className={cn(\"\", props.className)}\n      onClick={event => {\n        props.onClick->Option.forEach(onClick => onClick(event))\n        toggleSidebar()\n      }}\n    >\n      <Icons.PanelLeft className=\"\" />\n      <span className=\"sr-only\"> {\"Toggle Sidebar\"->React.string} </span>\n    </Button>\n  }\n}\n\nmodule Rail = {\n  @react.componentWithProps(BaseUi.Types.DomProps.t)\n  let make = (props: BaseUi.Types.DomProps.t) => {\n    let {toggleSidebar} = use()\n\n    <button\n      {...props}\n      dataSidebar={props.dataSidebar->Option.getOr(\"rail\")}\n      dataSlot={props.dataSlot->Option.getOr(\"sidebar-rail\")}\n      ariaLabel={props.ariaLabel->Option.getOr(\"Toggle Sidebar\")}\n      tabIndex={props.tabIndex->Option.getOr(-1)}\n      onClick={switch props.onClick {\n      | Some(onClick) => onClick\n      | None => _ => toggleSidebar()\n      }}\n      title={props.title->Option.getOr(\"Toggle Sidebar\")}\n      className={cn(\n        \"hover:after:bg-sidebar-border absolute inset-y-0 z-20 hidden w-4 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:start-1/2 after:w-[2px] sm:flex ltr:-translate-x-1/2 rtl:-translate-x-1/2 in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize [[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize hover:group-data-[collapsible=offcanvas]:bg-sidebar group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full [[data-side=left][data-collapsible=offcanvas]_&]:-right-2 [[data-side=right][data-collapsible=offcanvas]_&]:-left-2\",\n        props.className,\n      )}\n    />\n  }\n}\n\nmodule Inset = {\n  @react.componentWithProps(BaseUi.Types.DomProps.t)\n  let make = (props: BaseUi.Types.DomProps.t) =>\n    <main\n      {...props}\n      dataSlot={props.dataSlot->Option.getOr(\"sidebar-inset\")}\n      className={cn(\n        \"bg-background md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2 relative flex w-full flex-1 flex-col\",\n        props.className,\n      )}\n    />\n}\n\nmodule Input = {\n  @react.componentWithProps(BaseUi.Input.props)\n  let make = (props: BaseUi.Input.props) =>\n    <BaseUi.Input\n      {...props}\n      dataSlot={props.dataSlot->Option.getOr(\"sidebar-input\")}\n      dataSidebar={props.dataSidebar->Option.getOr(\"input\")}\n      className={cn(\"bg-background h-8 w-full shadow-none\", props.className)}\n    />\n}\n\nmodule Header = {\n  @react.componentWithProps(BaseUi.Types.DomProps.t)\n  let make = (props: BaseUi.Types.DomProps.t) =>\n    <div\n      {...props}\n      dataSlot={props.dataSlot->Option.getOr(\"sidebar-header\")}\n      dataSidebar={props.dataSidebar->Option.getOr(\"header\")}\n      className={cn(\"gap-2 p-2 flex flex-col\", props.className)}\n    />\n}\n\nmodule Footer = {\n  @react.componentWithProps(BaseUi.Types.DomProps.t)\n  let make = (props: BaseUi.Types.DomProps.t) =>\n    <div\n      {...props}\n      dataSlot={props.dataSlot->Option.getOr(\"sidebar-footer\")}\n      dataSidebar={props.dataSidebar->Option.getOr(\"footer\")}\n      className={cn(\"gap-2 p-2 flex flex-col\", props.className)}\n    />\n}\n\nmodule Separator = {\n  @react.componentWithProps(BaseUi.Types.BaseUIComponentProps.t)\n  let make = (props: BaseUi.Types.BaseUIComponentProps.t) =>\n    <BaseUi.Separator\n      {...props}\n      dataSlot={props.dataSlot->Option.getOr(\"sidebar-separator\")}\n      dataSidebar={props.dataSidebar->Option.getOr(\"separator\")}\n      className={cn(\"bg-sidebar-border mx-2 w-auto\", props.className)}\n    />\n}\n\nmodule Content = {\n  @react.componentWithProps(BaseUi.Types.DomProps.t)\n  let make = (props: BaseUi.Types.DomProps.t) => {\n    let dataSlot = props.dataSlot->Option.getOr(\"sidebar-content\")\n    <div\n      {...props}\n      dataSlot\n      dataSidebar=\"content\"\n      className={cn(\n        \"no-scrollbar gap-0 flex min-h-0 flex-1 flex-col overflow-auto group-data-[collapsible=icon]:overflow-hidden\",\n        props.className,\n      )}\n    />\n  }\n}\n\nmodule Group = {\n  @react.componentWithProps(BaseUi.Types.DomProps.t)\n  let make = (props: BaseUi.Types.DomProps.t) =>\n    <div\n      {...props}\n      dataSlot={props.dataSlot->Option.getOr(\"sidebar-group\")}\n      dataSidebar={props.dataSidebar->Option.getOr(\"group\")}\n      className={cn(\"p-2 relative flex w-full min-w-0 flex-col\", props.className)}\n    />\n}\n\nmodule GroupLabel = {\n  let toDomProps: BaseUi.Types.BaseUIComponentProps.t => BaseUi.Types.DomProps.t = %raw(`({className, render, ...props}) => props`)\n\n  @react.componentWithProps(BaseUi.Types.BaseUIComponentProps.t)\n  let make = (props: BaseUi.Types.BaseUIComponentProps.t) => {\n    BaseUi.Render.use({\n      defaultTagName: \"div\",\n      props: BaseUi.Render.mergeProps(\n        {\n          className: cn(\n            \"text-sidebar-foreground/70 ring-sidebar-ring h-8 rounded-md px-2 text-xs font-medium transition-[margin,opacity] duration-200 ease-linear group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0 focus-visible:ring-2 [&>svg]:size-4 flex shrink-0 items-center outline-hidden [&>svg]:shrink-0\",\n            props.className,\n          ),\n        },\n        toDomProps(props),\n      ),\n      render: ?props.render,\n      state: {RenderState.slot: \"sidebar-group-label\", sidebar: \"group-label\"},\n    })\n  }\n}\n\nmodule GroupAction = {\n  let toDomProps: BaseUi.Types.BaseUIComponentProps.t => BaseUi.Types.DomProps.t = %raw(`({className, render, ...props}) => props`)\n\n  @react.componentWithProps(BaseUi.Types.BaseUIComponentProps.t)\n  let make = (props: BaseUi.Types.BaseUIComponentProps.t) => {\n    BaseUi.Render.use({\n      defaultTagName: \"button\",\n      props: BaseUi.Render.mergeProps(\n        {\n          className: cn(\n            \"text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground absolute top-3.5 right-3 w-5 rounded-md p-0 focus-visible:ring-2 [&>svg]:size-4 flex aspect-square items-center justify-center outline-hidden transition-transform [&>svg]:shrink-0 after:absolute after:-inset-2 md:after:hidden group-data-[collapsible=icon]:hidden\",\n            props.className,\n          ),\n        },\n        toDomProps(props),\n      ),\n      render: ?props.render,\n      state: {RenderState.slot: \"sidebar-group-action\", sidebar: \"group-action\"},\n    })\n  }\n}\n\nmodule GroupContent = {\n  @react.componentWithProps(BaseUi.Types.DomProps.t)\n  let make = (props: BaseUi.Types.DomProps.t) =>\n    <div\n      {...props}\n      dataSlot={props.dataSlot->Option.getOr(\"sidebar-group-content\")}\n      dataSidebar={props.dataSidebar->Option.getOr(\"group-content\")}\n      className={cn(\"text-sm w-full\", props.className)}\n    />\n}\n\nmodule Menu = {\n  @react.componentWithProps(BaseUi.Types.DomProps.t)\n  let make = (props: BaseUi.Types.DomProps.t) =>\n    <ul\n      {...props}\n      dataSlot={props.dataSlot->Option.getOr(\"sidebar-menu\")}\n      dataSidebar={props.dataSidebar->Option.getOr(\"menu\")}\n      className={cn(\"gap-0 flex w-full min-w-0 flex-col\", props.className)}\n    />\n}\n\nmodule MenuItem = {\n  @react.componentWithProps(BaseUi.Types.DomProps.t)\n  let make = (props: BaseUi.Types.DomProps.t) =>\n    <li\n      {...props}\n      dataSlot={props.dataSlot->Option.getOr(\"sidebar-menu-item\")}\n      dataSidebar={props.dataSidebar->Option.getOr(\"menu-item\")}\n      className={cn(\"group/menu-item relative\", props.className)}\n    />\n}\n\ntype menuButtonTooltipConfig = {\n  children?: React.element,\n  className?: string,\n  id?: string,\n  style?: ReactDOM.Style.t,\n  onClick?: JsxEvent.Mouse.t => unit,\n  onKeyDown?: JsxEvent.Keyboard.t => unit,\n  side?: Side.t,\n  sideOffset?: float,\n  align?: Align.t,\n  alignOffset?: float,\n}\n\nmodule MenuButton = {\n  module Variant = {\n    @unboxed\n    type t =\n      | @as(\"default\") Default\n      | @as(\"outline\") Outline\n  }\n  module Size = {\n    @unboxed\n    type t =\n      | @as(\"default\") Default\n      | @as(\"sm\") Sm\n      | @as(\"lg\") Lg\n  }\n\n  let sidebarMenuButtonVariants = (~variant=Variant.Default, ~size=Size.Default) => {\n    let base = \"ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground data-active:bg-sidebar-accent data-active:text-sidebar-accent-foreground data-open:hover:bg-sidebar-accent data-open:hover:text-sidebar-accent-foreground gap-2 rounded-md p-2 text-left text-sm transition-[width,height,padding] group-has-data-[sidebar=menu-action]/menu-item:pr-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! focus-visible:ring-2 data-active:font-medium peer/menu-button flex w-full items-center overflow-hidden outline-hidden group/menu-button disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&_svg]:size-4 [&_svg]:shrink-0\"\n    let variantClass = switch variant {\n    | Variant.Outline => \"bg-background hover:bg-sidebar-accent hover:text-sidebar-accent-foreground shadow-[0_0_0_1px_var(--sidebar-border)] hover:shadow-[0_0_0_1px_var(--sidebar-accent)]\"\n    | Default => \"hover:bg-sidebar-accent hover:text-sidebar-accent-foreground\"\n    }\n    let sizeClass = switch size {\n    | Sm => \"h-7 text-xs\"\n    | Lg => \"h-12 text-sm group-data-[collapsible=icon]:p-0!\"\n    | Default => \"h-8 text-sm\"\n    }\n    `${base} ${variantClass} ${sizeClass}`\n  }\n\n  type state = {\n    slot: string,\n    sidebar: string,\n    size: Size.t,\n    active: bool,\n  }\n\n  type props = {\n    variant?: Variant.t,\n    size?: Size.t,\n    isActive?: bool,\n    tooltip?: Tooltip.Content.props,\n    ...BaseUi.Types.BaseUIComponentProps.t,\n  }\n\n  let toDomProps: props => BaseUi.Types.DomProps.t = %raw(`({variant, size, isActive, tooltip, className, render, ...props}) => props`)\n\n  @react.componentWithProps(props)\n  let make = (props: props) => {\n    let variant = props.variant->Option.getOr(Variant.Default)\n    let size = props.size->Option.getOr(Size.Default)\n    let isActive = props.isActive->Option.getOr(false)\n    let {isMobile, state} = use()\n    let comp = BaseUi.Render.use({\n      defaultTagName: \"button\",\n      props: BaseUi.Render.mergeProps(\n        {className: cn(sidebarMenuButtonVariants(~variant, ~size), props.className)},\n        toDomProps(props),\n      ),\n      render: ?{\n        switch props.tooltip {\n        | Some(_) => Some(<Tooltip.Trigger render=?props.render />)\n        | None => props.render\n        }\n      },\n      state: {\n        slot: \"sidebar-menu-button\",\n        sidebar: \"menu-button\",\n        size,\n        active: isActive,\n      },\n    })\n    switch props.tooltip {\n    | None => comp\n    | Some(tooltip) =>\n      <Tooltip>\n        {comp}\n        <Tooltip.Content\n          {...tooltip}\n          side={tooltip.side->Option.getOr(Side.Right)}\n          align={tooltip.align->Option.getOr(Align.Center)}\n          hidden={tooltip.hidden->Option.getOr(state !== Collapsed || isMobile)}\n        />\n      </Tooltip>\n    }\n  }\n}\n\nmodule MenuAction = {\n  type props = {\n    showOnHover?: bool,\n    @as(\"type\") type_?: BaseUi.Types.ButtonType.t,\n    ...BaseUi.Types.BaseUIComponentWithoutTypeProps.t,\n  }\n\n  let toDomProps: props => BaseUi.Types.DomProps.t = %raw(`({showOnHover, className, render, ...props}) => props`)\n\n  @react.componentWithProps(props)\n  let make = (props: props) => {\n    let showOnHover = props.showOnHover->Option.getOr(false)\n    let domProps = toDomProps(props)\n    let domProps = switch (props.render, props.type_) {\n    | (None, None) => {...domProps, type_: \"button\"}\n    | _ => domProps\n    }\n    BaseUi.Render.use({\n      defaultTagName: \"button\",\n      props: BaseUi.Render.mergeProps(\n        {\n          className: cn3(\n            \"text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground peer-hover/menu-button:text-sidebar-accent-foreground absolute top-1.5 right-1 aspect-square w-5 rounded-md p-0 peer-data-[size=default]/menu-button:top-1.5 peer-data-[size=lg]/menu-button:top-2.5 peer-data-[size=sm]/menu-button:top-1 focus-visible:ring-2 [&>svg]:size-4 flex items-center justify-center outline-hidden transition-transform group-data-[collapsible=icon]:hidden after:absolute after:-inset-2 md:after:hidden [&>svg]:shrink-0\",\n            showOnHover\n              ? \"group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 peer-data-active/menu-button:text-sidebar-accent-foreground aria-expanded:opacity-100 md:opacity-0\"\n              : \"\",\n            props.className,\n          ),\n        },\n        domProps,\n      ),\n      render: ?props.render,\n      state: {RenderState.slot: \"sidebar-menu-action\", sidebar: \"menu-action\"},\n    })\n  }\n}\n\nmodule MenuBadge = {\n  @react.componentWithProps(BaseUi.Types.DomProps.t)\n  let make = (props: BaseUi.Types.DomProps.t) =>\n    <div\n      {...props}\n      dataSlot={props.dataSlot->Option.getOr(\"sidebar-menu-badge\")}\n      dataSidebar={props.dataSidebar->Option.getOr(\"menu-badge\")}\n      className={cn(\n        \"text-sidebar-foreground peer-hover/menu-button:text-sidebar-accent-foreground peer-data-active/menu-button:text-sidebar-accent-foreground pointer-events-none absolute right-1 h-5 min-w-5 rounded-md px-1 text-xs font-medium peer-data-[size=default]/menu-button:top-1.5 peer-data-[size=lg]/menu-button:top-2.5 peer-data-[size=sm]/menu-button:top-1 flex items-center justify-center tabular-nums select-none group-data-[collapsible=icon]:hidden\",\n        props.className,\n      )}\n    />\n}\n\nmodule MenuSkeleton = {\n  type props = {showIcon?: bool, ...BaseUi.Types.DomProps.t}\n\n  let toDomProps: props => BaseUi.Types.DomProps.t = %raw(`({showIcon, ...props}) => props`)\n\n  @react.componentWithProps(props)\n  let make = (props: props) => {\n    let showIcon = props.showIcon->Option.getOr(false)\n\n    let (width, _setWidth) = React.useState(() => `${Float.toString(mathRandom() *. 40. +. 50.)}%`)\n    let textStyle = ReactDOM.Style._dictToStyle(\n      dict{\n        \"--skeleton-width\": width,\n      },\n    )\n    <div\n      {...toDomProps(props)}\n      dataSlot={props.dataSlot->Option.getOr(\"sidebar-menu-skeleton\")}\n      dataSidebar={props.dataSidebar->Option.getOr(\"menu-skeleton\")}\n      className={cn(\"h-8 gap-2 rounded-md px-2 flex items-center\", props.className)}\n    >\n      {showIcon\n        ? <Skeleton className=\"size-4 rounded-md\" dataSidebar=\"menu-skeleton-icon\" />\n        : React.null}\n      <Skeleton\n        className=\"h-4 max-w-(--skeleton-width) flex-1\"\n        dataSidebar=\"menu-skeleton-text\"\n        style={textStyle}\n      />\n      {props.children->Option.getOr(React.null)}\n    </div>\n  }\n}\n\nmodule MenuSub = {\n  @react.componentWithProps(BaseUi.Types.DomProps.t)\n  let make = (props: BaseUi.Types.DomProps.t) =>\n    <ul\n      {...props}\n      dataSlot={props.dataSlot->Option.getOr(\"sidebar-menu-sub\")}\n      dataSidebar={props.dataSidebar->Option.getOr(\"menu-sub\")}\n      className={cn(\n        \"border-sidebar-border mx-3.5 translate-x-px gap-1 border-l px-2.5 py-0.5 group-data-[collapsible=icon]:hidden flex min-w-0 flex-col\",\n        props.className,\n      )}\n    />\n}\n\nmodule MenuSubItem = {\n  @react.componentWithProps(BaseUi.Types.DomProps.t)\n  let make = (props: BaseUi.Types.DomProps.t) =>\n    <li\n      {...props}\n      dataSlot={props.dataSlot->Option.getOr(\"sidebar-menu-sub-item\")}\n      dataSidebar={props.dataSidebar->Option.getOr(\"menu-sub-item\")}\n      className={cn(\"group/menu-sub-item relative\", props.className)}\n    />\n}\n\nmodule MenuSubButton = {\n  module Size = {\n    @unboxed\n    type t =\n      | @as(\"sm\") Sm\n      | @as(\"md\") Md\n  }\n\n  type state = {\n    slot: string,\n    sidebar: string,\n    size: Size.t,\n    active: bool,\n  }\n\n  type props = {\n    size?: Size.t,\n    isActive?: bool,\n    ...BaseUi.Types.BaseUIComponentProps.t,\n  }\n\n  let toDomProps: props => BaseUi.Types.DomProps.t = %raw(`({size, isActive, className, render, ...props}) => props`)\n\n  @react.componentWithProps(props)\n  let make = (props: props) => {\n    let size = props.size->Option.getOr(Size.Md)\n    let isActive = props.isActive->Option.getOr(false)\n\n    BaseUi.Render.use({\n      defaultTagName: \"a\",\n      props: BaseUi.Render.mergeProps(\n        {\n          className: cn(\n            \"text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground [&>svg]:text-sidebar-accent-foreground data-active:bg-sidebar-accent data-active:text-sidebar-accent-foreground h-7 gap-2 rounded-md px-2 focus-visible:ring-2 data-[size=md]:text-sm data-[size=sm]:text-xs [&>svg]:size-4 flex min-w-0 -translate-x-px items-center overflow-hidden outline-hidden group-data-[collapsible=icon]:hidden disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:shrink-0\",\n            props.className,\n          ),\n        },\n        toDomProps(props),\n      ),\n      render: ?props.render,\n      state: {\n        slot: \"sidebar-menu-sub-button\",\n        sidebar: \"menu-sub-button\",\n        size,\n        active: isActive,\n      },\n    })\n  }\n}\n",
      "type": "registry:file",
      "target": "@ui/Sidebar.res"
    }
  ],
  "type": "registry:ui"
}