@flxgde/gigamenu 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flxgde-gigamenu.mjs","sources":["../../../src/lib/types.ts","../../../src/lib/gigamenu.service.ts","../../../src/lib/gigamenu-templates.directive.ts","../../../src/lib/frecency.service.ts","../../../src/lib/gigamenu.component.ts","../../../src/lib/gigamenu.component.html","../../../src/flxgde-gigamenu.ts"],"sourcesContent":["export type GigamenuItemCategory = 'page' | 'command';\n\nexport interface GigamenuItem {\n id: string;\n label: string;\n description?: string;\n /** Emoji or text icon */\n icon?: string;\n /** CSS class for icon libraries (e.g., 'pi pi-home', 'fa fa-home') */\n iconClass?: string;\n keywords?: string[];\n category: GigamenuItemCategory;\n /** Action to execute. Receives args string if user typed text after the separator. */\n action: (args?: string) => void;\n}\n\nexport interface GigamenuPage extends Omit<GigamenuItem, 'category' | 'action'> {\n path: string;\n}\n\nexport interface GigamenuCommand extends Omit<GigamenuItem, 'category'> {\n shortcut?: string;\n}\n\nexport interface GigamenuConfig {\n placeholder?: string;\n maxResults?: number;\n autoDiscoverRoutes?: boolean;\n /** Separator between search query and arguments (default: ' ') */\n argSeparator?: string;\n}\n\nexport const DEFAULT_CONFIG: GigamenuConfig = {\n placeholder: 'Search pages and commands...',\n maxResults: 10,\n autoDiscoverRoutes: true,\n argSeparator: ' ',\n};\n\n/**\n * Base interface for defining a command in a separate file.\n * Each command file should export a constant implementing this interface.\n */\nexport interface CommandDefinition {\n readonly id: string;\n readonly label: string;\n readonly description?: string;\n readonly icon?: string;\n readonly iconClass?: string;\n readonly keywords?: string[];\n readonly shortcut?: string;\n execute(): void;\n}\n\n/**\n * Helper function to define a command with type safety.\n */\nexport function defineCommand(command: CommandDefinition): CommandDefinition {\n return command;\n}\n\n/**\n * Information about a route passed to the filter function.\n */\nexport interface RouteInfo {\n path: string;\n fullPath: string;\n data?: Record<string, unknown>;\n title?: string;\n}\n\n/**\n * Filter function to include/exclude routes from discovery.\n * Return true to include the route, false to exclude it.\n */\nexport type RouteFilter = (route: RouteInfo) => boolean;\n\n/**\n * Mapped page data returned from the map function.\n */\nexport interface MappedPage {\n label?: string;\n description?: string;\n icon?: string;\n iconClass?: string;\n keywords?: string[];\n}\n\n/**\n * Map function to customize page data for discovered routes.\n * Return partial page data to override defaults, or null to skip the route.\n */\nexport type RouteMapper = (route: RouteInfo) => MappedPage | null;\n\n/**\n * Options for route discovery.\n */\nexport interface DiscoverRoutesOptions {\n filter?: RouteFilter;\n map?: RouteMapper;\n}\n","import { Injectable, signal, computed } from '@angular/core';\nimport { Router, Route, Routes } from '@angular/router';\nimport {\n GigamenuItem,\n GigamenuCommand,\n GigamenuPage,\n GigamenuConfig,\n DEFAULT_CONFIG,\n DiscoverRoutesOptions,\n RouteInfo,\n} from './types';\n\n@Injectable({ providedIn: 'root' })\nexport class GigamenuService {\n private readonly _items = signal<Map<string, GigamenuItem>>(new Map());\n private readonly _isOpen = signal(false);\n private readonly _config = signal<GigamenuConfig>(DEFAULT_CONFIG);\n\n readonly items = computed(() => Array.from(this._items().values()));\n readonly isOpen = this._isOpen.asReadonly();\n readonly config = this._config.asReadonly();\n\n constructor(private readonly router: Router) {}\n\n configure(config: Partial<GigamenuConfig>): void {\n this._config.update((current) => ({ ...current, ...config }));\n }\n\n open(): void {\n this._isOpen.set(true);\n }\n\n close(): void {\n this._isOpen.set(false);\n }\n\n toggle(): void {\n this._isOpen.update((v) => !v);\n }\n\n registerItem(item: GigamenuItem): void {\n this._items.update((items) => {\n const newItems = new Map(items);\n newItems.set(item.id, item);\n return newItems;\n });\n }\n\n unregisterItem(id: string): void {\n this._items.update((items) => {\n const newItems = new Map(items);\n newItems.delete(id);\n return newItems;\n });\n }\n\n registerCommand(command: GigamenuCommand): void {\n this.registerItem({\n ...command,\n category: 'command',\n });\n }\n\n registerPage(page: GigamenuPage): void {\n this.registerItem({\n ...page,\n category: 'page',\n action: () => this.router.navigate([page.path]),\n });\n }\n\n discoverRoutes(options?: DiscoverRoutesOptions): void;\n discoverRoutes(routes?: Routes, options?: DiscoverRoutesOptions): void;\n discoverRoutes(\n routesOrOptions?: Routes | DiscoverRoutesOptions,\n maybeOptions?: DiscoverRoutesOptions\n ): void {\n let routes: Routes;\n let options: DiscoverRoutesOptions | undefined;\n\n if (Array.isArray(routesOrOptions)) {\n routes = routesOrOptions;\n options = maybeOptions;\n } else {\n routes = this.router.config;\n options = routesOrOptions;\n }\n\n this.extractPagesFromRoutes(routes, '', options?.filter);\n }\n\n private extractPagesFromRoutes(\n routes: Routes,\n parentPath: string,\n filter?: (route: RouteInfo) => boolean\n ): void {\n for (const route of routes) {\n if (route.redirectTo !== undefined) continue;\n\n const fullPath = parentPath\n ? `${parentPath}/${route.path ?? ''}`\n : route.path ?? '';\n\n if (route.path !== undefined && route.path !== '**') {\n const routeInfo: RouteInfo = {\n path: route.path,\n fullPath: `/${fullPath}`,\n data: route.data as Record<string, unknown> | undefined,\n title: typeof route.title === 'string' ? route.title : undefined,\n };\n\n // Apply filter if provided\n if (filter && !filter(routeInfo)) {\n // Still process children even if this route is filtered\n if (route.children) {\n this.extractPagesFromRoutes(route.children, fullPath, filter);\n }\n continue;\n }\n\n const label = routeInfo.title || this.pathToLabel(route.path || 'Home');\n this.registerPage({\n id: `page:${fullPath || '/'}`,\n label,\n path: `/${fullPath}`,\n description: `Navigate to ${label}`,\n });\n }\n\n if (route.children) {\n this.extractPagesFromRoutes(route.children, fullPath, filter);\n }\n }\n }\n\n private pathToLabel(path: string): string {\n return path\n .split('/')\n .pop()!\n .replace(/[-_]/g, ' ')\n .replace(/\\b\\w/g, (c) => c.toUpperCase());\n }\n}\n","import { Directive, TemplateRef, inject } from '@angular/core';\nimport { GigamenuItem } from './types';\n\n/**\n * Context provided to the item template.\n */\nexport interface GigamenuItemContext {\n /** The menu item being rendered */\n $implicit: GigamenuItem;\n /** The index of the item in the filtered list */\n index: number;\n /** Whether this item is currently selected */\n selected: boolean;\n}\n\n/**\n * Context provided to the empty template.\n */\nexport interface GigamenuEmptyContext {\n /** The current search query */\n $implicit: string;\n}\n\n/**\n * Context provided to the header template.\n */\nexport interface GigamenuHeaderContext {\n /** The current full query */\n $implicit: string;\n /** The search term (before separator) */\n searchTerm: string;\n /** The arguments (after separator) */\n args: string;\n /** Callback to update the query */\n onQueryChange: (value: string) => void;\n /** Callback for keydown events */\n onKeydown: (event: KeyboardEvent) => void;\n /** Placeholder text */\n placeholder: string;\n}\n\n/**\n * Context provided to the footer template.\n */\nexport interface GigamenuFooterContext {\n /** Number of filtered items */\n $implicit: number;\n /** Total number of items */\n total: number;\n}\n\n/**\n * Template directive for customizing menu item rendering.\n *\n * @example\n * ```html\n * <gm-gigamenu>\n * <ng-template gmItem let-item let-selected=\"selected\" let-index=\"index\">\n * <div [class.active]=\"selected\">\n * {{ item.label }}\n * </div>\n * </ng-template>\n * </gm-gigamenu>\n * ```\n */\n@Directive({\n selector: '[gmItem]',\n standalone: true,\n})\nexport class GigamenuItemTemplate {\n readonly template = inject<TemplateRef<GigamenuItemContext>>(TemplateRef);\n}\n\n/**\n * Template directive for customizing empty state rendering.\n *\n * @example\n * ```html\n * <gm-gigamenu>\n * <ng-template gmEmpty let-query>\n * <div>No results for \"{{ query }}\"</div>\n * </ng-template>\n * </gm-gigamenu>\n * ```\n */\n@Directive({\n selector: '[gmEmpty]',\n standalone: true,\n})\nexport class GigamenuEmptyTemplate {\n readonly template = inject<TemplateRef<GigamenuEmptyContext>>(TemplateRef);\n}\n\n/**\n * Template directive for customizing header/search input rendering.\n *\n * @example\n * ```html\n * <gm-gigamenu>\n * <ng-template gmHeader let-query let-onQueryChange=\"onQueryChange\" let-onKeydown=\"onKeydown\">\n * <input [value]=\"query\" (input)=\"onQueryChange($event.target.value)\" (keydown)=\"onKeydown($event)\" />\n * </ng-template>\n * </gm-gigamenu>\n * ```\n */\n@Directive({\n selector: '[gmHeader]',\n standalone: true,\n})\nexport class GigamenuHeaderTemplate {\n readonly template = inject<TemplateRef<GigamenuHeaderContext>>(TemplateRef);\n}\n\n/**\n * Template directive for customizing footer rendering.\n *\n * @example\n * ```html\n * <gm-gigamenu>\n * <ng-template gmFooter let-count let-total=\"total\">\n * <div>Showing {{ count }} of {{ total }} items</div>\n * </ng-template>\n * </gm-gigamenu>\n * ```\n */\n@Directive({\n selector: '[gmFooter]',\n standalone: true,\n})\nexport class GigamenuFooterTemplate {\n readonly template = inject<TemplateRef<GigamenuFooterContext>>(TemplateRef);\n}\n\n/**\n * Template directive for customizing the entire panel/dialog container.\n * When provided, replaces the entire default panel structure.\n *\n * @example\n * ```html\n * <gm-gigamenu>\n * <ng-template gmPanel let-items let-query=\"query\" let-selectedIndex=\"selectedIndex\">\n * <div class=\"my-custom-panel\">\n * <!-- Custom implementation -->\n * </div>\n * </ng-template>\n * </gm-gigamenu>\n * ```\n */\nexport interface GigamenuPanelContext {\n /** Filtered items to display */\n $implicit: GigamenuItem[];\n /** Current full query */\n query: string;\n /** The search term (before separator) */\n searchTerm: string;\n /** The arguments (after separator) */\n args: string;\n /** Currently selected index */\n selectedIndex: number;\n /** Callback to execute an item */\n executeItem: (item: GigamenuItem) => void;\n /** Callback to update selection */\n setSelectedIndex: (index: number) => void;\n /** Callback to update query */\n setQuery: (query: string) => void;\n /** Callback to close the menu */\n close: () => void;\n /** Placeholder text from config */\n placeholder: string;\n}\n\n@Directive({\n selector: '[gmPanel]',\n standalone: true,\n})\nexport class GigamenuPanelTemplate {\n readonly template = inject<TemplateRef<GigamenuPanelContext>>(TemplateRef);\n}\n","import { Injectable, PLATFORM_ID, Inject } from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\n\ninterface FrecencyEntry {\n itemId: string;\n count: number;\n lastUsed: number;\n}\n\ninterface FrecencyData {\n [searchTerm: string]: FrecencyEntry[];\n}\n\nconst STORAGE_KEY = 'gigamenu_frecency';\nconst GLOBAL_KEY = '__global__';\nconst MAX_ENTRIES_PER_TERM = 10;\nconst MAX_TERMS = 100;\nconst DECAY_FACTOR = 0.9;\n\n@Injectable({ providedIn: 'root' })\nexport class FrecencyService {\n private data: FrecencyData = {};\n private readonly isBrowser: boolean;\n\n constructor(@Inject(PLATFORM_ID) platformId: object) {\n this.isBrowser = isPlatformBrowser(platformId);\n this.load();\n }\n\n /**\n * Record that an item was selected for a given search term.\n */\n recordSelection(searchTerm: string, itemId: string): void {\n // Always record to global for overall frecency\n this.recordToKey(GLOBAL_KEY, itemId);\n\n // Also record to specific search term if provided\n const normalizedTerm = this.normalizeTerm(searchTerm);\n if (normalizedTerm) {\n this.recordToKey(normalizedTerm, itemId);\n }\n\n this.pruneAndSave();\n }\n\n private recordToKey(key: string, itemId: string): void {\n if (!this.data[key]) {\n this.data[key] = [];\n }\n\n const entries = this.data[key];\n const existing = entries.find((e) => e.itemId === itemId);\n\n if (existing) {\n existing.count++;\n existing.lastUsed = Date.now();\n } else {\n entries.push({\n itemId,\n count: 1,\n lastUsed: Date.now(),\n });\n }\n\n // Keep only top entries\n this.data[key] = entries\n .sort((a, b) => this.calculateScore(b) - this.calculateScore(a))\n .slice(0, MAX_ENTRIES_PER_TERM);\n }\n\n /**\n * Get frecency scores for items matching a search term.\n * Returns a map of itemId -> score (higher is better).\n */\n getScores(searchTerm: string): Map<string, number> {\n const scores = new Map<string, number>();\n const normalizedTerm = this.normalizeTerm(searchTerm);\n\n // If no search term, return global scores\n if (!normalizedTerm) {\n const globalEntries = this.data[GLOBAL_KEY];\n if (globalEntries) {\n for (const entry of globalEntries) {\n scores.set(entry.itemId, this.calculateScore(entry));\n }\n }\n return scores;\n }\n\n // Exact match for search term\n const exactEntries = this.data[normalizedTerm];\n if (exactEntries) {\n for (const entry of exactEntries) {\n const score = this.calculateScore(entry);\n scores.set(entry.itemId, score);\n }\n }\n\n // Prefix matches (for partial typing)\n for (const [term, entries] of Object.entries(this.data)) {\n if (term !== GLOBAL_KEY && term !== normalizedTerm && term.startsWith(normalizedTerm)) {\n for (const entry of entries) {\n const currentScore = scores.get(entry.itemId) ?? 0;\n // Prefix matches get reduced weight\n const prefixScore = this.calculateScore(entry) * 0.5;\n scores.set(entry.itemId, Math.max(currentScore, prefixScore));\n }\n }\n }\n\n return scores;\n }\n\n /**\n * Get the most likely item for a search term (for auto-selection).\n * Returns itemId if there's a strong match, null otherwise.\n */\n getTopMatch(searchTerm: string): string | null {\n const normalizedTerm = this.normalizeTerm(searchTerm);\n if (!normalizedTerm) return null;\n\n const entries = this.data[normalizedTerm];\n if (!entries || entries.length === 0) return null;\n\n const topEntry = entries[0];\n const score = this.calculateScore(topEntry);\n\n // Only auto-select if strong confidence (used multiple times recently)\n if (topEntry.count >= 2 && score > 5) {\n return topEntry.itemId;\n }\n\n return null;\n }\n\n private calculateScore(entry: FrecencyEntry): number {\n const ageInHours = (Date.now() - entry.lastUsed) / (60 * 60 * 24);\n const recencyScore = Math.pow(DECAY_FACTOR, ageInHours);\n return entry.count * recencyScore;\n }\n\n private normalizeTerm(term: string): string {\n return term.toLowerCase().trim();\n }\n\n private load(): void {\n if (!this.isBrowser) return;\n\n try {\n const stored = localStorage.getItem(STORAGE_KEY);\n if (stored) {\n this.data = JSON.parse(stored);\n }\n } catch {\n this.data = {};\n }\n }\n\n private pruneAndSave(): void {\n if (!this.isBrowser) return;\n\n // Prune old terms if we have too many\n const terms = Object.keys(this.data);\n if (terms.length > MAX_TERMS) {\n const termScores = terms.map((term) => ({\n term,\n maxScore: Math.max(...this.data[term].map((e) => this.calculateScore(e))),\n }));\n termScores.sort((a, b) => b.maxScore - a.maxScore);\n\n const keepTerms = new Set(termScores.slice(0, MAX_TERMS).map((t) => t.term));\n for (const term of terms) {\n if (!keepTerms.has(term)) {\n delete this.data[term];\n }\n }\n }\n\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(this.data));\n } catch {\n // Storage full or unavailable\n }\n }\n}\n","import {\n Component,\n signal,\n computed,\n effect,\n ElementRef,\n viewChild,\n contentChild,\n HostListener,\n PLATFORM_ID,\n Inject,\n TemplateRef,\n} from '@angular/core';\nimport { isPlatformBrowser, NgTemplateOutlet } from '@angular/common';\nimport { GigamenuService } from './gigamenu.service';\nimport { FrecencyService } from './frecency.service';\nimport { GigamenuItem } from './types';\nimport {\n GigamenuItemTemplate,\n GigamenuEmptyTemplate,\n GigamenuHeaderTemplate,\n GigamenuFooterTemplate,\n GigamenuPanelTemplate,\n GigamenuItemContext,\n GigamenuEmptyContext,\n GigamenuHeaderContext,\n GigamenuFooterContext,\n GigamenuPanelContext,\n} from './gigamenu-templates.directive';\n\n@Component({\n selector: 'gm-gigamenu',\n standalone: true,\n imports: [NgTemplateOutlet],\n templateUrl: 'gigamenu.component.html',\n styles: `\n :host {\n display: contents;\n }\n `,\n})\nexport class GigamenuComponent {\n private readonly searchInput = viewChild<ElementRef<HTMLInputElement>>('searchInput');\n private readonly listContainer = viewChild<ElementRef<HTMLDivElement>>('listContainer');\n private readonly isBrowser: boolean;\n\n // Template queries\n protected readonly itemTemplate = contentChild(GigamenuItemTemplate);\n protected readonly emptyTemplate = contentChild(GigamenuEmptyTemplate);\n protected readonly headerTemplate = contentChild(GigamenuHeaderTemplate);\n protected readonly footerTemplate = contentChild(GigamenuFooterTemplate);\n protected readonly panelTemplate = contentChild(GigamenuPanelTemplate);\n\n protected readonly query = signal('');\n protected readonly selectedIndex = signal(0);\n\n /** Parsed search term (before first separator) */\n protected readonly searchTerm = computed(() => {\n const q = this.query();\n const separator = this.service.config().argSeparator ?? ' ';\n const sepIndex = q.indexOf(separator);\n if (sepIndex === -1) return q;\n return q.substring(0, sepIndex);\n });\n\n /** Parsed arguments (after first separator) */\n protected readonly args = computed(() => {\n const q = this.query();\n const separator = this.service.config().argSeparator ?? ' ';\n const sepIndex = q.indexOf(separator);\n if (sepIndex === -1) return '';\n return q.substring(sepIndex + separator.length);\n });\n\n protected readonly filteredItems = computed(() => {\n const searchTerm = this.searchTerm().toLowerCase().trim();\n const items = this.service.items();\n const maxResults = this.service.config().maxResults ?? 10;\n\n if (!searchTerm) {\n // No query: sort by frecency scores from empty searches\n const scores = this.frecency.getScores('');\n return this.sortByFrecency(items, scores).slice(0, maxResults);\n }\n\n // Filter matching items using only search term (not args)\n const matched = items.filter((item) => this.matchesQuery(item, searchTerm));\n\n // Sort by frecency for this search term\n const scores = this.frecency.getScores(searchTerm);\n return this.sortByFrecency(matched, scores).slice(0, maxResults);\n });\n\n constructor(\n protected readonly service: GigamenuService,\n private readonly frecency: FrecencyService,\n @Inject(PLATFORM_ID) platformId: object\n ) {\n this.isBrowser = isPlatformBrowser(platformId);\n\n effect(() => {\n if (this.service.isOpen() && this.isBrowser) {\n setTimeout(() => this.searchInput()?.nativeElement.focus(), 0);\n }\n });\n\n effect(() => {\n const items = this.filteredItems();\n const searchTerm = this.searchTerm();\n\n // Check for auto-select based on frecency\n if (searchTerm && items.length > 0) {\n const topMatch = this.frecency.getTopMatch(searchTerm);\n if (topMatch) {\n const idx = items.findIndex((item) => item.id === topMatch);\n if (idx !== -1) {\n this.selectedIndex.set(idx);\n return;\n }\n }\n }\n\n this.selectedIndex.set(0);\n });\n }\n\n @HostListener('document:keydown', ['$event'])\n onGlobalKeydown(event: KeyboardEvent): void {\n if (!this.isBrowser) return;\n\n if ((event.metaKey || event.ctrlKey) && event.key === 'k') {\n event.preventDefault();\n this.service.toggle();\n return;\n }\n\n if (event.key === '/' && !this.isInputFocused()) {\n event.preventDefault();\n this.service.open();\n return;\n }\n\n if (event.key === 'Escape' && this.service.isOpen()) {\n event.preventDefault();\n this.close();\n }\n }\n\n protected onInputKeydown(event: KeyboardEvent): void {\n const items = this.filteredItems();\n\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n this.selectedIndex.update((i) => Math.min(i + 1, items.length - 1));\n this.scrollSelectedIntoView();\n break;\n\n case 'ArrowUp':\n event.preventDefault();\n this.selectedIndex.update((i) => Math.max(i - 1, 0));\n this.scrollSelectedIntoView();\n break;\n\n case 'Enter':\n event.preventDefault();\n const selected = items[this.selectedIndex()];\n if (selected) {\n this.executeItem(selected);\n }\n break;\n\n case 'Escape':\n event.preventDefault();\n this.close();\n break;\n }\n }\n\n private scrollSelectedIntoView(): void {\n const container = this.listContainer()?.nativeElement;\n if (!container) return;\n\n const selectedButton = container.querySelector(\n `[data-index=\"${this.selectedIndex()}\"]`\n ) as HTMLElement | null;\n\n if (selectedButton) {\n selectedButton.scrollIntoView({ block: 'nearest' });\n }\n }\n\n protected onQueryChange(event: Event): void {\n const value = (event.target as HTMLInputElement).value;\n this.query.set(value);\n }\n\n protected onBackdropClick(event: MouseEvent): void {\n if (event.target === event.currentTarget) {\n this.close();\n }\n }\n\n protected executeItem(item: GigamenuItem): void {\n // Record the selection for frecency learning (use search term, not full query)\n const searchTerm = this.searchTerm();\n this.frecency.recordSelection(searchTerm, item.id);\n\n // Get args before closing (which resets query)\n const args = this.args() || undefined;\n\n this.close();\n item.action(args);\n }\n\n // Template context getters\n protected getItemContext(item: GigamenuItem, index: number): GigamenuItemContext {\n return {\n $implicit: item,\n index,\n selected: this.selectedIndex() === index,\n };\n }\n\n protected getEmptyContext(): GigamenuEmptyContext {\n return {\n $implicit: this.query(),\n };\n }\n\n protected getHeaderContext(): GigamenuHeaderContext {\n return {\n $implicit: this.query(),\n searchTerm: this.searchTerm(),\n args: this.args(),\n onQueryChange: (value: string) => this.query.set(value),\n onKeydown: (event: KeyboardEvent) => this.onInputKeydown(event),\n placeholder: this.service.config().placeholder ?? '',\n };\n }\n\n protected getFooterContext(): GigamenuFooterContext {\n return {\n $implicit: this.filteredItems().length,\n total: this.service.items().length,\n };\n }\n\n protected getPanelContext(): GigamenuPanelContext {\n return {\n $implicit: this.filteredItems(),\n query: this.query(),\n searchTerm: this.searchTerm(),\n args: this.args(),\n selectedIndex: this.selectedIndex(),\n executeItem: (item: GigamenuItem) => this.executeItem(item),\n setSelectedIndex: (index: number) => this.selectedIndex.set(index),\n setQuery: (query: string) => this.query.set(query),\n close: () => this.close(),\n placeholder: this.service.config().placeholder ?? '',\n };\n }\n\n private close(): void {\n this.service.close();\n this.query.set('');\n this.selectedIndex.set(0);\n }\n\n private sortByFrecency(items: GigamenuItem[], scores: Map<string, number>): GigamenuItem[] {\n if (scores.size === 0) return items;\n\n return [...items].sort((a, b) => {\n const scoreA = scores.get(a.id) ?? 0;\n const scoreB = scores.get(b.id) ?? 0;\n return scoreB - scoreA;\n });\n }\n\n private matchesQuery(item: GigamenuItem, query: string): boolean {\n const searchableText = [\n item.label,\n item.description,\n ...(item.keywords ?? []),\n ]\n .filter(Boolean)\n .join(' ')\n .toLowerCase();\n\n const words = query.split(/\\s+/);\n return words.every((word) => searchableText.includes(word));\n }\n\n private isInputFocused(): boolean {\n const activeElement = document.activeElement;\n if (!activeElement) return false;\n\n const tagName = activeElement.tagName.toLowerCase();\n return (\n tagName === 'input' ||\n tagName === 'textarea' ||\n (activeElement as HTMLElement).isContentEditable\n );\n }\n}\n","@if (service.isOpen()) {\n<div\n class=\"fixed inset-0 z-50 flex items-start justify-center pt-[15vh]\"\n (click)=\"onBackdropClick($event)\"\n>\n <div class=\"fixed inset-0 bg-black/50 backdrop-blur-sm\"></div>\n\n <!-- Custom panel template -->\n @if (panelTemplate(); as pt) {\n <ng-container\n [ngTemplateOutlet]=\"pt.template\"\n [ngTemplateOutletContext]=\"getPanelContext()\"\n ></ng-container>\n } @else {\n <!-- Default panel -->\n <div\n class=\"relative z-10 w-full max-w-xl overflow-hidden rounded-xl border border-neutral-200 bg-white shadow-2xl dark:border-neutral-700 dark:bg-neutral-900\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Command menu\"\n >\n <!-- Header -->\n @if (headerTemplate(); as ht) {\n <ng-container\n [ngTemplateOutlet]=\"ht.template\"\n [ngTemplateOutletContext]=\"getHeaderContext()\"\n ></ng-container>\n } @else {\n <div class=\"flex items-center border-b border-neutral-200 px-4 dark:border-neutral-700\">\n <svg\n class=\"h-5 w-5 text-neutral-400\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\"\n />\n </svg>\n <div class=\"relative flex-1\">\n <!-- Styled overlay for syntax highlighting -->\n <div\n class=\"pointer-events-none absolute inset-0 flex items-center px-3 py-4 text-base\"\n aria-hidden=\"true\"\n >\n <span class=\"text-neutral-900 dark:text-neutral-100\">{{ searchTerm() }}</span>@if (args()) {<span class=\"text-neutral-900 dark:text-neutral-100\">{{ service.config().argSeparator }}</span><span class=\"text-purple-600 dark:text-purple-400\">{{ args() }}</span>}\n </div>\n <!-- Transparent input on top -->\n <input\n #searchInput\n type=\"text\"\n [placeholder]=\"service.config().placeholder\"\n [value]=\"query()\"\n (input)=\"onQueryChange($event)\"\n (keydown)=\"onInputKeydown($event)\"\n class=\"relative z-10 w-full bg-transparent px-3 py-4 text-base text-transparent caret-neutral-900 placeholder-neutral-400 outline-none dark:caret-neutral-100\"\n />\n </div>\n <kbd\n class=\"rounded border border-neutral-200 bg-neutral-100 px-1.5 py-0.5 text-xs text-neutral-500 dark:border-neutral-600 dark:bg-neutral-800 dark:text-neutral-400\"\n >\n ESC\n </kbd>\n </div>\n }\n\n <!-- Items list -->\n <div #listContainer class=\"max-h-80 overflow-y-auto p-2\">\n @if (filteredItems().length === 0) {\n <!-- Empty state -->\n @if (emptyTemplate(); as et) {\n <ng-container\n [ngTemplateOutlet]=\"et.template\"\n [ngTemplateOutletContext]=\"getEmptyContext()\"\n ></ng-container>\n } @else {\n <div class=\"px-3 py-8 text-center text-neutral-500\">\n No results found\n </div>\n }\n } @else {\n @for (item of filteredItems(); track item.id; let i = $index) {\n <!-- Custom item template -->\n @if (itemTemplate(); as it) {\n <ng-container\n [ngTemplateOutlet]=\"it.template\"\n [ngTemplateOutletContext]=\"getItemContext(item, i)\"\n ></ng-container>\n } @else {\n <!-- Default item -->\n <button\n type=\"button\"\n (click)=\"executeItem(item)\"\n (mouseenter)=\"selectedIndex.set(i)\"\n [attr.data-index]=\"i\"\n [class]=\"\n 'flex w-full items-center gap-3 rounded-lg px-3 py-2.5 text-left transition-colors ' +\n (selectedIndex() === i\n ? 'bg-neutral-100 dark:bg-neutral-800'\n : 'hover:bg-neutral-50 dark:hover:bg-neutral-800/50')\n \"\n >\n @if (item.iconClass) {\n <i [class]=\"item.iconClass + ' text-lg text-neutral-600 dark:text-neutral-300'\"></i>\n } @else if (item.icon) {\n <span class=\"text-lg\">{{ item.icon }}</span>\n } @else {\n <span\n class=\"flex h-6 w-6 items-center justify-center rounded bg-neutral-200 text-xs font-medium text-neutral-600 dark:bg-neutral-700 dark:text-neutral-300\"\n >\n {{ item.category === 'page' ? 'P' : 'C' }}\n </span>\n }\n <div class=\"flex-1 min-w-0\">\n <div class=\"truncate font-medium text-neutral-900 dark:text-neutral-100\">\n {{ item.label }}\n </div>\n @if (item.description) {\n <div class=\"truncate text-sm text-neutral-500 dark:text-neutral-400\">\n {{ item.description }}\n </div>\n }\n </div>\n <span\n class=\"rounded-full px-2 py-0.5 text-xs\"\n [class]=\"\n item.category === 'page'\n ? 'bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400'\n : 'bg-purple-100 text-purple-700 dark:bg-purple-900/30 dark:text-purple-400'\n \"\n >\n {{ item.category }}\n </span>\n </button>\n }\n }\n }\n </div>\n\n <!-- Footer -->\n @if (footerTemplate(); as ft) {\n <ng-container\n [ngTemplateOutlet]=\"ft.template\"\n [ngTemplateOutletContext]=\"getFooterContext()\"\n ></ng-container>\n } @else {\n <div\n class=\"flex items-center justify-between border-t border-neutral-200 px-4 py-2 text-xs text-neutral-500 dark:border-neutral-700\"\n >\n <div class=\"flex items-center gap-3\">\n <span class=\"flex items-center gap-1\">\n <kbd class=\"rounded border border-neutral-300 bg-neutral-100 px-1 dark:border-neutral-600 dark:bg-neutral-800\">↑</kbd>\n <kbd class=\"rounded border border-neutral-300 bg-neutral-100 px-1 dark:border-neutral-600 dark:bg-neutral-800\">↓</kbd>\n navigate\n </span>\n <span class=\"flex items-center gap-1\">\n <kbd class=\"rounded border border-neutral-300 bg-neutral-100 px-1 dark:border-neutral-600 dark:bg-neutral-800\">↵</kbd>\n select\n </span>\n </div>\n <span>gigamenu</span>\n </div>\n }\n </div>\n }\n</div>\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,39 +1,43 @@
1
- {
2
- "name": "@flxgde/gigamenu",
3
- "version": "0.0.1",
4
- "description": "A keyboard-driven command palette menu for Angular applications",
5
- "keywords": [
6
- "angular",
7
- "command-palette",
8
- "keyboard-navigation",
9
- "menu",
10
- "spotlight",
11
- "ctrl-k"
12
- ],
13
- "author": "",
14
- "license": "MIT",
15
- "repository": {
16
- "type": "git",
17
- "url": "https://github.com/flxgde/gigamenu"
18
- },
19
- "homepage": "https://github.com/flxgde/gigamenu#readme",
20
- "bugs": {
21
- "url": "https://github.com/flxgde/gigamenu/issues"
22
- },
23
- "scripts": {
24
- "build": "ng-packagr",
25
- "build:prod": "ng-packagr -c tsconfig.lib.prod.json"
26
- },
27
- "sideEffects": false,
28
- "peerDependencies": {
29
- "@angular/common": "^21.0.0",
30
- "@angular/core": "^21.0.0",
31
- "@angular/router": "^21.0.0"
32
- },
33
- "devDependencies": {
34
- "ng-packagr": "^21.0.0",
35
- "@angular/compiler": "^21.0.0",
36
- "@angular/compiler-cli": "^21.0.0",
37
- "typescript": "~5.9.2"
38
- }
39
- }
1
+ {
2
+ "name": "@flxgde/gigamenu",
3
+ "version": "0.0.2",
4
+ "description": "A keyboard-driven command palette menu for Angular applications",
5
+ "keywords": [
6
+ "angular",
7
+ "command-palette",
8
+ "keyboard-navigation",
9
+ "menu",
10
+ "spotlight",
11
+ "ctrl-k"
12
+ ],
13
+ "author": "",
14
+ "license": "MIT",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/flxgde/gigamenu"
18
+ },
19
+ "homepage": "https://github.com/flxgde/gigamenu#readme",
20
+ "bugs": {
21
+ "url": "https://github.com/flxgde/gigamenu/issues"
22
+ },
23
+ "sideEffects": false,
24
+ "peerDependencies": {
25
+ "@angular/common": "^21.0.0",
26
+ "@angular/core": "^21.0.0",
27
+ "@angular/router": "^21.0.0"
28
+ },
29
+ "module": "fesm2022/flxgde-gigamenu.mjs",
30
+ "typings": "types/flxgde-gigamenu.d.ts",
31
+ "exports": {
32
+ "./package.json": {
33
+ "default": "./package.json"
34
+ },
35
+ ".": {
36
+ "types": "./types/flxgde-gigamenu.d.ts",
37
+ "default": "./fesm2022/flxgde-gigamenu.mjs"
38
+ }
39
+ },
40
+ "dependencies": {
41
+ "tslib": "^2.3.0"
42
+ }
43
+ }
@@ -0,0 +1,336 @@
1
+ import * as i0 from '@angular/core';
2
+ import { TemplateRef } from '@angular/core';
3
+ import { Router, Routes } from '@angular/router';
4
+
5
+ type GigamenuItemCategory = 'page' | 'command';
6
+ interface GigamenuItem {
7
+ id: string;
8
+ label: string;
9
+ description?: string;
10
+ /** Emoji or text icon */
11
+ icon?: string;
12
+ /** CSS class for icon libraries (e.g., 'pi pi-home', 'fa fa-home') */
13
+ iconClass?: string;
14
+ keywords?: string[];
15
+ category: GigamenuItemCategory;
16
+ /** Action to execute. Receives args string if user typed text after the separator. */
17
+ action: (args?: string) => void;
18
+ }
19
+ interface GigamenuPage extends Omit<GigamenuItem, 'category' | 'action'> {
20
+ path: string;
21
+ }
22
+ interface GigamenuCommand extends Omit<GigamenuItem, 'category'> {
23
+ shortcut?: string;
24
+ }
25
+ interface GigamenuConfig {
26
+ placeholder?: string;
27
+ maxResults?: number;
28
+ autoDiscoverRoutes?: boolean;
29
+ /** Separator between search query and arguments (default: ' ') */
30
+ argSeparator?: string;
31
+ }
32
+ declare const DEFAULT_CONFIG: GigamenuConfig;
33
+ /**
34
+ * Base interface for defining a command in a separate file.
35
+ * Each command file should export a constant implementing this interface.
36
+ */
37
+ interface CommandDefinition {
38
+ readonly id: string;
39
+ readonly label: string;
40
+ readonly description?: string;
41
+ readonly icon?: string;
42
+ readonly iconClass?: string;
43
+ readonly keywords?: string[];
44
+ readonly shortcut?: string;
45
+ execute(): void;
46
+ }
47
+ /**
48
+ * Helper function to define a command with type safety.
49
+ */
50
+ declare function defineCommand(command: CommandDefinition): CommandDefinition;
51
+ /**
52
+ * Information about a route passed to the filter function.
53
+ */
54
+ interface RouteInfo {
55
+ path: string;
56
+ fullPath: string;
57
+ data?: Record<string, unknown>;
58
+ title?: string;
59
+ }
60
+ /**
61
+ * Filter function to include/exclude routes from discovery.
62
+ * Return true to include the route, false to exclude it.
63
+ */
64
+ type RouteFilter = (route: RouteInfo) => boolean;
65
+ /**
66
+ * Mapped page data returned from the map function.
67
+ */
68
+ interface MappedPage {
69
+ label?: string;
70
+ description?: string;
71
+ icon?: string;
72
+ iconClass?: string;
73
+ keywords?: string[];
74
+ }
75
+ /**
76
+ * Map function to customize page data for discovered routes.
77
+ * Return partial page data to override defaults, or null to skip the route.
78
+ */
79
+ type RouteMapper = (route: RouteInfo) => MappedPage | null;
80
+ /**
81
+ * Options for route discovery.
82
+ */
83
+ interface DiscoverRoutesOptions {
84
+ filter?: RouteFilter;
85
+ map?: RouteMapper;
86
+ }
87
+
88
+ declare class GigamenuService {
89
+ private readonly router;
90
+ private readonly _items;
91
+ private readonly _isOpen;
92
+ private readonly _config;
93
+ readonly items: i0.Signal<GigamenuItem[]>;
94
+ readonly isOpen: i0.Signal<boolean>;
95
+ readonly config: i0.Signal<GigamenuConfig>;
96
+ constructor(router: Router);
97
+ configure(config: Partial<GigamenuConfig>): void;
98
+ open(): void;
99
+ close(): void;
100
+ toggle(): void;
101
+ registerItem(item: GigamenuItem): void;
102
+ unregisterItem(id: string): void;
103
+ registerCommand(command: GigamenuCommand): void;
104
+ registerPage(page: GigamenuPage): void;
105
+ discoverRoutes(options?: DiscoverRoutesOptions): void;
106
+ discoverRoutes(routes?: Routes, options?: DiscoverRoutesOptions): void;
107
+ private extractPagesFromRoutes;
108
+ private pathToLabel;
109
+ static ɵfac: i0.ɵɵFactoryDeclaration<GigamenuService, never>;
110
+ static ɵprov: i0.ɵɵInjectableDeclaration<GigamenuService>;
111
+ }
112
+
113
+ declare class FrecencyService {
114
+ private data;
115
+ private readonly isBrowser;
116
+ constructor(platformId: object);
117
+ /**
118
+ * Record that an item was selected for a given search term.
119
+ */
120
+ recordSelection(searchTerm: string, itemId: string): void;
121
+ private recordToKey;
122
+ /**
123
+ * Get frecency scores for items matching a search term.
124
+ * Returns a map of itemId -> score (higher is better).
125
+ */
126
+ getScores(searchTerm: string): Map<string, number>;
127
+ /**
128
+ * Get the most likely item for a search term (for auto-selection).
129
+ * Returns itemId if there's a strong match, null otherwise.
130
+ */
131
+ getTopMatch(searchTerm: string): string | null;
132
+ private calculateScore;
133
+ private normalizeTerm;
134
+ private load;
135
+ private pruneAndSave;
136
+ static ɵfac: i0.ɵɵFactoryDeclaration<FrecencyService, never>;
137
+ static ɵprov: i0.ɵɵInjectableDeclaration<FrecencyService>;
138
+ }
139
+
140
+ /**
141
+ * Context provided to the item template.
142
+ */
143
+ interface GigamenuItemContext {
144
+ /** The menu item being rendered */
145
+ $implicit: GigamenuItem;
146
+ /** The index of the item in the filtered list */
147
+ index: number;
148
+ /** Whether this item is currently selected */
149
+ selected: boolean;
150
+ }
151
+ /**
152
+ * Context provided to the empty template.
153
+ */
154
+ interface GigamenuEmptyContext {
155
+ /** The current search query */
156
+ $implicit: string;
157
+ }
158
+ /**
159
+ * Context provided to the header template.
160
+ */
161
+ interface GigamenuHeaderContext {
162
+ /** The current full query */
163
+ $implicit: string;
164
+ /** The search term (before separator) */
165
+ searchTerm: string;
166
+ /** The arguments (after separator) */
167
+ args: string;
168
+ /** Callback to update the query */
169
+ onQueryChange: (value: string) => void;
170
+ /** Callback for keydown events */
171
+ onKeydown: (event: KeyboardEvent) => void;
172
+ /** Placeholder text */
173
+ placeholder: string;
174
+ }
175
+ /**
176
+ * Context provided to the footer template.
177
+ */
178
+ interface GigamenuFooterContext {
179
+ /** Number of filtered items */
180
+ $implicit: number;
181
+ /** Total number of items */
182
+ total: number;
183
+ }
184
+ /**
185
+ * Template directive for customizing menu item rendering.
186
+ *
187
+ * @example
188
+ * ```html
189
+ * <gm-gigamenu>
190
+ * <ng-template gmItem let-item let-selected="selected" let-index="index">
191
+ * <div [class.active]="selected">
192
+ * {{ item.label }}
193
+ * </div>
194
+ * </ng-template>
195
+ * </gm-gigamenu>
196
+ * ```
197
+ */
198
+ declare class GigamenuItemTemplate {
199
+ readonly template: TemplateRef<GigamenuItemContext>;
200
+ static ɵfac: i0.ɵɵFactoryDeclaration<GigamenuItemTemplate, never>;
201
+ static ɵdir: i0.ɵɵDirectiveDeclaration<GigamenuItemTemplate, "[gmItem]", never, {}, {}, never, never, true, never>;
202
+ }
203
+ /**
204
+ * Template directive for customizing empty state rendering.
205
+ *
206
+ * @example
207
+ * ```html
208
+ * <gm-gigamenu>
209
+ * <ng-template gmEmpty let-query>
210
+ * <div>No results for "{{ query }}"</div>
211
+ * </ng-template>
212
+ * </gm-gigamenu>
213
+ * ```
214
+ */
215
+ declare class GigamenuEmptyTemplate {
216
+ readonly template: TemplateRef<GigamenuEmptyContext>;
217
+ static ɵfac: i0.ɵɵFactoryDeclaration<GigamenuEmptyTemplate, never>;
218
+ static ɵdir: i0.ɵɵDirectiveDeclaration<GigamenuEmptyTemplate, "[gmEmpty]", never, {}, {}, never, never, true, never>;
219
+ }
220
+ /**
221
+ * Template directive for customizing header/search input rendering.
222
+ *
223
+ * @example
224
+ * ```html
225
+ * <gm-gigamenu>
226
+ * <ng-template gmHeader let-query let-onQueryChange="onQueryChange" let-onKeydown="onKeydown">
227
+ * <input [value]="query" (input)="onQueryChange($event.target.value)" (keydown)="onKeydown($event)" />
228
+ * </ng-template>
229
+ * </gm-gigamenu>
230
+ * ```
231
+ */
232
+ declare class GigamenuHeaderTemplate {
233
+ readonly template: TemplateRef<GigamenuHeaderContext>;
234
+ static ɵfac: i0.ɵɵFactoryDeclaration<GigamenuHeaderTemplate, never>;
235
+ static ɵdir: i0.ɵɵDirectiveDeclaration<GigamenuHeaderTemplate, "[gmHeader]", never, {}, {}, never, never, true, never>;
236
+ }
237
+ /**
238
+ * Template directive for customizing footer rendering.
239
+ *
240
+ * @example
241
+ * ```html
242
+ * <gm-gigamenu>
243
+ * <ng-template gmFooter let-count let-total="total">
244
+ * <div>Showing {{ count }} of {{ total }} items</div>
245
+ * </ng-template>
246
+ * </gm-gigamenu>
247
+ * ```
248
+ */
249
+ declare class GigamenuFooterTemplate {
250
+ readonly template: TemplateRef<GigamenuFooterContext>;
251
+ static ɵfac: i0.ɵɵFactoryDeclaration<GigamenuFooterTemplate, never>;
252
+ static ɵdir: i0.ɵɵDirectiveDeclaration<GigamenuFooterTemplate, "[gmFooter]", never, {}, {}, never, never, true, never>;
253
+ }
254
+ /**
255
+ * Template directive for customizing the entire panel/dialog container.
256
+ * When provided, replaces the entire default panel structure.
257
+ *
258
+ * @example
259
+ * ```html
260
+ * <gm-gigamenu>
261
+ * <ng-template gmPanel let-items let-query="query" let-selectedIndex="selectedIndex">
262
+ * <div class="my-custom-panel">
263
+ * <!-- Custom implementation -->
264
+ * </div>
265
+ * </ng-template>
266
+ * </gm-gigamenu>
267
+ * ```
268
+ */
269
+ interface GigamenuPanelContext {
270
+ /** Filtered items to display */
271
+ $implicit: GigamenuItem[];
272
+ /** Current full query */
273
+ query: string;
274
+ /** The search term (before separator) */
275
+ searchTerm: string;
276
+ /** The arguments (after separator) */
277
+ args: string;
278
+ /** Currently selected index */
279
+ selectedIndex: number;
280
+ /** Callback to execute an item */
281
+ executeItem: (item: GigamenuItem) => void;
282
+ /** Callback to update selection */
283
+ setSelectedIndex: (index: number) => void;
284
+ /** Callback to update query */
285
+ setQuery: (query: string) => void;
286
+ /** Callback to close the menu */
287
+ close: () => void;
288
+ /** Placeholder text from config */
289
+ placeholder: string;
290
+ }
291
+ declare class GigamenuPanelTemplate {
292
+ readonly template: TemplateRef<GigamenuPanelContext>;
293
+ static ɵfac: i0.ɵɵFactoryDeclaration<GigamenuPanelTemplate, never>;
294
+ static ɵdir: i0.ɵɵDirectiveDeclaration<GigamenuPanelTemplate, "[gmPanel]", never, {}, {}, never, never, true, never>;
295
+ }
296
+
297
+ declare class GigamenuComponent {
298
+ protected readonly service: GigamenuService;
299
+ private readonly frecency;
300
+ private readonly searchInput;
301
+ private readonly listContainer;
302
+ private readonly isBrowser;
303
+ protected readonly itemTemplate: i0.Signal<GigamenuItemTemplate>;
304
+ protected readonly emptyTemplate: i0.Signal<GigamenuEmptyTemplate>;
305
+ protected readonly headerTemplate: i0.Signal<GigamenuHeaderTemplate>;
306
+ protected readonly footerTemplate: i0.Signal<GigamenuFooterTemplate>;
307
+ protected readonly panelTemplate: i0.Signal<GigamenuPanelTemplate>;
308
+ protected readonly query: i0.WritableSignal<string>;
309
+ protected readonly selectedIndex: i0.WritableSignal<number>;
310
+ /** Parsed search term (before first separator) */
311
+ protected readonly searchTerm: i0.Signal<string>;
312
+ /** Parsed arguments (after first separator) */
313
+ protected readonly args: i0.Signal<string>;
314
+ protected readonly filteredItems: i0.Signal<GigamenuItem[]>;
315
+ constructor(service: GigamenuService, frecency: FrecencyService, platformId: object);
316
+ onGlobalKeydown(event: KeyboardEvent): void;
317
+ protected onInputKeydown(event: KeyboardEvent): void;
318
+ private scrollSelectedIntoView;
319
+ protected onQueryChange(event: Event): void;
320
+ protected onBackdropClick(event: MouseEvent): void;
321
+ protected executeItem(item: GigamenuItem): void;
322
+ protected getItemContext(item: GigamenuItem, index: number): GigamenuItemContext;
323
+ protected getEmptyContext(): GigamenuEmptyContext;
324
+ protected getHeaderContext(): GigamenuHeaderContext;
325
+ protected getFooterContext(): GigamenuFooterContext;
326
+ protected getPanelContext(): GigamenuPanelContext;
327
+ private close;
328
+ private sortByFrecency;
329
+ private matchesQuery;
330
+ private isInputFocused;
331
+ static ɵfac: i0.ɵɵFactoryDeclaration<GigamenuComponent, never>;
332
+ static ɵcmp: i0.ɵɵComponentDeclaration<GigamenuComponent, "gm-gigamenu", never, {}, {}, ["itemTemplate", "emptyTemplate", "headerTemplate", "footerTemplate", "panelTemplate"], never, true, never>;
333
+ }
334
+
335
+ export { DEFAULT_CONFIG, FrecencyService, GigamenuComponent, GigamenuEmptyTemplate, GigamenuFooterTemplate, GigamenuHeaderTemplate, GigamenuItemTemplate, GigamenuPanelTemplate, GigamenuService, defineCommand };
336
+ export type { CommandDefinition, DiscoverRoutesOptions, GigamenuCommand, GigamenuConfig, GigamenuEmptyContext, GigamenuFooterContext, GigamenuHeaderContext, GigamenuItem, GigamenuItemCategory, GigamenuItemContext, GigamenuPage, GigamenuPanelContext, MappedPage, RouteFilter, RouteInfo, RouteMapper };
@@ -1,31 +0,0 @@
1
- name: Build & Publish
2
-
3
- on:
4
- push:
5
- branches: [main]
6
- tags:
7
- - 'v*'
8
-
9
- jobs:
10
- build:
11
- runs-on: self-hosted
12
- steps:
13
- - uses: actions/checkout@v4
14
-
15
- - uses: actions/setup-node@v4
16
- with:
17
- node-version: '22'
18
- registry-url: 'https://registry.npmjs.org'
19
-
20
- - name: Install dependencies
21
- run: npm ci
22
-
23
- - name: Build
24
- run: npm run build
25
-
26
- - name: Publish
27
- if: startsWith(github.ref, 'refs/tags/v')
28
- working-directory: dist/gigamenu
29
- run: npm publish --access public
30
- env:
31
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
package/ng-package.json DELETED
@@ -1,8 +0,0 @@
1
- {
2
- "$schema": "node_modules/ng-packagr/ng-package.schema.json",
3
- "dest": "dist/gigamenu",
4
- "lib": {
5
- "entryFile": "src/public-api.ts"
6
- },
7
- "assets": ["README.md"]
8
- }