Files
Danny White c49c2c8e8b fix(design-system): add missing breadcrumb demo components (#47421)
## What kind of change does this PR introduce?

Bug fix, docs update

## What is the current behavior?

- The breadcrumb component docs at
`/design-system/docs/components/breadcrumb` reference six
`ComponentPreview` demos, but the example components were never
implemented and their registry entries were commented out. The page
rendered without working previews.

Unrelated but snuck in:

- The “responsive” Admonition example is a H2 instead of H3 like the
others.
- The design system ⌘K command switcher grows to the full height of its
nav items instead of scrolling within a bounded list.

Closes DEPR-607
Closes DEPR-608

## What is the new behavior?

- Adds six breadcrumb example components (`breadcrumb-demo`,
`breadcrumb-separator`, `breadcrumb-dropdown`, `breadcrumb-ellipsis`,
`breadcrumb-link`, `breadcrumb-responsive`) under
`apps/design-system/registry/default/example/`
- Re-enables the corresponding entries in `registry/examples.ts` and
rebuilds `__registry__/index.tsx`
- Fixes invalid nested `<li>` markup in the responsive breadcrumb demo
that caused a hydration error

Also includes two small unrelated fixes:

- Caps the ⌘K switcher `CommandList` at `max-h-[300px]` so it scrolls
instead of stretching
- Corrects the admonition fragment docs header type

## Additional context

Test plan:
- [ ] Run `pnpm dev:design-system` and open
`/docs/components/breadcrumb`
- [ ] Confirm all six breadcrumb previews render
- [ ] Confirm no hydration warnings in the browser console for the
responsive example
- [ ] Open the ⌘K switcher and confirm the list scrolls within a bounded
height

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added multiple Breadcrumb demos to the design system gallery,
including link, dropdown, ellipsis, separator, and responsive variants.
  * Enabled these Breadcrumb demos in the examples registry.
* **Documentation**
  * Updated the “Responsive” docs heading level.
* **Style**
* Constrained the command menu list height inside the dialog for
improved fit.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-30 16:13:50 +00:00

125 lines
4.3 KiB
TypeScript

'use client'
import { CircleIcon, LaptopIcon, MoonIcon, Search, SunIcon } from 'lucide-react'
import { useTheme } from 'next-themes'
import { useRouter } from 'next/navigation'
import * as React from 'react'
import {
Button,
CommandDialog,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
CommandSeparator,
DialogProps,
DialogTitle,
} from 'ui'
import { docsConfig } from '@/config/docs'
import { cn } from '@/lib/utils'
export function CommandMenu({ ...props }: DialogProps) {
const router = useRouter()
const [open, setOpen] = React.useState(false)
const { setTheme } = useTheme()
React.useEffect(() => {
const down = (e: KeyboardEvent) => {
if ((e.key === 'k' && (e.metaKey || e.ctrlKey)) || e.key === '/') {
if (
(e.target instanceof HTMLElement && e.target.isContentEditable) ||
e.target instanceof HTMLInputElement ||
e.target instanceof HTMLTextAreaElement ||
e.target instanceof HTMLSelectElement
) {
return
}
e.preventDefault()
setOpen((open) => !open)
}
}
document.addEventListener('keydown', down)
return () => document.removeEventListener('keydown', down)
}, [])
const runCommand = React.useCallback((command: () => unknown) => {
setOpen(false)
command()
}, [])
return (
<>
<Button
variant="outline"
className={cn(
`lg:flex hidden relative h-8 w-full justify-start rounded-lg bg-background text-sm font-normal text-foreground-muted shadow-none sm:pr-12 md:w-40 lg:w-64 hover:border-foreground-muted hover:bg-surface-100 hover:text-foreground-lighter
`
)}
onClick={() => setOpen(true)}
{...props}
>
<span className="hidden lg:inline-flex">Search Design System...</span>
<span className="inline-flex lg:hidden">Search...</span>
<kbd className="pointer-events-none absolute right-[0.3rem] top-[0.3rem] hidden h-5 select-none items-center gap-1 rounded-sm border bg-surface-200 px-1.5 font-mono text-[10px] font-medium opacity-100 sm:flex text-foreground-light">
<span className="text-sm">⌘</span>K
</kbd>
</Button>
<Button
variant="text"
size="tiny"
className="px-1 group lg:hidden"
onClick={() => setOpen(true)}
icon={<Search size={16} />}
/>
<CommandDialog open={open} onOpenChange={setOpen}>
<DialogTitle className="sr-only">Search Design System...</DialogTitle>
<CommandInput placeholder="Type a command or search..." />
<CommandList className="max-h-[300px]">
<CommandEmpty>No results found.</CommandEmpty>
{docsConfig.sidebarNav.map((group) => (
<CommandGroup key={group.title} heading={group.title}>
{group.items.map((navItem) => (
<CommandItem
key={navItem.href}
value={navItem.title}
onSelect={() => {
runCommand(() => router.push(navItem.href as string))
}}
>
<div className="mr-2 flex h-4 w-4 items-center justify-center">
<CircleIcon className="h-3 w-3" strokeWidth={1} />
</div>
{navItem.title}
</CommandItem>
))}
</CommandGroup>
))}
<CommandSeparator />
<CommandGroup heading="Theme">
<CommandItem onSelect={() => runCommand(() => setTheme('light'))}>
<SunIcon className="mr-2 h-4 w-4" strokeWidth={1} />
Light
</CommandItem>
<CommandItem onSelect={() => runCommand(() => setTheme('dark'))}>
<MoonIcon className="mr-2 h-4 w-4" strokeWidth={1} />
Dark
</CommandItem>
<CommandItem onSelect={() => runCommand(() => setTheme('classic-dark'))}>
<MoonIcon className="mr-2 h-4 w-4" strokeWidth={1} />
Classic dark
</CommandItem>
<CommandItem onSelect={() => runCommand(() => setTheme('system'))}>
<LaptopIcon className="mr-2 h-4 w-4" strokeWidth={1} />
System
</CommandItem>
</CommandGroup>
</CommandList>
</CommandDialog>
</>
)
}