# Command Palette & Keyboard Shortcuts — Implementation Guide

The Command Palette (⌘K) and shortcut system in Impact Nova is **more involved** than most components. Follow this guide step by step. Use the subpath **`impact-nova/command-palette`** for all exports.

---

## 1. Minimal setup (required)

**Step 1:** Wrap your app with `CommandPaletteProvider`. Render `CommandPalette` once inside it (typically at the root so ⌘K works everywhere).

```tsx
import { CommandPaletteProvider, CommandPalette } from 'impact-nova/command-palette';

function App() {
  return (
    <CommandPaletteProvider>
      <YourAppLayout />
      <CommandPalette />  {/* ⌘K overlay — renders as a portal */}
    </CommandPaletteProvider>
  );
}
```

**Step 2:** Register at least one shortcut so the palette has commands. Use `useShortcut` for page/module/modal scope, or `useGlobalShortcut` for app-wide (e.g. ⌘K to open palette is built-in).

---

## 2. Registering shortcuts

### useShortcut (scoped: page, module, modal)

Use when the shortcut only applies in a certain part of the app (e.g. Save on a page, Create Task in a module).

```tsx
import { useShortcut } from 'impact-nova/command-palette';

function SaveButton() {
  useShortcut({
    id: 'document.save',
    label: 'Save Document',
    description: 'Save the current document',
    category: 'Document',
    scope: 'page',
    defaultKeybinding: { key: 's', meta: true },
    handler: () => saveDocument(),
  });

  return <button>Save</button>;
}
```

### useGlobalShortcut (app-wide)

Use for actions that should work from anywhere (e.g. Open Settings, Toggle Sidebar).

```tsx
import { useGlobalShortcut } from 'impact-nova/command-palette';

function App() {
  useGlobalShortcut({
    id: 'app.open-settings',
    label: 'Open Settings',
    category: 'Navigation',
    defaultKeybinding: { key: ',', meta: true },
    handler: () => openSettings(),
  });
  // ...
}
```

### KeyBinding shape

```ts
interface KeyBinding {
  key: string;     // e.g. 's', 'Enter', 'ArrowUp', 'k'
  meta?: boolean;  // ⌘ on Mac, Ctrl on Windows
  ctrl?: boolean;
  alt?: boolean;
  shift?: boolean;
}
```

Use `meta: true` for ⌘/Ctrl. Examples: Save = `{ key: 's', meta: true }`, Redo = `{ key: 'z', meta: true, shift: true }`.

---

## 3. Scope priority

When the same key is registered in multiple places, **scope priority** decides which runs (highest wins):

| Priority | Scope    | Use case                          |
|----------|----------|-----------------------------------|
| 4        | `modal`  | Dialogs, sheets, overlays         |
| 3        | `page`   | Page-level (save, export)        |
| 2        | `module` | Feature area (planning, analytics)|
| 1        | `global` | App-wide (⌘K, notifications)     |

Always set the correct `scope` so the right command fires (e.g. Save in a dialog vs Save on the page).

---

## 4. Multi-table / instance-aware shortcuts

When you have **multiple DataTables** (or similar) on one page and each uses the same shortcut (e.g. Alt+T to toggle columns), only the **focused** one should respond.

**Solution:** Wrap each table (or section) in `ShortcutScopeProvider` with a unique `instance`:

```tsx
import { ShortcutScopeProvider, useShortcut } from 'impact-nova/command-palette';

function DashboardPage() {
  return (
    <>
      <ShortcutScopeProvider scope="page" instance="sales-table" label="Sales">
        <SalesDataTable />
      </ShortcutScopeProvider>

      <ShortcutScopeProvider scope="page" instance="inventory-table" label="Inventory">
        <InventoryDataTable />
      </ShortcutScopeProvider>
    </>
  );
}

function SalesDataTable() {
  useShortcut({
    id: 'sales.toggle-columns',
    label: 'Toggle Column Visibility',
    scope: 'page',
    defaultKeybinding: { key: 't', alt: true },
    handler: () => toggleColumnsPanel(),
  });
  return <DataTable />;
}
```

Focus inside a table sets the active instance; the shortcut then runs only for that instance.

---

## 5. Opening the palette programmatically (e.g. button)

Use `useCommandPalette()` to get `setOpen`:

