shirkasoft-ui-components 1.0.11 → 1.0.14

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.
@@ -10,6 +10,7 @@ import { TranslocoService, TranslocoModule } from '@jsverse/transloco';
10
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 } from '@lucide/angular';
11
11
  import { Router } from '@angular/router';
12
12
  import { Subject, debounceTime } from 'rxjs';
13
+ import { Chart, registerables } from 'chart.js';
13
14
 
14
15
  const icons$6 = {
15
16
  search: LucideSearch,
@@ -299,7 +300,7 @@ class TextFieldComponent {
299
300
  useExisting: forwardRef(() => TextFieldComponent),
300
301
  multi: true,
301
302
  },
302
- ], viewQueries: [{ propertyName: "inputElement", first: true, predicate: ["input"], descendants: true, isSignal: true }, { propertyName: "textareaElement", first: true, predicate: ["textarea"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"relative mb-4\">\n @if (label()) {\n <div class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-300)] mb-1\">\n {{ label() }}\n </div>\n }\n\n <div class=\"relative\">\n @if (!isTextArea()) {\n <div class=\"flex\">\n @if (searchMode()) {\n @let isDisabledSearch = actualControl()?.disabled || isDisabled();\n <input\n #input\n [id]=\"id()\"\n type=\"text\"\n [value]=\"displayValue() || ''\"\n [placeholder]=\"placeholder() || label()\"\n [readOnly]=\"true\"\n [disabled]=\"isDisabledSearch\"\n (click)=\"!isDisabledSearch && searchButtonClick.emit()\"\n (keydown.enter)=\"!isDisabledSearch && searchButtonClick.emit()\"\n (blur)=\"onBlur()\"\n autocomplete=\"off\"\n [class.cursor-pointer]=\"!isDisabledSearch\"\n [class.cursor-not-allowed]=\"isDisabledSearch\"\n [class._shk-bg-surface-50]=\"isDisabledSearch\"\n [class.dark:[background-color:var(--shk-surface-800)]]=\"isDisabledSearch\"\n [class._shk-text-surface-400]=\"isDisabledSearch\"\n [class.dark:[color:var(--shk-surface-500)]]=\"isDisabledSearch\"\n class=\"block w-full px-3 py-2 _shk-text-surface-700 dark:[color:var(--shk-surface-200)] _shk-bg-surface-50 dark:[background-color:var(--shk-surface-800)] border rounded-l-lg transition-colors placeholder:[color:var(--shk-surface-400)] dark:placeholder:[color:var(--shk-surface-500)] focus:[background-color:var(--shk-surface-50)] dark:focus:[background-color:var(--shk-surface-800)] sm:text-sm\"\n [ngClass]=\"{\n 'border-red-500': shouldShowError() && !isDisabledSearch,\n '_shk-border dark:[border-color:var(--shk-surface-700)]': !shouldShowError() || isDisabledSearch,\n 'cursor-pointer': !isDisabledSearch,\n 'cursor-not-allowed _shk-text-surface-400 dark:[color:var(--shk-surface-500)]': isDisabledSearch\n }\"\n />\n <button\n type=\"button\"\n (click)=\"searchButtonClick.emit()\"\n tabindex=\"-1\"\n [disabled]=\"isDisabledSearch\"\n class=\"px-3 flex items-center justify-center shrink-0 _shk-bg-primary hover:[background-color:var(--shk-primary-700)] text-white border _shk-border-primary rounded-r-lg transition-colors duration-200 disabled:[background-color:var(--shk-surface-300)] dark:disabled:[background-color:var(--shk-surface-700)] disabled:[border-color:var(--shk-surface-300)] dark:disabled:[border-color:var(--shk-surface-700)] disabled:cursor-not-allowed\"\n >\n <svg [lucideIcon]=\"getIcon('search')\" class=\"w-4 h-4\"></svg>\n </button>\n }\n\n @if (!searchMode()) {\n <input\n #input\n [id]=\"id()\"\n [maxlength]=\"maxLength() || (formatCard() ? 19 : null)\"\n [min]=\"type() === 'number' && preventNegative() ? '0' : null\"\n (keypress)=\"type() === 'number' || numbersOnly() ? numberValidation($event) : null\"\n [type]=\"effectiveType()\"\n [formControl]=\"$any(actualControl())\"\n [placeholder]=\"placeholder() || label()\"\n (input)=\"onInput($event)\"\n autocomplete=\"new-password\"\n (blur)=\"onBlur()\"\n class=\"block w-full px-3 py-2 _shk-text-surface-700 dark:[color:var(--shk-surface-200)] _shk-bg-surface-50 dark:[background-color:var(--shk-surface-800)] border rounded-lg transition-colors placeholder:[color:var(--shk-surface-400)] dark:placeholder:[color:var(--shk-surface-500)] focus:outline-none focus:[background-color:var(--shk-surface-50)] dark:focus:[background-color:var(--shk-surface-800)] focus:ring-1 disabled:[background-color:var(--shk-surface-50)] dark:disabled:[background-color:var(--shk-surface-800)] disabled:cursor-not-allowed sm:text-sm\"\n [ngClass]=\"{\n 'border-red-500 focus:border-red-500 focus:ring-red-500': shouldShowError(),\n 'border-green-500 focus:border-green-500 focus:ring-green-500': wasFixedError(),\n '_shk-border dark:[border-color:var(--shk-surface-700)] focus:[border-color:var(--shk-primary-500)] focus:[--tw-ring-color:var(--shk-primary-500)]': !shouldShowError() && !wasFixedError()\n }\"\n [class.pr-8]=\"type() === 'password' && actualControl()?.value?.length > 0\"\n [class.pr-3]=\"type() !== 'password' || !actualControl()?.value?.length\"\n />\n\n @if (type() === 'password' && actualControl()?.value?.length > 0) {\n <button\n type=\"button\"\n (click)=\"togglePasswordVisibility()\"\n [disabled]=\"actualControl()?.disabled\"\n class=\"absolute right-3 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)] focus:outline-none\"\n >\n @if (showPassword()) {\n <svg [lucideIcon]=\"getIcon('eye-off')\" class=\"w-4 h-4\"></svg>\n } @else {\n <svg [lucideIcon]=\"getIcon('eye')\" class=\"w-4 h-4\"></svg>\n }\n </button>\n }\n }\n </div>\n }\n\n @if (isTextArea()) {\n <textarea\n #textarea\n [id]=\"id()\"\n [formControl]=\"$any(actualControl())\"\n [placeholder]=\"placeholder() || label()\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n [class]=\"isTextArea() ? textAreaHeight() : 'h-28'\"\n class=\"block w-full px-3 py-2 _shk-text-surface-700 dark:[color:var(--shk-surface-200)] _shk-bg-surface-50 dark:[background-color:var(--shk-surface-800)] border rounded-lg transition-colors placeholder:[color:var(--shk-surface-400)] dark:placeholder:[color:var(--shk-surface-500)] focus:outline-none focus:[background-color:var(--shk-surface-50)] dark:focus:[background-color:var(--shk-surface-800)] focus:ring-1 resize-none disabled:[background-color:var(--shk-surface-50)] dark:disabled:[background-color:var(--shk-surface-800)] disabled:cursor-not-allowed disabled:[color:var(--shk-surface-400)] dark:disabled:[color:var(--shk-surface-500)] sm:text-sm\"\n [ngClass]=\"{\n 'border-red-500 focus:border-red-500 focus:ring-red-500': shouldShowError(),\n 'border-green-500 focus:border-green-500 focus:ring-green-500': wasFixedError(),\n '_shk-border dark:[border-color:var(--shk-surface-700)] focus:[border-color:var(--shk-primary-500)] focus:[--tw-ring-color:var(--shk-primary-500)]': !shouldShowError() && !wasFixedError()\n }\"\n ></textarea>\n }\n </div>\n\n @if (shouldShowError()) {\n <div class=\"mt-1 text-xs text-red-500 max-h-20 overflow-y-auto\" tabindex=\"-1\">\n <ul class=\"list-disc pl-4 space-y-1\">\n @for (error of getErrorMessages(); track error) {\n <li>{{ error }}</li>\n }\n </ul>\n </div>\n }\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { 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.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: LucideDynamicIcon, selector: "svg[lucideIcon]", inputs: ["lucideIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
303
+ ], viewQueries: [{ propertyName: "inputElement", first: true, predicate: ["input"], descendants: true, isSignal: true }, { propertyName: "textareaElement", first: true, predicate: ["textarea"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"relative mb-4\">\n @if (label()) {\n <div class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-600)] mb-1\">\n {{ label() }}\n </div>\n }\n\n <div class=\"relative\">\n @if (!isTextArea()) {\n <div class=\"flex\">\n @if (searchMode()) {\n @let isDisabledSearch = actualControl()?.disabled || isDisabled();\n <input\n #input\n [id]=\"id()\"\n type=\"text\"\n [value]=\"displayValue() || ''\"\n [placeholder]=\"placeholder() || label()\"\n [readOnly]=\"true\"\n [disabled]=\"isDisabledSearch\"\n (click)=\"!isDisabledSearch && searchButtonClick.emit()\"\n (keydown.enter)=\"!isDisabledSearch && searchButtonClick.emit()\"\n (blur)=\"onBlur()\"\n autocomplete=\"off\"\n [class.cursor-pointer]=\"!isDisabledSearch\"\n [class.cursor-not-allowed]=\"isDisabledSearch\"\n [class._shk-bg-surface-50]=\"isDisabledSearch\"\n [class.dark:[background-color:var(--shk-surface-100)]]=\"isDisabledSearch\"\n [class._shk-text-surface-400]=\"isDisabledSearch\"\n [class.dark:[color:var(--shk-surface-400)]]=\"isDisabledSearch\"\n class=\"block w-full px-3 py-2 _shk-text-surface-700 dark:[color:var(--shk-surface-700)] _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] border rounded-l-lg transition-colors placeholder:[color:var(--shk-surface-400)] dark:placeholder:[color:var(--shk-surface-400)] focus:[background-color:var(--shk-surface-50)] dark:focus:[background-color:var(--shk-surface-100)] sm:text-sm\"\n [ngClass]=\"{\n 'border-red-500': shouldShowError() && !isDisabledSearch,\n '_shk-border': !shouldShowError() || isDisabledSearch,\n 'cursor-pointer': !isDisabledSearch,\n 'cursor-not-allowed _shk-text-surface-400 dark:[color:var(--shk-surface-400)]': isDisabledSearch\n }\"\n />\n <button\n type=\"button\"\n (click)=\"searchButtonClick.emit()\"\n tabindex=\"-1\"\n [disabled]=\"isDisabledSearch\"\n class=\"px-3 flex items-center justify-center shrink-0 _shk-bg-primary hover:[background-color:var(--shk-primary-700)] text-white border _shk-border-primary rounded-r-lg transition-colors duration-200 disabled:[background-color:var(--shk-surface-300)] dark:disabled:[background-color:var(--shk-surface-200)] disabled:[border-color:var(--shk-surface-300)] dark:disabled:[border-color:var(--shk-surface-200)] disabled:cursor-not-allowed\"\n >\n <svg [lucideIcon]=\"getIcon('search')\" class=\"w-4 h-4\"></svg>\n </button>\n }\n\n @if (!searchMode()) {\n <input\n #input\n [id]=\"id()\"\n [maxlength]=\"maxLength() || (formatCard() ? 19 : null)\"\n [min]=\"type() === 'number' && preventNegative() ? '0' : null\"\n (keypress)=\"type() === 'number' || numbersOnly() ? numberValidation($event) : null\"\n [type]=\"effectiveType()\"\n [formControl]=\"$any(actualControl())\"\n [placeholder]=\"placeholder() || label()\"\n (input)=\"onInput($event)\"\n autocomplete=\"new-password\"\n (blur)=\"onBlur()\"\n class=\"block w-full px-3 py-2 _shk-text-surface-700 dark:[color:var(--shk-surface-700)] _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] border rounded-lg transition-colors placeholder:[color:var(--shk-surface-400)] dark:placeholder:[color:var(--shk-surface-400)] focus:outline-none focus:[background-color:var(--shk-surface-50)] dark:focus:[background-color:var(--shk-surface-100)] focus:ring-1 disabled:[background-color:var(--shk-surface-50)] dark:disabled:[background-color:var(--shk-surface-100)] disabled:cursor-not-allowed sm:text-sm\"\n [ngClass]=\"{\n 'border-red-500 focus:border-red-500 focus:ring-red-500': shouldShowError(),\n 'border-green-500 focus:border-green-500 focus:ring-green-500': wasFixedError(),\n '_shk-border focus:[border-color:var(--shk-primary-500)] focus:[--tw-ring-color:var(--shk-primary-500)]': !shouldShowError() && !wasFixedError()\n }\"\n [class.pr-8]=\"type() === 'password' && actualControl()?.value?.length > 0\"\n [class.pr-3]=\"type() !== 'password' || !actualControl()?.value?.length\"\n />\n\n @if (type() === 'password' && actualControl()?.value?.length > 0) {\n <button\n type=\"button\"\n (click)=\"togglePasswordVisibility()\"\n [disabled]=\"actualControl()?.disabled\"\n class=\"absolute right-3 top-1/2 -translate-y-1/2 _shk-text-surface-400 dark:[color:var(--shk-surface-400)] hover:[color:var(--shk-surface-600)] dark:hover:[color:var(--shk-surface-600)] focus:outline-none\"\n >\n @if (showPassword()) {\n <svg [lucideIcon]=\"getIcon('eye-off')\" class=\"w-4 h-4\"></svg>\n } @else {\n <svg [lucideIcon]=\"getIcon('eye')\" class=\"w-4 h-4\"></svg>\n }\n </button>\n }\n }\n </div>\n }\n\n @if (isTextArea()) {\n <textarea\n #textarea\n [id]=\"id()\"\n [formControl]=\"$any(actualControl())\"\n [placeholder]=\"placeholder() || label()\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n [class]=\"isTextArea() ? textAreaHeight() : 'h-28'\"\n class=\"block w-full px-3 py-2 _shk-text-surface-700 dark:[color:var(--shk-surface-700)] _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] border rounded-lg transition-colors placeholder:[color:var(--shk-surface-400)] dark:placeholder:[color:var(--shk-surface-400)] focus:outline-none focus:[background-color:var(--shk-surface-50)] dark:focus:[background-color:var(--shk-surface-100)] focus:ring-1 resize-none disabled:[background-color:var(--shk-surface-50)] dark:disabled:[background-color:var(--shk-surface-100)] disabled:cursor-not-allowed disabled:[color:var(--shk-surface-400)] dark:disabled:[color:var(--shk-surface-400)] sm:text-sm\"\n [ngClass]=\"{\n 'border-red-500 focus:border-red-500 focus:ring-red-500': shouldShowError(),\n 'border-green-500 focus:border-green-500 focus:ring-green-500': wasFixedError(),\n '_shk-border focus:[border-color:var(--shk-primary-500)] focus:[--tw-ring-color:var(--shk-primary-500)]': !shouldShowError() && !wasFixedError()\n }\"\n ></textarea>\n }\n </div>\n\n @if (shouldShowError()) {\n <div class=\"mt-1 text-xs text-red-500 max-h-20 overflow-y-auto\" tabindex=\"-1\">\n <ul class=\"list-disc pl-4 space-y-1\">\n @for (error of getErrorMessages(); track error) {\n <li>{{ error }}</li>\n }\n </ul>\n </div>\n }\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { 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.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: LucideDynamicIcon, selector: "svg[lucideIcon]", inputs: ["lucideIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
303
304
  }
304
305
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: TextFieldComponent, decorators: [{
305
306
  type: Component,
@@ -309,7 +310,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImpo
309
310
  useExisting: forwardRef(() => TextFieldComponent),
310
311
  multi: true,
311
312
  },
312
- ], template: "<div class=\"relative mb-4\">\n @if (label()) {\n <div class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-300)] mb-1\">\n {{ label() }}\n </div>\n }\n\n <div class=\"relative\">\n @if (!isTextArea()) {\n <div class=\"flex\">\n @if (searchMode()) {\n @let isDisabledSearch = actualControl()?.disabled || isDisabled();\n <input\n #input\n [id]=\"id()\"\n type=\"text\"\n [value]=\"displayValue() || ''\"\n [placeholder]=\"placeholder() || label()\"\n [readOnly]=\"true\"\n [disabled]=\"isDisabledSearch\"\n (click)=\"!isDisabledSearch && searchButtonClick.emit()\"\n (keydown.enter)=\"!isDisabledSearch && searchButtonClick.emit()\"\n (blur)=\"onBlur()\"\n autocomplete=\"off\"\n [class.cursor-pointer]=\"!isDisabledSearch\"\n [class.cursor-not-allowed]=\"isDisabledSearch\"\n [class._shk-bg-surface-50]=\"isDisabledSearch\"\n [class.dark:[background-color:var(--shk-surface-800)]]=\"isDisabledSearch\"\n [class._shk-text-surface-400]=\"isDisabledSearch\"\n [class.dark:[color:var(--shk-surface-500)]]=\"isDisabledSearch\"\n class=\"block w-full px-3 py-2 _shk-text-surface-700 dark:[color:var(--shk-surface-200)] _shk-bg-surface-50 dark:[background-color:var(--shk-surface-800)] border rounded-l-lg transition-colors placeholder:[color:var(--shk-surface-400)] dark:placeholder:[color:var(--shk-surface-500)] focus:[background-color:var(--shk-surface-50)] dark:focus:[background-color:var(--shk-surface-800)] sm:text-sm\"\n [ngClass]=\"{\n 'border-red-500': shouldShowError() && !isDisabledSearch,\n '_shk-border dark:[border-color:var(--shk-surface-700)]': !shouldShowError() || isDisabledSearch,\n 'cursor-pointer': !isDisabledSearch,\n 'cursor-not-allowed _shk-text-surface-400 dark:[color:var(--shk-surface-500)]': isDisabledSearch\n }\"\n />\n <button\n type=\"button\"\n (click)=\"searchButtonClick.emit()\"\n tabindex=\"-1\"\n [disabled]=\"isDisabledSearch\"\n class=\"px-3 flex items-center justify-center shrink-0 _shk-bg-primary hover:[background-color:var(--shk-primary-700)] text-white border _shk-border-primary rounded-r-lg transition-colors duration-200 disabled:[background-color:var(--shk-surface-300)] dark:disabled:[background-color:var(--shk-surface-700)] disabled:[border-color:var(--shk-surface-300)] dark:disabled:[border-color:var(--shk-surface-700)] disabled:cursor-not-allowed\"\n >\n <svg [lucideIcon]=\"getIcon('search')\" class=\"w-4 h-4\"></svg>\n </button>\n }\n\n @if (!searchMode()) {\n <input\n #input\n [id]=\"id()\"\n [maxlength]=\"maxLength() || (formatCard() ? 19 : null)\"\n [min]=\"type() === 'number' && preventNegative() ? '0' : null\"\n (keypress)=\"type() === 'number' || numbersOnly() ? numberValidation($event) : null\"\n [type]=\"effectiveType()\"\n [formControl]=\"$any(actualControl())\"\n [placeholder]=\"placeholder() || label()\"\n (input)=\"onInput($event)\"\n autocomplete=\"new-password\"\n (blur)=\"onBlur()\"\n class=\"block w-full px-3 py-2 _shk-text-surface-700 dark:[color:var(--shk-surface-200)] _shk-bg-surface-50 dark:[background-color:var(--shk-surface-800)] border rounded-lg transition-colors placeholder:[color:var(--shk-surface-400)] dark:placeholder:[color:var(--shk-surface-500)] focus:outline-none focus:[background-color:var(--shk-surface-50)] dark:focus:[background-color:var(--shk-surface-800)] focus:ring-1 disabled:[background-color:var(--shk-surface-50)] dark:disabled:[background-color:var(--shk-surface-800)] disabled:cursor-not-allowed sm:text-sm\"\n [ngClass]=\"{\n 'border-red-500 focus:border-red-500 focus:ring-red-500': shouldShowError(),\n 'border-green-500 focus:border-green-500 focus:ring-green-500': wasFixedError(),\n '_shk-border dark:[border-color:var(--shk-surface-700)] focus:[border-color:var(--shk-primary-500)] focus:[--tw-ring-color:var(--shk-primary-500)]': !shouldShowError() && !wasFixedError()\n }\"\n [class.pr-8]=\"type() === 'password' && actualControl()?.value?.length > 0\"\n [class.pr-3]=\"type() !== 'password' || !actualControl()?.value?.length\"\n />\n\n @if (type() === 'password' && actualControl()?.value?.length > 0) {\n <button\n type=\"button\"\n (click)=\"togglePasswordVisibility()\"\n [disabled]=\"actualControl()?.disabled\"\n class=\"absolute right-3 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)] focus:outline-none\"\n >\n @if (showPassword()) {\n <svg [lucideIcon]=\"getIcon('eye-off')\" class=\"w-4 h-4\"></svg>\n } @else {\n <svg [lucideIcon]=\"getIcon('eye')\" class=\"w-4 h-4\"></svg>\n }\n </button>\n }\n }\n </div>\n }\n\n @if (isTextArea()) {\n <textarea\n #textarea\n [id]=\"id()\"\n [formControl]=\"$any(actualControl())\"\n [placeholder]=\"placeholder() || label()\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n [class]=\"isTextArea() ? textAreaHeight() : 'h-28'\"\n class=\"block w-full px-3 py-2 _shk-text-surface-700 dark:[color:var(--shk-surface-200)] _shk-bg-surface-50 dark:[background-color:var(--shk-surface-800)] border rounded-lg transition-colors placeholder:[color:var(--shk-surface-400)] dark:placeholder:[color:var(--shk-surface-500)] focus:outline-none focus:[background-color:var(--shk-surface-50)] dark:focus:[background-color:var(--shk-surface-800)] focus:ring-1 resize-none disabled:[background-color:var(--shk-surface-50)] dark:disabled:[background-color:var(--shk-surface-800)] disabled:cursor-not-allowed disabled:[color:var(--shk-surface-400)] dark:disabled:[color:var(--shk-surface-500)] sm:text-sm\"\n [ngClass]=\"{\n 'border-red-500 focus:border-red-500 focus:ring-red-500': shouldShowError(),\n 'border-green-500 focus:border-green-500 focus:ring-green-500': wasFixedError(),\n '_shk-border dark:[border-color:var(--shk-surface-700)] focus:[border-color:var(--shk-primary-500)] focus:[--tw-ring-color:var(--shk-primary-500)]': !shouldShowError() && !wasFixedError()\n }\"\n ></textarea>\n }\n </div>\n\n @if (shouldShowError()) {\n <div class=\"mt-1 text-xs text-red-500 max-h-20 overflow-y-auto\" tabindex=\"-1\">\n <ul class=\"list-disc pl-4 space-y-1\">\n @for (error of getErrorMessages(); track error) {\n <li>{{ error }}</li>\n }\n </ul>\n </div>\n }\n</div>\n" }]
313
+ ], template: "<div class=\"relative mb-4\">\n @if (label()) {\n <div class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-600)] mb-1\">\n {{ label() }}\n </div>\n }\n\n <div class=\"relative\">\n @if (!isTextArea()) {\n <div class=\"flex\">\n @if (searchMode()) {\n @let isDisabledSearch = actualControl()?.disabled || isDisabled();\n <input\n #input\n [id]=\"id()\"\n type=\"text\"\n [value]=\"displayValue() || ''\"\n [placeholder]=\"placeholder() || label()\"\n [readOnly]=\"true\"\n [disabled]=\"isDisabledSearch\"\n (click)=\"!isDisabledSearch && searchButtonClick.emit()\"\n (keydown.enter)=\"!isDisabledSearch && searchButtonClick.emit()\"\n (blur)=\"onBlur()\"\n autocomplete=\"off\"\n [class.cursor-pointer]=\"!isDisabledSearch\"\n [class.cursor-not-allowed]=\"isDisabledSearch\"\n [class._shk-bg-surface-50]=\"isDisabledSearch\"\n [class.dark:[background-color:var(--shk-surface-100)]]=\"isDisabledSearch\"\n [class._shk-text-surface-400]=\"isDisabledSearch\"\n [class.dark:[color:var(--shk-surface-400)]]=\"isDisabledSearch\"\n class=\"block w-full px-3 py-2 _shk-text-surface-700 dark:[color:var(--shk-surface-700)] _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] border rounded-l-lg transition-colors placeholder:[color:var(--shk-surface-400)] dark:placeholder:[color:var(--shk-surface-400)] focus:[background-color:var(--shk-surface-50)] dark:focus:[background-color:var(--shk-surface-100)] sm:text-sm\"\n [ngClass]=\"{\n 'border-red-500': shouldShowError() && !isDisabledSearch,\n '_shk-border': !shouldShowError() || isDisabledSearch,\n 'cursor-pointer': !isDisabledSearch,\n 'cursor-not-allowed _shk-text-surface-400 dark:[color:var(--shk-surface-400)]': isDisabledSearch\n }\"\n />\n <button\n type=\"button\"\n (click)=\"searchButtonClick.emit()\"\n tabindex=\"-1\"\n [disabled]=\"isDisabledSearch\"\n class=\"px-3 flex items-center justify-center shrink-0 _shk-bg-primary hover:[background-color:var(--shk-primary-700)] text-white border _shk-border-primary rounded-r-lg transition-colors duration-200 disabled:[background-color:var(--shk-surface-300)] dark:disabled:[background-color:var(--shk-surface-200)] disabled:[border-color:var(--shk-surface-300)] dark:disabled:[border-color:var(--shk-surface-200)] disabled:cursor-not-allowed\"\n >\n <svg [lucideIcon]=\"getIcon('search')\" class=\"w-4 h-4\"></svg>\n </button>\n }\n\n @if (!searchMode()) {\n <input\n #input\n [id]=\"id()\"\n [maxlength]=\"maxLength() || (formatCard() ? 19 : null)\"\n [min]=\"type() === 'number' && preventNegative() ? '0' : null\"\n (keypress)=\"type() === 'number' || numbersOnly() ? numberValidation($event) : null\"\n [type]=\"effectiveType()\"\n [formControl]=\"$any(actualControl())\"\n [placeholder]=\"placeholder() || label()\"\n (input)=\"onInput($event)\"\n autocomplete=\"new-password\"\n (blur)=\"onBlur()\"\n class=\"block w-full px-3 py-2 _shk-text-surface-700 dark:[color:var(--shk-surface-700)] _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] border rounded-lg transition-colors placeholder:[color:var(--shk-surface-400)] dark:placeholder:[color:var(--shk-surface-400)] focus:outline-none focus:[background-color:var(--shk-surface-50)] dark:focus:[background-color:var(--shk-surface-100)] focus:ring-1 disabled:[background-color:var(--shk-surface-50)] dark:disabled:[background-color:var(--shk-surface-100)] disabled:cursor-not-allowed sm:text-sm\"\n [ngClass]=\"{\n 'border-red-500 focus:border-red-500 focus:ring-red-500': shouldShowError(),\n 'border-green-500 focus:border-green-500 focus:ring-green-500': wasFixedError(),\n '_shk-border focus:[border-color:var(--shk-primary-500)] focus:[--tw-ring-color:var(--shk-primary-500)]': !shouldShowError() && !wasFixedError()\n }\"\n [class.pr-8]=\"type() === 'password' && actualControl()?.value?.length > 0\"\n [class.pr-3]=\"type() !== 'password' || !actualControl()?.value?.length\"\n />\n\n @if (type() === 'password' && actualControl()?.value?.length > 0) {\n <button\n type=\"button\"\n (click)=\"togglePasswordVisibility()\"\n [disabled]=\"actualControl()?.disabled\"\n class=\"absolute right-3 top-1/2 -translate-y-1/2 _shk-text-surface-400 dark:[color:var(--shk-surface-400)] hover:[color:var(--shk-surface-600)] dark:hover:[color:var(--shk-surface-600)] focus:outline-none\"\n >\n @if (showPassword()) {\n <svg [lucideIcon]=\"getIcon('eye-off')\" class=\"w-4 h-4\"></svg>\n } @else {\n <svg [lucideIcon]=\"getIcon('eye')\" class=\"w-4 h-4\"></svg>\n }\n </button>\n }\n }\n </div>\n }\n\n @if (isTextArea()) {\n <textarea\n #textarea\n [id]=\"id()\"\n [formControl]=\"$any(actualControl())\"\n [placeholder]=\"placeholder() || label()\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n [class]=\"isTextArea() ? textAreaHeight() : 'h-28'\"\n class=\"block w-full px-3 py-2 _shk-text-surface-700 dark:[color:var(--shk-surface-700)] _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] border rounded-lg transition-colors placeholder:[color:var(--shk-surface-400)] dark:placeholder:[color:var(--shk-surface-400)] focus:outline-none focus:[background-color:var(--shk-surface-50)] dark:focus:[background-color:var(--shk-surface-100)] focus:ring-1 resize-none disabled:[background-color:var(--shk-surface-50)] dark:disabled:[background-color:var(--shk-surface-100)] disabled:cursor-not-allowed disabled:[color:var(--shk-surface-400)] dark:disabled:[color:var(--shk-surface-400)] sm:text-sm\"\n [ngClass]=\"{\n 'border-red-500 focus:border-red-500 focus:ring-red-500': shouldShowError(),\n 'border-green-500 focus:border-green-500 focus:ring-green-500': wasFixedError(),\n '_shk-border focus:[border-color:var(--shk-primary-500)] focus:[--tw-ring-color:var(--shk-primary-500)]': !shouldShowError() && !wasFixedError()\n }\"\n ></textarea>\n }\n </div>\n\n @if (shouldShowError()) {\n <div class=\"mt-1 text-xs text-red-500 max-h-20 overflow-y-auto\" tabindex=\"-1\">\n <ul class=\"list-disc pl-4 space-y-1\">\n @for (error of getErrorMessages(); track error) {\n <li>{{ error }}</li>\n }\n </ul>\n </div>\n }\n</div>\n" }]
313
314
  }], ctorParameters: () => [], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], formatCard: [{ type: i0.Input, args: [{ isSignal: true, alias: "formatCard", required: false }] }], preventNegative: [{ type: i0.Input, args: [{ isSignal: true, alias: "preventNegative", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], numbersOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "numbersOnly", required: false }] }], allowDecimals: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowDecimals", required: false }] }], maxLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxLength", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], errorMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessages", required: false }] }], formGroup: [{ type: i0.Input, args: [{ isSignal: true, alias: "formGroup", required: false }] }], control: [{ type: i0.Input, args: [{ isSignal: true, alias: "control", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], isTextArea: [{ type: i0.Input, args: [{ isSignal: true, alias: "isTextArea", required: false }] }], textAreaHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "textAreaHeight", required: false }] }], searchMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchMode", required: false }] }], displayValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayValue", required: false }] }], searchButtonClick: [{ type: i0.Output, args: ["searchButtonClick"] }], inputElement: [{ type: i0.ViewChild, args: ['input', { isSignal: true }] }], textareaElement: [{ type: i0.ViewChild, args: ['textarea', { isSignal: true }] }] } });
