shirkasoft-ui-components 1.0.26 → 1.1.1

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.
@@ -1,18 +1,18 @@
1
1
  import * as i1 from '@angular/common';
2
2
  import { CommonModule, isPlatformBrowser } from '@angular/common';
3
3
  import * as i0 from '@angular/core';
4
- import { inject, ChangeDetectorRef, input, output, viewChild, signal, computed, DestroyRef, effect, forwardRef, ChangeDetectionStrategy, Component, Injectable, model, ElementRef, HostListener, ApplicationRef, EnvironmentInjector, createComponent, ViewContainerRef, untracked, PLATFORM_ID, Inject } from '@angular/core';
4
+ import { inject, ChangeDetectorRef, input, output, viewChild, signal, computed, DestroyRef, effect, forwardRef, ChangeDetectionStrategy, Component, Injectable, model, ElementRef, HostListener, ApplicationRef, EnvironmentInjector, createComponent, ViewContainerRef, untracked, PLATFORM_ID, Inject, Directive, contentChildren } from '@angular/core';
5
5
  import * as i2 from '@angular/forms';
6
6
  import { ReactiveFormsModule, NG_VALUE_ACCESSOR, FormsModule, FormControl, FormGroup, FormBuilder } from '@angular/forms';
7
7
  import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
8
8
  import * as i1$1 from '@jsverse/transloco';
9
9
  import { TranslocoService, TranslocoModule } from '@jsverse/transloco';
10
- import { LucideEyeOff, LucideEye, LucideSearch, LucideDynamicIcon, LucideX, LucideTriangleAlert, LucideInfo, LucideCircleX, LucideCheck, LucideLoader, LucideTrash2, LucideLoaderCircle, LucideMinimize2, LucideMaximize2, LucideChevronRight, LucideChevronLeft, LucideChevronDown, LucideFile, LucideUpload, LucideList, LucideWarehouse, LucideUserCog, LucideShieldCheck, LucideCalculator, LucidePercent, LucideDollarSign, LucideLineChart, LucideBot, LucideReceipt, LucideUsers, LucideTruck, LucideTag, LucideTags, LucideBox, LucidePackage, LucideLandmark, LucideBuilding, LucideUserPlus, LucideUserRoundX, LucideUserCheck, LucideUser, LucideLogOut, LucideSettings, LucideClock, LucideStar, LucideVideo, LucidePlay, LucideShare2, LucideCopy, LucideCircleCheck, LucideArchive, LucideFileText, LucidePresentation, LucideFileSpreadsheet, LucideRefreshCw, LucideCirclePlus, LucidePlus, LucideDownload, LucideToggleLeft, LucideToggleRight, LucideUserPen, LucideKey, LucidePencil, LucideFunnel, LucideInbox, LucideArrowUpDown, LucideArrowDown, LucideArrowUp, LucideChevronsRight, LucideChevronsLeft, LucideBarChart3, LucideMenu, LucideBuilding2, LucideLayoutDashboard, LucideHome, LucideHouse, LucideBanknote, LucidePanelRight, LucideGlobe, LucideCalendarCheck, LucideCalendar, LucideSliders, LucideWallet, LucideBriefcase, LucideIdCard, LucideCreditCard, LucideChartLine, LucideChartPie, LucidePuzzle, LucideLayers, LucideShield } from '@lucide/angular';
10
+ import { LucideEyeOff, LucideEye, LucideSearch, LucideDynamicIcon, LucideX, LucideTriangleAlert, LucideInfo, LucideCircleX, LucideCheck, LucideLoader, LucideTrash2, LucideLoaderCircle, LucideMinimize2, LucideMaximize2, LucideChevronRight, LucideChevronLeft, LucideChevronDown, LucideFile, LucideUpload, LucideList, LucideWarehouse, LucideUserCog, LucideShieldCheck, LucideCalculator, LucidePercent, LucideDollarSign, LucideLineChart, LucideBot, LucideReceipt, LucideUsers, LucideTruck, LucideTag, LucideTags, LucideBox, LucidePackage, LucideLandmark, LucideBuilding, LucideUserPlus, LucideUserRoundX, LucideUserCheck, LucideUser, LucideLogOut, LucideSettings, LucideClock, LucideStar, LucideVideo, LucidePlay, LucideShare2, LucideCopy, LucideCircleCheck, LucideArchive, LucideFileText, LucidePresentation, LucideFileSpreadsheet, LucideRefreshCw, LucideCirclePlus, LucidePlus, LucideDownload, LucideToggleLeft, LucideToggleRight, LucideUserPen, LucideKey, LucidePencil, LucideFunnel, LucideInbox, LucideArrowUpDown, LucideArrowDown, LucideArrowUp, LucideChevronsRight, LucideChevronsLeft, LucideBarChart3, LucideMenu, LucideBuilding2, LucideLayoutDashboard, LucideHome, LucideHouse, LucideBanknote, LucidePanelRight, LucideGlobe, LucideCalendarCheck, LucideCalendar, LucideSliders, LucideWallet, LucideBriefcase, LucideIdCard, LucideCreditCard, LucideChartLine, LucideChartPie, LucidePuzzle, LucideLayers, LucideShield, LucideUserRound, LucideMapPin, LucideUtensils, LucideShip, LucideBus, LucideMountain, LucideCar, LucideTicket, LucideHotel, LucideCalendarDays, LucideCircleHelp, LucideCircleAlert, LucideStickyNote, LucideCoins, LucideMap, LucideClipboardCheck, LucideScrollText, LucideArrowLeft } from '@lucide/angular';
11
11
  import { Router } from '@angular/router';
12
12
  import { Subject, debounceTime } from 'rxjs';
13
13
  import { Chart, registerables } from 'chart.js';
14
14
 
15
- const icons$6 = {
15
+ const icons$9 = {
16
16
  search: LucideSearch,
17
17
  eye: LucideEye,
18
18
  'eye-off': LucideEyeOff,
@@ -40,7 +40,7 @@ class TextFieldComponent {
40
40
  this.displayValue = input('', ...(ngDevMode ? [{ debugName: "displayValue" }] : /* istanbul ignore next */ []));
41
41
  this.autocomplete = input('new-password', ...(ngDevMode ? [{ debugName: "autocomplete" }] : /* istanbul ignore next */ []));
42
42
  this.searchButtonClick = output();
43
- this.getIcon = (name) => icons$6[name] ?? LucideEye;
43
+ this.getIcon = (name) => icons$9[name] ?? LucideEye;
44
44
  this.inputElement = viewChild('input', ...(ngDevMode ? [{ debugName: "inputElement" }] : /* istanbul ignore next */ []));
45
45
  this.textareaElement = viewChild('textarea', ...(ngDevMode ? [{ debugName: "textareaElement" }] : /* istanbul ignore next */ []));
46
46
  this._value = signal('', ...(ngDevMode ? [{ debugName: "_value" }] : /* istanbul ignore next */ []));
@@ -368,7 +368,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImpo
368
368
  }]
369
369
  }] });
370
370
 
371
- const icons$5 = {
371
+ const icons$8 = {
372
372
  check: LucideCheck,
373
373
  'circle-x': LucideCircleX,
374
374
  info: LucideInfo,
@@ -379,7 +379,7 @@ class NotificationComponent {
379
379
  constructor() {
380
380
  this.position = input('center-top', ...(ngDevMode ? [{ debugName: "position" }] : /* istanbul ignore next */ []));
381
381
  this.notificationService = inject(NotificationService);
382
- this.getIcon = (name) => icons$5[name] ?? LucideInfo;
382
+ this.getIcon = (name) => icons$8[name] ?? LucideInfo;
383
383
  this.iconMap = {
384
384
  success: 'check',
385
385
  error: 'circle-x',
@@ -988,7 +988,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImpo
988
988
  args: ['document:keydown.escape']
989
989
  }] } });
990
990
 
