ng-hub-ui-breadcrumbs 22.4.2 → 22.5.0
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.
- package/LICENSE +21 -0
- package/README.md +108 -3
- package/fesm2022/ng-hub-ui-breadcrumbs.mjs +113 -30
- package/fesm2022/ng-hub-ui-breadcrumbs.mjs.map +1 -1
- package/package.json +1 -1
- package/types/ng-hub-ui-breadcrumbs.d.ts +122 -20
- package/ng-hub-ui-breadcrumbs-22.4.2.tgz +0 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Carlos Morcillo Fernández
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALING IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -67,6 +67,9 @@ It supports static labels, dynamic labels resolved from route data (via function
|
|
|
67
67
|
- **Custom Templates**: Full control over how each breadcrumb item is rendered using a structural directive.
|
|
68
68
|
- **RTL Support**: Ships a flipped divider token (`--hub-breadcrumb-divider-flipped`) for Right-to-Left layouts.
|
|
69
69
|
- **Opt-in Truncation + Tooltip**: Set `truncateItems` to clip long labels with an ellipsis (bounded by `--hub-breadcrumb-max-item-width`) and reveal the full text on hover — the native `title` by default, or the richer hub-ui tooltip when wired (see below).
|
|
70
|
+
- **Collapsing for Long Trails**: `maxItems` folds the middle behind a `…` button that expands the trail in place, keeping `itemsBeforeCollapse` / `itemsAfterCollapse` crumbs at each end.
|
|
71
|
+
- **Destinations Beyond the Router**: A crumb may carry `href`, `target`, `rel` and `download` and render a plain anchor — for ancestors served outside the Angular application, or a file to download.
|
|
72
|
+
- **Keyboard Focus Ring**: Links and the collapsed indicator take the design-system focus ring, re-tintable through `--hub-breadcrumb-focus-*`.
|
|
70
73
|
- **Lazy Loading Compatible**: Works seamlessly with lazy-loaded routes.
|
|
71
74
|
- **Zero Manual Style Import**: Styles are bundled within the component — no separate SCSS import is required.
|
|
72
75
|
|
|
@@ -280,6 +283,17 @@ The main container component. It reads the breadcrumb trail directly from the An
|
|
|
280
283
|
| --------- | -------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
281
284
|
| `variant` | `string` | `undefined` | Selects a **semantic accent** for the breadcrumb links and their hover. The built-in values (`primary`, `success`, `danger`, `warning`, `info`) map to the exact design-system tints; **any other string is also accepted** and resolves through `--hub-sys-color-<variant>`. The current (last) item always stays muted. When omitted, links use the standard link colour (no visual change). |
|
|
282
285
|
| `truncateItems` | `boolean` | `false` | When `true`, clips each label to `--hub-breadcrumb-max-item-width` (default `12rem`) with an ellipsis and shows the full text as a tooltip when a label overflows. Off by default, so the standard layout and wrapping are unchanged. |
|
|
286
|
+
| `items` | `BreadcrumbItem[] \| null` | `null` | Trail supplied by you, replacing the one derived from the router. The way in for crumbs the route tree cannot express — an ancestor served by another application, or a trail assembled by hand. Left `null`, the component keeps reading `HubBreadcrumbsService`. |
|
|
287
|
+
| `maxItems` | `number \| undefined` | `undefined` | Length above which the trail collapses behind an indicator. Undefined never collapses, however long the trail grows. |
|
|
288
|
+
| `itemsBeforeCollapse` | `number` | `1` | Crumbs kept at the head of a collapsed trail. |
|
|
289
|
+
| `itemsAfterCollapse` | `number` | `1` | Crumbs kept at the tail of a collapsed trail, the current page included. |
|
|
290
|
+
| `collapsedAriaLabel` | `string` | `'Show the hidden breadcrumb items'` | Accessible name of the collapsed indicator. It is an input because it is the one string this component announces, and the library carries no translations of its own. |
|
|
291
|
+
|
|
292
|
+
#### Outputs
|
|
293
|
+
|
|
294
|
+
| Output | Type | Description |
|
|
295
|
+
| ------ | ---- | ----------- |
|
|
296
|
+
| `collapsedClick` | `void` | Fires when the collapsed indicator is activated. The trail expands on its own; the event is there for consumers that want to react as well — open a menu of the hidden crumbs, log the interaction. |
|
|
283
297
|
|
|
284
298
|
```html
|
|
285
299
|
<!-- Built-in semantic accent -->
|
|
@@ -290,8 +304,57 @@ The main container component. It reads the breadcrumb trail directly from the An
|
|
|
290
304
|
|
|
291
305
|
<!-- Clip long labels and reveal the full text on hover -->
|
|
292
306
|
<hub-breadcrumb [truncateItems]="true"></hub-breadcrumb>
|
|
307
|
+
|
|
308
|
+
<!-- Fold a deep trail: first crumb, indicator, last crumb -->
|
|
309
|
+
<hub-breadcrumb [maxItems]="4"></hub-breadcrumb>
|
|
310
|
+
|
|
311
|
+
<!-- Keep two ancestors and the last two crumbs -->
|
|
312
|
+
<hub-breadcrumb [maxItems]="4" [itemsBeforeCollapse]="2" [itemsAfterCollapse]="2"></hub-breadcrumb>
|
|
293
313
|
```
|
|
294
314
|
|
|
315
|
+
#### Collapsing long trails
|
|
316
|
+
|
|
317
|
+
Above `maxItems` crumbs the middle folds behind a `…` button. The button takes
|
|
318
|
+
keyboard focus, announces itself with `collapsedAriaLabel`, opens the trail in
|
|
319
|
+
place and emits `collapsedClick`. An expansion answers one trail: the next
|
|
320
|
+
navigation collapses it again.
|
|
321
|
+
|
|
322
|
+
#### Crumbs that leave the application
|
|
323
|
+
|
|
324
|
+
A crumb carrying `href` renders a plain anchor instead of a `routerLink`, with
|
|
325
|
+
`target`, `rel` and `download` passed through. A `_blank` crumb with no `rel` of
|
|
326
|
+
its own gets `rel="noopener noreferrer"`, so the destination never inherits a
|
|
327
|
+
handle on the opener.
|
|
328
|
+
|
|
329
|
+
Either declare it on the route:
|
|
330
|
+
|
|
331
|
+
```ts
|
|
332
|
+
{
|
|
333
|
+
path: 'invoices',
|
|
334
|
+
component: InvoicesComponent,
|
|
335
|
+
data: {
|
|
336
|
+
breadcrumb: { label: 'Invoices', href: 'https://legacy.example.com/invoices', target: '_blank' }
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
…or hand the whole trail over, when the route tree cannot express it:
|
|
342
|
+
|
|
343
|
+
```ts
|
|
344
|
+
readonly trail: BreadcrumbItem[] = [
|
|
345
|
+
{ label: 'Example.com', url: '/', href: 'https://example.com', target: '_blank' },
|
|
346
|
+
{ label: 'Handbook', url: '/handbook', href: '/assets/handbook.pdf', download: 'handbook.pdf' },
|
|
347
|
+
{ label: 'Docs', url: '/docs' },
|
|
348
|
+
{ label: 'Breadcrumbs', url: '/docs/breadcrumbs' }
|
|
349
|
+
];
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
```html
|
|
353
|
+
<hub-breadcrumb [items]="trail"></hub-breadcrumb>
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
The last crumb is never a link, whatever it declares: it is the current page.
|
|
357
|
+
|
|
295
358
|
#### Tooltip on truncated labels (optional)
|
|
296
359
|
|
|
297
360
|
When `truncateItems` is on, a clipped label exposes its full text on hover. By
|
|
@@ -339,8 +402,24 @@ An optional `NgModule` that imports and exports `HubBreadcrumbComponent` and `Hu
|
|
|
339
402
|
| Property | Type | Description |
|
|
340
403
|
| -------- | -------- | -------------------------------------------------------- |
|
|
341
404
|
| `label` | `string` | The resolved text to display for the breadcrumb. |
|
|
342
|
-
| `url` | `string` | The
|
|
343
|
-
| `data` | `any` | The original route data object (useful for icons, etc.). |
|
|
405
|
+
| `url` | `string` | The in-app destination, handed to `routerLink`. |
|
|
406
|
+
| `data` | `any` | Optional. The original route data object (useful for icons, etc.). |
|
|
407
|
+
| `href` | `string` | Optional. External destination. When present the crumb renders a plain anchor instead of a `routerLink`. |
|
|
408
|
+
| `target` | `string` | Optional. Anchor `target` (e.g. `_blank`). Only meaningful alongside `href`. |
|
|
409
|
+
| `rel` | `string` | Optional. Anchor `rel`. Left unset, a `_blank` crumb still gets `noopener noreferrer`. |
|
|
410
|
+
| `download` | `string` | Optional. Anchor `download`: the crumb points at a file to save instead of a page to open. |
|
|
411
|
+
|
|
412
|
+
#### BreadcrumbRouteConfig
|
|
413
|
+
|
|
414
|
+
The object form accepted by a route's `data.breadcrumb`, for crumbs whose destination lies outside the router. The string and function forms stay valid and remain the right choice for an ordinary in-app crumb.
|
|
415
|
+
|
|
416
|
+
| Property | Type | Description |
|
|
417
|
+
| ---------- | ------------------------------------- | -------------------------------------------------------------- |
|
|
418
|
+
| `label` | `string \| ((data: any) => string)` | Static label, or a function receiving the route's resolved `data`. |
|
|
419
|
+
| `href` | `string` | Optional. Same as on `BreadcrumbItem`. |
|
|
420
|
+
| `target` | `string` | Optional. Same as on `BreadcrumbItem`. |
|
|
421
|
+
| `rel` | `string` | Optional. Same as on `BreadcrumbItem`. |
|
|
422
|
+
| `download` | `string` | Optional. Same as on `BreadcrumbItem`. |
|
|
344
423
|
|
|
345
424
|
#### BreadcrumbTemplateContext
|
|
346
425
|
|
|
@@ -371,11 +450,37 @@ For a complete and up-to-date token catalog, see [CSS Variables Reference](./doc
|
|
|
371
450
|
The link colour follows the `--hub-breadcrumb-accent` token (which itself defaults to the standard link colour). Setting a `variant` re-bases this token; you can also override it directly:
|
|
372
451
|
|
|
373
452
|
```scss
|
|
374
|
-
|
|
453
|
+
/* The accent is read on the crumb element itself (the link colour and its hover are
|
|
454
|
+
derived there), so the override must land on that element and must outrank the
|
|
455
|
+
component's own `:host` defaults — a bare `.hub-breadcrumb` rule ties on specificity
|
|
456
|
+
and loses on source order. Scope it, or set it inline. */
|
|
457
|
+
.my-page .hub-breadcrumb {
|
|
375
458
|
--hub-breadcrumb-accent: var(--hub-sys-color-info);
|
|
376
459
|
}
|
|
377
460
|
```
|
|
378
461
|
|
|
462
|
+
### Focus ring and collapsed indicator
|
|
463
|
+
|
|
464
|
+
Keyboard focus is drawn with the design-system ring, so a breadcrumb focus looks like focus everywhere else in the application. Re-tint it without touching the outline:
|
|
465
|
+
|
|
466
|
+
```scss
|
|
467
|
+
/* The component declares its defaults on :host, so an override has to land on the
|
|
468
|
+
crumb element itself or inside it — a token set on an ancestor never reaches it. */
|
|
469
|
+
.hub-breadcrumb__list {
|
|
470
|
+
--hub-breadcrumb-focus-ring-color: rgba(25, 135, 84, 0.35);
|
|
471
|
+
--hub-breadcrumb-focus-ring-width: 0.25rem;
|
|
472
|
+
--hub-breadcrumb-focus-ring-radius: 0.25rem;
|
|
473
|
+
--hub-breadcrumb-link-focus-color: #146c43;
|
|
474
|
+
--hub-breadcrumb-focus-bg: rgba(25, 135, 84, 0.08);
|
|
475
|
+
|
|
476
|
+
/* The `…` button shown when `maxItems` folds the trail */
|
|
477
|
+
--hub-breadcrumb-collapsed-color: #6c757d;
|
|
478
|
+
--hub-breadcrumb-collapsed-hover-color: #146c43;
|
|
479
|
+
--hub-breadcrumb-collapsed-bg: transparent;
|
|
480
|
+
--hub-breadcrumb-collapsed-hover-bg: rgba(25, 135, 84, 0.08);
|
|
481
|
+
}
|
|
482
|
+
```
|
|
483
|
+
|
|
379
484
|
### Bootstrap integration (optional)
|
|
380
485
|
|
|
381
486
|
```scss
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, TemplateRef, Directive, InjectionToken, input, ElementRef, signal, afterNextRender, effect, Injectable, contentChild, computed, Component, NgModule, makeEnvironmentProviders } from '@angular/core';
|
|
3
|
-
import { NgTemplateOutlet
|
|
2
|
+
import { inject, TemplateRef, Directive, InjectionToken, input, ElementRef, signal, afterNextRender, effect, Injectable, contentChild, output, computed, linkedSignal, Component, NgModule, makeEnvironmentProviders } from '@angular/core';
|
|
3
|
+
import { NgTemplateOutlet } from '@angular/common';
|
|
4
|
+
import { toSignal } from '@angular/core/rxjs-interop';
|
|
4
5
|
import { Router, ActivatedRoute, NavigationEnd, RouterLink } from '@angular/router';
|
|
5
6
|
import { filter, startWith, map } from 'rxjs';
|
|
6
7
|
|
|
@@ -142,43 +143,44 @@ class HubBreadcrumbsService {
|
|
|
142
143
|
}
|
|
143
144
|
for (const child of children) {
|
|
144
145
|
const routeSegments = child.snapshot.url;
|
|
145
|
-
//
|
|
146
|
-
const routeURL = routeSegments
|
|
147
|
-
.map((segment) => segment.path)
|
|
148
|
-
.join('/');
|
|
146
|
+
// URL of this level
|
|
147
|
+
const routeURL = routeSegments.map((segment) => segment.path).join('/');
|
|
149
148
|
const nextUrl = routeURL ? `${url}/${routeURL}` : url;
|
|
150
|
-
//
|
|
149
|
+
// Only the routes declaring their own breadcrumb become a crumb
|
|
151
150
|
const hasBreadcrumbData = this.hasOwnBreadcrumbData(child);
|
|
152
151
|
if (hasBreadcrumbData) {
|
|
153
|
-
|
|
154
|
-
breadcrumbs.push({
|
|
155
|
-
label,
|
|
156
|
-
url: nextUrl,
|
|
157
|
-
data: child.snapshot.data
|
|
158
|
-
});
|
|
152
|
+
breadcrumbs.push(this.createItem(child, nextUrl));
|
|
159
153
|
}
|
|
160
|
-
// Continuar con los hijos
|
|
161
154
|
return this.createBreadcrumbs(child, nextUrl, breadcrumbs);
|
|
162
155
|
}
|
|
163
156
|
return breadcrumbs;
|
|
164
157
|
}
|
|
165
158
|
hasOwnBreadcrumbData(route) {
|
|
166
|
-
// Verificar si la ruta tiene su propia configuración de breadcrumb
|
|
167
159
|
const routeConfig = route.routeConfig;
|
|
168
|
-
return !!(routeConfig &&
|
|
169
|
-
routeConfig.data &&
|
|
170
|
-
routeConfig.data['breadcrumb']);
|
|
160
|
+
return !!(routeConfig && routeConfig.data && routeConfig.data['breadcrumb']);
|
|
171
161
|
}
|
|
172
|
-
|
|
162
|
+
/**
|
|
163
|
+
* Builds the crumb for a route. The object form of `data.breadcrumb` carries
|
|
164
|
+
* anchor metadata for destinations outside the router; whatever accompanies
|
|
165
|
+
* `label` there travels to the item untouched, so a new anchor attribute needs
|
|
166
|
+
* no change here.
|
|
167
|
+
*/
|
|
168
|
+
createItem(route, url) {
|
|
173
169
|
const data = route.snapshot.data;
|
|
174
|
-
|
|
175
|
-
if (
|
|
176
|
-
label =
|
|
177
|
-
|
|
178
|
-
if (data['resolvedData']) {
|
|
179
|
-
label = this.getResolvedBreadcrumb(label, data['resolvedData']);
|
|
170
|
+
const config = data['breadcrumb'];
|
|
171
|
+
if (this.isRouteConfig(config)) {
|
|
172
|
+
const { label: labelSource, ...anchor } = config;
|
|
173
|
+
return { label: this.resolveLabel(labelSource, data), url, data, ...anchor };
|
|
180
174
|
}
|
|
181
|
-
return label;
|
|
175
|
+
return { label: this.resolveLabel(config, data), url, data };
|
|
176
|
+
}
|
|
177
|
+
/** Narrows `data.breadcrumb` to its object form, excluding the function form. */
|
|
178
|
+
isRouteConfig(config) {
|
|
179
|
+
return typeof config === 'object' && config !== null;
|
|
180
|
+
}
|
|
181
|
+
resolveLabel(source, data) {
|
|
182
|
+
const label = typeof source === 'function' ? source(data) : source;
|
|
183
|
+
return data['resolvedData'] ? this.getResolvedBreadcrumb(label, data['resolvedData']) : label;
|
|
182
184
|
}
|
|
183
185
|
getResolvedBreadcrumb(template, data) {
|
|
184
186
|
return template.replace(/\{([^}]+)\}/g, (match, key) => {
|
|
@@ -218,6 +220,74 @@ class HubBreadcrumbComponent {
|
|
|
218
220
|
*/
|
|
219
221
|
truncateItems = input(false, /* @ts-ignore */
|
|
220
222
|
...(ngDevMode ? [{ debugName: "truncateItems" }] : /* istanbul ignore next */ []));
|
|
223
|
+
/**
|
|
224
|
+
* Trail supplied by the consumer, replacing the one derived from the router.
|
|
225
|
+
* It is the way in for crumbs the route tree cannot express — an ancestor
|
|
226
|
+
* served by another application, or a trail assembled by hand. Left `null`,
|
|
227
|
+
* the component keeps reading {@link HubBreadcrumbsService}.
|
|
228
|
+
*/
|
|
229
|
+
items = input(null, /* @ts-ignore */
|
|
230
|
+
...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
|
|
231
|
+
/**
|
|
232
|
+
* Length above which the trail collapses behind an indicator. Undefined (the
|
|
233
|
+
* default) never collapses, however long the trail grows.
|
|
234
|
+
*/
|
|
235
|
+
maxItems = input(undefined, /* @ts-ignore */
|
|
236
|
+
...(ngDevMode ? [{ debugName: "maxItems" }] : /* istanbul ignore next */ []));
|
|
237
|
+
/** Crumbs kept at the head of a collapsed trail. */
|
|
238
|
+
itemsBeforeCollapse = input(1, /* @ts-ignore */
|
|
239
|
+
...(ngDevMode ? [{ debugName: "itemsBeforeCollapse" }] : /* istanbul ignore next */ []));
|
|
240
|
+
/** Crumbs kept at the tail of a collapsed trail, the current page included. */
|
|
241
|
+
itemsAfterCollapse = input(1, /* @ts-ignore */
|
|
242
|
+
...(ngDevMode ? [{ debugName: "itemsAfterCollapse" }] : /* istanbul ignore next */ []));
|
|
243
|
+
/**
|
|
244
|
+
* Accessible name of the collapsed indicator. It is an input rather than a
|
|
245
|
+
* literal because it is the one string of this component a screen reader
|
|
246
|
+
* announces, and the library carries no translations of its own.
|
|
247
|
+
*/
|
|
248
|
+
collapsedAriaLabel = input('Show the hidden breadcrumb items', /* @ts-ignore */
|
|
249
|
+
...(ngDevMode ? [{ debugName: "collapsedAriaLabel" }] : /* istanbul ignore next */ []));
|
|
250
|
+
/**
|
|
251
|
+
* Fires when the collapsed indicator is activated. The trail expands in place
|
|
252
|
+
* on its own; the event is there for consumers who want to react as well —
|
|
253
|
+
* open a menu of the hidden crumbs, log the interaction.
|
|
254
|
+
*/
|
|
255
|
+
collapsedClick = output();
|
|
256
|
+
/** Trail as published by the service, tracked as a signal. */
|
|
257
|
+
#routerTrail = toSignal(this.breadcrumbs$, { initialValue: [] });
|
|
258
|
+
/** Effective trail: the manual one when supplied, the router's otherwise. */
|
|
259
|
+
trail = computed(() => this.items() ?? this.#routerTrail(), /* @ts-ignore */
|
|
260
|
+
...(ngDevMode ? [{ debugName: "trail" }] : /* istanbul ignore next */ []));
|
|
261
|
+
/**
|
|
262
|
+
* Whether the reader has opened a collapsed trail. Derived from the trail so a
|
|
263
|
+
* new navigation collapses it again — an expansion answers one trail, not the
|
|
264
|
+
* component's whole lifetime.
|
|
265
|
+
*/
|
|
266
|
+
expanded = linkedSignal({ ...(ngDevMode ? { debugName: "expanded" } : /* istanbul ignore next */ {}), source: this.trail,
|
|
267
|
+
computation: () => false });
|
|
268
|
+
/** Rendered positions, with the collapsed range folded into one indicator. */
|
|
269
|
+
rows = computed(() => {
|
|
270
|
+
const items = this.trail();
|
|
271
|
+
const before = Math.max(0, this.itemsBeforeCollapse());
|
|
272
|
+
const after = Math.max(0, this.itemsAfterCollapse());
|
|
273
|
+
const max = this.maxItems();
|
|
274
|
+
const rowAt = (item, index) => ({
|
|
275
|
+
item,
|
|
276
|
+
isLast: index === items.length - 1,
|
|
277
|
+
rel: this.resolveRel(item)
|
|
278
|
+
});
|
|
279
|
+
const collapses = max !== undefined && max > 0 && items.length > max && before + after < items.length;
|
|
280
|
+
if (!collapses || this.expanded()) {
|
|
281
|
+
return items.map(rowAt);
|
|
282
|
+
}
|
|
283
|
+
const tailStart = items.length - after;
|
|
284
|
+
return [
|
|
285
|
+
...items.slice(0, before).map(rowAt),
|
|
286
|
+
{ item: null, isLast: false, rel: null },
|
|
287
|
+
...items.slice(tailStart).map((item, index) => rowAt(item, tailStart + index))
|
|
288
|
+
];
|
|
289
|
+
}, /* @ts-ignore */
|
|
290
|
+
...(ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []));
|
|
221
291
|
/**
|
|
222
292
|
* Inline accent for custom (non-built-in) variants — the built-in five are
|
|
223
293
|
* resolved by the SCSS `@each` loop, so this returns `null` for them.
|
|
@@ -227,18 +297,31 @@ class HubBreadcrumbComponent {
|
|
|
227
297
|
return v && !BUILT_IN_VARIANTS.has(v) ? `var(--hub-sys-color-${v})` : null;
|
|
228
298
|
}, /* @ts-ignore */
|
|
229
299
|
...(ngDevMode ? [{ debugName: "customAccent" }] : /* istanbul ignore next */ []));
|
|
300
|
+
/** Opens a collapsed trail and lets the consumer act on the same gesture. */
|
|
301
|
+
expand() {
|
|
302
|
+
this.expanded.set(true);
|
|
303
|
+
this.collapsedClick.emit();
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* A crumb opening in a new tab hands the opener to the destination unless it
|
|
307
|
+
* says otherwise, so the default closes that door rather than leaving it to
|
|
308
|
+
* each consumer to remember.
|
|
309
|
+
*/
|
|
310
|
+
resolveRel(item) {
|
|
311
|
+
return item.rel ?? (item.target === '_blank' ? 'noopener noreferrer' : null);
|
|
312
|
+
}
|
|
230
313
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: HubBreadcrumbComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
231
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: HubBreadcrumbComponent, isStandalone: true, selector: "hub-breadcrumb", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, truncateItems: { classPropertyName: "truncateItems", publicName: "truncateItems", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.hub-breadcrumb--truncate": "truncateItems()", "attr.data-variant": "variant() ?? null", "style.--hub-breadcrumb-accent": "customAccent()" }, classAttribute: "hub-breadcrumb" }, queries: [{ propertyName: "itemTemplate", first: true, predicate: HubBreadcrumbItemDirective, descendants: true, read: TemplateRef, isSignal: 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\t<li class=\"hub-breadcrumb__item\" [class.hub-breadcrumb__item--active]=\"last\">\n\t\t\t\t@if (itemTemplate()) {\n\t\t\t\t\t<ng-container\n\t\t\t\t\t\t[ngTemplateOutlet]=\"itemTemplate()\"\n\t\t\t\t\t\t[ngTemplateOutletContext]=\"{\n\t\t\t\t\t\t\t$implicit: item,\n\t\t\t\t\t\t\tisLast: last\n\t\t\t\t\t\t}\"\n\t\t\t\t\t/>\n\t\t\t\t} @else {\n\t\t\t\t\t@if (!last) {\n\t\t\t\t\t\t<a [routerLink]=\"item.url\" class=\"hub-breadcrumb__link\" hubBreadcrumbLabel>\n\t\t\t\t\t\t\t{{ item.label }}\n\t\t\t\t\t\t</a>\n\t\t\t\t\t} @else {\n\t\t\t\t\t\t<span class=\"hub-breadcrumb__text\" hubBreadcrumbLabel aria-current=\"page\">{{ item.label }}</span>\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t</li>\n\t\t}\n\t</ol>\n</nav>\n", styles: [":root,:host{--hub-breadcrumb-padding-x: var(--hub-ref-space-3, 1rem);--hub-breadcrumb-padding-y: .25rem;--hub-breadcrumb-margin-bottom: var(--hub-ref-space-0, 0);--hub-breadcrumb-bg: var(--hub-sys-surface-page, transparent);--hub-breadcrumb-color: var(--hub-sys-text-primary, #212529);--hub-breadcrumb-border-radius: var(--hub-ref-radius-md, .375rem);--hub-breadcrumb-divider-color: var(--hub-sys-text-muted, #6c757d);--hub-breadcrumb-item-padding-x: var(--hub-ref-space-1, .25rem);--hub-breadcrumb-item-active-color: var(--hub-sys-text-muted, #6c757d);--hub-breadcrumb-accent: var(--hub-sys-color-primary, #0d6efd);--hub-breadcrumb-accent-emphasis: color-mix(in oklch, var(--hub-breadcrumb-accent) 80%, var(--hub-sys-color-ink, #212529));--hub-breadcrumb-accent-subtle: color-mix(in oklch, var(--hub-breadcrumb-accent) 12%, var(--hub-sys-surface-page, #fff));--hub-breadcrumb-accent-on: oklch(from var(--hub-breadcrumb-accent) clamp(0, (.62 - l) * 1000, 1) 0 h);--hub-breadcrumb-link-color: var(--hub-breadcrumb-accent);--hub-breadcrumb-link-hover-color: var(--hub-breadcrumb-accent-emphasis, var(--hub-sys-link-hover-color, #0a58ca));--hub-breadcrumb-link-decoration: none;--hub-breadcrumb-link-hover-decoration: underline;--hub-breadcrumb-divider: \">\";--hub-breadcrumb-divider-flipped: \"<\";--hub-breadcrumb-font-size: inherit;--hub-breadcrumb-max-item-width: 12rem}.hub-breadcrumb__nav .hub-breadcrumb__list{display:flex;flex-wrap:wrap;font-size:var(--hub-breadcrumb-font-size, inherit);padding:var(--hub-breadcrumb-padding-y, .25rem) var(--hub-breadcrumb-padding-x, var(--hub-ref-space-3, 1rem));margin-bottom:var(--hub-breadcrumb-margin-bottom, var(--hub-ref-space-0, 0));list-style:none;color:var(--hub-breadcrumb-color, var(--hub-sys-text-primary, #212529));background-color:var(--hub-breadcrumb-bg, var(--hub-sys-surface-page, transparent));border-radius:var(--hub-breadcrumb-border-radius, var(--hub-ref-radius-md, .375rem))}.hub-breadcrumb__nav .hub-breadcrumb__item+.hub-breadcrumb__item{padding-left:var(--hub-breadcrumb-item-padding-x, var(--hub-ref-space-1, .25rem))}.hub-breadcrumb__nav .hub-breadcrumb__item+.hub-breadcrumb__item:before{float:left;padding-right:var(--hub-breadcrumb-item-padding-x, var(--hub-ref-space-1, .25rem));color:var(--hub-breadcrumb-divider-color, var(--hub-sys-text-muted, #6c757d));content:var(--hub-breadcrumb-divider, \">\")}.hub-breadcrumb__nav .hub-breadcrumb__item--active{color:var(--hub-breadcrumb-item-active-color, var(--hub-sys-text-muted, #6c757d))}.hub-breadcrumb__nav .hub-breadcrumb__link{color:var(--hub-breadcrumb-link-color, var(--hub-sys-link-color, #0d6efd));text-decoration:var(--hub-breadcrumb-link-decoration, none)}.hub-breadcrumb__nav .hub-breadcrumb__link:hover{color:var(--hub-breadcrumb-link-hover-color, var(--hub-sys-link-hover-color, #0a58ca));text-decoration:var(--hub-breadcrumb-link-hover-decoration, underline)}[dir=rtl] .hub-breadcrumb__nav .hub-breadcrumb__item+.hub-breadcrumb__item:before{content:var(--hub-breadcrumb-divider-flipped, var(--hub-breadcrumb-divider, \">\"))}:host(.hub-breadcrumb--truncate) .hub-breadcrumb__nav .hub-breadcrumb__link,:host(.hub-breadcrumb--truncate) .hub-breadcrumb__nav .hub-breadcrumb__text,.hub-breadcrumb--truncate .hub-breadcrumb__nav .hub-breadcrumb__link,.hub-breadcrumb--truncate .hub-breadcrumb__nav .hub-breadcrumb__text{display:inline-block;max-inline-size:var(--hub-breadcrumb-max-item-width, 12rem);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}:host([data-variant=primary]),.hub-breadcrumb[data-variant=primary]{--hub-breadcrumb-accent: var(--hub-sys-color-primary)}:host([data-variant=secondary]),.hub-breadcrumb[data-variant=secondary]{--hub-breadcrumb-accent: var(--hub-sys-color-secondary)}:host([data-variant=success]),.hub-breadcrumb[data-variant=success]{--hub-breadcrumb-accent: var(--hub-sys-color-success)}:host([data-variant=danger]),.hub-breadcrumb[data-variant=danger]{--hub-breadcrumb-accent: var(--hub-sys-color-danger)}:host([data-variant=warning]),.hub-breadcrumb[data-variant=warning]{--hub-breadcrumb-accent: var(--hub-sys-color-warning)}:host([data-variant=info]),.hub-breadcrumb[data-variant=info]{--hub-breadcrumb-accent: var(--hub-sys-color-info)}:host([data-variant=neutral]),.hub-breadcrumb[data-variant=neutral]{--hub-breadcrumb-accent: var(--hub-sys-color-neutral)}:host([data-variant=light]),.hub-breadcrumb[data-variant=light]{--hub-breadcrumb-accent: var(--hub-sys-color-light)}:host([data-variant=dark]),.hub-breadcrumb[data-variant=dark]{--hub-breadcrumb-accent: var(--hub-sys-color-dark)}:host([data-variant]),.hub-breadcrumb[data-variant]{--hub-breadcrumb-accent-emphasis: color-mix(in oklch, var(--hub-breadcrumb-accent) 80%, var(--hub-sys-color-ink, #212529));--hub-breadcrumb-accent-subtle: color-mix(in oklch, var(--hub-breadcrumb-accent) 12%, var(--hub-sys-surface-page, #fff));--hub-breadcrumb-accent-on: oklch(from var(--hub-breadcrumb-accent) clamp(0, (.62 - l) * 1000, 1) 0 h);--hub-breadcrumb-link-hover-color: var(--hub-breadcrumb-accent-emphasis)}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "browserUrl", "routerLink"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: HubBreadcrumbLabelDirective, selector: "[hubBreadcrumbLabel]", inputs: ["hubBreadcrumbLabel"] }, { kind: "pipe", type: AsyncPipe, name: "async" }] });
|
|
314
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: HubBreadcrumbComponent, isStandalone: true, selector: "hub-breadcrumb", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, truncateItems: { classPropertyName: "truncateItems", publicName: "truncateItems", isSignal: true, isRequired: false, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, maxItems: { classPropertyName: "maxItems", publicName: "maxItems", isSignal: true, isRequired: false, transformFunction: null }, itemsBeforeCollapse: { classPropertyName: "itemsBeforeCollapse", publicName: "itemsBeforeCollapse", isSignal: true, isRequired: false, transformFunction: null }, itemsAfterCollapse: { classPropertyName: "itemsAfterCollapse", publicName: "itemsAfterCollapse", isSignal: true, isRequired: false, transformFunction: null }, collapsedAriaLabel: { classPropertyName: "collapsedAriaLabel", publicName: "collapsedAriaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { collapsedClick: "collapsedClick" }, host: { properties: { "class.hub-breadcrumb--truncate": "truncateItems()", "attr.data-variant": "variant() ?? null", "style.--hub-breadcrumb-accent": "customAccent()" }, classAttribute: "hub-breadcrumb" }, queries: [{ propertyName: "itemTemplate", first: true, predicate: HubBreadcrumbItemDirective, descendants: true, read: TemplateRef, isSignal: true }], ngImport: i0, template: "<nav aria-label=\"breadcrumb\" class=\"hub-breadcrumb__nav\">\n\t<ol class=\"hub-breadcrumb__list\">\n\t\t@for (row of rows(); track $index) {\n\t\t\t@if (row.item; as item) {\n\t\t\t\t<li class=\"hub-breadcrumb__item\" [class.hub-breadcrumb__item--active]=\"row.isLast\">\n\t\t\t\t\t@if (itemTemplate(); as template) {\n\t\t\t\t\t\t<ng-container\n\t\t\t\t\t\t\t[ngTemplateOutlet]=\"template\"\n\t\t\t\t\t\t\t[ngTemplateOutletContext]=\"{\n\t\t\t\t\t\t\t\t$implicit: item,\n\t\t\t\t\t\t\t\tisLast: row.isLast\n\t\t\t\t\t\t\t}\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t} @else if (row.isLast) {\n\t\t\t\t\t\t<span class=\"hub-breadcrumb__text\" hubBreadcrumbLabel aria-current=\"page\">{{ item.label }}</span>\n\t\t\t\t\t} @else if (item.href) {\n\t\t\t\t\t\t<a\n\t\t\t\t\t\t\tclass=\"hub-breadcrumb__link\"\n\t\t\t\t\t\t\thubBreadcrumbLabel\n\t\t\t\t\t\t\t[href]=\"item.href\"\n\t\t\t\t\t\t\t[attr.target]=\"item.target ?? null\"\n\t\t\t\t\t\t\t[attr.rel]=\"row.rel\"\n\t\t\t\t\t\t\t[attr.download]=\"item.download ?? null\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{{ item.label }}\n\t\t\t\t\t\t</a>\n\t\t\t\t\t} @else {\n\t\t\t\t\t\t<a [routerLink]=\"item.url\" class=\"hub-breadcrumb__link\" hubBreadcrumbLabel>\n\t\t\t\t\t\t\t{{ item.label }}\n\t\t\t\t\t\t</a>\n\t\t\t\t\t}\n\t\t\t\t</li>\n\t\t\t} @else {\n\t\t\t\t<li class=\"hub-breadcrumb__item hub-breadcrumb__item--collapsed\">\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclass=\"hub-breadcrumb__collapsed\"\n\t\t\t\t\t\t[attr.aria-label]=\"collapsedAriaLabel()\"\n\t\t\t\t\t\t[attr.aria-expanded]=\"expanded()\"\n\t\t\t\t\t\t(click)=\"expand()\"\n\t\t\t\t\t>\n\t\t\t\t\t\t…\n\t\t\t\t\t</button>\n\t\t\t\t</li>\n\t\t\t}\n\t\t}\n\t</ol>\n</nav>\n", styles: [":root,:host{--hub-breadcrumb-padding-x: var(--hub-ref-space-3, 1rem);--hub-breadcrumb-padding-y: .25rem;--hub-breadcrumb-margin-bottom: var(--hub-ref-space-0, 0);--hub-breadcrumb-bg: var(--hub-sys-surface-page, transparent);--hub-breadcrumb-color: var(--hub-sys-text-primary, #212529);--hub-breadcrumb-border-radius: var(--hub-ref-radius-md, .375rem);--hub-breadcrumb-divider-color: var(--hub-sys-text-muted, #6c757d);--hub-breadcrumb-item-padding-x: var(--hub-ref-space-1, .25rem);--hub-breadcrumb-item-active-color: var(--hub-sys-text-muted, #6c757d);--hub-breadcrumb-accent: var(--hub-sys-color-primary, #0d6efd);--hub-breadcrumb-accent-emphasis: color-mix(in oklch, var(--hub-breadcrumb-accent) 80%, var(--hub-sys-color-ink, #212529));--hub-breadcrumb-accent-subtle: color-mix(in oklch, var(--hub-breadcrumb-accent) 12%, var(--hub-sys-surface-page, #fff));--hub-breadcrumb-accent-on: oklch(from var(--hub-breadcrumb-accent) clamp(0, (.62 - l) * 1000, 1) 0 h);--hub-breadcrumb-link-color: var(--hub-breadcrumb-accent);--hub-breadcrumb-link-hover-color: var(--hub-breadcrumb-accent-emphasis, var(--hub-sys-link-hover-color, #0a58ca));--hub-breadcrumb-link-decoration: none;--hub-breadcrumb-link-hover-decoration: underline;--hub-breadcrumb-link-focus-color: var(--hub-breadcrumb-accent-emphasis);--hub-breadcrumb-focus-bg: transparent;--hub-breadcrumb-focus-ring-width: var(--hub-sys-focus-ring-width, .25rem);--hub-breadcrumb-focus-ring-color: var(--hub-sys-focus-ring-color, rgba(13, 110, 253, .25));--hub-breadcrumb-focus-ring-radius: var(--hub-ref-radius-sm, .25rem);--hub-breadcrumb-collapsed-color: var(--hub-sys-text-muted, #6c757d);--hub-breadcrumb-collapsed-hover-color: var(--hub-breadcrumb-accent);--hub-breadcrumb-collapsed-bg: transparent;--hub-breadcrumb-collapsed-hover-bg: var(--hub-breadcrumb-accent-subtle);--hub-breadcrumb-divider: \">\";--hub-breadcrumb-divider-flipped: \"<\";--hub-breadcrumb-font-size: inherit;--hub-breadcrumb-max-item-width: 12rem}.hub-breadcrumb__nav .hub-breadcrumb__list{display:flex;flex-wrap:wrap;font-size:var(--hub-breadcrumb-font-size, inherit);padding:var(--hub-breadcrumb-padding-y, .25rem) var(--hub-breadcrumb-padding-x, var(--hub-ref-space-3, 1rem));margin-bottom:var(--hub-breadcrumb-margin-bottom, var(--hub-ref-space-0, 0));list-style:none;color:var(--hub-breadcrumb-color, var(--hub-sys-text-primary, #212529));background-color:var(--hub-breadcrumb-bg, var(--hub-sys-surface-page, transparent));border-radius:var(--hub-breadcrumb-border-radius, var(--hub-ref-radius-md, .375rem))}.hub-breadcrumb__nav .hub-breadcrumb__item+.hub-breadcrumb__item{padding-inline-start:var(--hub-breadcrumb-item-padding-x, var(--hub-ref-space-1, .25rem))}.hub-breadcrumb__nav .hub-breadcrumb__item+.hub-breadcrumb__item:before{padding-inline-end:var(--hub-breadcrumb-item-padding-x, var(--hub-ref-space-1, .25rem));color:var(--hub-breadcrumb-divider-color, var(--hub-sys-text-muted, #6c757d));content:var(--hub-breadcrumb-divider, \">\")}.hub-breadcrumb__nav .hub-breadcrumb__item--active{color:var(--hub-breadcrumb-item-active-color, var(--hub-sys-text-muted, #6c757d))}.hub-breadcrumb__nav .hub-breadcrumb__link{color:var(--hub-breadcrumb-link-color, var(--hub-sys-link-color, #0d6efd));text-decoration:var(--hub-breadcrumb-link-decoration, none)}.hub-breadcrumb__nav .hub-breadcrumb__link:hover{color:var(--hub-breadcrumb-link-hover-color, var(--hub-sys-link-hover-color, #0a58ca));text-decoration:var(--hub-breadcrumb-link-hover-decoration, underline)}.hub-breadcrumb__nav .hub-breadcrumb__collapsed{display:inline-flex;align-items:center;padding:0 .125rem;border:0;border-radius:var(--hub-breadcrumb-focus-ring-radius, var(--hub-ref-radius-sm, .25rem));background-color:var(--hub-breadcrumb-collapsed-bg, transparent);color:var(--hub-breadcrumb-collapsed-color, var(--hub-sys-text-muted, #6c757d));font:inherit;line-height:inherit;cursor:pointer}.hub-breadcrumb__nav .hub-breadcrumb__collapsed:hover{background-color:var(--hub-breadcrumb-collapsed-hover-bg);color:var(--hub-breadcrumb-collapsed-hover-color)}.hub-breadcrumb__nav .hub-breadcrumb__link:focus-visible,.hub-breadcrumb__nav .hub-breadcrumb__collapsed:focus-visible{outline:0;border-radius:var(--hub-breadcrumb-focus-ring-radius, var(--hub-ref-radius-sm, .25rem));background-color:var(--hub-breadcrumb-focus-bg, transparent);color:var(--hub-breadcrumb-link-focus-color);box-shadow:0 0 0 var(--hub-breadcrumb-focus-ring-width, var(--hub-sys-focus-ring-width, .25rem)) var(--hub-breadcrumb-focus-ring-color, var(--hub-sys-focus-ring-color, rgba(13, 110, 253, .25)))}[dir=rtl] .hub-breadcrumb__nav .hub-breadcrumb__item+.hub-breadcrumb__item:before{content:var(--hub-breadcrumb-divider-flipped, var(--hub-breadcrumb-divider, \">\"))}:host(.hub-breadcrumb--truncate) .hub-breadcrumb__nav .hub-breadcrumb__link,:host(.hub-breadcrumb--truncate) .hub-breadcrumb__nav .hub-breadcrumb__text,.hub-breadcrumb--truncate .hub-breadcrumb__nav .hub-breadcrumb__link,.hub-breadcrumb--truncate .hub-breadcrumb__nav .hub-breadcrumb__text{display:inline-block;max-inline-size:var(--hub-breadcrumb-max-item-width, 12rem);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}:host([data-variant=primary]),.hub-breadcrumb[data-variant=primary]{--hub-breadcrumb-accent: var(--hub-sys-color-primary)}:host([data-variant=secondary]),.hub-breadcrumb[data-variant=secondary]{--hub-breadcrumb-accent: var(--hub-sys-color-secondary)}:host([data-variant=success]),.hub-breadcrumb[data-variant=success]{--hub-breadcrumb-accent: var(--hub-sys-color-success)}:host([data-variant=danger]),.hub-breadcrumb[data-variant=danger]{--hub-breadcrumb-accent: var(--hub-sys-color-danger)}:host([data-variant=warning]),.hub-breadcrumb[data-variant=warning]{--hub-breadcrumb-accent: var(--hub-sys-color-warning)}:host([data-variant=info]),.hub-breadcrumb[data-variant=info]{--hub-breadcrumb-accent: var(--hub-sys-color-info)}:host([data-variant=neutral]),.hub-breadcrumb[data-variant=neutral]{--hub-breadcrumb-accent: var(--hub-sys-color-neutral)}:host([data-variant=light]),.hub-breadcrumb[data-variant=light]{--hub-breadcrumb-accent: var(--hub-sys-color-light)}:host([data-variant=dark]),.hub-breadcrumb[data-variant=dark]{--hub-breadcrumb-accent: var(--hub-sys-color-dark)}:host([data-variant]),.hub-breadcrumb[data-variant]{--hub-breadcrumb-accent-emphasis: color-mix(in oklch, var(--hub-breadcrumb-accent) 80%, var(--hub-sys-color-ink, #212529));--hub-breadcrumb-accent-subtle: color-mix(in oklch, var(--hub-breadcrumb-accent) 12%, var(--hub-sys-surface-page, #fff));--hub-breadcrumb-accent-on: oklch(from var(--hub-breadcrumb-accent) clamp(0, (.62 - l) * 1000, 1) 0 h);--hub-breadcrumb-link-hover-color: var(--hub-breadcrumb-accent-emphasis)}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "browserUrl", "routerLink"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: HubBreadcrumbLabelDirective, selector: "[hubBreadcrumbLabel]", inputs: ["hubBreadcrumbLabel"] }] });
|
|
232
315
|
}
|
|
233
316
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: HubBreadcrumbComponent, decorators: [{
|
|
234
317
|
type: Component,
|
|
235
|
-
args: [{ selector: 'hub-breadcrumb', imports: [
|
|
318
|
+
args: [{ selector: 'hub-breadcrumb', imports: [RouterLink, NgTemplateOutlet, HubBreadcrumbLabelDirective], host: {
|
|
236
319
|
class: 'hub-breadcrumb',
|
|
237
320
|
'[class.hub-breadcrumb--truncate]': 'truncateItems()',
|
|
238
321
|
'[attr.data-variant]': 'variant() ?? null',
|
|
239
322
|
'[style.--hub-breadcrumb-accent]': 'customAccent()'
|
|
240
|
-
}, template: "<nav aria-label=\"breadcrumb\" class=\"hub-breadcrumb__nav\">\n\t<ol class=\"hub-breadcrumb__list\">\n\t\t@for (
|
|
241
|
-
}], propDecorators: { itemTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => HubBreadcrumbItemDirective), { ...{ read: TemplateRef }, isSignal: true }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], truncateItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "truncateItems", required: false }] }] } });
|
|
323
|
+
}, template: "<nav aria-label=\"breadcrumb\" class=\"hub-breadcrumb__nav\">\n\t<ol class=\"hub-breadcrumb__list\">\n\t\t@for (row of rows(); track $index) {\n\t\t\t@if (row.item; as item) {\n\t\t\t\t<li class=\"hub-breadcrumb__item\" [class.hub-breadcrumb__item--active]=\"row.isLast\">\n\t\t\t\t\t@if (itemTemplate(); as template) {\n\t\t\t\t\t\t<ng-container\n\t\t\t\t\t\t\t[ngTemplateOutlet]=\"template\"\n\t\t\t\t\t\t\t[ngTemplateOutletContext]=\"{\n\t\t\t\t\t\t\t\t$implicit: item,\n\t\t\t\t\t\t\t\tisLast: row.isLast\n\t\t\t\t\t\t\t}\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t} @else if (row.isLast) {\n\t\t\t\t\t\t<span class=\"hub-breadcrumb__text\" hubBreadcrumbLabel aria-current=\"page\">{{ item.label }}</span>\n\t\t\t\t\t} @else if (item.href) {\n\t\t\t\t\t\t<a\n\t\t\t\t\t\t\tclass=\"hub-breadcrumb__link\"\n\t\t\t\t\t\t\thubBreadcrumbLabel\n\t\t\t\t\t\t\t[href]=\"item.href\"\n\t\t\t\t\t\t\t[attr.target]=\"item.target ?? null\"\n\t\t\t\t\t\t\t[attr.rel]=\"row.rel\"\n\t\t\t\t\t\t\t[attr.download]=\"item.download ?? null\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{{ item.label }}\n\t\t\t\t\t\t</a>\n\t\t\t\t\t} @else {\n\t\t\t\t\t\t<a [routerLink]=\"item.url\" class=\"hub-breadcrumb__link\" hubBreadcrumbLabel>\n\t\t\t\t\t\t\t{{ item.label }}\n\t\t\t\t\t\t</a>\n\t\t\t\t\t}\n\t\t\t\t</li>\n\t\t\t} @else {\n\t\t\t\t<li class=\"hub-breadcrumb__item hub-breadcrumb__item--collapsed\">\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclass=\"hub-breadcrumb__collapsed\"\n\t\t\t\t\t\t[attr.aria-label]=\"collapsedAriaLabel()\"\n\t\t\t\t\t\t[attr.aria-expanded]=\"expanded()\"\n\t\t\t\t\t\t(click)=\"expand()\"\n\t\t\t\t\t>\n\t\t\t\t\t\t…\n\t\t\t\t\t</button>\n\t\t\t\t</li>\n\t\t\t}\n\t\t}\n\t</ol>\n</nav>\n", styles: [":root,:host{--hub-breadcrumb-padding-x: var(--hub-ref-space-3, 1rem);--hub-breadcrumb-padding-y: .25rem;--hub-breadcrumb-margin-bottom: var(--hub-ref-space-0, 0);--hub-breadcrumb-bg: var(--hub-sys-surface-page, transparent);--hub-breadcrumb-color: var(--hub-sys-text-primary, #212529);--hub-breadcrumb-border-radius: var(--hub-ref-radius-md, .375rem);--hub-breadcrumb-divider-color: var(--hub-sys-text-muted, #6c757d);--hub-breadcrumb-item-padding-x: var(--hub-ref-space-1, .25rem);--hub-breadcrumb-item-active-color: var(--hub-sys-text-muted, #6c757d);--hub-breadcrumb-accent: var(--hub-sys-color-primary, #0d6efd);--hub-breadcrumb-accent-emphasis: color-mix(in oklch, var(--hub-breadcrumb-accent) 80%, var(--hub-sys-color-ink, #212529));--hub-breadcrumb-accent-subtle: color-mix(in oklch, var(--hub-breadcrumb-accent) 12%, var(--hub-sys-surface-page, #fff));--hub-breadcrumb-accent-on: oklch(from var(--hub-breadcrumb-accent) clamp(0, (.62 - l) * 1000, 1) 0 h);--hub-breadcrumb-link-color: var(--hub-breadcrumb-accent);--hub-breadcrumb-link-hover-color: var(--hub-breadcrumb-accent-emphasis, var(--hub-sys-link-hover-color, #0a58ca));--hub-breadcrumb-link-decoration: none;--hub-breadcrumb-link-hover-decoration: underline;--hub-breadcrumb-link-focus-color: var(--hub-breadcrumb-accent-emphasis);--hub-breadcrumb-focus-bg: transparent;--hub-breadcrumb-focus-ring-width: var(--hub-sys-focus-ring-width, .25rem);--hub-breadcrumb-focus-ring-color: var(--hub-sys-focus-ring-color, rgba(13, 110, 253, .25));--hub-breadcrumb-focus-ring-radius: var(--hub-ref-radius-sm, .25rem);--hub-breadcrumb-collapsed-color: var(--hub-sys-text-muted, #6c757d);--hub-breadcrumb-collapsed-hover-color: var(--hub-breadcrumb-accent);--hub-breadcrumb-collapsed-bg: transparent;--hub-breadcrumb-collapsed-hover-bg: var(--hub-breadcrumb-accent-subtle);--hub-breadcrumb-divider: \">\";--hub-breadcrumb-divider-flipped: \"<\";--hub-breadcrumb-font-size: inherit;--hub-breadcrumb-max-item-width: 12rem}.hub-breadcrumb__nav .hub-breadcrumb__list{display:flex;flex-wrap:wrap;font-size:var(--hub-breadcrumb-font-size, inherit);padding:var(--hub-breadcrumb-padding-y, .25rem) var(--hub-breadcrumb-padding-x, var(--hub-ref-space-3, 1rem));margin-bottom:var(--hub-breadcrumb-margin-bottom, var(--hub-ref-space-0, 0));list-style:none;color:var(--hub-breadcrumb-color, var(--hub-sys-text-primary, #212529));background-color:var(--hub-breadcrumb-bg, var(--hub-sys-surface-page, transparent));border-radius:var(--hub-breadcrumb-border-radius, var(--hub-ref-radius-md, .375rem))}.hub-breadcrumb__nav .hub-breadcrumb__item+.hub-breadcrumb__item{padding-inline-start:var(--hub-breadcrumb-item-padding-x, var(--hub-ref-space-1, .25rem))}.hub-breadcrumb__nav .hub-breadcrumb__item+.hub-breadcrumb__item:before{padding-inline-end:var(--hub-breadcrumb-item-padding-x, var(--hub-ref-space-1, .25rem));color:var(--hub-breadcrumb-divider-color, var(--hub-sys-text-muted, #6c757d));content:var(--hub-breadcrumb-divider, \">\")}.hub-breadcrumb__nav .hub-breadcrumb__item--active{color:var(--hub-breadcrumb-item-active-color, var(--hub-sys-text-muted, #6c757d))}.hub-breadcrumb__nav .hub-breadcrumb__link{color:var(--hub-breadcrumb-link-color, var(--hub-sys-link-color, #0d6efd));text-decoration:var(--hub-breadcrumb-link-decoration, none)}.hub-breadcrumb__nav .hub-breadcrumb__link:hover{color:var(--hub-breadcrumb-link-hover-color, var(--hub-sys-link-hover-color, #0a58ca));text-decoration:var(--hub-breadcrumb-link-hover-decoration, underline)}.hub-breadcrumb__nav .hub-breadcrumb__collapsed{display:inline-flex;align-items:center;padding:0 .125rem;border:0;border-radius:var(--hub-breadcrumb-focus-ring-radius, var(--hub-ref-radius-sm, .25rem));background-color:var(--hub-breadcrumb-collapsed-bg, transparent);color:var(--hub-breadcrumb-collapsed-color, var(--hub-sys-text-muted, #6c757d));font:inherit;line-height:inherit;cursor:pointer}.hub-breadcrumb__nav .hub-breadcrumb__collapsed:hover{background-color:var(--hub-breadcrumb-collapsed-hover-bg);color:var(--hub-breadcrumb-collapsed-hover-color)}.hub-breadcrumb__nav .hub-breadcrumb__link:focus-visible,.hub-breadcrumb__nav .hub-breadcrumb__collapsed:focus-visible{outline:0;border-radius:var(--hub-breadcrumb-focus-ring-radius, var(--hub-ref-radius-sm, .25rem));background-color:var(--hub-breadcrumb-focus-bg, transparent);color:var(--hub-breadcrumb-link-focus-color);box-shadow:0 0 0 var(--hub-breadcrumb-focus-ring-width, var(--hub-sys-focus-ring-width, .25rem)) var(--hub-breadcrumb-focus-ring-color, var(--hub-sys-focus-ring-color, rgba(13, 110, 253, .25)))}[dir=rtl] .hub-breadcrumb__nav .hub-breadcrumb__item+.hub-breadcrumb__item:before{content:var(--hub-breadcrumb-divider-flipped, var(--hub-breadcrumb-divider, \">\"))}:host(.hub-breadcrumb--truncate) .hub-breadcrumb__nav .hub-breadcrumb__link,:host(.hub-breadcrumb--truncate) .hub-breadcrumb__nav .hub-breadcrumb__text,.hub-breadcrumb--truncate .hub-breadcrumb__nav .hub-breadcrumb__link,.hub-breadcrumb--truncate .hub-breadcrumb__nav .hub-breadcrumb__text{display:inline-block;max-inline-size:var(--hub-breadcrumb-max-item-width, 12rem);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}:host([data-variant=primary]),.hub-breadcrumb[data-variant=primary]{--hub-breadcrumb-accent: var(--hub-sys-color-primary)}:host([data-variant=secondary]),.hub-breadcrumb[data-variant=secondary]{--hub-breadcrumb-accent: var(--hub-sys-color-secondary)}:host([data-variant=success]),.hub-breadcrumb[data-variant=success]{--hub-breadcrumb-accent: var(--hub-sys-color-success)}:host([data-variant=danger]),.hub-breadcrumb[data-variant=danger]{--hub-breadcrumb-accent: var(--hub-sys-color-danger)}:host([data-variant=warning]),.hub-breadcrumb[data-variant=warning]{--hub-breadcrumb-accent: var(--hub-sys-color-warning)}:host([data-variant=info]),.hub-breadcrumb[data-variant=info]{--hub-breadcrumb-accent: var(--hub-sys-color-info)}:host([data-variant=neutral]),.hub-breadcrumb[data-variant=neutral]{--hub-breadcrumb-accent: var(--hub-sys-color-neutral)}:host([data-variant=light]),.hub-breadcrumb[data-variant=light]{--hub-breadcrumb-accent: var(--hub-sys-color-light)}:host([data-variant=dark]),.hub-breadcrumb[data-variant=dark]{--hub-breadcrumb-accent: var(--hub-sys-color-dark)}:host([data-variant]),.hub-breadcrumb[data-variant]{--hub-breadcrumb-accent-emphasis: color-mix(in oklch, var(--hub-breadcrumb-accent) 80%, var(--hub-sys-color-ink, #212529));--hub-breadcrumb-accent-subtle: color-mix(in oklch, var(--hub-breadcrumb-accent) 12%, var(--hub-sys-surface-page, #fff));--hub-breadcrumb-accent-on: oklch(from var(--hub-breadcrumb-accent) clamp(0, (.62 - l) * 1000, 1) 0 h);--hub-breadcrumb-link-hover-color: var(--hub-breadcrumb-accent-emphasis)}\n"] }]
|
|
324
|
+
}], propDecorators: { itemTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => HubBreadcrumbItemDirective), { ...{ read: TemplateRef }, isSignal: true }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], truncateItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "truncateItems", required: false }] }], items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], maxItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxItems", required: false }] }], itemsBeforeCollapse: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemsBeforeCollapse", required: false }] }], itemsAfterCollapse: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemsAfterCollapse", required: false }] }], collapsedAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsedAriaLabel", required: false }] }], collapsedClick: [{ type: i0.Output, args: ["collapsedClick"] }] } });
|
|
242
325
|
|
|
243
326
|
class HubBreadcrumbsModule {
|
|
244
327
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: HubBreadcrumbsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ng-hub-ui-breadcrumbs.mjs","sources":["../../../projects/breadcrumbs/src/lib/directives/breadcrumb-item.directive.ts","../../../projects/breadcrumbs/src/lib/breadcrumb-tooltip/breadcrumb-tooltip.token.ts","../../../projects/breadcrumbs/src/lib/directives/breadcrumb-label.directive.ts","../../../projects/breadcrumbs/src/lib/services/breadcrumbs.service.ts","../../../projects/breadcrumbs/src/lib/components/breadcrumb/breadcrumb.component.ts","../../../projects/breadcrumbs/src/lib/components/breadcrumb/breadcrumb.component.html","../../../projects/breadcrumbs/src/lib/breadcrumbs.module.ts","../../../projects/breadcrumbs/src/lib/breadcrumb-tooltip/breadcrumb-tooltip.provider.ts","../../../projects/breadcrumbs/src/public-api.ts","../../../projects/breadcrumbs/src/ng-hub-ui-breadcrumbs.ts"],"sourcesContent":["import { Directive, inject, TemplateRef } from '@angular/core';\nimport { BreadcrumbTemplateContext } from '../models/breadcrumb-template-context';\n\n@Directive({\n\tselector: '[hubBreadcrumbItem]'\n})\nexport class HubBreadcrumbItemDirective {\n\ttemplate = inject(TemplateRef<BreadcrumbTemplateContext>);\n}\n","import { InjectionToken } from '@angular/core';\nimport { HubBreadcrumbTooltipAdapter } from './breadcrumb-tooltip.types';\n\n/**\n * Injection token resolving the optional tooltip adapter used by truncated\n * breadcrumb labels.\n *\n * Inject it with `{ optional: true }`; a `null` value means \"use the native\n * `title` fallback\". Register it through {@link provideHubBreadcrumbTooltip}.\n */\nexport const HUB_BREADCRUMB_TOOLTIP_ADAPTER = new InjectionToken<HubBreadcrumbTooltipAdapter>('HUB_BREADCRUMB_TOOLTIP_ADAPTER');\n","import { afterNextRender, Directive, effect, ElementRef, inject, input, OnDestroy, signal } from '@angular/core';\nimport { HUB_BREADCRUMB_TOOLTIP_ADAPTER } from '../breadcrumb-tooltip/breadcrumb-tooltip.token';\nimport { HubBreadcrumbTooltipHandle } from '../breadcrumb-tooltip/breadcrumb-tooltip.types';\n\n/**\n * Adds an overflow-aware tooltip to a breadcrumb label element.\n *\n * Apply `[hubBreadcrumbLabel]` to the link/text of each breadcrumb item. When the\n * label is truncated (its rendered text is wider than its box — typically because\n * `hub-breadcrumb` truncation is enabled), the directive exposes the full text as\n * a tooltip: the native `title` attribute by default, or the richer hub-ui\n * tooltip when a {@link HUB_BREADCRUMB_TOOLTIP_ADAPTER} is provided. When the\n * label fits, no tooltip is shown.\n */\n@Directive({\n\tselector: '[hubBreadcrumbLabel]'\n})\nexport class HubBreadcrumbLabelDirective implements OnDestroy {\n\t/**\n\t * Explicit tooltip text. When empty, the host's own text content is used, but\n\t * only while it is truncated.\n\t */\n\treadonly tooltip = input('', { alias: 'hubBreadcrumbLabel' });\n\n\tprivate readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n\n\t/** Optional hub-ui tooltip adapter; absent means native `title` fallback. */\n\tprivate readonly adapter = inject(HUB_BREADCRUMB_TOOLTIP_ADAPTER, { optional: true });\n\n\t/** Whether the rendered label is wider than its clipping box. */\n\tprivate readonly isOverflowing = signal(false);\n\n\t/** Trimmed text content of the label, used as the auto tooltip source. */\n\tprivate readonly text = signal('');\n\n\t/** Becomes true once the browser-only overflow tracking is wired. */\n\tprivate readonly ready = signal(false);\n\n\tprivate resizeObserver: ResizeObserver | null = null;\n\tprivate mutationObserver: MutationObserver | null = null;\n\tprivate handle: HubBreadcrumbTooltipHandle | null = null;\n\n\tconstructor() {\n\t\tafterNextRender(() => this.initOverflowTracking());\n\n\t\teffect(() => {\n\t\t\tif (!this.ready()) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst explicit = this.tooltip().trim();\n\t\t\tconst text = explicit || (this.isOverflowing() ? this.text() : '');\n\t\t\tthis.applyTooltip(text);\n\t\t});\n\t}\n\n\tngOnDestroy(): void {\n\t\tthis.resizeObserver?.disconnect();\n\t\tthis.mutationObserver?.disconnect();\n\t\tthis.handle?.destroy();\n\t\tthis.handle = null;\n\t}\n\n\t/** Wires browser-only observers that keep the truncation state in sync. */\n\tprivate initOverflowTracking(): void {\n\t\tconst el = this.host.nativeElement;\n\t\tthis.measure(el);\n\n\t\tif (typeof ResizeObserver !== 'undefined') {\n\t\t\tthis.resizeObserver = new ResizeObserver(() => this.measure(el));\n\t\t\tthis.resizeObserver.observe(el);\n\t\t}\n\n\t\tif (typeof MutationObserver !== 'undefined') {\n\t\t\tthis.mutationObserver = new MutationObserver(() => this.measure(el));\n\t\t\tthis.mutationObserver.observe(el, { childList: true, characterData: true, subtree: true });\n\t\t}\n\n\t\tthis.ready.set(true);\n\t}\n\n\t/** Reads the host's text and truncation state into the signals. */\n\tprivate measure(el: HTMLElement): void {\n\t\tthis.text.set((el.textContent ?? '').trim());\n\t\tthis.isOverflowing.set(el.scrollWidth > el.clientWidth + 1);\n\t}\n\n\t/**\n\t * Applies the effective tooltip text through the hub-ui adapter when present,\n\t * or the native `title` attribute otherwise. An empty text removes both.\n\t */\n\tprivate applyTooltip(text: string): void {\n\t\tconst el = this.host.nativeElement;\n\n\t\tif (this.adapter) {\n\t\t\tel.removeAttribute('title');\n\t\t\tif (text) {\n\t\t\t\tif (this.handle) {\n\t\t\t\t\tthis.handle.update(text);\n\t\t\t\t} else {\n\t\t\t\t\tthis.handle = this.adapter.attach(el, text);\n\t\t\t\t}\n\t\t\t} else if (this.handle) {\n\t\t\t\tthis.handle.destroy();\n\t\t\t\tthis.handle = null;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (text) {\n\t\t\tel.setAttribute('title', text);\n\t\t} else {\n\t\t\tel.removeAttribute('title');\n\t\t}\n\t}\n}\n","import { inject, Injectable } from '@angular/core';\nimport { ActivatedRoute, NavigationEnd, Router } from '@angular/router';\nimport { filter, map, startWith } from 'rxjs';\nimport { BreadcrumbItem } from '../models/breadcrumb-item';\n\n@Injectable({\n\tprovidedIn: 'root'\n})\nexport class HubBreadcrumbsService {\n\t#router = inject(Router);\n\t#activatedRoute = inject(ActivatedRoute);\n\n\tbreadcrumbs$ = this.#router.events.pipe(\n\t\tfilter((event) => event instanceof NavigationEnd),\n\t\tstartWith(undefined),\n\t\tmap(() => this.createBreadcrumbs(this.#activatedRoute.root))\n\t);\n\n\tprivate createBreadcrumbs(\n\t\troute: ActivatedRoute,\n\t\turl: string = '',\n\t\tbreadcrumbs: BreadcrumbItem[] = []\n\t): BreadcrumbItem[] {\n\t\tconst children: ActivatedRoute[] = route.children;\n\n\t\tif (children.length === 0) {\n\t\t\treturn breadcrumbs;\n\t\t}\n\n\t\tfor (const child of children) {\n\t\t\tconst routeSegments = child.snapshot.url;\n\n\t\t\t// Construir la URL para este nivel\n\t\t\tconst routeURL: string = routeSegments\n\t\t\t\t.map((segment) => segment.path)\n\t\t\t\t.join('/');\n\n\t\t\tconst nextUrl = routeURL ? `${url}/${routeURL}` : url;\n\n\t\t\t// Verificar si esta ruta específica tiene datos de breadcrumb\n\t\t\tconst hasBreadcrumbData = this.hasOwnBreadcrumbData(child);\n\n\t\t\tif (hasBreadcrumbData) {\n\t\t\t\tconst label = this.getBreadcrumbLabel(child);\n\t\t\t\tbreadcrumbs.push({\n\t\t\t\t\tlabel,\n\t\t\t\t\turl: nextUrl,\n\t\t\t\t\tdata: child.snapshot.data\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Continuar con los hijos\n\t\t\treturn this.createBreadcrumbs(child, nextUrl, breadcrumbs);\n\t\t}\n\n\t\treturn breadcrumbs;\n\t}\n\n\tprivate hasOwnBreadcrumbData(route: ActivatedRoute): boolean {\n\t\t// Verificar si la ruta tiene su propia configuración de breadcrumb\n\t\tconst routeConfig = route.routeConfig;\n\t\treturn !!(\n\t\t\trouteConfig &&\n\t\t\trouteConfig.data &&\n\t\t\trouteConfig.data['breadcrumb']\n\t\t);\n\t}\n\n\tprivate getBreadcrumbLabel(route: ActivatedRoute): string {\n\t\tconst data = route.snapshot.data;\n\t\tlet label = data['breadcrumb'];\n\n\t\tif (typeof label === 'function') {\n\t\t\tlabel = label(data);\n\t\t}\n\n\t\tif (data['resolvedData']) {\n\t\t\tlabel = this.getResolvedBreadcrumb(label, data['resolvedData']);\n\t\t}\n\n\t\treturn label;\n\t}\n\n\tprivate getResolvedBreadcrumb(template: string, data: any): string {\n\t\treturn template.replace(/\\{([^}]+)\\}/g, (match, key) => {\n\t\t\treturn data[key] || match;\n\t\t});\n\t}\n}\n","import { AsyncPipe, NgTemplateOutlet } from '@angular/common';\nimport { Component, computed, contentChild, inject, input, TemplateRef } from '@angular/core';\nimport { RouterLink } from '@angular/router';\nimport { HubBreadcrumbItemDirective } from '../../directives/breadcrumb-item.directive';\nimport { HubBreadcrumbLabelDirective } from '../../directives/breadcrumb-label.directive';\nimport { HubBreadcrumbsService } from '../../services/breadcrumbs.service';\n\n/** Variants with exact design-system token coverage via the SCSS `@each` loop. */\nconst BUILT_IN_VARIANTS = new Set<string>(['primary', 'success', 'danger', 'warning', 'info']);\n\n@Component({\n\tselector: 'hub-breadcrumb',\n\timports: [AsyncPipe, RouterLink, NgTemplateOutlet, HubBreadcrumbLabelDirective],\n\ttemplateUrl: './breadcrumb.component.html',\n\tstyleUrl: './breadcrumb.component.scss',\n\thost: {\n\t\tclass: 'hub-breadcrumb',\n\t\t'[class.hub-breadcrumb--truncate]': 'truncateItems()',\n\t\t'[attr.data-variant]': 'variant() ?? null',\n\t\t'[style.--hub-breadcrumb-accent]': 'customAccent()'\n\t}\n})\nexport class HubBreadcrumbComponent {\n\t#breadcrumbsSvc = inject(HubBreadcrumbsService);\n\n\treadonly itemTemplate = contentChild(HubBreadcrumbItemDirective, { read: TemplateRef });\n\n\tbreadcrumbs$ = this.#breadcrumbsSvc.breadcrumbs$;\n\n\t/**\n\t * Semantic accent for the breadcrumb links: `'primary'` · `'success'` ·\n\t * `'danger'` · `'warning'` · `'info'`, or any custom string (read as\n\t * `--hub-sys-color-<variant>`). Re-bases `--hub-breadcrumb-accent`; the\n\t * current (last) item stays muted. Defaults to the standard link colour.\n\t */\n\treadonly variant = input<string>();\n\n\t/**\n\t * Opt-in per-item truncation. When `true`, each label is clipped to\n\t * `--hub-breadcrumb-max-item-width` with an ellipsis and, if it overflows,\n\t * exposes its full text as a tooltip (native `title`, or the hub-ui tooltip\n\t * when {@link provideHubBreadcrumbTooltip} is wired). Off by default, so the\n\t * standard breadcrumb layout is unchanged.\n\t */\n\treadonly truncateItems = input(false);\n\n\t/**\n\t * Inline accent for custom (non-built-in) variants — the built-in five are\n\t * resolved by the SCSS `@each` loop, so this returns `null` for them.\n\t */\n\tprotected readonly customAccent = computed(() => {\n\t\tconst v = this.variant();\n\t\treturn v && !BUILT_IN_VARIANTS.has(v) ? `var(--hub-sys-color-${v})` : null;\n\t});\n}\n","<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\t<li class=\"hub-breadcrumb__item\" [class.hub-breadcrumb__item--active]=\"last\">\n\t\t\t\t@if (itemTemplate()) {\n\t\t\t\t\t<ng-container\n\t\t\t\t\t\t[ngTemplateOutlet]=\"itemTemplate()\"\n\t\t\t\t\t\t[ngTemplateOutletContext]=\"{\n\t\t\t\t\t\t\t$implicit: item,\n\t\t\t\t\t\t\tisLast: last\n\t\t\t\t\t\t}\"\n\t\t\t\t\t/>\n\t\t\t\t} @else {\n\t\t\t\t\t@if (!last) {\n\t\t\t\t\t\t<a [routerLink]=\"item.url\" class=\"hub-breadcrumb__link\" hubBreadcrumbLabel>\n\t\t\t\t\t\t\t{{ item.label }}\n\t\t\t\t\t\t</a>\n\t\t\t\t\t} @else {\n\t\t\t\t\t\t<span class=\"hub-breadcrumb__text\" hubBreadcrumbLabel aria-current=\"page\">{{ item.label }}</span>\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t</li>\n\t\t}\n\t</ol>\n</nav>\n","import { NgModule } from '@angular/core';\nimport { HubBreadcrumbComponent } from './components/breadcrumb/breadcrumb.component';\nimport { HubBreadcrumbItemDirective } from './directives/breadcrumb-item.directive';\n\n@NgModule({\n\tdeclarations: [],\n\timports: [HubBreadcrumbComponent, HubBreadcrumbItemDirective],\n\texports: [HubBreadcrumbComponent, HubBreadcrumbItemDirective]\n})\nexport class HubBreadcrumbsModule {}\n","import { EnvironmentProviders, makeEnvironmentProviders } from '@angular/core';\nimport { HUB_BREADCRUMB_TOOLTIP_ADAPTER } from './breadcrumb-tooltip.token';\nimport { HubBreadcrumbTooltipAdapter } from './breadcrumb-tooltip.types';\n\n/**\n * Registers a tooltip adapter so truncated breadcrumb labels render the rich\n * hub-ui tooltip instead of the native `title` fallback.\n *\n * ```ts\n * import { provideHubBreadcrumbTooltip } from 'ng-hub-ui-breadcrumbs';\n * import { hubTooltipAdapter } from 'ng-hub-ui-utils';\n *\n * providers: [provideHubBreadcrumbTooltip(hubTooltipAdapter)];\n * ```\n *\n * @param adapter Tooltip adapter implementation (e.g. `hubTooltipAdapter` from\n * `ng-hub-ui-utils`).\n * @returns Environment providers to add to the application config.\n */\nexport function provideHubBreadcrumbTooltip(adapter: HubBreadcrumbTooltipAdapter): EnvironmentProviders {\n\treturn makeEnvironmentProviders([\n\t\t{\n\t\t\tprovide: HUB_BREADCRUMB_TOOLTIP_ADAPTER,\n\t\t\tuseValue: adapter\n\t\t}\n\t]);\n}\n","/*\n * Public API Surface of breadcrumbs\n */\nexport * from './lib/breadcrumbs.module';\nexport * from './lib/breadcrumb-tooltip';\nexport * from './lib/components/breadcrumb/breadcrumb.component';\nexport * from './lib/directives/breadcrumb-item.directive';\nexport * from './lib/directives/breadcrumb-label.directive';\nexport * from './lib/services/breadcrumbs.service';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ng-hub-ui-breadcrumbs.mjs","sources":["../../../projects/breadcrumbs/src/lib/directives/breadcrumb-item.directive.ts","../../../projects/breadcrumbs/src/lib/breadcrumb-tooltip/breadcrumb-tooltip.token.ts","../../../projects/breadcrumbs/src/lib/directives/breadcrumb-label.directive.ts","../../../projects/breadcrumbs/src/lib/services/breadcrumbs.service.ts","../../../projects/breadcrumbs/src/lib/components/breadcrumb/breadcrumb.component.ts","../../../projects/breadcrumbs/src/lib/components/breadcrumb/breadcrumb.component.html","../../../projects/breadcrumbs/src/lib/breadcrumbs.module.ts","../../../projects/breadcrumbs/src/lib/breadcrumb-tooltip/breadcrumb-tooltip.provider.ts","../../../projects/breadcrumbs/src/public-api.ts","../../../projects/breadcrumbs/src/ng-hub-ui-breadcrumbs.ts"],"sourcesContent":["import { Directive, inject, TemplateRef } from '@angular/core';\nimport { BreadcrumbTemplateContext } from '../models/breadcrumb-template-context';\n\n@Directive({\n\tselector: '[hubBreadcrumbItem]'\n})\nexport class HubBreadcrumbItemDirective {\n\ttemplate = inject(TemplateRef<BreadcrumbTemplateContext>);\n}\n","import { InjectionToken } from '@angular/core';\nimport { HubBreadcrumbTooltipAdapter } from './breadcrumb-tooltip.types';\n\n/**\n * Injection token resolving the optional tooltip adapter used by truncated\n * breadcrumb labels.\n *\n * Inject it with `{ optional: true }`; a `null` value means \"use the native\n * `title` fallback\". Register it through {@link provideHubBreadcrumbTooltip}.\n */\nexport const HUB_BREADCRUMB_TOOLTIP_ADAPTER = new InjectionToken<HubBreadcrumbTooltipAdapter>('HUB_BREADCRUMB_TOOLTIP_ADAPTER');\n","import { afterNextRender, Directive, effect, ElementRef, inject, input, OnDestroy, signal } from '@angular/core';\nimport { HUB_BREADCRUMB_TOOLTIP_ADAPTER } from '../breadcrumb-tooltip/breadcrumb-tooltip.token';\nimport { HubBreadcrumbTooltipHandle } from '../breadcrumb-tooltip/breadcrumb-tooltip.types';\n\n/**\n * Adds an overflow-aware tooltip to a breadcrumb label element.\n *\n * Apply `[hubBreadcrumbLabel]` to the link/text of each breadcrumb item. When the\n * label is truncated (its rendered text is wider than its box — typically because\n * `hub-breadcrumb` truncation is enabled), the directive exposes the full text as\n * a tooltip: the native `title` attribute by default, or the richer hub-ui\n * tooltip when a {@link HUB_BREADCRUMB_TOOLTIP_ADAPTER} is provided. When the\n * label fits, no tooltip is shown.\n */\n@Directive({\n\tselector: '[hubBreadcrumbLabel]'\n})\nexport class HubBreadcrumbLabelDirective implements OnDestroy {\n\t/**\n\t * Explicit tooltip text. When empty, the host's own text content is used, but\n\t * only while it is truncated.\n\t */\n\treadonly tooltip = input('', { alias: 'hubBreadcrumbLabel' });\n\n\tprivate readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n\n\t/** Optional hub-ui tooltip adapter; absent means native `title` fallback. */\n\tprivate readonly adapter = inject(HUB_BREADCRUMB_TOOLTIP_ADAPTER, { optional: true });\n\n\t/** Whether the rendered label is wider than its clipping box. */\n\tprivate readonly isOverflowing = signal(false);\n\n\t/** Trimmed text content of the label, used as the auto tooltip source. */\n\tprivate readonly text = signal('');\n\n\t/** Becomes true once the browser-only overflow tracking is wired. */\n\tprivate readonly ready = signal(false);\n\n\tprivate resizeObserver: ResizeObserver | null = null;\n\tprivate mutationObserver: MutationObserver | null = null;\n\tprivate handle: HubBreadcrumbTooltipHandle | null = null;\n\n\tconstructor() {\n\t\tafterNextRender(() => this.initOverflowTracking());\n\n\t\teffect(() => {\n\t\t\tif (!this.ready()) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst explicit = this.tooltip().trim();\n\t\t\tconst text = explicit || (this.isOverflowing() ? this.text() : '');\n\t\t\tthis.applyTooltip(text);\n\t\t});\n\t}\n\n\tngOnDestroy(): void {\n\t\tthis.resizeObserver?.disconnect();\n\t\tthis.mutationObserver?.disconnect();\n\t\tthis.handle?.destroy();\n\t\tthis.handle = null;\n\t}\n\n\t/** Wires browser-only observers that keep the truncation state in sync. */\n\tprivate initOverflowTracking(): void {\n\t\tconst el = this.host.nativeElement;\n\t\tthis.measure(el);\n\n\t\tif (typeof ResizeObserver !== 'undefined') {\n\t\t\tthis.resizeObserver = new ResizeObserver(() => this.measure(el));\n\t\t\tthis.resizeObserver.observe(el);\n\t\t}\n\n\t\tif (typeof MutationObserver !== 'undefined') {\n\t\t\tthis.mutationObserver = new MutationObserver(() => this.measure(el));\n\t\t\tthis.mutationObserver.observe(el, { childList: true, characterData: true, subtree: true });\n\t\t}\n\n\t\tthis.ready.set(true);\n\t}\n\n\t/** Reads the host's text and truncation state into the signals. */\n\tprivate measure(el: HTMLElement): void {\n\t\tthis.text.set((el.textContent ?? '').trim());\n\t\tthis.isOverflowing.set(el.scrollWidth > el.clientWidth + 1);\n\t}\n\n\t/**\n\t * Applies the effective tooltip text through the hub-ui adapter when present,\n\t * or the native `title` attribute otherwise. An empty text removes both.\n\t */\n\tprivate applyTooltip(text: string): void {\n\t\tconst el = this.host.nativeElement;\n\n\t\tif (this.adapter) {\n\t\t\tel.removeAttribute('title');\n\t\t\tif (text) {\n\t\t\t\tif (this.handle) {\n\t\t\t\t\tthis.handle.update(text);\n\t\t\t\t} else {\n\t\t\t\t\tthis.handle = this.adapter.attach(el, text);\n\t\t\t\t}\n\t\t\t} else if (this.handle) {\n\t\t\t\tthis.handle.destroy();\n\t\t\t\tthis.handle = null;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (text) {\n\t\t\tel.setAttribute('title', text);\n\t\t} else {\n\t\t\tel.removeAttribute('title');\n\t\t}\n\t}\n}\n","import { inject, Injectable } from '@angular/core';\nimport { ActivatedRoute, NavigationEnd, Router } from '@angular/router';\nimport { filter, map, startWith } from 'rxjs';\nimport { BreadcrumbItem, BreadcrumbRouteConfig, BreadcrumbRouteData } from '../models/breadcrumb-item';\n\n@Injectable({\n\tprovidedIn: 'root'\n})\nexport class HubBreadcrumbsService {\n\t#router = inject(Router);\n\t#activatedRoute = inject(ActivatedRoute);\n\n\tbreadcrumbs$ = this.#router.events.pipe(\n\t\tfilter((event) => event instanceof NavigationEnd),\n\t\tstartWith(undefined),\n\t\tmap(() => this.createBreadcrumbs(this.#activatedRoute.root))\n\t);\n\n\tprivate createBreadcrumbs(route: ActivatedRoute, url: string = '', breadcrumbs: BreadcrumbItem[] = []): BreadcrumbItem[] {\n\t\tconst children: ActivatedRoute[] = route.children;\n\n\t\tif (children.length === 0) {\n\t\t\treturn breadcrumbs;\n\t\t}\n\n\t\tfor (const child of children) {\n\t\t\tconst routeSegments = child.snapshot.url;\n\n\t\t\t// URL of this level\n\t\t\tconst routeURL: string = routeSegments.map((segment) => segment.path).join('/');\n\n\t\t\tconst nextUrl = routeURL ? `${url}/${routeURL}` : url;\n\n\t\t\t// Only the routes declaring their own breadcrumb become a crumb\n\t\t\tconst hasBreadcrumbData = this.hasOwnBreadcrumbData(child);\n\n\t\t\tif (hasBreadcrumbData) {\n\t\t\t\tbreadcrumbs.push(this.createItem(child, nextUrl));\n\t\t\t}\n\n\t\t\treturn this.createBreadcrumbs(child, nextUrl, breadcrumbs);\n\t\t}\n\n\t\treturn breadcrumbs;\n\t}\n\n\tprivate hasOwnBreadcrumbData(route: ActivatedRoute): boolean {\n\t\tconst routeConfig = route.routeConfig;\n\t\treturn !!(routeConfig && routeConfig.data && routeConfig.data['breadcrumb']);\n\t}\n\n\t/**\n\t * Builds the crumb for a route. The object form of `data.breadcrumb` carries\n\t * anchor metadata for destinations outside the router; whatever accompanies\n\t * `label` there travels to the item untouched, so a new anchor attribute needs\n\t * no change here.\n\t */\n\tprivate createItem(route: ActivatedRoute, url: string): BreadcrumbItem {\n\t\tconst data = route.snapshot.data;\n\t\tconst config: BreadcrumbRouteData = data['breadcrumb'];\n\n\t\tif (this.isRouteConfig(config)) {\n\t\t\tconst { label: labelSource, ...anchor } = config;\n\t\t\treturn { label: this.resolveLabel(labelSource, data), url, data, ...anchor };\n\t\t}\n\n\t\treturn { label: this.resolveLabel(config, data), url, data };\n\t}\n\n\t/** Narrows `data.breadcrumb` to its object form, excluding the function form. */\n\tprivate isRouteConfig(config: BreadcrumbRouteData): config is BreadcrumbRouteConfig {\n\t\treturn typeof config === 'object' && config !== null;\n\t}\n\n\tprivate resolveLabel(source: string | ((data: any) => string), data: any): string {\n\t\tconst label = typeof source === 'function' ? source(data) : source;\n\n\t\treturn data['resolvedData'] ? this.getResolvedBreadcrumb(label, data['resolvedData']) : label;\n\t}\n\n\tprivate getResolvedBreadcrumb(template: string, data: any): string {\n\t\treturn template.replace(/\\{([^}]+)\\}/g, (match, key) => {\n\t\t\treturn data[key] || match;\n\t\t});\n\t}\n}\n","import { NgTemplateOutlet } from '@angular/common';\nimport { Component, computed, contentChild, inject, input, linkedSignal, output, TemplateRef } from '@angular/core';\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport { RouterLink } from '@angular/router';\nimport { HubBreadcrumbItemDirective } from '../../directives/breadcrumb-item.directive';\nimport { HubBreadcrumbLabelDirective } from '../../directives/breadcrumb-label.directive';\nimport { BreadcrumbItem } from '../../models/breadcrumb-item';\nimport { HubBreadcrumbsService } from '../../services/breadcrumbs.service';\n\n/** Variants with exact design-system token coverage via the SCSS `@each` loop. */\nconst BUILT_IN_VARIANTS = new Set<string>(['primary', 'success', 'danger', 'warning', 'info']);\n\n/**\n * One rendered position of the trail. A `null` item is the collapsed indicator,\n * which occupies a position of its own so the separators fall around it exactly\n * as they do around a crumb.\n */\ninterface BreadcrumbRow {\n\titem: BreadcrumbItem | null;\n\tisLast: boolean;\n\t/** Resolved anchor `rel`, already defended for `_blank` targets. */\n\trel: string | null;\n}\n\n@Component({\n\tselector: 'hub-breadcrumb',\n\timports: [RouterLink, NgTemplateOutlet, HubBreadcrumbLabelDirective],\n\ttemplateUrl: './breadcrumb.component.html',\n\tstyleUrl: './breadcrumb.component.scss',\n\thost: {\n\t\tclass: 'hub-breadcrumb',\n\t\t'[class.hub-breadcrumb--truncate]': 'truncateItems()',\n\t\t'[attr.data-variant]': 'variant() ?? null',\n\t\t'[style.--hub-breadcrumb-accent]': 'customAccent()'\n\t}\n})\nexport class HubBreadcrumbComponent {\n\t#breadcrumbsSvc = inject(HubBreadcrumbsService);\n\n\treadonly itemTemplate = contentChild(HubBreadcrumbItemDirective, { read: TemplateRef });\n\n\tbreadcrumbs$ = this.#breadcrumbsSvc.breadcrumbs$;\n\n\t/**\n\t * Semantic accent for the breadcrumb links: `'primary'` · `'success'` ·\n\t * `'danger'` · `'warning'` · `'info'`, or any custom string (read as\n\t * `--hub-sys-color-<variant>`). Re-bases `--hub-breadcrumb-accent`; the\n\t * current (last) item stays muted. Defaults to the standard link colour.\n\t */\n\treadonly variant = input<string>();\n\n\t/**\n\t * Opt-in per-item truncation. When `true`, each label is clipped to\n\t * `--hub-breadcrumb-max-item-width` with an ellipsis and, if it overflows,\n\t * exposes its full text as a tooltip (native `title`, or the hub-ui tooltip\n\t * when {@link provideHubBreadcrumbTooltip} is wired). Off by default, so the\n\t * standard breadcrumb layout is unchanged.\n\t */\n\treadonly truncateItems = input(false);\n\n\t/**\n\t * Trail supplied by the consumer, replacing the one derived from the router.\n\t * It is the way in for crumbs the route tree cannot express — an ancestor\n\t * served by another application, or a trail assembled by hand. Left `null`,\n\t * the component keeps reading {@link HubBreadcrumbsService}.\n\t */\n\treadonly items = input<BreadcrumbItem[] | null>(null);\n\n\t/**\n\t * Length above which the trail collapses behind an indicator. Undefined (the\n\t * default) never collapses, however long the trail grows.\n\t */\n\treadonly maxItems = input<number | undefined>(undefined);\n\n\t/** Crumbs kept at the head of a collapsed trail. */\n\treadonly itemsBeforeCollapse = input(1);\n\n\t/** Crumbs kept at the tail of a collapsed trail, the current page included. */\n\treadonly itemsAfterCollapse = input(1);\n\n\t/**\n\t * Accessible name of the collapsed indicator. It is an input rather than a\n\t * literal because it is the one string of this component a screen reader\n\t * announces, and the library carries no translations of its own.\n\t */\n\treadonly collapsedAriaLabel = input('Show the hidden breadcrumb items');\n\n\t/**\n\t * Fires when the collapsed indicator is activated. The trail expands in place\n\t * on its own; the event is there for consumers who want to react as well —\n\t * open a menu of the hidden crumbs, log the interaction.\n\t */\n\treadonly collapsedClick = output<void>();\n\n\t/** Trail as published by the service, tracked as a signal. */\n\treadonly #routerTrail = toSignal(this.breadcrumbs$, { initialValue: [] as BreadcrumbItem[] });\n\n\t/** Effective trail: the manual one when supplied, the router's otherwise. */\n\tprotected readonly trail = computed(() => this.items() ?? this.#routerTrail());\n\n\t/**\n\t * Whether the reader has opened a collapsed trail. Derived from the trail so a\n\t * new navigation collapses it again — an expansion answers one trail, not the\n\t * component's whole lifetime.\n\t */\n\tprotected readonly expanded = linkedSignal<BreadcrumbItem[], boolean>({\n\t\tsource: this.trail,\n\t\tcomputation: () => false\n\t});\n\n\t/** Rendered positions, with the collapsed range folded into one indicator. */\n\tprotected readonly rows = computed<BreadcrumbRow[]>(() => {\n\t\tconst items = this.trail();\n\t\tconst before = Math.max(0, this.itemsBeforeCollapse());\n\t\tconst after = Math.max(0, this.itemsAfterCollapse());\n\t\tconst max = this.maxItems();\n\n\t\tconst rowAt = (item: BreadcrumbItem, index: number): BreadcrumbRow => ({\n\t\t\titem,\n\t\t\tisLast: index === items.length - 1,\n\t\t\trel: this.resolveRel(item)\n\t\t});\n\n\t\tconst collapses = max !== undefined && max > 0 && items.length > max && before + after < items.length;\n\n\t\tif (!collapses || this.expanded()) {\n\t\t\treturn items.map(rowAt);\n\t\t}\n\n\t\tconst tailStart = items.length - after;\n\n\t\treturn [\n\t\t\t...items.slice(0, before).map(rowAt),\n\t\t\t{ item: null, isLast: false, rel: null },\n\t\t\t...items.slice(tailStart).map((item, index) => rowAt(item, tailStart + index))\n\t\t];\n\t});\n\n\t/**\n\t * Inline accent for custom (non-built-in) variants — the built-in five are\n\t * resolved by the SCSS `@each` loop, so this returns `null` for them.\n\t */\n\tprotected readonly customAccent = computed(() => {\n\t\tconst v = this.variant();\n\t\treturn v && !BUILT_IN_VARIANTS.has(v) ? `var(--hub-sys-color-${v})` : null;\n\t});\n\n\t/** Opens a collapsed trail and lets the consumer act on the same gesture. */\n\tprotected expand(): void {\n\t\tthis.expanded.set(true);\n\t\tthis.collapsedClick.emit();\n\t}\n\n\t/**\n\t * A crumb opening in a new tab hands the opener to the destination unless it\n\t * says otherwise, so the default closes that door rather than leaving it to\n\t * each consumer to remember.\n\t */\n\tprivate resolveRel(item: BreadcrumbItem): string | null {\n\t\treturn item.rel ?? (item.target === '_blank' ? 'noopener noreferrer' : null);\n\t}\n}\n","<nav aria-label=\"breadcrumb\" class=\"hub-breadcrumb__nav\">\n\t<ol class=\"hub-breadcrumb__list\">\n\t\t@for (row of rows(); track $index) {\n\t\t\t@if (row.item; as item) {\n\t\t\t\t<li class=\"hub-breadcrumb__item\" [class.hub-breadcrumb__item--active]=\"row.isLast\">\n\t\t\t\t\t@if (itemTemplate(); as template) {\n\t\t\t\t\t\t<ng-container\n\t\t\t\t\t\t\t[ngTemplateOutlet]=\"template\"\n\t\t\t\t\t\t\t[ngTemplateOutletContext]=\"{\n\t\t\t\t\t\t\t\t$implicit: item,\n\t\t\t\t\t\t\t\tisLast: row.isLast\n\t\t\t\t\t\t\t}\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t} @else if (row.isLast) {\n\t\t\t\t\t\t<span class=\"hub-breadcrumb__text\" hubBreadcrumbLabel aria-current=\"page\">{{ item.label }}</span>\n\t\t\t\t\t} @else if (item.href) {\n\t\t\t\t\t\t<a\n\t\t\t\t\t\t\tclass=\"hub-breadcrumb__link\"\n\t\t\t\t\t\t\thubBreadcrumbLabel\n\t\t\t\t\t\t\t[href]=\"item.href\"\n\t\t\t\t\t\t\t[attr.target]=\"item.target ?? null\"\n\t\t\t\t\t\t\t[attr.rel]=\"row.rel\"\n\t\t\t\t\t\t\t[attr.download]=\"item.download ?? null\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{{ item.label }}\n\t\t\t\t\t\t</a>\n\t\t\t\t\t} @else {\n\t\t\t\t\t\t<a [routerLink]=\"item.url\" class=\"hub-breadcrumb__link\" hubBreadcrumbLabel>\n\t\t\t\t\t\t\t{{ item.label }}\n\t\t\t\t\t\t</a>\n\t\t\t\t\t}\n\t\t\t\t</li>\n\t\t\t} @else {\n\t\t\t\t<li class=\"hub-breadcrumb__item hub-breadcrumb__item--collapsed\">\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclass=\"hub-breadcrumb__collapsed\"\n\t\t\t\t\t\t[attr.aria-label]=\"collapsedAriaLabel()\"\n\t\t\t\t\t\t[attr.aria-expanded]=\"expanded()\"\n\t\t\t\t\t\t(click)=\"expand()\"\n\t\t\t\t\t>\n\t\t\t\t\t\t…\n\t\t\t\t\t</button>\n\t\t\t\t</li>\n\t\t\t}\n\t\t}\n\t</ol>\n</nav>\n","import { NgModule } from '@angular/core';\nimport { HubBreadcrumbComponent } from './components/breadcrumb/breadcrumb.component';\nimport { HubBreadcrumbItemDirective } from './directives/breadcrumb-item.directive';\n\n@NgModule({\n\tdeclarations: [],\n\timports: [HubBreadcrumbComponent, HubBreadcrumbItemDirective],\n\texports: [HubBreadcrumbComponent, HubBreadcrumbItemDirective]\n})\nexport class HubBreadcrumbsModule {}\n","import { EnvironmentProviders, makeEnvironmentProviders } from '@angular/core';\nimport { HUB_BREADCRUMB_TOOLTIP_ADAPTER } from './breadcrumb-tooltip.token';\nimport { HubBreadcrumbTooltipAdapter } from './breadcrumb-tooltip.types';\n\n/**\n * Registers a tooltip adapter so truncated breadcrumb labels render the rich\n * hub-ui tooltip instead of the native `title` fallback.\n *\n * ```ts\n * import { provideHubBreadcrumbTooltip } from 'ng-hub-ui-breadcrumbs';\n * import { hubTooltipAdapter } from 'ng-hub-ui-utils';\n *\n * providers: [provideHubBreadcrumbTooltip(hubTooltipAdapter)];\n * ```\n *\n * @param adapter Tooltip adapter implementation (e.g. `hubTooltipAdapter` from\n * `ng-hub-ui-utils`).\n * @returns Environment providers to add to the application config.\n */\nexport function provideHubBreadcrumbTooltip(adapter: HubBreadcrumbTooltipAdapter): EnvironmentProviders {\n\treturn makeEnvironmentProviders([\n\t\t{\n\t\t\tprovide: HUB_BREADCRUMB_TOOLTIP_ADAPTER,\n\t\t\tuseValue: adapter\n\t\t}\n\t]);\n}\n","/*\n * Public API Surface of breadcrumbs\n */\nexport * from './lib/breadcrumbs.module';\nexport * from './lib/breadcrumb-tooltip';\nexport * from './lib/components/breadcrumb/breadcrumb.component';\nexport * from './lib/directives/breadcrumb-item.directive';\nexport * from './lib/directives/breadcrumb-label.directive';\nexport * from './lib/models/breadcrumb-item';\nexport * from './lib/models/breadcrumb-template-context';\nexport * from './lib/services/breadcrumbs.service';\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,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ng-hub-ui-breadcrumbs",
|
|
3
|
-
"version": "22.
|
|
3
|
+
"version": "22.5.0",
|
|
4
4
|
"description": "A flexible and reusable breadcrumb component for Angular applications that automatically generates breadcrumbs based on routing configuration",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"angular",
|
|
@@ -1,16 +1,58 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as _angular_core from '@angular/core';
|
|
2
2
|
import { TemplateRef, InjectionToken, EnvironmentProviders, OnDestroy } from '@angular/core';
|
|
3
3
|
import * as rxjs from 'rxjs';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* A single crumb of the trail.
|
|
7
|
+
*
|
|
8
|
+
* `url` is the in-app destination and remains the default one: it is handed to
|
|
9
|
+
* `routerLink`. The optional anchor fields take over when the crumb's canonical
|
|
10
|
+
* destination is not an Angular route — a section still served by a legacy app,
|
|
11
|
+
* another domain, or a file meant to be saved rather than opened.
|
|
12
|
+
*/
|
|
5
13
|
interface BreadcrumbItem {
|
|
6
14
|
label: string;
|
|
7
15
|
url: string;
|
|
8
|
-
data
|
|
16
|
+
data?: any;
|
|
17
|
+
/** External destination. When present the crumb renders a plain anchor, not a `routerLink`. */
|
|
18
|
+
href?: string;
|
|
19
|
+
/** Anchor `target` (e.g. `_blank`). Only meaningful alongside `href`. */
|
|
20
|
+
target?: string;
|
|
21
|
+
/** Anchor `rel`. Left unset, a `_blank` crumb still gets `noopener noreferrer`. */
|
|
22
|
+
rel?: string;
|
|
23
|
+
/** Anchor `download`: the crumb points at a file to save instead of a page to open. */
|
|
24
|
+
download?: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Object form accepted by a route's `data.breadcrumb`, for the crumbs whose
|
|
28
|
+
* destination lies outside the router. The string and function forms stay valid
|
|
29
|
+
* and are the right choice for the ordinary in-app crumb.
|
|
30
|
+
*
|
|
31
|
+
* ```ts
|
|
32
|
+
* { path: 'invoices', data: { breadcrumb: { label: 'Invoices', href: 'https://legacy.example.com/invoices' } } }
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
interface BreadcrumbRouteConfig extends Pick<BreadcrumbItem, 'href' | 'target' | 'rel' | 'download'> {
|
|
36
|
+
/** Static label, or a function receiving the route's resolved `data`. */
|
|
37
|
+
label: string | ((data: any) => string);
|
|
9
38
|
}
|
|
39
|
+
/** Every shape a route may declare under `data.breadcrumb`. */
|
|
40
|
+
type BreadcrumbRouteData = string | ((data: any) => string) | BreadcrumbRouteConfig;
|
|
10
41
|
|
|
42
|
+
/**
|
|
43
|
+
* One rendered position of the trail. A `null` item is the collapsed indicator,
|
|
44
|
+
* which occupies a position of its own so the separators fall around it exactly
|
|
45
|
+
* as they do around a crumb.
|
|
46
|
+
*/
|
|
47
|
+
interface BreadcrumbRow {
|
|
48
|
+
item: BreadcrumbItem | null;
|
|
49
|
+
isLast: boolean;
|
|
50
|
+
/** Resolved anchor `rel`, already defended for `_blank` targets. */
|
|
51
|
+
rel: string | null;
|
|
52
|
+
}
|
|
11
53
|
declare class HubBreadcrumbComponent {
|
|
12
54
|
#private;
|
|
13
|
-
readonly itemTemplate:
|
|
55
|
+
readonly itemTemplate: _angular_core.Signal<TemplateRef<any> | undefined>;
|
|
14
56
|
breadcrumbs$: rxjs.Observable<BreadcrumbItem[]>;
|
|
15
57
|
/**
|
|
16
58
|
* Semantic accent for the breadcrumb links: `'primary'` · `'success'` ·
|
|
@@ -18,7 +60,7 @@ declare class HubBreadcrumbComponent {
|
|
|
18
60
|
* `--hub-sys-color-<variant>`). Re-bases `--hub-breadcrumb-accent`; the
|
|
19
61
|
* current (last) item stays muted. Defaults to the standard link colour.
|
|
20
62
|
*/
|
|
21
|
-
readonly variant:
|
|
63
|
+
readonly variant: _angular_core.InputSignal<string | undefined>;
|
|
22
64
|
/**
|
|
23
65
|
* Opt-in per-item truncation. When `true`, each label is clipped to
|
|
24
66
|
* `--hub-breadcrumb-max-item-width` with an ellipsis and, if it overflows,
|
|
@@ -26,26 +68,72 @@ declare class HubBreadcrumbComponent {
|
|
|
26
68
|
* when {@link provideHubBreadcrumbTooltip} is wired). Off by default, so the
|
|
27
69
|
* standard breadcrumb layout is unchanged.
|
|
28
70
|
*/
|
|
29
|
-
readonly truncateItems:
|
|
71
|
+
readonly truncateItems: _angular_core.InputSignal<boolean>;
|
|
72
|
+
/**
|
|
73
|
+
* Trail supplied by the consumer, replacing the one derived from the router.
|
|
74
|
+
* It is the way in for crumbs the route tree cannot express — an ancestor
|
|
75
|
+
* served by another application, or a trail assembled by hand. Left `null`,
|
|
76
|
+
* the component keeps reading {@link HubBreadcrumbsService}.
|
|
77
|
+
*/
|
|
78
|
+
readonly items: _angular_core.InputSignal<BreadcrumbItem[] | null>;
|
|
79
|
+
/**
|
|
80
|
+
* Length above which the trail collapses behind an indicator. Undefined (the
|
|
81
|
+
* default) never collapses, however long the trail grows.
|
|
82
|
+
*/
|
|
83
|
+
readonly maxItems: _angular_core.InputSignal<number | undefined>;
|
|
84
|
+
/** Crumbs kept at the head of a collapsed trail. */
|
|
85
|
+
readonly itemsBeforeCollapse: _angular_core.InputSignal<number>;
|
|
86
|
+
/** Crumbs kept at the tail of a collapsed trail, the current page included. */
|
|
87
|
+
readonly itemsAfterCollapse: _angular_core.InputSignal<number>;
|
|
88
|
+
/**
|
|
89
|
+
* Accessible name of the collapsed indicator. It is an input rather than a
|
|
90
|
+
* literal because it is the one string of this component a screen reader
|
|
91
|
+
* announces, and the library carries no translations of its own.
|
|
92
|
+
*/
|
|
93
|
+
readonly collapsedAriaLabel: _angular_core.InputSignal<string>;
|
|
94
|
+
/**
|
|
95
|
+
* Fires when the collapsed indicator is activated. The trail expands in place
|
|
96
|
+
* on its own; the event is there for consumers who want to react as well —
|
|
97
|
+
* open a menu of the hidden crumbs, log the interaction.
|
|
98
|
+
*/
|
|
99
|
+
readonly collapsedClick: _angular_core.OutputEmitterRef<void>;
|
|
100
|
+
/** Effective trail: the manual one when supplied, the router's otherwise. */
|
|
101
|
+
protected readonly trail: _angular_core.Signal<BreadcrumbItem[]>;
|
|
102
|
+
/**
|
|
103
|
+
* Whether the reader has opened a collapsed trail. Derived from the trail so a
|
|
104
|
+
* new navigation collapses it again — an expansion answers one trail, not the
|
|
105
|
+
* component's whole lifetime.
|
|
106
|
+
*/
|
|
107
|
+
protected readonly expanded: _angular_core.WritableSignal<boolean>;
|
|
108
|
+
/** Rendered positions, with the collapsed range folded into one indicator. */
|
|
109
|
+
protected readonly rows: _angular_core.Signal<BreadcrumbRow[]>;
|
|
30
110
|
/**
|
|
31
111
|
* Inline accent for custom (non-built-in) variants — the built-in five are
|
|
32
112
|
* resolved by the SCSS `@each` loop, so this returns `null` for them.
|
|
33
113
|
*/
|
|
34
|
-
protected readonly customAccent:
|
|
35
|
-
|
|
36
|
-
|
|
114
|
+
protected readonly customAccent: _angular_core.Signal<string | null>;
|
|
115
|
+
/** Opens a collapsed trail and lets the consumer act on the same gesture. */
|
|
116
|
+
protected expand(): void;
|
|
117
|
+
/**
|
|
118
|
+
* A crumb opening in a new tab hands the opener to the destination unless it
|
|
119
|
+
* says otherwise, so the default closes that door rather than leaving it to
|
|
120
|
+
* each consumer to remember.
|
|
121
|
+
*/
|
|
122
|
+
private resolveRel;
|
|
123
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<HubBreadcrumbComponent, never>;
|
|
124
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<HubBreadcrumbComponent, "hub-breadcrumb", never, { "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "truncateItems": { "alias": "truncateItems"; "required": false; "isSignal": true; }; "items": { "alias": "items"; "required": false; "isSignal": true; }; "maxItems": { "alias": "maxItems"; "required": false; "isSignal": true; }; "itemsBeforeCollapse": { "alias": "itemsBeforeCollapse"; "required": false; "isSignal": true; }; "itemsAfterCollapse": { "alias": "itemsAfterCollapse"; "required": false; "isSignal": true; }; "collapsedAriaLabel": { "alias": "collapsedAriaLabel"; "required": false; "isSignal": true; }; }, { "collapsedClick": "collapsedClick"; }, ["itemTemplate"], never, true, never>;
|
|
37
125
|
}
|
|
38
126
|
|
|
39
127
|
declare class HubBreadcrumbItemDirective {
|
|
40
128
|
template: TemplateRef<any>;
|
|
41
|
-
static ɵfac:
|
|
42
|
-
static ɵdir:
|
|
129
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<HubBreadcrumbItemDirective, never>;
|
|
130
|
+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<HubBreadcrumbItemDirective, "[hubBreadcrumbItem]", never, {}, {}, never, never, true, never>;
|
|
43
131
|
}
|
|
44
132
|
|
|
45
133
|
declare class HubBreadcrumbsModule {
|
|
46
|
-
static ɵfac:
|
|
47
|
-
static ɵmod:
|
|
48
|
-
static ɵinj:
|
|
134
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<HubBreadcrumbsModule, never>;
|
|
135
|
+
static ɵmod: _angular_core.ɵɵNgModuleDeclaration<HubBreadcrumbsModule, never, [typeof HubBreadcrumbComponent, typeof HubBreadcrumbItemDirective], [typeof HubBreadcrumbComponent, typeof HubBreadcrumbItemDirective]>;
|
|
136
|
+
static ɵinj: _angular_core.ɵɵInjectorDeclaration<HubBreadcrumbsModule>;
|
|
49
137
|
}
|
|
50
138
|
|
|
51
139
|
/**
|
|
@@ -120,7 +208,7 @@ declare class HubBreadcrumbLabelDirective implements OnDestroy {
|
|
|
120
208
|
* Explicit tooltip text. When empty, the host's own text content is used, but
|
|
121
209
|
* only while it is truncated.
|
|
122
210
|
*/
|
|
123
|
-
readonly tooltip:
|
|
211
|
+
readonly tooltip: _angular_core.InputSignal<string>;
|
|
124
212
|
private readonly host;
|
|
125
213
|
/** Optional hub-ui tooltip adapter; absent means native `title` fallback. */
|
|
126
214
|
private readonly adapter;
|
|
@@ -144,8 +232,13 @@ declare class HubBreadcrumbLabelDirective implements OnDestroy {
|
|
|
144
232
|
* or the native `title` attribute otherwise. An empty text removes both.
|
|
145
233
|
*/
|
|
146
234
|
private applyTooltip;
|
|
147
|
-
static ɵfac:
|
|
148
|
-
static ɵdir:
|
|
235
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<HubBreadcrumbLabelDirective, never>;
|
|
236
|
+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<HubBreadcrumbLabelDirective, "[hubBreadcrumbLabel]", never, { "tooltip": { "alias": "hubBreadcrumbLabel"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
interface BreadcrumbTemplateContext {
|
|
240
|
+
$implicit: BreadcrumbItem;
|
|
241
|
+
isLast: boolean;
|
|
149
242
|
}
|
|
150
243
|
|
|
151
244
|
declare class HubBreadcrumbsService {
|
|
@@ -153,11 +246,20 @@ declare class HubBreadcrumbsService {
|
|
|
153
246
|
breadcrumbs$: rxjs.Observable<BreadcrumbItem[]>;
|
|
154
247
|
private createBreadcrumbs;
|
|
155
248
|
private hasOwnBreadcrumbData;
|
|
156
|
-
|
|
249
|
+
/**
|
|
250
|
+
* Builds the crumb for a route. The object form of `data.breadcrumb` carries
|
|
251
|
+
* anchor metadata for destinations outside the router; whatever accompanies
|
|
252
|
+
* `label` there travels to the item untouched, so a new anchor attribute needs
|
|
253
|
+
* no change here.
|
|
254
|
+
*/
|
|
255
|
+
private createItem;
|
|
256
|
+
/** Narrows `data.breadcrumb` to its object form, excluding the function form. */
|
|
257
|
+
private isRouteConfig;
|
|
258
|
+
private resolveLabel;
|
|
157
259
|
private getResolvedBreadcrumb;
|
|
158
|
-
static ɵfac:
|
|
159
|
-
static ɵprov:
|
|
260
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<HubBreadcrumbsService, never>;
|
|
261
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<HubBreadcrumbsService>;
|
|
160
262
|
}
|
|
161
263
|
|
|
162
264
|
export { HUB_BREADCRUMB_TOOLTIP_ADAPTER, HubBreadcrumbComponent, HubBreadcrumbItemDirective, HubBreadcrumbLabelDirective, HubBreadcrumbsModule, HubBreadcrumbsService, provideHubBreadcrumbTooltip };
|
|
163
|
-
export type { HubBreadcrumbTooltipAdapter, HubBreadcrumbTooltipHandle };
|
|
265
|
+
export type { BreadcrumbItem, BreadcrumbRouteConfig, BreadcrumbRouteData, BreadcrumbTemplateContext, HubBreadcrumbTooltipAdapter, HubBreadcrumbTooltipHandle };
|
|
Binary file
|