ngx-opalbytes-components 1.28.0 → 1.29.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/README.md CHANGED
@@ -234,11 +234,13 @@ src/
234
234
  └── components/
235
235
  | ├── accordion/
236
236
  | ├── accordion-item/
237
+ | ├── avatar/
237
238
  | ├── base-button/
238
239
  | ├── base-icon/
239
240
  | ├── base-input/
240
241
  | ├── base-time-range/
241
242
  | ├── base-toggle/
243
+ | ├── breadcrumb/
242
244
  | ├── checkbox/
243
245
  | ├── drop-down/
244
246
  | ├── footer/
@@ -930,6 +932,61 @@ Um componente de alternância (toggle switch) que funciona com `ngModel` ou `for
930
932
  | `inputChange` | `EventEmitter<string>` | Emitido a cada mudança no input. |
931
933
  | `statusChanged` | `EventEmitter<CaoBaseToggleComponent>` | Emitido quando o toggle é alternado. |
932
934
 
935
+ ---
936
+
937
+ ### `CaoBreadcrumbComponent`
938
+
939
+ Trilha de navegação (breadcrumb) com ícones Lucide ou imagem, link de navegação, badge e divisor customizável.
940
+
941
+ **Seletor:** `<cao-breadcrumb>`
942
+
943
+ **Interface `ICaoBreadcrumbItem`**
944
+
945
+ | Propriedade | Tipo | Padrão | Descrição |
946
+ | --- | --- | --- | --- |
947
+ | `label` | `string` | — | Texto do item. |
948
+ | `icon` | `string` | — | Nome do ícone Lucide ou URL/caminho/data URI de imagem. |
949
+ | `isLucideIcon` | `boolean` | `true` | Define se `icon` é Lucide. |
950
+ | `iconPosition` | `'left' \| 'right'` | `'left'` | Direção do ícone em relação ao texto. |
951
+ | `iconColor` / `iconSize` / `iconStrokeWidth` | `string` / `number` / `number` | — / `16` / `1.5` | Aparência do ícone. |
952
+ | `link` | `string \| unknown[]` | — | Navegação interna (`routerLink`). |
953
+ | `queryParams` | `Params` | — | Query params do `link`. |
954
+ | `href` / `target` | `string` / `'_self' \| '_blank' ...` | — | Navegação externa. |
955
+ | `command` | `(e: ICaoBreadcrumbItemClickEvent) => void` | — | Callback de clique (sem `link`/`href` vira `<button>`). |
956
+ | `badge` / `badgeColor` / `badgeBgColor` | `string \| number` / `string` / `string` | — | Badge do item. |
957
+ | `disabled` | `boolean` | `false` | Desabilita o item. |
958
+ | `ariaLabel` / `dataCy` | `string` | — | Acessibilidade e testes E2E. |
959
+
960
+ **Atributos (Inputs)**
961
+
962
+ | Atributo | Tipo | Padrão | Descrição |
963
+ | --- | --- | --- | --- |
964
+ | `items` | `ICaoBreadcrumbItem[]` | `[]` | Itens; o último é a página atual (`aria-current="page"`). |
965
+ | `home` | `ICaoBreadcrumbItem` | `undefined` | Item inicial opcional. |
966
+ | `separator` | `string` | `'/'` | Texto do divisor. |
967
+ | `separatorIcon` | `string` | `''` | Ícone do divisor (sobrepõe `separator`). |
968
+ | `isLucideSeparatorIcon` | `boolean` | `true` | Define se `separatorIcon` é Lucide. |
969
+ | `separatorIconSize` / `separatorIconStrokeWidth` | `number` | `14` / `1.5` | Aparência do ícone divisor. |
970
+ | `linkColor`, `linkHoverColor`, `currentColor`, `separatorColor`, `fontSize`, `gap` | `string` | `''` | Atalhos para as CSS custom properties. |
971
+ | `ariaLabel` | `string` | `'Breadcrumb'` | `aria-label` do `<nav>`. |
972
+ | `dataCy` | `string` | `''` | Atributo para testes E2E. |
973
+
974
+ **Eventos (Outputs):** `itemClick` → `ICaoBreadcrumbItemClickEvent` (`item`, `index`, `originalEvent`).
975
+
976
+ **CSS Custom Properties:** `--cao-breadcrumb-link-color` (`#6b7280`), `--cao-breadcrumb-link-hover-color` (`#4f46e5`), `--cao-breadcrumb-current-color` (`#111827`), `--cao-breadcrumb-separator-color` (`#9ca3af`), `--cao-breadcrumb-disabled-color`, `--cao-breadcrumb-focus-ring`, `--cao-breadcrumb-badge-bg`, `--cao-breadcrumb-badge-text`, `--cao-breadcrumb-gap` (`8px`), `--cao-breadcrumb-font-size` (`0.875rem`).
977
+
978
+ ```html
979
+ <cao-breadcrumb
980
+ [home]="{ icon: 'house', ariaLabel: 'Início', link: '/' }"
981
+ [items]="[
982
+ { label: 'Pedidos', icon: 'package', iconPosition: 'right', link: '/pedidos', badge: 12 },
983
+ { label: 'Pedido #42' }
984
+ ]"
985
+ separatorIcon="chevron-right" />
986
+ ```
987
+
988
+ > Depende de `BaseIcon` (copie junto ao usar `cao-comp`) e de `@angular/router`.
989
+
933
990
  ---