991
- const icons$4 = {
991
+ const icons$7 = {
992
992
  info: LucideInfo,
993
993
  'triangle-alert': LucideTriangleAlert,
994
994
  x: LucideX,
@@ -997,7 +997,7 @@ const icons$4 = {
997
997
  };
998
998
  class ConfirmDialogComponent {
999
999
  constructor() {
1000
- this.getIcon = (name) => icons$4[name] ?? LucideTriangleAlert;
1000
+ this.getIcon = (name) => icons$7[name] ?? LucideTriangleAlert;
1001
1001
  this.title = input('Confirmar acción', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
1002
1002
  this.message = input('¿Está seguro de realizar esta acción?', ...(ngDevMode ? [{ debugName: "message" }] : /* istanbul ignore next */ []));
1003
1003
  this.confirmLabel = input('Confirmar', ...(ngDevMode ? [{ debugName: "confirmLabel" }] : /* istanbul ignore next */ []));
@@ -1133,7 +1133,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImpo
1133
1133
  args: [{ providedIn: 'root' }]
1134
1134
  }], ctorParameters: () => [] });
1135
1135
 
1136
- const icons$3 = {
1136
+ const icons$6 = {
1137
1137
  x: LucideX,
1138
1138
  check: LucideCheck,
1139
1139
  'maximize-2': LucideMaximize2,
@@ -1142,7 +1142,7 @@ const icons$3 = {
1142
1142
  };
1143
1143
  class ModalComponent {
1144
1144
  constructor() {
1145
- this.getIcon = (name) => icons$3[name] ?? LucideX;
1145
+ this.getIcon = (name) => icons$6[name] ?? LucideX;
1146
1146
  this.notificationSrv = inject(NotificationService);
1147
1147
  this.destroyRef = inject(DestroyRef);
1148
1148
  this.modalSrv = inject(ModalService);
@@ -1320,7 +1320,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImpo
1320
1320
  args: [{ selector: 'shk-modal', standalone: true, imports: [CommonModule, LucideDynamicIcon], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (visible()) {\n <div\n class=\"fixed inset-0 bg-black/40 backdrop-blur-sm flex items-center justify-center z-40 p-4 pt-4 overflow-y-auto _shk-scrollbar\"\n (click)=\"closeModal()\"\n >\n <div\n class=\"bg-white dark:[background-color:var(--shk-surface-100)] rounded-xl shadow-2xl overflow-hidden flex flex-col animate-in fade-in zoom-in duration-200\"\n [class.w-[95vw]]=\"isExpanded()\"\n [class.h-[90vh]]=\"isExpanded()\"\n [class.w-full]=\"!isExpanded()\"\n [style.max-width]=\"isExpanded() ? undefined : computedModalWidth()\"\n (click)=\"$event.stopPropagation()\"\n >\n <div class=\"h-1.5 w-full _shk-gradient-emerald shrink-0\"></div>\n\n <div class=\"flex items-center justify-between px-6 pt-4 pb-2 shrink-0\">\n <span class=\"font-semibold text-lg _shk-text-surface-800 dark:[color:var(--shk-surface-800)]\">{{ title() }}</span>\n <div class=\"flex items-center gap-2\">\n @if (showExpandButton()) {\n <button\n type=\"button\"\n (click)=\"toggleExpand()\"\n class=\"p-1.5 rounded-lg hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] _shk-text-surface-500 dark:[color:var(--shk-surface-500)] transition-colors\"\n >\n @if (isExpanded()) {\n <svg [lucideIcon]=\"getIcon('minimize-2')\" class=\"w-4 h-4\"></svg>\n } @else {\n <svg [lucideIcon]=\"getIcon('maximize-2')\" class=\"w-4 h-4\"></svg>\n }\n </button>\n }\n <button\n type=\"button\"\n (click)=\"closeModal()\"\n class=\"p-1.5 rounded-lg hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] _shk-text-surface-500 dark:[color:var(--shk-surface-500)] transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('x')\" class=\"w-4 h-4\"></svg>\n </button>\n </div>\n </div>\n\n <div class=\"overflow-y-auto px-6 py-4 flex-1 max-h-[70vh] _shk-scrollbar\">\n <ng-container #dynamicContent></ng-container>\n </div>\n\n @if (modalButtonsVisible()) {\n <hr class=\"border-t _shk-border dark:[border-color:var(--shk-surface-200)] shrink-0\" />\n <div class=\"flex justify-end gap-3 px-6 py-4 shrink-0\">\n <button\n type=\"button\"\n (click)=\"closeModal()\"\n [disabled]=\"loading()\"\n class=\"px-4 py-2 text-sm font-semibold _shk-text-surface-600 dark:[color:var(--shk-surface-600)] _shk-bg-surface-100 dark:[background-color:var(--shk-surface-200)] hover:[background-color:var(--shk-surface-200)] dark:hover:[background-color:var(--shk-surface-300)] rounded-lg transition-colors flex items-center gap-2 disabled:opacity-50\"\n >\n <svg [lucideIcon]=\"getIcon('x')\" class=\"w-4 h-4\"></svg>\n {{ cancelLabel() }}\n </button>\n <button\n type=\"button\"\n (click)=\"onAccept()\"\n [disabled]=\"loading()\"\n class=\"px-4 py-2 text-sm font-semibold _shk-text-white _shk-bg-emerald hover:[background-color:var(--shk-emerald-700)] rounded-lg shadow-md transition-all flex items-center gap-2 disabled:opacity-50\"\n >\n @if (loading()) {\n <svg [lucideIcon]=\"getIcon('loader-circle')\" class=\"w-4 h-4 animate-spin\"></svg>\n } @else {\n <svg [lucideIcon]=\"getIcon('check')\" class=\"w-4 h-4\"></svg>\n }\n {{ acceptLabel() }}\n </button>\n </div>\n }\n </div>\n </div>\n}\n" }]
1321
1321
  }], ctorParameters: () => [], propDecorators: { container: [{ type: i0.ViewChild, args: ['dynamicContent', { ...{ read: ViewContainerRef }, isSignal: true }] }] } });
1322
1322
 
1323
- const icons$2 = {
1323
+ const icons$5 = {
1324
1324
  'chevron-down': LucideChevronDown,
1325
1325
  'chevron-left': LucideChevronLeft,
1326
1326
  'chevron-right': LucideChevronRight,
@@ -1328,7 +1328,7 @@ const icons$2 = {
1328
1328
  class SelectComponent {
1329
1329
  constructor(elementRef) {
1330
1330
  this.elementRef = elementRef;
1331
- this.getIcon = (name) => icons$2[name] ?? LucideChevronDown;
1331
+ this.getIcon = (name) => icons$5[name] ?? LucideChevronDown;
1332
1332
  this.options = input([], ...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
1333
1333
  this.multiple = input(false, ...(ngDevMode ? [{ debugName: "multiple" }] : /* istanbul ignore next */ []));
1334
1334
  this.validCombinations = input(undefined, ...(ngDevMode ? [{ debugName: "validCombinations" }] : /* istanbul ignore next */ []));
@@ -1955,14 +1955,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImpo
1955
1955
  args: ['document:mousedown', ['$event']]
1956
1956
  }] } });
1957
1957
 
1958
- const icons$1 = {
1958
+ const icons$4 = {
1959
1959
  upload: LucideUpload,
1960
1960
  file: LucideFile,
1961
1961
  x: LucideX,
1962
1962
  };
1963
1963
  class FileUploadComponent {
1964
1964
  constructor() {
1965
- this.getIcon = (name) => icons$1[name] ?? LucideUpload;
1965
+ this.getIcon = (name) => icons$4[name] ?? LucideUpload;
1966
1966
  this.transloco = inject(TranslocoService);
1967
1967
  this.label = input('Cargar archivo', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
1968
1968
  this.accept = input('image/*', ...(ngDevMode ? [{ debugName: "accept" }] : /* istanbul ignore next */ []));
@@ -2149,7 +2149,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImpo
2149
2149
  args: [{ selector: 'shk-file-upload', standalone: true, imports: [CommonModule, LucideDynamicIcon], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"flex flex-col gap-2\">\n @if (label()) {\n <label class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-300)]\">\n {{ label() }}\n </label>\n }\n\n @if (canAddMore()) {\n <div\n class=\"relative border-2 border-dashed _shk-border dark:[border-color:var(--shk-surface-700)] rounded-lg p-4 transition-colors hover:[border-color:var(--shk-primary-400)] dark:hover:[border-color:var(--shk-primary-500)]\"\n [class.border-red-400]=\"errorMessage()\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n >\n <input\n #fileInput\n type=\"file\"\n [accept]=\"accept()\"\n [multiple]=\"multiple()\"\n (change)=\"onFileChange($event)\"\n class=\"hidden\"\n />\n\n <div\n class=\"flex flex-col items-center gap-2 cursor-pointer\"\n (click)=\"fileInput.click()\"\n [class.drag-over]=\"isDragOver()\"\n >\n <svg [lucideIcon]=\"getIcon('upload')\" class=\"w-8 h-8 _shk-icon-subtle dark:[color:var(--shk-surface-600)]\"></svg>\n <span class=\"text-sm _shk-text-surface-700 dark:[color:var(--shk-surface-300)]\">\n {{ fileUploadText() }}\n </span>\n @if (fileRecommendation()) {\n <span class=\"text-xs _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\">\n {{ fileRecommendation() }}\n </span>\n }\n </div>\n </div>\n }\n\n @if (maxReached()) {\n <div class=\"text-xs _shk-text-surface-400 dark:[color:var(--shk-surface-500)] text-center py-2\">\n M\u00E1ximo {{ maxFiles() }} archivos alcanzado\n </div>\n }\n\n @if (selectedFiles().length > 0) {\n <div class=\"flex flex-wrap gap-3\">\n @for (file of selectedFiles(); track file.name + file.size + file.lastModified) {\n <div class=\"relative group\">\n @if (isImageFile(file)) {\n <img\n [src]=\"previewUrl(file)\"\n [alt]=\"file.name\"\n class=\"w-20 h-20 object-cover rounded-lg _shk-border dark:[border-color:var(--shk-surface-700)]\"\n />\n } @else {\n <div class=\"w-20 h-20 rounded-lg _shk-border dark:[border-color:var(--shk-surface-700)] flex flex-col items-center justify-center _shk-bg-surface-50 dark:[background-color:var(--shk-surface-800)] gap-1\">\n <svg [lucideIcon]=\"getIcon('file')\" class=\"w-6 h-6 _shk-text-surface-400\"></svg>\n <span class=\"text-[10px] _shk-text-surface-400 truncate max-w-[70px] px-1 text-center\">{{ file.name }}</span>\n </div>\n }\n <button\n type=\"button\"\n (click)=\"removeFile(file)\"\n class=\"absolute -top-1.5 -right-1.5 w-5 h-5 bg-red-500 text-white rounded-full text-xs flex items-center justify-center opacity-0 group-hover:opacity-100 transition shadow\"\n >\n <svg [lucideIcon]=\"getIcon('x')\" class=\"w-3 h-3\"></svg>\n </button>\n </div>\n }\n </div>\n @if (!multiple()) {\n <button\n type=\"button\"\n (click)=\"changeFiles()\"\n class=\"text-xs _shk-text-primary hover:[color:var(--shk-primary-700)] dark:[color:var(--shk-primary-400)] dark:hover:[color:var(--shk-primary-300)] underline cursor-pointer bg-transparent border-0\"\n >\n {{ changeFilesText() }}\n </button>\n }\n }\n\n @if (errorMessage()) {\n <p class=\"text-xs _shk-text-red-500\">{{ errorMessage() }}</p>\n }\n</div>" }]
2150
2150
  }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], accept: [{ type: i0.Input, args: [{ isSignal: true, alias: "accept", required: false }] }], maxFileSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFileSize", required: false }] }], maxFiles: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFiles", required: false }] }], fileUploadText: [{ type: i0.Input, args: [{ isSignal: true, alias: "fileUploadText", required: false }] }], fileRecommendation: [{ type: i0.Input, args: [{ isSignal: true, alias: "fileRecommendation", required: false }] }], changeFilesText: [{ type: i0.Input, args: [{ isSignal: true, alias: "changeFilesText", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], fileSelected: [{ type: i0.Output, args: ["fileSelected"] }], fileRemoved: [{ type: i0.Output, args: ["fileRemoved"] }], fileError: [{ type: i0.Output, args: ["fileError"] }], fileWarning: [{ type: i0.Output, args: ["fileWarning"] }] } });
2151
2151
 
2152
- const icons = {
2152
+ const icons$3 = {
2153
2153
  'chevrons-left': LucideChevronsLeft,
2154
2154
  'chevrons-right': LucideChevronsRight,
2155
2155
  'chevron-left': LucideChevronLeft,
@@ -2226,15 +2226,15 @@ const icons = {
2226
2226
  warehouse: LucideWarehouse,
2227
2227
  list: LucideList,
2228
2228
  };
2229
- function getIcon$2(name) {
2230
- return icons[name] ?? LucidePlus;
2229
+ function getIcon$5(name) {
2230
+ return icons$3[name] ?? LucidePlus;
2231
2231
  }
2232
2232
  class TableComponent {
2233
2233
  constructor() {
2234
2234
  this.fb = inject(FormBuilder);
2235
2235
  this.cdr = inject(ChangeDetectorRef);
2236
2236
  this.transloco = inject(TranslocoService);
2237
- this.getIcon = getIcon$2;
2237
+ this.getIcon = getIcon$5;
2238
2238
  this.actionsHeaderLabel = toSignal(this.transloco.selectTranslate('common.actions'), { initialValue: 'Acciones' });
2239
2239
  this.data = input([], ...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
2240
2240
  this.columns = input([], ...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
@@ -2689,7 +2689,7 @@ class TableComponent {
2689
2689
  }
2690
2690
  }
2691
2691
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: TableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2692
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: TableComponent, isStandalone: true, selector: "shk-table", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, rowsPerPage: { classPropertyName: "rowsPerPage", publicName: "rowsPerPage", isSignal: true, isRequired: false, transformFunction: null }, rowsPerPageOptions: { classPropertyName: "rowsPerPageOptions", publicName: "rowsPerPageOptions", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, showActionRow: { classPropertyName: "showActionRow", publicName: "showActionRow", isSignal: true, isRequired: false, transformFunction: null }, customTemplates: { classPropertyName: "customTemplates", publicName: "customTemplates", isSignal: true, isRequired: false, transformFunction: null }, headerActions: { classPropertyName: "headerActions", publicName: "headerActions", isSignal: true, isRequired: false, transformFunction: null }, rowActions: { classPropertyName: "rowActions", publicName: "rowActions", isSignal: true, isRequired: false, transformFunction: null }, hasShadow: { classPropertyName: "hasShadow", publicName: "hasShadow", isSignal: true, isRequired: false, transformFunction: null }, defaultSortField: { classPropertyName: "defaultSortField", publicName: "defaultSortField", isSignal: true, isRequired: false, transformFunction: null }, defaultSortOrder: { classPropertyName: "defaultSortOrder", publicName: "defaultSortOrder", isSignal: true, isRequired: false, transformFunction: null }, showSearch: { classPropertyName: "showSearch", publicName: "showSearch", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, serverSide: { classPropertyName: "serverSide", publicName: "serverSide", isSignal: true, isRequired: false, transformFunction: null }, totalRecords: { classPropertyName: "totalRecords", publicName: "totalRecords", isSignal: true, isRequired: false, transformFunction: null }, filters: { classPropertyName: "filters", publicName: "filters", isSignal: true, isRequired: false, transformFunction: null }, activeFilter: { classPropertyName: "activeFilter", publicName: "activeFilter", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { refresh: "refresh", pageChange: "pageChange", filterChange: "filterChange", searchChange: "searchChange", filterClick: "filterClick" }, ngImport: i0, template: "<div class=\"space-y-2 min-[1440px]:space-y-3 mt-2 min-[1440px]:mt-3 animate-fade-in pb-8\">\n\n @if (showSearch() || filters().length > 0 || headerActions().length > 0) {\n <div class=\"card p-2 min-[1440px]:p-2.5 flex flex-row items-center justify-between gap-2\">\n\n <div class=\"flex items-center gap-2 min-[1440px]:gap-3 flex-1 min-w-0\">\n @if (showSearch()) {\n <div class=\"relative w-full md:w-52 min-[1440px]:w-56\">\n <div class=\"absolute inset-y-0 left-0 pl-2.5 flex items-center pointer-events-none\">\n <svg [lucideIcon]=\"getIcon('search')\" class=\"w-3.5 h-3.5 _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\"></svg>\n </div>\n <input\n type=\"text\"\n [value]=\"searchQuery()\"\n (input)=\"onSearchInput($any($event.target).value)\"\n [placeholder]=\"searchPlaceholder() || ('common.search_placeholder' | transloco)\"\n class=\"block w-full pl-8 pr-3 py-1.5 text-xs border _shk-border dark:[border-color:var(--shk-surface-200)] rounded-md leading-5\n _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] placeholder:[color:var(--shk-surface-400)] dark:placeholder:[color:var(--shk-surface-500)]\n _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\n focus:outline-none focus:bg-white dark:focus:[background-color:var(--shk-surface-800)] focus:[border-color:var(--shk-primary-500)] focus:ring-1\n focus:[--tw-ring-color:var(--shk-primary-500)]\"\n />\n </div>\n }\n\n @if (filters().length > 0) {\n <div class=\"flex _shk-bg-surface-100 dark:[background-color:var(--shk-surface-100)] p-0.5 rounded-md ml-auto\">\n @for (f of filters(); track f.value) {\n <button\n type=\"button\"\n (click)=\"onFilterClick(f.value)\"\n class=\"px-2.5 min-[1440px]:px-3 py-1 text-xs font-medium rounded _shk-text-surface-700 dark:[color:var(--shk-surface-700)] transition-all\"\n [class]=\"f.value === activeFilter() ? 'bg-white shadow-sm dark:[background-color:var(--shk-surface-700)]' : ''\"\n >\n {{ f.label }}\n </button>\n }\n </div>\n }\n </div>\n\n @if (headerActions().length > 0) {\n <div class=\"flex items-center gap-1.5 shrink-0\">\n @for (action of headerActions(); track $index) {\n @if (isHeaderActionVisible(action)) {\n <button\n type=\"button\"\n [class]=\"action.class || 'inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md _shk-bg-primary text-white hover:[background-color:var(--shk-primary-700)] transition-colors disabled:opacity-50 disabled:cursor-not-allowed'\"\n [disabled]=\"isHeaderActionDisabled(action)\"\n (click)=\"action.onClick()\"\n >\n @if (action.icon) {\n <svg\n [lucideIcon]=\"getIcon(action.icon)\"\n class=\"w-3.5 h-3.5\"\n ></svg>\n }\n {{ action.label }}\n </button>\n }\n }\n </div>\n }\n\n </div>\n }\n\n <div\n class=\"card p-0 overflow-hidden\"\n [class.shadow-lg]=\"hasShadow()\"\n >\n\n <div class=\"table-scroll-wrapper _shk-scrollbar\">\n <table class=\"w-full\">\n <thead>\n <tr>\n @for (col of columnsWithActions(); track col.field) {\n <th\n (click)=\"col.field !== 'actions' && col.sortable && toggleSort(col.field)\"\n [style.cursor]=\"col.field !== 'actions' && col.sortable ? 'pointer' : 'default'\"\n [style.width]=\"col.width || 'auto'\"\n [style.min-width]=\"col.field === 'actions' ? '130px' : 'auto'\"\n class=\"px-2 min-[1440px]:px-3 py-2 min-[1440px]:py-2.5 text-left text-[10px] min-[1440px]:text-xs font-bold _shk-text-surface-500 dark:[color:var(--shk-surface-400)] uppercase tracking-wider\n _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] border-b _shk-border dark:[border-color:var(--shk-surface-200)]\"\n >\n @if (col.field !== 'actions') {\n <div class=\"flex items-center justify-between gap-2\">\n <span>{{ col.header }}</span>\n <div class=\"flex items-center gap-1\">\n @if (col.sortable) {\n <div class=\"relative group\">\n @if (sortField() === col.field) {\n <svg [lucideIcon]=\"getIcon(sortOrder() === 1 ? 'arrow-up' : 'arrow-down')\"\n class=\"w-3.5 h-3.5 _shk-text-primary\"></svg>\n } @else {\n <svg [lucideIcon]=\"getIcon('arrow-up-down')\"\n class=\"w-3.5 h-3.5 _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\"></svg>\n }\n <span class=\"absolute top-full left-1/2 -translate-x-1/2 mt-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ 'table.tooltips.sort' | transloco }}\n </span>\n </div>\n }\n @if (col.filter) {\n <div class=\"relative group\">\n <button\n type=\"button\"\n (click)=\"$event.stopPropagation(); toggleFilter(col.field)\"\n class=\"_shk-text-surface-400 dark:[color:var(--shk-surface-500)] hover:[color:var(--shk-surface-600)] dark:hover:[color:var(--shk-surface-300)] transition-colors\"\n >\n <svg\n [lucideIcon]=\"getIcon('filter')\"\n class=\"w-3.5 h-3.5\"\n [class._shk-text-primary]=\"columnFiltersForm.get(col.field)?.value\"\n ></svg>\n <span class=\"absolute top-full left-1/2 -translate-x-1/2 mt-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ 'table.tooltips.filter' | transloco }}\n </span>\n </button>\n </div>\n }\n </div>\n </div>\n\n @if (col.filter && showFilterInput()[col.field]) {\n <div\n class=\"mt-2\"\n [formGroup]=\"columnFiltersForm\"\n (click)=\"$event.stopPropagation()\"\n >\n <div class=\"relative\">\n @if (col.filterType !== 'select') {\n <input\n type=\"text\"\n [formControlName]=\"col.field\"\n class=\"w-full px-3 py-1.5 text-sm rounded-md border _shk-border dark:[border-color:var(--shk-surface-200)] bg-white dark:[background-color:var(--shk-surface-100)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\n focus:[border-color:var(--shk-primary-500)] focus:ring-1 focus:[--tw-ring-color:var(--shk-primary-500)]\n placeholder:[color:var(--shk-surface-400)] dark:placeholder:[color:var(--shk-surface-500)]\"\n [placeholder]=\"col.filterPlaceholder || ('common.search_placeholder' | transloco)\"\n />\n }\n @if (col.filterType === 'select') {\n <select\n [formControlName]=\"col.field\"\n class=\"w-full px-2 py-1 text-xs rounded-md border _shk-border dark:[border-color:var(--shk-surface-200)] bg-white dark:[background-color:var(--shk-surface-100)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)] focus:[border-color:var(--shk-primary-500)] focus:ring-1 focus:[--tw-ring-color:var(--shk-primary-500)] appearance-none\"\n >\n <option [ngValue]=\"null\">A/D</option>\n @for (opt of col.filterOptions || []; track opt.value) {\n <option [ngValue]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n }\n @if (columnFiltersForm.get(col.field)?.value && col.filterType !== 'select') {\n <button\n type=\"button\"\n class=\"absolute right-2 top-1/2 -translate-y-1/2 _shk-text-surface-400 dark:[color:var(--shk-surface-500)] hover:[color:var(--shk-surface-600)] dark:hover:[color:var(--shk-surface-300)]\"\n (click)=\"clearFilter(col.field)\"\n >\n <svg [lucideIcon]=\"getIcon('x')\" class=\"w-3.5 h-3.5\"></svg>\n </button>\n }\n </div>\n </div>\n }\n } @else {\n <div class=\"flex items-center justify-center\">\n <span>{{ col.header }}</span>\n </div>\n }\n </th>\n }\n </tr>\n </thead>\n\n @if (loading()) {\n <tbody class=\"border-b _shk-border dark:[border-color:var(--shk-surface-100)]\">\n <tr>\n <td [attr.colspan]=\"columnsWithActions().length\" class=\"text-center py-12\">\n <div class=\"flex items-center justify-center\">\n <svg [lucideIcon]=\"getIcon('loader')\" class=\"w-6 h-6 animate-spin _shk-text-primary\"></svg>\n </div>\n </td>\n </tr>\n </tbody>\n } @else if (effectiveDisplayedData().length === 0) {\n <tbody class=\"border-b _shk-border dark:[border-color:var(--shk-surface-100)]\">\n <tr>\n <td [attr.colspan]=\"columnsWithActions().length\" class=\"text-center py-12\">\n <div class=\"flex flex-col items-center\">\n <div class=\"w-16 h-16 _shk-bg-surface-100 dark:[background-color:var(--shk-surface-100)] rounded-full flex items-center justify-center mb-4\">\n <svg [lucideIcon]=\"getIcon('inbox')\" class=\"w-8 h-8 _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\"></svg>\n </div>\n <p class=\"text-lg font-semibold _shk-text-surface-600 dark:[color:var(--shk-surface-300)]\">\n {{ emptyMessage() || ('common.no_records' | transloco) }}\n </p>\n </div>\n </td>\n </tr>\n </tbody>\n } @else {\n <tbody>\n @for (rowData of effectiveDisplayedData(); track $index) {\n <tr class=\"hover:[background-color:color-mix(in srgb,var(--shk-primary-50)30%,transparent)] dark:hover:[background-color:color-mix(in srgb,var(--shk-primary-900)10%,transparent)] transition-colors duration-200 border-b _shk-border dark:[border-color:var(--shk-surface-100)]\">\n @for (col of columnsWithActions(); track col.field) {\n <td\n class=\"px-2 min-[1440px]:px-3 py-2 min-[1440px]:py-2.5 text-xs font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-700)] whitespace-nowrap\"\n [style.overflow]=\"col.field === 'actions' ? 'visible' : 'hidden'\"\n [style.text-overflow]=\"col.field === 'actions' ? 'clip' : 'ellipsis'\"\n >\n @if (col.field !== 'actions') {\n @if (col.template === 'tag') {\n <span\n class=\"inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium\"\n [class]=\"getTagClass(col.tagSeverity ? col.tagSeverity(rowData) : undefined)\"\n [style]=\"col.tagStyle ? col.tagStyle(rowData) : undefined\"\n >\n {{ col.tagValue ? col.tagValue(rowData) : rowData[col.field] }}\n </span>\n } @else if (col.format) {\n <span>{{ col.format(rowData) }}</span>\n } @else {\n <ng-container\n *ngTemplateOutlet=\"\n customTemplates()[col.field] || defaultTemplate;\n context: { $implicit: rowData, field: col.field }\n \"\n ></ng-container>\n }\n } @else {\n <div class=\"flex items-center justify-start gap-px\">\n @for (action of rowActions(); track $index) {\n @if (isRowActionVisible(action, rowData)) {\n <div class=\"relative group\">\n <button\n type=\"button\"\n (click)=\"action.onClick(rowData)\"\n [class]=\"'table-action-btn hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] rounded-md ' + getRowActionClass(action, rowData)\"\n [disabled]=\"isRowActionDisabled(action, rowData) || false\"\n >\n <svg\n [lucideIcon]=\"getIcon(getRowActionIconName(action, rowData))\"\n class=\"w-4 h-4\"\n ></svg>\n </button>\n <span class=\"absolute bottom-full left-1/2 -translate-x-1/2 mb-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ getRowActionLabel(action, rowData) }}\n </span>\n </div>\n }\n }\n </div>\n }\n </td>\n }\n </tr>\n }\n </tbody>\n }\n </table>\n\n <ng-template #defaultTemplate let-rowData let-field=\"field\">\n {{ truncate(rowData[field], 30) }}\n </ng-template>\n </div>\n\n <div class=\"flex items-center justify-between gap-4 px-2 min-[1440px]:px-3 py-2 border-t _shk-border dark:[border-color:var(--shk-surface-100)]\">\n <div class=\"text-xs _shk-text-surface-600 dark:[color:var(--shk-surface-400)]\">{{ getPageReport() }}</div>\n <div class=\"flex items-center gap-0.5\">\n <button\n type=\"button\"\n (click)=\"goToFirst()\"\n [disabled]=\"isFirstPage()\"\n class=\"p-1 _shk-text-surface-500 hover:[color:var(--shk-surface-700)] dark:[color:var(--shk-surface-400)] dark:hover:[color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed rounded transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('chevrons-left')\" class=\"w-4 h-4\"></svg>\n </button>\n <button\n type=\"button\"\n (click)=\"prev()\"\n [disabled]=\"isFirstPage()\"\n class=\"p-1 _shk-text-surface-500 hover:[color:var(--shk-surface-700)] dark:[color:var(--shk-surface-400)] dark:hover:[color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed rounded transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('chevron-left')\" class=\"w-4 h-4\"></svg>\n </button>\n <span class=\"px-2 text-xs font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\">{{ currentPage() }} / {{ totalPages() }}</span>\n <button\n type=\"button\"\n (click)=\"next()\"\n [disabled]=\"isLastPage()\"\n class=\"p-1 _shk-text-surface-500 hover:[color:var(--shk-surface-700)] dark:[color:var(--shk-surface-400)] dark:hover:[color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed rounded transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('chevron-right')\" class=\"w-4 h-4\"></svg>\n </button>\n <button\n type=\"button\"\n (click)=\"goToLast()\"\n [disabled]=\"isLastPage()\"\n class=\"p-1 _shk-text-surface-500 hover:[color:var(--shk-surface-700)] dark:[color:var(--shk-surface-400)] dark:hover:[color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed rounded transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('chevrons-right')\" class=\"w-4 h-4\"></svg>\n </button>\n </div>\n <div class=\"flex items-center gap-1.5 text-xs _shk-text-surface-600 dark:[color:var(--shk-surface-400)]\">\n <span>{{ 'table.rows' | transloco }}</span>\n <select\n [value]=\"rowsPerPageLocal()\"\n (change)=\"onRowsPerPageChange($any($event.target).value)\"\n class=\"border _shk-border dark:[border-color:var(--shk-surface-200)] rounded px-2 py-1 text-xs bg-white dark:[background-color:var(--shk-surface-100)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)] focus:outline-none focus:[border-color:var(--shk-primary-500)]\"\n >\n @for (opt of rowsPerPageOptions(); track opt) {\n <option [value]=\"opt\">{{ opt }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n\n</div>\n", styles: ["input:focus{outline:none}input[type=text]{font-weight:400!important}table th{white-space:nowrap}table td{white-space:nowrap;text-overflow:ellipsis}td button svg{width:1.125rem!important;height:1.125rem!important}td button:disabled{opacity:.4;cursor:not-allowed}.table-action-btn svg{width:1rem!important;height:1rem!important;min-width:1rem!important;min-height:1rem!important}.table-action-btn{padding:.5rem!important;min-width:2rem!important;min-height:2rem!important;display:inline-flex!important;align-items:center!important;justify-content:center!important}.table-scroll-wrapper{width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-scroll-wrapper table{table-layout:fixed;min-width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: TranslocoModule }, { kind: "component", type: LucideDynamicIcon, selector: "svg[lucideIcon]", inputs: ["lucideIcon"] }, { kind: "pipe", type: i1$1.TranslocoPipe, name: "transloco" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2692
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: TableComponent, isStandalone: true, selector: "shk-table", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, rowsPerPage: { classPropertyName: "rowsPerPage", publicName: "rowsPerPage", isSignal: true, isRequired: false, transformFunction: null }, rowsPerPageOptions: { classPropertyName: "rowsPerPageOptions", publicName: "rowsPerPageOptions", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, showActionRow: { classPropertyName: "showActionRow", publicName: "showActionRow", isSignal: true, isRequired: false, transformFunction: null }, customTemplates: { classPropertyName: "customTemplates", publicName: "customTemplates", isSignal: true, isRequired: false, transformFunction: null }, headerActions: { classPropertyName: "headerActions", publicName: "headerActions", isSignal: true, isRequired: false, transformFunction: null }, rowActions: { classPropertyName: "rowActions", publicName: "rowActions", isSignal: true, isRequired: false, transformFunction: null }, hasShadow: { classPropertyName: "hasShadow", publicName: "hasShadow", isSignal: true, isRequired: false, transformFunction: null }, defaultSortField: { classPropertyName: "defaultSortField", publicName: "defaultSortField", isSignal: true, isRequired: false, transformFunction: null }, defaultSortOrder: { classPropertyName: "defaultSortOrder", publicName: "defaultSortOrder", isSignal: true, isRequired: false, transformFunction: null }, showSearch: { classPropertyName: "showSearch", publicName: "showSearch", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, serverSide: { classPropertyName: "serverSide", publicName: "serverSide", isSignal: true, isRequired: false, transformFunction: null }, totalRecords: { classPropertyName: "totalRecords", publicName: "totalRecords", isSignal: true, isRequired: false, transformFunction: null }, filters: { classPropertyName: "filters", publicName: "filters", isSignal: true, isRequired: false, transformFunction: null }, activeFilter: { classPropertyName: "activeFilter", publicName: "activeFilter", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { refresh: "refresh", pageChange: "pageChange", filterChange: "filterChange", searchChange: "searchChange", filterClick: "filterClick" }, ngImport: i0, template: "<div class=\"space-y-2 min-[1440px]:space-y-3 mt-2 min-[1440px]:mt-3 animate-fade-in pb-8\">\n\n @if (showSearch() || filters().length > 0 || headerActions().length > 0) {\n <div class=\"card p-2 min-[1440px]:p-2.5 flex flex-row items-center justify-between gap-2\">\n\n <div class=\"flex items-center gap-2 min-[1440px]:gap-3 flex-1 min-w-0\">\n @if (showSearch()) {\n <div class=\"relative w-full md:w-52 min-[1440px]:w-56\">\n <div class=\"absolute inset-y-0 left-0 pl-2.5 flex items-center pointer-events-none\">\n <svg [lucideIcon]=\"getIcon('search')\" class=\"w-3.5 h-3.5 _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\"></svg>\n </div>\n <input\n type=\"text\"\n [value]=\"searchQuery()\"\n (input)=\"onSearchInput($any($event.target).value)\"\n [placeholder]=\"searchPlaceholder() || ('common.search_placeholder' | transloco)\"\n class=\"block w-full pl-8 pr-3 py-1.5 text-xs border _shk-border dark:[border-color:var(--shk-surface-200)] rounded-md leading-5\n _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] placeholder:[color:var(--shk-surface-400)] dark:placeholder:[color:var(--shk-surface-500)]\n _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\n focus:outline-none focus:bg-white dark:focus:[background-color:var(--shk-surface-800)] focus:[border-color:var(--shk-primary-500)] focus:ring-1\n focus:[--tw-ring-color:var(--shk-primary-500)]\"\n />\n </div>\n }\n\n @if (filters().length > 0) {\n <div class=\"flex _shk-bg-surface-100 dark:[background-color:var(--shk-surface-100)] p-0.5 rounded-md ml-auto\">\n @for (f of filters(); track f.value) {\n <button\n type=\"button\"\n (click)=\"onFilterClick(f.value)\"\n class=\"px-2.5 min-[1440px]:px-3 py-1 text-xs font-medium rounded _shk-text-surface-700 dark:[color:var(--shk-surface-700)] transition-all\"\n [class]=\"f.value === activeFilter() ? 'bg-white shadow-sm dark:[background-color:var(--shk-surface-700)]' : ''\"\n >\n {{ f.label }}\n </button>\n }\n </div>\n }\n </div>\n\n @if (headerActions().length > 0) {\n <div class=\"flex items-center gap-1.5 shrink-0\">\n @for (action of headerActions(); track $index) {\n @if (isHeaderActionVisible(action)) {\n <button\n type=\"button\"\n [class]=\"action.class || 'inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md _shk-bg-primary text-white hover:[background-color:var(--shk-primary-700)] transition-colors disabled:opacity-50 disabled:cursor-not-allowed'\"\n [disabled]=\"isHeaderActionDisabled(action)\"\n (click)=\"action.onClick()\"\n >\n @if (action.icon) {\n <svg\n [lucideIcon]=\"getIcon(action.icon)\"\n class=\"w-3.5 h-3.5\"\n ></svg>\n }\n {{ action.label }}\n </button>\n }\n }\n </div>\n }\n\n </div>\n }\n\n <div\n class=\"card p-0 overflow-hidden\"\n [class.shadow-lg]=\"hasShadow()\"\n >\n\n <div class=\"table-scroll-wrapper _shk-scrollbar\">\n <table class=\"w-full\">\n <thead>\n <tr>\n @for (col of columnsWithActions(); track col.field) {\n <th\n (click)=\"col.field !== 'actions' && col.sortable && toggleSort(col.field)\"\n [style.cursor]=\"col.field !== 'actions' && col.sortable ? 'pointer' : 'default'\"\n [style.width]=\"col.width || 'auto'\"\n [style.min-width]=\"col.field === 'actions' ? '130px' : 'auto'\"\n class=\"px-2 min-[1440px]:px-3 py-2 min-[1440px]:py-2.5 text-left text-[10px] min-[1440px]:text-xs font-bold _shk-text-surface-500 dark:[color:var(--shk-surface-400)] uppercase tracking-wider\n _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] border-b _shk-border dark:[border-color:var(--shk-surface-200)]\"\n >\n @if (col.field !== 'actions') {\n <div class=\"flex items-center justify-between gap-2\">\n <span>{{ col.header }}</span>\n <div class=\"flex items-center gap-1\">\n @if (col.sortable) {\n <div class=\"relative group\">\n @if (sortField() === col.field) {\n <svg [lucideIcon]=\"getIcon(sortOrder() === 1 ? 'arrow-up' : 'arrow-down')\"\n class=\"w-3.5 h-3.5 _shk-text-primary\"></svg>\n } @else {\n <svg [lucideIcon]=\"getIcon('arrow-up-down')\"\n class=\"w-3.5 h-3.5 _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\"></svg>\n }\n <span class=\"absolute top-full left-1/2 -translate-x-1/2 mt-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ 'table.tooltips.sort' | transloco }}\n </span>\n </div>\n }\n @if (col.filter) {\n <div class=\"relative group\">\n <button\n type=\"button\"\n (click)=\"$event.stopPropagation(); toggleFilter(col.field)\"\n class=\"_shk-text-surface-400 dark:[color:var(--shk-surface-500)] hover:[color:var(--shk-surface-600)] dark:hover:[color:var(--shk-surface-300)] transition-colors\"\n >\n <svg\n [lucideIcon]=\"getIcon('filter')\"\n class=\"w-3.5 h-3.5\"\n [class._shk-text-primary]=\"columnFiltersForm.get(col.field)?.value\"\n ></svg>\n <span class=\"absolute top-full left-1/2 -translate-x-1/2 mt-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ 'table.tooltips.filter' | transloco }}\n </span>\n </button>\n </div>\n }\n </div>\n </div>\n\n @if (col.filter && showFilterInput()[col.field]) {\n <div\n class=\"mt-2\"\n [formGroup]=\"columnFiltersForm\"\n (click)=\"$event.stopPropagation()\"\n >\n <div class=\"relative\">\n @if (col.filterType !== 'select') {\n <input\n type=\"text\"\n [formControlName]=\"col.field\"\n class=\"w-full px-3 py-1.5 text-sm rounded-md border _shk-border dark:[border-color:var(--shk-surface-200)] bg-white dark:[background-color:var(--shk-surface-100)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\n focus:[border-color:var(--shk-primary-500)] focus:ring-1 focus:[--tw-ring-color:var(--shk-primary-500)]\n placeholder:[color:var(--shk-surface-400)] dark:placeholder:[color:var(--shk-surface-500)]\"\n [placeholder]=\"col.filterPlaceholder || ('common.search_placeholder' | transloco)\"\n />\n }\n @if (col.filterType === 'select') {\n <select\n [formControlName]=\"col.field\"\n class=\"w-full px-2 py-1 text-xs rounded-md border _shk-border dark:[border-color:var(--shk-surface-200)] bg-white dark:[background-color:var(--shk-surface-100)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)] focus:[border-color:var(--shk-primary-500)] focus:ring-1 focus:[--tw-ring-color:var(--shk-primary-500)] appearance-none\"\n >\n <option [ngValue]=\"null\">A/D</option>\n @for (opt of col.filterOptions || []; track opt.value) {\n <option [ngValue]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n }\n @if (columnFiltersForm.get(col.field)?.value && col.filterType !== 'select') {\n <button\n type=\"button\"\n class=\"absolute right-2 top-1/2 -translate-y-1/2 _shk-text-surface-400 dark:[color:var(--shk-surface-500)] hover:[color:var(--shk-surface-600)] dark:hover:[color:var(--shk-surface-300)]\"\n (click)=\"clearFilter(col.field)\"\n >\n <svg [lucideIcon]=\"getIcon('x')\" class=\"w-3.5 h-3.5\"></svg>\n </button>\n }\n </div>\n </div>\n }\n } @else {\n <div class=\"flex items-center justify-center\">\n <span>{{ col.header }}</span>\n </div>\n }\n </th>\n }\n </tr>\n </thead>\n\n @if (loading()) {\n <tbody class=\"border-b _shk-border dark:[border-color:var(--shk-surface-100)]\">\n <tr>\n <td [attr.colspan]=\"columnsWithActions().length\" class=\"text-center py-12\">\n <div class=\"flex items-center justify-center\">\n <svg [lucideIcon]=\"getIcon('loader')\" class=\"w-6 h-6 animate-spin _shk-text-primary\"></svg>\n </div>\n </td>\n </tr>\n </tbody>\n } @else if (effectiveDisplayedData().length === 0) {\n <tbody class=\"border-b _shk-border dark:[border-color:var(--shk-surface-100)]\">\n <tr>\n <td [attr.colspan]=\"columnsWithActions().length\" class=\"text-center py-12\">\n <div class=\"flex flex-col items-center\">\n <div class=\"w-16 h-16 _shk-bg-surface-100 dark:[background-color:var(--shk-surface-100)] rounded-full flex items-center justify-center mb-4\">\n <svg [lucideIcon]=\"getIcon('inbox')\" class=\"w-8 h-8 _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\"></svg>\n </div>\n <p class=\"text-lg font-semibold _shk-text-surface-600 dark:[color:var(--shk-surface-300)]\">\n {{ emptyMessage() || ('common.no_records' | transloco) }}\n </p>\n </div>\n </td>\n </tr>\n </tbody>\n } @else {\n <tbody>\n @for (rowData of effectiveDisplayedData(); track $index) {\n <tr class=\"hover:[background-color:color-mix(in srgb,var(--shk-primary-50)30%,transparent)] dark:hover:[background-color:color-mix(in srgb,var(--shk-primary-900)10%,transparent)] transition-colors duration-200 border-b _shk-border dark:[border-color:var(--shk-surface-100)]\">\n @for (col of columnsWithActions(); track col.field) {\n <td\n class=\"px-2 min-[1440px]:px-3 py-2 min-[1440px]:py-2.5 text-xs font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-700)] whitespace-nowrap\"\n [style.overflow]=\"col.field === 'actions' ? 'visible' : 'hidden'\"\n [style.text-overflow]=\"col.field === 'actions' ? 'clip' : 'ellipsis'\"\n >\n @if (col.field !== 'actions') {\n @if (col.template === 'tag') {\n <span\n class=\"inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium\"\n [class]=\"getTagClass(col.tagSeverity ? col.tagSeverity(rowData) : undefined)\"\n [style]=\"col.tagStyle ? col.tagStyle(rowData) : undefined\"\n >\n {{ col.tagValue ? col.tagValue(rowData) : rowData[col.field] }}\n </span>\n } @else if (col.format) {\n <span>{{ col.format(rowData) }}</span>\n } @else {\n <ng-container\n *ngTemplateOutlet=\"\n customTemplates()[col.field] || defaultTemplate;\n context: { $implicit: rowData, field: col.field }\n \"\n ></ng-container>\n }\n } @else {\n <div class=\"flex items-center justify-start gap-px\">\n @for (action of rowActions(); track $index) {\n @if (isRowActionVisible(action, rowData)) {\n <div class=\"relative group\">\n <button\n type=\"button\"\n (click)=\"action.onClick(rowData)\"\n [class]=\"'table-action-btn hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] rounded-md ' + getRowActionClass(action, rowData)\"\n [disabled]=\"isRowActionDisabled(action, rowData) || false\"\n >\n <svg\n [lucideIcon]=\"getIcon(getRowActionIconName(action, rowData))\"\n class=\"w-4 h-4\"\n ></svg>\n </button>\n <span class=\"absolute bottom-full left-1/2 -translate-x-1/2 mb-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ getRowActionLabel(action, rowData) }}\n </span>\n </div>\n }\n }\n </div>\n }\n </td>\n }\n </tr>\n }\n </tbody>\n }\n </table>\n\n <ng-template #defaultTemplate let-rowData let-field=\"field\">\n {{ truncate(rowData[field], 30) }}\n </ng-template>\n </div>\n\n <div class=\"flex items-center justify-between gap-4 px-2 min-[1440px]:px-3 py-2 border-t _shk-border dark:[border-color:var(--shk-surface-100)]\">\n <div class=\"text-xs _shk-text-surface-600 dark:[color:var(--shk-surface-400)]\">{{ getPageReport() }}</div>\n <div class=\"flex items-center gap-0.5\">\n <button\n type=\"button\"\n (click)=\"goToFirst()\"\n [disabled]=\"isFirstPage()\"\n class=\"p-1 _shk-text-surface-500 hover:[color:var(--shk-surface-700)] dark:[color:var(--shk-surface-400)] dark:hover:[color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed rounded transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('chevrons-left')\" class=\"w-4 h-4\"></svg>\n </button>\n <button\n type=\"button\"\n (click)=\"prev()\"\n [disabled]=\"isFirstPage()\"\n class=\"p-1 _shk-text-surface-500 hover:[color:var(--shk-surface-700)] dark:[color:var(--shk-surface-400)] dark:hover:[color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed rounded transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('chevron-left')\" class=\"w-4 h-4\"></svg>\n </button>\n <span class=\"px-2 text-xs font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\">{{ currentPage() }} / {{ totalPages() }}</span>\n <button\n type=\"button\"\n (click)=\"next()\"\n [disabled]=\"isLastPage()\"\n class=\"p-1 _shk-text-surface-500 hover:[color:var(--shk-surface-700)] dark:[color:var(--shk-surface-400)] dark:hover:[color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed rounded transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('chevron-right')\" class=\"w-4 h-4\"></svg>\n </button>\n <button\n type=\"button\"\n (click)=\"goToLast()\"\n [disabled]=\"isLastPage()\"\n class=\"p-1 _shk-text-surface-500 hover:[color:var(--shk-surface-700)] dark:[color:var(--shk-surface-400)] dark:hover:[color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed rounded transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('chevrons-right')\" class=\"w-4 h-4\"></svg>\n </button>\n </div>\n <div class=\"flex items-center gap-1.5 text-xs _shk-text-surface-600 dark:[color:var(--shk-surface-400)]\">\n <span>{{ 'table.rows' | transloco }}</span>\n <select\n [value]=\"rowsPerPageLocal()\"\n (change)=\"onRowsPerPageChange($any($event.target).value)\"\n class=\"border _shk-border dark:[border-color:var(--shk-surface-200)] rounded px-2 py-1 text-xs bg-white dark:[background-color:var(--shk-surface-100)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)] focus:outline-none focus:[border-color:var(--shk-primary-500)]\"\n >\n @for (opt of rowsPerPageOptions(); track opt) {\n <option [value]=\"opt\">{{ opt }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n\n</div>\n", styles: ["input:focus{outline:none}input[type=text]{font-weight:400!important}table th{white-space:nowrap}table td{white-space:nowrap;text-overflow:ellipsis}td button svg{width:1.125rem!important;height:1.125rem!important}td button:disabled{opacity:.4;cursor:not-allowed}.table-action-btn svg{width:1rem!important;height:1rem!important;min-width:1rem!important;min-height:1rem!important}.table-action-btn{padding:.5rem!important;min-width:2rem!important;min-height:2rem!important;display:inline-flex!important;align-items:center!important;justify-content:center!important}.table-scroll-wrapper{width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-scroll-wrapper table{table-layout:fixed;width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: TranslocoModule }, { kind: "component", type: LucideDynamicIcon, selector: "svg[lucideIcon]", inputs: ["lucideIcon"] }, { kind: "pipe", type: i1$1.TranslocoPipe, name: "transloco" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2693
2693
  }
2694
2694
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: TableComponent, decorators: [{
2695
2695
  type: Component,
@@ -2698,7 +2698,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImpo
2698
2698
  ReactiveFormsModule,
2699
2699
  TranslocoModule,
2700
2700
  LucideDynamicIcon,
2701
- ], template: "<div class=\"space-y-2 min-[1440px]:space-y-3 mt-2 min-[1440px]:mt-3 animate-fade-in pb-8\">\n\n @if (showSearch() || filters().length > 0 || headerActions().length > 0) {\n <div class=\"card p-2 min-[1440px]:p-2.5 flex flex-row items-center justify-between gap-2\">\n\n <div class=\"flex items-center gap-2 min-[1440px]:gap-3 flex-1 min-w-0\">\n @if (showSearch()) {\n <div class=\"relative w-full md:w-52 min-[1440px]:w-56\">\n <div class=\"absolute inset-y-0 left-0 pl-2.5 flex items-center pointer-events-none\">\n <svg [lucideIcon]=\"getIcon('search')\" class=\"w-3.5 h-3.5 _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\"></svg>\n </div>\n <input\n type=\"text\"\n [value]=\"searchQuery()\"\n (input)=\"onSearchInput($any($event.target).value)\"\n [placeholder]=\"searchPlaceholder() || ('common.search_placeholder' | transloco)\"\n class=\"block w-full pl-8 pr-3 py-1.5 text-xs border _shk-border dark:[border-color:var(--shk-surface-200)] rounded-md leading-5\n _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] placeholder:[color:var(--shk-surface-400)] dark:placeholder:[color:var(--shk-surface-500)]\n _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\n focus:outline-none focus:bg-white dark:focus:[background-color:var(--shk-surface-800)] focus:[border-color:var(--shk-primary-500)] focus:ring-1\n focus:[--tw-ring-color:var(--shk-primary-500)]\"\n />\n </div>\n }\n\n @if (filters().length > 0) {\n <div class=\"flex _shk-bg-surface-100 dark:[background-color:var(--shk-surface-100)] p-0.5 rounded-md ml-auto\">\n @for (f of filters(); track f.value) {\n <button\n type=\"button\"\n (click)=\"onFilterClick(f.value)\"\n class=\"px-2.5 min-[1440px]:px-3 py-1 text-xs font-medium rounded _shk-text-surface-700 dark:[color:var(--shk-surface-700)] transition-all\"\n [class]=\"f.value === activeFilter() ? 'bg-white shadow-sm dark:[background-color:var(--shk-surface-700)]' : ''\"\n >\n {{ f.label }}\n </button>\n }\n </div>\n }\n </div>\n\n @if (headerActions().length > 0) {\n <div class=\"flex items-center gap-1.5 shrink-0\">\n @for (action of headerActions(); track $index) {\n @if (isHeaderActionVisible(action)) {\n <button\n type=\"button\"\n [class]=\"action.class || 'inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md _shk-bg-primary text-white hover:[background-color:var(--shk-primary-700)] transition-colors disabled:opacity-50 disabled:cursor-not-allowed'\"\n [disabled]=\"isHeaderActionDisabled(action)\"\n (click)=\"action.onClick()\"\n >\n @if (action.icon) {\n <svg\n [lucideIcon]=\"getIcon(action.icon)\"\n class=\"w-3.5 h-3.5\"\n ></svg>\n }\n {{ action.label }}\n </button>\n }\n }\n </div>\n }\n\n </div>\n }\n\n <div\n class=\"card p-0 overflow-hidden\"\n [class.shadow-lg]=\"hasShadow()\"\n >\n\n <div class=\"table-scroll-wrapper _shk-scrollbar\">\n <table class=\"w-full\">\n <thead>\n <tr>\n @for (col of columnsWithActions(); track col.field) {\n <th\n (click)=\"col.field !== 'actions' && col.sortable && toggleSort(col.field)\"\n [style.cursor]=\"col.field !== 'actions' && col.sortable ? 'pointer' : 'default'\"\n [style.width]=\"col.width || 'auto'\"\n [style.min-width]=\"col.field === 'actions' ? '130px' : 'auto'\"\n class=\"px-2 min-[1440px]:px-3 py-2 min-[1440px]:py-2.5 text-left text-[10px] min-[1440px]:text-xs font-bold _shk-text-surface-500 dark:[color:var(--shk-surface-400)] uppercase tracking-wider\n _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] border-b _shk-border dark:[border-color:var(--shk-surface-200)]\"\n >\n @if (col.field !== 'actions') {\n <div class=\"flex items-center justify-between gap-2\">\n <span>{{ col.header }}</span>\n <div class=\"flex items-center gap-1\">\n @if (col.sortable) {\n <div class=\"relative group\">\n @if (sortField() === col.field) {\n <svg [lucideIcon]=\"getIcon(sortOrder() === 1 ? 'arrow-up' : 'arrow-down')\"\n class=\"w-3.5 h-3.5 _shk-text-primary\"></svg>\n } @else {\n <svg [lucideIcon]=\"getIcon('arrow-up-down')\"\n class=\"w-3.5 h-3.5 _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\"></svg>\n }\n <span class=\"absolute top-full left-1/2 -translate-x-1/2 mt-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ 'table.tooltips.sort' | transloco }}\n </span>\n </div>\n }\n @if (col.filter) {\n <div class=\"relative group\">\n <button\n type=\"button\"\n (click)=\"$event.stopPropagation(); toggleFilter(col.field)\"\n class=\"_shk-text-surface-400 dark:[color:var(--shk-surface-500)] hover:[color:var(--shk-surface-600)] dark:hover:[color:var(--shk-surface-300)] transition-colors\"\n >\n <svg\n [lucideIcon]=\"getIcon('filter')\"\n class=\"w-3.5 h-3.5\"\n [class._shk-text-primary]=\"columnFiltersForm.get(col.field)?.value\"\n ></svg>\n <span class=\"absolute top-full left-1/2 -translate-x-1/2 mt-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ 'table.tooltips.filter' | transloco }}\n </span>\n </button>\n </div>\n }\n </div>\n </div>\n\n @if (col.filter && showFilterInput()[col.field]) {\n <div\n class=\"mt-2\"\n [formGroup]=\"columnFiltersForm\"\n (click)=\"$event.stopPropagation()\"\n >\n <div class=\"relative\">\n @if (col.filterType !== 'select') {\n <input\n type=\"text\"\n [formControlName]=\"col.field\"\n class=\"w-full px-3 py-1.5 text-sm rounded-md border _shk-border dark:[border-color:var(--shk-surface-200)] bg-white dark:[background-color:var(--shk-surface-100)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\n focus:[border-color:var(--shk-primary-500)] focus:ring-1 focus:[--tw-ring-color:var(--shk-primary-500)]\n placeholder:[color:var(--shk-surface-400)] dark:placeholder:[color:var(--shk-surface-500)]\"\n [placeholder]=\"col.filterPlaceholder || ('common.search_placeholder' | transloco)\"\n />\n }\n @if (col.filterType === 'select') {\n <select\n [formControlName]=\"col.field\"\n class=\"w-full px-2 py-1 text-xs rounded-md border _shk-border dark:[border-color:var(--shk-surface-200)] bg-white dark:[background-color:var(--shk-surface-100)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)] focus:[border-color:var(--shk-primary-500)] focus:ring-1 focus:[--tw-ring-color:var(--shk-primary-500)] appearance-none\"\n >\n <option [ngValue]=\"null\">A/D</option>\n @for (opt of col.filterOptions || []; track opt.value) {\n <option [ngValue]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n }\n @if (columnFiltersForm.get(col.field)?.value && col.filterType !== 'select') {\n <button\n type=\"button\"\n class=\"absolute right-2 top-1/2 -translate-y-1/2 _shk-text-surface-400 dark:[color:var(--shk-surface-500)] hover:[color:var(--shk-surface-600)] dark:hover:[color:var(--shk-surface-300)]\"\n (click)=\"clearFilter(col.field)\"\n >\n <svg [lucideIcon]=\"getIcon('x')\" class=\"w-3.5 h-3.5\"></svg>\n </button>\n }\n </div>\n </div>\n }\n } @else {\n <div class=\"flex items-center justify-center\">\n <span>{{ col.header }}</span>\n </div>\n }\n </th>\n }\n </tr>\n </thead>\n\n @if (loading()) {\n <tbody class=\"border-b _shk-border dark:[border-color:var(--shk-surface-100)]\">\n <tr>\n <td [attr.colspan]=\"columnsWithActions().length\" class=\"text-center py-12\">\n <div class=\"flex items-center justify-center\">\n <svg [lucideIcon]=\"getIcon('loader')\" class=\"w-6 h-6 animate-spin _shk-text-primary\"></svg>\n </div>\n </td>\n </tr>\n </tbody>\n } @else if (effectiveDisplayedData().length === 0) {\n <tbody class=\"border-b _shk-border dark:[border-color:var(--shk-surface-100)]\">\n <tr>\n <td [attr.colspan]=\"columnsWithActions().length\" class=\"text-center py-12\">\n <div class=\"flex flex-col items-center\">\n <div class=\"w-16 h-16 _shk-bg-surface-100 dark:[background-color:var(--shk-surface-100)] rounded-full flex items-center justify-center mb-4\">\n <svg [lucideIcon]=\"getIcon('inbox')\" class=\"w-8 h-8 _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\"></svg>\n </div>\n <p class=\"text-lg font-semibold _shk-text-surface-600 dark:[color:var(--shk-surface-300)]\">\n {{ emptyMessage() || ('common.no_records' | transloco) }}\n </p>\n </div>\n </td>\n </tr>\n </tbody>\n } @else {\n <tbody>\n @for (rowData of effectiveDisplayedData(); track $index) {\n <tr class=\"hover:[background-color:color-mix(in srgb,var(--shk-primary-50)30%,transparent)] dark:hover:[background-color:color-mix(in srgb,var(--shk-primary-900)10%,transparent)] transition-colors duration-200 border-b _shk-border dark:[border-color:var(--shk-surface-100)]\">\n @for (col of columnsWithActions(); track col.field) {\n <td\n class=\"px-2 min-[1440px]:px-3 py-2 min-[1440px]:py-2.5 text-xs font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-700)] whitespace-nowrap\"\n [style.overflow]=\"col.field === 'actions' ? 'visible' : 'hidden'\"\n [style.text-overflow]=\"col.field === 'actions' ? 'clip' : 'ellipsis'\"\n >\n @if (col.field !== 'actions') {\n @if (col.template === 'tag') {\n <span\n class=\"inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium\"\n [class]=\"getTagClass(col.tagSeverity ? col.tagSeverity(rowData) : undefined)\"\n [style]=\"col.tagStyle ? col.tagStyle(rowData) : undefined\"\n >\n {{ col.tagValue ? col.tagValue(rowData) : rowData[col.field] }}\n </span>\n } @else if (col.format) {\n <span>{{ col.format(rowData) }}</span>\n } @else {\n <ng-container\n *ngTemplateOutlet=\"\n customTemplates()[col.field] || defaultTemplate;\n context: { $implicit: rowData, field: col.field }\n \"\n ></ng-container>\n }\n } @else {\n <div class=\"flex items-center justify-start gap-px\">\n @for (action of rowActions(); track $index) {\n @if (isRowActionVisible(action, rowData)) {\n <div class=\"relative group\">\n <button\n type=\"button\"\n (click)=\"action.onClick(rowData)\"\n [class]=\"'table-action-btn hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] rounded-md ' + getRowActionClass(action, rowData)\"\n [disabled]=\"isRowActionDisabled(action, rowData) || false\"\n >\n <svg\n [lucideIcon]=\"getIcon(getRowActionIconName(action, rowData))\"\n class=\"w-4 h-4\"\n ></svg>\n </button>\n <span class=\"absolute bottom-full left-1/2 -translate-x-1/2 mb-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ getRowActionLabel(action, rowData) }}\n </span>\n </div>\n }\n }\n </div>\n }\n </td>\n }\n </tr>\n }\n </tbody>\n }\n </table>\n\n <ng-template #defaultTemplate let-rowData let-field=\"field\">\n {{ truncate(rowData[field], 30) }}\n </ng-template>\n </div>\n\n <div class=\"flex items-center justify-between gap-4 px-2 min-[1440px]:px-3 py-2 border-t _shk-border dark:[border-color:var(--shk-surface-100)]\">\n <div class=\"text-xs _shk-text-surface-600 dark:[color:var(--shk-surface-400)]\">{{ getPageReport() }}</div>\n <div class=\"flex items-center gap-0.5\">\n <button\n type=\"button\"\n (click)=\"goToFirst()\"\n [disabled]=\"isFirstPage()\"\n class=\"p-1 _shk-text-surface-500 hover:[color:var(--shk-surface-700)] dark:[color:var(--shk-surface-400)] dark:hover:[color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed rounded transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('chevrons-left')\" class=\"w-4 h-4\"></svg>\n </button>\n <button\n type=\"button\"\n (click)=\"prev()\"\n [disabled]=\"isFirstPage()\"\n class=\"p-1 _shk-text-surface-500 hover:[color:var(--shk-surface-700)] dark:[color:var(--shk-surface-400)] dark:hover:[color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed rounded transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('chevron-left')\" class=\"w-4 h-4\"></svg>\n </button>\n <span class=\"px-2 text-xs font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\">{{ currentPage() }} / {{ totalPages() }}</span>\n <button\n type=\"button\"\n (click)=\"next()\"\n [disabled]=\"isLastPage()\"\n class=\"p-1 _shk-text-surface-500 hover:[color:var(--shk-surface-700)] dark:[color:var(--shk-surface-400)] dark:hover:[color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed rounded transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('chevron-right')\" class=\"w-4 h-4\"></svg>\n </button>\n <button\n type=\"button\"\n (click)=\"goToLast()\"\n [disabled]=\"isLastPage()\"\n class=\"p-1 _shk-text-surface-500 hover:[color:var(--shk-surface-700)] dark:[color:var(--shk-surface-400)] dark:hover:[color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed rounded transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('chevrons-right')\" class=\"w-4 h-4\"></svg>\n </button>\n </div>\n <div class=\"flex items-center gap-1.5 text-xs _shk-text-surface-600 dark:[color:var(--shk-surface-400)]\">\n <span>{{ 'table.rows' | transloco }}</span>\n <select\n [value]=\"rowsPerPageLocal()\"\n (change)=\"onRowsPerPageChange($any($event.target).value)\"\n class=\"border _shk-border dark:[border-color:var(--shk-surface-200)] rounded px-2 py-1 text-xs bg-white dark:[background-color:var(--shk-surface-100)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)] focus:outline-none focus:[border-color:var(--shk-primary-500)]\"\n >\n @for (opt of rowsPerPageOptions(); track opt) {\n <option [value]=\"opt\">{{ opt }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n\n</div>\n", styles: ["input:focus{outline:none}input[type=text]{font-weight:400!important}table th{white-space:nowrap}table td{white-space:nowrap;text-overflow:ellipsis}td button svg{width:1.125rem!important;height:1.125rem!important}td button:disabled{opacity:.4;cursor:not-allowed}.table-action-btn svg{width:1rem!important;height:1rem!important;min-width:1rem!important;min-height:1rem!important}.table-action-btn{padding:.5rem!important;min-width:2rem!important;min-height:2rem!important;display:inline-flex!important;align-items:center!important;justify-content:center!important}.table-scroll-wrapper{width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-scroll-wrapper table{table-layout:fixed;min-width:100%}\n"] }]
2701
+ ], template: "<div class=\"space-y-2 min-[1440px]:space-y-3 mt-2 min-[1440px]:mt-3 animate-fade-in pb-8\">\n\n @if (showSearch() || filters().length > 0 || headerActions().length > 0) {\n <div class=\"card p-2 min-[1440px]:p-2.5 flex flex-row items-center justify-between gap-2\">\n\n <div class=\"flex items-center gap-2 min-[1440px]:gap-3 flex-1 min-w-0\">\n @if (showSearch()) {\n <div class=\"relative w-full md:w-52 min-[1440px]:w-56\">\n <div class=\"absolute inset-y-0 left-0 pl-2.5 flex items-center pointer-events-none\">\n <svg [lucideIcon]=\"getIcon('search')\" class=\"w-3.5 h-3.5 _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\"></svg>\n </div>\n <input\n type=\"text\"\n [value]=\"searchQuery()\"\n (input)=\"onSearchInput($any($event.target).value)\"\n [placeholder]=\"searchPlaceholder() || ('common.search_placeholder' | transloco)\"\n class=\"block w-full pl-8 pr-3 py-1.5 text-xs border _shk-border dark:[border-color:var(--shk-surface-200)] rounded-md leading-5\n _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] placeholder:[color:var(--shk-surface-400)] dark:placeholder:[color:var(--shk-surface-500)]\n _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\n focus:outline-none focus:bg-white dark:focus:[background-color:var(--shk-surface-800)] focus:[border-color:var(--shk-primary-500)] focus:ring-1\n focus:[--tw-ring-color:var(--shk-primary-500)]\"\n />\n </div>\n }\n\n @if (filters().length > 0) {\n <div class=\"flex _shk-bg-surface-100 dark:[background-color:var(--shk-surface-100)] p-0.5 rounded-md ml-auto\">\n @for (f of filters(); track f.value) {\n <button\n type=\"button\"\n (click)=\"onFilterClick(f.value)\"\n class=\"px-2.5 min-[1440px]:px-3 py-1 text-xs font-medium rounded _shk-text-surface-700 dark:[color:var(--shk-surface-700)] transition-all\"\n [class]=\"f.value === activeFilter() ? 'bg-white shadow-sm dark:[background-color:var(--shk-surface-700)]' : ''\"\n >\n {{ f.label }}\n </button>\n }\n </div>\n }\n </div>\n\n @if (headerActions().length > 0) {\n <div class=\"flex items-center gap-1.5 shrink-0\">\n @for (action of headerActions(); track $index) {\n @if (isHeaderActionVisible(action)) {\n <button\n type=\"button\"\n [class]=\"action.class || 'inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md _shk-bg-primary text-white hover:[background-color:var(--shk-primary-700)] transition-colors disabled:opacity-50 disabled:cursor-not-allowed'\"\n [disabled]=\"isHeaderActionDisabled(action)\"\n (click)=\"action.onClick()\"\n >\n @if (action.icon) {\n <svg\n [lucideIcon]=\"getIcon(action.icon)\"\n class=\"w-3.5 h-3.5\"\n ></svg>\n }\n {{ action.label }}\n </button>\n }\n }\n </div>\n }\n\n </div>\n }\n\n <div\n class=\"card p-0 overflow-hidden\"\n [class.shadow-lg]=\"hasShadow()\"\n >\n\n <div class=\"table-scroll-wrapper _shk-scrollbar\">\n <table class=\"w-full\">\n <thead>\n <tr>\n @for (col of columnsWithActions(); track col.field) {\n <th\n (click)=\"col.field !== 'actions' && col.sortable && toggleSort(col.field)\"\n [style.cursor]=\"col.field !== 'actions' && col.sortable ? 'pointer' : 'default'\"\n [style.width]=\"col.width || 'auto'\"\n [style.min-width]=\"col.field === 'actions' ? '130px' : 'auto'\"\n class=\"px-2 min-[1440px]:px-3 py-2 min-[1440px]:py-2.5 text-left text-[10px] min-[1440px]:text-xs font-bold _shk-text-surface-500 dark:[color:var(--shk-surface-400)] uppercase tracking-wider\n _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] border-b _shk-border dark:[border-color:var(--shk-surface-200)]\"\n >\n @if (col.field !== 'actions') {\n <div class=\"flex items-center justify-between gap-2\">\n <span>{{ col.header }}</span>\n <div class=\"flex items-center gap-1\">\n @if (col.sortable) {\n <div class=\"relative group\">\n @if (sortField() === col.field) {\n <svg [lucideIcon]=\"getIcon(sortOrder() === 1 ? 'arrow-up' : 'arrow-down')\"\n class=\"w-3.5 h-3.5 _shk-text-primary\"></svg>\n } @else {\n <svg [lucideIcon]=\"getIcon('arrow-up-down')\"\n class=\"w-3.5 h-3.5 _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\"></svg>\n }\n <span class=\"absolute top-full left-1/2 -translate-x-1/2 mt-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ 'table.tooltips.sort' | transloco }}\n </span>\n </div>\n }\n @if (col.filter) {\n <div class=\"relative group\">\n <button\n type=\"button\"\n (click)=\"$event.stopPropagation(); toggleFilter(col.field)\"\n class=\"_shk-text-surface-400 dark:[color:var(--shk-surface-500)] hover:[color:var(--shk-surface-600)] dark:hover:[color:var(--shk-surface-300)] transition-colors\"\n >\n <svg\n [lucideIcon]=\"getIcon('filter')\"\n class=\"w-3.5 h-3.5\"\n [class._shk-text-primary]=\"columnFiltersForm.get(col.field)?.value\"\n ></svg>\n <span class=\"absolute top-full left-1/2 -translate-x-1/2 mt-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ 'table.tooltips.filter' | transloco }}\n </span>\n </button>\n </div>\n }\n </div>\n </div>\n\n @if (col.filter && showFilterInput()[col.field]) {\n <div\n class=\"mt-2\"\n [formGroup]=\"columnFiltersForm\"\n (click)=\"$event.stopPropagation()\"\n >\n <div class=\"relative\">\n @if (col.filterType !== 'select') {\n <input\n type=\"text\"\n [formControlName]=\"col.field\"\n class=\"w-full px-3 py-1.5 text-sm rounded-md border _shk-border dark:[border-color:var(--shk-surface-200)] bg-white dark:[background-color:var(--shk-surface-100)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\n focus:[border-color:var(--shk-primary-500)] focus:ring-1 focus:[--tw-ring-color:var(--shk-primary-500)]\n placeholder:[color:var(--shk-surface-400)] dark:placeholder:[color:var(--shk-surface-500)]\"\n [placeholder]=\"col.filterPlaceholder || ('common.search_placeholder' | transloco)\"\n />\n }\n @if (col.filterType === 'select') {\n <select\n [formControlName]=\"col.field\"\n class=\"w-full px-2 py-1 text-xs rounded-md border _shk-border dark:[border-color:var(--shk-surface-200)] bg-white dark:[background-color:var(--shk-surface-100)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)] focus:[border-color:var(--shk-primary-500)] focus:ring-1 focus:[--tw-ring-color:var(--shk-primary-500)] appearance-none\"\n >\n <option [ngValue]=\"null\">A/D</option>\n @for (opt of col.filterOptions || []; track opt.value) {\n <option [ngValue]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n }\n @if (columnFiltersForm.get(col.field)?.value && col.filterType !== 'select') {\n <button\n type=\"button\"\n class=\"absolute right-2 top-1/2 -translate-y-1/2 _shk-text-surface-400 dark:[color:var(--shk-surface-500)] hover:[color:var(--shk-surface-600)] dark:hover:[color:var(--shk-surface-300)]\"\n (click)=\"clearFilter(col.field)\"\n >\n <svg [lucideIcon]=\"getIcon('x')\" class=\"w-3.5 h-3.5\"></svg>\n </button>\n }\n </div>\n </div>\n }\n } @else {\n <div class=\"flex items-center justify-center\">\n <span>{{ col.header }}</span>\n </div>\n }\n </th>\n }\n </tr>\n </thead>\n\n @if (loading()) {\n <tbody class=\"border-b _shk-border dark:[border-color:var(--shk-surface-100)]\">\n <tr>\n <td [attr.colspan]=\"columnsWithActions().length\" class=\"text-center py-12\">\n <div class=\"flex items-center justify-center\">\n <svg [lucideIcon]=\"getIcon('loader')\" class=\"w-6 h-6 animate-spin _shk-text-primary\"></svg>\n </div>\n </td>\n </tr>\n </tbody>\n } @else if (effectiveDisplayedData().length === 0) {\n <tbody class=\"border-b _shk-border dark:[border-color:var(--shk-surface-100)]\">\n <tr>\n <td [attr.colspan]=\"columnsWithActions().length\" class=\"text-center py-12\">\n <div class=\"flex flex-col items-center\">\n <div class=\"w-16 h-16 _shk-bg-surface-100 dark:[background-color:var(--shk-surface-100)] rounded-full flex items-center justify-center mb-4\">\n <svg [lucideIcon]=\"getIcon('inbox')\" class=\"w-8 h-8 _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\"></svg>\n </div>\n <p class=\"text-lg font-semibold _shk-text-surface-600 dark:[color:var(--shk-surface-300)]\">\n {{ emptyMessage() || ('common.no_records' | transloco) }}\n </p>\n </div>\n </td>\n </tr>\n </tbody>\n } @else {\n <tbody>\n @for (rowData of effectiveDisplayedData(); track $index) {\n <tr class=\"hover:[background-color:color-mix(in srgb,var(--shk-primary-50)30%,transparent)] dark:hover:[background-color:color-mix(in srgb,var(--shk-primary-900)10%,transparent)] transition-colors duration-200 border-b _shk-border dark:[border-color:var(--shk-surface-100)]\">\n @for (col of columnsWithActions(); track col.field) {\n <td\n class=\"px-2 min-[1440px]:px-3 py-2 min-[1440px]:py-2.5 text-xs font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-700)] whitespace-nowrap\"\n [style.overflow]=\"col.field === 'actions' ? 'visible' : 'hidden'\"\n [style.text-overflow]=\"col.field === 'actions' ? 'clip' : 'ellipsis'\"\n >\n @if (col.field !== 'actions') {\n @if (col.template === 'tag') {\n <span\n class=\"inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium\"\n [class]=\"getTagClass(col.tagSeverity ? col.tagSeverity(rowData) : undefined)\"\n [style]=\"col.tagStyle ? col.tagStyle(rowData) : undefined\"\n >\n {{ col.tagValue ? col.tagValue(rowData) : rowData[col.field] }}\n </span>\n } @else if (col.format) {\n <span>{{ col.format(rowData) }}</span>\n } @else {\n <ng-container\n *ngTemplateOutlet=\"\n customTemplates()[col.field] || defaultTemplate;\n context: { $implicit: rowData, field: col.field }\n \"\n ></ng-container>\n }\n } @else {\n <div class=\"flex items-center justify-start gap-px\">\n @for (action of rowActions(); track $index) {\n @if (isRowActionVisible(action, rowData)) {\n <div class=\"relative group\">\n <button\n type=\"button\"\n (click)=\"action.onClick(rowData)\"\n [class]=\"'table-action-btn hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] rounded-md ' + getRowActionClass(action, rowData)\"\n [disabled]=\"isRowActionDisabled(action, rowData) || false\"\n >\n <svg\n [lucideIcon]=\"getIcon(getRowActionIconName(action, rowData))\"\n class=\"w-4 h-4\"\n ></svg>\n </button>\n <span class=\"absolute bottom-full left-1/2 -translate-x-1/2 mb-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ getRowActionLabel(action, rowData) }}\n </span>\n </div>\n }\n }\n </div>\n }\n </td>\n }\n </tr>\n }\n </tbody>\n }\n </table>\n\n <ng-template #defaultTemplate let-rowData let-field=\"field\">\n {{ truncate(rowData[field], 30) }}\n </ng-template>\n </div>\n\n <div class=\"flex items-center justify-between gap-4 px-2 min-[1440px]:px-3 py-2 border-t _shk-border dark:[border-color:var(--shk-surface-100)]\">\n <div class=\"text-xs _shk-text-surface-600 dark:[color:var(--shk-surface-400)]\">{{ getPageReport() }}</div>\n <div class=\"flex items-center gap-0.5\">\n <button\n type=\"button\"\n (click)=\"goToFirst()\"\n [disabled]=\"isFirstPage()\"\n class=\"p-1 _shk-text-surface-500 hover:[color:var(--shk-surface-700)] dark:[color:var(--shk-surface-400)] dark:hover:[color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed rounded transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('chevrons-left')\" class=\"w-4 h-4\"></svg>\n </button>\n <button\n type=\"button\"\n (click)=\"prev()\"\n [disabled]=\"isFirstPage()\"\n class=\"p-1 _shk-text-surface-500 hover:[color:var(--shk-surface-700)] dark:[color:var(--shk-surface-400)] dark:hover:[color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed rounded transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('chevron-left')\" class=\"w-4 h-4\"></svg>\n </button>\n <span class=\"px-2 text-xs font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\">{{ currentPage() }} / {{ totalPages() }}</span>\n <button\n type=\"button\"\n (click)=\"next()\"\n [disabled]=\"isLastPage()\"\n class=\"p-1 _shk-text-surface-500 hover:[color:var(--shk-surface-700)] dark:[color:var(--shk-surface-400)] dark:hover:[color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed rounded transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('chevron-right')\" class=\"w-4 h-4\"></svg>\n </button>\n <button\n type=\"button\"\n (click)=\"goToLast()\"\n [disabled]=\"isLastPage()\"\n class=\"p-1 _shk-text-surface-500 hover:[color:var(--shk-surface-700)] dark:[color:var(--shk-surface-400)] dark:hover:[color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed rounded transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('chevrons-right')\" class=\"w-4 h-4\"></svg>\n </button>\n </div>\n <div class=\"flex items-center gap-1.5 text-xs _shk-text-surface-600 dark:[color:var(--shk-surface-400)]\">\n <span>{{ 'table.rows' | transloco }}</span>\n <select\n [value]=\"rowsPerPageLocal()\"\n (change)=\"onRowsPerPageChange($any($event.target).value)\"\n class=\"border _shk-border dark:[border-color:var(--shk-surface-200)] rounded px-2 py-1 text-xs bg-white dark:[background-color:var(--shk-surface-100)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)] focus:outline-none focus:[border-color:var(--shk-primary-500)]\"\n >\n @for (opt of rowsPerPageOptions(); track opt) {\n <option [value]=\"opt\">{{ opt }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n\n</div>\n", styles: ["input:focus{outline:none}input[type=text]{font-weight:400!important}table th{white-space:nowrap}table td{white-space:nowrap;text-overflow:ellipsis}td button svg{width:1.125rem!important;height:1.125rem!important}td button:disabled{opacity:.4;cursor:not-allowed}.table-action-btn svg{width:1rem!important;height:1rem!important;min-width:1rem!important;min-height:1rem!important}.table-action-btn{padding:.5rem!important;min-width:2rem!important;min-height:2rem!important;display:inline-flex!important;align-items:center!important;justify-content:center!important}.table-scroll-wrapper{width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-scroll-wrapper table{table-layout:fixed;width:100%}\n"] }]
2702
2702
  }], ctorParameters: () => [], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], rowsPerPage: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowsPerPage", required: false }] }], rowsPerPageOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowsPerPageOptions", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], showActionRow: [{ type: i0.Input, args: [{ isSignal: true, alias: "showActionRow", required: false }] }], customTemplates: [{ type: i0.Input, args: [{ isSignal: true, alias: "customTemplates", required: false }] }], headerActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerActions", required: false }] }], rowActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowActions", required: false }] }], hasShadow: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasShadow", required: false }] }], defaultSortField: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultSortField", required: false }] }], defaultSortOrder: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultSortOrder", required: false }] }], showSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSearch", required: false }] }], searchPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchPlaceholder", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], serverSide: [{ type: i0.Input, args: [{ isSignal: true, alias: "serverSide", required: false }] }], totalRecords: [{ type: i0.Input, args: [{ isSignal: true, alias: "totalRecords", required: false }] }], filters: [{ type: i0.Input, args: [{ isSignal: true, alias: "filters", required: false }] }], activeFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeFilter", required: false }] }], refresh: [{ type: i0.Output, args: ["refresh"] }], pageChange: [{ type: i0.Output, args: ["pageChange"] }], filterChange: [{ type: i0.Output, args: ["filterChange"] }], searchChange: [{ type: i0.Output, args: ["searchChange"] }], filterClick: [{ type: i0.Output, args: ["filterClick"] }] } });