314
315
 
315
316
  class NotificationService {
@@ -1028,11 +1029,11 @@ class ConfirmDialogComponent {
1028
1029
  this.resolveRef.set(null);
1029
1030
  }
1030
1031
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: ConfirmDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1031
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: ConfirmDialogComponent, isStandalone: true, selector: "shk-confirm-dialog", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: false, transformFunction: null }, confirmLabel: { classPropertyName: "confirmLabel", publicName: "confirmLabel", isSignal: true, isRequired: false, transformFunction: null }, cancelLabel: { classPropertyName: "cancelLabel", publicName: "cancelLabel", isSignal: true, isRequired: false, transformFunction: null }, loadingText: { classPropertyName: "loadingText", publicName: "loadingText", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, showCancel: { classPropertyName: "showCancel", publicName: "showCancel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed" }, ngImport: i0, template: "@if (visible()) {\n <div\n class=\"fixed inset-0 bg-black/40 backdrop-blur-sm flex items-center justify-center z-[9999] p-4\"\n (click)=\"onCancel()\"\n >\n <div\n class=\"bg-white dark:[background-color:var(--shk-surface-800)] rounded-2xl shadow-2xl max-w-sm w-full animate-in fade-in zoom-in duration-200 overflow-hidden\"\n (click)=\"$event.stopPropagation()\"\n >\n <div\n class=\"h-1.5 w-full\"\n [class._shk-gradient-red]=\"type() === 'danger'\"\n [class._shk-gradient-blue]=\"type() === 'info'\"\n [class._shk-bg-amber-400]=\"type() === 'warning'\"\n ></div>\n <div class=\"p-6\">\n <div class=\"flex items-start gap-4 mb-4\">\n <div\n class=\"w-12 h-12 rounded-full flex items-center justify-center shrink-0\"\n [ngClass]=\"{\n '_shk-bg-red-soft _shk-dark-bg-red-soft _shk-text-red-600 dark:[color:var(--shk-error-400)]': type() === 'danger',\n '_shk-bg-blue-soft _shk-dark-bg-blue-soft _shk-text-blue-600 dark:[color:var(--shk-info-400)]': type() === 'info',\n '_shk-bg-amber-soft _shk-dark-bg-amber-soft _shk-text-amber-600 dark:[color:var(--shk-amber-400)]': type() === 'warning',\n }\"\n >\n @if (type() === 'info') {\n <svg [lucideIcon]=\"getIcon('info')\" class=\"w-6 h-6\"></svg>\n } @else {\n <svg [lucideIcon]=\"getIcon('triangle-alert')\" class=\"w-6 h-6\"></svg>\n }\n </div>\n <div>\n <h3 class=\"text-lg font-bold _shk-text-surface-800 dark:[color:var(--shk-surface-100)]\">{{ title() }}</h3>\n <p class=\"_shk-text-surface-500 dark:[color:var(--shk-surface-400)] text-sm leading-relaxed mb-6\">{{ message() }}</p>\n </div>\n </div>\n <div class=\"flex gap-3\">\n @if (showCancel()) {\n <button\n type=\"button\"\n (click)=\"onCancel()\"\n [disabled]=\"loading()\"\n class=\"flex-1 px-4 py-2 text-sm font-semibold _shk-text-surface-600 dark:[color:var(--shk-surface-300)] _shk-bg-surface-100 dark:[background-color:var(--shk-surface-700)] hover:[background-color:var(--shk-surface-200)] dark:hover:[background-color:var(--shk-surface-600)] rounded-lg transition-colors flex items-center justify-center gap-2\"\n >\n <svg [lucideIcon]=\"getIcon('x')\" class=\"w-4 h-4\"></svg>\n {{ cancelLabel() }}\n </button>\n }\n <button\n type=\"button\"\n (click)=\"onConfirm()\"\n [disabled]=\"loading()\"\n class=\"flex-1 px-4 py-2 text-sm font-semibold text-white rounded-lg shadow-md transition-all flex items-center justify-center gap-2\"\n [class._shk-bg-red-600]=\"type() === 'danger'\"\n [class.hover:[background-color:var(--shk-error-700)]]=\"type() === 'danger'\"\n [class.[box-shadow:0_0_0_1px_var(--shk-error-500)_inset]]=\"type() === 'danger'\"\n [class._shk-bg-primary]=\"type() === 'info'\"\n [class.hover:[background-color:var(--shk-primary-700)]]=\"type() === 'info'\"\n [class.[box-shadow:0_0_0_1px_var(--shk-primary-500)_inset]]=\"type() === 'info'\"\n [class._shk-bg-amber-600]=\"type() === 'warning'\"\n [class.hover:[background-color:var(--shk-amber-700)]]=\"type() === 'warning'\"\n [class.[box-shadow:0_0_0_1px_var(--shk-amber-500)_inset]]=\"type() === 'warning'\"\n >\n @if (loading()) {\n <svg [lucideIcon]=\"getIcon('loader')\" class=\"w-4 h-4 animate-spin\"></svg>\n } @else if (type() === 'danger') {\n <svg [lucideIcon]=\"getIcon('trash-2')\" class=\"w-4 h-4\"></svg>\n }\n {{ loading() ? loadingText() : confirmLabel() }}\n </button>\n </div>\n </div>\n </div>\n </div>\n}\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: LucideDynamicIcon, selector: "svg[lucideIcon]", inputs: ["lucideIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1032
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: ConfirmDialogComponent, isStandalone: true, selector: "shk-confirm-dialog", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: false, transformFunction: null }, confirmLabel: { classPropertyName: "confirmLabel", publicName: "confirmLabel", isSignal: true, isRequired: false, transformFunction: null }, cancelLabel: { classPropertyName: "cancelLabel", publicName: "cancelLabel", isSignal: true, isRequired: false, transformFunction: null }, loadingText: { classPropertyName: "loadingText", publicName: "loadingText", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, showCancel: { classPropertyName: "showCancel", publicName: "showCancel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed" }, ngImport: i0, template: "@if (visible()) {\n <div\n class=\"fixed inset-0 bg-black/40 backdrop-blur-sm flex items-center justify-center z-[9999] p-4\"\n (click)=\"onCancel()\"\n >\n <div\n class=\"bg-white dark:[background-color:var(--shk-surface-100)] rounded-2xl shadow-2xl max-w-sm w-full animate-in fade-in zoom-in duration-200 overflow-hidden\"\n (click)=\"$event.stopPropagation()\"\n >\n <div\n class=\"h-1.5 w-full\"\n [class._shk-gradient-red]=\"type() === 'danger'\"\n [class._shk-gradient-blue]=\"type() === 'info'\"\n [class._shk-bg-amber-400]=\"type() === 'warning'\"\n ></div>\n <div class=\"p-6\">\n <div class=\"flex items-start gap-4 mb-4\">\n <div\n class=\"w-12 h-12 rounded-full flex items-center justify-center shrink-0\"\n [ngClass]=\"{\n '_shk-bg-red-soft _shk-text-red-600 dark:[color:var(--shk-error-400)]': type() === 'danger',\n '_shk-bg-blue-soft _shk-text-blue-600 dark:[color:var(--shk-info-400)]': type() === 'info',\n '_shk-bg-amber-soft _shk-text-amber-600 dark:[color:var(--shk-amber-400)]': type() === 'warning',\n }\"\n >\n @if (type() === 'info') {\n <svg [lucideIcon]=\"getIcon('info')\" class=\"w-6 h-6\"></svg>\n } @else {\n <svg [lucideIcon]=\"getIcon('triangle-alert')\" class=\"w-6 h-6\"></svg>\n }\n </div>\n <div>\n <h3 class=\"text-lg font-bold _shk-text-surface-800 dark:[color:var(--shk-surface-800)]\">{{ title() }}</h3>\n <p class=\"_shk-text-surface-500 dark:[color:var(--shk-surface-400)] text-sm leading-relaxed mb-6\">{{ message() }}</p>\n </div>\n </div>\n <div class=\"flex gap-3\">\n @if (showCancel()) {\n <button\n type=\"button\"\n (click)=\"onCancel()\"\n [disabled]=\"loading()\"\n class=\"flex-1 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 justify-center gap-2\"\n >\n <svg [lucideIcon]=\"getIcon('x')\" class=\"w-4 h-4\"></svg>\n {{ cancelLabel() }}\n </button>\n }\n <button\n type=\"button\"\n (click)=\"onConfirm()\"\n [disabled]=\"loading()\"\n class=\"flex-1 px-4 py-2 text-sm font-semibold text-white rounded-lg shadow-md transition-all flex items-center justify-center gap-2\"\n [class._shk-bg-red-600]=\"type() === 'danger'\"\n [class.hover:[background-color:var(--shk-error-700)]]=\"type() === 'danger'\"\n [class.[box-shadow:0_0_0_1px_var(--shk-error-500)_inset]]=\"type() === 'danger'\"\n [class._shk-bg-primary]=\"type() === 'info'\"\n [class.hover:[background-color:var(--shk-primary-700)]]=\"type() === 'info'\"\n [class.[box-shadow:0_0_0_1px_var(--shk-primary-500)_inset]]=\"type() === 'info'\"\n [class._shk-bg-amber-600]=\"type() === 'warning'\"\n [class.hover:[background-color:var(--shk-amber-700)]]=\"type() === 'warning'\"\n [class.[box-shadow:0_0_0_1px_var(--shk-amber-500)_inset]]=\"type() === 'warning'\"\n >\n @if (loading()) {\n <svg [lucideIcon]=\"getIcon('loader')\" class=\"w-4 h-4 animate-spin\"></svg>\n } @else if (type() === 'danger') {\n <svg [lucideIcon]=\"getIcon('trash-2')\" class=\"w-4 h-4\"></svg>\n }\n {{ loading() ? loadingText() : confirmLabel() }}\n </button>\n </div>\n </div>\n </div>\n </div>\n}\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: LucideDynamicIcon, selector: "svg[lucideIcon]", inputs: ["lucideIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1032
1033
  }