934
991
  ### `CaoAccordionComponent` e `CaoAccordionItemComponent`
935
992
 
@@ -1130,7 +1187,110 @@ export class FaqComponent {}
1130
1187
  - Fora de um `<cao-accordion>`, o item se comporta como um cartão expansível independente.
1131
1188
 
1132
1189
  ---
1190
+ ### `CaoAvatarComponent`
1191
+
1192
+ Avatar para representar usuários ou entidades, com imagem, ícone (Lucide ou imagem) ou texto (iniciais). Possui imagem padrão embutida, usada enquanto nenhuma fonte for informada ou quando a imagem falha ao carregar. Tamanho, formato e contorno (stroke) são configuráveis.
1193
+
1194
+ **Seletor:** `<cao-avatar>`
1195
+
1196
+ **Tipos**
1133
1197
 
1198
+ | Tipo | Valores |
1199
+ | --- | --- |
1200
+ | `CaoAvatarPresetSize` | `'small'` (24px) \| `'normal'` (32px) \| `'large'` (48px) \| `'xlarge'` (64px) |
1201
+ | `CaoAvatarShape` | `'circle'` \| `'rounded'` \| `'square'` |
1202
+ | `CaoAvatarStrokeStyle` | `'solid'` \| `'dashed'` \| `'dotted'` \| `'double'` |
1203
+
1204
+ **Atributos (Inputs)**
1205
+
1206
+ | Atributo | Tipo | Padrão | Descrição |
1207
+ | --- | --- | --- | --- |
1208
+ | `src` | `string \| null \| undefined` | `''` | URL da imagem. Se vazia ou se falhar ao carregar, o avatar usa `icon`, `label` ou a imagem padrão (nessa ordem). |
1209
+ | `defaultSrc` | `string` | `''` | Imagem padrão customizada. Se vazia, usa a silhueta embutida (`CAO_AVATAR_DEFAULT_SRC`). |
1210
+ | `label` | `string` | `''` | Texto exibido (ex.: iniciais) quando não há imagem nem ícone. |
1211
+ | `icon` | `string` | `''` | Nome do ícone Lucide ou caminho/URL de imagem usada como ícone. |
1212
+ | `isLucideIcon` | `boolean` | `true` | Define se `icon` é um ícone Lucide. |
1213
+ | `iconColor` | `string` | `''` | Cor do ícone Lucide. Se vazia, usa `textColor`. |
1214
+ | `size` | `CaoAvatarPresetSize \| number \| string` | `'normal'` | Tamanho predefinido, número em px ou texto (`'72px'`, `'4.5rem'`). Valores inválidos voltam para `'normal'`. |
1215
+ | `shape` | `CaoAvatarShape` | `'circle'` | Formato do avatar. |
1216
+ | `strokeWidth` | `number \| string` | `0` | Espessura do contorno. Número é convertido para `px`; `0` remove o contorno. |
1217
+ | `strokeColor` | `string` | `'#ffffff'` | Cor do contorno. |
1218
+ | `strokeStyle` | `CaoAvatarStrokeStyle` | `'solid'` | Estilo do contorno. |
1219
+ | `bgColor` | `string` | `''` | Cor de fundo (sobrescreve `--cao-avatar-bg`). |
1220
+ | `textColor` | `string` | `''` | Cor do texto/ícone (sobrescreve `--cao-avatar-text`). |
1221
+ | `alt` | `string` | `''` | Texto alternativo do avatar. |
1222
+ | `ariaLabel` | `string` | `''` | `aria-label` do avatar. Prioridade: `ariaLabel` → `alt` → `label` → `'Avatar'`. |
1223
+ | `dataCy` | `string` | `''` | Atributo para testes E2E com Cypress. |
1224
+
1225
+ **Ordem de exibição**
1226
+
1227
+ 1. `src` (se informado e carregado com sucesso);
1228
+ 2. `icon`;
1229
+ 3. `label`;
1230
+ 4. imagem padrão (`defaultSrc` ou a silhueta embutida).
1231
+
1232
+ Se o `src` falhar ao carregar (erro 404, URL inválida etc.), o componente passa automaticamente para o próximo item da lista.
1233
+
1234
+ **Constantes exportadas**
1235
+
1236
+ | Constante | Descrição |
1237
+ | --- | --- |
1238
+ | `CAO_AVATAR_DEFAULT_SRC` | Data URI da imagem padrão (silhueta em SVG, funciona offline). |
1239
+ | `CAO_AVATAR_SIZES` | Mapa dos tamanhos predefinidos em px (`small`, `normal`, `large`, `xlarge`). |
1240
+
1241
+ **CSS Custom Properties**
1242
+
1243
+ | Propriedade | Padrão | Descrição |
1244
+ | --- | --- | --- |
1245
+ | `--cao-avatar-bg` | `#e5e7eb` | Cor de fundo. |
1246
+ | `--cao-avatar-text` | `#374151` | Cor do texto/ícone. |
1247
+ | `--cao-avatar-radius` | `25%` | Raio da borda no formato `rounded`. |
1248
+
1249
+ **Exemplo básico:**
1250
+
1251
+ ```html
1252
+ <!-- Sem src: exibe a imagem padrão -->
1253
+ <cao-avatar></cao-avatar>
1254
+
1255
+ <!-- Com imagem -->
1256
+ <cao-avatar src="https://exemplo.com/foto.png" alt="Foto de Maria" size="large"></cao-avatar>
1257
+
1258
+ <!-- Com iniciais -->
1259
+ <cao-avatar label="MB" bgColor="#eef2ff" textColor="#4338ca"></cao-avatar>
1260
+
1261
+ <!-- Com ícone Lucide -->
1262
+ <cao-avatar icon="user" bgColor="#dcfce7" iconColor="#166534"></cao-avatar>
1263
+ ```
1264
+
1265
+ **Exemplo com tamanho, formato e contorno:**
1266
+
1267
+ ```html
1268
+ <cao-avatar src="assets/foto.png" size="xlarge" shape="rounded"></cao-avatar>
1269
+ <cao-avatar src="assets/foto.png" [size]="96" shape="square"></cao-avatar>
1270
+ <cao-avatar src="assets/foto.png" size="7rem"></cao-avatar>
1271
+
1272
+ <cao-avatar
1273
+ src="assets/foto.png"
1274
+ size="xlarge"
1275
+ [strokeWidth]="3"
1276
+ strokeColor="#4f46e5"
1277
+ strokeStyle="dashed">
1278
+ </cao-avatar>
1279
+ ```
1280
+
1281
+ **Exemplo com imagem padrão customizada:**
1282
+
1283
+ ```html
1284
+ <cao-avatar [src]="usuario.foto" defaultSrc="assets/avatar-padrao.png"></cao-avatar>
1285
+ ```
1286
+
1287
+ **Observações:**
1288
+
1289
+ - Possui `role="img"` com `aria-label`; a imagem interna é decorativa (`alt=""`), evitando leitura duplicada.
1290
+ - A imagem padrão é um SVG em data URI e passa por `DomSanitizer.bypassSecurityTrustUrl` (conteúdo controlado pela lib). Data URIs em SVG informadas em `src` **não** recebem esse tratamento e podem ser bloqueadas pelo sanitizador do Angular — use URL, caminho de arquivo ou PNG/JPEG em base64.
1291
+ - Para ícones Lucide, registre os ícones usados com `provideLucideIcons` (de `@lucide/angular`).
1292
+ - Depende de `BaseIcon` (copie junto ao usar `cao-comp`).
1293
+ ---
1134
1294
  ### `CaoSlideToggleComponent`
