ng-sidebar-pro
Version:
A complete and professional sidebar pro library for modern Angular applications
1 lines • 84.8 kB
Source Map (JSON)
{"version":3,"file":"ng-sidebar-pro.mjs","sources":["../../../projects/ng-sidebar-pro/src/lib/services/navigation.service.ts","../../../projects/ng-sidebar-pro/src/lib/services/navigation-theme.service.ts","../../../projects/ng-sidebar-pro/src/lib/services/navigation-route-generator.service.ts","../../../projects/ng-sidebar-pro/src/lib/utils/route-builder.utils.ts","../../../projects/ng-sidebar-pro/src/lib/components/navigation-item/navigation-item.ts","../../../projects/ng-sidebar-pro/src/lib/components/navigation-header/navigation-header.ts","../../../projects/ng-sidebar-pro/src/lib/components/navigation-footer/navigation-footer.ts","../../../projects/ng-sidebar-pro/src/lib/components/navigation/navigation.ts","../../../projects/ng-sidebar-pro/src/lib/directives/navigation-tooltip.directive.ts","../../../projects/ng-sidebar-pro/src/lib/directives/navigation-ripple.directive.ts","../../../projects/ng-sidebar-pro/src/ng-sidebar-pro.ts"],"sourcesContent":["import { Injectable, inject, signal, computed } from '@angular/core';\r\nimport { Router, NavigationEnd } from '@angular/router';\r\nimport { filter, map } from 'rxjs/operators';\r\nimport { BehaviorSubject, Observable } from 'rxjs';\r\nimport { NavigationItem } from '../models/navigation.types';\r\nimport {NavigationConfig} from '../models/navigation-config.interface';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class NavigationService {\r\n private router = inject(Router);\r\n\r\n private configSubject = new BehaviorSubject<NavigationConfig | null>(null);\r\n private collapsedSubject = new BehaviorSubject<boolean>(false);\r\n private searchTermSubject = new BehaviorSubject<string>('');\r\n\r\n // Signals\r\n config = signal<NavigationConfig | null>(null);\r\n collapsed = signal<boolean>(false);\r\n searchTerm = signal<string>('');\r\n\r\n // Computed values\r\n filteredItems = computed(() => {\r\n const config = this.config();\r\n const search = this.searchTerm();\r\n\r\n if (!config || !search) {\r\n return config?.items || [];\r\n }\r\n\r\n return this.filterItemsBySearch(config.items, search);\r\n });\r\n\r\n currentRoute = signal<string>('');\r\n breadcrumbs = computed(() => {\r\n const config = this.config();\r\n const route = this.currentRoute();\r\n\r\n if (!config || !route) return [];\r\n\r\n return this.generateBreadcrumbs(config.items, route);\r\n });\r\n\r\n constructor() {\r\n // Listen to route changes\r\n this.router.events\r\n .pipe(\r\n filter(event => event instanceof NavigationEnd),\r\n map(event => (event as NavigationEnd).url)\r\n )\r\n .subscribe(url => {\r\n this.currentRoute.set(url);\r\n });\r\n }\r\n\r\n // Configuration methods\r\n setConfig(config: NavigationConfig): void {\r\n this.config.set(config);\r\n this.configSubject.next(config);\r\n }\r\n\r\n getConfig(): Observable<NavigationConfig | null> {\r\n return this.configSubject.asObservable();\r\n }\r\n\r\n // Collapse methods\r\n setCollapsed(collapsed: boolean): void {\r\n this.collapsed.set(collapsed);\r\n this.collapsedSubject.next(collapsed);\r\n }\r\n\r\n toggleCollapsed(): void {\r\n const current = this.collapsed();\r\n this.setCollapsed(!current);\r\n }\r\n\r\n getCollapsed(): Observable<boolean> {\r\n return this.collapsedSubject.asObservable();\r\n }\r\n\r\n // Search methods\r\n setSearchTerm(term: string): void {\r\n this.searchTerm.set(term);\r\n this.searchTermSubject.next(term);\r\n }\r\n\r\n getSearchTerm(): Observable<string> {\r\n return this.searchTermSubject.asObservable();\r\n }\r\n\r\n // Navigation methods\r\n navigateToItem(item: NavigationItem): void {\r\n if (item.external) {\r\n window.open(item.route, item.target || '_blank');\r\n return;\r\n }\r\n\r\n if (item.redirectTo) {\r\n this.router.navigate([item.redirectTo]);\r\n return;\r\n }\r\n\r\n this.router.navigate([item.route]);\r\n }\r\n\r\n // Utility methods\r\n findItemById(id: string): NavigationItem | null {\r\n const config = this.config();\r\n if (!config) return null;\r\n\r\n return this.findItemInList(config.items, id);\r\n }\r\n\r\n findItemByRoute(route: string): NavigationItem | null {\r\n const config = this.config();\r\n if (!config) return null;\r\n\r\n return this.findItemByRouteInList(config.items, route);\r\n }\r\n\r\n isItemActive(item: NavigationItem): boolean {\r\n const currentRoute = this.currentRoute();\r\n return currentRoute.startsWith(item.route);\r\n }\r\n\r\n canAccessItem(item: NavigationItem): boolean {\r\n // Implement your access control logic here\r\n // This is a simplified version\r\n if (item.disabled || item.hidden) return false;\r\n\r\n // Check permissions, roles, etc.\r\n // You can inject your auth service here\r\n\r\n return true;\r\n }\r\n\r\n private filterItemsBySearch(items: NavigationItem[], searchTerm: string): NavigationItem[] {\r\n const filtered: NavigationItem[] = [];\r\n\r\n for (const item of items) {\r\n if (this.itemMatchesSearch(item, searchTerm)) {\r\n filtered.push(item);\r\n } else if (item.subItems) {\r\n const filteredSubItems = this.filterItemsBySearch(item.subItems, searchTerm);\r\n if (filteredSubItems.length > 0) {\r\n filtered.push({\r\n ...item,\r\n subItems: filteredSubItems\r\n });\r\n }\r\n }\r\n }\r\n\r\n return filtered;\r\n }\r\n\r\n private itemMatchesSearch(item: NavigationItem, searchTerm: string): boolean {\r\n const term = searchTerm.toLowerCase();\r\n return item.label.toLowerCase().includes(term) ||\r\n (item.tooltip && item.tooltip.toLowerCase().includes(term)) ||\r\n (item.data?.description && item.data.description.toLowerCase().includes(term)) || false;\r\n }\r\n\r\n private findItemInList(items: NavigationItem[], id: string): NavigationItem | null {\r\n for (const item of items) {\r\n if (item.id === id) return item;\r\n\r\n if (item.subItems) {\r\n const found = this.findItemInList(item.subItems, id);\r\n if (found) return found;\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n private findItemByRouteInList(items: NavigationItem[], route: string): NavigationItem | null {\r\n for (const item of items) {\r\n if (item.route === route) return item;\r\n\r\n if (item.subItems) {\r\n const found = this.findItemByRouteInList(item.subItems, route);\r\n if (found) return found;\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n private generateBreadcrumbs(items: NavigationItem[], route: string): NavigationItem[] {\r\n const breadcrumbs: NavigationItem[] = [];\r\n\r\n const findPath = (itemList: NavigationItem[], targetRoute: string, path: NavigationItem[] = []): boolean => {\r\n for (const item of itemList) {\r\n const currentPath = [...path, item];\r\n\r\n if (item.route === targetRoute) {\r\n breadcrumbs.push(...currentPath);\r\n return true;\r\n }\r\n\r\n if (item.subItems && findPath(item.subItems, targetRoute, currentPath)) {\r\n return true;\r\n }\r\n }\r\n return false;\r\n };\r\n\r\n findPath(items, route);\r\n return breadcrumbs;\r\n }\r\n}\r\n","import { Injectable, signal, computed, inject, DOCUMENT } from '@angular/core';\r\nimport { NavigationTheme, NavigationStyles } from '../models/navigation-config.interface';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class NavigationThemeService {\r\n private document = inject(DOCUMENT);\r\n\r\n currentTheme = signal<NavigationTheme>('modern-light');\r\n customStyles = signal<NavigationStyles | null>(null);\r\n\r\n // Built-in themes\r\n private themes: Record<NavigationTheme, NavigationStyles> = {\r\n 'modern-light': {\r\n colors: {\r\n primary: '#2563eb',\r\n accent: '#3b82f6',\r\n background: '#ffffff',\r\n surface: '#f8fafc',\r\n text: '#1e293b',\r\n textSecondary: '#64748b',\r\n border: '#e2e8f0',\r\n hover: '#f1f5f9',\r\n active: '#e0e7ff',\r\n disabled: '#94a3b8'\r\n },\r\n typography: {\r\n fontFamily: '\"Inter\", -apple-system, BlinkMacSystemFont, sans-serif',\r\n fontSize: '14px',\r\n fontWeight: '500',\r\n lineHeight: '1.5'\r\n },\r\n spacing: {\r\n padding: '12px 16px',\r\n margin: '4px 0',\r\n itemSpacing: '2px',\r\n levelIndent: '20px'\r\n },\r\n borders: {\r\n radius: '8px',\r\n width: '1px',\r\n style: 'solid'\r\n },\r\n shadows: {\r\n small: '0 1px 2px 0 rgb(0 0 0 / 0.05)',\r\n medium: '0 4px 6px -1px rgb(0 0 0 / 0.1)',\r\n large: '0 10px 15px -3px rgb(0 0 0 / 0.1)'\r\n },\r\n animations: {\r\n duration: '200ms',\r\n easing: 'cubic-bezier(0.4, 0, 0.2, 1)',\r\n expandCollapse: '300ms ease-in-out',\r\n hover: '150ms ease-out'\r\n }\r\n },\r\n 'modern-dark': {\r\n colors: {\r\n primary: '#3b82f6',\r\n accent: '#60a5fa',\r\n background: '#0f172a',\r\n surface: '#1e293b',\r\n text: '#f1f5f9',\r\n textSecondary: '#94a3b8',\r\n border: '#334155',\r\n hover: '#475569',\r\n active: '#1e40af',\r\n disabled: '#64748b'\r\n },\r\n typography: {\r\n fontFamily: '\"Inter\", -apple-system, BlinkMacSystemFont, sans-serif',\r\n fontSize: '14px',\r\n fontWeight: '500',\r\n lineHeight: '1.5'\r\n },\r\n spacing: {\r\n padding: '12px 16px',\r\n margin: '4px 0',\r\n itemSpacing: '2px',\r\n levelIndent: '20px'\r\n },\r\n borders: {\r\n radius: '8px',\r\n width: '1px',\r\n style: 'solid'\r\n },\r\n shadows: {\r\n small: '0 1px 2px 0 rgb(0 0 0 / 0.3)',\r\n medium: '0 4px 6px -1px rgb(0 0 0 / 0.4)',\r\n large: '0 10px 15px -3px rgb(0 0 0 / 0.5)'\r\n },\r\n animations: {\r\n duration: '200ms',\r\n easing: 'cubic-bezier(0.4, 0, 0.2, 1)',\r\n expandCollapse: '300ms ease-in-out',\r\n hover: '150ms ease-out'\r\n }\r\n },\r\n 'glassmorphism': {\r\n colors: {\r\n primary: '#3b82f6',\r\n accent: '#60a5fa',\r\n background: 'rgba(255, 255, 255, 0.1)',\r\n surface: 'rgba(255, 255, 255, 0.2)',\r\n text: '#ffffff',\r\n textSecondary: 'rgba(255, 255, 255, 0.7)',\r\n border: 'rgba(255, 255, 255, 0.2)',\r\n hover: 'rgba(255, 255, 255, 0.1)',\r\n active: 'rgba(59, 130, 246, 0.3)',\r\n disabled: 'rgba(255, 255, 255, 0.3)'\r\n },\r\n typography: {\r\n fontFamily: '\"Inter\", -apple-system, BlinkMacSystemFont, sans-serif',\r\n fontSize: '14px',\r\n fontWeight: '500',\r\n lineHeight: '1.5'\r\n },\r\n spacing: {\r\n padding: '12px 16px',\r\n margin: '4px 0',\r\n itemSpacing: '2px',\r\n levelIndent: '20px'\r\n },\r\n borders: {\r\n radius: '12px',\r\n width: '1px',\r\n style: 'solid'\r\n },\r\n shadows: {\r\n small: '0 8px 32px 0 rgba(31, 38, 135, 0.37)',\r\n medium: '0 8px 32px 0 rgba(31, 38, 135, 0.37)',\r\n large: '0 8px 32px 0 rgba(31, 38, 135, 0.37)'\r\n },\r\n animations: {\r\n duration: '300ms',\r\n easing: 'cubic-bezier(0.4, 0, 0.2, 1)',\r\n expandCollapse: '400ms ease-in-out',\r\n hover: '200ms ease-out'\r\n }\r\n },\r\n 'classic-light': {\r\n // Classic theme styles...\r\n colors: {\r\n primary: '#1976d2',\r\n accent: '#2196f3',\r\n background: '#fafafa',\r\n surface: '#ffffff',\r\n text: '#212121',\r\n textSecondary: '#757575',\r\n border: '#e0e0e0',\r\n hover: '#f5f5f5',\r\n active: '#e3f2fd',\r\n disabled: '#bdbdbd'\r\n }\r\n // ... other properties\r\n },\r\n 'classic-dark': {\r\n // Classic dark theme styles...\r\n colors: {\r\n primary: '#2196f3',\r\n accent: '#64b5f6',\r\n background: '#303030',\r\n surface: '#424242',\r\n text: '#ffffff',\r\n textSecondary: '#bdbdbd',\r\n border: '#616161',\r\n hover: '#525252',\r\n active: '#1976d2',\r\n disabled: '#757575'\r\n }\r\n // ... other properties\r\n },\r\n 'minimal': {\r\n // Minimal theme styles...\r\n colors: {\r\n primary: '#000000',\r\n accent: '#333333',\r\n background: '#ffffff',\r\n surface: '#ffffff',\r\n text: '#000000',\r\n textSecondary: '#666666',\r\n border: '#e5e5e5',\r\n hover: '#f8f8f8',\r\n active: '#f0f0f0',\r\n disabled: '#cccccc'\r\n }\r\n // ... other properties\r\n },\r\n 'custom': {\r\n // Will be overridden by customStyles\r\n colors: {},\r\n typography: {},\r\n spacing: {},\r\n borders: {},\r\n shadows: {},\r\n animations: {}\r\n }\r\n };\r\n\r\n // Computed styles based on current theme\r\n computedStyles = computed(() => {\r\n const theme = this.currentTheme();\r\n const custom = this.customStyles();\r\n\r\n if (theme === 'custom' && custom) {\r\n return custom;\r\n }\r\n\r\n const baseStyles = this.themes[theme];\r\n\r\n // Merge with custom styles if provided\r\n if (custom) {\r\n return this.mergeStyles(baseStyles, custom);\r\n }\r\n\r\n return baseStyles;\r\n });\r\n\r\n setTheme(theme: NavigationTheme): void {\r\n this.currentTheme.set(theme);\r\n this.applyThemeToDocument();\r\n }\r\n\r\n setCustomStyles(styles: NavigationStyles): void {\r\n this.customStyles.set(styles);\r\n if (this.currentTheme() === 'custom') {\r\n this.applyThemeToDocument();\r\n }\r\n }\r\n\r\n getThemeStyles(theme: NavigationTheme): NavigationStyles {\r\n return this.themes[theme] || this.themes['modern-light'];\r\n }\r\n\r\n private applyThemeToDocument(): void {\r\n const styles = this.computedStyles();\r\n const root = this.document.documentElement;\r\n\r\n // Apply CSS custom properties\r\n if (styles.colors) {\r\n Object.entries(styles.colors).forEach(([key, value]) => {\r\n if (value) {\r\n root.style.setProperty(`--nav-color-${this.kebabCase(key)}`, value);\r\n }\r\n });\r\n }\r\n\r\n if (styles.typography) {\r\n Object.entries(styles.typography).forEach(([key, value]) => {\r\n if (value) {\r\n root.style.setProperty(`--nav-typography-${this.kebabCase(key)}`, value);\r\n }\r\n });\r\n }\r\n\r\n if (styles.spacing) {\r\n Object.entries(styles.spacing).forEach(([key, value]) => {\r\n if (value) {\r\n root.style.setProperty(`--nav-spacing-${this.kebabCase(key)}`, value);\r\n }\r\n });\r\n }\r\n\r\n // Apply other style categories...\r\n }\r\n\r\n private mergeStyles(base: NavigationStyles, custom: NavigationStyles): NavigationStyles {\r\n return {\r\n colors: { ...base.colors, ...custom.colors },\r\n typography: { ...base.typography, ...custom.typography },\r\n spacing: { ...base.spacing, ...custom.spacing },\r\n borders: { ...base.borders, ...custom.borders },\r\n shadows: { ...base.shadows, ...custom.shadows },\r\n animations: { ...base.animations, ...custom.animations }\r\n };\r\n }\r\n\r\n private kebabCase(str: string): string {\r\n return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { Route } from '@angular/router';\r\nimport { NavigationItem } from '../models/navigation.types';\r\nimport {NavigationConfig} from '../models/navigation-config.interface';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class NavigationRouteGeneratorService {\r\n\r\n /**\r\n * Generates Angular routes from navigation configuration\r\n */\r\n generateRoutes(config: NavigationConfig): Route[] {\r\n const routes: Route[] = [];\r\n\r\n if (config.rootComponent) {\r\n routes.push({\r\n path: '',\r\n component: config.rootComponent,\r\n data: config.baseData,\r\n children: [\r\n ...config.items.map(item => this.itemToRoute(item)),\r\n ...(config.defaultRoute ? [{\r\n path: '',\r\n redirectTo: config.defaultRoute,\r\n pathMatch: 'full' as const\r\n }] : [])\r\n ]\r\n });\r\n } else {\r\n routes.push(...config.items.map(item => this.itemToRoute(item)));\r\n\r\n if (config.defaultRoute) {\r\n routes.push({\r\n path: '',\r\n redirectTo: config.defaultRoute,\r\n pathMatch: 'full'\r\n });\r\n }\r\n }\r\n\r\n return routes;\r\n }\r\n\r\n /**\r\n * Converts a navigation item to an Angular route\r\n */\r\n private itemToRoute(item: NavigationItem): Route {\r\n const route: Route = {\r\n path: item.route,\r\n data: {\r\n ...item.data,\r\n navigationItem: item\r\n }\r\n };\r\n\r\n // Handle different route types\r\n if (item.loadChildren) {\r\n route.loadChildren = item.loadChildren;\r\n } else if (item.component) {\r\n route.component = item.component;\r\n }\r\n\r\n // Handle redirects\r\n if (item.redirectTo) {\r\n route.redirectTo = item.redirectTo;\r\n if (item.routeMatch) {\r\n route.pathMatch = item.routeMatch;\r\n }\r\n }\r\n\r\n // Handle guards\r\n if (item.canActivate) {\r\n route.canActivate = item.canActivate;\r\n }\r\n\r\n if (item.guards?.canActivate) {\r\n route.canActivate = item.guards.canActivate;\r\n }\r\n\r\n if (item.guards?.canDeactivate) {\r\n route.canDeactivate = item.guards.canDeactivate;\r\n }\r\n\r\n // Handle resolvers\r\n if (item.resolve) {\r\n route.resolve = item.resolve;\r\n }\r\n\r\n // Handle children\r\n if (item.subItems && item.subItems.length > 0) {\r\n route.children = item.subItems.map(subItem => this.itemToRoute(subItem));\r\n\r\n // Add default redirect for container routes\r\n if (item.routeType === 'container' || item.hasRootComponent) {\r\n route.children.unshift({\r\n path: '',\r\n redirectTo: item.subItems[0].route,\r\n pathMatch: 'full'\r\n });\r\n }\r\n }\r\n\r\n return route;\r\n }\r\n}\r\n","import {MenuItemList} from '../types/menu.types';\r\n\r\nexport class RouteBuilderUtils {\r\n /**\r\n * Construye la ruta completa para navegación basada en la configuración\r\n */\r\n static buildNavigationRoute(item: MenuItemList, parentPath = ''): string {\r\n const currentPath = parentPath ? `${parentPath}/${item.route}` : item.route;\r\n\r\n // Si es ruta raíz sin parent\r\n if (!parentPath) {\r\n return item.route;\r\n }\r\n\r\n return currentPath;\r\n }\r\n\r\n /**\r\n * Determina si un item es navegable (puede ser clickeado para navegar)\r\n */\r\n static isNavigableItem(item: MenuItemList): boolean {\r\n // Si tiene component o loadChildren, es navegable\r\n if (item.component || item.loadChildren) {\r\n return true;\r\n }\r\n\r\n // Si tiene redirectTo, es navegable\r\n if (item.redirectTo) {\r\n return true;\r\n }\r\n\r\n // Si no tiene subitems, asumimos que es navegable\r\n if (!item.subItems || item.subItems.length === 0) {\r\n return true;\r\n }\r\n\r\n // Si tiene container type, también es navegable\r\n // if (item.routeType === 'container' || item.hasRootComponent || item.rootComponent) {\r\n // return true;\r\n // }\r\n\r\n return false;\r\n }\r\n\r\n /**\r\n * Construye el routerLink apropiado para el template\r\n */\r\n static buildRouterLink(item: MenuItemList, parentRoute?: string): string | string[] {\r\n if (item.redirectTo) {\r\n return item.redirectTo;\r\n }\r\n\r\n // Para items de primer nivel\r\n if (!parentRoute) {\r\n return `/${item.route}`;\r\n }\r\n\r\n // Para subitems\r\n return `/${parentRoute}/${item.route}`;\r\n }\r\n\r\n /**\r\n * Obtiene la ruta completa desde la raíz\r\n */\r\n static getFullRoute(item: MenuItemList, menuItems: MenuItemList[]): string {\r\n const pathParts: string[] = [];\r\n\r\n // Buscar el parent de este item\r\n const parent = this.findParentItem(item, menuItems);\r\n\r\n if (parent) {\r\n // Si el parent es container type, incluir su ruta\r\n if (parent.routeType === 'container' || parent.hasRootComponent || parent.rootComponent) {\r\n pathParts.push(parent.route);\r\n }\r\n }\r\n\r\n pathParts.push(item.route);\r\n\r\n return '/' + pathParts.join('/');\r\n }\r\n\r\n /**\r\n * Encuentra el item padre de un subitem\r\n */\r\n static findParentItem(targetItem: MenuItemList, menuItems: MenuItemList[]): MenuItemList | null {\r\n for (const item of menuItems) {\r\n if (item.subItems) {\r\n for (const subItem of item.subItems) {\r\n if (subItem === targetItem || subItem.id === targetItem.id) {\r\n return item;\r\n }\r\n // Búsqueda recursiva para subitems anidados\r\n const found = this.findParentItem(targetItem, item.subItems);\r\n if (found) return item;\r\n }\r\n }\r\n }\r\n return null;\r\n }\r\n}\r\n","import { Component, input, inject, computed, signal } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { MatListModule } from '@angular/material/list';\r\nimport { MatIconModule } from '@angular/material/icon';\r\nimport { MatButtonModule } from '@angular/material/button';\r\nimport { MatTooltipModule } from '@angular/material/tooltip';\r\nimport { MatBadgeModule } from '@angular/material/badge';\r\nimport { RouterModule } from '@angular/router';\r\nimport { trigger, style, transition, animate } from '@angular/animations';\r\n\r\nimport { NavigationItem } from '../../models/navigation.types';\r\nimport { NavigationService } from '../../services/navigation.service';\r\nimport {RouteBuilderUtils} from '../../utils/route-builder.utils';\r\n\r\n@Component({\r\n selector: 'es-navigation-item',\r\n standalone: true,\r\n imports: [\r\n CommonModule,\r\n RouterModule,\r\n MatListModule,\r\n MatIconModule,\r\n MatButtonModule,\r\n MatTooltipModule,\r\n MatBadgeModule\r\n ],\r\n template: `\r\n <!-- Navigable Item -->\r\n @if (isNavigable()) {\r\n <mat-list-item\r\n [routerLink]=\"routerLink()\"\r\n routerLinkActive=\"active\"\r\n [routerLinkActiveOptions]=\"routerLinkOptions()\"\r\n [matTooltip]=\"getTooltip()\"\r\n [matTooltipDisabled]=\"!shouldShowTooltip()\"\r\n matTooltipPosition=\"right\"\r\n class=\"nav-item navigable\"\r\n [class]=\"itemClasses()\"\r\n [style]=\"itemStyles()\"\r\n (click)=\"onItemClick()\">\r\n\r\n <!-- Icon -->\r\n @if (item().icon) {\r\n <mat-icon\r\n matListItemIcon\r\n [style.opacity]=\"iconOpacity()\"\r\n [matBadge]=\"badgeText()\"\r\n [matBadgeColor]=\"badgeColor()\"\r\n [matBadgeHidden]=\"!hasBadge() || badgePosition() !== 'icon'\"\r\n [matBadgeSize]=\"badgeSize()\">\r\n {{ item().icon }}\r\n </mat-icon>\r\n }\r\n\r\n <!-- Label -->\r\n @if (!collapsed()) {\r\n <span matListItemTitle class=\"item-label\">\r\n {{ item().label }}\r\n\r\n <!-- Inline Badge -->\r\n @if (hasBadge() && badgePosition() === 'inline') {\r\n <span class=\"inline-badge\" [class]=\"'badge-' + badgeColor()\">\r\n {{ badgeText() }}\r\n </span>\r\n }\r\n </span>\r\n }\r\n\r\n <!-- Expand Icon for Container Types -->\r\n @if (hasExpandableSubItems() && !collapsed()) {\r\n <mat-icon\r\n matListItemMeta\r\n class=\"expand-icon\"\r\n (click)=\"toggleExpanded($event)\">\r\n {{ expanded() ? 'expand_less' : 'expand_more' }}\r\n </mat-icon>\r\n }\r\n\r\n <!-- Badge (Top-right position) -->\r\n @if (hasBadge() && badgePosition() === 'top-right' && !collapsed()) {\r\n <span class=\"top-right-badge\" [class]=\"'badge-' + badgeColor()\">\r\n {{ badgeText() }}\r\n </span>\r\n }\r\n </mat-list-item>\r\n }\r\n @else {\r\n <!-- Non-navigable Item (Expandable) -->\r\n <mat-list-item\r\n (click)=\"toggleExpanded()\"\r\n [matTooltip]=\"getTooltip()\"\r\n [matTooltipDisabled]=\"!shouldShowTooltip()\"\r\n matTooltipPosition=\"right\"\r\n class=\"nav-item expandable\"\r\n [class]=\"itemClasses()\"\r\n [style]=\"itemStyles()\">\r\n\r\n <!-- Icon -->\r\n @if (item().icon) {\r\n <mat-icon matListItemIcon [style.opacity]=\"iconOpacity()\">\r\n {{ item().icon }}\r\n </mat-icon>\r\n }\r\n\r\n <!-- Label -->\r\n @if (!collapsed()) {\r\n <span matListItemTitle class=\"item-label\">{{ item().label }}</span>\r\n <mat-icon matListItemMeta class=\"expand-icon\">\r\n {{ expanded() ? 'expand_less' : 'expand_more' }}\r\n </mat-icon>\r\n }\r\n </mat-list-item>\r\n }\r\n\r\n <!-- Sub-items -->\r\n @if (hasSubItems() && shouldShowSubItems()) {\r\n <div class=\"sub-items\"\r\n [class.container-subitems]=\"isContainerType()\"\r\n [style]=\"subItemsStyles()\"\r\n @expandContractMenu>\r\n @for (subItem of item().subItems; track subItem.id || $index) {\r\n <es-navigation-item\r\n [item]=\"subItem\"\r\n [collapsed]=\"collapsed()\"\r\n [level]=\"level() + 1\"\r\n [parentRoute]=\"getParentRouteForSubItem()\"\r\n [allMenuItems]=\"allMenuItems()\"\r\n />\r\n }\r\n </div>\r\n }\r\n `,\r\n styleUrls: ['./navigation-item.scss'],\r\n animations: [\r\n trigger('expandContractMenu', [\r\n transition(':enter', [\r\n style({ opacity: 0, height: '0px', overflow: 'hidden' }),\r\n animate('300ms ease-in-out', style({ opacity: 1, height: '*' }))\r\n ]),\r\n transition(':leave', [\r\n style({ opacity: 1, height: '*', overflow: 'hidden' }),\r\n animate('300ms ease-in-out', style({ opacity: 0, height: '0px' }))\r\n ])\r\n ])\r\n ]\r\n})\r\nexport class NavigationItemComponent {\r\n item = input.required<NavigationItem>();\r\n collapsed = input(false);\r\n level = input(0);\r\n parentRoute = input<string>();\r\n allMenuItems = input<NavigationItem[]>([]);\r\n\r\n navigationService = inject(NavigationService);\r\n\r\n expanded = signal(false);\r\n\r\n // Computed properties\r\n isNavigable = computed(() => {\r\n return RouteBuilderUtils.isNavigableItem(this.item());\r\n });\r\n\r\n routerLink = computed(() => {\r\n if (!this.isNavigable()) return null;\r\n\r\n if (this.isContainerType()) {\r\n return `/${this.item().route}`;\r\n }\r\n\r\n if (this.parentRoute()) {\r\n return `/${this.parentRoute()}/${this.item().route}`;\r\n }\r\n\r\n if (this.allMenuItems().length > 0) {\r\n return RouteBuilderUtils.getFullRoute(this.item(), this.allMenuItems());\r\n }\r\n\r\n return `/${this.item().route}`;\r\n });\r\n\r\n routerLinkOptions = computed(() => {\r\n return this.isContainerType() ? { exact: false } : { exact: true };\r\n });\r\n\r\n hasSubItems = computed(() => {\r\n const subItems = this.item().subItems;\r\n return subItems && subItems.length > 0;\r\n });\r\n\r\n isContainerType = computed(() => {\r\n return this.item().routeType === 'container' ||\r\n this.item().hasRootComponent ||\r\n !!this.item().rootComponent;\r\n });\r\n\r\n hasExpandableSubItems = computed(() => {\r\n return this.hasSubItems() && !this.isContainerType();\r\n });\r\n\r\n shouldShowSubItems = computed(() => {\r\n if (!this.hasSubItems() || this.collapsed()) return false;\r\n return this.expanded();\r\n });\r\n\r\n getParentRouteForSubItem = computed(() => {\r\n if (this.isContainerType()) {\r\n return this.item().route;\r\n }\r\n\r\n if (this.parentRoute()) {\r\n return `${this.parentRoute()}/${this.item().route}`;\r\n }\r\n\r\n return this.item().route;\r\n });\r\n\r\n // Badge computed properties\r\n hasBadge = computed(() => {\r\n const badge = this.item().badge;\r\n return badge && (badge.text || badge.count !== undefined);\r\n });\r\n\r\n badgeText = computed(() => {\r\n const badge = this.item().badge;\r\n if (!badge) return '';\r\n return badge.text || (badge.count !== undefined ? badge.count.toString() : '');\r\n });\r\n\r\n badgeColor = computed(() => {\r\n return this.item().badge?.color || 'primary' as any\r\n });\r\n\r\n badgePosition = computed(() => {\r\n return this.item().badge?.position || 'top-right';\r\n });\r\n\r\n badgeSize = computed(() => {\r\n const level = this.level();\r\n return level > 1 ? 'small' : 'medium';\r\n });\r\n\r\n // Style computed properties\r\n itemClasses = computed(() => {\r\n const classes = [];\r\n\r\n if (this.item().cssClass) {\r\n classes.push(this.item().cssClass);\r\n }\r\n\r\n if (this.item().disabled) {\r\n classes.push('disabled');\r\n }\r\n\r\n if (this.level() > 0) {\r\n classes.push(`level-${this.level()}`);\r\n }\r\n\r\n if (this.expanded()) {\r\n classes.push('expanded');\r\n }\r\n\r\n return classes.join(' ');\r\n });\r\n\r\n itemStyles = computed(() => {\r\n const styles: any = { ...this.item().style };\r\n\r\n // Dynamic padding based on level\r\n styles.paddingLeft = `${16 + (this.level() * 20)}px`;\r\n\r\n // Dynamic font size\r\n const baseSize = 14;\r\n const sizeDecrement = 1;\r\n const minSize = 12;\r\n const fontSize = Math.max(baseSize - (this.level() * sizeDecrement), minSize);\r\n styles.fontSize = `${fontSize}px`;\r\n\r\n return styles;\r\n });\r\n\r\n subItemsStyles = computed(() => {\r\n return {\r\n borderLeft: `${Math.max(1, 3 - this.level())}px solid var(--nav-color-border)`,\r\n marginLeft: `${12 + (this.level() * 8)}px`\r\n };\r\n });\r\n\r\n iconOpacity = computed(() => {\r\n const baseOpacity = 1;\r\n const opacityDecrement = 0.1;\r\n const minOpacity = 0.6;\r\n return Math.max(baseOpacity - (this.level() * opacityDecrement), minOpacity);\r\n });\r\n\r\n // Tooltip\r\n getTooltip = () => {\r\n return this.item().tooltip || (this.collapsed() ? this.item().label : '');\r\n };\r\n\r\n shouldShowTooltip = computed(() => {\r\n return this.collapsed() || !!this.item().tooltip;\r\n });\r\n\r\n // Event handlers\r\n toggleExpanded(event?: Event): void {\r\n if (event) {\r\n event.stopPropagation();\r\n event.preventDefault();\r\n }\r\n\r\n if (this.hasSubItems()) {\r\n this.expanded.update(current => !current);\r\n }\r\n }\r\n\r\n onItemClick(): void {\r\n if (this.item().disabled) return;\r\n\r\n // Handle external links\r\n if (this.item().external && this.item().route) {\r\n window.open(this.item().route, this.item().target || '_blank');\r\n return;\r\n }\r\n\r\n // Let router handle the navigation\r\n this.navigationService.navigateToItem(this.item());\r\n }\r\n}\r\n","import { Component, input, output } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { MatIconModule } from '@angular/material/icon';\r\nimport { MatButtonModule } from '@angular/material/button';\r\nimport { MatMenuModule } from '@angular/material/menu';\r\nimport { MatDividerModule } from '@angular/material/divider';\r\nimport { NavigationHeaderConfig } from '../../models/navigation-config.interface';\r\nimport {MatTooltip} from '@angular/material/tooltip';\r\nimport {MatBadgeModule} from '@angular/material/badge';\r\n\r\n@Component({\r\n selector: 'es-navigation-header',\r\n standalone: true,\r\n imports: [\r\n CommonModule,\r\n MatIconModule,\r\n MatButtonModule,\r\n MatMenuModule,\r\n MatDividerModule,\r\n MatTooltip,\r\n MatBadgeModule\r\n ],\r\n template: `\r\n <div class=\"nav-header\" [class.collapsed]=\"collapsed()\">\r\n <!-- Logo and Title -->\r\n @if (!collapsed()) {\r\n <div class=\"header-brand\">\r\n @if (config().logo) {\r\n <img [src]=\"config().logo\" alt=\"Logo\" class=\"logo\">\r\n }\r\n @if (config().title) {\r\n <h1 class=\"title\">{{ config().title }}</h1>\r\n }\r\n </div>\r\n } @else {\r\n @if (config().logo) {\r\n <img [src]=\"config().logo\" alt=\"Logo\" class=\"logo-mini\">\r\n }\r\n }\r\n\r\n <!-- Header Actions -->\r\n @if (config().actions && (config().actions || []).length > 0) {\r\n <div class=\"header-actions\" [class.collapsed]=\"collapsed()\">\r\n @for (action of config().actions; track $index) {\r\n <button mat-icon-button\r\n [matTooltip]=\"action.label\"\r\n (click)=\"action.action()\"\r\n class=\"header-action\">\r\n <mat-icon [matBadge]=\"action.badge?.text || ''\"\r\n [matBadgeHidden]=\"!action.badge\"\r\n [matBadgeColor]=\"'primary'\">\r\n {{ action.icon }}\r\n </mat-icon>\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- User Profile -->\r\n @if (config().showUserProfile && config().userProfile && !collapsed()) {\r\n <div class=\"user-profile\">\r\n <button mat-button [matMenuTriggerFor]=\"userMenu\" class=\"user-button\">\r\n @if (config().userProfile?.avatar) {\r\n <img [src]=\"config().userProfile!.avatar\" alt=\"Avatar\" class=\"avatar\">\r\n } @else {\r\n <mat-icon>account_circle</mat-icon>\r\n }\r\n <div class=\"user-info\">\r\n <span class=\"user-name\">{{ config().userProfile?.name }}</span>\r\n @if (config().userProfile?.role) {\r\n <span class=\"user-role\">{{ config().userProfile?.role }}</span>\r\n }\r\n </div>\r\n <mat-icon>expand_more</mat-icon>\r\n </button>\r\n\r\n <mat-menu #userMenu=\"matMenu\">\r\n @if (config().userProfile?.menu) {\r\n @for (menuItem of config().userProfile!.menu; track menuItem.id) {\r\n <button mat-menu-item (click)=\"onUserMenuClick(menuItem)\">\r\n @if (menuItem.icon) {\r\n <mat-icon>{{ menuItem.icon }}</mat-icon>\r\n }\r\n <span>{{ menuItem.label }}</span>\r\n </button>\r\n @if ($index < config().userProfile!.menu!.length - 1) {\r\n <mat-divider></mat-divider>\r\n }\r\n }\r\n }\r\n </mat-menu>\r\n </div>\r\n }\r\n\r\n <!-- Collapse Toggle -->\r\n <button mat-icon-button\r\n class=\"collapse-toggle-header\"\r\n (click)=\"toggleCollapse.emit()\"\r\n matTooltip=\"Toggle Navigation\">\r\n <mat-icon>menu</mat-icon>\r\n </button>\r\n </div>\r\n `,\r\n styleUrls: ['./navigation-header.scss']\r\n})\r\nexport class NavigationHeaderComponent {\r\n config = input.required<NavigationHeaderConfig>();\r\n collapsed = input(false);\r\n\r\n toggleCollapse = output<void>();\r\n\r\n onUserMenuClick(menuItem: any): void {\r\n if (menuItem.external && menuItem.route) {\r\n window.open(menuItem.route, menuItem.target || '_blank');\r\n } else if (menuItem.action) {\r\n menuItem.action();\r\n }\r\n // Add more navigation logic as needed\r\n }\r\n}\r\n","import { Component, input } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { MatIconModule } from '@angular/material/icon';\r\nimport { MatButtonModule } from '@angular/material/button';\r\nimport { NavigationFooterConfig } from '../../models/navigation-config.interface';\r\n\r\n@Component({\r\n selector: 'es-navigation-footer',\r\n standalone: true,\r\n imports: [\r\n CommonModule,\r\n MatIconModule,\r\n MatButtonModule\r\n ],\r\n template: `\r\n <div class=\"nav-footer\" [class.collapsed]=\"collapsed()\">\r\n @if (!collapsed()) {\r\n <!-- Footer Text -->\r\n @if (config().text) {\r\n <div class=\"footer-text\">{{ config().text }}</div>\r\n }\r\n\r\n <!-- Footer Links -->\r\n @if (config().links && (config().links || []).length > 0) {\r\n <div class=\"footer-links\">\r\n @for (link of config().links; track $index) {\r\n <a [href]=\"link.url\"\r\n [target]=\"link.external ? '_blank' : '_self'\"\r\n class=\"footer-link\">\r\n {{ link.label }}\r\n </a>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Version -->\r\n @if (config().showVersion && config().version) {\r\n <div class=\"footer-version\">v{{ config().version }}</div>\r\n }\r\n }\r\n </div>\r\n `,\r\n styleUrls: ['./navigation-footer.scss']\r\n})\r\nexport class NavigationFooterComponent {\r\n config = input.required<NavigationFooterConfig>();\r\n collapsed = input(false);\r\n}\r\n","import {Component, input, inject, computed, OnInit, ViewEncapsulation} from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { MatListModule } from '@angular/material/list';\r\nimport { MatIconModule } from '@angular/material/icon';\r\nimport { MatButtonModule } from '@angular/material/button';\r\nimport { MatInputModule } from '@angular/material/input';\r\nimport { MatFormFieldModule } from '@angular/material/form-field';\r\nimport { MatTooltipModule } from '@angular/material/tooltip';\r\nimport { RouterModule } from '@angular/router';\r\n\r\nimport { NavigationConfig } from '../../models/navigation-config.interface';\r\nimport { NavigationService } from '../../services/navigation.service';\r\nimport { NavigationThemeService } from '../../services/navigation-theme.service';\r\nimport {NavigationItemComponent} from '../navigation-item/navigation-item';\r\nimport {NavigationHeaderComponent} from '../navigation-header/navigation-header';\r\nimport {NavigationFooterComponent} from '../navigation-footer/navigation-footer';\r\n\r\n@Component({\r\n selector: 'es-navigation',\r\n standalone: true,\r\n imports: [\r\n CommonModule,\r\n RouterModule,\r\n MatListModule,\r\n MatIconModule,\r\n MatButtonModule,\r\n MatInputModule,\r\n MatFormFieldModule,\r\n MatTooltipModule,\r\n NavigationItemComponent,\r\n NavigationHeaderComponent,\r\n NavigationFooterComponent\r\n ],\r\n template: `\r\n <nav class=\"ng-smart-nav\"\r\n [class]=\"navigationClasses()\"\r\n [style]=\"navigationStyles()\">\r\n\r\n <!-- Header -->\r\n @if (config()?.settings?.header) {\r\n <es-navigation-header\r\n [config]=\"config()!.settings!.header!\"\r\n [collapsed]=\"navigationService.collapsed()\"\r\n (toggleCollapse)=\"toggleCollapse()\"\r\n />\r\n }\r\n\r\n <!-- Search -->\r\n @if (config()?.settings?.search?.enabled) {\r\n <div class=\"nav-search\" [class.collapsed]=\"navigationService.collapsed()\">\r\n @if (!navigationService.collapsed()) {\r\n <mat-form-field appearance=\"outline\" class=\"search-field\">\r\n <mat-label>{{ config()?.settings?.search?.placeholder || 'Search...' }}</mat-label>\r\n <input matInput\r\n [value]=\"navigationService.searchTerm()\"\r\n (input)=\"onSearchChange($event)\"\r\n type=\"text\">\r\n <mat-icon matSuffix>search</mat-icon>\r\n </mat-form-field>\r\n } @else {\r\n <button mat-icon-button\r\n class=\"search-toggle\"\r\n matTooltip=\"Search\"\r\n (click)=\"toggleSearch()\">\r\n <mat-icon>search</mat-icon>\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Navigation Items -->\r\n <div class=\"nav-content\">\r\n <mat-nav-list class=\"nav-list\">\r\n @for (item of visibleItems(); track item.id || $index) {\r\n <es-navigation-item\r\n [item]=\"item\"\r\n [collapsed]=\"navigationService.collapsed()\"\r\n [level]=\"0\"\r\n [allMenuItems]=\"visibleItems()\"\r\n />\r\n }\r\n </mat-nav-list>\r\n </div>\r\n\r\n <!-- Footer -->\r\n @if (config()?.settings?.footer) {\r\n <es-navigation-footer\r\n [config]=\"config()!.settings!.footer!\"\r\n [collapsed]=\"navigationService.collapsed()\"\r\n />\r\n }\r\n\r\n <!-- Collapse Toggle (if enabled) -->\r\n @if (config()?.settings?.collapsible) {\r\n <button mat-icon-button\r\n class=\"collapse-toggle\"\r\n [matTooltip]=\"navigationService.collapsed() ? 'Expand' : 'Collapse'\"\r\n (click)=\"toggleCollapse()\">\r\n <mat-icon>\r\n {{ navigationService.collapsed() ? 'chevron_right' : 'chevron_left' }}\r\n </mat-icon>\r\n </button>\r\n }\r\n </nav>\r\n `,\r\n styleUrls: ['./../../../styles/navigation.scss'], // ← AQUÍ\r\n encapsulation: ViewEncapsulation.None // ← IMPORTANTE\r\n\r\n})\r\nexport class NavigationComponent implements OnInit {\r\n config = input<NavigationConfig>();\r\n\r\n navigationService = inject(NavigationService);\r\n themeService = inject(NavigationThemeService);\r\n\r\n searchExpanded = false;\r\n\r\n // Computed properties\r\n visibleItems = computed(() => {\r\n const items = this.navigationService.filteredItems();\r\n return items.filter(item => this.navigationService.canAccessItem(item));\r\n });\r\n\r\n navigationClasses = computed(() => {\r\n const config = this.config();\r\n const collapsed = this.navigationService.collapsed();\r\n const theme = this.themeService.currentTheme();\r\n const layout = config?.layout || 'sidebar';\r\n\r\n return [\r\n 'ng-smart-nav',\r\n `layout-${layout}`,\r\n `theme-${theme}`,\r\n collapsed ? 'collapsed' : 'expanded',\r\n config?.settings?.collapsible ? 'collapsible' : ''\r\n ].filter(Boolean).join(' ');\r\n });\r\n\r\n navigationStyles = computed(() => {\r\n const config = this.config();\r\n const collapsed = this.navigationService.collapsed();\r\n const styles = this.themeService.computedStyles();\r\n\r\n const customStyles: any = {};\r\n\r\n // Apply width based on collapsed state\r\n if (config?.layout === 'sidebar' || config?.layout === 'mini-sidebar') {\r\n if (collapsed) {\r\n customStyles.width = `${config.settings?.collapsedWidth || 64}px`;\r\n } else {\r\n customStyles.width = `${config.settings?.expandedWidth || 280}px`;\r\n }\r\n }\r\n\r\n // Apply theme colors\r\n if (styles.colors) {\r\n customStyles['--nav-bg'] = styles.colors.background;\r\n customStyles['--nav-surface'] = styles.colors.surface;\r\n customStyles['--nav-text'] = styles.colors.text;\r\n customStyles['--nav-border'] = styles.colors.border;\r\n }\r\n\r\n return customStyles;\r\n });\r\n\r\n ngOnInit() {\r\n const config = this.config();\r\n if (config) {\r\n this.navigationService.setConfig(config);\r\n\r\n if (config.theme) {\r\n this.themeService.setTheme(config.theme);\r\n }\r\n\r\n if (config.customStyles) {\r\n this.themeService.setCustomStyles(config.customStyles);\r\n }\r\n }\r\n }\r\n\r\n toggleCollapse(): void {\r\n this.navigationService.toggleCollapsed();\r\n }\r\n\r\n toggleSearch(): void {\r\n this.searchExpanded = !this.searchExpanded;\r\n // Implement search modal or overlay for collapsed state\r\n }\r\n\r\n onSearchChange(event: Event): void {\r\n const target = event.target as HTMLInputElement;\r\n this.navigationService.setSearchTerm(target.value);\r\n }\r\n}\r\n","import { Directive, input, ElementRef, Renderer2, OnInit } from '@angular/core';\r\n\r\n@Directive({\r\n selector: '[esTooltip]',\r\n standalone: true\r\n})\r\nexport class NavigationTooltipDirective implements OnInit {\r\n ngSmartTooltip = input<string>('');\r\n position = input<'top' | 'bottom' | 'left' | 'right'>('top');\r\n\r\n constructor(\r\n private el: ElementRef,\r\n private renderer: Renderer2\r\n ) {}\r\n\r\n ngOnInit() {\r\n // Custom tooltip implementation\r\n // This is a simplified version - you might want to use a more robust solution\r\n this.renderer.setAttribute(this.el.nativeElement, 'title', this.ngSmartTooltip());\r\n }\r\n}\r\n","import { Directive, ElementRef, Renderer2, HostListener } from '@angular/core';\r\n\r\n@Directive({\r\n selector: '[esRipple]',\r\n standalone: true\r\n})\r\nexport class NavigationRippleDirective {\r\n constructor(\r\n private el: ElementRef,\r\n private renderer: Renderer2\r\n ) {}\r\n\r\n @HostListener('click', ['$event'])\r\n onClick(event: MouseEvent) {\r\n this.createRipple(event);\r\n }\r\n\r\n private createRipple(event: MouseEvent) {\r\n const ripple = this.renderer.createElement('span');\r\n const rect = this.el.nativeElement.getBoundingClientRect();\r\n const size = Math.max(rect.width, rect.height);\r\n const x = event.clientX - rect.left - size / 2;\r\n const y = event.clientY - rect.top - size / 2;\r\n\r\n this.renderer.addClass(ripple, 'nav-ripple');\r\n this.renderer.setStyle(ripple, 'width', `${size}px`);\r\n this.renderer.setStyle(ripple, 'height', `${size}px`);\r\n this.renderer.setStyle(ripple, 'left', `${x}px`);\r\n this.renderer.setStyle(ripple, 'top', `${y}px`);\r\n\r\n this.renderer.appendChild(this.el.nativeElement, ripple);\r\n\r\n setTimeout(() => {\r\n this.renderer.removeChild(this.el.nativeElement, ripple);\r\n }, 600);\r\n }\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1","i2","i3","i4","i5"],"mappings":"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