1033
1034
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: ConfirmDialogComponent, decorators: [{
1034
1035
  type: Component,
1035
- args: [{ selector: 'shk-confirm-dialog', 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-[9999] p-4\"\n (click)=\"onCancel()\"\n >\n <div\n class=\"bg-white dark:[background-color:var(--shk-surface-800)] rounded-2xl shadow-2xl max-w-sm w-full animate-in fade-in zoom-in duration-200 overflow-hidden\"\n (click)=\"$event.stopPropagation()\"\n >\n <div\n class=\"h-1.5 w-full\"\n [class._shk-gradient-red]=\"type() === 'danger'\"\n [class._shk-gradient-blue]=\"type() === 'info'\"\n [class._shk-bg-amber-400]=\"type() === 'warning'\"\n ></div>\n <div class=\"p-6\">\n <div class=\"flex items-start gap-4 mb-4\">\n <div\n class=\"w-12 h-12 rounded-full flex items-center justify-center shrink-0\"\n [ngClass]=\"{\n '_shk-bg-red-soft _shk-dark-bg-red-soft _shk-text-red-600 dark:[color:var(--shk-error-400)]': type() === 'danger',\n '_shk-bg-blue-soft _shk-dark-bg-blue-soft _shk-text-blue-600 dark:[color:var(--shk-info-400)]': type() === 'info',\n '_shk-bg-amber-soft _shk-dark-bg-amber-soft _shk-text-amber-600 dark:[color:var(--shk-amber-400)]': type() === 'warning',\n }\"\n >\n @if (type() === 'info') {\n <svg [lucideIcon]=\"getIcon('info')\" class=\"w-6 h-6\"></svg>\n } @else {\n <svg [lucideIcon]=\"getIcon('triangle-alert')\" class=\"w-6 h-6\"></svg>\n }\n </div>\n <div>\n <h3 class=\"text-lg font-bold _shk-text-surface-800 dark:[color:var(--shk-surface-100)]\">{{ title() }}</h3>\n <p class=\"_shk-text-surface-500 dark:[color:var(--shk-surface-400)] text-sm leading-relaxed mb-6\">{{ message() }}</p>\n </div>\n </div>\n <div class=\"flex gap-3\">\n @if (showCancel()) {\n <button\n type=\"button\"\n (click)=\"onCancel()\"\n [disabled]=\"loading()\"\n class=\"flex-1 px-4 py-2 text-sm font-semibold _shk-text-surface-600 dark:[color:var(--shk-surface-300)] _shk-bg-surface-100 dark:[background-color:var(--shk-surface-700)] hover:[background-color:var(--shk-surface-200)] dark:hover:[background-color:var(--shk-surface-600)] rounded-lg transition-colors flex items-center justify-center gap-2\"\n >\n <svg [lucideIcon]=\"getIcon('x')\" class=\"w-4 h-4\"></svg>\n {{ cancelLabel() }}\n </button>\n }\n <button\n type=\"button\"\n (click)=\"onConfirm()\"\n [disabled]=\"loading()\"\n class=\"flex-1 px-4 py-2 text-sm font-semibold text-white rounded-lg shadow-md transition-all flex items-center justify-center gap-2\"\n [class._shk-bg-red-600]=\"type() === 'danger'\"\n [class.hover:[background-color:var(--shk-error-700)]]=\"type() === 'danger'\"\n [class.[box-shadow:0_0_0_1px_var(--shk-error-500)_inset]]=\"type() === 'danger'\"\n [class._shk-bg-primary]=\"type() === 'info'\"\n [class.hover:[background-color:var(--shk-primary-700)]]=\"type() === 'info'\"\n [class.[box-shadow:0_0_0_1px_var(--shk-primary-500)_inset]]=\"type() === 'info'\"\n [class._shk-bg-amber-600]=\"type() === 'warning'\"\n [class.hover:[background-color:var(--shk-amber-700)]]=\"type() === 'warning'\"\n [class.[box-shadow:0_0_0_1px_var(--shk-amber-500)_inset]]=\"type() === 'warning'\"\n >\n @if (loading()) {\n <svg [lucideIcon]=\"getIcon('loader')\" class=\"w-4 h-4 animate-spin\"></svg>\n } @else if (type() === 'danger') {\n <svg [lucideIcon]=\"getIcon('trash-2')\" class=\"w-4 h-4\"></svg>\n }\n {{ loading() ? loadingText() : confirmLabel() }}\n </button>\n </div>\n </div>\n </div>\n </div>\n}\n" }]
1036
+ args: [{ selector: 'shk-confirm-dialog', 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-[9999] p-4\"\n (click)=\"onCancel()\"\n >\n <div\n class=\"bg-white dark:[background-color:var(--shk-surface-100)] rounded-2xl shadow-2xl max-w-sm w-full animate-in fade-in zoom-in duration-200 overflow-hidden\"\n (click)=\"$event.stopPropagation()\"\n >\n <div\n class=\"h-1.5 w-full\"\n [class._shk-gradient-red]=\"type() === 'danger'\"\n [class._shk-gradient-blue]=\"type() === 'info'\"\n [class._shk-bg-amber-400]=\"type() === 'warning'\"\n ></div>\n <div class=\"p-6\">\n <div class=\"flex items-start gap-4 mb-4\">\n <div\n class=\"w-12 h-12 rounded-full flex items-center justify-center shrink-0\"\n [ngClass]=\"{\n '_shk-bg-red-soft _shk-text-red-600 dark:[color:var(--shk-error-400)]': type() === 'danger',\n '_shk-bg-blue-soft _shk-text-blue-600 dark:[color:var(--shk-info-400)]': type() === 'info',\n '_shk-bg-amber-soft _shk-text-amber-600 dark:[color:var(--shk-amber-400)]': type() === 'warning',\n }\"\n >\n @if (type() === 'info') {\n <svg [lucideIcon]=\"getIcon('info')\" class=\"w-6 h-6\"></svg>\n } @else {\n <svg [lucideIcon]=\"getIcon('triangle-alert')\" class=\"w-6 h-6\"></svg>\n }\n </div>\n <div>\n <h3 class=\"text-lg font-bold _shk-text-surface-800 dark:[color:var(--shk-surface-800)]\">{{ title() }}</h3>\n <p class=\"_shk-text-surface-500 dark:[color:var(--shk-surface-400)] text-sm leading-relaxed mb-6\">{{ message() }}</p>\n </div>\n </div>\n <div class=\"flex gap-3\">\n @if (showCancel()) {\n <button\n type=\"button\"\n (click)=\"onCancel()\"\n [disabled]=\"loading()\"\n class=\"flex-1 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 justify-center gap-2\"\n >\n <svg [lucideIcon]=\"getIcon('x')\" class=\"w-4 h-4\"></svg>\n {{ cancelLabel() }}\n </button>\n }\n <button\n type=\"button\"\n (click)=\"onConfirm()\"\n [disabled]=\"loading()\"\n class=\"flex-1 px-4 py-2 text-sm font-semibold text-white rounded-lg shadow-md transition-all flex items-center justify-center gap-2\"\n [class._shk-bg-red-600]=\"type() === 'danger'\"\n [class.hover:[background-color:var(--shk-error-700)]]=\"type() === 'danger'\"\n [class.[box-shadow:0_0_0_1px_var(--shk-error-500)_inset]]=\"type() === 'danger'\"\n [class._shk-bg-primary]=\"type() === 'info'\"\n [class.hover:[background-color:var(--shk-primary-700)]]=\"type() === 'info'\"\n [class.[box-shadow:0_0_0_1px_var(--shk-primary-500)_inset]]=\"type() === 'info'\"\n [class._shk-bg-amber-600]=\"type() === 'warning'\"\n [class.hover:[background-color:var(--shk-amber-700)]]=\"type() === 'warning'\"\n [class.[box-shadow:0_0_0_1px_var(--shk-amber-500)_inset]]=\"type() === 'warning'\"\n >\n @if (loading()) {\n <svg [lucideIcon]=\"getIcon('loader')\" class=\"w-4 h-4 animate-spin\"></svg>\n } @else if (type() === 'danger') {\n <svg [lucideIcon]=\"getIcon('trash-2')\" class=\"w-4 h-4\"></svg>\n }\n {{ loading() ? loadingText() : confirmLabel() }}\n </button>\n </div>\n </div>\n </div>\n </div>\n}\n" }]
1036
1037
  }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], message: [{ type: i0.Input, args: [{ isSignal: true, alias: "message", required: false }] }], confirmLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "confirmLabel", required: false }] }], cancelLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "cancelLabel", required: false }] }], loadingText: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingText", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], showCancel: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCancel", required: false }] }], closed: [{ type: i0.Output, args: ["closed"] }] } });