1135
1295
 
1136
1296
  Um switch (slide toggle) acessível e customizável, com suporte a `ngModel` e formulários reativos via `ControlValueAccessor`. O visual é construído com trilho e thumb animados, sem depender do Material em runtime.
package/cli/cao-comp.cjs CHANGED
@@ -185,7 +185,7 @@ import { fn } from 'storybook/test';
185
185
  import { CaoBaseButtonComponent } from '../../app/components/base-button/base-button.component';
186
186
 
187
187
  const meta: Meta<CaoBaseButtonComponent> = {
188
- title: 'Components/Base Button',
188
+ title: 'Componentes/Base Button',
189
189
  component: CaoBaseButtonComponent,
190
190
  tags: ['autodocs'],
191
191
  args: { buttonClick: fn() },
@@ -327,18 +327,18 @@ function setupStorybook(destination, force) {
327
327
  if (conflicts.length) {
328
328
  process.stderr.write(
329
329
  `Erro: os seguintes arquivos ja existem no destino (use --force para sobrescrever):\n` +
330
- conflicts.map((c) => ` - ${c}`).join('\n') +
331
- '\n'
330
+ conflicts.map((c) => ` - ${c}`).join('\n') +
331
+ '\n'
332
332
  );
333
333
  return 1;
334
334
  }
335
335
 
336
336
  process.stdout.write(
337
337
  `Setup de Storybook gerado em "${root}".\n` +
338
- `Arquivos criados:\n` +
339
- created.map((c) => ` - ${c}`).join('\n') +
340
- '\n' +
341
- `Leia ${path.join(root, 'STORYBOOK-SETUP.md')} para instalar as dependencias e rodar.\n`
338
+ `Arquivos criados:\n` +
339
+ created.map((c) => ` - ${c}`).join('\n') +
340
+ '\n' +
341
+ `Leia ${path.join(root, 'STORYBOOK-SETUP.md')} para instalar as dependencias e rodar.\n`
342
342
  );
343
343
  return 0;
344
344
  }
@@ -429,7 +429,7 @@ function main() {
429
429
  const available = listComponents(templatesDir).join(', ');
430
430
  process.stderr.write(
431
431
  `Erro: componente "${component}" nao encontrado.\n` +
432
- `Componentes disponiveis: ${available}\n`
432
+ `Componentes disponiveis: ${available}\n`
433
433
  );
434
434
  return 1;
435
435
  }
@@ -441,8 +441,8 @@ function main() {
441
441
  if (conflicts.length) {
442
442
  process.stderr.write(
443
443
  `Erro: os seguintes arquivos ja existem no destino (use --force para sobrescrever):\n` +
444
- conflicts.map((c) => ` - ${c}`).join('\n') +
445
- '\n'
444
+ conflicts.map((c) => ` - ${c}`).join('\n') +
445
+ '\n'
446
446
  );
447
447
  return 1;
448
448
  }
@@ -22,7 +22,7 @@ import { ScrollDispatcher, CdkScrollable } from '@angular/cdk/scrolling';
22
22
  import { BehaviorSubject, Subscription, combineLatest, startWith, map, Subject } from 'rxjs';
23
23
  import * as i1$2 from '@angular/material/icon';
24
24
  import { MatIconModule } from '@angular/material/icon';
25
- import { Router, ActivatedRoute } from '@angular/router';
25
+ import { Router, ActivatedRoute, RouterLink } from '@angular/router';
26
26
  import { MatAutocompleteModule } from '@angular/material/autocomplete';
27
27
  import * as i2$3 from '@angular/material/button';
28
28
  import { MatButtonModule } from '@angular/material/button';
@@ -3501,6 +3501,61 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
3501
3501
  args: ["style"]
3502
3502
  }] } });
