Angular Example: InjectHotkeySequences

import { Component, signal } from '@angular/core'
import {
  formatForDisplay,
  injectHotkey,
  injectHotkeyRegistrations,
  injectHotkeySequences,
} from '@tanstack/angular-hotkeys'
import type { Hotkey } from '@tanstack/angular-hotkeys'

@Component({
  selector: 'app-root',
  standalone: true,
  templateUrl: './app.component.html',
  styleUrl: './app.component.css',
})
export class AppComponent {
  lastSequence = signal<string | null>(null)
  history = signal<Array<string>>([])
  readonly helloSequenceEnabled = signal(true)

  formatForDisplay = formatForDisplay
  readonly registrations = injectHotkeyRegistrations()

  constructor() {
    const addToHistory = (action: string) => {
      this.lastSequence.set(action)
      this.history.update((h) => [...h.slice(-9), action])
    }

    injectHotkeySequences([
      {
        sequence: ['G', 'G'],
        callback: () => addToHistory('gg → Go to top'),
        options: {
          meta: {
            name: 'Go to top',
            description: 'Scroll to the beginning of the document',
          },
        },
      },
      {
        sequence: ['Shift+G'],
        callback: () => addToHistory('G → Go to bottom'),
        options: {
          meta: {
            name: 'Go to bottom',
            description: 'Scroll to the end of the document',
          },
        },
      },
      {
        sequence: ['D', 'D'],
        callback: () => addToHistory('dd → Delete line'),
        options: {
          meta: {
            name: 'Delete line',
            description: 'Delete the current line',
          },
        },
      },
      {
        sequence: ['Y', 'Y'],
        callback: () => addToHistory('yy → Yank (copy) line'),
        options: {
          meta: {
            name: 'Yank line',
            description: 'Copy the current line to clipboard',
          },
        },
      },
      {
        sequence: ['D', 'W'],
        callback: () => addToHistory('dw → Delete word'),
        options: {
          meta: {
            name: 'Delete word',
            description: 'Delete from cursor to end of word',
          },
        },
      },
      {
        sequence: ['C', 'I', 'W'],
        callback: () => addToHistory('ciw → Change inner word'),
        options: {
          meta: {
            name: 'Change inner word',
            description: 'Delete word under cursor and enter insert mode',
          },
        },
      },
      {
        sequence: ['ArrowUp', 'ArrowUp', 'ArrowDown', 'ArrowDown'],
        callback: () => addToHistory('↑↑↓↓ → Konami code (partial)'),
        options: {
          timeout: 1500,
          meta: {
            name: 'Konami code',
            description: 'Partial Konami code using arrow keys',
          },
        },
      },
      {
        sequence: ['ArrowLeft', 'ArrowRight', 'ArrowLeft', 'ArrowRight'],
        callback: () => addToHistory('←→←→ → Side to side!'),
        options: {
          timeout: 1500,
          meta: {
            name: 'Side to side',
            description: 'Left-right-left-right arrow pattern',
          },
        },
      },
      {
        sequence: ['H', 'E', 'L', 'L', 'O'],
        callback: () => addToHistory('hello → Hello World!'),
        options: () => ({
          enabled: this.helloSequenceEnabled(),
          meta: {
            name: 'Hello',
            description: 'Spell out hello to trigger',
          },
        }),
      },
      {
        sequence: ['Shift+R', 'Shift+T'],
        callback: () => addToHistory('⇧R ⇧T → Chained Shift+letter (2 steps)'),
        options: {
          meta: {
            name: 'Chained Shift',
            description: 'Two consecutive Shift+letter chords',
          },
        },
      },
    ])

    injectHotkey('Escape', () => {
      this.lastSequence.set(null)
      this.history.set([])
    })
  }

  clearHistory(): void {
    this.history.set([])
  }

  toggleHelloSequence(): void {
    this.helloSequenceEnabled.update((enabled) => !enabled)
  }