1037
1038
 
1038
1039
  class ConfirmDialogService {
@@ -1303,11 +1304,11 @@ class ModalComponent {
1303
1304
  }
1304
1305
  }
1305
1306
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: ModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1306
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: ModalComponent, isStandalone: true, selector: "shk-modal", viewQueries: [{ propertyName: "container", first: true, predicate: ["dynamicContent"], descendants: true, read: ViewContainerRef, isSignal: true }], ngImport: i0, template: "@if (visible()) {\n <div\n class=\"fixed inset-0 bg-black/40 backdrop-blur-sm flex items-start justify-center z-40 p-4 pt-[5vh] sm:pt-[10vh] overflow-y-auto\"\n (click)=\"closeModal()\"\n >\n <div\n class=\"bg-white dark:[background-color:var(--shk-surface-800)] 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-100)]\">{{ 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-700)] _shk-text-surface-500 dark:[color:var(--shk-surface-400)] 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-700)] _shk-text-surface-500 dark:[color:var(--shk-surface-400)] 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]\">\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-700)] 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-300)] _shk-bg-surface-100 dark:[background-color:var(--shk-surface-700)] hover:[background-color:var(--shk-surface-200)] dark:hover:[background-color:var(--shk-surface-600)] 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-primary hover:[background-color:var(--shk-primary-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", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: LucideDynamicIcon, selector: "svg[lucideIcon]", inputs: ["lucideIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1307
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: ModalComponent, isStandalone: true, selector: "shk-modal", viewQueries: [{ propertyName: "container", first: true, predicate: ["dynamicContent"], descendants: true, read: ViewContainerRef, isSignal: true }], ngImport: i0, 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\"\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]\">\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", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: LucideDynamicIcon, selector: "svg[lucideIcon]", inputs: ["lucideIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1307
1308
  }
1308
1309
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: ModalComponent, decorators: [{
1309
1310
  type: Component,
1310
- 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-start justify-center z-40 p-4 pt-[5vh] sm:pt-[10vh] overflow-y-auto\"\n (click)=\"closeModal()\"\n >\n <div\n class=\"bg-white dark:[background-color:var(--shk-surface-800)] 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-100)]\">{{ 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-700)] _shk-text-surface-500 dark:[color:var(--shk-surface-400)] 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-700)] _shk-text-surface-500 dark:[color:var(--shk-surface-400)] 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]\">\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-700)] 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-300)] _shk-bg-surface-100 dark:[background-color:var(--shk-surface-700)] hover:[background-color:var(--shk-surface-200)] dark:hover:[background-color:var(--shk-surface-600)] 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-primary hover:[background-color:var(--shk-primary-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" }]
1311
+ 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\"\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]\">\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" }]
1311
1312
  }], ctorParameters: () => [], propDecorators: { container: [{ type: i0.ViewChild, args: ['dynamicContent', { ...{ read: ViewContainerRef }, isSignal: true }] }] } });
