@angularforge/command-palette
Architecture
Directory structure, component tree, and data flow.
Directory Structure
src/lib/
├── models/ command.model.ts — Command, SearchResult, CommandGroup, Config
├── tokens/ command-palette.tokens.ts — InjectionToken + defaults
├── search/ fuzzy-search.engine.ts — Ranked fuzzy search engine
├── keyboard/ shortcut.parser.ts — parseShortcut / matchesAnyShortcut
├── services/ command-palette.service.ts — Signals-only state hub
├── providers/ command-palette.provider.ts — provideCommandPalette()
└── components/
├── palette-item/ — Single command row (role="option")
├── palette-group/ — Category section (role="group")
├── palette-results/ — Scrollable listbox (role="listbox")
├── palette-input/ — Combobox search input
└── command-palette/ — Host component (af-command-palette)Component Tree
CommandPaletteComponent (af-command-palette)
— Listens: (document:keydown) for shortcuts + Escape
— CDK BlockScrollStrategy (scroll locked while open)
— Owns: activeIndex signal, scrolling
@if (service.isOpen())
└── div.af-cp-root
├── div.af-cp-backdrop (click → close)
└── div.af-cp-dialog (role="dialog", cdkTrapFocus)
├── PaletteInputComponent (role="combobox")
├── PaletteResultsComponent (role="listbox")
│ └── PaletteGroupComponent × N (role="group")
│ └── PaletteItemComponent × N (role="option")
└── div.af-cp-footer (keyboard hints)Data Flow
register(commands)
↓
CommandPaletteService._commands (signal Map)
↓
results = computed(fuzzySearch(_commands, query))
↓
groups = computed(groupBy(results, 'category'))
↓
Template renders groups → items