@dotglitch/ngx-common
Version:
Angular components and utilities that are commonly used.
509 lines (502 loc) • 38.6 kB
JavaScript
import * as i6 from '@angular/cdk/scrolling';
import { ScrollingModule } from '@angular/cdk/scrolling';
import * as i0 from '@angular/core';
import { Input, Component, Injectable, isDevMode, HostListener, ViewChild, Inject } from '@angular/core';
import * as i1 from '@angular/material/dialog';
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
import * as i3 from '@angular/material/icon';
import { MatIconModule } from '@angular/material/icon';
import * as i4 from '@angular/material/input';
import { MatInputModule } from '@angular/material/input';
import * as i7 from 'ngx-scrollbar';
import { NgScrollbarModule, NgScrollbar } from 'ngx-scrollbar';
import * as i2 from '@dotglitch/ngx-common/core';
import * as i5 from '@angular/material/form-field';
class BreadcrumbComponent {
constructor(commandPalette) {
this.commandPalette = commandPalette;
this.breadcrumbs = [];
}
selectBreadcrumb(crumb) {
const index = this.breadcrumbs.indexOf(crumb);
if (index == -1)
throw new Error("Something terrible happened.");
const layer = this.breadcrumbs.at(-1);
layer.destroying = true;
setTimeout(() => {
this.commandPalette.setCommandList(this.breadcrumbs.at(-2).commands);
this.commandPalette.breadcrumbs.pop();
this.commandPalette.activeIndex = layer.selectedIndex;
}, 190);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: BreadcrumbComponent, deps: [{ token: CommandPaletteComponent }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: BreadcrumbComponent, isStandalone: true, selector: "ngx-commandpalette-breadcrumb", inputs: { breadcrumbs: "breadcrumbs" }, ngImport: i0, template: "@for (crumb of breadcrumbs; track crumb; let i = $index) {\n <div class=\"crumb\">\n <div\n class=\"crumb_inner\"\n [class.destroy]=\"crumb.destroying\"\n [class.root]=\"i == 0\"\n (click)=\"selectBreadcrumb(crumb)\"\n >\n {{crumb.action.label}}\n </div>\n </div>\n}\n", styles: [":host{display:flex}.crumb{overflow:hidden;height:26px;padding:0 16px;margin:0 -16px}.crumb .crumb_inner{--background-color: #3498db;color:#fff;position:relative;background:var(--background-color);padding:2px 5px 0 6px;margin-right:12px;text-align:center;white-space:pre;font-size:14px;-webkit-user-select:none;user-select:none;cursor:pointer;transition:transform var(--transition),opacity var(--transition),width var(--transition);animation:crumbIn var(--transition) 1}.crumb .crumb_inner.destroy{animation:crumbOut var(--transition) 1}.crumb .crumb_inner:before,.crumb .crumb_inner:after{content:\"\";position:absolute;top:0;border:0 solid var(--background-color);border-width:14px 8px;width:0;height:0}.crumb .crumb_inner:before{left:-14px;border-left-color:#0000}.crumb .crumb_inner:after{left:100%;border-color:#0000;border-left-color:var(--background-color)}.crumb .crumb_inner:hover{--background-color: #1abc9c}.crumb .crumb_inner:active{--background-color: #16a085}.crumb:nth-child(2n) .crumb_inner{--background-color: #2980b9}.crumb:first-child .crumb_inner{padding-left:6px;border-radius:4px 0 0 4px}.crumb:first-child .crumb_inner:before{border:none}.crumb:last-child:not(:only-child) .crumb_inner{padding-right:6px;border-radius:0 4px 4px 0}.crumb:last-child:not(:only-child) .crumb_inner:after{border:none}@keyframes crumbIn{0%{transform:translate(-10px);opacity:0}to{transform:translate(0);opacity:1}}@keyframes crumbOut{to{transform:translate(-10px);opacity:0}0%{transform:translate(0);opacity:1}}mat-form-field input{transition:width .2s ease,opacity .15s 0ms cubic-bezier(.4,0,.2,1)!important}\n"] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: BreadcrumbComponent, decorators: [{
type: Component,
args: [{ selector: 'ngx-commandpalette-breadcrumb', standalone: true, template: "@for (crumb of breadcrumbs; track crumb; let i = $index) {\n <div class=\"crumb\">\n <div\n class=\"crumb_inner\"\n [class.destroy]=\"crumb.destroying\"\n [class.root]=\"i == 0\"\n (click)=\"selectBreadcrumb(crumb)\"\n >\n {{crumb.action.label}}\n </div>\n </div>\n}\n", styles: [":host{display:flex}.crumb{overflow:hidden;height:26px;padding:0 16px;margin:0 -16px}.crumb .crumb_inner{--background-color: #3498db;color:#fff;position:relative;background:var(--background-color);padding:2px 5px 0 6px;margin-right:12px;text-align:center;white-space:pre;font-size:14px;-webkit-user-select:none;user-select:none;cursor:pointer;transition:transform var(--transition),opacity var(--transition),width var(--transition);animation:crumbIn var(--transition) 1}.crumb .crumb_inner.destroy{animation:crumbOut var(--transition) 1}.crumb .crumb_inner:before,.crumb .crumb_inner:after{content:\"\";position:absolute;top:0;border:0 solid var(--background-color);border-width:14px 8px;width:0;height:0}.crumb .crumb_inner:before{left:-14px;border-left-color:#0000}.crumb .crumb_inner:after{left:100%;border-color:#0000;border-left-color:var(--background-color)}.crumb .crumb_inner:hover{--background-color: #1abc9c}.crumb .crumb_inner:active{--background-color: #16a085}.crumb:nth-child(2n) .crumb_inner{--background-color: #2980b9}.crumb:first-child .crumb_inner{padding-left:6px;border-radius:4px 0 0 4px}.crumb:first-child .crumb_inner:before{border:none}.crumb:last-child:not(:only-child) .crumb_inner{padding-right:6px;border-radius:0 4px 4px 0}.crumb:last-child:not(:only-child) .crumb_inner:after{border:none}@keyframes crumbIn{0%{transform:translate(-10px);opacity:0}to{transform:translate(0);opacity:1}}@keyframes crumbOut{to{transform:translate(-10px);opacity:0}0%{transform:translate(0);opacity:1}}mat-form-field input{transition:width .2s ease,opacity .15s 0ms cubic-bezier(.4,0,.2,1)!important}\n"] }]
}], ctorParameters: () => [{ type: CommandPaletteComponent }], propDecorators: { breadcrumbs: [{
type: Input
}] } });
class ShortcutComponent {
constructor() {
this.keys = [];
}
ngOnChanges() {
this.keys = this.shortcut?.split("+");
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ShortcutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: ShortcutComponent, isStandalone: true, selector: "ngx-commandpalette-shortcut", inputs: { shortcut: "shortcut" }, usesOnChanges: true, ngImport: i0, template: "@for (key of keys; track key; let i = $index) {\n @if(i > 0) {\n <span class=\"plus\">+</span>\n }\n\n <span class=\"key\">{{key}}</span>\n}\n", styles: [".key{background:#444;padding:2px 6px;border-radius:4px;font-family:Fira Mono,Courier New,Courier,monospace;text-transform:capitalize}.plus{margin:0 4px}\n"] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ShortcutComponent, decorators: [{
type: Component,
args: [{ selector: 'ngx-commandpalette-shortcut', standalone: true, template: "@for (key of keys; track key; let i = $index) {\n @if(i > 0) {\n <span class=\"plus\">+</span>\n }\n\n <span class=\"key\">{{key}}</span>\n}\n", styles: [".key{background:#444;padding:2px 6px;border-radius:4px;font-family:Fira Mono,Courier New,Courier,monospace;text-transform:capitalize}.plus{margin:0 4px}\n"] }]
}], propDecorators: { shortcut: [{
type: Input
}] } });
class CommandPaletteService {
constructor(dialog, lazyLoader) {
this.dialog = dialog;
this.lazyLoader = lazyLoader;
this.commandBlocks = [];
window.addEventListener("keydown", (evt) => this.onKeyDown(evt));
this.interval = setInterval(() => {
// Go backwards since we're splicing items out of the array.
for (let i = this.commandBlocks.length; i >= 0; i--) {
let commandBlock = this.commandBlocks[i];
// If the current index is somehow null, rip it out of
// the array and wait for cleanup to trigger again
// for the rest of the array.
// TODO: Could this lead to leaks where things at the end
// never get cleaned?
if (commandBlock == null) {
this.commandBlocks.splice(i, 1);
return;
}
// If the element has been disconnected from the DOM, we will
// treat it as having been permanently removed.
// TODO: Could this ever cause unintended consequences?
if (!commandBlock?.element.isConnected)
this.commandBlocks.splice(i, 1);
}
}, 5 * 60 * 1000);
}
ngOnDestroy() {
clearInterval(this.interval);
}
getCommandBlocks(element = document.body) {
const elementPath = [element];
let currentTarget = element;
do {
elementPath.unshift(currentTarget = currentTarget.parentElement);
} while (currentTarget.parentElement);
// Ordered matching command blocks, closest first
const matchingCommandBlocks = [];
for (const element of elementPath) {
const commandBlock = this.commandBlocks.find(cb => cb.element == element);
if (commandBlock) {
matchingCommandBlocks.unshift(commandBlock);
}
}
return matchingCommandBlocks;
}
/**
* Handle keydown events
*
* If an event has been removed from the DOM tree, we don't need
* to explicitly remove the bindings, as they will never fire
*
* We periodically check and remove unconnected command blocks
*/
onKeyDown(evt) {
const matchingCommandBlocks = this.getCommandBlocks(evt.target);
// String in format `ctrl+alt+F`, `ctrl+F` etc.
const key = [
evt.ctrlKey ? "ctrl" : undefined,
evt.altKey ? "alt" : undefined,
evt.shiftKey ? "shift" : undefined,
evt.metaKey ? "meta" : undefined,
evt.code.startsWith("Key") ? evt.key : evt.code
].filter(a => a).join('+').toLowerCase();
for (const commandBlock of matchingCommandBlocks) {
const action = commandBlock.actions.find(a => {
return Array.isArray(a.shortcutKey)
? a.shortcutKey.includes(key)
: a.shortcutKey == key;
});
if (action) {
evt.stopPropagation();
evt.preventDefault();
this.invokeAction(action);
// Execute the action and move on.
return;
}
// Keep checking for matching actions
}
// If execution reaches this point, there were no matching actions on the
// path of elements that were registered.
}
addCommand(element, action) {
const commandBlock = this.commandBlocks.find(b => b.element == element) ?? (() => {
const cb = { element, actions: [] };
this.commandBlocks.push(cb);
return cb;
})();
// This is likely a duplicate entry
if (commandBlock.actions.find(a => a.shortcutKey && a.shortcutKey == action.shortcutKey)) {
console.warn(`Inserting duplicate action on element`, { element, action });
}
else {
// log(LogIcon.circle_blue, `Inserted action`, action)
}
// Make the shortcut keys lowercase so case sensitivity doesn't scalp someone
if (action.shortcutKey) {
if (Array.isArray(action.shortcutKey))
action.shortcutKey = action.shortcutKey.map(k => k.toLowerCase());
else
action.shortcutKey = action.shortcutKey.toLowerCase();
}
commandBlock.actions.push(action);
}
removeCommand(element, action) {
const commandBlock = this.commandBlocks.find(b => b.element == element) ?? { element, actions: [] };
const actionIndex = commandBlock?.actions.findIndex(a => typeof action == "string" ? a.shortcutKey == action : a == action);
if (!commandBlock) {
console.error(`Cannot remove command: element does not have any commands registered`, { element, action });
}
else if (actionIndex == -1) {
console.warn(`Cannot remove command: not present in list`, { element, action });
}
else {
commandBlock.actions.splice(actionIndex, 1);
}
}
/**
*
*/
initialize(options) {
this.attachElementCommands([
{
shortcutKey: options.keybind,
action: () => this.openPalette(),
description: "Open the command palette",
keywords: ["command", "prompt", "console", "actions"],
label: "Command Palette",
visibleInList: false
}
]);
}
/**
* Open the command palette
*/
openPalette() {
return this.dialog.open(CommandPaletteComponent, {
position: {
top: "8px"
},
data: {
contextElement: document.activeElement
},
panelClass: ['ngx-command-palette'],
backdropClass: ['ngx-command-palette'],
restoreFocus: true,
role: 'dialog'
});
}
/**
* Public helper to invoke an action.
*/
invokeAction(action, args) {
const fn = action.action;
if (typeof fn == 'function') {
try {
const res = fn(args);
// Handle promises so that the GUI can show spinners for them
if (res instanceof Promise) {
// TODO
}
else {
// TODO
}
}
catch (ex) {
console.error(`Executing action threw an error`, { action }, ex);
}
}
else {
console.warn(`Cannot execute action, type is not "function"`, { action });
}
}
attachElementCommands(element = document.body, actions = []) {
if (Array.isArray(element)) {
actions = element;
element = document.body;
}
actions.forEach(a => this.addCommand(element, a));
}
/**
* Detach specified commands from an Element subtree
*/
detachElementCommands(element = document.body, actions = []) {
actions.forEach(a => this.removeCommand(element, a));
}
/**
* Return the list of registered commands under a given element
*/
getRegisteredCommands(element = document.body) {
return this.getCommandBlocks(element).map(c => c.actions).flat();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CommandPaletteService, deps: [{ token: i1.MatDialog }, { token: i2.LazyLoaderService }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CommandPaletteService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CommandPaletteService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}], ctorParameters: () => [{ type: i1.MatDialog }, { type: i2.LazyLoaderService }] });
class CommandPaletteComponent {
get el() { return this.elementRef.nativeElement; }
constructor(commandPalette, dialog, elementRef, changeDetector, data) {
this.commandPalette = commandPalette;
this.dialog = dialog;
this.elementRef = elementRef;
this.changeDetector = changeDetector;
this.MAT_ICON_REGEX = /[:\/\.]/;
this.queryString = "";
this.activeIndex = 0;
this.rowHeight = 29;
this.padding = 6;
this.commands = [];
this.filteredCommands = [];
this.breadcrumbs = [];
this.contextElement = this.contextElement ?? data.contextElement;
}
ngOnInit() {
this.commands = this.commandPalette.getRegisteredCommands(this.contextElement);
this.setCommandList(this.commands);
// TODO: custom name
this.breadcrumbs.push({
action: { label: "/" },
commands: this.commands,
destroying: false,
selectedIndex: 0
});
}
onKeyDown(evt) {
switch (evt.key) {
case "Enter": {
// Fire the first command
if (this.filteredCommands.length > 0)
this.executeCommand(this.filteredCommands[this.activeIndex]);
evt.stopPropagation();
return;
}
case "ArrowUp": {
this.activeIndex = Math.max(this.activeIndex - 1, 0);
evt.stopPropagation();
this.focusRow();
return;
}
case "ArrowDown": {
this.activeIndex = Math.min(this.filteredCommands.length - 1, this.activeIndex + 1);
evt.stopPropagation();
this.focusRow();
return;
}
case "PageUp": {
// Fire the first command
this.activeIndex = Math.max(this.activeIndex - 12, 0);
evt.stopPropagation();
this.focusRow();
return;
}
case "PageDown": {
this.activeIndex = Math.min(this.filteredCommands.length - 1, this.activeIndex + 12);
evt.stopPropagation();
this.focusRow();
return;
}
case "Escape": {
this.dialog.close();
evt.stopPropagation();
return;
}
case "Backspace": {
// If we have no characters and we're hitting backspace, go back
// to the previous menu in the breadcrumb
if (this.queryString.length == 0 && this.breadcrumbs.length > 1) {
const layer = this.breadcrumbs.at(-1);
layer.destroying = true;
setTimeout(() => {
this.setCommandList(this.breadcrumbs.at(-2).commands);
this.breadcrumbs.pop();
this.activeIndex = layer.selectedIndex;
}, 190);
return;
}
else {
break;
}
}
case "Delete": {
}
}
this.activeIndex = 0;
this.commands.forEach(c => c['_renderedLabel'] = '');
// Check in the next tick to get the input's
// value so that it's updated
setTimeout(() => {
this.queryString = evt.target.value;
this.filterResults();
});
}
async filterResults() {
// Whitespace doesn't count.
if (this.queryString.trim().length == 0) {
this.filteredCommands = this.commands;
return;
}
const queryChars = this.queryString
.toLowerCase()
.split('');
const matchedCommands = [];
for (const command of this.commands) {
const { label } = command;
// Check the label
if (command.label) {
const commandChars = label
.toLowerCase()
.split('');
let renderedLabel = '';
let lastIndex = 0;
let isMatch = true;
for (const char of queryChars) {
const index = commandChars.indexOf(char, lastIndex);
if (index == -1) {
isMatch = false;
break;
}
else {
renderedLabel += label.slice(lastIndex, index) + `<b>${label.slice(index, index + 1)}</b>`;
lastIndex = index + 1;
}
}
renderedLabel += label.slice(lastIndex);
if (isMatch) {
command['_renderedLabel'] = renderedLabel;
matchedCommands.push(command);
}
}
// Check the hint
if (command.hint) {
const commandChars = label
.toLowerCase()
.split('');
let renderedHint = '';
let lastIndex = 0;
let isMatch = true;
for (const char of queryChars) {
const index = commandChars.indexOf(char, lastIndex);
if (index == -1) {
isMatch = false;
break;
}
else {
renderedHint += label.slice(lastIndex, index) + `<b>${label.slice(index, index + 1)}</b>`;
lastIndex = index + 1;
}
}
renderedHint += label.slice(lastIndex);
if (isMatch) {
command['_renderedHint'] = renderedHint;
matchedCommands.push(command);
}
}
}
this.filteredCommands = matchedCommands;
}
setCommandList(commands) {
this.commands = commands
.filter(c => c.visibleInList != false);
this.filteredCommands = this.commands;
this.queryString = '';
this.activeIndex = 0;
// Reset the filter labels
this.commands.forEach(command => command['_renderedLabel'] = '');
}
focusRow() {
const top = this.activeIndex * this.rowHeight;
const height = this.rowHeight;
const viewTop = this.scrollbar?.viewport?.scrollTop;
const viewHeight = this.scrollbar?.viewport?.clientHeight;
const viewBottom = viewTop + viewHeight;
if (top < viewTop) {
this.scrollbar.viewport.nativeElement.scrollTo({ top: top + this.padding });
}
else if ((top + height) > viewBottom) {
this.scrollbar.viewport.nativeElement.scrollTo({ top: ((top + this.rowHeight) - viewHeight) + this.padding });
}
// Immediately check for changes to update template
this.changeDetector.detectChanges();
}
executeCommand(command) {
// Open a sub menu of items
if (Array.isArray(command.subMenu)) {
this.breadcrumbs.push({
action: command,
commands: command.subMenu,
selectedIndex: this.activeIndex,
destroying: false
});
this.setCommandList(command.subMenu);
}
// Directly invoke the action and kill the dialog
else {
this.commandPalette.invokeAction(command);
this.dialog.close();
}
}
onBlur() {
if (!isDevMode()) {
this.dialog.close();
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CommandPaletteComponent, deps: [{ token: CommandPaletteService }, { token: i1.MatDialogRef }, { token: i0.ElementRef }, { token: i0.ChangeDetectorRef }, { token: MAT_DIALOG_DATA }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: CommandPaletteComponent, isStandalone: true, selector: "ngx-command-palette", inputs: { contextElement: "contextElement" }, host: { listeners: { "click": "textInput.nativeElement.focus()", "window:blur": "onBlur()", "window:resize": "onBlur()" } }, viewQueries: [{ propertyName: "scrollbar", first: true, predicate: NgScrollbar, descendants: true }, { propertyName: "textInput", first: true, predicate: ["textinput"], descendants: true }], ngImport: i0, template: "<mat-form-field style=\"width: 100%; padding: 8px 8px 0 8px\">\n <ngx-commandpalette-breadcrumb\n [breadcrumbs]=\"breadcrumbs\"\n />\n <input\n #textinput\n matInput\n type=\"text\"\n [value]=\"queryString\"\n (keydown)=\"onKeyDown($event)\"\n >\n</mat-form-field>\n\n@if (filteredCommands.length == 0) {\n <div class=\"commands\">\n <div class=\"command selected\">\n <div class=\"label\">No matching results.</div>\n </div>\n </div>\n}\n@else {\n <div\n class=\"commands\"\n [style.flex]=\"(filteredCommands.length * rowHeight) + 'px'\"\n [class.shadow]=\"scrollbar?.viewport?.scrollTop > 2\"\n >\n <ng-scrollbar #scrollbar>\n <cdk-virtual-scroll-viewport [itemSize]=\"rowHeight\" scrollViewport [minBufferPx]=\"150\">\n <div\n *cdkVirtualFor=\"let command of filteredCommands; let index = index\"\n class=\"command\"\n [style.height]=\"rowHeight + 'px'\"\n [class.selected]=\"index==activeIndex\"\n [class.has-icon]=\"command.icon\"\n [attr.index]=\"index\"\n (click)=\"executeCommand(command)\"\n >\n @if (command.icon) {\n <div class=\"icon\">\n @if (!MAT_ICON_REGEX.test(command.icon)) {\n <mat-icon [fontIcon]=\"command.icon\"></mat-icon>\n }\n @else {\n <img [src]=\"command.icon\"/>\n }\n </div>\n }\n\n <div\n class=\"label\"\n [innerHTML]=\"command['_renderedLabel'] || command.label || command.description\"\n ></div>\n\n @if (command['_renderedHint'] || command.hint) {\n <div\n class=\"hint\"\n [innerHTML]=\"command['_renderedHint'] || command.hint\"\n ></div>\n }\n <div style=\"flex: 1\"></div>\n\n <div>\n @for (shortcut of (command.shortcutKey?.find ? command.shortcutKey : [command.shortcutKey]); track shortcut) {\n @if (shortcut) {\n <ngx-commandpalette-shortcut [shortcut]=\"shortcut\"/>\n }\n }\n </div>\n </div>\n </cdk-virtual-scroll-viewport>\n </ng-scrollbar>\n </div>\n}\n\n", styles: [":host{display:flex;flex-direction:column;width:860px;max-height:460px;border:1px solid #484848;border-radius:6px;background-color:#222;-webkit-user-select:none;user-select:none;overflow:hidden;--text-color: #ccc;--transition: .25s ease}.commands{max-height:100%;overflow:hidden;position:relative;padding:0 6px}.commands .command{display:flex;padding-left:16px;padding-right:32px;align-items:center;border-radius:3px;justify-content:space-between;color:var(--text-color);font-size:15.5px;background-color:#0000}.commands .command:hover{background-color:#2a2d2e}.commands .command.selected{background-color:#04395e}.commands .command.has-icon{padding-left:8px}.commands .command .label ::ng-deep b{color:#2196f3}.commands .command .icon{width:38px;height:100%;display:flex;align-items:center;justify-content:center}.commands .command img{max-height:100%;padding:4px}.commands .command .hint{margin-left:12px;opacity:.75}.commands.shadow:after{box-shadow:#000 0 6px 6px -6px inset}.commands:after{content:\"\";position:absolute;top:0;left:0;width:100%;height:6px;box-shadow:#0000 0 6px 6px -6px inset;transition:box-shadow .3s ease}ng-scrollbar.ng-scrollbar{--scrollbar-padding: 0px;--scrollbar-size: 14px;--scrollbar-border-radius: 0;--scrollbar-thumb-color: #4440;--scrollbar-thumb-transition: height ease-out .15s, width ease-out .15s, background-color ease 1.2s;animation:fadeScrollbar 1.2s ease}ng-scrollbar.ng-scrollbar:hover{--scrollbar-thumb-color: #444f}@keyframes fadeScrollbar{0%{--scrollbar-thumb-color: #444f}to{--scrollbar-thumb-color: #4440}}cdk-virtual-scroll-viewport{height:100%;padding-bottom:6px}:host ::ng-deep .mdc-text-field--no-label:not(.mdc-text-field--outlined):not(.mdc-text-field--textarea) .mat-mdc-form-field-infix{padding:2px 0 4px}:host ::ng-deep .mat-mdc-form-field-infix{min-height:32px;display:flex}:host ::ng-deep .mat-mdc-text-field-wrapper{margin-bottom:8px;padding:0 12px}:host ::ng-deep .mat-mdc-form-field-subscript-wrapper{display:none}::ng-deep .light app-command-palette{border:1px solid #e5e5e5;background-color:#f8f8f8;--text-color: #262626}::ng-deep .light app-command-palette .commands .command:hover{background-color:#f2f2f2}::ng-deep .light app-command-palette .commands .command.selected{background-color:#e8e8e8}\n"], dependencies: [{ kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "component", type: i5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i6.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i6.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i6.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "ngmodule", type: NgScrollbarModule }, { kind: "component", type: i7.NgScrollbar, selector: "ng-scrollbar", inputs: ["disabled", "sensorDisabled", "pointerEventsDisabled", "viewportPropagateMouseMove", "autoHeightDisabled", "autoWidthDisabled", "viewClass", "trackClass", "thumbClass", "minThumbSize", "trackClickScrollDuration", "pointerEventsMethod", "track", "visibility", "appearance", "position", "sensorDebounce", "scrollAuditTime"], outputs: ["updated"], exportAs: ["ngScrollbar"] }, { kind: "directive", type: i7.ScrollViewport, selector: "[scrollViewport]" }, { kind: "component", type: ShortcutComponent, selector: "ngx-commandpalette-shortcut", inputs: ["shortcut"] }, { kind: "component", type: BreadcrumbComponent, selector: "ngx-commandpalette-breadcrumb", inputs: ["breadcrumbs"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CommandPaletteComponent, decorators: [{
type: Component,
args: [{ selector: 'ngx-command-palette', host: {
"(click)": "textInput.nativeElement.focus()"
}, imports: [
MatIconModule,
MatInputModule,
ScrollingModule,
NgScrollbarModule,
ShortcutComponent,
BreadcrumbComponent
], standalone: true, template: "<mat-form-field style=\"width: 100%; padding: 8px 8px 0 8px\">\n <ngx-commandpalette-breadcrumb\n [breadcrumbs]=\"breadcrumbs\"\n />\n <input\n #textinput\n matInput\n type=\"text\"\n [value]=\"queryString\"\n (keydown)=\"onKeyDown($event)\"\n >\n</mat-form-field>\n\n@if (filteredCommands.length == 0) {\n <div class=\"commands\">\n <div class=\"command selected\">\n <div class=\"label\">No matching results.</div>\n </div>\n </div>\n}\n@else {\n <div\n class=\"commands\"\n [style.flex]=\"(filteredCommands.length * rowHeight) + 'px'\"\n [class.shadow]=\"scrollbar?.viewport?.scrollTop > 2\"\n >\n <ng-scrollbar #scrollbar>\n <cdk-virtual-scroll-viewport [itemSize]=\"rowHeight\" scrollViewport [minBufferPx]=\"150\">\n <div\n *cdkVirtualFor=\"let command of filteredCommands; let index = index\"\n class=\"command\"\n [style.height]=\"rowHeight + 'px'\"\n [class.selected]=\"index==activeIndex\"\n [class.has-icon]=\"command.icon\"\n [attr.index]=\"index\"\n (click)=\"executeCommand(command)\"\n >\n @if (command.icon) {\n <div class=\"icon\">\n @if (!MAT_ICON_REGEX.test(command.icon)) {\n <mat-icon [fontIcon]=\"command.icon\"></mat-icon>\n }\n @else {\n <img [src]=\"command.icon\"/>\n }\n </div>\n }\n\n <div\n class=\"label\"\n [innerHTML]=\"command['_renderedLabel'] || command.label || command.description\"\n ></div>\n\n @if (command['_renderedHint'] || command.hint) {\n <div\n class=\"hint\"\n [innerHTML]=\"command['_renderedHint'] || command.hint\"\n ></div>\n }\n <div style=\"flex: 1\"></div>\n\n <div>\n @for (shortcut of (command.shortcutKey?.find ? command.shortcutKey : [command.shortcutKey]); track shortcut) {\n @if (shortcut) {\n <ngx-commandpalette-shortcut [shortcut]=\"shortcut\"/>\n }\n }\n </div>\n </div>\n </cdk-virtual-scroll-viewport>\n </ng-scrollbar>\n </div>\n}\n\n", styles: [":host{display:flex;flex-direction:column;width:860px;max-height:460px;border:1px solid #484848;border-radius:6px;background-color:#222;-webkit-user-select:none;user-select:none;overflow:hidden;--text-color: #ccc;--transition: .25s ease}.commands{max-height:100%;overflow:hidden;position:relative;padding:0 6px}.commands .command{display:flex;padding-left:16px;padding-right:32px;align-items:center;border-radius:3px;justify-content:space-between;color:var(--text-color);font-size:15.5px;background-color:#0000}.commands .command:hover{background-color:#2a2d2e}.commands .command.selected{background-color:#04395e}.commands .command.has-icon{padding-left:8px}.commands .command .label ::ng-deep b{color:#2196f3}.commands .command .icon{width:38px;height:100%;display:flex;align-items:center;justify-content:center}.commands .command img{max-height:100%;padding:4px}.commands .command .hint{margin-left:12px;opacity:.75}.commands.shadow:after{box-shadow:#000 0 6px 6px -6px inset}.commands:after{content:\"\";position:absolute;top:0;left:0;width:100%;height:6px;box-shadow:#0000 0 6px 6px -6px inset;transition:box-shadow .3s ease}ng-scrollbar.ng-scrollbar{--scrollbar-padding: 0px;--scrollbar-size: 14px;--scrollbar-border-radius: 0;--scrollbar-thumb-color: #4440;--scrollbar-thumb-transition: height ease-out .15s, width ease-out .15s, background-color ease 1.2s;animation:fadeScrollbar 1.2s ease}ng-scrollbar.ng-scrollbar:hover{--scrollbar-thumb-color: #444f}@keyframes fadeScrollbar{0%{--scrollbar-thumb-color: #444f}to{--scrollbar-thumb-color: #4440}}cdk-virtual-scroll-viewport{height:100%;padding-bottom:6px}:host ::ng-deep .mdc-text-field--no-label:not(.mdc-text-field--outlined):not(.mdc-text-field--textarea) .mat-mdc-form-field-infix{padding:2px 0 4px}:host ::ng-deep .mat-mdc-form-field-infix{min-height:32px;display:flex}:host ::ng-deep .mat-mdc-text-field-wrapper{margin-bottom:8px;padding:0 12px}:host ::ng-deep .mat-mdc-form-field-subscript-wrapper{display:none}::ng-deep .light app-command-palette{border:1px solid #e5e5e5;background-color:#f8f8f8;--text-color: #262626}::ng-deep .light app-command-palette .commands .command:hover{background-color:#f2f2f2}::ng-deep .light app-command-palette .commands .command.selected{background-color:#e8e8e8}\n"] }]
}], ctorParameters: () => [{ type: CommandPaletteService }, { type: i1.MatDialogRef }, { type: i0.ElementRef }, { type: i0.ChangeDetectorRef }, { type: undefined, decorators: [{
type: Inject,
args: [MAT_DIALOG_DATA]
}] }], propDecorators: { scrollbar: [{
type: ViewChild,
args: [NgScrollbar]
}], textInput: [{
type: ViewChild,
args: ['textinput']
}], contextElement: [{
type: Input
}], onBlur: [{
type: HostListener,
args: ["window:blur"]
}, {
type: HostListener,
args: ["window:resize"]
}] } });
/**
* Generated bundle index. Do not edit.
*/
export { CommandPaletteComponent, CommandPaletteService };
//# sourceMappingURL=dotglitch-ngx-common-command-palette.mjs.map