1312
1313
 
1313
1314
  const icons$2 = {
@@ -1918,13 +1919,13 @@ class SelectComponent {
1918
1919
  this.onTouched = fn;
1919
1920
  }
1920
1921
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: SelectComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
1921
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: SelectComponent, isStandalone: true, selector: "shk-select", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, validCombinations: { classPropertyName: "validCombinations", publicName: "validCombinations", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, isLoading: { classPropertyName: "isLoading", publicName: "isLoading", isSignal: true, isRequired: false, transformFunction: null }, isAllDataLoaded: { classPropertyName: "isAllDataLoaded", publicName: "isAllDataLoaded", isSignal: true, isRequired: false, transformFunction: null }, allowCustomEntries: { classPropertyName: "allowCustomEntries", publicName: "allowCustomEntries", isSignal: true, isRequired: false, transformFunction: null }, formGroup: { classPropertyName: "formGroup", publicName: "formGroup", isSignal: true, isRequired: false, transformFunction: null }, isSearchable: { classPropertyName: "isSearchable", publicName: "isSearchable", isSignal: true, isRequired: false, transformFunction: null }, itemsPerPage: { classPropertyName: "itemsPerPage", publicName: "itemsPerPage", isSignal: true, isRequired: false, transformFunction: null }, control: { classPropertyName: "control", publicName: "control", isSignal: true, isRequired: false, transformFunction: null }, usePagination: { classPropertyName: "usePagination", publicName: "usePagination", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, errorMessages: { classPropertyName: "errorMessages", publicName: "errorMessages", isSignal: true, isRequired: false, transformFunction: null }, preserveSearchOnLoad: { classPropertyName: "preserveSearchOnLoad", publicName: "preserveSearchOnLoad", isSignal: true, isRequired: false, transformFunction: null }, emptyMessageKey: { classPropertyName: "emptyMessageKey", publicName: "emptyMessageKey", isSignal: true, isRequired: false, transformFunction: null }, dropdownUpward: { classPropertyName: "dropdownUpward", publicName: "dropdownUpward", isSignal: true, isRequired: false, transformFunction: null }, showEmptyOption: { classPropertyName: "showEmptyOption", publicName: "showEmptyOption", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionChange: "selectionChange", search: "search" }, host: { listeners: { "document:click": "onClickOutside($event)" } }, providers: [
1922
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: SelectComponent, isStandalone: true, selector: "shk-select", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, validCombinations: { classPropertyName: "validCombinations", publicName: "validCombinations", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, isLoading: { classPropertyName: "isLoading", publicName: "isLoading", isSignal: true, isRequired: false, transformFunction: null }, isAllDataLoaded: { classPropertyName: "isAllDataLoaded", publicName: "isAllDataLoaded", isSignal: true, isRequired: false, transformFunction: null }, allowCustomEntries: { classPropertyName: "allowCustomEntries", publicName: "allowCustomEntries", isSignal: true, isRequired: false, transformFunction: null }, formGroup: { classPropertyName: "formGroup", publicName: "formGroup", isSignal: true, isRequired: false, transformFunction: null }, isSearchable: { classPropertyName: "isSearchable", publicName: "isSearchable", isSignal: true, isRequired: false, transformFunction: null }, itemsPerPage: { classPropertyName: "itemsPerPage", publicName: "itemsPerPage", isSignal: true, isRequired: false, transformFunction: null }, control: { classPropertyName: "control", publicName: "control", isSignal: true, isRequired: false, transformFunction: null }, usePagination: { classPropertyName: "usePagination", publicName: "usePagination", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, errorMessages: { classPropertyName: "errorMessages", publicName: "errorMessages", isSignal: true, isRequired: false, transformFunction: null }, preserveSearchOnLoad: { classPropertyName: "preserveSearchOnLoad", publicName: "preserveSearchOnLoad", isSignal: true, isRequired: false, transformFunction: null }, emptyMessageKey: { classPropertyName: "emptyMessageKey", publicName: "emptyMessageKey", isSignal: true, isRequired: false, transformFunction: null }, dropdownUpward: { classPropertyName: "dropdownUpward", publicName: "dropdownUpward", isSignal: true, isRequired: false, transformFunction: null }, showEmptyOption: { classPropertyName: "showEmptyOption", publicName: "showEmptyOption", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionChange: "selectionChange", search: "search" }, host: { listeners: { "document:mousedown": "onClickOutside($event)" } }, providers: [
1922
1923
  {
1923
1924
  provide: NG_VALUE_ACCESSOR,
1924
1925
  useExisting: forwardRef(() => SelectComponent),
1925
1926
  multi: true,
1926
1927
  },
1927
- ], viewQueries: [{ propertyName: "filterInput", first: true, predicate: ["filterInput"], descendants: true, isSignal: true }, { propertyName: "selectContainer", first: true, predicate: ["selectContainer"], descendants: true, isSignal: true }, { propertyName: "selectTrigger", first: true, predicate: ["selectTrigger"], descendants: true, isSignal: true }, { propertyName: "dropdownContainer", first: true, predicate: ["dropdownContainer"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n #selectContainer\n class=\"relative w-full font-sans outline-none\"\n>\n @if (label()) {\n <div class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-300)] mb-1\">\n {{ label() }}\n </div>\n }\n\n <div\n #selectTrigger\n class=\"flex justify-between items-center w-full px-3 py-2 border _shk-border dark:[border-color:var(--shk-surface-700)] rounded-lg _shk-bg-surface-50 dark:[background-color:var(--shk-surface-800)] transition-colors duration-150 cursor-pointer min-h-[2.5rem] _shk-text-surface-700 dark:[color:var(--shk-surface-200)] focus-within:outline-none focus-within:[background-color:var(--shk-surface-50)] dark:focus-within:[background-color:var(--shk-surface-800)] focus-within:ring-1 focus-within:[--tw-ring-color:var(--shk-primary-500)] focus-within:[border-color:var(--shk-primary-500)] focus:outline-none focus:ring-1 focus:[--tw-ring-color:var(--shk-primary-500)] focus:[border-color:var(--shk-primary-500)] sm:text-sm\"\n [attr.tabindex]=\"isDisabled() ? -1 : 0\"\n (keydown)=\"onKeydown($event)\"\n (click)=\"toggleDropdown()\"\n [class.open]=\"isOpen()\"\n [class.disabled-select]=\"isDisabled()\"\n [class._shk-border-red]=\"shouldShowError()\"\n >\n <div class=\"selected-value truncate\">\n @if (isSearchable() && isOpen()) {\n <input\n #filterInput\n type=\"text\"\n class=\"w-full bg-transparent border-0 outline-none p-0 _shk-text-surface-700 dark:[color:var(--shk-surface-200)]\"\n placeholder=\"Buscar...\"\n [value]=\"searchTerm()\"\n (input)=\"onInputChange($event)\"\n (keydown)=\"handleKeyDown($event)\"\n (click)=\"$event.stopPropagation()\"\n />\n } @else {\n <span\n [class._shk-text-surface-400]=\"!hasSelectedValues()\"\n [class._shk-text-surface-700]=\"hasSelectedValues()\"\n >\n {{ displayValue() }}\n </span>\n }\n </div>\n <div\n class=\"text-xs transition-transform duration-200 shrink-0 ml-2\"\n [class.rotate-180]=\"isOpen()\"\n >\n <svg\n [lucideIcon]=\"getIcon('chevron-down')\"\n class=\"w-4 h-4 _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\"\n ></svg>\n </div>\n </div>\n\n @if (isOpen()) {\n <div\n #dropdownContainer\n (keydown)=\"onKeydown($event)\"\n class=\"absolute left-0 right-0 _shk-bg-surface-50 dark:[background-color:var(--shk-surface-800)] border _shk-border dark:[border-color:var(--shk-surface-700)] rounded-lg max-h-[240px] overflow-y-auto z-50 shadow-lg\"\n [class.top-full]=\"!dropdownUpward()\"\n [class.bottom-full]=\"dropdownUpward()\"\n [class.mt-1]=\"!dropdownUpward()\"\n [class.mb-1]=\"dropdownUpward()\"\n >\n @if (showCustomOption()) {\n <div\n class=\"flex items-center gap-2 px-3 py-2 cursor-pointer hover:[background-color:var(--shk-surface-50)] dark:hover:[background-color:var(--shk-surface-700)] text-sm\"\n (click)=\"onCustomOptionClick()\"\n >\n <span class=\"font-semibold _shk-text-primary\">Crear nuevo:</span>\n <span class=\"_shk-text-surface-700 dark:[color:var(--shk-surface-200)] ml-1\">{{ searchTerm() }}</span>\n </div>\n }\n\n @for (option of regularOptions(); track trackByFn($index, option); let i = $index) {\n <div\n class=\"flex items-center gap-2 px-3 py-2 cursor-pointer hover:[background-color:var(--shk-surface-50)] dark:hover:[background-color:var(--shk-surface-700)] text-sm _shk-text-surface-700 dark:[color:var(--shk-surface-200)]\"\n [class.opacity-50]=\"isOptionDisabled(option)\"\n [class.select-option-active]=\"focusedIndex() === i\"\n [class._shk-text-surface-400]=\"option.value === null\"\n (click)=\"!isOptionDisabled(option) && onOptionClick(option)\"\n >\n @if (multiple()) {\n <input\n type=\"checkbox\"\n [checked]=\"isSelected(option)\"\n [disabled]=\"isOptionDisabled(option)\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"!isOptionDisabled(option) && toggleOption(option)\"\n class=\"flex-shrink-0 [accent-color:var(--shk-primary-600)]\"\n />\n {{ option.label }}\n } @else {\n {{ option.label }}\n }\n </div>\n }\n\n <div class=\"px-3 py-2 text-center\">\n @if (isLoading() && regularOptions().length === 0) {\n <div class=\"flex items-center justify-center gap-2 text-sm _shk-text-surface-500 dark:[color:var(--shk-surface-400)]\">\n <svg class=\"spinner\" viewBox=\"0 0 50 50\">\n <circle\n class=\"path\"\n cx=\"25\"\n cy=\"25\"\n r=\"20\"\n fill=\"none\"\n stroke-width=\"5\"\n ></circle>\n </svg>\n Cargando m\u00E1s resultados...\n </div>\n }\n\n @if (!isLoading() && isAllDataLoaded() && regularOptions().length === 0) {\n <div class=\"text-sm _shk-text-surface-400 dark:[color:var(--shk-surface-500)] italic\">\n No se encontraron coincidencias\n </div>\n }\n\n @if (options().length === 0) {\n <div class=\"text-sm _shk-text-surface-400 dark:[color:var(--shk-surface-500)] italic\">\n {{ emptyMessageKey() | transloco }}\n </div>\n }\n </div>\n\n @if (usePagination() && totalPages() > 1) {\n <div class=\"flex justify-between items-center px-3 py-2 border-t _shk-border dark:[border-color:var(--shk-surface-700)]\">\n <button\n class=\"bg-transparent border-0 cursor-pointer px-2 py-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-700)] disabled:opacity-50 disabled:cursor-not-allowed _shk-text-surface-600 dark:[color:var(--shk-surface-300)]\"\n [disabled]=\"currentPage() === 1\"\n (click)=\"$event.stopPropagation(); previousPage()\"\n >\n <svg [lucideIcon]=\"getIcon('chevron-left')\" class=\"w-4 h-4\"></svg>\n </button>\n <span class=\"text-sm _shk-text-surface-600 dark:[color:var(--shk-surface-300)]\">\n {{ currentPage() }} de {{ totalPages() }}\n </span>\n <button\n class=\"bg-transparent border-0 cursor-pointer px-2 py-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-700)] disabled:opacity-50 disabled:cursor-not-allowed _shk-text-surface-600 dark:[color:var(--shk-surface-300)]\"\n [disabled]=\"currentPage() === totalPages()\"\n (click)=\"$event.stopPropagation(); nextPage()\"\n >\n <svg [lucideIcon]=\"getIcon('chevron-right')\" class=\"w-4 h-4\"></svg>\n </button>\n </div>\n }\n </div>\n }\n\n @if (shouldShowError()) {\n <div class=\"mt-1 text-xs text-red-500 max-h-20 overflow-y-auto\" tabindex=\"-1\">\n <ul class=\"list-disc pl-4 space-y-1\">\n @for (error of getErrorMessages(); track error) {\n <li>{{ error }}</li>\n }\n </ul>\n </div>\n }\n</div>", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: FormsModule }, { 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 });
1928
+ ], viewQueries: [{ propertyName: "filterInput", first: true, predicate: ["filterInput"], descendants: true, isSignal: true }, { propertyName: "selectContainer", first: true, predicate: ["selectContainer"], descendants: true, isSignal: true }, { propertyName: "selectTrigger", first: true, predicate: ["selectTrigger"], descendants: true, isSignal: true }, { propertyName: "dropdownContainer", first: true, predicate: ["dropdownContainer"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n #selectContainer\n class=\"relative w-full font-sans outline-none\"\n>\n @if (label()) {\n <div class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-600)] mb-1\">\n {{ label() }}\n </div>\n }\n\n <div\n #selectTrigger\n class=\"flex justify-between items-center w-full px-3 py-2 border _shk-border rounded-lg _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] transition-colors duration-150 cursor-pointer min-h-[2.5rem] _shk-text-surface-700 dark:[color:var(--shk-surface-700)] focus-within:outline-none focus-within:[background-color:var(--shk-surface-50)] dark:focus-within:[background-color:var(--shk-surface-100)] focus-within:ring-1 focus-within:[--tw-ring-color:var(--shk-primary-500)] focus-within:[border-color:var(--shk-primary-500)] focus:outline-none focus:ring-1 focus:[--tw-ring-color:var(--shk-primary-500)] focus:[border-color:var(--shk-primary-500)] sm:text-sm\"\n [attr.tabindex]=\"isDisabled() ? -1 : 0\"\n (keydown)=\"onKeydown($event)\"\n (click)=\"toggleDropdown()\"\n [class.open]=\"isOpen()\"\n [class.disabled-select]=\"isDisabled()\"\n [class._shk-border-red]=\"shouldShowError()\"\n >\n <div class=\"selected-value truncate\">\n @if (isSearchable() && isOpen()) {\n <input\n #filterInput\n type=\"text\"\n class=\"w-full bg-transparent border-0 outline-none p-0 _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\"\n placeholder=\"Buscar...\"\n [value]=\"searchTerm()\"\n (input)=\"onInputChange($event)\"\n (keydown)=\"handleKeyDown($event)\"\n (click)=\"$event.stopPropagation()\"\n />\n } @else {\n <span\n [class._shk-text-surface-400]=\"!hasSelectedValues()\"\n [class._shk-text-surface-800]=\"hasSelectedValues()\"\n >\n {{ displayValue() }}\n </span>\n }\n </div>\n <div\n class=\"text-xs transition-transform duration-200 shrink-0 ml-2\"\n [class.rotate-180]=\"isOpen()\"\n >\n <svg\n [lucideIcon]=\"getIcon('chevron-down')\"\n class=\"w-4 h-4 _shk-text-surface-400 dark:[color:var(--shk-surface-400)]\"\n ></svg>\n </div>\n </div>\n\n @if (isOpen()) {\n <div\n #dropdownContainer\n (keydown)=\"onKeydown($event)\"\n class=\"absolute left-0 right-0 _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] border _shk-border rounded-lg max-h-[240px] overflow-y-auto z-50 shadow-lg\"\n [class.top-full]=\"!dropdownUpward()\"\n [class.bottom-full]=\"dropdownUpward()\"\n [class.mt-1]=\"!dropdownUpward()\"\n [class.mb-1]=\"dropdownUpward()\"\n >\n @if (showCustomOption()) {\n <div\n class=\"flex items-center gap-2 px-3 py-2 cursor-pointer hover:[background-color:var(--shk-surface-50)] dark:hover:[background-color:var(--shk-surface-200)] text-sm\"\n (click)=\"onCustomOptionClick()\"\n >\n <span class=\"font-semibold _shk-text-primary\">Crear nuevo:</span>\n <span class=\"_shk-text-surface-700 dark:[color:var(--shk-surface-700)] ml-1\">{{ searchTerm() }}</span>\n </div>\n }\n\n @for (option of regularOptions(); track trackByFn($index, option); let i = $index) {\n <div\n class=\"flex items-center gap-2 px-3 py-2 cursor-pointer hover:[background-color:var(--shk-surface-50)] dark:hover:[background-color:var(--shk-surface-200)] text-sm _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\"\n [class.opacity-50]=\"isOptionDisabled(option)\"\n [class.select-option-active]=\"focusedIndex() === i\"\n [class._shk-text-surface-400]=\"option.value === null\"\n (click)=\"!isOptionDisabled(option) && onOptionClick(option)\"\n >\n @if (multiple()) {\n <input\n type=\"checkbox\"\n [checked]=\"isSelected(option)\"\n [disabled]=\"isOptionDisabled(option)\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"!isOptionDisabled(option) && toggleOption(option)\"\n class=\"flex-shrink-0 [accent-color:var(--shk-primary-600)]\"\n />\n {{ option.label }}\n } @else {\n {{ option.label }}\n }\n </div>\n }\n\n <div class=\"px-3 py-2 text-center\">\n @if (isLoading() && regularOptions().length === 0) {\n <div class=\"flex items-center justify-center gap-2 text-sm _shk-text-surface-500\">\n <svg class=\"spinner\" viewBox=\"0 0 50 50\">\n <circle\n class=\"path\"\n cx=\"25\"\n cy=\"25\"\n r=\"20\"\n fill=\"none\"\n stroke-width=\"5\"\n ></circle>\n </svg>\n Cargando m\u00E1s resultados...\n </div>\n }\n\n @if (!isLoading() && isAllDataLoaded() && regularOptions().length === 0) {\n <div class=\"text-sm _shk-text-surface-400 italic\">\n No se encontraron coincidencias\n </div>\n }\n\n @if (options().length === 0) {\n <div class=\"text-sm _shk-text-surface-400 italic\">\n {{ emptyMessageKey() | transloco }}\n </div>\n }\n </div>\n\n @if (usePagination() && totalPages() > 1) {\n <div class=\"flex justify-between items-center px-3 py-2 border-t _shk-border\">\n <button\n class=\"bg-transparent border-0 cursor-pointer px-2 py-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-50 disabled:cursor-not-allowed _shk-text-surface-600 dark:[color:var(--shk-surface-600)]\"\n [disabled]=\"currentPage() === 1\"\n (click)=\"$event.stopPropagation(); previousPage()\"\n >\n <svg [lucideIcon]=\"getIcon('chevron-left')\" class=\"w-4 h-4\"></svg>\n </button>\n <span class=\"text-sm _shk-text-surface-600 dark:[color:var(--shk-surface-600)]\">\n {{ currentPage() }} de {{ totalPages() }}\n </span>\n <button\n class=\"bg-transparent border-0 cursor-pointer px-2 py-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-50 disabled:cursor-not-allowed _shk-text-surface-600 dark:[color:var(--shk-surface-600)]\"\n [disabled]=\"currentPage() === totalPages()\"\n (click)=\"$event.stopPropagation(); nextPage()\"\n >\n <svg [lucideIcon]=\"getIcon('chevron-right')\" class=\"w-4 h-4\"></svg>\n </button>\n </div>\n }\n </div>\n }\n\n @if (shouldShowError()) {\n <div class=\"mt-1 text-xs text-red-500 max-h-20 overflow-y-auto\" tabindex=\"-1\">\n <ul class=\"list-disc pl-4 space-y-1\">\n @for (error of getErrorMessages(); track error) {\n <li>{{ error }}</li>\n }\n </ul>\n </div>\n }\n</div>", styles: [".select-option-active{background-color:var(--shk-primary-50);outline:2px solid var(--shk-primary-500);outline-offset:-2px;color:var(--shk-primary-700)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: FormsModule }, { 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 });
1928
1929
  }
1929
1930
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: SelectComponent, decorators: [{
1930
1931
  type: Component,
@@ -1940,10 +1941,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImpo
1940
1941
  useExisting: forwardRef(() => SelectComponent),
1941
1942
  multi: true,
1942
1943
  },
1943
- ], template: "<div\n #selectContainer\n class=\"relative w-full font-sans outline-none\"\n>\n @if (label()) {\n <div class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-300)] mb-1\">\n {{ label() }}\n </div>\n }\n\n <div\n #selectTrigger\n class=\"flex justify-between items-center w-full px-3 py-2 border _shk-border dark:[border-color:var(--shk-surface-700)] rounded-lg _shk-bg-surface-50 dark:[background-color:var(--shk-surface-800)] transition-colors duration-150 cursor-pointer min-h-[2.5rem] _shk-text-surface-700 dark:[color:var(--shk-surface-200)] focus-within:outline-none focus-within:[background-color:var(--shk-surface-50)] dark:focus-within:[background-color:var(--shk-surface-800)] focus-within:ring-1 focus-within:[--tw-ring-color:var(--shk-primary-500)] focus-within:[border-color:var(--shk-primary-500)] focus:outline-none focus:ring-1 focus:[--tw-ring-color:var(--shk-primary-500)] focus:[border-color:var(--shk-primary-500)] sm:text-sm\"\n [attr.tabindex]=\"isDisabled() ? -1 : 0\"\n (keydown)=\"onKeydown($event)\"\n (click)=\"toggleDropdown()\"\n [class.open]=\"isOpen()\"\n [class.disabled-select]=\"isDisabled()\"\n [class._shk-border-red]=\"shouldShowError()\"\n >\n <div class=\"selected-value truncate\">\n @if (isSearchable() && isOpen()) {\n <input\n #filterInput\n type=\"text\"\n class=\"w-full bg-transparent border-0 outline-none p-0 _shk-text-surface-700 dark:[color:var(--shk-surface-200)]\"\n placeholder=\"Buscar...\"\n [value]=\"searchTerm()\"\n (input)=\"onInputChange($event)\"\n (keydown)=\"handleKeyDown($event)\"\n (click)=\"$event.stopPropagation()\"\n />\n } @else {\n <span\n [class._shk-text-surface-400]=\"!hasSelectedValues()\"\n [class._shk-text-surface-700]=\"hasSelectedValues()\"\n >\n {{ displayValue() }}\n </span>\n }\n </div>\n <div\n class=\"text-xs transition-transform duration-200 shrink-0 ml-2\"\n [class.rotate-180]=\"isOpen()\"\n >\n <svg\n [lucideIcon]=\"getIcon('chevron-down')\"\n class=\"w-4 h-4 _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\"\n ></svg>\n </div>\n </div>\n\n @if (isOpen()) {\n <div\n #dropdownContainer\n (keydown)=\"onKeydown($event)\"\n class=\"absolute left-0 right-0 _shk-bg-surface-50 dark:[background-color:var(--shk-surface-800)] border _shk-border dark:[border-color:var(--shk-surface-700)] rounded-lg max-h-[240px] overflow-y-auto z-50 shadow-lg\"\n [class.top-full]=\"!dropdownUpward()\"\n [class.bottom-full]=\"dropdownUpward()\"\n [class.mt-1]=\"!dropdownUpward()\"\n [class.mb-1]=\"dropdownUpward()\"\n >\n @if (showCustomOption()) {\n <div\n class=\"flex items-center gap-2 px-3 py-2 cursor-pointer hover:[background-color:var(--shk-surface-50)] dark:hover:[background-color:var(--shk-surface-700)] text-sm\"\n (click)=\"onCustomOptionClick()\"\n >\n <span class=\"font-semibold _shk-text-primary\">Crear nuevo:</span>\n <span class=\"_shk-text-surface-700 dark:[color:var(--shk-surface-200)] ml-1\">{{ searchTerm() }}</span>\n </div>\n }\n\n @for (option of regularOptions(); track trackByFn($index, option); let i = $index) {\n <div\n class=\"flex items-center gap-2 px-3 py-2 cursor-pointer hover:[background-color:var(--shk-surface-50)] dark:hover:[background-color:var(--shk-surface-700)] text-sm _shk-text-surface-700 dark:[color:var(--shk-surface-200)]\"\n [class.opacity-50]=\"isOptionDisabled(option)\"\n [class.select-option-active]=\"focusedIndex() === i\"\n [class._shk-text-surface-400]=\"option.value === null\"\n (click)=\"!isOptionDisabled(option) && onOptionClick(option)\"\n >\n @if (multiple()) {\n <input\n type=\"checkbox\"\n [checked]=\"isSelected(option)\"\n [disabled]=\"isOptionDisabled(option)\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"!isOptionDisabled(option) && toggleOption(option)\"\n class=\"flex-shrink-0 [accent-color:var(--shk-primary-600)]\"\n />\n {{ option.label }}\n } @else {\n {{ option.label }}\n }\n </div>\n }\n\n <div class=\"px-3 py-2 text-center\">\n @if (isLoading() && regularOptions().length === 0) {\n <div class=\"flex items-center justify-center gap-2 text-sm _shk-text-surface-500 dark:[color:var(--shk-surface-400)]\">\n <svg class=\"spinner\" viewBox=\"0 0 50 50\">\n <circle\n class=\"path\"\n cx=\"25\"\n cy=\"25\"\n r=\"20\"\n fill=\"none\"\n stroke-width=\"5\"\n ></circle>\n </svg>\n Cargando m\u00E1s resultados...\n </div>\n }\n\n @if (!isLoading() && isAllDataLoaded() && regularOptions().length === 0) {\n <div class=\"text-sm _shk-text-surface-400 dark:[color:var(--shk-surface-500)] italic\">\n No se encontraron coincidencias\n </div>\n }\n\n @if (options().length === 0) {\n <div class=\"text-sm _shk-text-surface-400 dark:[color:var(--shk-surface-500)] italic\">\n {{ emptyMessageKey() | transloco }}\n </div>\n }\n </div>\n\n @if (usePagination() && totalPages() > 1) {\n <div class=\"flex justify-between items-center px-3 py-2 border-t _shk-border dark:[border-color:var(--shk-surface-700)]\">\n <button\n class=\"bg-transparent border-0 cursor-pointer px-2 py-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-700)] disabled:opacity-50 disabled:cursor-not-allowed _shk-text-surface-600 dark:[color:var(--shk-surface-300)]\"\n [disabled]=\"currentPage() === 1\"\n (click)=\"$event.stopPropagation(); previousPage()\"\n >\n <svg [lucideIcon]=\"getIcon('chevron-left')\" class=\"w-4 h-4\"></svg>\n </button>\n <span class=\"text-sm _shk-text-surface-600 dark:[color:var(--shk-surface-300)]\">\n {{ currentPage() }} de {{ totalPages() }}\n </span>\n <button\n class=\"bg-transparent border-0 cursor-pointer px-2 py-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-700)] disabled:opacity-50 disabled:cursor-not-allowed _shk-text-surface-600 dark:[color:var(--shk-surface-300)]\"\n [disabled]=\"currentPage() === totalPages()\"\n (click)=\"$event.stopPropagation(); nextPage()\"\n >\n <svg [lucideIcon]=\"getIcon('chevron-right')\" class=\"w-4 h-4\"></svg>\n </button>\n </div>\n }\n </div>\n }\n\n @if (shouldShowError()) {\n <div class=\"mt-1 text-xs text-red-500 max-h-20 overflow-y-auto\" tabindex=\"-1\">\n <ul class=\"list-disc pl-4 space-y-1\">\n @for (error of getErrorMessages(); track error) {\n <li>{{ error }}</li>\n }\n </ul>\n </div>\n }\n</div>" }]
1944
+ ], template: "<div\n #selectContainer\n class=\"relative w-full font-sans outline-none\"\n>\n @if (label()) {\n <div class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-600)] mb-1\">\n {{ label() }}\n </div>\n }\n\n <div\n #selectTrigger\n class=\"flex justify-between items-center w-full px-3 py-2 border _shk-border rounded-lg _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] transition-colors duration-150 cursor-pointer min-h-[2.5rem] _shk-text-surface-700 dark:[color:var(--shk-surface-700)] focus-within:outline-none focus-within:[background-color:var(--shk-surface-50)] dark:focus-within:[background-color:var(--shk-surface-100)] focus-within:ring-1 focus-within:[--tw-ring-color:var(--shk-primary-500)] focus-within:[border-color:var(--shk-primary-500)] focus:outline-none focus:ring-1 focus:[--tw-ring-color:var(--shk-primary-500)] focus:[border-color:var(--shk-primary-500)] sm:text-sm\"\n [attr.tabindex]=\"isDisabled() ? -1 : 0\"\n (keydown)=\"onKeydown($event)\"\n (click)=\"toggleDropdown()\"\n [class.open]=\"isOpen()\"\n [class.disabled-select]=\"isDisabled()\"\n [class._shk-border-red]=\"shouldShowError()\"\n >\n <div class=\"selected-value truncate\">\n @if (isSearchable() && isOpen()) {\n <input\n #filterInput\n type=\"text\"\n class=\"w-full bg-transparent border-0 outline-none p-0 _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\"\n placeholder=\"Buscar...\"\n [value]=\"searchTerm()\"\n (input)=\"onInputChange($event)\"\n (keydown)=\"handleKeyDown($event)\"\n (click)=\"$event.stopPropagation()\"\n />\n } @else {\n <span\n [class._shk-text-surface-400]=\"!hasSelectedValues()\"\n [class._shk-text-surface-800]=\"hasSelectedValues()\"\n >\n {{ displayValue() }}\n </span>\n }\n </div>\n <div\n class=\"text-xs transition-transform duration-200 shrink-0 ml-2\"\n [class.rotate-180]=\"isOpen()\"\n >\n <svg\n [lucideIcon]=\"getIcon('chevron-down')\"\n class=\"w-4 h-4 _shk-text-surface-400 dark:[color:var(--shk-surface-400)]\"\n ></svg>\n </div>\n </div>\n\n @if (isOpen()) {\n <div\n #dropdownContainer\n (keydown)=\"onKeydown($event)\"\n class=\"absolute left-0 right-0 _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] border _shk-border rounded-lg max-h-[240px] overflow-y-auto z-50 shadow-lg\"\n [class.top-full]=\"!dropdownUpward()\"\n [class.bottom-full]=\"dropdownUpward()\"\n [class.mt-1]=\"!dropdownUpward()\"\n [class.mb-1]=\"dropdownUpward()\"\n >\n @if (showCustomOption()) {\n <div\n class=\"flex items-center gap-2 px-3 py-2 cursor-pointer hover:[background-color:var(--shk-surface-50)] dark:hover:[background-color:var(--shk-surface-200)] text-sm\"\n (click)=\"onCustomOptionClick()\"\n >\n <span class=\"font-semibold _shk-text-primary\">Crear nuevo:</span>\n <span class=\"_shk-text-surface-700 dark:[color:var(--shk-surface-700)] ml-1\">{{ searchTerm() }}</span>\n </div>\n }\n\n @for (option of regularOptions(); track trackByFn($index, option); let i = $index) {\n <div\n class=\"flex items-center gap-2 px-3 py-2 cursor-pointer hover:[background-color:var(--shk-surface-50)] dark:hover:[background-color:var(--shk-surface-200)] text-sm _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\"\n [class.opacity-50]=\"isOptionDisabled(option)\"\n [class.select-option-active]=\"focusedIndex() === i\"\n [class._shk-text-surface-400]=\"option.value === null\"\n (click)=\"!isOptionDisabled(option) && onOptionClick(option)\"\n >\n @if (multiple()) {\n <input\n type=\"checkbox\"\n [checked]=\"isSelected(option)\"\n [disabled]=\"isOptionDisabled(option)\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"!isOptionDisabled(option) && toggleOption(option)\"\n class=\"flex-shrink-0 [accent-color:var(--shk-primary-600)]\"\n />\n {{ option.label }}\n } @else {\n {{ option.label }}\n }\n </div>\n }\n\n <div class=\"px-3 py-2 text-center\">\n @if (isLoading() && regularOptions().length === 0) {\n <div class=\"flex items-center justify-center gap-2 text-sm _shk-text-surface-500\">\n <svg class=\"spinner\" viewBox=\"0 0 50 50\">\n <circle\n class=\"path\"\n cx=\"25\"\n cy=\"25\"\n r=\"20\"\n fill=\"none\"\n stroke-width=\"5\"\n ></circle>\n </svg>\n Cargando m\u00E1s resultados...\n </div>\n }\n\n @if (!isLoading() && isAllDataLoaded() && regularOptions().length === 0) {\n <div class=\"text-sm _shk-text-surface-400 italic\">\n No se encontraron coincidencias\n </div>\n }\n\n @if (options().length === 0) {\n <div class=\"text-sm _shk-text-surface-400 italic\">\n {{ emptyMessageKey() | transloco }}\n </div>\n }\n </div>\n\n @if (usePagination() && totalPages() > 1) {\n <div class=\"flex justify-between items-center px-3 py-2 border-t _shk-border\">\n <button\n class=\"bg-transparent border-0 cursor-pointer px-2 py-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-50 disabled:cursor-not-allowed _shk-text-surface-600 dark:[color:var(--shk-surface-600)]\"\n [disabled]=\"currentPage() === 1\"\n (click)=\"$event.stopPropagation(); previousPage()\"\n >\n <svg [lucideIcon]=\"getIcon('chevron-left')\" class=\"w-4 h-4\"></svg>\n </button>\n <span class=\"text-sm _shk-text-surface-600 dark:[color:var(--shk-surface-600)]\">\n {{ currentPage() }} de {{ totalPages() }}\n </span>\n <button\n class=\"bg-transparent border-0 cursor-pointer px-2 py-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-50 disabled:cursor-not-allowed _shk-text-surface-600 dark:[color:var(--shk-surface-600)]\"\n [disabled]=\"currentPage() === totalPages()\"\n (click)=\"$event.stopPropagation(); nextPage()\"\n >\n <svg [lucideIcon]=\"getIcon('chevron-right')\" class=\"w-4 h-4\"></svg>\n </button>\n </div>\n }\n </div>\n }\n\n @if (shouldShowError()) {\n <div class=\"mt-1 text-xs text-red-500 max-h-20 overflow-y-auto\" tabindex=\"-1\">\n <ul class=\"list-disc pl-4 space-y-1\">\n @for (error of getErrorMessages(); track error) {\n <li>{{ error }}</li>\n }\n </ul>\n </div>\n }\n</div>", styles: [".select-option-active{background-color:var(--shk-primary-50);outline:2px solid var(--shk-primary-500);outline-offset:-2px;color:var(--shk-primary-700)}\n"] }]
1944
1945
  }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], validCombinations: [{ type: i0.Input, args: [{ isSignal: true, alias: "validCombinations", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], isLoading: [{ type: i0.Input, args: [{ isSignal: true, alias: "isLoading", required: false }] }], isAllDataLoaded: [{ type: i0.Input, args: [{ isSignal: true, alias: "isAllDataLoaded", required: false }] }], allowCustomEntries: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowCustomEntries", required: false }] }], formGroup: [{ type: i0.Input, args: [{ isSignal: true, alias: "formGroup", required: false }] }], isSearchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "isSearchable", required: false }] }], itemsPerPage: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemsPerPage", required: false }] }], control: [{ type: i0.Input, args: [{ isSignal: true, alias: "control", required: false }] }], usePagination: [{ type: i0.Input, args: [{ isSignal: true, alias: "usePagination", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], errorMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessages", required: false }] }], preserveSearchOnLoad: [{ type: i0.Input, args: [{ isSignal: true, alias: "preserveSearchOnLoad", required: false }] }], emptyMessageKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessageKey", required: false }] }], dropdownUpward: [{ type: i0.Input, args: [{ isSignal: true, alias: "dropdownUpward", required: false }] }], showEmptyOption: [{ type: i0.Input, args: [{ isSignal: true, alias: "showEmptyOption", required: false }] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], search: [{ type: i0.Output, args: ["search"] }], filterInput: [{ type: i0.ViewChild, args: ['filterInput', { isSignal: true }] }], selectContainer: [{ type: i0.ViewChild, args: ['selectContainer', { isSignal: true }] }], selectTrigger: [{ type: i0.ViewChild, args: ['selectTrigger', { isSignal: true }] }], dropdownContainer: [{ type: i0.ViewChild, args: ['dropdownContainer', { isSignal: true }] }], onClickOutside: [{
1945
1946
  type: HostListener,
1946
- args: ['document:click', ['$event']]
1947
+ args: ['document:mousedown', ['$event']]
1947
1948
  }] } });
