UNPKG

@dotglitch/ngx-common

Version:

Angular components and utilities that are commonly used.

509 lines (502 loc) 38.6 kB
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