{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "sidebar",
  "title": "Sidebar",
  "description": "Links down the side, in groups. Collapses to icons that keep their names.",
  "registryDependencies": [
    "https://creance.pages.dev/r/creance-base.json",
    "https://creance.pages.dev/r/icon-button.json",
    "https://creance.pages.dev/r/tooltip.json"
  ],
  "files": [
    {
      "path": "sidebar/Sidebar.css",
      "content": ".cr-sidebar {\n  display: flex;\n  flex-direction: column;\n  gap: var(--cr-space-1);\n  box-sizing: border-box;\n  width: var(--cr-sidebar-width, 256px);\n  min-height: 100%;\n  padding: var(--cr-space-3);\n  color: var(--cr-color-text-default);\n  font-family: var(--cr-font-family-sans);\n}\n\n.cr-sidebar.cr-surface {\n  border-radius: var(--cr-radius-xl);\n}\n\n.cr-sidebar[data-collapsed] {\n  width: var(--cr-sidebar-collapsed-width, 68px);\n  align-items: center;\n}\n\n.cr-sidebar__header {\n  margin-bottom: var(--cr-space-1);\n}\n\n.cr-sidebar__body {\n  display: flex;\n  flex: 1;\n  flex-direction: column;\n  min-height: 0;\n  overflow-y: auto;\n}\n\n.cr-sidebar__title {\n  margin: var(--cr-space-4) var(--cr-space-3) var(--cr-space-1);\n  color: var(--cr-color-text-muted);\n  font-size: var(--cr-font-size-xs);\n  font-weight: var(--cr-font-weight-semibold);\n}\n\n.cr-sidebar__list {\n  display: flex;\n  flex-direction: column;\n  gap: 2px;\n  margin: 0;\n  padding: 0;\n  list-style: none;\n}\n\n.cr-sidebar__link {\n  display: flex;\n  align-items: center;\n  gap: var(--cr-space-3);\n  box-sizing: border-box;\n  min-height: 40px;\n  padding: 0 var(--cr-space-3);\n  border-radius: var(--cr-radius-md);\n  color: var(--cr-color-text-secondary);\n  font-size: var(--cr-font-size-md);\n  font-weight: var(--cr-font-weight-medium);\n  text-decoration: none;\n}\n\n.cr-sidebar__link:hover {\n  background: var(--cr-color-bg-subtle);\n  color: var(--cr-color-text-default);\n}\n\n.cr-sidebar__link[aria-current='page'] {\n  background: var(--cr-color-ink-bg);\n  color: var(--cr-color-ink-fg);\n  font-weight: var(--cr-font-weight-semibold);\n}\n\n.cr-sidebar__link:focus-visible {\n  outline: var(--cr-focus-width) solid var(--cr-color-focus);\n  outline-offset: var(--cr-focus-offset);\n}\n\n.cr-sidebar__icon {\n  display: grid;\n  place-items: center;\n  flex: none;\n  width: 18px;\n  font-size: var(--cr-font-size-lg);\n  font-weight: var(--cr-font-weight-semibold);\n}\n\n.cr-sidebar__label {\n  flex: 1;\n  min-width: 0;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n}\n\n.cr-sidebar__count {\n  min-width: 18px;\n  padding: 0 5px;\n  border-radius: var(--cr-radius-full);\n  background: var(--cr-color-bg-subtle);\n  font-size: 11px;\n  font-weight: var(--cr-font-weight-bold);\n  line-height: 18px;\n  text-align: center;\n}\n\n.cr-sidebar__link[aria-current='page'] .cr-sidebar__count {\n  background: color-mix(in srgb, currentColor 22%, transparent);\n}\n\n.cr-sidebar__footer {\n  display: flex;\n  align-items: center;\n  gap: var(--cr-space-2);\n  padding-top: var(--cr-space-3);\n  border-top: 1px solid var(--cr-color-border-default);\n}\n\n.cr-sidebar__footer-slot {\n  flex: 1;\n  min-width: 0;\n}\n\n/* Collapsed: icons only. Labels stay in the page for screen readers; the count becomes a dot. */\n.cr-sidebar[data-collapsed] .cr-sidebar__title {\n  height: 1px;\n  margin: var(--cr-space-3) var(--cr-space-2);\n  overflow: hidden;\n  background: var(--cr-color-border-default);\n  color: transparent;\n}\n\n.cr-sidebar[data-collapsed] .cr-sidebar__link {\n  position: relative;\n  justify-content: center;\n  width: 44px;\n  min-height: 44px;\n  padding: 0;\n  border-radius: 14px;\n}\n\n.cr-sidebar[data-collapsed] .cr-sidebar__label {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  overflow: hidden;\n  clip-path: inset(50%);\n}\n\n.cr-sidebar[data-collapsed] .cr-sidebar__count {\n  position: absolute;\n  top: 7px;\n  right: 7px;\n  width: 8px;\n  min-width: 0;\n  height: 8px;\n  padding: 0;\n  overflow: hidden;\n  background: currentColor;\n  color: inherit;\n  font-size: 0;\n}\n\n.cr-sidebar[data-collapsed] .cr-sidebar__footer {\n  flex-direction: column;\n}\n",
      "type": "registry:file",
      "target": "@components/creance/sidebar/Sidebar.css"
    },
    {
      "path": "sidebar/Sidebar.tsx",
      "content": "'use client';\n\nimport { useId, useState, type MouseEventHandler, type ReactNode } from 'react';\nimport { IconButton } from '@/components/creance/icon-button/IconButton';\nimport { Tooltip } from '@/components/creance/tooltip/Tooltip';\nimport { cx } from '@/lib/creance/cx';\nimport { SidebarIcon } from '@/lib/creance/icons';\nimport './Sidebar.css';\n\nexport interface SidebarItem {\n  /** Also the tooltip and accessible name when the sidebar is collapsed. */\n  label: string;\n  href?: string;\n  onClick?: MouseEventHandler<HTMLAnchorElement>;\n  /** The page the person is on. */\n  current?: boolean;\n  /** Shown beside the label. Collapsed, it becomes a dot. */\n  count?: number;\n  /** Decorative. Collapsed, a link with no icon shows the first letter of its label. */\n  icon?: ReactNode;\n}\n\nexport interface SidebarGroup {\n  /** A heading above the group. */\n  title?: string;\n  items: SidebarItem[];\n}\n\ntype Slot = ReactNode | ((state: { collapsed: boolean }) => ReactNode);\n\nexport interface SidebarProps {\n  groups: SidebarGroup[];\n  /** Above the links: a logo or a workspace switcher. A function receives `{ collapsed }`. */\n  header?: Slot;\n  /** Below the links: the account. A function receives `{ collapsed }`. */\n  footer?: Slot;\n  /** Shows a button that collapses the sidebar to icons. */\n  collapsible?: boolean;\n  collapsed?: boolean;\n  defaultCollapsed?: boolean;\n  onCollapsedChange?: (collapsed: boolean) => void;\n  /** `flush` has no background of its own, for use inside AppShell. `card` is a glass tile. */\n  variant?: 'flush' | 'card';\n  /** Accessible name of the nav. Default \"Sidebar\". */\n  label?: string;\n  collapseLabel?: string;\n  expandLabel?: string;\n  className?: string;\n}\n\n/** Links down the side of an app, in groups. Collapses to icons; each icon keeps its name as a tooltip and for screen readers. */\nexport function Sidebar({\n  groups,\n  header,\n  footer,\n  collapsible,\n  collapsed: controlled,\n  defaultCollapsed = false,\n  onCollapsedChange,\n  variant = 'flush',\n  label = 'Sidebar',\n  collapseLabel = 'Collapse sidebar',\n  expandLabel = 'Expand sidebar',\n  className,\n}: SidebarProps) {\n  const [own, setOwn] = useState(defaultCollapsed);\n  const collapsed = controlled ?? own;\n  const id = useId();\n  const slot = (s: Slot) => (typeof s === 'function' ? s({ collapsed }) : s);\n\n  function toggle() {\n    setOwn(!collapsed);\n    onCollapsedChange?.(!collapsed);\n  }\n\n  return (\n    <nav aria-label={label} className={cx('cr-sidebar', variant === 'card' && 'cr-surface', className)} data-collapsed={collapsed || undefined}>\n      {header !== undefined && <div className=\"cr-sidebar__header\">{slot(header)}</div>}\n      <div className=\"cr-sidebar__body\">\n        {groups.map((group, g) => (\n          <div key={g} className=\"cr-sidebar__group\">\n            {group.title && (\n              <p id={`${id}-${g}`} className=\"cr-sidebar__title\">\n                {group.title}\n              </p>\n            )}\n            <ul className=\"cr-sidebar__list\" aria-labelledby={group.title ? `${id}-${g}` : undefined}>\n              {group.items.map((item, i) => {\n                const link = (\n                  <a className=\"cr-sidebar__link\" href={item.href} onClick={item.onClick} aria-current={item.current ? 'page' : undefined}>\n                    <span className=\"cr-sidebar__icon\" aria-hidden=\"true\">\n                      {item.icon ?? item.label.charAt(0)}\n                    </span>\n                    <span className=\"cr-sidebar__label\">{item.label}</span>\n                    {/* The space keeps the count a separate word in the link's accessible name. */}\n                    {item.count !== undefined && ' '}\n                    {item.count !== undefined && <span className=\"cr-sidebar__count\">{item.count}</span>}\n                  </a>\n                );\n                return (\n                  <li key={i}>\n                    {collapsed ? (\n                      <Tooltip side=\"right\" content={item.count === undefined ? item.label : `${item.label} · ${item.count}`}>\n                        {link}\n                      </Tooltip>\n                    ) : (\n                      link\n                    )}\n                  </li>\n                );\n              })}\n            </ul>\n          </div>\n        ))}\n      </div>\n      {(footer !== undefined || collapsible) && (\n        <div className=\"cr-sidebar__footer\">\n          {footer !== undefined && <div className=\"cr-sidebar__footer-slot\">{slot(footer)}</div>}\n          {collapsible && (\n            <IconButton\n              size=\"sm\"\n              icon={<SidebarIcon />}\n              label={collapsed ? expandLabel : collapseLabel}\n              aria-expanded={!collapsed}\n              tooltip={false}\n              onClick={toggle}\n            />\n          )}\n        </div>\n      )}\n    </nav>\n  );\n}\n",
      "type": "registry:ui",
      "target": "@components/creance/sidebar/Sidebar.tsx"
    }
  ],
  "categories": [
    "molecule",
    "navigation"
  ],
  "type": "registry:ui"
}