1948
1949
 
1949
1950
  const icons$1 = {
@@ -2679,7 +2680,7 @@ class TableComponent {
2679
2680
  }
2680
2681
  }
2681
2682
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: TableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2682
- static ɵ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-700)] rounded-md leading-5\n _shk-bg-surface-50 dark:[background-color:var(--shk-surface-800)] placeholder:[color:var(--shk-surface-400)] dark:placeholder:[color:var(--shk-surface-500)]\n _shk-text-surface-700 dark:[color:var(--shk-surface-200)]\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-800)] 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-200)] 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 [style.max-width]=\"col.field === 'actions' ? 'none' : (col.width || '300px')\"\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-800)] border-b _shk-border dark:[border-color:var(--shk-surface-700)]\"\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-700)] bg-white dark:[background-color:var(--shk-surface-800)] _shk-text-surface-700 dark:[color:var(--shk-surface-200)]\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-700)] bg-white dark:[background-color:var(--shk-surface-800)] _shk-text-surface-700 dark:[color:var(--shk-surface-200)] 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-800)]\">\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-800)]\">\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-800)] 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-800)]\">\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-200)] whitespace-nowrap\"\n [style.max-width]=\"col.width || '300px'\"\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-700)] 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-800)]\">\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-200)]\">{{ 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-700)] rounded px-2 py-1 text-xs bg-white dark:[background-color:var(--shk-surface-800)] _shk-text-surface-700 dark:[color:var(--shk-surface-200)] 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:auto}.table-scroll-wrapper table{table-layout:fixed}\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 });
2683
+ static ɵ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%}.table-scroll-wrapper table{table-layout:fixed}\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 });
2683
2684
  }