  formatSeq(seq: Array<string>): string {
    return seq.map((h) => formatForDisplay(h as Hotkey)).join(' ')
  }
}
import { Component, signal } from '@angular/core'
import {
  formatForDisplay,
  injectHotkey,
  injectHotkeyRegistrations,
  injectHotkeySequences,
} from '@tanstack/angular-hotkeys'
import type { Hotkey } from '@tanstack/angular-hotkeys'

@Component({
  selector: 'app-root',
  standalone: true,
  templateUrl: './app.component.html',
  styleUrl: './app.component.css',
})
export class AppComponent {
  lastSequence = signal<string | null>(null)
  history = signal<Array<string>>([])
  readonly helloSequenceEnabled = signal(true)

  formatForDisplay = formatForDisplay
  readonly registrations = injectHotkeyRegistrations()

  constructor() {
    const addToHistory = (action: string) => {
      this.lastSequence.set(action)
      this.history.update((h) => [...h.slice(-9), action])
    }

    injectHotkeySequences([
      {
        sequence: ['G', 'G'],
        callback: () => addToHistory('gg → Go to top'),
        options: {
          meta: {
            name: 'Go to top',
            description: 'Scroll to the beginning of the document',
          },
        },
      },
      {
        sequence: ['Shift+G'],
        callback: () => addToHistory('G → Go to bottom'),
        options: {
          meta: {
            name: 'Go to bottom',
            description: 'Scroll to the end of the document',
          },
        },
      },
      {
        sequence: ['D', 'D'],
        callback: () => addToHistory('dd → Delete line'),
        options: {
          meta: {
            name: 'Delete line',
            description: 'Delete the current line',
          },
        },
      },
      {
        sequence: ['Y', 'Y'],
        callback: () => addToHistory('yy → Yank (copy) line'),
        options: {
          meta: {
            name: 'Yank line',
            description: 'Copy the current line to clipboard',
          },
        },
      },
      {
        sequence: ['D', 'W'],
        callback: () => addToHistory('dw → Delete word'),
        options: {
          meta: {
            name: 'Delete word',
            description: 'Delete from cursor to end of word',
          },
        },
      },
      {
        sequence: ['C', 'I', 'W'],
        callback: () => addToHistory('ciw → Change inner word'),
        options: {
          meta: {
            name: 'Change inner word',
            description: 'Delete word under cursor and enter insert mode',
          },
        },
      },
      {
        sequence: ['ArrowUp', 'ArrowUp', 'ArrowDown', 'ArrowDown'],
        callback: () => addToHistory('↑↑↓↓ → Konami code (partial)'),
        options: {
          timeout: 1500,
          meta: {
            name: 'Konami code',
            description: 'Partial Konami code using arrow keys',
          },
        },
      },
      {
        sequence: ['ArrowLeft', 'ArrowRight', 'ArrowLeft', 'ArrowRight'],
        callback: () => addToHistory('←→←→ → Side to side!'),
        options: {
          timeout: 1500,
          meta: {
            name: 'Side to side',
            description: 'Left-right-left-right arrow pattern',
          },
        },
      },
      {
        sequence: ['H', 'E', 'L', 'L', 'O'],
        callback: () => addToHistory('hello → Hello World!'),
        options: () => ({
          enabled: this.helloSequenceEnabled(),
          meta: {
            name: 'Hello',
            description: 'Spell out hello to trigger',
          },
        }),
      },
      {
        sequence: ['Shift+R', 'Shift+T'],
        callback: () => addToHistory('⇧R ⇧T → Chained Shift+letter (2 steps)'),
        options: {
          meta: {
            name: 'Chained Shift',
            description: 'Two consecutive Shift+letter chords',
          },
        },
      },
    ])

    injectHotkey('Escape', () => {
      this.lastSequence.set(null)
      this.history.set([])
    })
  }

  clearHistory(): void {
    this.history.set([])
  }

  toggleHelloSequence(): void {
    this.helloSequenceEnabled.update((enabled) => !enabled)
  }

  formatSeq(seq: Array<string>): string {
    return seq.map((h) => formatForDisplay(h as Hotkey)).join(' ')
  }
}