3503
3503
 
3504
+ class CaoBreadcrumbComponent {
3505
+ /** Itens do breadcrumb. O último item é tratado como página atual. */
3506
+ items = input([], ...(ngDevMode ? [{ debugName: "items" }] : []));
3507
+ /** Item "home" opcional, sempre exibido como primeiro item. */
3508
+ home = input(undefined, ...(ngDevMode ? [{ debugName: "home" }] : []));
3509
+ /** Texto do divisor. Padrão: `'/'`. Ignorado se `separatorIcon` for informado. */
3510
+ separator = input('/', ...(ngDevMode ? [{ debugName: "separator" }] : []));
3511
+ /** Ícone do divisor (nome Lucide ou imagem). Tem prioridade sobre `separator`. */
3512
+ separatorIcon = input('', ...(ngDevMode ? [{ debugName: "separatorIcon" }] : []));
3513
+ isLucideSeparatorIcon = input(true, ...(ngDevMode ? [{ debugName: "isLucideSeparatorIcon" }] : []));
3514
+ separatorIconSize = input(14, ...(ngDevMode ? [{ debugName: "separatorIconSize" }] : []));
3515
+ separatorIconStrokeWidth = input(1.5, ...(ngDevMode ? [{ debugName: "separatorIconStrokeWidth" }] : []));
3516
+ linkColor = input('', ...(ngDevMode ? [{ debugName: "linkColor" }] : []));
3517
+ linkHoverColor = input('', ...(ngDevMode ? [{ debugName: "linkHoverColor" }] : []));
3518
+ currentColor = input('', ...(ngDevMode ? [{ debugName: "currentColor" }] : []));
3519
+ separatorColor = input('', ...(ngDevMode ? [{ debugName: "separatorColor" }] : []));
3520
+ fontSize = input('', ...(ngDevMode ? [{ debugName: "fontSize" }] : []));
3521
+ gap = input('', ...(ngDevMode ? [{ debugName: "gap" }] : []));
3522
+ ariaLabel = input('Breadcrumb', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : []));
3523
+ dataCy = input('', ...(ngDevMode ? [{ debugName: "dataCy" }] : []));
3524
+ /** Emitido ao clicar em qualquer item interativo. */
3525
+ itemClick = output();
3526
+ allItems = computed(() => {
3527
+ const home = this.home();
3528
+ return home ? [home, ...this.items()] : this.items();
3529
+ }, ...(ngDevMode ? [{ debugName: "allItems" }] : []));
3530
+ isInteractive(item, isLast) {
3531
+ return !isLast && !item.disabled && (this.hasLink(item) || !!item.href || !!item.command);
3532
+ }
3533
+ hasLink(item) {
3534
+ return item.link !== undefined && item.link !== null;
3535
+ }
3536
+ onItemClick(item, index, event) {
3537
+ if (item.disabled) {
3538
+ event.preventDefault();
3539
+ return;
3540
+ }
3541
+ const payload = { item, index, originalEvent: event };
3542
+ item.command?.(payload);
3543
+ this.itemClick.emit(payload);
3544
+ }
3545
+ iconPosition(item) {
3546
+ return item.iconPosition ?? 'left';
3547
+ }
3548
+ isLucide(item) {
3549
+ return item.isLucideIcon ?? true;
3550
+ }
3551
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: CaoBreadcrumbComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3552
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: CaoBreadcrumbComponent, isStandalone: true, selector: "cao-breadcrumb", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, home: { classPropertyName: "home", publicName: "home", isSignal: true, isRequired: false, transformFunction: null }, separator: { classPropertyName: "separator", publicName: "separator", isSignal: true, isRequired: false, transformFunction: null }, separatorIcon: { classPropertyName: "separatorIcon", publicName: "separatorIcon", isSignal: true, isRequired: false, transformFunction: null }, isLucideSeparatorIcon: { classPropertyName: "isLucideSeparatorIcon", publicName: "isLucideSeparatorIcon", isSignal: true, isRequired: false, transformFunction: null }, separatorIconSize: { classPropertyName: "separatorIconSize", publicName: "separatorIconSize", isSignal: true, isRequired: false, transformFunction: null }, separatorIconStrokeWidth: { classPropertyName: "separatorIconStrokeWidth", publicName: "separatorIconStrokeWidth", isSignal: true, isRequired: false, transformFunction: null }, linkColor: { classPropertyName: "linkColor", publicName: "linkColor", isSignal: true, isRequired: false, transformFunction: null }, linkHoverColor: { classPropertyName: "linkHoverColor", publicName: "linkHoverColor", isSignal: true, isRequired: false, transformFunction: null }, currentColor: { classPropertyName: "currentColor", publicName: "currentColor", isSignal: true, isRequired: false, transformFunction: null }, separatorColor: { classPropertyName: "separatorColor", publicName: "separatorColor", isSignal: true, isRequired: false, transformFunction: null }, fontSize: { classPropertyName: "fontSize", publicName: "fontSize", isSignal: true, isRequired: false, transformFunction: null }, gap: { classPropertyName: "gap", publicName: "gap", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, dataCy: { classPropertyName: "dataCy", publicName: "dataCy", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemClick: "itemClick" }, ngImport: i0, template: "<ng-template #content let-item let-index=\"index\">\n @if (item.icon && iconPosition(item) === 'left') {\n <ng-container *ngTemplateOutlet=\"icon; context: { $implicit: item }\" />\n }\n @if (item.label) {\n <span class=\"cao-breadcrumb__label\">{{ item.label }}</span>\n }\n @if (item.icon && iconPosition(item) === 'right') {\n <ng-container *ngTemplateOutlet=\"icon; context: { $implicit: item }\" />\n }\n @if (item.badge !== undefined && item.badge !== null && item.badge !== '') {\n <span\n class=\"cao-breadcrumb__badge\"\n [style.color]=\"item.badgeColor || null\"\n [style.background-color]=\"item.badgeBgColor || null\"\n [attr.data-cy]=\"item.dataCy ? item.dataCy + '-badge' : null\">\n {{ item.badge }}\n </span>\n }\n</ng-template>\n\n<ng-template #icon let-item>\n <span class=\"cao-breadcrumb__icon\" aria-hidden=\"true\">\n <cao-base-icon\n [imgSource]=\"item.icon\"\n [isLucideIcon]=\"isLucide(item)\"\n [iconColor]=\"item.iconColor ?? ''\"\n [strokeWidthIcon]=\"item.iconStrokeWidth ?? 1.5\"\n [size]=\"item.iconSize ?? 16\" />\n </span>\n</ng-template>\n\n@if (allItems().length) {\n <nav\n class=\"cao-breadcrumb\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.data-cy]=\"dataCy() || null\"\n [style.--cao-breadcrumb-link-color]=\"linkColor() || null\"\n [style.--cao-breadcrumb-link-hover-color]=\"linkHoverColor() || null\"\n [style.--cao-breadcrumb-current-color]=\"currentColor() || null\"\n [style.--cao-breadcrumb-separator-color]=\"separatorColor() || null\"\n [style.--cao-breadcrumb-font-size]=\"fontSize() || null\"\n [style.--cao-breadcrumb-gap]=\"gap() || null\">\n <ol class=\"cao-breadcrumb__list\">\n @for (item of allItems(); track $index; let i = $index; let last = $last) {\n <li\n class=\"cao-breadcrumb__item\"\n [class.cao-breadcrumb__item--current]=\"last\"\n [class.cao-breadcrumb__item--disabled]=\"item.disabled\"\n [attr.data-cy]=\"item.dataCy || null\">\n @if (isInteractive(item, last)) {\n @if (hasLink(item)) {\n <a\n class=\"cao-breadcrumb__action\"\n [routerLink]=\"item.link\"\n [queryParams]=\"item.queryParams\"\n [target]=\"item.target ?? '_self'\"\n [attr.aria-label]=\"item.ariaLabel || null\"\n (click)=\"onItemClick(item, i, $event)\">\n <ng-container *ngTemplateOutlet=\"content; context: { $implicit: item, index: i }\" />\n </a>\n } @else if (item.href) {\n <a\n class=\"cao-breadcrumb__action\"\n [attr.href]=\"item.href\"\n [attr.target]=\"item.target || null\"\n [attr.rel]=\"item.target === '_blank' ? 'noopener noreferrer' : null\"\n [attr.aria-label]=\"item.ariaLabel || null\"\n (click)=\"onItemClick(item, i, $event)\">\n <ng-container *ngTemplateOutlet=\"content; context: { $implicit: item, index: i }\" />\n </a>\n } @else {\n <button\n type=\"button\"\n class=\"cao-breadcrumb__action\"\n [attr.aria-label]=\"item.ariaLabel || null\"\n (click)=\"onItemClick(item, i, $event)\">\n <ng-container *ngTemplateOutlet=\"content; context: { $implicit: item, index: i }\" />\n </button>\n }\n } @else {\n <span\n class=\"cao-breadcrumb__text\"\n [attr.aria-current]=\"last ? 'page' : null\"\n [attr.aria-disabled]=\"item.disabled ? 'true' : null\"\n [attr.aria-label]=\"item.ariaLabel || null\">\n <ng-container *ngTemplateOutlet=\"content; context: { $implicit: item, index: i }\" />\n </span>\n }\n </li>\n\n @if (!last) {\n <li class=\"cao-breadcrumb__separator\" role=\"presentation\" aria-hidden=\"true\">\n @if (separatorIcon()) {\n <cao-base-icon\n [imgSource]=\"separatorIcon()\"\n [isLucideIcon]=\"isLucideSeparatorIcon()\"\n [strokeWidthIcon]=\"separatorIconStrokeWidth()\"\n [size]=\"separatorIconSize()\" />\n } @else {\n {{ separator() }}\n }\n </li>\n }\n }\n </ol>\n </nav>\n}", styles: [":host{display:block}.cao-breadcrumb{--_link: var(--cao-breadcrumb-link-color, #6b7280);--_link-hover: var(--cao-breadcrumb-link-hover-color, #4f46e5);--_current: var(--cao-breadcrumb-current-color, #111827);--_separator: var(--cao-breadcrumb-separator-color, #9ca3af);--_disabled: var(--cao-breadcrumb-disabled-color, #d1d5db);--_focus: var(--cao-breadcrumb-focus-ring, rgba(79, 70, 229, .35));--_badge-bg: var(--cao-breadcrumb-badge-bg, #eef2ff);--_badge-text: var(--cao-breadcrumb-badge-text, #4338ca);--_gap: var(--cao-breadcrumb-gap, 8px);--_size: var(--cao-breadcrumb-font-size, .875rem)}.cao-breadcrumb__list{display:flex;flex-wrap:wrap;align-items:center;gap:var(--_gap);margin:0;padding:0;list-style:none;font-size:var(--_size);line-height:1.25}.cao-breadcrumb__item,.cao-breadcrumb__separator{display:inline-flex;align-items:center}.cao-breadcrumb__separator{color:var(--_separator);-webkit-user-select:none;user-select:none}.cao-breadcrumb__action,.cao-breadcrumb__text{display:inline-flex;align-items:center;gap:6px;padding:2px 4px;border:0;border-radius:4px;background:none;color:var(--_link);font:inherit;text-decoration:none}.cao-breadcrumb__action{cursor:pointer;transition:color .15s ease}.cao-breadcrumb__action:hover{color:var(--_link-hover);text-decoration:underline;text-underline-offset:3px}.cao-breadcrumb__action:focus-visible{outline:2px solid var(--_focus);outline-offset:1px}.cao-breadcrumb__item--current .cao-breadcrumb__text{color:var(--_current);font-weight:600}.cao-breadcrumb__item--disabled .cao-breadcrumb__text{color:var(--_disabled);cursor:not-allowed}.cao-breadcrumb__icon{display:inline-flex;align-items:center;line-height:0}.cao-breadcrumb__badge{display:inline-flex;align-items:center;justify-content:center;min-width:18px;padding:1px 6px;border-radius:999px;background:var(--_badge-bg);color:var(--_badge-text);font-size:.75em;font-weight:600;line-height:1.4}@media(prefers-reduced-motion:reduce){.cao-breadcrumb__action{transition:none}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: CaoBaseIcon, selector: "cao-base-icon", inputs: ["imgSource", "isLucideIcon", "strokeWidthIcon", "iconColor", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3553
+ }
3554
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: CaoBreadcrumbComponent, decorators: [{
3555
+ type: Component,
3556
+ args: [{ selector: 'cao-breadcrumb', imports: [NgTemplateOutlet, RouterLink, CaoBaseIcon], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-template #content let-item let-index=\"index\">\n @if (item.icon && iconPosition(item) === 'left') {\n <ng-container *ngTemplateOutlet=\"icon; context: { $implicit: item }\" />\n }\n @if (item.label) {\n <span class=\"cao-breadcrumb__label\">{{ item.label }}</span>\n }\n @if (item.icon && iconPosition(item) === 'right') {\n <ng-container *ngTemplateOutlet=\"icon; context: { $implicit: item }\" />\n }\n @if (item.badge !== undefined && item.badge !== null && item.badge !== '') {\n <span\n class=\"cao-breadcrumb__badge\"\n [style.color]=\"item.badgeColor || null\"\n [style.background-color]=\"item.badgeBgColor || null\"\n [attr.data-cy]=\"item.dataCy ? item.dataCy + '-badge' : null\">\n {{ item.badge }}\n </span>\n }\n</ng-template>\n\n<ng-template #icon let-item>\n <span class=\"cao-breadcrumb__icon\" aria-hidden=\"true\">\n <cao-base-icon\n [imgSource]=\"item.icon\"\n [isLucideIcon]=\"isLucide(item)\"\n [iconColor]=\"item.iconColor ?? ''\"\n [strokeWidthIcon]=\"item.iconStrokeWidth ?? 1.5\"\n [size]=\"item.iconSize ?? 16\" />\n </span>\n</ng-template>\n\n@if (allItems().length) {\n <nav\n class=\"cao-breadcrumb\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.data-cy]=\"dataCy() || null\"\n [style.--cao-breadcrumb-link-color]=\"linkColor() || null\"\n [style.--cao-breadcrumb-link-hover-color]=\"linkHoverColor() || null\"\n [style.--cao-breadcrumb-current-color]=\"currentColor() || null\"\n [style.--cao-breadcrumb-separator-color]=\"separatorColor() || null\"\n [style.--cao-breadcrumb-font-size]=\"fontSize() || null\"\n [style.--cao-breadcrumb-gap]=\"gap() || null\">\n <ol class=\"cao-breadcrumb__list\">\n @for (item of allItems(); track $index; let i = $index; let last = $last) {\n <li\n class=\"cao-breadcrumb__item\"\n [class.cao-breadcrumb__item--current]=\"last\"\n [class.cao-breadcrumb__item--disabled]=\"item.disabled\"\n [attr.data-cy]=\"item.dataCy || null\">\n @if (isInteractive(item, last)) {\n @if (hasLink(item)) {\n <a\n class=\"cao-breadcrumb__action\"\n [routerLink]=\"item.link\"\n [queryParams]=\"item.queryParams\"\n [target]=\"item.target ?? '_self'\"\n [attr.aria-label]=\"item.ariaLabel || null\"\n (click)=\"onItemClick(item, i, $event)\">\n <ng-container *ngTemplateOutlet=\"content; context: { $implicit: item, index: i }\" />\n </a>\n } @else if (item.href) {\n <a\n class=\"cao-breadcrumb__action\"\n [attr.href]=\"item.href\"\n [attr.target]=\"item.target || null\"\n [attr.rel]=\"item.target === '_blank' ? 'noopener noreferrer' : null\"\n [attr.aria-label]=\"item.ariaLabel || null\"\n (click)=\"onItemClick(item, i, $event)\">\n <ng-container *ngTemplateOutlet=\"content; context: { $implicit: item, index: i }\" />\n </a>\n } @else {\n <button\n type=\"button\"\n class=\"cao-breadcrumb__action\"\n [attr.aria-label]=\"item.ariaLabel || null\"\n (click)=\"onItemClick(item, i, $event)\">\n <ng-container *ngTemplateOutlet=\"content; context: { $implicit: item, index: i }\" />\n </button>\n }\n } @else {\n <span\n class=\"cao-breadcrumb__text\"\n [attr.aria-current]=\"last ? 'page' : null\"\n [attr.aria-disabled]=\"item.disabled ? 'true' : null\"\n [attr.aria-label]=\"item.ariaLabel || null\">\n <ng-container *ngTemplateOutlet=\"content; context: { $implicit: item, index: i }\" />\n </span>\n }\n </li>\n\n @if (!last) {\n <li class=\"cao-breadcrumb__separator\" role=\"presentation\" aria-hidden=\"true\">\n @if (separatorIcon()) {\n <cao-base-icon\n [imgSource]=\"separatorIcon()\"\n [isLucideIcon]=\"isLucideSeparatorIcon()\"\n [strokeWidthIcon]=\"separatorIconStrokeWidth()\"\n [size]=\"separatorIconSize()\" />\n } @else {\n {{ separator() }}\n }\n </li>\n }\n }\n </ol>\n </nav>\n}", styles: [":host{display:block}.cao-breadcrumb{--_link: var(--cao-breadcrumb-link-color, #6b7280);--_link-hover: var(--cao-breadcrumb-link-hover-color, #4f46e5);--_current: var(--cao-breadcrumb-current-color, #111827);--_separator: var(--cao-breadcrumb-separator-color, #9ca3af);--_disabled: var(--cao-breadcrumb-disabled-color, #d1d5db);--_focus: var(--cao-breadcrumb-focus-ring, rgba(79, 70, 229, .35));--_badge-bg: var(--cao-breadcrumb-badge-bg, #eef2ff);--_badge-text: var(--cao-breadcrumb-badge-text, #4338ca);--_gap: var(--cao-breadcrumb-gap, 8px);--_size: var(--cao-breadcrumb-font-size, .875rem)}.cao-breadcrumb__list{display:flex;flex-wrap:wrap;align-items:center;gap:var(--_gap);margin:0;padding:0;list-style:none;font-size:var(--_size);line-height:1.25}.cao-breadcrumb__item,.cao-breadcrumb__separator{display:inline-flex;align-items:center}.cao-breadcrumb__separator{color:var(--_separator);-webkit-user-select:none;user-select:none}.cao-breadcrumb__action,.cao-breadcrumb__text{display:inline-flex;align-items:center;gap:6px;padding:2px 4px;border:0;border-radius:4px;background:none;color:var(--_link);font:inherit;text-decoration:none}.cao-breadcrumb__action{cursor:pointer;transition:color .15s ease}.cao-breadcrumb__action:hover{color:var(--_link-hover);text-decoration:underline;text-underline-offset:3px}.cao-breadcrumb__action:focus-visible{outline:2px solid var(--_focus);outline-offset:1px}.cao-breadcrumb__item--current .cao-breadcrumb__text{color:var(--_current);font-weight:600}.cao-breadcrumb__item--disabled .cao-breadcrumb__text{color:var(--_disabled);cursor:not-allowed}.cao-breadcrumb__icon{display:inline-flex;align-items:center;line-height:0}.cao-breadcrumb__badge{display:inline-flex;align-items:center;justify-content:center;min-width:18px;padding:1px 6px;border-radius:999px;background:var(--_badge-bg);color:var(--_badge-text);font-size:.75em;font-weight:600;line-height:1.4}@media(prefers-reduced-motion:reduce){.cao-breadcrumb__action{transition:none}}\n"] }]
3557
+ }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], home: [{ type: i0.Input, args: [{ isSignal: true, alias: "home", required: false }] }], separator: [{ type: i0.Input, args: [{ isSignal: true, alias: "separator", required: false }] }], separatorIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "separatorIcon", required: false }] }], isLucideSeparatorIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "isLucideSeparatorIcon", required: false }] }], separatorIconSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "separatorIconSize", required: false }] }], separatorIconStrokeWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "separatorIconStrokeWidth", required: false }] }], linkColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "linkColor", required: false }] }], linkHoverColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "linkHoverColor", required: false }] }], currentColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentColor", required: false }] }], separatorColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "separatorColor", required: false }] }], fontSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "fontSize", required: false }] }], gap: [{ type: i0.Input, args: [{ isSignal: true, alias: "gap", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], dataCy: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataCy", required: false }] }], itemClick: [{ type: i0.Output, args: ["itemClick"] }] } });
3558
+
3504
3559
  class BaseModalService {
3505
3560
  constructor() { }
3506
3561
  toggleModalEvent = new EventEmitter();
@@ -4802,5 +4857,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
4802
4857
  * Generated bundle index. Do not edit.
4803
4858
  */
4804
4859
 
4805
- export { BaseAlert, BaseAlertService, BaseDialog, BaseDialogService, BaseFilterTablePaginatedService, BaseFilterTableService, BaseModal, BaseModalService, BasePaginationService, BaseTable, BaseTablePaginated, BaseTableService, BaseTimeRange, CAO_ACCORDION, CaoAccordionComponent, CaoAccordionItemComponent, CaoAutocompleteComponent, CaoBaseButtonComponent, CaoBaseIcon, CaoBaseInput, CaoBaseToggleComponent, CaoBaseWidgetComponent, CaoCardComponent, CaoCheckboxComponent, CaoDropDownComponent, CaoError, CaoFormField, CaoHint, CaoKpi, CaoRadioButtonComponent, CaoRadioGroupComponent, CaoSkeletonComponent, CaoSlideToggleComponent, CaoTabGroup, CaoTabPanel, CaoWidgetService, DEFAULT_ERROR_STATE_MATCHER, ErrorStateMatcher, Footer, LinksButton, Paginator, ShowOnDirtyErrorStateMatcher, StepComponent, StepperComponent, TablePaginatedService, TimePicker, getPtBrPaginatorIntlBasePaginated, getPtBrPaginatorIntlBaseTable };
4860
+ export { BaseAlert, BaseAlertService, BaseDialog, BaseDialogService, BaseFilterTablePaginatedService, BaseFilterTableService, BaseModal, BaseModalService, BasePaginationService, BaseTable, BaseTablePaginated, BaseTableService, BaseTimeRange, CAO_ACCORDION, CaoAccordionComponent, CaoAccordionItemComponent, CaoAutocompleteComponent, CaoBaseButtonComponent, CaoBaseIcon, CaoBaseInput, CaoBaseToggleComponent, CaoBaseWidgetComponent, CaoBreadcrumbComponent, CaoCardComponent, CaoCheckboxComponent, CaoDropDownComponent, CaoError, CaoFormField, CaoHint, CaoKpi, CaoRadioButtonComponent, CaoRadioGroupComponent, CaoSkeletonComponent, CaoSlideToggleComponent, CaoTabGroup, CaoTabPanel, CaoWidgetService, DEFAULT_ERROR_STATE_MATCHER, ErrorStateMatcher, Footer, LinksButton, Paginator, ShowOnDirtyErrorStateMatcher, StepComponent, StepperComponent, TablePaginatedService, TimePicker, getPtBrPaginatorIntlBasePaginated, getPtBrPaginatorIntlBaseTable };
4806
4861
  //# sourceMappingURL=ngx-opalbytes-components.mjs.map