2684
2685
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: TableComponent, decorators: [{
2685
2686
  type: Component,
@@ -2688,7 +2689,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImpo
2688
2689
  ReactiveFormsModule,
2689
2690
  TranslocoModule,
2690
2691
  LucideDynamicIcon,
2691
- ], 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-700)] rounded-md leading-5\n _shk-bg-surface-50 dark:[background-color:var(--shk-surface-800)] placeholder:[color:var(--shk-surface-400)] dark:placeholder:[color:var(--shk-surface-500)]\n _shk-text-surface-700 dark:[color:var(--shk-surface-200)]\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-800)] 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-200)] 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 [style.max-width]=\"col.field === 'actions' ? 'none' : (col.width || '300px')\"\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-800)] border-b _shk-border dark:[border-color:var(--shk-surface-700)]\"\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-700)] bg-white dark:[background-color:var(--shk-surface-800)] _shk-text-surface-700 dark:[color:var(--shk-surface-200)]\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-700)] bg-white dark:[background-color:var(--shk-surface-800)] _shk-text-surface-700 dark:[color:var(--shk-surface-200)] 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-800)]\">\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-800)]\">\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-800)] 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-800)]\">\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-200)] whitespace-nowrap\"\n [style.max-width]=\"col.width || '300px'\"\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-700)] 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-800)]\">\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-200)]\">{{ 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-700)] rounded px-2 py-1 text-xs bg-white dark:[background-color:var(--shk-surface-800)] _shk-text-surface-700 dark:[color:var(--shk-surface-200)] 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:auto}.table-scroll-wrapper table{table-layout:fixed}\n"] }]
2692
+ ], 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%}.table-scroll-wrapper table{table-layout:fixed}\n"] }]
2692
2693
  }], 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"] }] } });
