ng-hub-ui-breadcrumbs
Version:
A flexible and reusable breadcrumb component for Angular applications that automatically generates breadcrumbs based on routing configuration
133 lines (125 loc) • 10.4 kB
JavaScript
import * as i0 from '@angular/core';
import { inject, TemplateRef, Directive, Injectable, Component, ContentChild, NgModule } from '@angular/core';
import { AsyncPipe, NgTemplateOutlet } from '@angular/common';
import { Router, ActivatedRoute, NavigationEnd, RouterLink } from '@angular/router';
import { filter, startWith, map } from 'rxjs';
class HubBreadcrumbItemDirective {
constructor() {
this.template = inject((TemplateRef));
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.4", ngImport: i0, type: HubBreadcrumbItemDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.4", type: HubBreadcrumbItemDirective, isStandalone: true, selector: "[hubBreadcrumbItem]", ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.4", ngImport: i0, type: HubBreadcrumbItemDirective, decorators: [{
type: Directive,
args: [{
selector: '[hubBreadcrumbItem]',
standalone: true
}]
}] });
class HubBreadcrumbsService {
constructor() {
this.#router = inject(Router);
this.#activatedRoute = inject(ActivatedRoute);
this.breadcrumbs$ = this.#router.events.pipe(filter((event) => event instanceof NavigationEnd), startWith(undefined), map(() => this.createBreadcrumbs(this.#activatedRoute.root)));
}
#router;
#activatedRoute;
createBreadcrumbs(route, url = '', breadcrumbs = []) {
const children = route.children;
if (children.length === 0) {
return breadcrumbs;
}
for (const child of children) {
const routeSegments = child.snapshot.url;
// Construir la URL para este nivel
const routeURL = routeSegments
.map((segment) => segment.path)
.join('/');
const nextUrl = routeURL ? `${url}/${routeURL}` : url;
// Verificar si esta ruta específica tiene datos de breadcrumb
const hasBreadcrumbData = this.hasOwnBreadcrumbData(child);
if (hasBreadcrumbData) {
const label = this.getBreadcrumbLabel(child);
breadcrumbs.push({
label,
url: nextUrl,
data: child.snapshot.data
});
}
// Continuar con los hijos
return this.createBreadcrumbs(child, nextUrl, breadcrumbs);
}
return breadcrumbs;
}
hasOwnBreadcrumbData(route) {
// Verificar si la ruta tiene su propia configuración de breadcrumb
const routeConfig = route.routeConfig;
return !!(routeConfig &&
routeConfig.data &&
routeConfig.data['breadcrumb']);
}
getBreadcrumbLabel(route) {
const data = route.snapshot.data;
let label = data['breadcrumb'];
if (typeof label === 'function') {
label = label(data);
}
if (data['resolvedData']) {
label = this.getResolvedBreadcrumb(label, data['resolvedData']);
}
return label;
}
getResolvedBreadcrumb(template, data) {
return template.replace(/\{([^}]+)\}/g, (match, key) => {
return data[key] || match;
});
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.4", ngImport: i0, type: HubBreadcrumbsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.4", ngImport: i0, type: HubBreadcrumbsService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.4", ngImport: i0, type: HubBreadcrumbsService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}] });
class HubBreadcrumbsComponent {
constructor() {
this.#breadcrumbsSvc = inject(HubBreadcrumbsService);
this.breadcrumbs$ = this.#breadcrumbsSvc.breadcrumbs$;
}
#breadcrumbsSvc;
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.4", ngImport: i0, type: HubBreadcrumbsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.4", type: HubBreadcrumbsComponent, isStandalone: true, selector: "hub-breadcrumbs", host: { classAttribute: "hub-breadcrumb" }, queries: [{ propertyName: "itemTemplate", first: true, predicate: HubBreadcrumbItemDirective, descendants: true }], ngImport: i0, template: "<nav aria-label=\"breadcrumb\" class=\"hub-breadcrumb__nav\">\n\t<ol class=\"hub-breadcrumb__list\">\n\t\t@for (item of breadcrumbs$ | async; track item; let last = $last) {\n\t\t<li\n\t\t\tclass=\"hub-breadcrumb__item\"\n\t\t\t[class.hub-breadcrumb__item--active]=\"last\"\n\t\t>\n\t\t\t@if (itemTemplate) {\n\t\t\t<ng-container\n\t\t\t\t[ngTemplateOutlet]=\"itemTemplate.template\"\n\t\t\t\t[ngTemplateOutletContext]=\"{ $implicit: item, isLast: last }\"\n\t\t\t/>\n\t\t\t} @else { @if (!last) {\n\t\t\t<a [routerLink]=\"item.url\" class=\"hub-breadcrumb__link\">\n\t\t\t\t{{ item.label }}\n\t\t\t</a>\n\t\t\t} @else {\n\t\t\t<span class=\"hub-breadcrumb__text\">{{ item.label }}</span>\n\t\t\t} }\n\t\t</li>\n\t\t}\n\t</ol>\n</nav>\n", styles: [".hub-breadcrumb__list{--hub-breadcrumb-padding-x: 1rem;--hub-breadcrumb-padding-y: .25rem;--hub-breadcrumb-margin-bottom: 0;--hub-breadcrumb-bg: white;--hub-breadcrumb-border-radius: 50rem;--hub-breadcrumb-divider-color: black;--hub-breadcrumb-item-padding-x: .5rem;--hub-breadcrumb-item-active-color: black;display:flex;flex-wrap:wrap;padding:var(--hub-breadcrumb-padding-y) var(--hub-breadcrumb-padding-x);margin-bottom:var(--hub-breadcrumb-margin-bottom);list-style:none;background-color:var(--hub-breadcrumb-bg)}.hub-breadcrumb__item+.hub-breadcrumb__item{padding-left:var(--hub-breadcrumb-item-padding-x)}.hub-breadcrumb__item+.hub-breadcrumb__item:before{float:left;padding-right:var(--hub-breadcrumb-item-padding-x);color:var(--hub-breadcrumb-divider-color);content:var(--hub-breadcrumb-divider, \">\")}.hub-breadcrumb__item--active{color:var(--hub-breadcrumb-item-active-color)}\n"], dependencies: [{ kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.4", ngImport: i0, type: HubBreadcrumbsComponent, decorators: [{
type: Component,
args: [{ selector: 'hub-breadcrumbs', standalone: true, imports: [AsyncPipe, RouterLink, NgTemplateOutlet], host: {
class: 'hub-breadcrumb'
}, template: "<nav aria-label=\"breadcrumb\" class=\"hub-breadcrumb__nav\">\n\t<ol class=\"hub-breadcrumb__list\">\n\t\t@for (item of breadcrumbs$ | async; track item; let last = $last) {\n\t\t<li\n\t\t\tclass=\"hub-breadcrumb__item\"\n\t\t\t[class.hub-breadcrumb__item--active]=\"last\"\n\t\t>\n\t\t\t@if (itemTemplate) {\n\t\t\t<ng-container\n\t\t\t\t[ngTemplateOutlet]=\"itemTemplate.template\"\n\t\t\t\t[ngTemplateOutletContext]=\"{ $implicit: item, isLast: last }\"\n\t\t\t/>\n\t\t\t} @else { @if (!last) {\n\t\t\t<a [routerLink]=\"item.url\" class=\"hub-breadcrumb__link\">\n\t\t\t\t{{ item.label }}\n\t\t\t</a>\n\t\t\t} @else {\n\t\t\t<span class=\"hub-breadcrumb__text\">{{ item.label }}</span>\n\t\t\t} }\n\t\t</li>\n\t\t}\n\t</ol>\n</nav>\n", styles: [".hub-breadcrumb__list{--hub-breadcrumb-padding-x: 1rem;--hub-breadcrumb-padding-y: .25rem;--hub-breadcrumb-margin-bottom: 0;--hub-breadcrumb-bg: white;--hub-breadcrumb-border-radius: 50rem;--hub-breadcrumb-divider-color: black;--hub-breadcrumb-item-padding-x: .5rem;--hub-breadcrumb-item-active-color: black;display:flex;flex-wrap:wrap;padding:var(--hub-breadcrumb-padding-y) var(--hub-breadcrumb-padding-x);margin-bottom:var(--hub-breadcrumb-margin-bottom);list-style:none;background-color:var(--hub-breadcrumb-bg)}.hub-breadcrumb__item+.hub-breadcrumb__item{padding-left:var(--hub-breadcrumb-item-padding-x)}.hub-breadcrumb__item+.hub-breadcrumb__item:before{float:left;padding-right:var(--hub-breadcrumb-item-padding-x);color:var(--hub-breadcrumb-divider-color);content:var(--hub-breadcrumb-divider, \">\")}.hub-breadcrumb__item--active{color:var(--hub-breadcrumb-item-active-color)}\n"] }]
}], propDecorators: { itemTemplate: [{
type: ContentChild,
args: [HubBreadcrumbItemDirective]
}] } });
class HubBreadcrumbsModule {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.4", ngImport: i0, type: HubBreadcrumbsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.0.4", ngImport: i0, type: HubBreadcrumbsModule, imports: [HubBreadcrumbsComponent, HubBreadcrumbItemDirective], exports: [HubBreadcrumbsComponent, HubBreadcrumbItemDirective] }); }
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.0.4", ngImport: i0, type: HubBreadcrumbsModule }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.4", ngImport: i0, type: HubBreadcrumbsModule, decorators: [{
type: NgModule,
args: [{
declarations: [],
imports: [HubBreadcrumbsComponent, HubBreadcrumbItemDirective],
exports: [HubBreadcrumbsComponent, HubBreadcrumbItemDirective]
}]
}] });
/*
* Public API Surface of breadcrumbs
*/
/**
* Generated bundle index. Do not edit.
*/
export { HubBreadcrumbItemDirective, HubBreadcrumbsComponent, HubBreadcrumbsModule, HubBreadcrumbsService };
//# sourceMappingURL=ng-hub-ui-breadcrumbs.mjs.map