Add keyboard support to your application.
The core of this project is a service that the components of your app could use to register (and unregister) commands.
By default the command palette interface will be triggered by hitting 'Control' twice. This will open an overlay with all commands listed and a search box where you can filter them.
npm i -S @yuuvis/command-palette
In your app import module and register entry component:
// app.module.ts
@NgModule({
...
imports: [
CommandPaletteModule.forRoot(),
],
...
entryComponents: [CommandPaletteComponent]
})
export class AppModule {}
You can also configure th emodule by provideing a configuration to the forRoot
function:
CommandPaletteModule.forRoot({
// the key that opens the overlay (hit twice)
triggerKey: 'Shift',
// accent color to be used in the overlay
accentColor: 'hotpink',
// character that will enter search mode if typed at the beginning
searchModeIndicator: '?',
// placeholder for command paletts input field
placeholder: 'Enter your command'
}),
Now components can register commands using CommandPaletteService
and listen to them beeing triggerd.
// any of your components
constructor(private cmdService: CommandPaletteService) {
// subscribe to any command being triggered
this.cmdService.command$.subscribe((c: CommandPaletteCommand) => console.log('command$', c));
// register a single command and subscribe to it
cmdService.registerCommand(
{ id: 'id1', label: 'BPM: Create task' }
).subscribe((c: CommandPaletteCommand) => console.log('CREATE A TASK'));
// register multiple commands and subscribe to them
cmdService.registerCommands(
{ id: 'id2', label: 'Navigate: Open inbox' },
{ id: 'id3', label: 'Navigate: Open settings' }
).subscribe((c: CommandPaletteCommand) => {
if(c.id === 'id2') // ... open the inbox
if(c.id === 'id3') // ... open the settings
});
// register command with callback
cmdService.registerCommand(
{ id: 'id2', label: 'Task: Do awesome stuff', callback: () => {
// executed once the command is triggered
alert('Great! You did it.')
} }
).subscribe()
}
Sometimes it is necessary to update command properties. If users for example change the apps language you'll need to change the labels of the registered commands as well.
// app.component.ts
import { CommandPalettService } from "@yuuvis/command-palette";
import { TranslateService } from "@ngx-translate/core";
export class AppComponent {
constructor(
private translate: TranslateService,
private cmpService: CommandPaletteService
) {
this.translate.onLangChange.subscribe((_) => {
// update commands on app language change
this.cmpService.updateCommands(this.getCommands());
});
// register commands in the first place
this.cmpService.updateCommands(this.getCommands());
}
private getCommands(): CommandPaletteCommand[] {
return [
{ id: "1", label: this.translate.instant("command.first") },
{ id: "2", label: this.translate.instant("command.second") },
{ id: "3", label: this.translate.instant("command.third") },
];
}
}
The library will register a couple of css variables that you could overwrite in your app:
/* Accent color */
--cmp-color-accent: hotpink;
/* Text on top of an accent colored background */
--cmp-color-accent-text: #fff;
/* Color of text that should be highlighted on accent colored background */
--cmp-color-accent-text-highlight: #000;
/* Components regular text color */
--cmp-color-text: #fff;
/* Color of text that should be highlighted */
--cmp-color-text-highlight: var(--cmp-color-accent);
/* Components base font size */
--cmp-font-size: 1em;
/* Background color if commands are hovered */
--cmp-hover-background: rgba(255, 255, 255, 0.1);
/* the backdrops background color */
--cmp-backdrop-color: rgba(0, 0, 0, 0.9);
/* Width of search and command items */
--cmp-width: 30vw;
/* Minimum width of search and command items */
--cmp-min-width: 300px;
You could also use this library to trigger custom searches. Therefore you have to define a searchModeIndicator
and register a callback function on CommandPaletteService
.
Let's say you define the character ?
as search mode indictator then inserting thisi character into the search fiels will trigger the search mode.
// app.module.ts
@NgModule({
imports: [
...CommandPaletteModule.forRoot({
searchModeIndicator: "?",
searchModeExplaination: `You entered '?' so you are in search mode now and your query will find objects instaed of commands ...`,
}),
],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
// app.component.ts
import {
CommandPaletteService,
CommandPaletteCommand,
} from "@yuuvis/command-palette";
export class AppComponent {
constructor(private cmdService: CommandPaletteService) {
// register callback
cmdService.onSearchTerm = (term, cb) => {
cb(this.executeSearch(term));
};
}
executeSearch(term): CommandPaletteCommand[] {
// trigger actual search
}
}
In some situations you need to disable functionality of the command palette for a while. For example if a user edits data on the site that has not yet been saved you do not want to trigger any command until the user saved his work.
CommandPaletteService
offers a set of functions to disable the overlay and also provide an explaination to the user:
constructor(private cmdService: CommandPaletteService) {
this.pendingChanges$.subscribe((hasPendingChnages: boolean) => {
if(hasPendingChanges) {
this.cmdService.addDisabledCause({id: 'pending', message: 'Disabled due to pending changes. Please save your changes.'});
} else {
this.cmdService.removeDisabledCause('pending');
}
})
}
You could add as many causes as you want. They will all be shown to the user as a list of reasons why the command palette is disabled right now. If you got more then one cause you could also remove all of them at once by running this.cmdService.removeAllDisabledCauses()
.