2693
2694
 
2694
2695
  class TooltipComponent {
@@ -2798,6 +2799,96 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImpo
2798
2799
  args: ['mouseenter']
2799
2800
  }] } });
2800
2801
 
2802
+ Chart.register(...registerables);
2803
+ class ChartComponent {
2804
+ type = input('bar', ...(ngDevMode ? [{ debugName: "type" }] : /* istanbul ignore next */ []));
2805
+ data = input({ datasets: [] }, ...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
2806
+ options = input({}, ...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
2807
+ canvasRef = viewChild.required('canvas');
2808
+ chartInstance = null;
2809
+ initialized = false;
2810
+ ngAfterViewInit() {
2811
+ this.initialized = true;
2812
+ this.initChart();
2813
+ }
2814
+ ngOnDestroy() {
2815
+ this.chartInstance?.destroy();
2816
+ }
2817
+ initChart() {
2818
+ const ctx = this.canvasRef().nativeElement.getContext('2d');
2819
+ if (!ctx)
2820
+ return;
2821
+ this.chartInstance = new Chart(ctx, {
2822
+ type: this.type(),
2823
+ data: this.data(),
2824
+ options: this.options(),
2825
+ });
2826
+ }
2827
+ constructor() {
2828
+ effect(() => {
2829
+ const t = this.type();
2830
+ const d = this.data();
2831
+ const o = this.options();
2832
+ untracked(() => {
2833
+ if (!this.initialized)
2834
+ return;
2835
+ this.updateChart(t, d, o);
2836
+ });
2837
+ });
2838
+ }
2839
+ updateChart(type, data, options) {
2840
+ if (!this.chartInstance) {
2841
+ this.initChart();
2842
+ return;
2843
+ }
2844
+ const config = this.chartInstance.config;
2845
+ if (type !== config.type) {
2846
+ this.chartInstance.destroy();
2847
+ this.chartInstance = null;
2848
+ this.initChart();
2849
+ return;
2850
+ }
2851
+ this.chartInstance.data = data;
2852
+ this.chartInstance.options = options;
2853
+ this.chartInstance.update();
2854
+ }
2855
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: ChartComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2856
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.18", type: ChartComponent, isStandalone: true, selector: "shk-chart", inputs: { type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "canvasRef", first: true, predicate: ["canvas"], descendants: true, isSignal: true }], ngImport: i0, template: `
2857
+ <div class="relative h-full w-full">
2858
+ <canvas #canvas></canvas>
2859
+ </div>
2860
+ `, isInline: true });
2861
+ }
2862
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: ChartComponent, decorators: [{
2863
+ type: Component,
2864
+ args: [{
2865
+ selector: 'shk-chart',
2866
+ standalone: true,
2867
+ template: `
2868
+ <div class="relative h-full w-full">
2869
+ <canvas #canvas></canvas>
2870
+ </div>
2871
+ `,
2872
+ }]
2873
+ }], ctorParameters: () => [], propDecorators: { type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], canvasRef: [{ type: i0.ViewChild, args: ['canvas', { isSignal: true }] }] } });
2874
+
2875
+ const COLOR_PALETTE = [
2876
+ { bg: 'rgba(59, 130, 246, 0.2)', border: 'rgb(59, 130, 246)' },
2877
+ { bg: 'rgba(34, 197, 94, 0.2)', border: 'rgb(34, 197, 94)' },
2878
+ { bg: 'rgba(249, 115, 22, 0.2)', border: 'rgb(249, 115, 22)' },
2879
+ { bg: 'rgba(139, 92, 246, 0.2)', border: 'rgb(139, 92, 246)' },
2880
+ { bg: 'rgba(236, 72, 153, 0.2)', border: 'rgb(236, 72, 153)' },
2881
+ { bg: 'rgba(6, 182, 212, 0.2)', border: 'rgb(6, 182, 212)' },
2882
+ ];
2883
+ function readThemeColors() {
2884
+ const docStyle = getComputedStyle(document.documentElement);
2885
+ return {
2886
+ text: docStyle.getPropertyValue('--shk-surface-900') || '#27272a',
2887
+ muted: docStyle.getPropertyValue('--shk-surface-500') || '#71717a',
2888
+ border: docStyle.getPropertyValue('--shk-surface-200') || '#e4e4e7',
2889
+ };
2890
+ }
2891
+
2801
2892
  /* Theme — import theme.css in your global styles.css:
2802
2893
  @import '@shirkasoft/ui-components/theme.css';
2803
2894
  Override --shk-* CSS variables at :root or .dark to theme.
@@ -2807,5 +2898,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImpo
2807
2898
  * Generated bundle index. Do not edit.
2808
2899
  */
2809
2900
 
2810
- export { ConfirmDialogComponent, ConfirmDialogService, DatePickerComponent, FileUploadComponent, ModalComponent, ModalService, NotificationComponent, NotificationService, PriceInputComponent, SelectComponent, TableComponent, TextFieldComponent, ToggleComponent, TooltipComponent };
2901
+ export { COLOR_PALETTE, ChartComponent, ConfirmDialogComponent, ConfirmDialogService, DatePickerComponent, FileUploadComponent, ModalComponent, ModalService, NotificationComponent, NotificationService, PriceInputComponent, SelectComponent, TableComponent, TextFieldComponent, ToggleComponent, TooltipComponent, readThemeColors };
2811
2902
  //# sourceMappingURL=shirkasoft-ui-components.mjs.map