2703
2703
 
2704
2704
  class TooltipComponent {
@@ -2850,7 +2850,7 @@ const ICONS$1 = {
2850
2850
  logout: LucideLogOut,
2851
2851
  x: LucideX,
2852
2852
  };
2853
- function getIcon$1(name) {
2853
+ function getIcon$4(name) {
2854
2854
  if (!name)
2855
2855
  return null;
2856
2856
  return ICONS$1[name] ?? LucideMenu;
@@ -2880,7 +2880,7 @@ class SidebarComponent {
2880
2880
  this.mobileOpen = model(false, ...(ngDevMode ? [{ debugName: "mobileOpen" }] : /* istanbul ignore next */ []));
2881
2881
  this.itemClick = output();
2882
2882
  this.toggle = output();
2883
- this.getIcon = getIcon$1;
2883
+ this.getIcon = getIcon$4;
2884
2884
  this.selectedId = signal('', ...(ngDevMode ? [{ debugName: "selectedId" }] : /* istanbul ignore next */ []));
2885
2885
  this.expandedGroups = signal(new Set(), ...(ngDevMode ? [{ debugName: "expandedGroups" }] : /* istanbul ignore next */ []));
2886
2886
  this.isBrowser = isPlatformBrowser(this.platformId);
@@ -2973,11 +2973,11 @@ class SidebarComponent {
2973
2973
  }
2974
2974
  }
2975
2975
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: SidebarComponent, deps: [{ token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Component }); }
2976
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: SidebarComponent, isStandalone: true, selector: "shk-sidebar", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, groups: { classPropertyName: "groups", publicName: "groups", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, subtitle: { classPropertyName: "subtitle", publicName: "subtitle", isSignal: true, isRequired: false, transformFunction: null }, logo: { classPropertyName: "logo", publicName: "logo", isSignal: true, isRequired: false, transformFunction: null }, activeItemId: { classPropertyName: "activeItemId", publicName: "activeItemId", isSignal: true, isRequired: false, transformFunction: null }, userRole: { classPropertyName: "userRole", publicName: "userRole", isSignal: true, isRequired: false, transformFunction: null }, collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null }, showToggle: { classPropertyName: "showToggle", publicName: "showToggle", isSignal: true, isRequired: false, transformFunction: null }, responsive: { classPropertyName: "responsive", publicName: "responsive", isSignal: true, isRequired: false, transformFunction: null }, fixed: { classPropertyName: "fixed", publicName: "fixed", isSignal: true, isRequired: false, transformFunction: null }, hasShadow: { classPropertyName: "hasShadow", publicName: "hasShadow", isSignal: true, isRequired: false, transformFunction: null }, expandedWidth: { classPropertyName: "expandedWidth", publicName: "expandedWidth", isSignal: true, isRequired: false, transformFunction: null }, collapsedWidth: { classPropertyName: "collapsedWidth", publicName: "collapsedWidth", isSignal: true, isRequired: false, transformFunction: null }, defaultExpanded: { classPropertyName: "defaultExpanded", publicName: "defaultExpanded", isSignal: true, isRequired: false, transformFunction: null }, labelPipe: { classPropertyName: "labelPipe", publicName: "labelPipe", isSignal: true, isRequired: false, transformFunction: null }, expandTooltip: { classPropertyName: "expandTooltip", publicName: "expandTooltip", isSignal: true, isRequired: false, transformFunction: null }, collapseTooltip: { classPropertyName: "collapseTooltip", publicName: "collapseTooltip", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, mobileOpen: { classPropertyName: "mobileOpen", publicName: "mobileOpen", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { collapsed: "collapsedChange", mobileOpen: "mobileOpenChange", itemClick: "itemClick", toggle: "toggle" }, host: { listeners: { "window:resize": "onResize($event)" } }, ngImport: i0, template: "<aside\n [class.fixed]=\"fixed()\"\n [class.relative]=\"!fixed()\"\n [class.h-screen]=\"fixed()\"\n [class.h-full]=\"!fixed()\"\n class=\"top-0 left-0 flex flex-col shrink-0 sidebar-transition sidebar-mobile-transform z-40 _shk-bg-white dark:[background-color:var(--shk-surface-50)] border-r _shk-border dark:[border-color:var(--shk-surface-100)]\"\n [class.shadow-sm]=\"hasShadow()\"\n [style.width]=\"width()\"\n [style.transform]=\"responsive() ? (mobileOpen() ? 'translateX(0)' : 'translateX(-100%)') : null\"\n>\n <!-- Mobile overlay backdrop -->\n @if (responsive() && mobileOpen()) {\n <div\n class=\"fixed inset-0 bg-black/50 z-30 lg:hidden\"\n (click)=\"mobileOpen.set(false)\"\n ></div>\n }\n\n <!-- Logo / Brand -->\n @if (logo() || title() || subtitle()) {\n <div\n class=\"flex items-center h-20 px-4 border-b _shk-border dark:[border-color:var(--shk-surface-100)] shrink-0\"\n >\n <div class=\"flex items-center gap-3 overflow-hidden\">\n @if (logo()) {\n <img [src]=\"logo()\" alt=\"Logo\" class=\"h-16 w-16 shrink-0 object-contain\" />\n }\n @if (!collapsed() && (title() || subtitle())) {\n <div class=\"flex flex-col leading-tight whitespace-nowrap\">\n @if (title()) {\n <span class=\"text-lg font-bold _shk-text-surface-800 dark:[color:var(--shk-surface-800)]\">\n {{ title() }}\n </span>\n }\n @if (subtitle()) {\n <span class=\"text-sm _shk-text-surface-500 dark:[color:var(--shk-surface-500)]\">\n {{ subtitle() }}\n </span>\n }\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Toggle button -->\n @if (showToggle() && collapsible()) {\n <button\n type=\"button\"\n (click)=\"onToggle()\"\n class=\"group absolute -right-3 top-20 z-50 w-6 h-6 rounded-full bg-white dark:[background-color:var(--shk-surface-100)] border _shk-border dark:[border-color:var(--shk-surface-200)] shadow-md max-lg:hidden flex items-center justify-center _shk-text-surface-600 dark:[color:var(--shk-surface-600)] hover:[background-color:var(--shk-primary-50)] dark:hover:[background-color:var(--shk-surface-200)] hover:[color:var(--shk-primary-600)] dark:hover:[color:var(--shk-primary-400)] transition-colors\"\n >\n @if (collapsed()) {\n <svg [lucideIcon]=\"getIcon('chevron-right')\" class=\"w-3 h-3\"></svg>\n } @else {\n <svg [lucideIcon]=\"getIcon('chevron-left')\" class=\"w-3 h-3\"></svg>\n }\n <span\n class=\"absolute left-full ml-1 top-1/2 -translate-y-1/2 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\"\n >\n {{ collapsed() ? expandTooltip() : collapseTooltip() }}\n </span>\n </button>\n }\n\n <ng-content select=\"[sidebarHeader]\"></ng-content>\n\n <!-- Custom content between header and nav -->\n <ng-content select=\"[sidebarContent]\"></ng-content>\n\n <!-- Navigation -->\n <nav class=\"flex-1 sidebar-scroll _shk-scrollbar py-4 px-3\">\n <ul class=\"space-y-1\">\n @for (item of navItems(); track item.id) {\n @if (item.separator) {\n <li class=\"my-2 border-t _shk-border dark:[border-color:var(--shk-surface-200)]\"></li>\n }\n\n @if (item.children?.length) {\n <!-- Group -->\n <li>\n @if (collapsed()) {\n <shk-tooltip [text]=\"label(item)\" position=\"right\" mode=\"fixed\">\n <div\n class=\"flex items-center justify-center px-3 py-2.5 rounded-lg transition-all duration-200\"\n [class._shk-bg-primary]=\"isGroupActive(item)\"\n [class._shk-text-white]=\"isGroupActive(item)\"\n [class._shk-text-surface-500]=\"!isGroupActive(item)\"\n >\n @if (item.icon) {\n <svg [lucideIcon]=\"getIcon(item.icon)\" class=\"w-5 h-5 shrink-0\"></svg>\n }\n </div>\n </shk-tooltip>\n } @else {\n <button\n type=\"button\"\n (click)=\"toggleGroup(item)\"\n class=\"w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all duration-200 group relative\"\n [class._shk-bg-primary]=\"isGroupActive(item)\"\n [class._shk-text-white]=\"isGroupActive(item)\"\n [class.shadow-md]=\"isGroupActive(item)\"\n [class._shk-text-surface-700]=\"!isGroupActive(item)\"\n [class.dark:[color:var(--shk-surface-600)]]=\"!isGroupActive(item)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isGroupActive(item)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isGroupActive(item)\"\n [class.hover:[color:var(--shk-surface-900)]]=\"!isGroupActive(item)\"\n [class.dark:hover:[color:var(--shk-surface-700)]]=\"!isGroupActive(item)\"\n >\n @if (item.icon) {\n <svg [lucideIcon]=\"getIcon(item.icon)\" class=\"w-5 h-5 shrink-0\"></svg>\n }\n <span class=\"flex-1 text-left whitespace-nowrap overflow-hidden\">{{ label(item) }}</span>\n <svg\n [lucideIcon]=\"getIcon('chevron-down')\"\n class=\"w-4 h-4 transition-transform duration-200 shrink-0\"\n [class.rotate-180]=\"isGroupExpanded(item)\"\n ></svg>\n </button>\n\n @if (isGroupExpanded(item)) {\n <ul class=\"ml-3 mt-1 space-y-1 border-l-2 _shk-border dark:[border-color:var(--shk-surface-200)] pl-2\">\n @for (child of item.children; track child.id) {\n <li>\n <button\n type=\"button\"\n (click)=\"onItemClick(child)\"\n class=\"w-full flex items-center gap-3 px-3 py-2 rounded-lg text-sm font-medium transition-all duration-200\"\n [class._shk-bg-primary]=\"isItemActive(child)\"\n [class._shk-text-white]=\"isItemActive(child)\"\n [class._shk-text-surface-600]=\"!isItemActive(child)\"\n [class.dark:[color:var(--shk-surface-400)]]=\"!isItemActive(child)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isItemActive(child)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isItemActive(child)\"\n [class.hover:[color:var(--shk-surface-900)]]=\"!isItemActive(child)\"\n [class.dark:hover:[color:var(--shk-surface-700)]]=\"!isItemActive(child)\"\n >\n @if (child.icon) {\n <svg [lucideIcon]=\"getIcon(child.icon)\" class=\"w-4 h-4 shrink-0\"></svg>\n }\n <span class=\"whitespace-nowrap overflow-hidden\">{{ label(child) }}</span>\n @if (isItemActive(child)) {\n <span class=\"w-1.5 h-1.5 rounded-full bg-white shrink-0 ml-auto\"></span>\n }\n </button>\n </li>\n }\n </ul>\n }\n }\n </li>\n } @else {\n <!-- Standalone item -->\n <li>\n @if (collapsed()) {\n <shk-tooltip [text]=\"label(item)\" position=\"right\" mode=\"fixed\">\n <button\n type=\"button\"\n (click)=\"onItemClick(item)\"\n class=\"w-full flex items-center justify-center px-3 py-2.5 rounded-lg text-sm font-medium transition-all duration-200\"\n [class._shk-bg-primary]=\"isItemActive(item)\"\n [class._shk-text-white]=\"isItemActive(item)\"\n [class.shadow-md]=\"isItemActive(item)\"\n [class._shk-text-surface-700]=\"!isItemActive(item)\"\n [class.dark:[color:var(--shk-surface-600)]]=\"!isItemActive(item)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isItemActive(item)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isItemActive(item)\"\n [class.hover:[color:var(--shk-surface-900)]]=\"!isItemActive(item)\"\n [class.dark:hover:[color:var(--shk-surface-700)]]=\"!isItemActive(item)\"\n >\n @if (item.icon) {\n <svg [lucideIcon]=\"getIcon(item.icon)\" class=\"w-5 h-5 shrink-0\"></svg>\n }\n </button>\n </shk-tooltip>\n } @else {\n <button\n type=\"button\"\n (click)=\"onItemClick(item)\"\n class=\"w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all duration-200\"\n [class._shk-bg-primary]=\"isItemActive(item)\"\n [class._shk-text-white]=\"isItemActive(item)\"\n [class.shadow-md]=\"isItemActive(item)\"\n [class._shk-text-surface-700]=\"!isItemActive(item)\"\n [class.dark:[color:var(--shk-surface-600)]]=\"!isItemActive(item)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isItemActive(item)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isItemActive(item)\"\n [class.hover:[color:var(--shk-surface-900)]]=\"!isItemActive(item)\"\n [class.dark:hover:[color:var(--shk-surface-700)]]=\"!isItemActive(item)\"\n >\n @if (item.icon) {\n <svg [lucideIcon]=\"getIcon(item.icon)\" class=\"w-5 h-5 shrink-0\"></svg>\n }\n <span class=\"flex-1 text-left whitespace-nowrap overflow-hidden\">{{ label(item) }}</span>\n @if (item.badge !== undefined) {\n <span\n class=\"text-xs font-bold px-2 py-0.5 rounded-full _shk-bg-primary _shk-text-white shrink-0\"\n [class.hidden]=\"collapsed()\"\n >\n {{ item.badge }}\n </span>\n }\n @if (isItemActive(item)) {\n <span class=\"w-1.5 h-1.5 rounded-full bg-white shrink-0\"></span>\n }\n </button>\n }\n </li>\n }\n }\n </ul>\n </nav>\n\n <!-- Footer -->\n <div class=\"shrink-0 p-2 [&:empty]:hidden\">\n <ng-content select=\"[sidebarFooter]\"></ng-content>\n </div>\n</aside>\n", styles: [":host{display:block}.sidebar-transition{transition:width .3s cubic-bezier(.4,0,.2,1),transform .3s cubic-bezier(.4,0,.2,1)}.sidebar-scroll{overflow-y:auto;overflow-x:visible}@media(min-width:1024px){.sidebar-mobile-transform{transform:none!important}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: LucideDynamicIcon, selector: "svg[lucideIcon]", inputs: ["lucideIcon"] }, { kind: "component", type: TooltipComponent, selector: "shk-tooltip", inputs: ["text", "position", "mode", "offset"] }] }); }
2976
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: SidebarComponent, isStandalone: true, selector: "shk-sidebar", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, groups: { classPropertyName: "groups", publicName: "groups", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, subtitle: { classPropertyName: "subtitle", publicName: "subtitle", isSignal: true, isRequired: false, transformFunction: null }, logo: { classPropertyName: "logo", publicName: "logo", isSignal: true, isRequired: false, transformFunction: null }, activeItemId: { classPropertyName: "activeItemId", publicName: "activeItemId", isSignal: true, isRequired: false, transformFunction: null }, userRole: { classPropertyName: "userRole", publicName: "userRole", isSignal: true, isRequired: false, transformFunction: null }, collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null }, showToggle: { classPropertyName: "showToggle", publicName: "showToggle", isSignal: true, isRequired: false, transformFunction: null }, responsive: { classPropertyName: "responsive", publicName: "responsive", isSignal: true, isRequired: false, transformFunction: null }, fixed: { classPropertyName: "fixed", publicName: "fixed", isSignal: true, isRequired: false, transformFunction: null }, hasShadow: { classPropertyName: "hasShadow", publicName: "hasShadow", isSignal: true, isRequired: false, transformFunction: null }, expandedWidth: { classPropertyName: "expandedWidth", publicName: "expandedWidth", isSignal: true, isRequired: false, transformFunction: null }, collapsedWidth: { classPropertyName: "collapsedWidth", publicName: "collapsedWidth", isSignal: true, isRequired: false, transformFunction: null }, defaultExpanded: { classPropertyName: "defaultExpanded", publicName: "defaultExpanded", isSignal: true, isRequired: false, transformFunction: null }, labelPipe: { classPropertyName: "labelPipe", publicName: "labelPipe", isSignal: true, isRequired: false, transformFunction: null }, expandTooltip: { classPropertyName: "expandTooltip", publicName: "expandTooltip", isSignal: true, isRequired: false, transformFunction: null }, collapseTooltip: { classPropertyName: "collapseTooltip", publicName: "collapseTooltip", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, mobileOpen: { classPropertyName: "mobileOpen", publicName: "mobileOpen", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { collapsed: "collapsedChange", mobileOpen: "mobileOpenChange", itemClick: "itemClick", toggle: "toggle" }, host: { listeners: { "window:resize": "onResize($event)" } }, ngImport: i0, template: "@if (responsive() && mobileOpen()) {\n <!-- Mobile overlay backdrop (sibling of aside: must NOT be inside the\n transformed aside, otherwise it becomes its containing block and\n only covers the sidebar, also blocking nav clicks on mobile) -->\n <div\n class=\"fixed inset-0 bg-black/50 z-30 lg:hidden\"\n (click)=\"mobileOpen.set(false)\"\n ></div>\n}\n\n<aside\n [class.fixed]=\"fixed()\"\n [class.relative]=\"!fixed()\"\n [class.h-screen]=\"fixed()\"\n [class.h-full]=\"!fixed()\"\n class=\"top-0 left-0 flex flex-col shrink-0 sidebar-transition sidebar-mobile-transform z-40 _shk-bg-white dark:[background-color:var(--shk-surface-50)] border-r _shk-border dark:[border-color:var(--shk-surface-100)]\"\n [class.shadow-sm]=\"hasShadow()\"\n [style.width]=\"width()\"\n [style.transform]=\"responsive() ? (mobileOpen() ? 'translateX(0)' : 'translateX(-100%)') : null\"\n>\n <!-- Logo / Brand -->\n @if (logo() || title() || subtitle()) {\n <div\n class=\"flex items-center h-20 px-4 border-b _shk-border dark:[border-color:var(--shk-surface-100)] shrink-0\"\n >\n <div class=\"flex items-center gap-3 overflow-hidden\">\n @if (logo()) {\n <img [src]=\"logo()\" alt=\"Logo\" class=\"h-16 w-16 shrink-0 object-contain\" />\n }\n @if (!collapsed() && (title() || subtitle())) {\n <div class=\"flex flex-col leading-tight whitespace-nowrap\">\n @if (title()) {\n <span class=\"text-lg font-bold _shk-text-surface-800 dark:[color:var(--shk-surface-800)]\">\n {{ title() }}\n </span>\n }\n @if (subtitle()) {\n <span class=\"text-sm _shk-text-surface-500 dark:[color:var(--shk-surface-500)]\">\n {{ subtitle() }}\n </span>\n }\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Toggle button -->\n @if (showToggle() && collapsible()) {\n <button\n type=\"button\"\n (click)=\"onToggle()\"\n class=\"group absolute -right-3 top-20 z-50 w-6 h-6 rounded-full bg-white dark:[background-color:var(--shk-surface-100)] border _shk-border dark:[border-color:var(--shk-surface-200)] shadow-md max-lg:hidden flex items-center justify-center _shk-text-surface-600 dark:[color:var(--shk-surface-600)] hover:[background-color:var(--shk-primary-50)] dark:hover:[background-color:var(--shk-surface-200)] hover:[color:var(--shk-primary-600)] dark:hover:[color:var(--shk-primary-400)] transition-colors\"\n >\n @if (collapsed()) {\n <svg [lucideIcon]=\"getIcon('chevron-right')\" class=\"w-3 h-3\"></svg>\n } @else {\n <svg [lucideIcon]=\"getIcon('chevron-left')\" class=\"w-3 h-3\"></svg>\n }\n <span\n class=\"absolute left-full ml-1 top-1/2 -translate-y-1/2 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\"\n >\n {{ collapsed() ? expandTooltip() : collapseTooltip() }}\n </span>\n </button>\n }\n\n <ng-content select=\"[sidebarHeader]\"></ng-content>\n\n <!-- Custom content between header and nav -->\n <ng-content select=\"[sidebarContent]\"></ng-content>\n\n <!-- Navigation -->\n <nav class=\"flex-1 sidebar-scroll _shk-scrollbar py-4 px-3\">\n <ul class=\"space-y-1\">\n @for (item of navItems(); track item.id) {\n @if (item.separator) {\n <li class=\"my-2 border-t _shk-border dark:[border-color:var(--shk-surface-200)]\"></li>\n }\n\n @if (item.children?.length) {\n <!-- Group -->\n <li>\n @if (collapsed()) {\n <shk-tooltip [text]=\"label(item)\" position=\"right\" mode=\"fixed\">\n <div\n class=\"flex items-center justify-center px-3 py-2.5 rounded-lg transition-all duration-200\"\n [class._shk-bg-primary]=\"isGroupActive(item)\"\n [class._shk-text-white]=\"isGroupActive(item)\"\n [class._shk-text-surface-500]=\"!isGroupActive(item)\"\n >\n @if (item.icon) {\n <svg [lucideIcon]=\"getIcon(item.icon)\" class=\"w-5 h-5 shrink-0\"></svg>\n }\n </div>\n </shk-tooltip>\n } @else {\n <button\n type=\"button\"\n (click)=\"toggleGroup(item)\"\n class=\"w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all duration-200 group relative\"\n [class._shk-bg-primary]=\"isGroupActive(item)\"\n [class._shk-text-white]=\"isGroupActive(item)\"\n [class.shadow-md]=\"isGroupActive(item)\"\n [class._shk-text-surface-700]=\"!isGroupActive(item)\"\n [class.dark:[color:var(--shk-surface-600)]]=\"!isGroupActive(item)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isGroupActive(item)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isGroupActive(item)\"\n [class.hover:[color:var(--shk-surface-900)]]=\"!isGroupActive(item)\"\n [class.dark:hover:[color:var(--shk-surface-700)]]=\"!isGroupActive(item)\"\n >\n @if (item.icon) {\n <svg [lucideIcon]=\"getIcon(item.icon)\" class=\"w-5 h-5 shrink-0\"></svg>\n }\n <span class=\"flex-1 text-left whitespace-nowrap overflow-hidden\">{{ label(item) }}</span>\n <svg\n [lucideIcon]=\"getIcon('chevron-down')\"\n class=\"w-4 h-4 transition-transform duration-200 shrink-0\"\n [class.rotate-180]=\"isGroupExpanded(item)\"\n ></svg>\n </button>\n\n @if (isGroupExpanded(item)) {\n <ul class=\"ml-3 mt-1 space-y-1 border-l-2 _shk-border dark:[border-color:var(--shk-surface-200)] pl-2\">\n @for (child of item.children; track child.id) {\n <li>\n <button\n type=\"button\"\n (click)=\"onItemClick(child)\"\n class=\"w-full flex items-center gap-3 px-3 py-2 rounded-lg text-sm font-medium transition-all duration-200\"\n [class._shk-bg-primary-soft]=\"isItemActive(child)\"\n [class._shk-bg-primary-soft-dark]=\"isItemActive(child)\"\n [class._shk-text-primary-700]=\"isItemActive(child)\"\n [class.dark:[color:var(--shk-primary-300)]]=\"isItemActive(child)\"\n [class._shk-text-surface-600]=\"!isItemActive(child)\"\n [class.dark:[color:var(--shk-surface-400)]]=\"!isItemActive(child)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isItemActive(child)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isItemActive(child)\"\n [class.hover:[color:var(--shk-surface-900)]]=\"!isItemActive(child)\"\n [class.dark:hover:[color:var(--shk-surface-700)]]=\"!isItemActive(child)\"\n >\n @if (child.icon) {\n <svg [lucideIcon]=\"getIcon(child.icon)\" class=\"w-4 h-4 shrink-0\"></svg>\n }\n <span class=\"whitespace-nowrap overflow-hidden\">{{ label(child) }}</span>\n @if (isItemActive(child)) {\n <span class=\"w-1.5 h-1.5 rounded-full _shk-bg-primary shrink-0 ml-auto\"></span>\n }\n </button>\n </li>\n }\n </ul>\n }\n }\n </li>\n } @else {\n <!-- Standalone item -->\n <li>\n @if (collapsed()) {\n <shk-tooltip [text]=\"label(item)\" position=\"right\" mode=\"fixed\">\n <button\n type=\"button\"\n (click)=\"onItemClick(item)\"\n class=\"w-full flex items-center justify-center px-3 py-2.5 rounded-lg text-sm font-medium transition-all duration-200\"\n [class._shk-bg-primary]=\"isItemActive(item)\"\n [class._shk-text-white]=\"isItemActive(item)\"\n [class.shadow-md]=\"isItemActive(item)\"\n [class._shk-text-surface-700]=\"!isItemActive(item)\"\n [class.dark:[color:var(--shk-surface-600)]]=\"!isItemActive(item)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isItemActive(item)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isItemActive(item)\"\n [class.hover:[color:var(--shk-surface-900)]]=\"!isItemActive(item)\"\n [class.dark:hover:[color:var(--shk-surface-700)]]=\"!isItemActive(item)\"\n >\n @if (item.icon) {\n <svg [lucideIcon]=\"getIcon(item.icon)\" class=\"w-5 h-5 shrink-0\"></svg>\n }\n </button>\n </shk-tooltip>\n } @else {\n <button\n type=\"button\"\n (click)=\"onItemClick(item)\"\n class=\"w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all duration-200\"\n [class._shk-bg-primary]=\"isItemActive(item)\"\n [class._shk-text-white]=\"isItemActive(item)\"\n [class.shadow-md]=\"isItemActive(item)\"\n [class._shk-text-surface-700]=\"!isItemActive(item)\"\n [class.dark:[color:var(--shk-surface-600)]]=\"!isItemActive(item)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isItemActive(item)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isItemActive(item)\"\n [class.hover:[color:var(--shk-surface-900)]]=\"!isItemActive(item)\"\n [class.dark:hover:[color:var(--shk-surface-700)]]=\"!isItemActive(item)\"\n >\n @if (item.icon) {\n <svg [lucideIcon]=\"getIcon(item.icon)\" class=\"w-5 h-5 shrink-0\"></svg>\n }\n <span class=\"flex-1 text-left whitespace-nowrap overflow-hidden\">{{ label(item) }}</span>\n @if (item.badge !== undefined) {\n <span\n class=\"text-xs font-bold px-2 py-0.5 rounded-full _shk-bg-primary _shk-text-white shrink-0\"\n [class.hidden]=\"collapsed()\"\n >\n {{ item.badge }}\n </span>\n }\n @if (isItemActive(item)) {\n <span class=\"w-1.5 h-1.5 rounded-full bg-white shrink-0\"></span>\n }\n </button>\n }\n </li>\n }\n }\n </ul>\n </nav>\n\n <!-- Footer -->\n <div class=\"shrink-0 p-2 [&:empty]:hidden\">\n <ng-content select=\"[sidebarFooter]\"></ng-content>\n </div>\n</aside>\n", styles: [":host{display:block}.sidebar-transition{transition:width .3s cubic-bezier(.4,0,.2,1),transform .3s cubic-bezier(.4,0,.2,1)}.sidebar-scroll{overflow-y:auto;overflow-x:visible}@media(min-width:1024px){.sidebar-mobile-transform{transform:none!important}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: LucideDynamicIcon, selector: "svg[lucideIcon]", inputs: ["lucideIcon"] }, { kind: "component", type: TooltipComponent, selector: "shk-tooltip", inputs: ["text", "position", "mode", "offset"] }] }); }
2977
2977
  }
2978
2978
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: SidebarComponent, decorators: [{
2979
2979
  type: Component,
2980
- args: [{ selector: 'shk-sidebar', standalone: true, imports: [CommonModule, LucideDynamicIcon, TooltipComponent], template: "<aside\n [class.fixed]=\"fixed()\"\n [class.relative]=\"!fixed()\"\n [class.h-screen]=\"fixed()\"\n [class.h-full]=\"!fixed()\"\n class=\"top-0 left-0 flex flex-col shrink-0 sidebar-transition sidebar-mobile-transform z-40 _shk-bg-white dark:[background-color:var(--shk-surface-50)] border-r _shk-border dark:[border-color:var(--shk-surface-100)]\"\n [class.shadow-sm]=\"hasShadow()\"\n [style.width]=\"width()\"\n [style.transform]=\"responsive() ? (mobileOpen() ? 'translateX(0)' : 'translateX(-100%)') : null\"\n>\n <!-- Mobile overlay backdrop -->\n @if (responsive() && mobileOpen()) {\n <div\n class=\"fixed inset-0 bg-black/50 z-30 lg:hidden\"\n (click)=\"mobileOpen.set(false)\"\n ></div>\n }\n\n <!-- Logo / Brand -->\n @if (logo() || title() || subtitle()) {\n <div\n class=\"flex items-center h-20 px-4 border-b _shk-border dark:[border-color:var(--shk-surface-100)] shrink-0\"\n >\n <div class=\"flex items-center gap-3 overflow-hidden\">\n @if (logo()) {\n <img [src]=\"logo()\" alt=\"Logo\" class=\"h-16 w-16 shrink-0 object-contain\" />\n }\n @if (!collapsed() && (title() || subtitle())) {\n <div class=\"flex flex-col leading-tight whitespace-nowrap\">\n @if (title()) {\n <span class=\"text-lg font-bold _shk-text-surface-800 dark:[color:var(--shk-surface-800)]\">\n {{ title() }}\n </span>\n }\n @if (subtitle()) {\n <span class=\"text-sm _shk-text-surface-500 dark:[color:var(--shk-surface-500)]\">\n {{ subtitle() }}\n </span>\n }\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Toggle button -->\n @if (showToggle() && collapsible()) {\n <button\n type=\"button\"\n (click)=\"onToggle()\"\n class=\"group absolute -right-3 top-20 z-50 w-6 h-6 rounded-full bg-white dark:[background-color:var(--shk-surface-100)] border _shk-border dark:[border-color:var(--shk-surface-200)] shadow-md max-lg:hidden flex items-center justify-center _shk-text-surface-600 dark:[color:var(--shk-surface-600)] hover:[background-color:var(--shk-primary-50)] dark:hover:[background-color:var(--shk-surface-200)] hover:[color:var(--shk-primary-600)] dark:hover:[color:var(--shk-primary-400)] transition-colors\"\n >\n @if (collapsed()) {\n <svg [lucideIcon]=\"getIcon('chevron-right')\" class=\"w-3 h-3\"></svg>\n } @else {\n <svg [lucideIcon]=\"getIcon('chevron-left')\" class=\"w-3 h-3\"></svg>\n }\n <span\n class=\"absolute left-full ml-1 top-1/2 -translate-y-1/2 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\"\n >\n {{ collapsed() ? expandTooltip() : collapseTooltip() }}\n </span>\n </button>\n }\n\n <ng-content select=\"[sidebarHeader]\"></ng-content>\n\n <!-- Custom content between header and nav -->\n <ng-content select=\"[sidebarContent]\"></ng-content>\n\n <!-- Navigation -->\n <nav class=\"flex-1 sidebar-scroll _shk-scrollbar py-4 px-3\">\n <ul class=\"space-y-1\">\n @for (item of navItems(); track item.id) {\n @if (item.separator) {\n <li class=\"my-2 border-t _shk-border dark:[border-color:var(--shk-surface-200)]\"></li>\n }\n\n @if (item.children?.length) {\n <!-- Group -->\n <li>\n @if (collapsed()) {\n <shk-tooltip [text]=\"label(item)\" position=\"right\" mode=\"fixed\">\n <div\n class=\"flex items-center justify-center px-3 py-2.5 rounded-lg transition-all duration-200\"\n [class._shk-bg-primary]=\"isGroupActive(item)\"\n [class._shk-text-white]=\"isGroupActive(item)\"\n [class._shk-text-surface-500]=\"!isGroupActive(item)\"\n >\n @if (item.icon) {\n <svg [lucideIcon]=\"getIcon(item.icon)\" class=\"w-5 h-5 shrink-0\"></svg>\n }\n </div>\n </shk-tooltip>\n } @else {\n <button\n type=\"button\"\n (click)=\"toggleGroup(item)\"\n class=\"w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all duration-200 group relative\"\n [class._shk-bg-primary]=\"isGroupActive(item)\"\n [class._shk-text-white]=\"isGroupActive(item)\"\n [class.shadow-md]=\"isGroupActive(item)\"\n [class._shk-text-surface-700]=\"!isGroupActive(item)\"\n [class.dark:[color:var(--shk-surface-600)]]=\"!isGroupActive(item)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isGroupActive(item)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isGroupActive(item)\"\n [class.hover:[color:var(--shk-surface-900)]]=\"!isGroupActive(item)\"\n [class.dark:hover:[color:var(--shk-surface-700)]]=\"!isGroupActive(item)\"\n >\n @if (item.icon) {\n <svg [lucideIcon]=\"getIcon(item.icon)\" class=\"w-5 h-5 shrink-0\"></svg>\n }\n <span class=\"flex-1 text-left whitespace-nowrap overflow-hidden\">{{ label(item) }}</span>\n <svg\n [lucideIcon]=\"getIcon('chevron-down')\"\n class=\"w-4 h-4 transition-transform duration-200 shrink-0\"\n [class.rotate-180]=\"isGroupExpanded(item)\"\n ></svg>\n </button>\n\n @if (isGroupExpanded(item)) {\n <ul class=\"ml-3 mt-1 space-y-1 border-l-2 _shk-border dark:[border-color:var(--shk-surface-200)] pl-2\">\n @for (child of item.children; track child.id) {\n <li>\n <button\n type=\"button\"\n (click)=\"onItemClick(child)\"\n class=\"w-full flex items-center gap-3 px-3 py-2 rounded-lg text-sm font-medium transition-all duration-200\"\n [class._shk-bg-primary]=\"isItemActive(child)\"\n [class._shk-text-white]=\"isItemActive(child)\"\n [class._shk-text-surface-600]=\"!isItemActive(child)\"\n [class.dark:[color:var(--shk-surface-400)]]=\"!isItemActive(child)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isItemActive(child)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isItemActive(child)\"\n [class.hover:[color:var(--shk-surface-900)]]=\"!isItemActive(child)\"\n [class.dark:hover:[color:var(--shk-surface-700)]]=\"!isItemActive(child)\"\n >\n @if (child.icon) {\n <svg [lucideIcon]=\"getIcon(child.icon)\" class=\"w-4 h-4 shrink-0\"></svg>\n }\n <span class=\"whitespace-nowrap overflow-hidden\">{{ label(child) }}</span>\n @if (isItemActive(child)) {\n <span class=\"w-1.5 h-1.5 rounded-full bg-white shrink-0 ml-auto\"></span>\n }\n </button>\n </li>\n }\n </ul>\n }\n }\n </li>\n } @else {\n <!-- Standalone item -->\n <li>\n @if (collapsed()) {\n <shk-tooltip [text]=\"label(item)\" position=\"right\" mode=\"fixed\">\n <button\n type=\"button\"\n (click)=\"onItemClick(item)\"\n class=\"w-full flex items-center justify-center px-3 py-2.5 rounded-lg text-sm font-medium transition-all duration-200\"\n [class._shk-bg-primary]=\"isItemActive(item)\"\n [class._shk-text-white]=\"isItemActive(item)\"\n [class.shadow-md]=\"isItemActive(item)\"\n [class._shk-text-surface-700]=\"!isItemActive(item)\"\n [class.dark:[color:var(--shk-surface-600)]]=\"!isItemActive(item)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isItemActive(item)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isItemActive(item)\"\n [class.hover:[color:var(--shk-surface-900)]]=\"!isItemActive(item)\"\n [class.dark:hover:[color:var(--shk-surface-700)]]=\"!isItemActive(item)\"\n >\n @if (item.icon) {\n <svg [lucideIcon]=\"getIcon(item.icon)\" class=\"w-5 h-5 shrink-0\"></svg>\n }\n </button>\n </shk-tooltip>\n } @else {\n <button\n type=\"button\"\n (click)=\"onItemClick(item)\"\n class=\"w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all duration-200\"\n [class._shk-bg-primary]=\"isItemActive(item)\"\n [class._shk-text-white]=\"isItemActive(item)\"\n [class.shadow-md]=\"isItemActive(item)\"\n [class._shk-text-surface-700]=\"!isItemActive(item)\"\n [class.dark:[color:var(--shk-surface-600)]]=\"!isItemActive(item)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isItemActive(item)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isItemActive(item)\"\n [class.hover:[color:var(--shk-surface-900)]]=\"!isItemActive(item)\"\n [class.dark:hover:[color:var(--shk-surface-700)]]=\"!isItemActive(item)\"\n >\n @if (item.icon) {\n <svg [lucideIcon]=\"getIcon(item.icon)\" class=\"w-5 h-5 shrink-0\"></svg>\n }\n <span class=\"flex-1 text-left whitespace-nowrap overflow-hidden\">{{ label(item) }}</span>\n @if (item.badge !== undefined) {\n <span\n class=\"text-xs font-bold px-2 py-0.5 rounded-full _shk-bg-primary _shk-text-white shrink-0\"\n [class.hidden]=\"collapsed()\"\n >\n {{ item.badge }}\n </span>\n }\n @if (isItemActive(item)) {\n <span class=\"w-1.5 h-1.5 rounded-full bg-white shrink-0\"></span>\n }\n </button>\n }\n </li>\n }\n }\n </ul>\n </nav>\n\n <!-- Footer -->\n <div class=\"shrink-0 p-2 [&:empty]:hidden\">\n <ng-content select=\"[sidebarFooter]\"></ng-content>\n </div>\n</aside>\n", styles: [":host{display:block}.sidebar-transition{transition:width .3s cubic-bezier(.4,0,.2,1),transform .3s cubic-bezier(.4,0,.2,1)}.sidebar-scroll{overflow-y:auto;overflow-x:visible}@media(min-width:1024px){.sidebar-mobile-transform{transform:none!important}}\n"] }]
2980
+ args: [{ selector: 'shk-sidebar', standalone: true, imports: [CommonModule, LucideDynamicIcon, TooltipComponent], template: "@if (responsive() && mobileOpen()) {\n <!-- Mobile overlay backdrop (sibling of aside: must NOT be inside the\n transformed aside, otherwise it becomes its containing block and\n only covers the sidebar, also blocking nav clicks on mobile) -->\n <div\n class=\"fixed inset-0 bg-black/50 z-30 lg:hidden\"\n (click)=\"mobileOpen.set(false)\"\n ></div>\n}\n\n<aside\n [class.fixed]=\"fixed()\"\n [class.relative]=\"!fixed()\"\n [class.h-screen]=\"fixed()\"\n [class.h-full]=\"!fixed()\"\n class=\"top-0 left-0 flex flex-col shrink-0 sidebar-transition sidebar-mobile-transform z-40 _shk-bg-white dark:[background-color:var(--shk-surface-50)] border-r _shk-border dark:[border-color:var(--shk-surface-100)]\"\n [class.shadow-sm]=\"hasShadow()\"\n [style.width]=\"width()\"\n [style.transform]=\"responsive() ? (mobileOpen() ? 'translateX(0)' : 'translateX(-100%)') : null\"\n>\n <!-- Logo / Brand -->\n @if (logo() || title() || subtitle()) {\n <div\n class=\"flex items-center h-20 px-4 border-b _shk-border dark:[border-color:var(--shk-surface-100)] shrink-0\"\n >\n <div class=\"flex items-center gap-3 overflow-hidden\">\n @if (logo()) {\n <img [src]=\"logo()\" alt=\"Logo\" class=\"h-16 w-16 shrink-0 object-contain\" />\n }\n @if (!collapsed() && (title() || subtitle())) {\n <div class=\"flex flex-col leading-tight whitespace-nowrap\">\n @if (title()) {\n <span class=\"text-lg font-bold _shk-text-surface-800 dark:[color:var(--shk-surface-800)]\">\n {{ title() }}\n </span>\n }\n @if (subtitle()) {\n <span class=\"text-sm _shk-text-surface-500 dark:[color:var(--shk-surface-500)]\">\n {{ subtitle() }}\n </span>\n }\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Toggle button -->\n @if (showToggle() && collapsible()) {\n <button\n type=\"button\"\n (click)=\"onToggle()\"\n class=\"group absolute -right-3 top-20 z-50 w-6 h-6 rounded-full bg-white dark:[background-color:var(--shk-surface-100)] border _shk-border dark:[border-color:var(--shk-surface-200)] shadow-md max-lg:hidden flex items-center justify-center _shk-text-surface-600 dark:[color:var(--shk-surface-600)] hover:[background-color:var(--shk-primary-50)] dark:hover:[background-color:var(--shk-surface-200)] hover:[color:var(--shk-primary-600)] dark:hover:[color:var(--shk-primary-400)] transition-colors\"\n >\n @if (collapsed()) {\n <svg [lucideIcon]=\"getIcon('chevron-right')\" class=\"w-3 h-3\"></svg>\n } @else {\n <svg [lucideIcon]=\"getIcon('chevron-left')\" class=\"w-3 h-3\"></svg>\n }\n <span\n class=\"absolute left-full ml-1 top-1/2 -translate-y-1/2 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\"\n >\n {{ collapsed() ? expandTooltip() : collapseTooltip() }}\n </span>\n </button>\n }\n\n <ng-content select=\"[sidebarHeader]\"></ng-content>\n\n <!-- Custom content between header and nav -->\n <ng-content select=\"[sidebarContent]\"></ng-content>\n\n <!-- Navigation -->\n <nav class=\"flex-1 sidebar-scroll _shk-scrollbar py-4 px-3\">\n <ul class=\"space-y-1\">\n @for (item of navItems(); track item.id) {\n @if (item.separator) {\n <li class=\"my-2 border-t _shk-border dark:[border-color:var(--shk-surface-200)]\"></li>\n }\n\n @if (item.children?.length) {\n <!-- Group -->\n <li>\n @if (collapsed()) {\n <shk-tooltip [text]=\"label(item)\" position=\"right\" mode=\"fixed\">\n <div\n class=\"flex items-center justify-center px-3 py-2.5 rounded-lg transition-all duration-200\"\n [class._shk-bg-primary]=\"isGroupActive(item)\"\n [class._shk-text-white]=\"isGroupActive(item)\"\n [class._shk-text-surface-500]=\"!isGroupActive(item)\"\n >\n @if (item.icon) {\n <svg [lucideIcon]=\"getIcon(item.icon)\" class=\"w-5 h-5 shrink-0\"></svg>\n }\n </div>\n </shk-tooltip>\n } @else {\n <button\n type=\"button\"\n (click)=\"toggleGroup(item)\"\n class=\"w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all duration-200 group relative\"\n [class._shk-bg-primary]=\"isGroupActive(item)\"\n [class._shk-text-white]=\"isGroupActive(item)\"\n [class.shadow-md]=\"isGroupActive(item)\"\n [class._shk-text-surface-700]=\"!isGroupActive(item)\"\n [class.dark:[color:var(--shk-surface-600)]]=\"!isGroupActive(item)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isGroupActive(item)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isGroupActive(item)\"\n [class.hover:[color:var(--shk-surface-900)]]=\"!isGroupActive(item)\"\n [class.dark:hover:[color:var(--shk-surface-700)]]=\"!isGroupActive(item)\"\n >\n @if (item.icon) {\n <svg [lucideIcon]=\"getIcon(item.icon)\" class=\"w-5 h-5 shrink-0\"></svg>\n }\n <span class=\"flex-1 text-left whitespace-nowrap overflow-hidden\">{{ label(item) }}</span>\n <svg\n [lucideIcon]=\"getIcon('chevron-down')\"\n class=\"w-4 h-4 transition-transform duration-200 shrink-0\"\n [class.rotate-180]=\"isGroupExpanded(item)\"\n ></svg>\n </button>\n\n @if (isGroupExpanded(item)) {\n <ul class=\"ml-3 mt-1 space-y-1 border-l-2 _shk-border dark:[border-color:var(--shk-surface-200)] pl-2\">\n @for (child of item.children; track child.id) {\n <li>\n <button\n type=\"button\"\n (click)=\"onItemClick(child)\"\n class=\"w-full flex items-center gap-3 px-3 py-2 rounded-lg text-sm font-medium transition-all duration-200\"\n [class._shk-bg-primary-soft]=\"isItemActive(child)\"\n [class._shk-bg-primary-soft-dark]=\"isItemActive(child)\"\n [class._shk-text-primary-700]=\"isItemActive(child)\"\n [class.dark:[color:var(--shk-primary-300)]]=\"isItemActive(child)\"\n [class._shk-text-surface-600]=\"!isItemActive(child)\"\n [class.dark:[color:var(--shk-surface-400)]]=\"!isItemActive(child)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isItemActive(child)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isItemActive(child)\"\n [class.hover:[color:var(--shk-surface-900)]]=\"!isItemActive(child)\"\n [class.dark:hover:[color:var(--shk-surface-700)]]=\"!isItemActive(child)\"\n >\n @if (child.icon) {\n <svg [lucideIcon]=\"getIcon(child.icon)\" class=\"w-4 h-4 shrink-0\"></svg>\n }\n <span class=\"whitespace-nowrap overflow-hidden\">{{ label(child) }}</span>\n @if (isItemActive(child)) {\n <span class=\"w-1.5 h-1.5 rounded-full _shk-bg-primary shrink-0 ml-auto\"></span>\n }\n </button>\n </li>\n }\n </ul>\n }\n }\n </li>\n } @else {\n <!-- Standalone item -->\n <li>\n @if (collapsed()) {\n <shk-tooltip [text]=\"label(item)\" position=\"right\" mode=\"fixed\">\n <button\n type=\"button\"\n (click)=\"onItemClick(item)\"\n class=\"w-full flex items-center justify-center px-3 py-2.5 rounded-lg text-sm font-medium transition-all duration-200\"\n [class._shk-bg-primary]=\"isItemActive(item)\"\n [class._shk-text-white]=\"isItemActive(item)\"\n [class.shadow-md]=\"isItemActive(item)\"\n [class._shk-text-surface-700]=\"!isItemActive(item)\"\n [class.dark:[color:var(--shk-surface-600)]]=\"!isItemActive(item)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isItemActive(item)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isItemActive(item)\"\n [class.hover:[color:var(--shk-surface-900)]]=\"!isItemActive(item)\"\n [class.dark:hover:[color:var(--shk-surface-700)]]=\"!isItemActive(item)\"\n >\n @if (item.icon) {\n <svg [lucideIcon]=\"getIcon(item.icon)\" class=\"w-5 h-5 shrink-0\"></svg>\n }\n </button>\n </shk-tooltip>\n } @else {\n <button\n type=\"button\"\n (click)=\"onItemClick(item)\"\n class=\"w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all duration-200\"\n [class._shk-bg-primary]=\"isItemActive(item)\"\n [class._shk-text-white]=\"isItemActive(item)\"\n [class.shadow-md]=\"isItemActive(item)\"\n [class._shk-text-surface-700]=\"!isItemActive(item)\"\n [class.dark:[color:var(--shk-surface-600)]]=\"!isItemActive(item)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isItemActive(item)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isItemActive(item)\"\n [class.hover:[color:var(--shk-surface-900)]]=\"!isItemActive(item)\"\n [class.dark:hover:[color:var(--shk-surface-700)]]=\"!isItemActive(item)\"\n >\n @if (item.icon) {\n <svg [lucideIcon]=\"getIcon(item.icon)\" class=\"w-5 h-5 shrink-0\"></svg>\n }\n <span class=\"flex-1 text-left whitespace-nowrap overflow-hidden\">{{ label(item) }}</span>\n @if (item.badge !== undefined) {\n <span\n class=\"text-xs font-bold px-2 py-0.5 rounded-full _shk-bg-primary _shk-text-white shrink-0\"\n [class.hidden]=\"collapsed()\"\n >\n {{ item.badge }}\n </span>\n }\n @if (isItemActive(item)) {\n <span class=\"w-1.5 h-1.5 rounded-full bg-white shrink-0\"></span>\n }\n </button>\n }\n </li>\n }\n }\n </ul>\n </nav>\n\n <!-- Footer -->\n <div class=\"shrink-0 p-2 [&:empty]:hidden\">\n <ng-content select=\"[sidebarFooter]\"></ng-content>\n </div>\n</aside>\n", styles: [":host{display:block}.sidebar-transition{transition:width .3s cubic-bezier(.4,0,.2,1),transform .3s cubic-bezier(.4,0,.2,1)}.sidebar-scroll{overflow-y:auto;overflow-x:visible}@media(min-width:1024px){.sidebar-mobile-transform{transform:none!important}}\n"] }]
2981
2981
  }], ctorParameters: () => [{ type: Object, decorators: [{
2982
2982
  type: Inject,
2983
2983
  args: [PLATFORM_ID]
@@ -3026,7 +3026,7 @@ const ICONS = {
3026
3026
  'chevron-down': LucideChevronDown,
3027
3027
  x: LucideX,
3028
3028
  };
3029
- function getIcon(name) {
3029
+ function getIcon$3(name) {
3030
3030
  if (!name)
3031
3031
  return null;
3032
3032
  return ICONS[name] ?? LucideMenu;
@@ -3055,7 +3055,7 @@ class RailSidebarComponent {
3055
3055
  this.logoutRequested = output();
3056
3056
  this.toggleSidebar = output();
3057
3057
  this.workspaceClick = output();
3058
- this.getIcon = getIcon;
3058
+ this.getIcon = getIcon$3;
3059
3059
  this.expandedGroups = signal(new Set(), ...(ngDevMode ? [{ debugName: "expandedGroups" }] : /* istanbul ignore next */ []));
3060
3060
  this.width = computed(() => this.collapsed() ? this.railWidth() : this.expandedWidth(), ...(ngDevMode ? [{ debugName: "width" }] : /* istanbul ignore next */ []));
3061
3061
  this.activeSection = computed(() => this.sections().find((s) => s.key === this.activeSectionKey()) ?? null, ...(ngDevMode ? [{ debugName: "activeSection" }] : /* istanbul ignore next */ []));
@@ -3167,11 +3167,11 @@ class RailSidebarComponent {
3167
3167
  this.toggleSidebar.emit(this.collapsed());
3168
3168
  }
3169
3169
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: RailSidebarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3170
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: RailSidebarComponent, isStandalone: true, selector: "shk-rail-sidebar", inputs: { sections: { classPropertyName: "sections", publicName: "sections", isSignal: true, isRequired: false, transformFunction: null }, activeUrl: { classPropertyName: "activeUrl", publicName: "activeUrl", isSignal: true, isRequired: false, transformFunction: null }, activeSectionKey: { classPropertyName: "activeSectionKey", publicName: "activeSectionKey", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, activeLang: { classPropertyName: "activeLang", publicName: "activeLang", isSignal: true, isRequired: false, transformFunction: null }, langs: { classPropertyName: "langs", publicName: "langs", isSignal: true, isRequired: false, transformFunction: null }, logo: { classPropertyName: "logo", publicName: "logo", isSignal: true, isRequired: false, transformFunction: null }, appName: { classPropertyName: "appName", publicName: "appName", isSignal: true, isRequired: false, transformFunction: null }, userRole: { classPropertyName: "userRole", publicName: "userRole", isSignal: true, isRequired: false, transformFunction: null }, labelPipe: { classPropertyName: "labelPipe", publicName: "labelPipe", isSignal: true, isRequired: false, transformFunction: null }, railWidth: { classPropertyName: "railWidth", publicName: "railWidth", isSignal: true, isRequired: false, transformFunction: null }, expandedWidth: { classPropertyName: "expandedWidth", publicName: "expandedWidth", isSignal: true, isRequired: false, transformFunction: null }, workspaceTooltip: { classPropertyName: "workspaceTooltip", publicName: "workspaceTooltip", isSignal: true, isRequired: false, transformFunction: null }, logoutTooltip: { classPropertyName: "logoutTooltip", publicName: "logoutTooltip", isSignal: true, isRequired: false, transformFunction: null }, collapseTooltip: { classPropertyName: "collapseTooltip", publicName: "collapseTooltip", isSignal: true, isRequired: false, transformFunction: null }, expandTooltip: { classPropertyName: "expandTooltip", publicName: "expandTooltip", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeSectionKey: "activeSectionKeyChange", collapsed: "collapsedChange", sectionSelected: "sectionSelected", itemClick: "itemClick", setLang: "setLang", logoutRequested: "logoutRequested", toggleSidebar: "toggleSidebar", workspaceClick: "workspaceClick" }, ngImport: i0, template: "<aside\n class=\"h-full flex overflow-hidden shrink-0 _shk-bg-white dark:[background-color:var(--shk-surface-50)] border-r _shk-border dark:[border-color:var(--shk-surface-100)]\"\n [style.width]=\"width()\"\n>\n <!-- Rail: vertical icon column -->\n <div\n class=\"h-full flex flex-col items-center shrink-0 px-[0.3rem] py-2 gap-1 border-r _shk-border dark:[border-color:var(--shk-surface-100)]\"\n [style.width]=\"railWidth()\"\n >\n <!-- Workspace / logo -->\n <div class=\"flex items-center justify-center w-full\">\n <button\n type=\"button\"\n (click)=\"onWorkspace()\"\n [class.is-collapsed]=\"collapsed()\"\n class=\"rail-workspace w-[3.2rem] h-[3.2rem] rounded-xl _shk-bg-surface-100 dark:[background-color:var(--shk-surface-200)] border-none grid place-items-center p-0 relative transition-all\"\n [title]=\"workspaceTooltip()\"\n >\n @if (logo()) {\n <img [src]=\"logo()\" alt=\"Logo\" class=\"rail-app-icon w-8 h-8 object-contain\" />\n } @else {\n <svg [lucideIcon]=\"getIcon('menu')\" class=\"rail-app-icon w-6 h-6 _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\"></svg>\n }\n @if (collapsed()) {\n <svg [lucideIcon]=\"getIcon('panel-right')\" class=\"rail-toggle-icon w-5 h-5 _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\"></svg>\n }\n </button>\n </div>\n\n <!-- Section actions -->\n <div class=\"rail-actions flex-1 flex flex-col items-center gap-1 pt-1\">\n @for (section of sections(); track section.key) {\n <shk-tooltip [text]=\"label(section.label)\" position=\"right\" mode=\"fixed\">\n <button\n type=\"button\"\n (click)=\"onSectionClick(section)\"\n class=\"rail-icon w-[3.4rem] h-[3.4rem] rounded-[0.85rem] grid place-items-center transition-all cursor-pointer\"\n [class.is-active]=\"isSectionActive(section)\"\n [attr.aria-label]=\"label(section.label)\"\n >\n <svg [lucideIcon]=\"getIcon(section.icon)\" class=\"w-5 h-5\"></svg>\n </button>\n </shk-tooltip>\n }\n </div>\n\n <!-- Bottom: language + logout -->\n <div class=\"rail-bottom mt-auto flex flex-col items-center gap-1\">\n <button\n type=\"button\"\n (click)=\"onToggleLang()\"\n class=\"rail-icon w-[3.4rem] h-[3.4rem] rounded-[0.85rem] grid place-items-center transition-all cursor-pointer\"\n [title]=\"activeLang()\"\n >\n <div class=\"flex flex-col items-center gap-[0.15rem]\">\n <svg [lucideIcon]=\"getIcon('globe')\" class=\"w-5 h-5\"></svg>\n <span class=\"rail-lang-code text-[0.5rem] font-bold tracking-[0.05em] leading-none\">{{ activeLang() | uppercase }}</span>\n </div>\n </button>\n\n <button\n type=\"button\"\n (click)=\"logoutRequested.emit()\"\n class=\"rail-icon rail-logout w-[3.4rem] h-[3.4rem] rounded-[0.85rem] grid place-items-center transition-all cursor-pointer\"\n [title]=\"logoutTooltip()\"\n >\n <svg [lucideIcon]=\"getIcon('log-out')\" class=\"w-5 h-5\"></svg>\n </button>\n </div>\n </div>\n\n <!-- Nav: section panel (hidden when collapsed) -->\n @if (!collapsed()) {\n <div class=\"flex-1 min-w-0 flex flex-col _shk-bg-white dark:[background-color:var(--shk-surface-50)]\">\n <!-- Brand header -->\n <div class=\"flex items-center justify-between gap-2 px-3 py-4 border-b _shk-border dark:[border-color:var(--shk-surface-100)]\">\n <span class=\"nav-app text-base font-bold whitespace-nowrap overflow-hidden text-ellipsis _shk-text-surface-800 dark:[color:var(--shk-surface-800)]\">\n {{ appName() }}\n </span>\n <button\n type=\"button\"\n (click)=\"onToggleSidebar()\"\n class=\"nav-toggle w-[1.8rem] h-[1.8rem] rounded-lg border-none bg-transparent grid place-items-center cursor-pointer shrink-0 transition-colors _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\"\n [title]=\"collapseTooltip()\"\n >\n <svg [lucideIcon]=\"getIcon('panel-right')\" class=\"w-4 h-4\"></svg>\n </button>\n </div>\n\n <!-- Menu -->\n <nav class=\"flex-1 overflow-y-auto _shk-scrollbar px-2 py-3\">\n @if (activeSection()) {\n <div class=\"px-2 pb-3\">\n <span class=\"nav-section-label text-xs font-bold tracking-[0.08em] uppercase _shk-text-surface-400 dark:[color:var(--shk-surface-500)] block whitespace-nowrap overflow-hidden text-ellipsis\">\n {{ label(activeSection()!.label) }}\n </span>\n </div>\n }\n\n <ul class=\"space-y-1\">\n @for (item of navItems(); track item.id) {\n @if (item.separator) {\n <li class=\"my-2 border-t _shk-border dark:[border-color:var(--shk-surface-200)]\"></li>\n }\n\n @if (item.children?.length) {\n <!-- Expandable group -->\n <li>\n <button\n type=\"button\"\n (click)=\"toggleGroup(item)\"\n class=\"w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all duration-200\"\n [class._shk-bg-primary]=\"isGroupActive(item)\"\n [class._shk-text-white]=\"isGroupActive(item)\"\n [class.shadow-md]=\"isGroupActive(item)\"\n [class._shk-text-surface-700]=\"!isGroupActive(item)\"\n [class.dark:[color:var(--shk-surface-600)]]=\"!isGroupActive(item)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isGroupActive(item)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isGroupActive(item)\"\n >\n @if (item.icon) {\n <svg [lucideIcon]=\"getIcon(item.icon)\" class=\"w-5 h-5 shrink-0\"></svg>\n }\n <span class=\"flex-1 text-left whitespace-nowrap overflow-hidden\">{{ label(item.label) }}</span>\n <svg\n [lucideIcon]=\"getIcon('chevron-down')\"\n class=\"w-4 h-4 transition-transform duration-200 shrink-0\"\n [class.rotate-180]=\"isGroupExpanded(item)\"\n ></svg>\n </button>\n\n @if (isGroupExpanded(item)) {\n <ul class=\"ml-3 mt-1 space-y-1 border-l-2 _shk-border dark:[border-color:var(--shk-surface-200)] pl-2\">\n @for (child of item.children; track child.id) {\n <li>\n <button\n type=\"button\"\n (click)=\"onItemClick(child)\"\n class=\"w-full flex items-center gap-3 px-3 py-2 rounded-lg text-sm font-medium transition-all duration-200\"\n [class._shk-bg-primary]=\"isItemActive(child)\"\n [class._shk-text-white]=\"isItemActive(child)\"\n [class._shk-text-surface-600]=\"!isItemActive(child)\"\n [class.dark:[color:var(--shk-surface-400)]]=\"!isItemActive(child)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isItemActive(child)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isItemActive(child)\"\n >\n @if (child.icon) {\n <svg [lucideIcon]=\"getIcon(child.icon)\" class=\"w-4 h-4 shrink-0\"></svg>\n }\n <span class=\"flex-1 text-left whitespace-nowrap overflow-hidden\">{{ label(child.label) }}</span>\n </button>\n </li>\n }\n </ul>\n }\n </li>\n } @else {\n <!-- Standalone item -->\n <li>\n <button\n type=\"button\"\n (click)=\"onItemClick(item)\"\n class=\"w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all duration-200\"\n [class._shk-bg-primary]=\"isItemActive(item)\"\n [class._shk-text-white]=\"isItemActive(item)\"\n [class.shadow-md]=\"isItemActive(item)\"\n [class._shk-text-surface-700]=\"!isItemActive(item)\"\n [class.dark:[color:var(--shk-surface-600)]]=\"!isItemActive(item)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isItemActive(item)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isItemActive(item)\"\n >\n @if (item.icon) {\n <svg [lucideIcon]=\"getIcon(item.icon)\" class=\"w-5 h-5 shrink-0\"></svg>\n }\n <span class=\"flex-1 text-left whitespace-nowrap overflow-hidden\">{{ label(item.label) }}</span>\n @if (item.badge !== undefined) {\n <span class=\"text-xs font-bold px-2 py-0.5 rounded-full _shk-bg-primary _shk-text-white shrink-0\">\n {{ item.badge }}\n </span>\n }\n </button>\n </li>\n }\n }\n </ul>\n </nav>\n </div>\n }\n</aside>\n", styles: [":host{display:block}.rail-workspace{cursor:pointer;transition:opacity .2s ease,box-shadow .2s ease}.rail-workspace.is-collapsed:hover{cursor:col-resize}.rail-workspace .rail-app-icon,.rail-workspace .rail-toggle-icon{grid-area:1 / 1 / 2 / 2;transition:opacity .2s ease}.rail-toggle-icon,.rail-workspace.is-collapsed:hover .rail-app-icon{opacity:0}.rail-workspace.is-collapsed:hover .rail-toggle-icon{opacity:1}.rail-icon{background:transparent;color:var(--shk-surface-700);border:1px solid transparent;transition:transform .18s ease,color .18s ease,background-color .18s ease,box-shadow .18s ease}.rail-icon svg{stroke-width:1.8}.rail-icon:hover{background:var(--shk-surface-100);color:var(--shk-primary-600)}.dark .rail-icon:hover{background:var(--shk-surface-200);color:var(--shk-primary-400)}.rail-icon.is-active{background:var(--shk-primary-600);color:#fff;box-shadow:0 1px 2px #0003}.dark .rail-icon.is-active{background:var(--shk-primary-500);color:#fff}.rail-logout:hover{color:var(--shk-error-500)}.dark .rail-logout:hover{color:var(--shk-error-400)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: LucideDynamicIcon, selector: "svg[lucideIcon]", inputs: ["lucideIcon"] }, { kind: "component", type: TooltipComponent, selector: "shk-tooltip", inputs: ["text", "position", "mode", "offset"] }, { kind: "pipe", type: i1.UpperCasePipe, name: "uppercase" }] }); }
3170
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: RailSidebarComponent, isStandalone: true, selector: "shk-rail-sidebar", inputs: { sections: { classPropertyName: "sections", publicName: "sections", isSignal: true, isRequired: false, transformFunction: null }, activeUrl: { classPropertyName: "activeUrl", publicName: "activeUrl", isSignal: true, isRequired: false, transformFunction: null }, activeSectionKey: { classPropertyName: "activeSectionKey", publicName: "activeSectionKey", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, activeLang: { classPropertyName: "activeLang", publicName: "activeLang", isSignal: true, isRequired: false, transformFunction: null }, langs: { classPropertyName: "langs", publicName: "langs", isSignal: true, isRequired: false, transformFunction: null }, logo: { classPropertyName: "logo", publicName: "logo", isSignal: true, isRequired: false, transformFunction: null }, appName: { classPropertyName: "appName", publicName: "appName", isSignal: true, isRequired: false, transformFunction: null }, userRole: { classPropertyName: "userRole", publicName: "userRole", isSignal: true, isRequired: false, transformFunction: null }, labelPipe: { classPropertyName: "labelPipe", publicName: "labelPipe", isSignal: true, isRequired: false, transformFunction: null }, railWidth: { classPropertyName: "railWidth", publicName: "railWidth", isSignal: true, isRequired: false, transformFunction: null }, expandedWidth: { classPropertyName: "expandedWidth", publicName: "expandedWidth", isSignal: true, isRequired: false, transformFunction: null }, workspaceTooltip: { classPropertyName: "workspaceTooltip", publicName: "workspaceTooltip", isSignal: true, isRequired: false, transformFunction: null }, logoutTooltip: { classPropertyName: "logoutTooltip", publicName: "logoutTooltip", isSignal: true, isRequired: false, transformFunction: null }, collapseTooltip: { classPropertyName: "collapseTooltip", publicName: "collapseTooltip", isSignal: true, isRequired: false, transformFunction: null }, expandTooltip: { classPropertyName: "expandTooltip", publicName: "expandTooltip", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeSectionKey: "activeSectionKeyChange", collapsed: "collapsedChange", sectionSelected: "sectionSelected", itemClick: "itemClick", setLang: "setLang", logoutRequested: "logoutRequested", toggleSidebar: "toggleSidebar", workspaceClick: "workspaceClick" }, ngImport: i0, template: "<aside\n class=\"h-full flex overflow-hidden shrink-0 _shk-bg-white dark:[background-color:var(--shk-surface-50)] border-r _shk-border dark:[border-color:var(--shk-surface-100)]\"\n [style.width]=\"width()\"\n>\n <!-- Rail: vertical icon column -->\n <div\n class=\"h-full flex flex-col items-center shrink-0 px-[0.3rem] py-2 gap-1 border-r _shk-border dark:[border-color:var(--shk-surface-100)]\"\n [style.width]=\"railWidth()\"\n >\n <!-- Workspace / logo -->\n <div class=\"flex items-center justify-center w-full\">\n <button\n type=\"button\"\n (click)=\"onWorkspace()\"\n [class.is-collapsed]=\"collapsed()\"\n class=\"rail-workspace w-[3.2rem] h-[3.2rem] rounded-xl _shk-bg-surface-100 dark:[background-color:var(--shk-surface-200)] border-none grid place-items-center p-0 relative transition-all\"\n [title]=\"workspaceTooltip()\"\n >\n @if (logo()) {\n <img [src]=\"logo()\" alt=\"Logo\" class=\"rail-app-icon w-8 h-8 object-contain\" />\n } @else {\n <svg [lucideIcon]=\"getIcon('menu')\" class=\"rail-app-icon w-6 h-6 _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\"></svg>\n }\n @if (collapsed()) {\n <svg [lucideIcon]=\"getIcon('panel-right')\" class=\"rail-toggle-icon w-5 h-5 _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\"></svg>\n }\n </button>\n </div>\n\n <!-- Section actions -->\n <div class=\"rail-actions flex-1 flex flex-col items-center gap-1 pt-1\">\n @for (section of sections(); track section.key) {\n <shk-tooltip [text]=\"label(section.label)\" position=\"right\" mode=\"fixed\">\n <button\n type=\"button\"\n (click)=\"onSectionClick(section)\"\n class=\"rail-icon w-[3.4rem] h-[3.4rem] rounded-[0.85rem] grid place-items-center transition-all cursor-pointer\"\n [class.is-active]=\"isSectionActive(section)\"\n [attr.aria-label]=\"label(section.label)\"\n >\n <svg [lucideIcon]=\"getIcon(section.icon)\" class=\"w-5 h-5\"></svg>\n </button>\n </shk-tooltip>\n }\n </div>\n\n <!-- Bottom: language + logout -->\n <div class=\"rail-bottom mt-auto flex flex-col items-center gap-1\">\n <button\n type=\"button\"\n (click)=\"onToggleLang()\"\n class=\"rail-icon w-[3.4rem] h-[3.4rem] rounded-[0.85rem] grid place-items-center transition-all cursor-pointer\"\n [title]=\"activeLang()\"\n >\n <div class=\"flex flex-col items-center gap-[0.15rem]\">\n <svg [lucideIcon]=\"getIcon('globe')\" class=\"w-5 h-5\"></svg>\n <span class=\"rail-lang-code text-[0.5rem] font-bold tracking-[0.05em] leading-none\">{{ activeLang() | uppercase }}</span>\n </div>\n </button>\n\n <button\n type=\"button\"\n (click)=\"logoutRequested.emit()\"\n class=\"rail-icon rail-logout w-[3.4rem] h-[3.4rem] rounded-[0.85rem] grid place-items-center transition-all cursor-pointer\"\n [title]=\"logoutTooltip()\"\n >\n <svg [lucideIcon]=\"getIcon('log-out')\" class=\"w-5 h-5\"></svg>\n </button>\n </div>\n </div>\n\n <!-- Nav: section panel (hidden when collapsed) -->\n @if (!collapsed()) {\n <div class=\"flex-1 min-w-0 flex flex-col _shk-bg-white dark:[background-color:var(--shk-surface-50)]\">\n <!-- Brand header -->\n <div class=\"flex items-center justify-between gap-2 px-3 py-4 border-b _shk-border dark:[border-color:var(--shk-surface-100)]\">\n <span class=\"nav-app text-base font-bold whitespace-nowrap overflow-hidden text-ellipsis _shk-text-surface-800 dark:[color:var(--shk-surface-800)]\">\n {{ appName() }}\n </span>\n <button\n type=\"button\"\n (click)=\"onToggleSidebar()\"\n class=\"nav-toggle w-[1.8rem] h-[1.8rem] rounded-lg border-none bg-transparent grid place-items-center cursor-pointer shrink-0 transition-colors _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\"\n [title]=\"collapseTooltip()\"\n >\n <svg [lucideIcon]=\"getIcon('panel-right')\" class=\"w-4 h-4\"></svg>\n </button>\n </div>\n\n <!-- Menu -->\n <nav class=\"flex-1 overflow-y-auto _shk-scrollbar px-2 py-3\">\n @if (activeSection()) {\n <div class=\"px-2 pb-3\">\n <span class=\"nav-section-label text-xs font-bold tracking-[0.08em] uppercase _shk-text-surface-400 dark:[color:var(--shk-surface-500)] block whitespace-nowrap overflow-hidden text-ellipsis\">\n {{ label(activeSection()!.label) }}\n </span>\n </div>\n }\n\n <ul class=\"space-y-1\">\n @for (item of navItems(); track item.id) {\n @if (item.separator) {\n <li class=\"my-2 border-t _shk-border dark:[border-color:var(--shk-surface-200)]\"></li>\n }\n\n @if (item.children?.length) {\n <!-- Expandable group -->\n <li>\n <button\n type=\"button\"\n (click)=\"toggleGroup(item)\"\n class=\"w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all duration-200\"\n [class._shk-bg-primary]=\"isGroupActive(item)\"\n [class._shk-text-white]=\"isGroupActive(item)\"\n [class.shadow-md]=\"isGroupActive(item)\"\n [class._shk-text-surface-700]=\"!isGroupActive(item)\"\n [class.dark:[color:var(--shk-surface-600)]]=\"!isGroupActive(item)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isGroupActive(item)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isGroupActive(item)\"\n >\n @if (item.icon) {\n <svg [lucideIcon]=\"getIcon(item.icon)\" class=\"w-5 h-5 shrink-0\"></svg>\n }\n <span class=\"flex-1 text-left whitespace-nowrap overflow-hidden\">{{ label(item.label) }}</span>\n <svg\n [lucideIcon]=\"getIcon('chevron-down')\"\n class=\"w-4 h-4 transition-transform duration-200 shrink-0\"\n [class.rotate-180]=\"isGroupExpanded(item)\"\n ></svg>\n </button>\n\n @if (isGroupExpanded(item)) {\n <ul class=\"ml-3 mt-1 space-y-1 border-l-2 _shk-border dark:[border-color:var(--shk-surface-200)] pl-2\">\n @for (child of item.children; track child.id) {\n <li>\n <button\n type=\"button\"\n (click)=\"onItemClick(child)\"\n class=\"w-full flex items-center gap-3 px-3 py-2 rounded-lg text-sm font-medium transition-all duration-200\"\n [class._shk-bg-primary-soft]=\"isItemActive(child)\"\n [class._shk-bg-primary-soft-dark]=\"isItemActive(child)\"\n [class._shk-text-primary-700]=\"isItemActive(child)\"\n [class.dark:[color:var(--shk-primary-300)]]=\"isItemActive(child)\"\n [class._shk-text-surface-600]=\"!isItemActive(child)\"\n [class.dark:[color:var(--shk-surface-400)]]=\"!isItemActive(child)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isItemActive(child)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isItemActive(child)\"\n [class.hover:[color:var(--shk-surface-900)]]=\"!isItemActive(child)\"\n [class.dark:hover:[color:var(--shk-surface-700)]]=\"!isItemActive(child)\"\n >\n @if (child.icon) {\n <svg [lucideIcon]=\"getIcon(child.icon)\" class=\"w-4 h-4 shrink-0\"></svg>\n }\n <span class=\"whitespace-nowrap overflow-hidden\">{{ label(child.label) }}</span>\n @if (isItemActive(child)) {\n <span class=\"w-1.5 h-1.5 rounded-full _shk-bg-primary shrink-0 ml-auto\"></span>\n }\n </button>\n </li>\n }\n </ul>\n }\n </li>\n } @else {\n <!-- Standalone item -->\n <li>\n <button\n type=\"button\"\n (click)=\"onItemClick(item)\"\n class=\"w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all duration-200\"\n [class._shk-bg-primary]=\"isItemActive(item)\"\n [class._shk-text-white]=\"isItemActive(item)\"\n [class.shadow-md]=\"isItemActive(item)\"\n [class._shk-text-surface-700]=\"!isItemActive(item)\"\n [class.dark:[color:var(--shk-surface-600)]]=\"!isItemActive(item)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isItemActive(item)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isItemActive(item)\"\n >\n @if (item.icon) {\n <svg [lucideIcon]=\"getIcon(item.icon)\" class=\"w-5 h-5 shrink-0\"></svg>\n }\n <span class=\"flex-1 text-left whitespace-nowrap overflow-hidden\">{{ label(item.label) }}</span>\n @if (item.badge !== undefined) {\n <span class=\"text-xs font-bold px-2 py-0.5 rounded-full _shk-bg-primary _shk-text-white shrink-0\">\n {{ item.badge }}\n </span>\n }\n </button>\n </li>\n }\n }\n </ul>\n </nav>\n </div>\n }\n</aside>\n", styles: [":host{display:block}.rail-workspace{cursor:pointer;transition:opacity .2s ease,box-shadow .2s ease}.rail-workspace.is-collapsed:hover{cursor:col-resize}.rail-workspace .rail-app-icon,.rail-workspace .rail-toggle-icon{grid-area:1 / 1 / 2 / 2;transition:opacity .2s ease}.rail-toggle-icon,.rail-workspace.is-collapsed:hover .rail-app-icon{opacity:0}.rail-workspace.is-collapsed:hover .rail-toggle-icon{opacity:1}.rail-icon{background:transparent;color:var(--shk-surface-700);border:1px solid transparent;transition:transform .18s ease,color .18s ease,background-color .18s ease,box-shadow .18s ease}.rail-icon svg{stroke-width:1.8}.rail-icon:hover{background:var(--shk-surface-100);color:var(--shk-primary-600)}.dark .rail-icon:hover{background:var(--shk-surface-200);color:var(--shk-primary-400)}.rail-icon.is-active{background:var(--shk-primary-600);color:#fff;box-shadow:0 1px 2px #0003}.dark .rail-icon.is-active{background:var(--shk-primary-500);color:#fff}.rail-logout:hover{color:var(--shk-error-500)}.dark .rail-logout:hover{color:var(--shk-error-400)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: LucideDynamicIcon, selector: "svg[lucideIcon]", inputs: ["lucideIcon"] }, { kind: "component", type: TooltipComponent, selector: "shk-tooltip", inputs: ["text", "position", "mode", "offset"] }, { kind: "pipe", type: i1.UpperCasePipe, name: "uppercase" }] }); }
3171
3171
  }
3172
3172
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: RailSidebarComponent, decorators: [{
3173
3173
  type: Component,
3174
- args: [{ selector: 'shk-rail-sidebar', standalone: true, imports: [CommonModule, LucideDynamicIcon, TooltipComponent], template: "<aside\n class=\"h-full flex overflow-hidden shrink-0 _shk-bg-white dark:[background-color:var(--shk-surface-50)] border-r _shk-border dark:[border-color:var(--shk-surface-100)]\"\n [style.width]=\"width()\"\n>\n <!-- Rail: vertical icon column -->\n <div\n class=\"h-full flex flex-col items-center shrink-0 px-[0.3rem] py-2 gap-1 border-r _shk-border dark:[border-color:var(--shk-surface-100)]\"\n [style.width]=\"railWidth()\"\n >\n <!-- Workspace / logo -->\n <div class=\"flex items-center justify-center w-full\">\n <button\n type=\"button\"\n (click)=\"onWorkspace()\"\n [class.is-collapsed]=\"collapsed()\"\n class=\"rail-workspace w-[3.2rem] h-[3.2rem] rounded-xl _shk-bg-surface-100 dark:[background-color:var(--shk-surface-200)] border-none grid place-items-center p-0 relative transition-all\"\n [title]=\"workspaceTooltip()\"\n >\n @if (logo()) {\n <img [src]=\"logo()\" alt=\"Logo\" class=\"rail-app-icon w-8 h-8 object-contain\" />\n } @else {\n <svg [lucideIcon]=\"getIcon('menu')\" class=\"rail-app-icon w-6 h-6 _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\"></svg>\n }\n @if (collapsed()) {\n <svg [lucideIcon]=\"getIcon('panel-right')\" class=\"rail-toggle-icon w-5 h-5 _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\"></svg>\n }\n </button>\n </div>\n\n <!-- Section actions -->\n <div class=\"rail-actions flex-1 flex flex-col items-center gap-1 pt-1\">\n @for (section of sections(); track section.key) {\n <shk-tooltip [text]=\"label(section.label)\" position=\"right\" mode=\"fixed\">\n <button\n type=\"button\"\n (click)=\"onSectionClick(section)\"\n class=\"rail-icon w-[3.4rem] h-[3.4rem] rounded-[0.85rem] grid place-items-center transition-all cursor-pointer\"\n [class.is-active]=\"isSectionActive(section)\"\n [attr.aria-label]=\"label(section.label)\"\n >\n <svg [lucideIcon]=\"getIcon(section.icon)\" class=\"w-5 h-5\"></svg>\n </button>\n </shk-tooltip>\n }\n </div>\n\n <!-- Bottom: language + logout -->\n <div class=\"rail-bottom mt-auto flex flex-col items-center gap-1\">\n <button\n type=\"button\"\n (click)=\"onToggleLang()\"\n class=\"rail-icon w-[3.4rem] h-[3.4rem] rounded-[0.85rem] grid place-items-center transition-all cursor-pointer\"\n [title]=\"activeLang()\"\n >\n <div class=\"flex flex-col items-center gap-[0.15rem]\">\n <svg [lucideIcon]=\"getIcon('globe')\" class=\"w-5 h-5\"></svg>\n <span class=\"rail-lang-code text-[0.5rem] font-bold tracking-[0.05em] leading-none\">{{ activeLang() | uppercase }}</span>\n </div>\n </button>\n\n <button\n type=\"button\"\n (click)=\"logoutRequested.emit()\"\n class=\"rail-icon rail-logout w-[3.4rem] h-[3.4rem] rounded-[0.85rem] grid place-items-center transition-all cursor-pointer\"\n [title]=\"logoutTooltip()\"\n >\n <svg [lucideIcon]=\"getIcon('log-out')\" class=\"w-5 h-5\"></svg>\n </button>\n </div>\n </div>\n\n <!-- Nav: section panel (hidden when collapsed) -->\n @if (!collapsed()) {\n <div class=\"flex-1 min-w-0 flex flex-col _shk-bg-white dark:[background-color:var(--shk-surface-50)]\">\n <!-- Brand header -->\n <div class=\"flex items-center justify-between gap-2 px-3 py-4 border-b _shk-border dark:[border-color:var(--shk-surface-100)]\">\n <span class=\"nav-app text-base font-bold whitespace-nowrap overflow-hidden text-ellipsis _shk-text-surface-800 dark:[color:var(--shk-surface-800)]\">\n {{ appName() }}\n </span>\n <button\n type=\"button\"\n (click)=\"onToggleSidebar()\"\n class=\"nav-toggle w-[1.8rem] h-[1.8rem] rounded-lg border-none bg-transparent grid place-items-center cursor-pointer shrink-0 transition-colors _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\"\n [title]=\"collapseTooltip()\"\n >\n <svg [lucideIcon]=\"getIcon('panel-right')\" class=\"w-4 h-4\"></svg>\n </button>\n </div>\n\n <!-- Menu -->\n <nav class=\"flex-1 overflow-y-auto _shk-scrollbar px-2 py-3\">\n @if (activeSection()) {\n <div class=\"px-2 pb-3\">\n <span class=\"nav-section-label text-xs font-bold tracking-[0.08em] uppercase _shk-text-surface-400 dark:[color:var(--shk-surface-500)] block whitespace-nowrap overflow-hidden text-ellipsis\">\n {{ label(activeSection()!.label) }}\n </span>\n </div>\n }\n\n <ul class=\"space-y-1\">\n @for (item of navItems(); track item.id) {\n @if (item.separator) {\n <li class=\"my-2 border-t _shk-border dark:[border-color:var(--shk-surface-200)]\"></li>\n }\n\n @if (item.children?.length) {\n <!-- Expandable group -->\n <li>\n <button\n type=\"button\"\n (click)=\"toggleGroup(item)\"\n class=\"w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all duration-200\"\n [class._shk-bg-primary]=\"isGroupActive(item)\"\n [class._shk-text-white]=\"isGroupActive(item)\"\n [class.shadow-md]=\"isGroupActive(item)\"\n [class._shk-text-surface-700]=\"!isGroupActive(item)\"\n [class.dark:[color:var(--shk-surface-600)]]=\"!isGroupActive(item)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isGroupActive(item)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isGroupActive(item)\"\n >\n @if (item.icon) {\n <svg [lucideIcon]=\"getIcon(item.icon)\" class=\"w-5 h-5 shrink-0\"></svg>\n }\n <span class=\"flex-1 text-left whitespace-nowrap overflow-hidden\">{{ label(item.label) }}</span>\n <svg\n [lucideIcon]=\"getIcon('chevron-down')\"\n class=\"w-4 h-4 transition-transform duration-200 shrink-0\"\n [class.rotate-180]=\"isGroupExpanded(item)\"\n ></svg>\n </button>\n\n @if (isGroupExpanded(item)) {\n <ul class=\"ml-3 mt-1 space-y-1 border-l-2 _shk-border dark:[border-color:var(--shk-surface-200)] pl-2\">\n @for (child of item.children; track child.id) {\n <li>\n <button\n type=\"button\"\n (click)=\"onItemClick(child)\"\n class=\"w-full flex items-center gap-3 px-3 py-2 rounded-lg text-sm font-medium transition-all duration-200\"\n [class._shk-bg-primary]=\"isItemActive(child)\"\n [class._shk-text-white]=\"isItemActive(child)\"\n [class._shk-text-surface-600]=\"!isItemActive(child)\"\n [class.dark:[color:var(--shk-surface-400)]]=\"!isItemActive(child)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isItemActive(child)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isItemActive(child)\"\n >\n @if (child.icon) {\n <svg [lucideIcon]=\"getIcon(child.icon)\" class=\"w-4 h-4 shrink-0\"></svg>\n }\n <span class=\"flex-1 text-left whitespace-nowrap overflow-hidden\">{{ label(child.label) }}</span>\n </button>\n </li>\n }\n </ul>\n }\n </li>\n } @else {\n <!-- Standalone item -->\n <li>\n <button\n type=\"button\"\n (click)=\"onItemClick(item)\"\n class=\"w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all duration-200\"\n [class._shk-bg-primary]=\"isItemActive(item)\"\n [class._shk-text-white]=\"isItemActive(item)\"\n [class.shadow-md]=\"isItemActive(item)\"\n [class._shk-text-surface-700]=\"!isItemActive(item)\"\n [class.dark:[color:var(--shk-surface-600)]]=\"!isItemActive(item)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isItemActive(item)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isItemActive(item)\"\n >\n @if (item.icon) {\n <svg [lucideIcon]=\"getIcon(item.icon)\" class=\"w-5 h-5 shrink-0\"></svg>\n }\n <span class=\"flex-1 text-left whitespace-nowrap overflow-hidden\">{{ label(item.label) }}</span>\n @if (item.badge !== undefined) {\n <span class=\"text-xs font-bold px-2 py-0.5 rounded-full _shk-bg-primary _shk-text-white shrink-0\">\n {{ item.badge }}\n </span>\n }\n </button>\n </li>\n }\n }\n </ul>\n </nav>\n </div>\n }\n</aside>\n", styles: [":host{display:block}.rail-workspace{cursor:pointer;transition:opacity .2s ease,box-shadow .2s ease}.rail-workspace.is-collapsed:hover{cursor:col-resize}.rail-workspace .rail-app-icon,.rail-workspace .rail-toggle-icon{grid-area:1 / 1 / 2 / 2;transition:opacity .2s ease}.rail-toggle-icon,.rail-workspace.is-collapsed:hover .rail-app-icon{opacity:0}.rail-workspace.is-collapsed:hover .rail-toggle-icon{opacity:1}.rail-icon{background:transparent;color:var(--shk-surface-700);border:1px solid transparent;transition:transform .18s ease,color .18s ease,background-color .18s ease,box-shadow .18s ease}.rail-icon svg{stroke-width:1.8}.rail-icon:hover{background:var(--shk-surface-100);color:var(--shk-primary-600)}.dark .rail-icon:hover{background:var(--shk-surface-200);color:var(--shk-primary-400)}.rail-icon.is-active{background:var(--shk-primary-600);color:#fff;box-shadow:0 1px 2px #0003}.dark .rail-icon.is-active{background:var(--shk-primary-500);color:#fff}.rail-logout:hover{color:var(--shk-error-500)}.dark .rail-logout:hover{color:var(--shk-error-400)}\n"] }]
3174
+ args: [{ selector: 'shk-rail-sidebar', standalone: true, imports: [CommonModule, LucideDynamicIcon, TooltipComponent], template: "<aside\n class=\"h-full flex overflow-hidden shrink-0 _shk-bg-white dark:[background-color:var(--shk-surface-50)] border-r _shk-border dark:[border-color:var(--shk-surface-100)]\"\n [style.width]=\"width()\"\n>\n <!-- Rail: vertical icon column -->\n <div\n class=\"h-full flex flex-col items-center shrink-0 px-[0.3rem] py-2 gap-1 border-r _shk-border dark:[border-color:var(--shk-surface-100)]\"\n [style.width]=\"railWidth()\"\n >\n <!-- Workspace / logo -->\n <div class=\"flex items-center justify-center w-full\">\n <button\n type=\"button\"\n (click)=\"onWorkspace()\"\n [class.is-collapsed]=\"collapsed()\"\n class=\"rail-workspace w-[3.2rem] h-[3.2rem] rounded-xl _shk-bg-surface-100 dark:[background-color:var(--shk-surface-200)] border-none grid place-items-center p-0 relative transition-all\"\n [title]=\"workspaceTooltip()\"\n >\n @if (logo()) {\n <img [src]=\"logo()\" alt=\"Logo\" class=\"rail-app-icon w-8 h-8 object-contain\" />\n } @else {\n <svg [lucideIcon]=\"getIcon('menu')\" class=\"rail-app-icon w-6 h-6 _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\"></svg>\n }\n @if (collapsed()) {\n <svg [lucideIcon]=\"getIcon('panel-right')\" class=\"rail-toggle-icon w-5 h-5 _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\"></svg>\n }\n </button>\n </div>\n\n <!-- Section actions -->\n <div class=\"rail-actions flex-1 flex flex-col items-center gap-1 pt-1\">\n @for (section of sections(); track section.key) {\n <shk-tooltip [text]=\"label(section.label)\" position=\"right\" mode=\"fixed\">\n <button\n type=\"button\"\n (click)=\"onSectionClick(section)\"\n class=\"rail-icon w-[3.4rem] h-[3.4rem] rounded-[0.85rem] grid place-items-center transition-all cursor-pointer\"\n [class.is-active]=\"isSectionActive(section)\"\n [attr.aria-label]=\"label(section.label)\"\n >\n <svg [lucideIcon]=\"getIcon(section.icon)\" class=\"w-5 h-5\"></svg>\n </button>\n </shk-tooltip>\n }\n </div>\n\n <!-- Bottom: language + logout -->\n <div class=\"rail-bottom mt-auto flex flex-col items-center gap-1\">\n <button\n type=\"button\"\n (click)=\"onToggleLang()\"\n class=\"rail-icon w-[3.4rem] h-[3.4rem] rounded-[0.85rem] grid place-items-center transition-all cursor-pointer\"\n [title]=\"activeLang()\"\n >\n <div class=\"flex flex-col items-center gap-[0.15rem]\">\n <svg [lucideIcon]=\"getIcon('globe')\" class=\"w-5 h-5\"></svg>\n <span class=\"rail-lang-code text-[0.5rem] font-bold tracking-[0.05em] leading-none\">{{ activeLang() | uppercase }}</span>\n </div>\n </button>\n\n <button\n type=\"button\"\n (click)=\"logoutRequested.emit()\"\n class=\"rail-icon rail-logout w-[3.4rem] h-[3.4rem] rounded-[0.85rem] grid place-items-center transition-all cursor-pointer\"\n [title]=\"logoutTooltip()\"\n >\n <svg [lucideIcon]=\"getIcon('log-out')\" class=\"w-5 h-5\"></svg>\n </button>\n </div>\n </div>\n\n <!-- Nav: section panel (hidden when collapsed) -->\n @if (!collapsed()) {\n <div class=\"flex-1 min-w-0 flex flex-col _shk-bg-white dark:[background-color:var(--shk-surface-50)]\">\n <!-- Brand header -->\n <div class=\"flex items-center justify-between gap-2 px-3 py-4 border-b _shk-border dark:[border-color:var(--shk-surface-100)]\">\n <span class=\"nav-app text-base font-bold whitespace-nowrap overflow-hidden text-ellipsis _shk-text-surface-800 dark:[color:var(--shk-surface-800)]\">\n {{ appName() }}\n </span>\n <button\n type=\"button\"\n (click)=\"onToggleSidebar()\"\n class=\"nav-toggle w-[1.8rem] h-[1.8rem] rounded-lg border-none bg-transparent grid place-items-center cursor-pointer shrink-0 transition-colors _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\"\n [title]=\"collapseTooltip()\"\n >\n <svg [lucideIcon]=\"getIcon('panel-right')\" class=\"w-4 h-4\"></svg>\n </button>\n </div>\n\n <!-- Menu -->\n <nav class=\"flex-1 overflow-y-auto _shk-scrollbar px-2 py-3\">\n @if (activeSection()) {\n <div class=\"px-2 pb-3\">\n <span class=\"nav-section-label text-xs font-bold tracking-[0.08em] uppercase _shk-text-surface-400 dark:[color:var(--shk-surface-500)] block whitespace-nowrap overflow-hidden text-ellipsis\">\n {{ label(activeSection()!.label) }}\n </span>\n </div>\n }\n\n <ul class=\"space-y-1\">\n @for (item of navItems(); track item.id) {\n @if (item.separator) {\n <li class=\"my-2 border-t _shk-border dark:[border-color:var(--shk-surface-200)]\"></li>\n }\n\n @if (item.children?.length) {\n <!-- Expandable group -->\n <li>\n <button\n type=\"button\"\n (click)=\"toggleGroup(item)\"\n class=\"w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all duration-200\"\n [class._shk-bg-primary]=\"isGroupActive(item)\"\n [class._shk-text-white]=\"isGroupActive(item)\"\n [class.shadow-md]=\"isGroupActive(item)\"\n [class._shk-text-surface-700]=\"!isGroupActive(item)\"\n [class.dark:[color:var(--shk-surface-600)]]=\"!isGroupActive(item)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isGroupActive(item)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isGroupActive(item)\"\n >\n @if (item.icon) {\n <svg [lucideIcon]=\"getIcon(item.icon)\" class=\"w-5 h-5 shrink-0\"></svg>\n }\n <span class=\"flex-1 text-left whitespace-nowrap overflow-hidden\">{{ label(item.label) }}</span>\n <svg\n [lucideIcon]=\"getIcon('chevron-down')\"\n class=\"w-4 h-4 transition-transform duration-200 shrink-0\"\n [class.rotate-180]=\"isGroupExpanded(item)\"\n ></svg>\n </button>\n\n @if (isGroupExpanded(item)) {\n <ul class=\"ml-3 mt-1 space-y-1 border-l-2 _shk-border dark:[border-color:var(--shk-surface-200)] pl-2\">\n @for (child of item.children; track child.id) {\n <li>\n <button\n type=\"button\"\n (click)=\"onItemClick(child)\"\n class=\"w-full flex items-center gap-3 px-3 py-2 rounded-lg text-sm font-medium transition-all duration-200\"\n [class._shk-bg-primary-soft]=\"isItemActive(child)\"\n [class._shk-bg-primary-soft-dark]=\"isItemActive(child)\"\n [class._shk-text-primary-700]=\"isItemActive(child)\"\n [class.dark:[color:var(--shk-primary-300)]]=\"isItemActive(child)\"\n [class._shk-text-surface-600]=\"!isItemActive(child)\"\n [class.dark:[color:var(--shk-surface-400)]]=\"!isItemActive(child)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isItemActive(child)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isItemActive(child)\"\n [class.hover:[color:var(--shk-surface-900)]]=\"!isItemActive(child)\"\n [class.dark:hover:[color:var(--shk-surface-700)]]=\"!isItemActive(child)\"\n >\n @if (child.icon) {\n <svg [lucideIcon]=\"getIcon(child.icon)\" class=\"w-4 h-4 shrink-0\"></svg>\n }\n <span class=\"whitespace-nowrap overflow-hidden\">{{ label(child.label) }}</span>\n @if (isItemActive(child)) {\n <span class=\"w-1.5 h-1.5 rounded-full _shk-bg-primary shrink-0 ml-auto\"></span>\n }\n </button>\n </li>\n }\n </ul>\n }\n </li>\n } @else {\n <!-- Standalone item -->\n <li>\n <button\n type=\"button\"\n (click)=\"onItemClick(item)\"\n class=\"w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all duration-200\"\n [class._shk-bg-primary]=\"isItemActive(item)\"\n [class._shk-text-white]=\"isItemActive(item)\"\n [class.shadow-md]=\"isItemActive(item)\"\n [class._shk-text-surface-700]=\"!isItemActive(item)\"\n [class.dark:[color:var(--shk-surface-600)]]=\"!isItemActive(item)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isItemActive(item)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isItemActive(item)\"\n >\n @if (item.icon) {\n <svg [lucideIcon]=\"getIcon(item.icon)\" class=\"w-5 h-5 shrink-0\"></svg>\n }\n <span class=\"flex-1 text-left whitespace-nowrap overflow-hidden\">{{ label(item.label) }}</span>\n @if (item.badge !== undefined) {\n <span class=\"text-xs font-bold px-2 py-0.5 rounded-full _shk-bg-primary _shk-text-white shrink-0\">\n {{ item.badge }}\n </span>\n }\n </button>\n </li>\n }\n }\n </ul>\n </nav>\n </div>\n }\n</aside>\n", styles: [":host{display:block}.rail-workspace{cursor:pointer;transition:opacity .2s ease,box-shadow .2s ease}.rail-workspace.is-collapsed:hover{cursor:col-resize}.rail-workspace .rail-app-icon,.rail-workspace .rail-toggle-icon{grid-area:1 / 1 / 2 / 2;transition:opacity .2s ease}.rail-toggle-icon,.rail-workspace.is-collapsed:hover .rail-app-icon{opacity:0}.rail-workspace.is-collapsed:hover .rail-toggle-icon{opacity:1}.rail-icon{background:transparent;color:var(--shk-surface-700);border:1px solid transparent;transition:transform .18s ease,color .18s ease,background-color .18s ease,box-shadow .18s ease}.rail-icon svg{stroke-width:1.8}.rail-icon:hover{background:var(--shk-surface-100);color:var(--shk-primary-600)}.dark .rail-icon:hover{background:var(--shk-surface-200);color:var(--shk-primary-400)}.rail-icon.is-active{background:var(--shk-primary-600);color:#fff;box-shadow:0 1px 2px #0003}.dark .rail-icon.is-active{background:var(--shk-primary-500);color:#fff}.rail-logout:hover{color:var(--shk-error-500)}.dark .rail-logout:hover{color:var(--shk-error-400)}\n"] }]
3175
3175
  }], ctorParameters: () => [], propDecorators: { sections: [{ type: i0.Input, args: [{ isSignal: true, alias: "sections", required: false }] }], activeUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeUrl", required: false }] }], activeSectionKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeSectionKey", required: false }] }, { type: i0.Output, args: ["activeSectionKeyChange"] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }, { type: i0.Output, args: ["collapsedChange"] }], activeLang: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeLang", required: false }] }], langs: [{ type: i0.Input, args: [{ isSignal: true, alias: "langs", required: false }] }], logo: [{ type: i0.Input, args: [{ isSignal: true, alias: "logo", required: false }] }], appName: [{ type: i0.Input, args: [{ isSignal: true, alias: "appName", required: false }] }], userRole: [{ type: i0.Input, args: [{ isSignal: true, alias: "userRole", required: false }] }], labelPipe: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelPipe", required: false }] }], railWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "railWidth", required: false }] }], expandedWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandedWidth", required: false }] }], workspaceTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "workspaceTooltip", required: false }] }], logoutTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "logoutTooltip", required: false }] }], collapseTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapseTooltip", required: false }] }], expandTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandTooltip", required: false }] }], sectionSelected: [{ type: i0.Output, args: ["sectionSelected"] }], itemClick: [{ type: i0.Output, args: ["itemClick"] }], setLang: [{ type: i0.Output, args: ["setLang"] }], logoutRequested: [{ type: i0.Output, args: ["logoutRequested"] }], toggleSidebar: [{ type: i0.Output, args: ["toggleSidebar"] }], workspaceClick: [{ type: i0.Output, args: ["workspaceClick"] }] } });
3176
3176
 
3177
3177
  class ChartComponent {
@@ -3285,6 +3285,473 @@ function readThemeColors() {
3285
3285
  };
3286
3286
  }
3287
3287
 
3288
+ const icons$2 = {
3289
+ plus: LucidePlus,
3290
+ pencil: LucidePencil,
3291
+ 'trash-2': LucideTrash2,
3292
+ delete: LucideTrash2,
3293
+ 'circle-plus': LucideCirclePlus,
3294
+ 'circle-help': LucideCircleHelp,
3295
+ calendar: LucideCalendar,
3296
+ 'calendar-days': LucideCalendarDays,
3297
+ clock: LucideClock,
3298
+ tag: LucideTag,
3299
+ package: LucidePackage,
3300
+ info: LucideInfo,
3301
+ inbox: LucideInbox,
3302
+ hotel: LucideHotel,
3303
+ ticket: LucideTicket,
3304
+ car: LucideCar,
3305
+ mountain: LucideMountain,
3306
+ bus: LucideBus,
3307
+ ship: LucideShip,
3308
+ shield: LucideShield,
3309
+ utensils: LucideUtensils,
3310
+ 'map-pin': LucideMapPin,
3311
+ 'user-round': LucideUserRound,
3312
+ };
3313
+ function getIcon$2(name) {
3314
+ return icons$2[name] ?? LucideCircleHelp;
3315
+ }
3316
+ const DEFAULT_MARKER_GRADIENTS = [
3317
+ 'bg-gradient-to-br from-blue-500 to-blue-600',
3318
+ 'bg-gradient-to-br from-emerald-500 to-emerald-600',
3319
+ 'bg-gradient-to-br from-violet-500 to-violet-600',
3320
+ 'bg-gradient-to-br from-orange-500 to-orange-600',
3321
+ 'bg-gradient-to-br from-rose-500 to-rose-600',
3322
+ 'bg-gradient-to-br from-cyan-500 to-cyan-600',
3323
+ 'bg-gradient-to-br from-amber-500 to-amber-600',
3324
+ 'bg-gradient-to-br from-indigo-500 to-indigo-600',
3325
+ 'bg-gradient-to-br from-teal-500 to-teal-600',
3326
+ 'bg-gradient-to-br from-pink-500 to-pink-600',
3327
+ ];
3328
+ /** Supplier-type style palette used by the original wac-app timeline. */
3329
+ const DEFAULT_SUPPLIER_ICON_COLORS = {
3330
+ accommodation: { bg: '#3d5a80', text: '#ffffff' },
3331
+ air_tickets: { bg: '#98c1d9', text: '#293241' },
3332
+ rent_a_car: { bg: '#ee6c4d', text: '#ffffff' },
3333
+ excursion: { bg: '#e0fbfc', text: '#293241' },
3334
+ transfer: { bg: '#293241', text: '#ffffff' },
3335
+ cruise: { bg: '#3d5a80', text: '#ffffff' },
3336
+ insurance: { bg: '#98c1d9', text: '#293241' },
3337
+ restaurant: { bg: '#6b7280', text: '#ffffff' },
3338
+ visit: { bg: '#14b8a6', text: '#ffffff' },
3339
+ guide: { bg: '#06b6d4', text: '#ffffff' },
3340
+ package: { bg: '#84cc16', text: '#ffffff' },
3341
+ other: { bg: '#e0fbfc', text: '#293241' },
3342
+ };
3343
+ /** Maps a sub-item `type` to a lucide icon name. */
3344
+ const DEFAULT_SUPPLIER_TYPE_ICONS = {
3345
+ accommodation: 'hotel',
3346
+ air_tickets: 'ticket',
3347
+ rent_a_car: 'car',
3348
+ excursion: 'mountain',
3349
+ transfer: 'bus',
3350
+ cruise: 'ship',
3351
+ insurance: 'shield',
3352
+ restaurant: 'utensils',
3353
+ visit: 'map-pin',
3354
+ guide: 'user-round',
3355
+ package: 'package',
3356
+ other: 'tag',
3357
+ };
3358
+ class TimelineComponent {
3359
+ constructor() {
3360
+ this.getIcon = getIcon$2;
3361
+ /** Timeline data. */
3362
+ this.items = input([], ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
3363
+ // ---------- Layout ----------
3364
+ /** 'left' = line and markers on the left; 'alternate' = cards alternate around a centered line on lg+. */
3365
+ this.alignment = input('alternate', ...(ngDevMode ? [{ debugName: "alignment" }] : /* istanbul ignore next */ []));
3366
+ /** Shows/hides the vertical connector line. */
3367
+ this.showLine = input(true, ...(ngDevMode ? [{ debugName: "showLine" }] : /* istanbul ignore next */ []));
3368
+ /** Marker diameter. */
3369
+ this.markerSize = input('md', ...(ngDevMode ? [{ debugName: "markerSize" }] : /* istanbul ignore next */ []));
3370
+ /** Gradient classes cycled across markers when the item has no `color`. */
3371
+ this.markerGradients = input(DEFAULT_MARKER_GRADIENTS, ...(ngDevMode ? [{ debugName: "markerGradients" }] : /* istanbul ignore next */ []));
3372
+ /** Shows the info column on the opposite side of the card (alternate mode, lg+). */
3373
+ this.showOpposite = input(true, ...(ngDevMode ? [{ debugName: "showOpposite" }] : /* istanbul ignore next */ []));
3374
+ /** Shows the item description. */
3375
+ this.showDescription = input(true, ...(ngDevMode ? [{ debugName: "showDescription" }] : /* istanbul ignore next */ []));
3376
+ /** Shows meta chips inside sub items. */
3377
+ this.showSubItemMeta = input(true, ...(ngDevMode ? [{ debugName: "showSubItemMeta" }] : /* istanbul ignore next */ []));
3378
+ /** Shows the price of each sub item. */
3379
+ this.showSubItemPrice = input(true, ...(ngDevMode ? [{ debugName: "showSubItemPrice" }] : /* istanbul ignore next */ []));
3380
+ /** Auto-append "N {subItemCountLabel}" under the title when the item has no subtitle. */
3381
+ this.showSubItemCount = input(false, ...(ngDevMode ? [{ debugName: "showSubItemCount" }] : /* istanbul ignore next */ []));
3382
+ this.subItemCountLabel = input('elementos', ...(ngDevMode ? [{ debugName: "subItemCountLabel" }] : /* istanbul ignore next */ []));
3383
+ // ---------- Header ----------
3384
+ this.showHeader = input(true, ...(ngDevMode ? [{ debugName: "showHeader" }] : /* istanbul ignore next */ []));
3385
+ this.headerTitle = input('', ...(ngDevMode ? [{ debugName: "headerTitle" }] : /* istanbul ignore next */ []));
3386
+ /** Convenience "add" button in the header. */
3387
+ this.showAddItem = input(false, ...(ngDevMode ? [{ debugName: "showAddItem" }] : /* istanbul ignore next */ []));
3388
+ this.addItemLabel = input('Añadir', ...(ngDevMode ? [{ debugName: "addItemLabel" }] : /* istanbul ignore next */ []));
3389
+ this.addItemIcon = input('plus', ...(ngDevMode ? [{ debugName: "addItemIcon" }] : /* istanbul ignore next */ []));
3390
+ this.addItemTooltip = input('Añadir elemento', ...(ngDevMode ? [{ debugName: "addItemTooltip" }] : /* istanbul ignore next */ []));
3391
+ this.headerActions = input([], ...(ngDevMode ? [{ debugName: "headerActions" }] : /* istanbul ignore next */ []));
3392
+ // ---------- Actions ----------
3393
+ /** Renders "+ Añadir sub-elemento" in each card footer. */
3394
+ this.showAddSubItem = input(false, ...(ngDevMode ? [{ debugName: "showAddSubItem" }] : /* istanbul ignore next */ []));
3395
+ this.addSubItemLabel = input('Añadir', ...(ngDevMode ? [{ debugName: "addSubItemLabel" }] : /* istanbul ignore next */ []));
3396
+ this.addSubItemTooltip = input('Añadir sub-elemento', ...(ngDevMode ? [{ debugName: "addSubItemTooltip" }] : /* istanbul ignore next */ []));
3397
+ this.itemActions = input([], ...(ngDevMode ? [{ debugName: "itemActions" }] : /* istanbul ignore next */ []));
3398
+ this.subItemActions = input([], ...(ngDevMode ? [{ debugName: "subItemActions" }] : /* istanbul ignore next */ []));
3399
+ // ---------- Sub-item icon mapping ----------
3400
+ /** Maps a sub-item `type` to a lucide icon name. */
3401
+ this.iconMap = input({}, ...(ngDevMode ? [{ debugName: "iconMap" }] : /* istanbul ignore next */ []));
3402
+ /** Maps a sub-item `type` to its icon-box colors. */
3403
+ this.iconColors = input({}, ...(ngDevMode ? [{ debugName: "iconColors" }] : /* istanbul ignore next */ []));
3404
+ /** Icon used when nothing matches. */
3405
+ this.fallbackIcon = input('circle-help', ...(ngDevMode ? [{ debugName: "fallbackIcon" }] : /* istanbul ignore next */ []));
3406
+ // ---------- Empty state ----------
3407
+ this.showEmptyState = input(true, ...(ngDevMode ? [{ debugName: "showEmptyState" }] : /* istanbul ignore next */ []));
3408
+ this.emptyMessage = input('Sin elementos', ...(ngDevMode ? [{ debugName: "emptyMessage" }] : /* istanbul ignore next */ []));
3409
+ this.emptyIcon = input('calendar-days', ...(ngDevMode ? [{ debugName: "emptyIcon" }] : /* istanbul ignore next */ []));
3410
+ // ---------- Labels ----------
3411
+ this.editTooltip = input('Editar', ...(ngDevMode ? [{ debugName: "editTooltip" }] : /* istanbul ignore next */ []));
3412
+ this.deleteTooltip = input('Eliminar', ...(ngDevMode ? [{ debugName: "deleteTooltip" }] : /* istanbul ignore next */ []));
3413
+ this.optionalLabel = input('Opcional', ...(ngDevMode ? [{ debugName: "optionalLabel" }] : /* istanbul ignore next */ []));
3414
+ this.noSubItemsMessage = input('', ...(ngDevMode ? [{ debugName: "noSubItemsMessage" }] : /* istanbul ignore next */ []));
3415
+ /** Custom content templates: keys 'marker', 'opposite', 'content', 'description', 'subItem', 'empty'. */
3416
+ this.customTemplates = input({}, ...(ngDevMode ? [{ debugName: "customTemplates" }] : /* istanbul ignore next */ []));
3417
+ // ---------- Outputs ----------
3418
+ this.addItem = output();
3419
+ this.addSubItem = output();
3420
+ this.itemClick = output();
3421
+ this.subItemClick = output();
3422
+ }
3423
+ // ---------- Helpers ----------
3424
+ markerText(item, index) {
3425
+ return item.markerText ?? index + 1;
3426
+ }
3427
+ markerClass(item, index) {
3428
+ const base = 'flex items-center justify-center rounded-full text-white shadow-md';
3429
+ const size = this.markerSize() === 'sm'
3430
+ ? 'w-8 h-8 text-xs'
3431
+ : this.markerSize() === 'lg'
3432
+ ? 'w-12 h-12 text-base'
3433
+ : 'w-10 h-10 text-sm';
3434
+ const color = item.color || this.markerGradients()[index % this.markerGradients().length];
3435
+ return `${base} ${size} ${color}`;
3436
+ }
3437
+ markerColumnClass() {
3438
+ const size = this.markerSize() === 'sm' ? 'w-8' : this.markerSize() === 'lg' ? 'w-12' : 'w-10';
3439
+ return `relative z-10 flex justify-center shrink-0 ${size}`;
3440
+ }
3441
+ alternateMarkerColumnClass() {
3442
+ return `${this.markerColumnClass()} lg:absolute lg:left-1/2 lg:-translate-x-1/2 lg:top-0`;
3443
+ }
3444
+ lineClass() {
3445
+ const pos = this.markerSize() === 'sm' ? 'left-4' : this.markerSize() === 'lg' ? 'left-6' : 'left-5';
3446
+ const base = `absolute top-4 bottom-4 w-px _shk-bg-surface-200 dark:[background-color:var(--shk-surface-200)] ${pos}`;
3447
+ if (this.alignment() === 'alternate') {
3448
+ return `${base} lg:left-1/2 lg:-translate-x-1/2`;
3449
+ }
3450
+ return base;
3451
+ }
3452
+ subItemIconName(sub) {
3453
+ const type = sub.type || '';
3454
+ return sub.icon || this.iconMap()[type] || this.fallbackIcon();
3455
+ }
3456
+ subItemStyle(sub) {
3457
+ const palette = this.iconColors()[sub.type || ''];
3458
+ if (palette)
3459
+ return { 'background-color': palette.bg, color: palette.text };
3460
+ return {
3461
+ 'background-color': sub.color || '#6b7280',
3462
+ color: sub.colorText || '#ffffff',
3463
+ };
3464
+ }
3465
+ // ---------- Header actions ----------
3466
+ isHeaderActionVisible(action) {
3467
+ return action.isVisible ? action.isVisible() : true;
3468
+ }
3469
+ isHeaderActionDisabled(action) {
3470
+ return action.isDisabled ? action.isDisabled() : false;
3471
+ }
3472
+ // ---------- Item actions ----------
3473
+ getItemActionLabel(action, item) {
3474
+ return typeof action.label === 'function' ? action.label(item) : action.label;
3475
+ }
3476
+ getItemActionIconName(action, item) {
3477
+ return typeof action.icon === 'function' ? action.icon(item) : action.icon;
3478
+ }
3479
+ getItemActionClass(action, item) {
3480
+ if (!action.class)
3481
+ return '';
3482
+ return typeof action.class === 'function' ? action.class(item) : action.class;
3483
+ }
3484
+ isItemActionVisible(action, item) {
3485
+ return action.isVisible ? action.isVisible(item) : true;
3486
+ }
3487
+ isItemActionDisabled(action, item) {
3488
+ return action.isDisabled ? action.isDisabled(item) : false;
3489
+ }
3490
+ // ---------- Sub-item actions ----------
3491
+ getSubItemActionLabel(action, item, sub) {
3492
+ return typeof action.label === 'function' ? action.label(item, sub) : action.label;
3493
+ }
3494
+ getSubItemActionIconName(action, item, sub) {
3495
+ return typeof action.icon === 'function' ? action.icon(item, sub) : action.icon;
3496
+ }
3497
+ isSubItemActionVisible(action, item, sub) {
3498
+ return action.isVisible ? action.isVisible(item, sub) : true;
3499
+ }
3500
+ isSubItemActionDisabled(action, item, sub) {
3501
+ return action.isDisabled ? action.isDisabled(item, sub) : false;
3502
+ }
3503
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: TimelineComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3504
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: TimelineComponent, isStandalone: true, selector: "shk-timeline", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, alignment: { classPropertyName: "alignment", publicName: "alignment", isSignal: true, isRequired: false, transformFunction: null }, showLine: { classPropertyName: "showLine", publicName: "showLine", isSignal: true, isRequired: false, transformFunction: null }, markerSize: { classPropertyName: "markerSize", publicName: "markerSize", isSignal: true, isRequired: false, transformFunction: null }, markerGradients: { classPropertyName: "markerGradients", publicName: "markerGradients", isSignal: true, isRequired: false, transformFunction: null }, showOpposite: { classPropertyName: "showOpposite", publicName: "showOpposite", isSignal: true, isRequired: false, transformFunction: null }, showDescription: { classPropertyName: "showDescription", publicName: "showDescription", isSignal: true, isRequired: false, transformFunction: null }, showSubItemMeta: { classPropertyName: "showSubItemMeta", publicName: "showSubItemMeta", isSignal: true, isRequired: false, transformFunction: null }, showSubItemPrice: { classPropertyName: "showSubItemPrice", publicName: "showSubItemPrice", isSignal: true, isRequired: false, transformFunction: null }, showSubItemCount: { classPropertyName: "showSubItemCount", publicName: "showSubItemCount", isSignal: true, isRequired: false, transformFunction: null }, subItemCountLabel: { classPropertyName: "subItemCountLabel", publicName: "subItemCountLabel", isSignal: true, isRequired: false, transformFunction: null }, showHeader: { classPropertyName: "showHeader", publicName: "showHeader", isSignal: true, isRequired: false, transformFunction: null }, headerTitle: { classPropertyName: "headerTitle", publicName: "headerTitle", isSignal: true, isRequired: false, transformFunction: null }, showAddItem: { classPropertyName: "showAddItem", publicName: "showAddItem", isSignal: true, isRequired: false, transformFunction: null }, addItemLabel: { classPropertyName: "addItemLabel", publicName: "addItemLabel", isSignal: true, isRequired: false, transformFunction: null }, addItemIcon: { classPropertyName: "addItemIcon", publicName: "addItemIcon", isSignal: true, isRequired: false, transformFunction: null }, addItemTooltip: { classPropertyName: "addItemTooltip", publicName: "addItemTooltip", isSignal: true, isRequired: false, transformFunction: null }, headerActions: { classPropertyName: "headerActions", publicName: "headerActions", isSignal: true, isRequired: false, transformFunction: null }, showAddSubItem: { classPropertyName: "showAddSubItem", publicName: "showAddSubItem", isSignal: true, isRequired: false, transformFunction: null }, addSubItemLabel: { classPropertyName: "addSubItemLabel", publicName: "addSubItemLabel", isSignal: true, isRequired: false, transformFunction: null }, addSubItemTooltip: { classPropertyName: "addSubItemTooltip", publicName: "addSubItemTooltip", isSignal: true, isRequired: false, transformFunction: null }, itemActions: { classPropertyName: "itemActions", publicName: "itemActions", isSignal: true, isRequired: false, transformFunction: null }, subItemActions: { classPropertyName: "subItemActions", publicName: "subItemActions", isSignal: true, isRequired: false, transformFunction: null }, iconMap: { classPropertyName: "iconMap", publicName: "iconMap", isSignal: true, isRequired: false, transformFunction: null }, iconColors: { classPropertyName: "iconColors", publicName: "iconColors", isSignal: true, isRequired: false, transformFunction: null }, fallbackIcon: { classPropertyName: "fallbackIcon", publicName: "fallbackIcon", isSignal: true, isRequired: false, transformFunction: null }, showEmptyState: { classPropertyName: "showEmptyState", publicName: "showEmptyState", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, emptyIcon: { classPropertyName: "emptyIcon", publicName: "emptyIcon", isSignal: true, isRequired: false, transformFunction: null }, editTooltip: { classPropertyName: "editTooltip", publicName: "editTooltip", isSignal: true, isRequired: false, transformFunction: null }, deleteTooltip: { classPropertyName: "deleteTooltip", publicName: "deleteTooltip", isSignal: true, isRequired: false, transformFunction: null }, optionalLabel: { classPropertyName: "optionalLabel", publicName: "optionalLabel", isSignal: true, isRequired: false, transformFunction: null }, noSubItemsMessage: { classPropertyName: "noSubItemsMessage", publicName: "noSubItemsMessage", isSignal: true, isRequired: false, transformFunction: null }, customTemplates: { classPropertyName: "customTemplates", publicName: "customTemplates", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { addItem: "addItem", addSubItem: "addSubItem", itemClick: "itemClick", subItemClick: "subItemClick" }, ngImport: i0, template: "<div class=\"space-y-4\">\n\n <!-- ============ Header ============ -->\n @if (showHeader() && (headerTitle() || showAddItem() || headerActions().length > 0)) {\n <div class=\"flex flex-wrap items-center justify-between gap-2\">\n @if (headerTitle()) {\n <div class=\"text-sm font-semibold _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\">\n {{ headerTitle() }}\n </div>\n }\n <div class=\"flex items-center gap-1.5 ml-auto\">\n @if (showAddItem()) {\n <button\n type=\"button\"\n (click)=\"addItem.emit()\"\n [attr.aria-label]=\"addItemTooltip()\"\n class=\"inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md _shk-bg-primary text-white hover:[background-color:var(--shk-primary-700)] transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon(addItemIcon())\" class=\"w-3.5 h-3.5\"></svg>\n {{ addItemLabel() }}\n </button>\n }\n @for (action of headerActions(); track $index) {\n @if (isHeaderActionVisible(action)) {\n <button\n type=\"button\"\n [class]=\"action.class || 'inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md _shk-bg-primary text-white hover:[background-color:var(--shk-primary-700)] transition-colors disabled:opacity-50 disabled:cursor-not-allowed'\"\n [disabled]=\"isHeaderActionDisabled(action)\"\n (click)=\"action.onClick()\"\n >\n @if (action.icon) {\n <svg [lucideIcon]=\"getIcon(action.icon)\" class=\"w-3.5 h-3.5\"></svg>\n }\n {{ action.label }}\n </button>\n }\n }\n </div>\n </div>\n }\n\n <!-- ============ Timeline ============ -->\n @if (items().length > 0) {\n <div class=\"relative\">\n @if (showLine()) {\n <div [class]=\"lineClass()\" aria-hidden=\"true\"></div>\n }\n\n @for (item of items(); track item.id; let i = $index) {\n @if (alignment() === 'alternate') {\n <div class=\"relative flex items-start gap-4 lg:grid lg:grid-cols-2 lg:gap-0\">\n <!-- Marker (centered on desktop) -->\n <div [class]=\"alternateMarkerColumnClass()\">\n <span [class]=\"markerClass(item, i)\">\n <ng-container\n *ngTemplateOutlet=\"customTemplates()['marker'] || defaultMarker; context: { $implicit: item, index: i }\"\n ></ng-container>\n </span>\n </div>\n\n <!-- Content card -->\n <div\n class=\"flex-1 min-w-0\"\n [class.lg:order-1]=\"$even\"\n [class.lg:order-2]=\"!$even\"\n [class.lg:pr-12]=\"$even\"\n [class.lg:pl-12]=\"!$even\"\n >\n <ng-container\n *ngTemplateOutlet=\"customTemplates()['content'] || card; context: { $implicit: item, index: i }\"\n ></ng-container>\n </div>\n\n <!-- Opposite info -->\n @if (showOpposite()) {\n <div\n class=\"hidden lg:flex lg:items-center\"\n [class.lg:order-2]=\"$even\"\n [class.lg:order-1]=\"!$even\"\n [class.lg:justify-end]=\"$even\"\n [class.lg:pl-12]=\"!$even\"\n >\n <ng-container\n *ngTemplateOutlet=\"customTemplates()['opposite'] || itemInfo; context: { $implicit: item, index: i }\"\n ></ng-container>\n </div>\n }\n </div>\n } @else {\n <!-- Left alignment -->\n <div class=\"relative flex items-start gap-4\">\n <div [class]=\"markerColumnClass()\">\n <span [class]=\"markerClass(item, i)\">\n <ng-container\n *ngTemplateOutlet=\"customTemplates()['marker'] || defaultMarker; context: { $implicit: item, index: i }\"\n ></ng-container>\n </span>\n </div>\n <div class=\"flex-1 min-w-0\">\n <ng-container\n *ngTemplateOutlet=\"customTemplates()['content'] || card; context: { $implicit: item, index: i }\"\n ></ng-container>\n </div>\n </div>\n }\n }\n </div>\n } @else if (showEmptyState()) {\n <!-- ============ Empty state ============ -->\n <div class=\"text-center py-12\">\n @if (customTemplates()['empty']) {\n <ng-container *ngTemplateOutlet=\"customTemplates()['empty']\"></ng-container>\n } @else {\n <div class=\"w-16 h-16 mx-auto mb-4 _shk-bg-surface-100 dark:[background-color:var(--shk-surface-100)] rounded-full flex items-center justify-center\">\n <svg [lucideIcon]=\"getIcon(emptyIcon())\" class=\"w-8 h-8 _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\"></svg>\n </div>\n <p class=\"text-sm _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\">{{ emptyMessage() }}</p>\n }\n </div>\n }\n\n <!-- ============ Templates ============ -->\n\n <ng-template #defaultMarker let-item let-index=\"index\">\n <span class=\"font-bold\">{{ markerText(item, index) }}</span>\n </ng-template>\n\n <ng-template #itemInfo let-item>\n <div>\n @if (item.badge !== undefined && item.badge !== null && item.badge !== '') {\n <div class=\"mb-2\">\n <span class=\"inline-flex items-center gap-1 px-2.5 py-1 rounded-full text-xs font-semibold _shk-bg-surface-100 dark:[background-color:var(--shk-surface-200)] _shk-text-surface-600 dark:[color:var(--shk-surface-600)]\">\n @if (item.badgeIcon) {\n <svg [lucideIcon]=\"getIcon(item.badgeIcon)\" class=\"w-3 h-3\"></svg>\n }\n {{ item.badge }}\n </span>\n </div>\n }\n @if (item.title) {\n <div class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\">{{ item.title }}</div>\n }\n @let subCount = (item.subItems?.length || 0);\n @if (item.subtitle || (showSubItemCount() && subCount > 0)) {\n <div class=\"text-xs _shk-text-surface-400 dark:[color:var(--shk-surface-500)] mt-1\">\n {{ item.subtitle || (subCount + ' ' + subItemCountLabel()) }}\n </div>\n }\n </div>\n </ng-template>\n\n <ng-template #card let-item>\n @let subItems = item.subItems || [];\n <div class=\"shk-timeline-card mb-4 bg-white dark:[background-color:var(--shk-surface-50)] rounded-xl border _shk-border dark:[border-color:var(--shk-surface-200)] shadow-sm overflow-hidden\">\n <!-- Header (mobile in alternate, always in left) -->\n <div class=\"flex items-center gap-2 px-4 pt-4 pb-2\" [class.lg:hidden]=\"alignment() === 'alternate'\">\n <ng-container *ngTemplateOutlet=\"itemInfo; context: { $implicit: item }\"></ng-container>\n </div>\n\n <!-- Description -->\n @if (showDescription() && item.description) {\n <div class=\"px-4 pt-3\">\n @if (customTemplates()['description']) {\n <ng-container *ngTemplateOutlet=\"customTemplates()['description']; context: { $implicit: item }\"></ng-container>\n } @else {\n <p class=\"text-sm _shk-text-surface-600 dark:[color:var(--shk-surface-600)] leading-relaxed\">{{ item.description }}</p>\n }\n </div>\n }\n\n <!-- Sub items -->\n @if (subItems.length > 0) {\n <div class=\"mt-2\">\n @for (sub of subItems; track sub.id) {\n <ng-container\n *ngTemplateOutlet=\"customTemplates()['subItem'] || defaultSubItem; context: { $implicit: item, subItem: sub }\"\n ></ng-container>\n }\n </div>\n } @else if (noSubItemsMessage()) {\n <div class=\"px-4 py-6 text-center\">\n <div class=\"inline-flex items-center gap-2 text-sm _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\">\n <svg [lucideIcon]=\"getIcon('info')\" class=\"w-4 h-4\"></svg>\n <span class=\"italic\">{{ noSubItemsMessage() }}</span>\n </div>\n </div>\n }\n\n <!-- Footer actions -->\n @if (showAddSubItem() || itemActions().length > 0) {\n <div class=\"flex items-center gap-1 px-4 py-2 _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] border-t _shk-border dark:[border-color:var(--shk-surface-100)]\">\n @if (showAddSubItem()) {\n <button\n type=\"button\"\n (click)=\"addSubItem.emit(item)\"\n class=\"relative group inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium _shk-text-primary hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] rounded-lg transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('circle-plus')\" class=\"w-3.5 h-3.5\"></svg>\n {{ addSubItemLabel() }}\n <span class=\"absolute bottom-full left-1/2 -translate-x-1/2 mb-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ addSubItemTooltip() }}\n </span>\n </button>\n }\n <div class=\"flex-1\"></div>\n @for (action of itemActions(); track $index) {\n @if (isItemActionVisible(action, item)) {\n <div class=\"relative group\">\n <button\n type=\"button\"\n (click)=\"action.onClick(item)\"\n [class]=\"'timeline-icon-btn ' + getItemActionClass(action, item)\"\n [disabled]=\"isItemActionDisabled(action, item)\"\n [attr.aria-label]=\"getItemActionLabel(action, item)\"\n >\n <svg [lucideIcon]=\"getIcon(getItemActionIconName(action, item))\" class=\"w-3.5 h-3.5\"></svg>\n </button>\n <span class=\"absolute bottom-full left-1/2 -translate-x-1/2 mb-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ getItemActionLabel(action, item) }}\n </span>\n </div>\n }\n }\n </div>\n }\n </div>\n </ng-template>\n\n <ng-template #defaultSubItem let-item let-sub=\"subItem\">\n <div class=\"px-4 py-3 border-t [border-color:var(--shk-surface-100)] dark:[border-color:var(--shk-surface-700)] hover:[background-color:color-mix(in srgb,var(--shk-primary-50)30%,transparent)] dark:hover:[background-color:color-mix(in srgb,var(--shk-primary-900)10%,transparent)] transition-colors duration-200 group\">\n <div class=\"flex items-start gap-3\">\n <span\n [class]=\"sub.iconClass || 'flex items-center justify-center w-9 h-9 rounded-lg shrink-0 mt-0.5'\"\n [style]=\"sub.iconClass ? undefined : subItemStyle(sub)\"\n >\n <svg [lucideIcon]=\"getIcon(subItemIconName(sub))\" class=\"w-4 h-4\"></svg>\n </span>\n\n <div class=\"flex-1 min-w-0\">\n <div class=\"flex items-center gap-2 flex-wrap\">\n @if (sub.optional) {\n <span class=\"text-[10px] font-semibold uppercase tracking-wide px-1.5 py-0.5 rounded _shk-bg-amber-soft _shk-text-amber-600 dark:[color:var(--shk-amber-400)]\">\n {{ sub.optionalLabel || optionalLabel() }}\n </span>\n }\n <span class=\"font-medium _shk-text-surface-800 dark:[color:var(--shk-surface-800)] text-sm truncate\">{{ sub.title }}</span>\n @if (sub.subtitle) {\n <span class=\"text-xs _shk-text-surface-400 dark:[color:var(--shk-surface-500)] truncate\">\u00B7 {{ sub.subtitle }}</span>\n }\n </div>\n\n @if (showSubItemMeta() && (sub.meta?.length || 0) > 0) {\n <div class=\"flex flex-wrap items-center gap-x-3 gap-y-1 mt-1.5 text-xs _shk-text-surface-500 dark:[color:var(--shk-surface-500)]\">\n @for (m of sub.meta!; track $index) {\n <span class=\"flex items-center gap-1\">\n <svg [lucideIcon]=\"getIcon(m.icon)\" class=\"w-3 h-3\"></svg>\n @if (m.label) {\n <span class=\"font-medium\">{{ m.label }}:</span>\n }\n {{ m.value }}\n </span>\n }\n </div>\n }\n </div>\n\n <div class=\"flex items-center gap-0.5 shrink-0\">\n @if (showSubItemPrice() && sub.price !== undefined && sub.price !== null && sub.price !== '') {\n <span class=\"font-semibold _shk-text-surface-700 dark:[color:var(--shk-surface-700)] text-xs mr-1\">{{ sub.price }}</span>\n }\n @for (action of subItemActions(); track $index) {\n @if (isSubItemActionVisible(action, item, sub)) {\n <div class=\"relative group\">\n <button\n type=\"button\"\n (click)=\"action.onClick(item, sub)\"\n class=\"timeline-icon-btn opacity-100 lg:opacity-0 lg:group-hover:opacity-100 transition-opacity\"\n [disabled]=\"isSubItemActionDisabled(action, item, sub)\"\n [attr.aria-label]=\"getSubItemActionLabel(action, item, sub)\"\n >\n <svg [lucideIcon]=\"getIcon(getSubItemActionIconName(action, item, sub))\" class=\"w-3.5 h-3.5\"></svg>\n </button>\n <span class=\"absolute top-full left-1/2 -translate-x-1/2 mt-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ getSubItemActionLabel(action, item, sub) }}\n </span>\n </div>\n }\n }\n </div>\n </div>\n </div>\n </ng-template>\n\n</div>\n", styles: [":host{display:block}.timeline-icon-btn{padding:.375rem;display:inline-flex;align-items:center;justify-content:center;border-radius:.5rem;color:var(--shk-primary-600);transition:background-color .15s ease-in-out,color .15s ease-in-out,opacity .15s ease-in-out}.timeline-icon-btn:hover:not(:disabled){background-color:color-mix(in srgb,var(--shk-primary-50) 60%,transparent);color:var(--shk-primary-700)}.timeline-icon-btn:disabled{opacity:.4;cursor:not-allowed}.timeline-icon-btn svg{width:.875rem!important;height:.875rem!important}.shk-timeline-card{animation:shk-timeline-fade-in .3s ease-out}@keyframes shk-timeline-fade-in{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: LucideDynamicIcon, selector: "svg[lucideIcon]", inputs: ["lucideIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3505
+ }
3506
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: TimelineComponent, decorators: [{
3507
+ type: Component,
3508
+ args: [{ selector: 'shk-timeline', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, LucideDynamicIcon], template: "<div class=\"space-y-4\">\n\n <!-- ============ Header ============ -->\n @if (showHeader() && (headerTitle() || showAddItem() || headerActions().length > 0)) {\n <div class=\"flex flex-wrap items-center justify-between gap-2\">\n @if (headerTitle()) {\n <div class=\"text-sm font-semibold _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\">\n {{ headerTitle() }}\n </div>\n }\n <div class=\"flex items-center gap-1.5 ml-auto\">\n @if (showAddItem()) {\n <button\n type=\"button\"\n (click)=\"addItem.emit()\"\n [attr.aria-label]=\"addItemTooltip()\"\n class=\"inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md _shk-bg-primary text-white hover:[background-color:var(--shk-primary-700)] transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon(addItemIcon())\" class=\"w-3.5 h-3.5\"></svg>\n {{ addItemLabel() }}\n </button>\n }\n @for (action of headerActions(); track $index) {\n @if (isHeaderActionVisible(action)) {\n <button\n type=\"button\"\n [class]=\"action.class || 'inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md _shk-bg-primary text-white hover:[background-color:var(--shk-primary-700)] transition-colors disabled:opacity-50 disabled:cursor-not-allowed'\"\n [disabled]=\"isHeaderActionDisabled(action)\"\n (click)=\"action.onClick()\"\n >\n @if (action.icon) {\n <svg [lucideIcon]=\"getIcon(action.icon)\" class=\"w-3.5 h-3.5\"></svg>\n }\n {{ action.label }}\n </button>\n }\n }\n </div>\n </div>\n }\n\n <!-- ============ Timeline ============ -->\n @if (items().length > 0) {\n <div class=\"relative\">\n @if (showLine()) {\n <div [class]=\"lineClass()\" aria-hidden=\"true\"></div>\n }\n\n @for (item of items(); track item.id; let i = $index) {\n @if (alignment() === 'alternate') {\n <div class=\"relative flex items-start gap-4 lg:grid lg:grid-cols-2 lg:gap-0\">\n <!-- Marker (centered on desktop) -->\n <div [class]=\"alternateMarkerColumnClass()\">\n <span [class]=\"markerClass(item, i)\">\n <ng-container\n *ngTemplateOutlet=\"customTemplates()['marker'] || defaultMarker; context: { $implicit: item, index: i }\"\n ></ng-container>\n </span>\n </div>\n\n <!-- Content card -->\n <div\n class=\"flex-1 min-w-0\"\n [class.lg:order-1]=\"$even\"\n [class.lg:order-2]=\"!$even\"\n [class.lg:pr-12]=\"$even\"\n [class.lg:pl-12]=\"!$even\"\n >\n <ng-container\n *ngTemplateOutlet=\"customTemplates()['content'] || card; context: { $implicit: item, index: i }\"\n ></ng-container>\n </div>\n\n <!-- Opposite info -->\n @if (showOpposite()) {\n <div\n class=\"hidden lg:flex lg:items-center\"\n [class.lg:order-2]=\"$even\"\n [class.lg:order-1]=\"!$even\"\n [class.lg:justify-end]=\"$even\"\n [class.lg:pl-12]=\"!$even\"\n >\n <ng-container\n *ngTemplateOutlet=\"customTemplates()['opposite'] || itemInfo; context: { $implicit: item, index: i }\"\n ></ng-container>\n </div>\n }\n </div>\n } @else {\n <!-- Left alignment -->\n <div class=\"relative flex items-start gap-4\">\n <div [class]=\"markerColumnClass()\">\n <span [class]=\"markerClass(item, i)\">\n <ng-container\n *ngTemplateOutlet=\"customTemplates()['marker'] || defaultMarker; context: { $implicit: item, index: i }\"\n ></ng-container>\n </span>\n </div>\n <div class=\"flex-1 min-w-0\">\n <ng-container\n *ngTemplateOutlet=\"customTemplates()['content'] || card; context: { $implicit: item, index: i }\"\n ></ng-container>\n </div>\n </div>\n }\n }\n </div>\n } @else if (showEmptyState()) {\n <!-- ============ Empty state ============ -->\n <div class=\"text-center py-12\">\n @if (customTemplates()['empty']) {\n <ng-container *ngTemplateOutlet=\"customTemplates()['empty']\"></ng-container>\n } @else {\n <div class=\"w-16 h-16 mx-auto mb-4 _shk-bg-surface-100 dark:[background-color:var(--shk-surface-100)] rounded-full flex items-center justify-center\">\n <svg [lucideIcon]=\"getIcon(emptyIcon())\" class=\"w-8 h-8 _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\"></svg>\n </div>\n <p class=\"text-sm _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\">{{ emptyMessage() }}</p>\n }\n </div>\n }\n\n <!-- ============ Templates ============ -->\n\n <ng-template #defaultMarker let-item let-index=\"index\">\n <span class=\"font-bold\">{{ markerText(item, index) }}</span>\n </ng-template>\n\n <ng-template #itemInfo let-item>\n <div>\n @if (item.badge !== undefined && item.badge !== null && item.badge !== '') {\n <div class=\"mb-2\">\n <span class=\"inline-flex items-center gap-1 px-2.5 py-1 rounded-full text-xs font-semibold _shk-bg-surface-100 dark:[background-color:var(--shk-surface-200)] _shk-text-surface-600 dark:[color:var(--shk-surface-600)]\">\n @if (item.badgeIcon) {\n <svg [lucideIcon]=\"getIcon(item.badgeIcon)\" class=\"w-3 h-3\"></svg>\n }\n {{ item.badge }}\n </span>\n </div>\n }\n @if (item.title) {\n <div class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\">{{ item.title }}</div>\n }\n @let subCount = (item.subItems?.length || 0);\n @if (item.subtitle || (showSubItemCount() && subCount > 0)) {\n <div class=\"text-xs _shk-text-surface-400 dark:[color:var(--shk-surface-500)] mt-1\">\n {{ item.subtitle || (subCount + ' ' + subItemCountLabel()) }}\n </div>\n }\n </div>\n </ng-template>\n\n <ng-template #card let-item>\n @let subItems = item.subItems || [];\n <div class=\"shk-timeline-card mb-4 bg-white dark:[background-color:var(--shk-surface-50)] rounded-xl border _shk-border dark:[border-color:var(--shk-surface-200)] shadow-sm overflow-hidden\">\n <!-- Header (mobile in alternate, always in left) -->\n <div class=\"flex items-center gap-2 px-4 pt-4 pb-2\" [class.lg:hidden]=\"alignment() === 'alternate'\">\n <ng-container *ngTemplateOutlet=\"itemInfo; context: { $implicit: item }\"></ng-container>\n </div>\n\n <!-- Description -->\n @if (showDescription() && item.description) {\n <div class=\"px-4 pt-3\">\n @if (customTemplates()['description']) {\n <ng-container *ngTemplateOutlet=\"customTemplates()['description']; context: { $implicit: item }\"></ng-container>\n } @else {\n <p class=\"text-sm _shk-text-surface-600 dark:[color:var(--shk-surface-600)] leading-relaxed\">{{ item.description }}</p>\n }\n </div>\n }\n\n <!-- Sub items -->\n @if (subItems.length > 0) {\n <div class=\"mt-2\">\n @for (sub of subItems; track sub.id) {\n <ng-container\n *ngTemplateOutlet=\"customTemplates()['subItem'] || defaultSubItem; context: { $implicit: item, subItem: sub }\"\n ></ng-container>\n }\n </div>\n } @else if (noSubItemsMessage()) {\n <div class=\"px-4 py-6 text-center\">\n <div class=\"inline-flex items-center gap-2 text-sm _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\">\n <svg [lucideIcon]=\"getIcon('info')\" class=\"w-4 h-4\"></svg>\n <span class=\"italic\">{{ noSubItemsMessage() }}</span>\n </div>\n </div>\n }\n\n <!-- Footer actions -->\n @if (showAddSubItem() || itemActions().length > 0) {\n <div class=\"flex items-center gap-1 px-4 py-2 _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] border-t _shk-border dark:[border-color:var(--shk-surface-100)]\">\n @if (showAddSubItem()) {\n <button\n type=\"button\"\n (click)=\"addSubItem.emit(item)\"\n class=\"relative group inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium _shk-text-primary hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] rounded-lg transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('circle-plus')\" class=\"w-3.5 h-3.5\"></svg>\n {{ addSubItemLabel() }}\n <span class=\"absolute bottom-full left-1/2 -translate-x-1/2 mb-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ addSubItemTooltip() }}\n </span>\n </button>\n }\n <div class=\"flex-1\"></div>\n @for (action of itemActions(); track $index) {\n @if (isItemActionVisible(action, item)) {\n <div class=\"relative group\">\n <button\n type=\"button\"\n (click)=\"action.onClick(item)\"\n [class]=\"'timeline-icon-btn ' + getItemActionClass(action, item)\"\n [disabled]=\"isItemActionDisabled(action, item)\"\n [attr.aria-label]=\"getItemActionLabel(action, item)\"\n >\n <svg [lucideIcon]=\"getIcon(getItemActionIconName(action, item))\" class=\"w-3.5 h-3.5\"></svg>\n </button>\n <span class=\"absolute bottom-full left-1/2 -translate-x-1/2 mb-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ getItemActionLabel(action, item) }}\n </span>\n </div>\n }\n }\n </div>\n }\n </div>\n </ng-template>\n\n <ng-template #defaultSubItem let-item let-sub=\"subItem\">\n <div class=\"px-4 py-3 border-t [border-color:var(--shk-surface-100)] dark:[border-color:var(--shk-surface-700)] hover:[background-color:color-mix(in srgb,var(--shk-primary-50)30%,transparent)] dark:hover:[background-color:color-mix(in srgb,var(--shk-primary-900)10%,transparent)] transition-colors duration-200 group\">\n <div class=\"flex items-start gap-3\">\n <span\n [class]=\"sub.iconClass || 'flex items-center justify-center w-9 h-9 rounded-lg shrink-0 mt-0.5'\"\n [style]=\"sub.iconClass ? undefined : subItemStyle(sub)\"\n >\n <svg [lucideIcon]=\"getIcon(subItemIconName(sub))\" class=\"w-4 h-4\"></svg>\n </span>\n\n <div class=\"flex-1 min-w-0\">\n <div class=\"flex items-center gap-2 flex-wrap\">\n @if (sub.optional) {\n <span class=\"text-[10px] font-semibold uppercase tracking-wide px-1.5 py-0.5 rounded _shk-bg-amber-soft _shk-text-amber-600 dark:[color:var(--shk-amber-400)]\">\n {{ sub.optionalLabel || optionalLabel() }}\n </span>\n }\n <span class=\"font-medium _shk-text-surface-800 dark:[color:var(--shk-surface-800)] text-sm truncate\">{{ sub.title }}</span>\n @if (sub.subtitle) {\n <span class=\"text-xs _shk-text-surface-400 dark:[color:var(--shk-surface-500)] truncate\">\u00B7 {{ sub.subtitle }}</span>\n }\n </div>\n\n @if (showSubItemMeta() && (sub.meta?.length || 0) > 0) {\n <div class=\"flex flex-wrap items-center gap-x-3 gap-y-1 mt-1.5 text-xs _shk-text-surface-500 dark:[color:var(--shk-surface-500)]\">\n @for (m of sub.meta!; track $index) {\n <span class=\"flex items-center gap-1\">\n <svg [lucideIcon]=\"getIcon(m.icon)\" class=\"w-3 h-3\"></svg>\n @if (m.label) {\n <span class=\"font-medium\">{{ m.label }}:</span>\n }\n {{ m.value }}\n </span>\n }\n </div>\n }\n </div>\n\n <div class=\"flex items-center gap-0.5 shrink-0\">\n @if (showSubItemPrice() && sub.price !== undefined && sub.price !== null && sub.price !== '') {\n <span class=\"font-semibold _shk-text-surface-700 dark:[color:var(--shk-surface-700)] text-xs mr-1\">{{ sub.price }}</span>\n }\n @for (action of subItemActions(); track $index) {\n @if (isSubItemActionVisible(action, item, sub)) {\n <div class=\"relative group\">\n <button\n type=\"button\"\n (click)=\"action.onClick(item, sub)\"\n class=\"timeline-icon-btn opacity-100 lg:opacity-0 lg:group-hover:opacity-100 transition-opacity\"\n [disabled]=\"isSubItemActionDisabled(action, item, sub)\"\n [attr.aria-label]=\"getSubItemActionLabel(action, item, sub)\"\n >\n <svg [lucideIcon]=\"getIcon(getSubItemActionIconName(action, item, sub))\" class=\"w-3.5 h-3.5\"></svg>\n </button>\n <span class=\"absolute top-full left-1/2 -translate-x-1/2 mt-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ getSubItemActionLabel(action, item, sub) }}\n </span>\n </div>\n }\n }\n </div>\n </div>\n </div>\n </ng-template>\n\n</div>\n", styles: [":host{display:block}.timeline-icon-btn{padding:.375rem;display:inline-flex;align-items:center;justify-content:center;border-radius:.5rem;color:var(--shk-primary-600);transition:background-color .15s ease-in-out,color .15s ease-in-out,opacity .15s ease-in-out}.timeline-icon-btn:hover:not(:disabled){background-color:color-mix(in srgb,var(--shk-primary-50) 60%,transparent);color:var(--shk-primary-700)}.timeline-icon-btn:disabled{opacity:.4;cursor:not-allowed}.timeline-icon-btn svg{width:.875rem!important;height:.875rem!important}.shk-timeline-card{animation:shk-timeline-fade-in .3s ease-out}@keyframes shk-timeline-fade-in{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}\n"] }]
3509
+ }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], alignment: [{ type: i0.Input, args: [{ isSignal: true, alias: "alignment", required: false }] }], showLine: [{ type: i0.Input, args: [{ isSignal: true, alias: "showLine", required: false }] }], markerSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "markerSize", required: false }] }], markerGradients: [{ type: i0.Input, args: [{ isSignal: true, alias: "markerGradients", required: false }] }], showOpposite: [{ type: i0.Input, args: [{ isSignal: true, alias: "showOpposite", required: false }] }], showDescription: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDescription", required: false }] }], showSubItemMeta: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSubItemMeta", required: false }] }], showSubItemPrice: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSubItemPrice", required: false }] }], showSubItemCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSubItemCount", required: false }] }], subItemCountLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "subItemCountLabel", required: false }] }], showHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "showHeader", required: false }] }], headerTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerTitle", required: false }] }], showAddItem: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAddItem", required: false }] }], addItemLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "addItemLabel", required: false }] }], addItemIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "addItemIcon", required: false }] }], addItemTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "addItemTooltip", required: false }] }], headerActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerActions", required: false }] }], showAddSubItem: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAddSubItem", required: false }] }], addSubItemLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "addSubItemLabel", required: false }] }], addSubItemTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "addSubItemTooltip", required: false }] }], itemActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemActions", required: false }] }], subItemActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "subItemActions", required: false }] }], iconMap: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconMap", required: false }] }], iconColors: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconColors", required: false }] }], fallbackIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "fallbackIcon", required: false }] }], showEmptyState: [{ type: i0.Input, args: [{ isSignal: true, alias: "showEmptyState", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], emptyIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyIcon", required: false }] }], editTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "editTooltip", required: false }] }], deleteTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "deleteTooltip", required: false }] }], optionalLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionalLabel", required: false }] }], noSubItemsMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "noSubItemsMessage", required: false }] }], customTemplates: [{ type: i0.Input, args: [{ isSignal: true, alias: "customTemplates", required: false }] }], addItem: [{ type: i0.Output, args: ["addItem"] }], addSubItem: [{ type: i0.Output, args: ["addSubItem"] }], itemClick: [{ type: i0.Output, args: ["itemClick"] }], subItemClick: [{ type: i0.Output, args: ["subItemClick"] }] } });
3510
+
3511
+ const icons$1 = {
3512
+ 'chevron-down': LucideChevronDown,
3513
+ 'chevron-right': LucideChevronRight,
3514
+ plus: LucidePlus,
3515
+ pencil: LucidePencil,
3516
+ 'trash-2': LucideTrash2,
3517
+ info: LucideInfo,
3518
+ };
3519
+ function getIcon$1(name) {
3520
+ return icons$1[name] ?? LucideChevronRight;
3521
+ }
3522
+ let fieldsetCounter = 0;
3523
+ class FieldsetComponent {
3524
+ constructor() {
3525
+ this.getIcon = getIcon$1;
3526
+ /** Title shown in the header. */
3527
+ this.legend = input('', ...(ngDevMode ? [{ debugName: "legend" }] : /* istanbul ignore next */ []));
3528
+ /** Collapsed state (default: collapsed). Two-way bindable with [(collapsed)]. */
3529
+ this.collapsed = model(true, ...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
3530
+ /** Whether the header toggles the content. */
3531
+ this.toggleable = input(true, ...(ngDevMode ? [{ debugName: "toggleable" }] : /* istanbul ignore next */ []));
3532
+ /** Shows the expand/collapse icon button. */
3533
+ this.showToggleIcon = input(true, ...(ngDevMode ? [{ debugName: "showToggleIcon" }] : /* istanbul ignore next */ []));
3534
+ /** Optional leading icon shown next to the legend. */
3535
+ this.icon = input('', ...(ngDevMode ? [{ debugName: "icon" }] : /* istanbul ignore next */ []));
3536
+ /** Optional badge/count shown after the legend. */
3537
+ this.badge = input('', ...(ngDevMode ? [{ debugName: "badge" }] : /* istanbul ignore next */ []));
3538
+ /** CSS classes for the badge (override). */
3539
+ this.badgeClass = input('', ...(ngDevMode ? [{ debugName: "badgeClass" }] : /* istanbul ignore next */ []));
3540
+ /** Icon shown when collapsed. */
3541
+ this.collapsedIcon = input('chevron-right', ...(ngDevMode ? [{ debugName: "collapsedIcon" }] : /* istanbul ignore next */ []));
3542
+ /** Icon shown when expanded. */
3543
+ this.expandedIcon = input('chevron-down', ...(ngDevMode ? [{ debugName: "expandedIcon" }] : /* istanbul ignore next */ []));
3544
+ /** Action buttons rendered on the right side of the header. */
3545
+ this.headerActions = input([], ...(ngDevMode ? [{ debugName: "headerActions" }] : /* istanbul ignore next */ []));
3546
+ /** Custom content templates: key 'legend' (context: $implicit collapsed, expanded). */
3547
+ this.customTemplates = input({}, ...(ngDevMode ? [{ debugName: "customTemplates" }] : /* istanbul ignore next */ []));
3548
+ this.hasShadow = input(true, ...(ngDevMode ? [{ debugName: "hasShadow" }] : /* istanbul ignore next */ []));
3549
+ this.expandLabel = input('Expandir', ...(ngDevMode ? [{ debugName: "expandLabel" }] : /* istanbul ignore next */ []));
3550
+ this.collapseLabel = input('Colapsar', ...(ngDevMode ? [{ debugName: "collapseLabel" }] : /* istanbul ignore next */ []));
3551
+ /** Emits the new expanded state when toggled. */
3552
+ this.toggle = output();
3553
+ this.expand = output();
3554
+ this.collapse = output();
3555
+ this.contentId = `shk-fieldset-content-${++fieldsetCounter}`;
3556
+ }
3557
+ onToggle() {
3558
+ if (!this.toggleable())
3559
+ return;
3560
+ const wasCollapsed = this.collapsed();
3561
+ const nowExpanded = wasCollapsed;
3562
+ this.collapsed.set(!wasCollapsed);
3563
+ this.toggle.emit(nowExpanded);
3564
+ if (nowExpanded) {
3565
+ this.expand.emit();
3566
+ }
3567
+ else {
3568
+ this.collapse.emit();
3569
+ }
3570
+ }
3571
+ isHeaderActionVisible(action) {
3572
+ return action.isVisible ? action.isVisible() : true;
3573
+ }
3574
+ isHeaderActionDisabled(action) {
3575
+ return action.isDisabled ? action.isDisabled() : false;
3576
+ }
3577
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: FieldsetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3578
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: FieldsetComponent, isStandalone: true, selector: "shk-fieldset", inputs: { legend: { classPropertyName: "legend", publicName: "legend", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, toggleable: { classPropertyName: "toggleable", publicName: "toggleable", isSignal: true, isRequired: false, transformFunction: null }, showToggleIcon: { classPropertyName: "showToggleIcon", publicName: "showToggleIcon", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, badge: { classPropertyName: "badge", publicName: "badge", isSignal: true, isRequired: false, transformFunction: null }, badgeClass: { classPropertyName: "badgeClass", publicName: "badgeClass", isSignal: true, isRequired: false, transformFunction: null }, collapsedIcon: { classPropertyName: "collapsedIcon", publicName: "collapsedIcon", isSignal: true, isRequired: false, transformFunction: null }, expandedIcon: { classPropertyName: "expandedIcon", publicName: "expandedIcon", isSignal: true, isRequired: false, transformFunction: null }, headerActions: { classPropertyName: "headerActions", publicName: "headerActions", isSignal: true, isRequired: false, transformFunction: null }, customTemplates: { classPropertyName: "customTemplates", publicName: "customTemplates", isSignal: true, isRequired: false, transformFunction: null }, hasShadow: { classPropertyName: "hasShadow", publicName: "hasShadow", isSignal: true, isRequired: false, transformFunction: null }, expandLabel: { classPropertyName: "expandLabel", publicName: "expandLabel", isSignal: true, isRequired: false, transformFunction: null }, collapseLabel: { classPropertyName: "collapseLabel", publicName: "collapseLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { collapsed: "collapsedChange", toggle: "toggle", expand: "expand", collapse: "collapse" }, ngImport: i0, template: "<div\n class=\"rounded-xl bg-white dark:[background-color:var(--shk-surface-50)] border _shk-border dark:[border-color:var(--shk-surface-200)] overflow-hidden\"\n [class.shadow-sm]=\"hasShadow()\"\n>\n <div\n class=\"flex items-center gap-2 px-4 py-3\"\n [class.border-b]=\"!collapsed()\"\n [class._shk-border]=\"!collapsed()\"\n [class.dark:[border-color:var(--shk-surface-200)]]=\"!collapsed()\"\n >\n <button\n type=\"button\"\n (click)=\"onToggle()\"\n [disabled]=\"!toggleable()\"\n [attr.aria-expanded]=\"!collapsed()\"\n [attr.aria-controls]=\"contentId\"\n class=\"flex items-center gap-2 flex-1 min-w-0 text-left group disabled:cursor-default\"\n >\n @if (customTemplates()['legend']) {\n <ng-container\n *ngTemplateOutlet=\"customTemplates()['legend']; context: { $implicit: collapsed(), expanded: !collapsed() }\"\n ></ng-container>\n } @else {\n @if (icon()) {\n <svg [lucideIcon]=\"getIcon(icon())\" class=\"w-4 h-4 _shk-text-primary shrink-0\"></svg>\n }\n <span class=\"font-semibold text-sm _shk-text-surface-800 dark:[color:var(--shk-surface-800)] truncate\">\n {{ legend() }}\n </span>\n @if (badge() !== undefined && badge() !== null && badge() !== '') {\n <span\n [class]=\"badgeClass() || 'inline-flex items-center px-2 py-0.5 rounded-full text-xs font-semibold _shk-bg-primary-soft _shk-text-primary-700 dark:[background-color:var(--shk-primary-900)] dark:[color:var(--shk-primary-300)] shrink-0'\"\n >\n {{ badge() }}\n </span>\n }\n }\n </button>\n\n @if (headerActions().length > 0) {\n <div class=\"flex items-center gap-0.5 shrink-0\">\n @for (action of headerActions(); track $index) {\n @if (isHeaderActionVisible(action)) {\n <div class=\"relative group\">\n <button\n type=\"button\"\n (click)=\"action.onClick()\"\n [class]=\"'fieldset-action-btn ' + (action.class || '')\"\n [disabled]=\"isHeaderActionDisabled(action)\"\n [attr.aria-label]=\"action.label\"\n >\n <svg [lucideIcon]=\"getIcon(action.icon)\" class=\"w-3.5 h-3.5\"></svg>\n </button>\n <span class=\"absolute bottom-full left-1/2 -translate-x-1/2 mb-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ action.label }}\n </span>\n </div>\n }\n }\n </div>\n }\n\n @if (toggleable() && showToggleIcon()) {\n <button\n type=\"button\"\n (click)=\"onToggle()\"\n [attr.aria-label]=\"collapsed() ? expandLabel() : collapseLabel()\"\n class=\"shk-fieldset-toggle shrink-0\"\n [disabled]=\"!toggleable()\"\n >\n <svg [lucideIcon]=\"getIcon(collapsed() ? collapsedIcon() : expandedIcon())\" class=\"w-4 h-4 transition-transform\"></svg>\n </button>\n }\n </div>\n\n @if (!collapsed()) {\n <div [id]=\"contentId\" class=\"shk-fieldset-content px-4 py-3.5\">\n <ng-content></ng-content>\n </div>\n }\n</div>\n", styles: [":host{display:block}.shk-fieldset-toggle{display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border-radius:.5rem;color:var(--shk-surface-400);transition:background-color .15s ease-in-out,color .15s ease-in-out}.shk-fieldset-toggle:hover:not(:disabled){background-color:var(--shk-surface-100);color:var(--shk-surface-700)}.shk-fieldset-toggle:disabled{cursor:default}.shk-fieldset-toggle svg{width:1rem!important;height:1rem!important}.fieldset-action-btn{display:inline-flex;align-items:center;justify-content:center;padding:.375rem;border-radius:.5rem;color:var(--shk-primary-600);transition:background-color .15s ease-in-out,color .15s ease-in-out,opacity .15s ease-in-out}.fieldset-action-btn:hover:not(:disabled){background-color:color-mix(in srgb,var(--shk-primary-50) 60%,transparent);color:var(--shk-primary-700)}.fieldset-action-btn:disabled{opacity:.4;cursor:not-allowed}.fieldset-action-btn svg{width:.875rem!important;height:.875rem!important}.shk-fieldset-content{animation:shk-fieldset-fade .25s ease-out}@keyframes shk-fieldset-fade{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: LucideDynamicIcon, selector: "svg[lucideIcon]", inputs: ["lucideIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3579
+ }
3580
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: FieldsetComponent, decorators: [{
3581
+ type: Component,
3582
+ args: [{ selector: 'shk-fieldset', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, LucideDynamicIcon], template: "<div\n class=\"rounded-xl bg-white dark:[background-color:var(--shk-surface-50)] border _shk-border dark:[border-color:var(--shk-surface-200)] overflow-hidden\"\n [class.shadow-sm]=\"hasShadow()\"\n>\n <div\n class=\"flex items-center gap-2 px-4 py-3\"\n [class.border-b]=\"!collapsed()\"\n [class._shk-border]=\"!collapsed()\"\n [class.dark:[border-color:var(--shk-surface-200)]]=\"!collapsed()\"\n >\n <button\n type=\"button\"\n (click)=\"onToggle()\"\n [disabled]=\"!toggleable()\"\n [attr.aria-expanded]=\"!collapsed()\"\n [attr.aria-controls]=\"contentId\"\n class=\"flex items-center gap-2 flex-1 min-w-0 text-left group disabled:cursor-default\"\n >\n @if (customTemplates()['legend']) {\n <ng-container\n *ngTemplateOutlet=\"customTemplates()['legend']; context: { $implicit: collapsed(), expanded: !collapsed() }\"\n ></ng-container>\n } @else {\n @if (icon()) {\n <svg [lucideIcon]=\"getIcon(icon())\" class=\"w-4 h-4 _shk-text-primary shrink-0\"></svg>\n }\n <span class=\"font-semibold text-sm _shk-text-surface-800 dark:[color:var(--shk-surface-800)] truncate\">\n {{ legend() }}\n </span>\n @if (badge() !== undefined && badge() !== null && badge() !== '') {\n <span\n [class]=\"badgeClass() || 'inline-flex items-center px-2 py-0.5 rounded-full text-xs font-semibold _shk-bg-primary-soft _shk-text-primary-700 dark:[background-color:var(--shk-primary-900)] dark:[color:var(--shk-primary-300)] shrink-0'\"\n >\n {{ badge() }}\n </span>\n }\n }\n </button>\n\n @if (headerActions().length > 0) {\n <div class=\"flex items-center gap-0.5 shrink-0\">\n @for (action of headerActions(); track $index) {\n @if (isHeaderActionVisible(action)) {\n <div class=\"relative group\">\n <button\n type=\"button\"\n (click)=\"action.onClick()\"\n [class]=\"'fieldset-action-btn ' + (action.class || '')\"\n [disabled]=\"isHeaderActionDisabled(action)\"\n [attr.aria-label]=\"action.label\"\n >\n <svg [lucideIcon]=\"getIcon(action.icon)\" class=\"w-3.5 h-3.5\"></svg>\n </button>\n <span class=\"absolute bottom-full left-1/2 -translate-x-1/2 mb-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ action.label }}\n </span>\n </div>\n }\n }\n </div>\n }\n\n @if (toggleable() && showToggleIcon()) {\n <button\n type=\"button\"\n (click)=\"onToggle()\"\n [attr.aria-label]=\"collapsed() ? expandLabel() : collapseLabel()\"\n class=\"shk-fieldset-toggle shrink-0\"\n [disabled]=\"!toggleable()\"\n >\n <svg [lucideIcon]=\"getIcon(collapsed() ? collapsedIcon() : expandedIcon())\" class=\"w-4 h-4 transition-transform\"></svg>\n </button>\n }\n </div>\n\n @if (!collapsed()) {\n <div [id]=\"contentId\" class=\"shk-fieldset-content px-4 py-3.5\">\n <ng-content></ng-content>\n </div>\n }\n</div>\n", styles: [":host{display:block}.shk-fieldset-toggle{display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border-radius:.5rem;color:var(--shk-surface-400);transition:background-color .15s ease-in-out,color .15s ease-in-out}.shk-fieldset-toggle:hover:not(:disabled){background-color:var(--shk-surface-100);color:var(--shk-surface-700)}.shk-fieldset-toggle:disabled{cursor:default}.shk-fieldset-toggle svg{width:1rem!important;height:1rem!important}.fieldset-action-btn{display:inline-flex;align-items:center;justify-content:center;padding:.375rem;border-radius:.5rem;color:var(--shk-primary-600);transition:background-color .15s ease-in-out,color .15s ease-in-out,opacity .15s ease-in-out}.fieldset-action-btn:hover:not(:disabled){background-color:color-mix(in srgb,var(--shk-primary-50) 60%,transparent);color:var(--shk-primary-700)}.fieldset-action-btn:disabled{opacity:.4;cursor:not-allowed}.fieldset-action-btn svg{width:.875rem!important;height:.875rem!important}.shk-fieldset-content{animation:shk-fieldset-fade .25s ease-out}@keyframes shk-fieldset-fade{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}\n"] }]
3583
+ }], propDecorators: { legend: [{ type: i0.Input, args: [{ isSignal: true, alias: "legend", required: false }] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }, { type: i0.Output, args: ["collapsedChange"] }], toggleable: [{ type: i0.Input, args: [{ isSignal: true, alias: "toggleable", required: false }] }], showToggleIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "showToggleIcon", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], badge: [{ type: i0.Input, args: [{ isSignal: true, alias: "badge", required: false }] }], badgeClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "badgeClass", required: false }] }], collapsedIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsedIcon", required: false }] }], expandedIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandedIcon", required: false }] }], headerActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerActions", required: false }] }], customTemplates: [{ type: i0.Input, args: [{ isSignal: true, alias: "customTemplates", required: false }] }], hasShadow: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasShadow", required: false }] }], expandLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandLabel", required: false }] }], collapseLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapseLabel", required: false }] }], toggle: [{ type: i0.Output, args: ["toggle"] }], expand: [{ type: i0.Output, args: ["expand"] }], collapse: [{ type: i0.Output, args: ["collapse"] }] } });
3584
+
3585
+ const icons = {
3586
+ check: LucideCheck,
3587
+ 'chevron-left': LucideChevronLeft,
3588
+ 'chevron-right': LucideChevronRight,
3589
+ 'arrow-left': LucideArrowLeft,
3590
+ x: LucideX,
3591
+ 'loader-circle': LucideLoaderCircle,
3592
+ 'file-contract': LucideScrollText,
3593
+ building: LucideBuilding,
3594
+ 'user-round': LucideUserRound,
3595
+ info: LucideInfo,
3596
+ 'clipboard-check': LucideClipboardCheck,
3597
+ package: LucidePackage,
3598
+ hotel: LucideHotel,
3599
+ map: LucideMap,
3600
+ tag: LucideTag,
3601
+ utensils: LucideUtensils,
3602
+ coins: LucideCoins,
3603
+ 'sticky-note': LucideStickyNote,
3604
+ 'circle-exclamation': LucideCircleAlert,
3605
+ 'circle-alert': LucideCircleAlert,
3606
+ };
3607
+ function getIcon(name) {
3608
+ return icons[name] ?? LucideChevronRight;
3609
+ }
3610
+ /** Declares a step's content template: <ng-template shkWizardStepContent="stepId">…</ng-template>. */
3611
+ class ShkWizardStepContent {
3612
+ constructor(templateRef) {
3613
+ this.templateRef = templateRef;
3614
+ this.stepId = input.required({ ...(ngDevMode ? { debugName: "stepId" } : /* istanbul ignore next */ {}), alias: 'shkWizardStepContent' });
3615
+ }
3616
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: ShkWizardStepContent, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive }); }
3617
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.18", type: ShkWizardStepContent, isStandalone: true, selector: "ng-template[shkWizardStepContent]", inputs: { stepId: { classPropertyName: "stepId", publicName: "shkWizardStepContent", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 }); }
3618
+ }
3619
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: ShkWizardStepContent, decorators: [{
3620
+ type: Directive,
3621
+ args: [{
3622
+ selector: 'ng-template[shkWizardStepContent]',
3623
+ standalone: true,
3624
+ }]
3625
+ }], ctorParameters: () => [{ type: i0.TemplateRef }], propDecorators: { stepId: [{ type: i0.Input, args: [{ isSignal: true, alias: "shkWizardStepContent", required: true }] }] } });
3626
+ let wizardCounter = 0;
3627
+ class WizardComponent {
3628
+ constructor() {
3629
+ this.getIcon = getIcon;
3630
+ /** Steps definition shown in the stepper and used to resolve step content. */
3631
+ this.steps = input([], ...(ngDevMode ? [{ debugName: "steps" }] : /* istanbul ignore next */ []));
3632
+ /** Active step id. Two-way bindable with [(currentStep)]. Null resolves to the first step. */
3633
+ this.currentStep = model(null, ...(ngDevMode ? [{ debugName: "currentStep" }] : /* istanbul ignore next */ []));
3634
+ // Header
3635
+ /** Shows the sticky header (back button + title). */
3636
+ this.showHeader = input(true, ...(ngDevMode ? [{ debugName: "showHeader" }] : /* istanbul ignore next */ []));
3637
+ this.headerTitle = input('', ...(ngDevMode ? [{ debugName: "headerTitle" }] : /* istanbul ignore next */ []));
3638
+ this.headerSubtitle = input('', ...(ngDevMode ? [{ debugName: "headerSubtitle" }] : /* istanbul ignore next */ []));
3639
+ /** Shows the round back button in the header. */
3640
+ this.showBackButton = input(true, ...(ngDevMode ? [{ debugName: "showBackButton" }] : /* istanbul ignore next */ []));
3641
+ this.backTooltip = input('Atrás', ...(ngDevMode ? [{ debugName: "backTooltip" }] : /* istanbul ignore next */ []));
3642
+ /** Optional lucide icon shown before the title. */
3643
+ this.headerIcon = input('', ...(ngDevMode ? [{ debugName: "headerIcon" }] : /* istanbul ignore next */ []));
3644
+ // Stepper
3645
+ /** Shows the progress stepper (hide it for edit mode, like wac-app does). */
3646
+ this.showStepper = input(true, ...(ngDevMode ? [{ debugName: "showStepper" }] : /* istanbul ignore next */ []));
3647
+ /** Lets the user click on previous steps to jump back. */
3648
+ this.stepperClickable = input(false, ...(ngDevMode ? [{ debugName: "stepperClickable" }] : /* istanbul ignore next */ []));
3649
+ // Footer
3650
+ this.showFooter = input(true, ...(ngDevMode ? [{ debugName: "showFooter" }] : /* istanbul ignore next */ []));
3651
+ /** Shows a "Paso X / N" counter on the left of the footer. */
3652
+ this.showStepCounter = input(false, ...(ngDevMode ? [{ debugName: "showStepCounter" }] : /* istanbul ignore next */ []));
3653
+ this.stepCounterPrefix = input('Paso', ...(ngDevMode ? [{ debugName: "stepCounterPrefix" }] : /* istanbul ignore next */ []));
3654
+ /** Shows the Cancel button on the first step (instead of a back button). */
3655
+ this.showCancel = input(true, ...(ngDevMode ? [{ debugName: "showCancel" }] : /* istanbul ignore next */ []));
3656
+ /** Auto-advances to the next step on the primary button when it is not the last step. */
3657
+ this.advanceOnNext = input(true, ...(ngDevMode ? [{ debugName: "advanceOnNext" }] : /* istanbul ignore next */ []));
3658
+ this.prevLabel = input('Atrás', ...(ngDevMode ? [{ debugName: "prevLabel" }] : /* istanbul ignore next */ []));
3659
+ this.prevIcon = input('chevron-left', ...(ngDevMode ? [{ debugName: "prevIcon" }] : /* istanbul ignore next */ []));
3660
+ this.cancelLabel = input('Cancelar', ...(ngDevMode ? [{ debugName: "cancelLabel" }] : /* istanbul ignore next */ []));
3661
+ this.cancelIcon = input('x', ...(ngDevMode ? [{ debugName: "cancelIcon" }] : /* istanbul ignore next */ []));
3662
+ this.nextLabel = input('Continuar', ...(ngDevMode ? [{ debugName: "nextLabel" }] : /* istanbul ignore next */ []));
3663
+ this.nextIcon = input('chevron-right', ...(ngDevMode ? [{ debugName: "nextIcon" }] : /* istanbul ignore next */ []));
3664
+ this.finishLabel = input('Finalizar', ...(ngDevMode ? [{ debugName: "finishLabel" }] : /* istanbul ignore next */ []));
3665
+ this.finishIcon = input('check', ...(ngDevMode ? [{ debugName: "finishIcon" }] : /* istanbul ignore next */ []));
3666
+ /** Overrides the primary footer button label for every step. */
3667
+ this.primaryLabel = input(null, ...(ngDevMode ? [{ debugName: "primaryLabel" }] : /* istanbul ignore next */ []));
3668
+ /** Overrides the primary footer button icon for every step. */
3669
+ this.primaryIcon = input(null, ...(ngDevMode ? [{ debugName: "primaryIcon" }] : /* istanbul ignore next */ []));
3670
+ /** Shows a loading spinner on the primary button and disables it. */
3671
+ this.primaryLoading = input(false, ...(ngDevMode ? [{ debugName: "primaryLoading" }] : /* istanbul ignore next */ []));
3672
+ /** Disables the primary footer button (e.g. while the step form is invalid). */
3673
+ this.primaryDisabled = input(false, ...(ngDevMode ? [{ debugName: "primaryDisabled" }] : /* istanbul ignore next */ []));
3674
+ // Outputs
3675
+ this.back = output();
3676
+ this.cancel = output();
3677
+ this.prev = output();
3678
+ this.next = output();
3679
+ this.finish = output();
3680
+ this.stepChange = output();
3681
+ this.stepContents = contentChildren(ShkWizardStepContent, ...(ngDevMode ? [{ debugName: "stepContents" }] : /* istanbul ignore next */ []));
3682
+ this.currentIndex = computed(() => {
3683
+ const id = this.currentStep();
3684
+ if (id == null)
3685
+ return this.steps().length > 0 ? 0 : -1;
3686
+ return this.steps().findIndex((s) => s.id === id);
3687
+ }, ...(ngDevMode ? [{ debugName: "currentIndex" }] : /* istanbul ignore next */ []));
3688
+ this.currentStepObj = computed(() => this.steps()[this.currentIndex()] ?? null, ...(ngDevMode ? [{ debugName: "currentStepObj" }] : /* istanbul ignore next */ []));
3689
+ this.isFirstStep = computed(() => this.currentIndex() === 0, ...(ngDevMode ? [{ debugName: "isFirstStep" }] : /* istanbul ignore next */ []));
3690
+ this.isLastStep = computed(() => this.currentIndex() === this.steps().length - 1, ...(ngDevMode ? [{ debugName: "isLastStep" }] : /* istanbul ignore next */ []));
3691
+ this.primaryActionLabel = computed(() => {
3692
+ if (this.primaryLabel())
3693
+ return this.primaryLabel();
3694
+ const step = this.currentStepObj();
3695
+ if (step?.primaryLabel)
3696
+ return step.primaryLabel;
3697
+ return this.isLastStep() ? this.finishLabel() : this.nextLabel();
3698
+ }, ...(ngDevMode ? [{ debugName: "primaryActionLabel" }] : /* istanbul ignore next */ []));
3699
+ this.primaryActionIcon = computed(() => {
3700
+ if (this.primaryIcon())
3701
+ return this.primaryIcon();
3702
+ const step = this.currentStepObj();
3703
+ if (step?.primaryIcon)
3704
+ return step.primaryIcon;
3705
+ return this.isLastStep() ? this.finishIcon() : this.nextIcon();
3706
+ }, ...(ngDevMode ? [{ debugName: "primaryActionIcon" }] : /* istanbul ignore next */ []));
3707
+ }
3708
+ getStepTemplate(id) {
3709
+ return this.stepContents().find((c) => c.stepId() === id)?.templateRef;
3710
+ }
3711
+ goTo(stepId) {
3712
+ const idx = this.steps().findIndex((s) => s.id === stepId);
3713
+ if (idx < 0)
3714
+ return;
3715
+ if (this.currentStep() === stepId)
3716
+ return;
3717
+ this.currentStep.set(stepId);
3718
+ this.stepChange.emit({ step: this.steps()[idx], index: idx });
3719
+ }
3720
+ onPrev() {
3721
+ const idx = this.currentIndex();
3722
+ if (idx <= 0)
3723
+ return;
3724
+ this.prev.emit();
3725
+ this.goTo(this.steps()[idx - 1].id);
3726
+ }
3727
+ onNext() {
3728
+ const idx = this.currentIndex();
3729
+ const next = this.steps()[idx + 1];
3730
+ if (!next)
3731
+ return;
3732
+ this.next.emit();
3733
+ if (this.advanceOnNext()) {
3734
+ this.goTo(next.id);
3735
+ }
3736
+ }
3737
+ onPrimary() {
3738
+ if (this.primaryLoading() || this.primaryDisabled())
3739
+ return;
3740
+ if (this.isLastStep()) {
3741
+ this.finish.emit();
3742
+ }
3743
+ else {
3744
+ this.onNext();
3745
+ }
3746
+ }
3747
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: WizardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3748
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: WizardComponent, isStandalone: true, selector: "shk-wizard", inputs: { steps: { classPropertyName: "steps", publicName: "steps", isSignal: true, isRequired: false, transformFunction: null }, currentStep: { classPropertyName: "currentStep", publicName: "currentStep", isSignal: true, isRequired: false, transformFunction: null }, showHeader: { classPropertyName: "showHeader", publicName: "showHeader", isSignal: true, isRequired: false, transformFunction: null }, headerTitle: { classPropertyName: "headerTitle", publicName: "headerTitle", isSignal: true, isRequired: false, transformFunction: null }, headerSubtitle: { classPropertyName: "headerSubtitle", publicName: "headerSubtitle", isSignal: true, isRequired: false, transformFunction: null }, showBackButton: { classPropertyName: "showBackButton", publicName: "showBackButton", isSignal: true, isRequired: false, transformFunction: null }, backTooltip: { classPropertyName: "backTooltip", publicName: "backTooltip", isSignal: true, isRequired: false, transformFunction: null }, headerIcon: { classPropertyName: "headerIcon", publicName: "headerIcon", isSignal: true, isRequired: false, transformFunction: null }, showStepper: { classPropertyName: "showStepper", publicName: "showStepper", isSignal: true, isRequired: false, transformFunction: null }, stepperClickable: { classPropertyName: "stepperClickable", publicName: "stepperClickable", isSignal: true, isRequired: false, transformFunction: null }, showFooter: { classPropertyName: "showFooter", publicName: "showFooter", isSignal: true, isRequired: false, transformFunction: null }, showStepCounter: { classPropertyName: "showStepCounter", publicName: "showStepCounter", isSignal: true, isRequired: false, transformFunction: null }, stepCounterPrefix: { classPropertyName: "stepCounterPrefix", publicName: "stepCounterPrefix", isSignal: true, isRequired: false, transformFunction: null }, showCancel: { classPropertyName: "showCancel", publicName: "showCancel", isSignal: true, isRequired: false, transformFunction: null }, advanceOnNext: { classPropertyName: "advanceOnNext", publicName: "advanceOnNext", isSignal: true, isRequired: false, transformFunction: null }, prevLabel: { classPropertyName: "prevLabel", publicName: "prevLabel", isSignal: true, isRequired: false, transformFunction: null }, prevIcon: { classPropertyName: "prevIcon", publicName: "prevIcon", isSignal: true, isRequired: false, transformFunction: null }, cancelLabel: { classPropertyName: "cancelLabel", publicName: "cancelLabel", isSignal: true, isRequired: false, transformFunction: null }, cancelIcon: { classPropertyName: "cancelIcon", publicName: "cancelIcon", isSignal: true, isRequired: false, transformFunction: null }, nextLabel: { classPropertyName: "nextLabel", publicName: "nextLabel", isSignal: true, isRequired: false, transformFunction: null }, nextIcon: { classPropertyName: "nextIcon", publicName: "nextIcon", isSignal: true, isRequired: false, transformFunction: null }, finishLabel: { classPropertyName: "finishLabel", publicName: "finishLabel", isSignal: true, isRequired: false, transformFunction: null }, finishIcon: { classPropertyName: "finishIcon", publicName: "finishIcon", isSignal: true, isRequired: false, transformFunction: null }, primaryLabel: { classPropertyName: "primaryLabel", publicName: "primaryLabel", isSignal: true, isRequired: false, transformFunction: null }, primaryIcon: { classPropertyName: "primaryIcon", publicName: "primaryIcon", isSignal: true, isRequired: false, transformFunction: null }, primaryLoading: { classPropertyName: "primaryLoading", publicName: "primaryLoading", isSignal: true, isRequired: false, transformFunction: null }, primaryDisabled: { classPropertyName: "primaryDisabled", publicName: "primaryDisabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { currentStep: "currentStepChange", back: "back", cancel: "cancel", prev: "prev", next: "next", finish: "finish", stepChange: "stepChange" }, queries: [{ propertyName: "stepContents", predicate: ShkWizardStepContent, isSignal: true }], ngImport: i0, template: "<div class=\"min-h-full bg-transparent\">\n\n <!-- ============ Sticky Header + Stepper ============ -->\n @if (showHeader()) {\n <div\n class=\"sticky top-0 z-20 bg-white dark:[background-color:var(--shk-surface-50)] border-b _shk-border dark:[border-color:var(--shk-surface-200)] shadow-sm\"\n >\n <div class=\"w-full px-4 sm:px-6 lg:px-8 py-4\">\n <div class=\"flex items-center gap-4 mb-4\">\n @if (showBackButton()) {\n <button\n type=\"button\"\n (click)=\"back.emit()\"\n [attr.aria-label]=\"backTooltip()\"\n [attr.title]=\"backTooltip()\"\n class=\"shk-wizard-icon-btn shrink-0\"\n >\n <svg [lucideIcon]=\"getIcon('arrow-left')\" class=\"w-4 h-4\"></svg>\n </button>\n }\n <div class=\"flex-1 min-w-0 flex items-center gap-2.5\">\n @if (headerIcon()) {\n <span class=\"w-9 h-9 rounded-lg _shk-bg-primary-soft _shk-text-primary flex items-center justify-center shrink-0\">\n <svg [lucideIcon]=\"getIcon(headerIcon())\" class=\"w-4 h-4\"></svg>\n </span>\n }\n <div class=\"min-w-0\">\n <h1 class=\"text-xl font-bold _shk-text-surface-800 dark:[color:var(--shk-surface-800)] truncate\">\n {{ headerTitle() }}\n </h1>\n @if (headerSubtitle()) {\n <p class=\"text-xs _shk-text-surface-500 dark:[color:var(--shk-surface-500)] mt-0.5 truncate\">\n {{ headerSubtitle() }}\n </p>\n }\n </div>\n </div>\n <ng-content select=\"[shkWizardHeaderActions]\"></ng-content>\n </div>\n\n <!-- Stepper -->\n @if (showStepper() && steps().length > 1) {\n <div class=\"flex items-center gap-2 w-full max-w-3xl mx-auto\">\n @for (step of steps(); track step.id; let i = $index, last = $last) {\n <div class=\"flex items-center gap-3 shrink-0\">\n <button\n type=\"button\"\n (click)=\"goTo(step.id)\"\n [disabled]=\"!stepperClickable() || currentIndex() < i\"\n [attr.aria-label]=\"step.label\"\n class=\"shk-wizard-stepper-dot\"\n [class._shk-bg-primary]=\"currentIndex() > i || currentIndex() === i\"\n [class.text-white]=\"currentIndex() > i || currentIndex() === i\"\n [class._shk-bg-surface-200]=\"currentIndex() < i\"\n [class._shk-text-surface-500]=\"currentIndex() < i\"\n [class.cursor-pointer]=\"stepperClickable() && currentIndex() >= i\"\n [class.cursor-default]=\"!stepperClickable() || currentIndex() < i\"\n >\n @if (currentIndex() > i) {\n <svg [lucideIcon]=\"getIcon(step.icon || 'check')\" class=\"w-4 h-4\"></svg>\n } @else if (step.icon) {\n <svg [lucideIcon]=\"getIcon(step.icon)\" class=\"w-4 h-4\"></svg>\n } @else {\n {{ i + 1 }}\n }\n </button>\n <span\n class=\"text-sm font-semibold transition-colors whitespace-nowrap hidden sm:inline\"\n [class._shk-text-surface-800]=\"currentIndex() === i\"\n [class._shk-text-surface-500]=\"currentIndex() !== i\"\n [class.dark:[color:var(--shk-surface-800)]]=\"currentIndex() === i\"\n [class.dark:[color:var(--shk-surface-500)]]=\"currentIndex() !== i\"\n >\n {{ step.label }}\n </span>\n </div>\n\n @if (!last) {\n <div class=\"flex-1 h-0.5 _shk-bg-surface-200 dark:[background-color:var(--shk-surface-200)] relative overflow-hidden rounded-full\">\n <div\n class=\"absolute inset-y-0 left-0 _shk-bg-primary transition-all duration-300\"\n [class.w-full]=\"currentIndex() > i\"\n [class.w-0]=\"currentIndex() <= i\"\n ></div>\n </div>\n }\n }\n </div>\n }\n </div>\n </div>\n }\n\n <!-- ============ Active step content ============ -->\n <div class=\"w-full px-4 sm:px-6 lg:px-8 py-6 pb-28\">\n @if (currentIndex() >= 0) {\n @if (getStepTemplate(steps()[currentIndex()].id); as tpl) {\n <div class=\"shk-wizard-fade\" [style.view-transition-name]=\"'shk-wizard-step'\">\n <ng-container\n *ngTemplateOutlet=\"tpl; context: { step: currentStepObj(), index: currentIndex() }\"\n ></ng-container>\n </div>\n } @else {\n <p class=\"text-sm _shk-text-surface-400 dark:[color:var(--shk-surface-400)]\">\n No hay contenido definido para el paso \u00AB{{ steps()[currentIndex()].label }}\u00BB.\n </p>\n }\n }\n </div>\n\n <!-- ============ Sticky Footer ============ -->\n @if (showFooter() && steps().length > 0) {\n <div\n class=\"sticky bottom-0 z-20 bg-white dark:[background-color:var(--shk-surface-50)] border-t _shk-border dark:[border-color:var(--shk-surface-200)] shadow-[0_-4px_12px_rgba(0,0,0,0.04)] mt-8\"\n >\n <div class=\"w-full px-4 sm:px-6 lg:px-8 py-4 flex items-center justify-end gap-3\">\n @if (showStepCounter()) {\n <span class=\"text-sm _shk-text-surface-500 dark:[color:var(--shk-surface-500)] mr-auto\">\n {{ stepCounterPrefix() }} {{ currentIndex() + 1 }} / {{ steps().length }}\n </span>\n }\n\n @if (isFirstStep()) {\n @if (showCancel()) {\n <button type=\"button\" (click)=\"cancel.emit()\" class=\"shk-wizard-btn-secondary\">\n @if (cancelIcon()) {\n <svg [lucideIcon]=\"getIcon(cancelIcon())\" class=\"w-4 h-4\"></svg>\n }\n {{ cancelLabel() }}\n </button>\n }\n } @else {\n <button type=\"button\" (click)=\"onPrev()\" class=\"shk-wizard-btn-secondary\">\n <svg [lucideIcon]=\"getIcon(prevIcon())\" class=\"w-4 h-4\"></svg>\n {{ prevLabel() }}\n </button>\n }\n\n <button\n type=\"button\"\n (click)=\"onPrimary()\"\n [disabled]=\"primaryDisabled() || primaryLoading()\"\n class=\"shk-wizard-btn-primary\"\n >\n @if (primaryLoading()) {\n <svg [lucideIcon]=\"getIcon('loader-circle')\" class=\"w-4 h-4 shk-wizard-spin\"></svg>\n } @else {\n @if (primaryActionIcon()) {\n <svg [lucideIcon]=\"getIcon(primaryActionIcon())\" class=\"w-4 h-4\"></svg>\n }\n }\n {{ primaryActionLabel() }}\n </button>\n </div>\n </div>\n }\n</div>\n", styles: [":host{display:block}.shk-wizard-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border-radius:9999px;color:var(--shk-surface-600);transition:background-color .15s ease-in-out,color .15s ease-in-out}.shk-wizard-icon-btn:hover:not(:disabled){background-color:var(--shk-surface-100);color:var(--shk-surface-800)}.shk-wizard-icon-btn:disabled{cursor:default}.shk-wizard-icon-btn svg{width:1rem!important;height:1rem!important}.shk-wizard-stepper-dot{display:flex;align-items:center;justify-content:center;width:2.25rem;height:2.25rem;border-radius:9999px;font-size:.875rem;font-weight:700;flex-shrink:0;transition:background-color .15s ease-in-out,color .15s ease-in-out}.shk-wizard-stepper-dot svg{width:1rem!important;height:1rem!important}.shk-wizard-btn-secondary{display:inline-flex;align-items:center;gap:.5rem;padding:.5rem 1rem;border-radius:.5rem;font-size:.875rem;font-weight:500;color:var(--shk-surface-700);background-color:transparent;border:1px solid var(--shk-surface-200);transition:background-color .15s ease-in-out,border-color .15s ease-in-out,color .15s ease-in-out}.shk-wizard-btn-secondary:hover:not(:disabled){background-color:var(--shk-surface-100);border-color:var(--shk-surface-300);color:var(--shk-surface-900)}.shk-wizard-btn-secondary:disabled{opacity:.5;cursor:not-allowed}.shk-wizard-btn-secondary svg{width:1rem!important;height:1rem!important}.shk-wizard-btn-primary{display:inline-flex;align-items:center;gap:.5rem;padding:.5rem 1rem;border-radius:.5rem;font-size:.875rem;font-weight:500;color:#fff;background-color:var(--shk-primary-600);box-shadow:0 6px 20px -6px color-mix(in srgb,var(--shk-primary-600) 55%,transparent);transition:background-color .15s ease-in-out,opacity .15s ease-in-out}.shk-wizard-btn-primary:hover:not(:disabled){background-color:var(--shk-primary-700)}.shk-wizard-btn-primary:disabled{opacity:.5;cursor:not-allowed;box-shadow:none}.shk-wizard-btn-primary svg{width:1rem!important;height:1rem!important}.shk-wizard-spin{animation:shk-wizard-spin .8s linear infinite}@keyframes shk-wizard-spin{to{transform:rotate(360deg)}}.shk-wizard-fade{animation:shk-wizard-fade .25s ease-out}@keyframes shk-wizard-fade{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: LucideDynamicIcon, selector: "svg[lucideIcon]", inputs: ["lucideIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3749
+ }
3750
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: WizardComponent, decorators: [{
3751
+ type: Component,
3752
+ args: [{ selector: 'shk-wizard', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, LucideDynamicIcon], template: "<div class=\"min-h-full bg-transparent\">\n\n <!-- ============ Sticky Header + Stepper ============ -->\n @if (showHeader()) {\n <div\n class=\"sticky top-0 z-20 bg-white dark:[background-color:var(--shk-surface-50)] border-b _shk-border dark:[border-color:var(--shk-surface-200)] shadow-sm\"\n >\n <div class=\"w-full px-4 sm:px-6 lg:px-8 py-4\">\n <div class=\"flex items-center gap-4 mb-4\">\n @if (showBackButton()) {\n <button\n type=\"button\"\n (click)=\"back.emit()\"\n [attr.aria-label]=\"backTooltip()\"\n [attr.title]=\"backTooltip()\"\n class=\"shk-wizard-icon-btn shrink-0\"\n >\n <svg [lucideIcon]=\"getIcon('arrow-left')\" class=\"w-4 h-4\"></svg>\n </button>\n }\n <div class=\"flex-1 min-w-0 flex items-center gap-2.5\">\n @if (headerIcon()) {\n <span class=\"w-9 h-9 rounded-lg _shk-bg-primary-soft _shk-text-primary flex items-center justify-center shrink-0\">\n <svg [lucideIcon]=\"getIcon(headerIcon())\" class=\"w-4 h-4\"></svg>\n </span>\n }\n <div class=\"min-w-0\">\n <h1 class=\"text-xl font-bold _shk-text-surface-800 dark:[color:var(--shk-surface-800)] truncate\">\n {{ headerTitle() }}\n </h1>\n @if (headerSubtitle()) {\n <p class=\"text-xs _shk-text-surface-500 dark:[color:var(--shk-surface-500)] mt-0.5 truncate\">\n {{ headerSubtitle() }}\n </p>\n }\n </div>\n </div>\n <ng-content select=\"[shkWizardHeaderActions]\"></ng-content>\n </div>\n\n <!-- Stepper -->\n @if (showStepper() && steps().length > 1) {\n <div class=\"flex items-center gap-2 w-full max-w-3xl mx-auto\">\n @for (step of steps(); track step.id; let i = $index, last = $last) {\n <div class=\"flex items-center gap-3 shrink-0\">\n <button\n type=\"button\"\n (click)=\"goTo(step.id)\"\n [disabled]=\"!stepperClickable() || currentIndex() < i\"\n [attr.aria-label]=\"step.label\"\n class=\"shk-wizard-stepper-dot\"\n [class._shk-bg-primary]=\"currentIndex() > i || currentIndex() === i\"\n [class.text-white]=\"currentIndex() > i || currentIndex() === i\"\n [class._shk-bg-surface-200]=\"currentIndex() < i\"\n [class._shk-text-surface-500]=\"currentIndex() < i\"\n [class.cursor-pointer]=\"stepperClickable() && currentIndex() >= i\"\n [class.cursor-default]=\"!stepperClickable() || currentIndex() < i\"\n >\n @if (currentIndex() > i) {\n <svg [lucideIcon]=\"getIcon(step.icon || 'check')\" class=\"w-4 h-4\"></svg>\n } @else if (step.icon) {\n <svg [lucideIcon]=\"getIcon(step.icon)\" class=\"w-4 h-4\"></svg>\n } @else {\n {{ i + 1 }}\n }\n </button>\n <span\n class=\"text-sm font-semibold transition-colors whitespace-nowrap hidden sm:inline\"\n [class._shk-text-surface-800]=\"currentIndex() === i\"\n [class._shk-text-surface-500]=\"currentIndex() !== i\"\n [class.dark:[color:var(--shk-surface-800)]]=\"currentIndex() === i\"\n [class.dark:[color:var(--shk-surface-500)]]=\"currentIndex() !== i\"\n >\n {{ step.label }}\n </span>\n </div>\n\n @if (!last) {\n <div class=\"flex-1 h-0.5 _shk-bg-surface-200 dark:[background-color:var(--shk-surface-200)] relative overflow-hidden rounded-full\">\n <div\n class=\"absolute inset-y-0 left-0 _shk-bg-primary transition-all duration-300\"\n [class.w-full]=\"currentIndex() > i\"\n [class.w-0]=\"currentIndex() <= i\"\n ></div>\n </div>\n }\n }\n </div>\n }\n </div>\n </div>\n }\n\n <!-- ============ Active step content ============ -->\n <div class=\"w-full px-4 sm:px-6 lg:px-8 py-6 pb-28\">\n @if (currentIndex() >= 0) {\n @if (getStepTemplate(steps()[currentIndex()].id); as tpl) {\n <div class=\"shk-wizard-fade\" [style.view-transition-name]=\"'shk-wizard-step'\">\n <ng-container\n *ngTemplateOutlet=\"tpl; context: { step: currentStepObj(), index: currentIndex() }\"\n ></ng-container>\n </div>\n } @else {\n <p class=\"text-sm _shk-text-surface-400 dark:[color:var(--shk-surface-400)]\">\n No hay contenido definido para el paso \u00AB{{ steps()[currentIndex()].label }}\u00BB.\n </p>\n }\n }\n </div>\n\n <!-- ============ Sticky Footer ============ -->\n @if (showFooter() && steps().length > 0) {\n <div\n class=\"sticky bottom-0 z-20 bg-white dark:[background-color:var(--shk-surface-50)] border-t _shk-border dark:[border-color:var(--shk-surface-200)] shadow-[0_-4px_12px_rgba(0,0,0,0.04)] mt-8\"\n >\n <div class=\"w-full px-4 sm:px-6 lg:px-8 py-4 flex items-center justify-end gap-3\">\n @if (showStepCounter()) {\n <span class=\"text-sm _shk-text-surface-500 dark:[color:var(--shk-surface-500)] mr-auto\">\n {{ stepCounterPrefix() }} {{ currentIndex() + 1 }} / {{ steps().length }}\n </span>\n }\n\n @if (isFirstStep()) {\n @if (showCancel()) {\n <button type=\"button\" (click)=\"cancel.emit()\" class=\"shk-wizard-btn-secondary\">\n @if (cancelIcon()) {\n <svg [lucideIcon]=\"getIcon(cancelIcon())\" class=\"w-4 h-4\"></svg>\n }\n {{ cancelLabel() }}\n </button>\n }\n } @else {\n <button type=\"button\" (click)=\"onPrev()\" class=\"shk-wizard-btn-secondary\">\n <svg [lucideIcon]=\"getIcon(prevIcon())\" class=\"w-4 h-4\"></svg>\n {{ prevLabel() }}\n </button>\n }\n\n <button\n type=\"button\"\n (click)=\"onPrimary()\"\n [disabled]=\"primaryDisabled() || primaryLoading()\"\n class=\"shk-wizard-btn-primary\"\n >\n @if (primaryLoading()) {\n <svg [lucideIcon]=\"getIcon('loader-circle')\" class=\"w-4 h-4 shk-wizard-spin\"></svg>\n } @else {\n @if (primaryActionIcon()) {\n <svg [lucideIcon]=\"getIcon(primaryActionIcon())\" class=\"w-4 h-4\"></svg>\n }\n }\n {{ primaryActionLabel() }}\n </button>\n </div>\n </div>\n }\n</div>\n", styles: [":host{display:block}.shk-wizard-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border-radius:9999px;color:var(--shk-surface-600);transition:background-color .15s ease-in-out,color .15s ease-in-out}.shk-wizard-icon-btn:hover:not(:disabled){background-color:var(--shk-surface-100);color:var(--shk-surface-800)}.shk-wizard-icon-btn:disabled{cursor:default}.shk-wizard-icon-btn svg{width:1rem!important;height:1rem!important}.shk-wizard-stepper-dot{display:flex;align-items:center;justify-content:center;width:2.25rem;height:2.25rem;border-radius:9999px;font-size:.875rem;font-weight:700;flex-shrink:0;transition:background-color .15s ease-in-out,color .15s ease-in-out}.shk-wizard-stepper-dot svg{width:1rem!important;height:1rem!important}.shk-wizard-btn-secondary{display:inline-flex;align-items:center;gap:.5rem;padding:.5rem 1rem;border-radius:.5rem;font-size:.875rem;font-weight:500;color:var(--shk-surface-700);background-color:transparent;border:1px solid var(--shk-surface-200);transition:background-color .15s ease-in-out,border-color .15s ease-in-out,color .15s ease-in-out}.shk-wizard-btn-secondary:hover:not(:disabled){background-color:var(--shk-surface-100);border-color:var(--shk-surface-300);color:var(--shk-surface-900)}.shk-wizard-btn-secondary:disabled{opacity:.5;cursor:not-allowed}.shk-wizard-btn-secondary svg{width:1rem!important;height:1rem!important}.shk-wizard-btn-primary{display:inline-flex;align-items:center;gap:.5rem;padding:.5rem 1rem;border-radius:.5rem;font-size:.875rem;font-weight:500;color:#fff;background-color:var(--shk-primary-600);box-shadow:0 6px 20px -6px color-mix(in srgb,var(--shk-primary-600) 55%,transparent);transition:background-color .15s ease-in-out,opacity .15s ease-in-out}.shk-wizard-btn-primary:hover:not(:disabled){background-color:var(--shk-primary-700)}.shk-wizard-btn-primary:disabled{opacity:.5;cursor:not-allowed;box-shadow:none}.shk-wizard-btn-primary svg{width:1rem!important;height:1rem!important}.shk-wizard-spin{animation:shk-wizard-spin .8s linear infinite}@keyframes shk-wizard-spin{to{transform:rotate(360deg)}}.shk-wizard-fade{animation:shk-wizard-fade .25s ease-out}@keyframes shk-wizard-fade{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}\n"] }]
3753
+ }], propDecorators: { steps: [{ type: i0.Input, args: [{ isSignal: true, alias: "steps", required: false }] }], currentStep: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentStep", required: false }] }, { type: i0.Output, args: ["currentStepChange"] }], showHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "showHeader", required: false }] }], headerTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerTitle", required: false }] }], headerSubtitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerSubtitle", required: false }] }], showBackButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showBackButton", required: false }] }], backTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "backTooltip", required: false }] }], headerIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerIcon", required: false }] }], showStepper: [{ type: i0.Input, args: [{ isSignal: true, alias: "showStepper", required: false }] }], stepperClickable: [{ type: i0.Input, args: [{ isSignal: true, alias: "stepperClickable", required: false }] }], showFooter: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFooter", required: false }] }], showStepCounter: [{ type: i0.Input, args: [{ isSignal: true, alias: "showStepCounter", required: false }] }], stepCounterPrefix: [{ type: i0.Input, args: [{ isSignal: true, alias: "stepCounterPrefix", required: false }] }], showCancel: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCancel", required: false }] }], advanceOnNext: [{ type: i0.Input, args: [{ isSignal: true, alias: "advanceOnNext", required: false }] }], prevLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "prevLabel", required: false }] }], prevIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "prevIcon", required: false }] }], cancelLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "cancelLabel", required: false }] }], cancelIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "cancelIcon", required: false }] }], nextLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "nextLabel", required: false }] }], nextIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "nextIcon", required: false }] }], finishLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "finishLabel", required: false }] }], finishIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "finishIcon", required: false }] }], primaryLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "primaryLabel", required: false }] }], primaryIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "primaryIcon", required: false }] }], primaryLoading: [{ type: i0.Input, args: [{ isSignal: true, alias: "primaryLoading", required: false }] }], primaryDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "primaryDisabled", required: false }] }], back: [{ type: i0.Output, args: ["back"] }], cancel: [{ type: i0.Output, args: ["cancel"] }], prev: [{ type: i0.Output, args: ["prev"] }], next: [{ type: i0.Output, args: ["next"] }], finish: [{ type: i0.Output, args: ["finish"] }], stepChange: [{ type: i0.Output, args: ["stepChange"] }], stepContents: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => ShkWizardStepContent), { isSignal: true }] }] } });
3754
+
3288
3755
  /* Theme — import theme.css in your global styles.css:
3289
3756
  @import '@shirkasoft/ui-components/theme.css';
3290
3757
  Override --shk-* CSS variables at :root or .dark to theme.
@@ -3294,5 +3761,5 @@ function readThemeColors() {
3294
3761
  * Generated bundle index. Do not edit.
3295
3762
  */
3296
3763
 
3297
- export { COLOR_PALETTE, ChartComponent, ConfirmDialogComponent, ConfirmDialogService, DatePickerComponent, FileUploadComponent, ModalComponent, ModalService, NotificationComponent, NotificationService, PriceInputComponent, RailSidebarComponent, SelectComponent, SidebarComponent, TableComponent, TextFieldComponent, ToggleComponent, TooltipComponent, readThemeColors };
3764
+ export { COLOR_PALETTE, ChartComponent, ConfirmDialogComponent, ConfirmDialogService, DEFAULT_MARKER_GRADIENTS, DEFAULT_SUPPLIER_ICON_COLORS, DEFAULT_SUPPLIER_TYPE_ICONS, DatePickerComponent, FieldsetComponent, FileUploadComponent, ModalComponent, ModalService, NotificationComponent, NotificationService, PriceInputComponent, RailSidebarComponent, SelectComponent, ShkWizardStepContent, SidebarComponent, TableComponent, TextFieldComponent, TimelineComponent, ToggleComponent, TooltipComponent, WizardComponent, readThemeColors };
3298
3765
  //# sourceMappingURL=shirkasoft-ui-components.mjs.map