```tsx
import { useCommandPalette, CommandPalette, Kbd } from 'impact-nova/command-palette';
import { Button } from 'impact-nova';

function Header() {
  const { setOpen } = useCommandPalette();

  return (
    <>
      <Button onClick={() => setOpen(true)} variant="outline">
        Open Command Palette <Kbd keybinding={{ key: 'k', meta: true }} size="sm" />
      </Button>
      <CommandPalette />
    </>
  );
}
```

`CommandPalette` must still be rendered inside `CommandPaletteProvider`.

---

## 6. Shortcut Settings panel (customise shortcuts)

The **ShortcutSettings** component is an AG Grid–powered panel where users can view and rebind shortcuts. Put it inside a **Sheet** (e.g. in your app settings):

```tsx
import { ShortcutSettings } from 'impact-nova/command-palette';
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetBody } from 'impact-nova/sheet';

function SettingsSheet({ open, onOpenChange }) {
  return (
    <Sheet open={open} onOpenChange={onOpenChange}>
      <SheetContent side="bottom" expandable>
        <SheetHeader>
          <SheetTitle>Keyboard Shortcuts</SheetTitle>
        </SheetHeader>
        <SheetBody className="p-0">
          <ShortcutSettings className="flex-1" />
        </SheetBody>
      </SheetContent>
    </Sheet>
  );
}
```

Features: click-to-record new keybinding, conflict detection, reset to default, source filter (system / user / ag-grid / browser). For AG Grid behaviour in this panel, follow AG Grid docs (see `impact-nova://ag-grid-rules`).

---

## 7. Browser shortcuts (read-only in palette)

To show browser-reserved shortcuts in the palette and settings without intercepting them, use `useBrowserShortcuts()`:

```tsx
import { useBrowserShortcuts } from 'impact-nova/command-palette';

function App() {
  useBrowserShortcuts();
  // Or hide dev-oriented ones:
  // useBrowserShortcuts({ exclude: ['devtools', 'page source', 'caret browsing', 'inspect'] });
  // ...
}
```

---

## 8. Kbd component (show shortcut in UI)

Display a keybinding with platform-aware symbols (⌘ on Mac, Ctrl on Windows):

```tsx
import { Kbd } from 'impact-nova/command-palette';

<Kbd keybinding={{ key: 'k', meta: true }} />           // ⌘ K
<Kbd keybinding={{ key: 's', meta: true }} size="lg" /> // large
<Kbd keys="⌘+S" />                                       // from string
```

Use `variant="muted"` or `variant="dark"` for different backgrounds.

---

## 9. Command definition (full shape)

When you need to pass a full command (e.g. for custom UI), use this shape:

```ts
interface CommandDefinition {
  id: string;
  label: string;
  description?: string;
  icon?: ReactNode;
  category?: string;
  scope: 'global' | 'module' | 'page' | 'modal';
  defaultKeybinding?: KeyBinding;
  handler: () => void;
  customisable?: boolean;   // default true
  hidden?: boolean;         // hide from palette, default false
  source?: 'system' | 'user' | 'ag-grid' | 'browser';
  passive?: boolean;        // show in palette but don't intercept keys
  instance?: string;        // for multi-table dispatch
}
```

Set `source: 'system'` and `customisable: false` for built-in shortcuts that must not be changed.

---

## 10. Checklist

- [ ] Wrap app with `CommandPaletteProvider`.
- [ ] Render `<CommandPalette />` once inside the provider.
- [ ] Register commands with `useShortcut` (scoped) or `useGlobalShortcut` (app-wide).
- [ ] Use correct `scope` (modal > page > module > global).
- [ ] For multiple tables/sections with same shortcut: wrap each in `ShortcutScopeProvider` with unique `instance`.
- [ ] Optional: add `ShortcutSettings` inside a Sheet for user customisation.
- [ ] Optional: `useBrowserShortcuts()` for read-only browser shortcuts; `Kbd` for showing shortcuts in UI.
- [ ] To open from a button: `useCommandPalette().setOpen(true)`.

**Import path:** `impact-nova/command-palette` — exports: `CommandPaletteProvider`, `CommandPalette`, `useShortcut`, `useGlobalShortcut`, `useCommandPalette`, `useBrowserShortcuts`, `ShortcutScopeProvider`, `ShortcutSettings`, `Kbd`.
