shirkasoft-ui-components 1.0.24 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +366 -202
- package/fesm2022/shirkasoft-ui-components.mjs +892 -46
- package/fesm2022/shirkasoft-ui-components.mjs.map +1 -1
- package/package.json +2 -1
- package/src/theme.css +32 -5
- package/types/shirkasoft-ui-components.d.ts +447 -6
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import * as i1 from '@angular/common';
|
|
2
|
-
import { CommonModule } from '@angular/common';
|
|
2
|
+
import { CommonModule, isPlatformBrowser } from '@angular/common';
|
|
3
3
|
import * as i0 from '@angular/core';
|
|
4
|
-
import { inject, ChangeDetectorRef, input, output, viewChild, signal, computed, DestroyRef, effect, forwardRef, ChangeDetectionStrategy, Component, Injectable, model, ElementRef, HostListener, ApplicationRef, EnvironmentInjector, createComponent, ViewContainerRef, untracked } from '@angular/core';
|
|
4
|
+
import { inject, ChangeDetectorRef, input, output, viewChild, signal, computed, DestroyRef, effect, forwardRef, ChangeDetectionStrategy, Component, Injectable, model, ElementRef, HostListener, ApplicationRef, EnvironmentInjector, createComponent, ViewContainerRef, untracked, PLATFORM_ID, Inject, Directive, contentChildren } from '@angular/core';
|
|
5
5
|
import * as i2 from '@angular/forms';
|
|
6
6
|
import { ReactiveFormsModule, NG_VALUE_ACCESSOR, FormsModule, FormControl, FormGroup, FormBuilder } from '@angular/forms';
|
|
7
7
|
import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
|
|
8
8
|
import * as i1$1 from '@jsverse/transloco';
|
|
9
9
|
import { TranslocoService, TranslocoModule } from '@jsverse/transloco';
|
|
10
|
-
import { LucideEyeOff, LucideEye, LucideSearch, LucideDynamicIcon, LucideX, LucideTriangleAlert, LucideInfo, LucideCircleX, LucideCheck, LucideLoader, LucideTrash2, LucideLoaderCircle, LucideMinimize2, LucideMaximize2, LucideChevronRight, LucideChevronLeft, LucideChevronDown, LucideFile, LucideUpload, LucideList, LucideWarehouse, LucideUserCog, LucideShieldCheck, LucideCalculator, LucidePercent, LucideDollarSign, LucideLineChart, LucideBot, LucideReceipt, LucideUsers, LucideTruck, LucideTag, LucideTags, LucideBox, LucidePackage, LucideLandmark, LucideBuilding, LucideUserPlus, LucideUserRoundX, LucideUserCheck, LucideUser, LucideLogOut, LucideSettings, LucideClock, LucideStar, LucideVideo, LucidePlay, LucideShare2, LucideCopy, LucideCircleCheck, LucideArchive, LucideFileText, LucidePresentation, LucideFileSpreadsheet, LucideRefreshCw, LucideCirclePlus, LucidePlus, LucideDownload, LucideToggleLeft, LucideToggleRight, LucideUserPen, LucideKey, LucidePencil, LucideFunnel, LucideInbox, LucideArrowUpDown, LucideArrowDown, LucideArrowUp, LucideChevronsRight, LucideChevronsLeft } from '@lucide/angular';
|
|
10
|
+
import { LucideEyeOff, LucideEye, LucideSearch, LucideDynamicIcon, LucideX, LucideTriangleAlert, LucideInfo, LucideCircleX, LucideCheck, LucideLoader, LucideTrash2, LucideLoaderCircle, LucideMinimize2, LucideMaximize2, LucideChevronRight, LucideChevronLeft, LucideChevronDown, LucideFile, LucideUpload, LucideList, LucideWarehouse, LucideUserCog, LucideShieldCheck, LucideCalculator, LucidePercent, LucideDollarSign, LucideLineChart, LucideBot, LucideReceipt, LucideUsers, LucideTruck, LucideTag, LucideTags, LucideBox, LucidePackage, LucideLandmark, LucideBuilding, LucideUserPlus, LucideUserRoundX, LucideUserCheck, LucideUser, LucideLogOut, LucideSettings, LucideClock, LucideStar, LucideVideo, LucidePlay, LucideShare2, LucideCopy, LucideCircleCheck, LucideArchive, LucideFileText, LucidePresentation, LucideFileSpreadsheet, LucideRefreshCw, LucideCirclePlus, LucidePlus, LucideDownload, LucideToggleLeft, LucideToggleRight, LucideUserPen, LucideKey, LucidePencil, LucideFunnel, LucideInbox, LucideArrowUpDown, LucideArrowDown, LucideArrowUp, LucideChevronsRight, LucideChevronsLeft, LucideBarChart3, LucideMenu, LucideBuilding2, LucideLayoutDashboard, LucideHome, LucideHouse, LucideBanknote, LucidePanelRight, LucideGlobe, LucideCalendarCheck, LucideCalendar, LucideSliders, LucideWallet, LucideBriefcase, LucideIdCard, LucideCreditCard, LucideChartLine, LucideChartPie, LucidePuzzle, LucideLayers, LucideShield, LucideUserRound, LucideMapPin, LucideUtensils, LucideShip, LucideBus, LucideMountain, LucideCar, LucideTicket, LucideHotel, LucideCalendarDays, LucideCircleHelp, LucideCircleAlert, LucideStickyNote, LucideCoins, LucideMap, LucideClipboardCheck, LucideScrollText, LucideArrowLeft } from '@lucide/angular';
|
|
11
11
|
import { Router } from '@angular/router';
|
|
12
12
|
import { Subject, debounceTime } from 'rxjs';
|
|
13
13
|
import { Chart, registerables } from 'chart.js';
|
|
14
14
|
|
|
15
|
-
const icons$
|
|
15
|
+
const icons$9 = {
|
|
16
16
|
search: LucideSearch,
|
|
17
17
|
eye: LucideEye,
|
|
18
18
|
'eye-off': LucideEyeOff,
|
|
@@ -40,7 +40,7 @@ class TextFieldComponent {
|
|
|
40
40
|
this.displayValue = input('', ...(ngDevMode ? [{ debugName: "displayValue" }] : /* istanbul ignore next */ []));
|
|
41
41
|
this.autocomplete = input('new-password', ...(ngDevMode ? [{ debugName: "autocomplete" }] : /* istanbul ignore next */ []));
|
|
42
42
|
this.searchButtonClick = output();
|
|
43
|
-
this.getIcon = (name) => icons$
|
|
43
|
+
this.getIcon = (name) => icons$9[name] ?? LucideEye;
|
|
44
44
|
this.inputElement = viewChild('input', ...(ngDevMode ? [{ debugName: "inputElement" }] : /* istanbul ignore next */ []));
|
|
45
45
|
this.textareaElement = viewChild('textarea', ...(ngDevMode ? [{ debugName: "textareaElement" }] : /* istanbul ignore next */ []));
|
|
46
46
|
this._value = signal('', ...(ngDevMode ? [{ debugName: "_value" }] : /* istanbul ignore next */ []));
|
|
@@ -301,7 +301,7 @@ class TextFieldComponent {
|
|
|
301
301
|
useExisting: forwardRef(() => TextFieldComponent),
|
|
302
302
|
multi: true,
|
|
303
303
|
},
|
|
304
|
-
], 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]=\"autocomplete()\"\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 }); }
|
|
304
|
+
], 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]=\"autocomplete()\"\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 _shk-scrollbar\" 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 }); }
|
|
305
305
|
}
|
|
306
306
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: TextFieldComponent, decorators: [{
|
|
307
307
|
type: Component,
|
|
@@ -311,7 +311,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImpo
|
|
|
311
311
|
useExisting: forwardRef(() => TextFieldComponent),
|
|
312
312
|
multi: true,
|
|
313
313
|
},
|
|
314
|
-
], 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]=\"autocomplete()\"\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" }]
|
|
314
|
+
], 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]=\"autocomplete()\"\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 _shk-scrollbar\" 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" }]
|
|
315
315
|
}], 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 }] }], autocomplete: [{ type: i0.Input, args: [{ isSignal: true, alias: "autocomplete", required: false }] }], searchButtonClick: [{ type: i0.Output, args: ["searchButtonClick"] }], inputElement: [{ type: i0.ViewChild, args: ['input', { isSignal: true }] }], textareaElement: [{ type: i0.ViewChild, args: ['textarea', { isSignal: true }] }] } });
|
|
316
316
|
|
|
317
317
|
class NotificationService {
|
|
@@ -368,7 +368,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImpo
|
|
|
368
368
|
}]
|
|
369
369
|
}] });
|
|
370
370
|
|
|
371
|
-
const icons$
|
|
371
|
+
const icons$8 = {
|
|
372
372
|
check: LucideCheck,
|
|
373
373
|
'circle-x': LucideCircleX,
|
|
374
374
|
info: LucideInfo,
|
|
@@ -379,7 +379,7 @@ class NotificationComponent {
|
|
|
379
379
|
constructor() {
|
|
380
380
|
this.position = input('center-top', ...(ngDevMode ? [{ debugName: "position" }] : /* istanbul ignore next */ []));
|
|
381
381
|
this.notificationService = inject(NotificationService);
|
|
382
|
-
this.getIcon = (name) => icons$
|
|
382
|
+
this.getIcon = (name) => icons$8[name] ?? LucideInfo;
|
|
383
383
|
this.iconMap = {
|
|
384
384
|
success: 'check',
|
|
385
385
|
error: 'circle-x',
|
|
@@ -969,7 +969,7 @@ class DatePickerComponent {
|
|
|
969
969
|
useExisting: forwardRef(() => DatePickerComponent),
|
|
970
970
|
multi: true,
|
|
971
971
|
},
|
|
972
|
-
], 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 <button\n type=\"button\"\n [id]=\"id()\"\n [disabled]=\"isDisabled()\"\n (click)=\"toggle()\"\n class=\"flex items-center justify-between w-full px-3 py-2 text-left _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] border rounded-lg transition-colors sm:text-sm focus:outline-none focus:ring-1 disabled:cursor-not-allowed disabled:[color:var(--shk-surface-400)] dark:disabled:[color:var(--shk-surface-500)]\"\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-200)] focus:[border-color:var(--shk-primary-500)] focus:[--tw-ring-color:var(--shk-primary-500)]': !shouldShowError() && !wasFixedError(),\n }\"\n >\n <span\n [ngClass]=\"value() ? '_shk-text-surface-700 dark:[color:var(--shk-surface-700)]' : '_shk-text-surface-400 dark:[color:var(--shk-surface-400)]'\"\n >\n {{ displayLabel() || placeholder() || label() }}\n </span>\n <svg\n class=\"w-4 h-4 _shk-text-surface-400 dark:[color:var(--shk-surface-400)] shrink-0\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"18\" rx=\"2\"></rect>\n <path d=\"M16 2v4M8 2v4M3 10h18\"></path>\n </svg>\n </button>\n\n @if (isOpen()) {\n <div class=\"fixed inset-0 z-40 bg-black/30\" (click)=\"close()\"></div>\n <div\n class=\"fixed z-50 top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-72 p-4 bg-white dark:[background-color:var(--shk-surface-100)] _shk-border dark:[border-color:var(--shk-surface-200)] rounded-lg shadow-xl\"\n (click)=\"$event.stopPropagation()\"\n >\n @if (view() === 'date') {\n <div class=\"flex items-center justify-between mb-3\">\n <button\n type=\"button\"\n (click)=\"prev()\"\n [disabled]=\"!canGoPrev()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M15 18l-6-6 6-6\"></path>\n </svg>\n </button>\n <span class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-600)]\">\n {{ monthNames()[viewMonth()] }} {{ viewYear() }}\n </span>\n <button\n type=\"button\"\n (click)=\"next()\"\n [disabled]=\"!canGoNext()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M9 18l6-6-6-6\"></path>\n </svg>\n </button>\n </div>\n\n <div class=\"grid grid-cols-7 gap-0 mb-1\">\n @for (name of dayNames(); track $index) {\n <div class=\"text-center text-xs font-medium _shk-text-surface-400 dark:[color:var(--shk-surface-400)] py-1\">\n {{ name }}\n </div>\n }\n </div>\n\n <div class=\"grid grid-cols-7 gap-0\">\n @for (day of calendarDays(); track $index) {\n @if (day !== null) {\n <button\n type=\"button\"\n (click)=\"selectDay(day)\"\n class=\"py-1.5 text-sm rounded transition-colors\"\n [ngClass]=\"{\n '_shk-bg-primary _shk-text-white hover:[background-color:var(--shk-primary-700)]': isSelectedDay(day),\n 'ring-1 [--tw-ring-color:var(--shk-primary-500)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)]': isToday(day) && !isSelectedDay(day),\n '_shk-text-surface-700 dark:[color:var(--shk-surface-700)] hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]': !isSelectedDay(day) && !isToday(day),\n }\"\n >\n {{ day }}\n </button>\n } @else {\n <div></div>\n }\n }\n </div>\n }\n\n @if (view() === 'month') {\n <div class=\"flex items-center justify-between mb-3\">\n <button\n type=\"button\"\n (click)=\"prev()\"\n [disabled]=\"!canGoPrev()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M15 18l-6-6 6-6\"></path>\n </svg>\n </button>\n <span class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-600)]\">{{ viewYear() }}</span>\n <button\n type=\"button\"\n (click)=\"next()\"\n [disabled]=\"!canGoNext()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M9 18l6-6-6-6\"></path>\n </svg>\n </button>\n </div>\n\n <div class=\"grid grid-cols-3 gap-1\">\n @for (name of monthNames(); track $index) {\n <button\n type=\"button\"\n (click)=\"selectMonth($index)\"\n class=\"py-2 text-sm rounded transition-colors\"\n [ngClass]=\"{\n '_shk-bg-primary _shk-text-white hover:[background-color:var(--shk-primary-700)]': isSelectedMonth($index),\n 'ring-1 [--tw-ring-color:var(--shk-primary-500)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)]': isCurrentMonth($index) && !isSelectedMonth($index),\n '_shk-text-surface-700 dark:[color:var(--shk-surface-700)] hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]': !isSelectedMonth($index) && !isCurrentMonth($index),\n }\"\n >\n {{ name }}\n </button>\n }\n </div>\n }\n\n @if (view() === 'year') {\n <div class=\"flex items-center justify-between mb-3\">\n <button\n type=\"button\"\n (click)=\"prev()\"\n [disabled]=\"!canGoPrev()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M15 18l-6-6 6-6\"></path>\n </svg>\n </button>\n <span class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-600)]\">\n {{ viewDecade() }} - {{ viewDecade() + 11 }}\n </span>\n <button\n type=\"button\"\n (click)=\"next()\"\n [disabled]=\"!canGoNext()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M9 18l6-6-6-6\"></path>\n </svg>\n </button>\n </div>\n\n <div class=\"grid grid-cols-3 gap-1\">\n @for (year of decadeYears(); track year) {\n <button\n type=\"button\"\n (click)=\"selectYear(year)\"\n class=\"py-2 text-sm rounded transition-colors\"\n [ngClass]=\"{\n '_shk-bg-primary _shk-text-white hover:[background-color:var(--shk-primary-700)]': isSelectedYear(year),\n 'ring-1 [--tw-ring-color:var(--shk-primary-500)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)]': isCurrentYear(year) && !isSelectedYear(year),\n '_shk-text-surface-700 dark:[color:var(--shk-surface-700)] hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]': !isSelectedYear(year) && !isCurrentYear(year),\n }\"\n >\n {{ year }}\n </button>\n }\n </div>\n }\n </div>\n }\n </div>\n\n @if (shouldShowError()) {\n <div class=\"mt-1 text-xs text-red-500 max-h-20 overflow-y-auto\">\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 }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
972
|
+
], 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 <button\n type=\"button\"\n [id]=\"id()\"\n [disabled]=\"isDisabled()\"\n (click)=\"toggle()\"\n class=\"flex items-center justify-between w-full px-3 py-2 text-left _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] border rounded-lg transition-colors sm:text-sm focus:outline-none focus:ring-1 disabled:cursor-not-allowed disabled:[color:var(--shk-surface-400)] dark:disabled:[color:var(--shk-surface-500)]\"\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-200)] focus:[border-color:var(--shk-primary-500)] focus:[--tw-ring-color:var(--shk-primary-500)]': !shouldShowError() && !wasFixedError(),\n }\"\n >\n <span\n [ngClass]=\"value() ? '_shk-text-surface-700 dark:[color:var(--shk-surface-700)]' : '_shk-text-surface-400 dark:[color:var(--shk-surface-400)]'\"\n >\n {{ displayLabel() || placeholder() || label() }}\n </span>\n <svg\n class=\"w-4 h-4 _shk-text-surface-400 dark:[color:var(--shk-surface-400)] shrink-0\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"18\" rx=\"2\"></rect>\n <path d=\"M16 2v4M8 2v4M3 10h18\"></path>\n </svg>\n </button>\n\n @if (isOpen()) {\n <div class=\"fixed inset-0 z-40 bg-black/30\" (click)=\"close()\"></div>\n <div\n class=\"fixed z-50 top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-72 p-4 bg-white dark:[background-color:var(--shk-surface-100)] _shk-border dark:[border-color:var(--shk-surface-200)] rounded-lg shadow-xl\"\n (click)=\"$event.stopPropagation()\"\n >\n @if (view() === 'date') {\n <div class=\"flex items-center justify-between mb-3\">\n <button\n type=\"button\"\n (click)=\"prev()\"\n [disabled]=\"!canGoPrev()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M15 18l-6-6 6-6\"></path>\n </svg>\n </button>\n <span class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-600)]\">\n {{ monthNames()[viewMonth()] }} {{ viewYear() }}\n </span>\n <button\n type=\"button\"\n (click)=\"next()\"\n [disabled]=\"!canGoNext()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M9 18l6-6-6-6\"></path>\n </svg>\n </button>\n </div>\n\n <div class=\"grid grid-cols-7 gap-0 mb-1\">\n @for (name of dayNames(); track $index) {\n <div class=\"text-center text-xs font-medium _shk-text-surface-400 dark:[color:var(--shk-surface-400)] py-1\">\n {{ name }}\n </div>\n }\n </div>\n\n <div class=\"grid grid-cols-7 gap-0\">\n @for (day of calendarDays(); track $index) {\n @if (day !== null) {\n <button\n type=\"button\"\n (click)=\"selectDay(day)\"\n class=\"py-1.5 text-sm rounded transition-colors\"\n [ngClass]=\"{\n '_shk-bg-primary _shk-text-white hover:[background-color:var(--shk-primary-700)]': isSelectedDay(day),\n 'ring-1 [--tw-ring-color:var(--shk-primary-500)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)]': isToday(day) && !isSelectedDay(day),\n '_shk-text-surface-700 dark:[color:var(--shk-surface-700)] hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]': !isSelectedDay(day) && !isToday(day),\n }\"\n >\n {{ day }}\n </button>\n } @else {\n <div></div>\n }\n }\n </div>\n }\n\n @if (view() === 'month') {\n <div class=\"flex items-center justify-between mb-3\">\n <button\n type=\"button\"\n (click)=\"prev()\"\n [disabled]=\"!canGoPrev()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M15 18l-6-6 6-6\"></path>\n </svg>\n </button>\n <span class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-600)]\">{{ viewYear() }}</span>\n <button\n type=\"button\"\n (click)=\"next()\"\n [disabled]=\"!canGoNext()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M9 18l6-6-6-6\"></path>\n </svg>\n </button>\n </div>\n\n <div class=\"grid grid-cols-3 gap-1\">\n @for (name of monthNames(); track $index) {\n <button\n type=\"button\"\n (click)=\"selectMonth($index)\"\n class=\"py-2 text-sm rounded transition-colors\"\n [ngClass]=\"{\n '_shk-bg-primary _shk-text-white hover:[background-color:var(--shk-primary-700)]': isSelectedMonth($index),\n 'ring-1 [--tw-ring-color:var(--shk-primary-500)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)]': isCurrentMonth($index) && !isSelectedMonth($index),\n '_shk-text-surface-700 dark:[color:var(--shk-surface-700)] hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]': !isSelectedMonth($index) && !isCurrentMonth($index),\n }\"\n >\n {{ name }}\n </button>\n }\n </div>\n }\n\n @if (view() === 'year') {\n <div class=\"flex items-center justify-between mb-3\">\n <button\n type=\"button\"\n (click)=\"prev()\"\n [disabled]=\"!canGoPrev()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M15 18l-6-6 6-6\"></path>\n </svg>\n </button>\n <span class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-600)]\">\n {{ viewDecade() }} - {{ viewDecade() + 11 }}\n </span>\n <button\n type=\"button\"\n (click)=\"next()\"\n [disabled]=\"!canGoNext()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M9 18l6-6-6-6\"></path>\n </svg>\n </button>\n </div>\n\n <div class=\"grid grid-cols-3 gap-1\">\n @for (year of decadeYears(); track year) {\n <button\n type=\"button\"\n (click)=\"selectYear(year)\"\n class=\"py-2 text-sm rounded transition-colors\"\n [ngClass]=\"{\n '_shk-bg-primary _shk-text-white hover:[background-color:var(--shk-primary-700)]': isSelectedYear(year),\n 'ring-1 [--tw-ring-color:var(--shk-primary-500)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)]': isCurrentYear(year) && !isSelectedYear(year),\n '_shk-text-surface-700 dark:[color:var(--shk-surface-700)] hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]': !isSelectedYear(year) && !isCurrentYear(year),\n }\"\n >\n {{ year }}\n </button>\n }\n </div>\n }\n </div>\n }\n </div>\n\n @if (shouldShowError()) {\n <div class=\"mt-1 text-xs text-red-500 max-h-20 overflow-y-auto _shk-scrollbar\">\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 }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
973
973
|
}
|
|
974
974
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: DatePickerComponent, decorators: [{
|
|
975
975
|
type: Component,
|
|
@@ -979,7 +979,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImpo
|
|
|
979
979
|
useExisting: forwardRef(() => DatePickerComponent),
|
|
980
980
|
multi: true,
|
|
981
981
|
},
|
|
982
|
-
], 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 <button\n type=\"button\"\n [id]=\"id()\"\n [disabled]=\"isDisabled()\"\n (click)=\"toggle()\"\n class=\"flex items-center justify-between w-full px-3 py-2 text-left _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] border rounded-lg transition-colors sm:text-sm focus:outline-none focus:ring-1 disabled:cursor-not-allowed disabled:[color:var(--shk-surface-400)] dark:disabled:[color:var(--shk-surface-500)]\"\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-200)] focus:[border-color:var(--shk-primary-500)] focus:[--tw-ring-color:var(--shk-primary-500)]': !shouldShowError() && !wasFixedError(),\n }\"\n >\n <span\n [ngClass]=\"value() ? '_shk-text-surface-700 dark:[color:var(--shk-surface-700)]' : '_shk-text-surface-400 dark:[color:var(--shk-surface-400)]'\"\n >\n {{ displayLabel() || placeholder() || label() }}\n </span>\n <svg\n class=\"w-4 h-4 _shk-text-surface-400 dark:[color:var(--shk-surface-400)] shrink-0\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"18\" rx=\"2\"></rect>\n <path d=\"M16 2v4M8 2v4M3 10h18\"></path>\n </svg>\n </button>\n\n @if (isOpen()) {\n <div class=\"fixed inset-0 z-40 bg-black/30\" (click)=\"close()\"></div>\n <div\n class=\"fixed z-50 top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-72 p-4 bg-white dark:[background-color:var(--shk-surface-100)] _shk-border dark:[border-color:var(--shk-surface-200)] rounded-lg shadow-xl\"\n (click)=\"$event.stopPropagation()\"\n >\n @if (view() === 'date') {\n <div class=\"flex items-center justify-between mb-3\">\n <button\n type=\"button\"\n (click)=\"prev()\"\n [disabled]=\"!canGoPrev()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M15 18l-6-6 6-6\"></path>\n </svg>\n </button>\n <span class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-600)]\">\n {{ monthNames()[viewMonth()] }} {{ viewYear() }}\n </span>\n <button\n type=\"button\"\n (click)=\"next()\"\n [disabled]=\"!canGoNext()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M9 18l6-6-6-6\"></path>\n </svg>\n </button>\n </div>\n\n <div class=\"grid grid-cols-7 gap-0 mb-1\">\n @for (name of dayNames(); track $index) {\n <div class=\"text-center text-xs font-medium _shk-text-surface-400 dark:[color:var(--shk-surface-400)] py-1\">\n {{ name }}\n </div>\n }\n </div>\n\n <div class=\"grid grid-cols-7 gap-0\">\n @for (day of calendarDays(); track $index) {\n @if (day !== null) {\n <button\n type=\"button\"\n (click)=\"selectDay(day)\"\n class=\"py-1.5 text-sm rounded transition-colors\"\n [ngClass]=\"{\n '_shk-bg-primary _shk-text-white hover:[background-color:var(--shk-primary-700)]': isSelectedDay(day),\n 'ring-1 [--tw-ring-color:var(--shk-primary-500)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)]': isToday(day) && !isSelectedDay(day),\n '_shk-text-surface-700 dark:[color:var(--shk-surface-700)] hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]': !isSelectedDay(day) && !isToday(day),\n }\"\n >\n {{ day }}\n </button>\n } @else {\n <div></div>\n }\n }\n </div>\n }\n\n @if (view() === 'month') {\n <div class=\"flex items-center justify-between mb-3\">\n <button\n type=\"button\"\n (click)=\"prev()\"\n [disabled]=\"!canGoPrev()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M15 18l-6-6 6-6\"></path>\n </svg>\n </button>\n <span class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-600)]\">{{ viewYear() }}</span>\n <button\n type=\"button\"\n (click)=\"next()\"\n [disabled]=\"!canGoNext()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M9 18l6-6-6-6\"></path>\n </svg>\n </button>\n </div>\n\n <div class=\"grid grid-cols-3 gap-1\">\n @for (name of monthNames(); track $index) {\n <button\n type=\"button\"\n (click)=\"selectMonth($index)\"\n class=\"py-2 text-sm rounded transition-colors\"\n [ngClass]=\"{\n '_shk-bg-primary _shk-text-white hover:[background-color:var(--shk-primary-700)]': isSelectedMonth($index),\n 'ring-1 [--tw-ring-color:var(--shk-primary-500)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)]': isCurrentMonth($index) && !isSelectedMonth($index),\n '_shk-text-surface-700 dark:[color:var(--shk-surface-700)] hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]': !isSelectedMonth($index) && !isCurrentMonth($index),\n }\"\n >\n {{ name }}\n </button>\n }\n </div>\n }\n\n @if (view() === 'year') {\n <div class=\"flex items-center justify-between mb-3\">\n <button\n type=\"button\"\n (click)=\"prev()\"\n [disabled]=\"!canGoPrev()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M15 18l-6-6 6-6\"></path>\n </svg>\n </button>\n <span class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-600)]\">\n {{ viewDecade() }} - {{ viewDecade() + 11 }}\n </span>\n <button\n type=\"button\"\n (click)=\"next()\"\n [disabled]=\"!canGoNext()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M9 18l6-6-6-6\"></path>\n </svg>\n </button>\n </div>\n\n <div class=\"grid grid-cols-3 gap-1\">\n @for (year of decadeYears(); track year) {\n <button\n type=\"button\"\n (click)=\"selectYear(year)\"\n class=\"py-2 text-sm rounded transition-colors\"\n [ngClass]=\"{\n '_shk-bg-primary _shk-text-white hover:[background-color:var(--shk-primary-700)]': isSelectedYear(year),\n 'ring-1 [--tw-ring-color:var(--shk-primary-500)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)]': isCurrentYear(year) && !isSelectedYear(year),\n '_shk-text-surface-700 dark:[color:var(--shk-surface-700)] hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]': !isSelectedYear(year) && !isCurrentYear(year),\n }\"\n >\n {{ year }}\n </button>\n }\n </div>\n }\n </div>\n }\n </div>\n\n @if (shouldShowError()) {\n <div class=\"mt-1 text-xs text-red-500 max-h-20 overflow-y-auto\">\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" }]
|
|
982
|
+
], 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 <button\n type=\"button\"\n [id]=\"id()\"\n [disabled]=\"isDisabled()\"\n (click)=\"toggle()\"\n class=\"flex items-center justify-between w-full px-3 py-2 text-left _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] border rounded-lg transition-colors sm:text-sm focus:outline-none focus:ring-1 disabled:cursor-not-allowed disabled:[color:var(--shk-surface-400)] dark:disabled:[color:var(--shk-surface-500)]\"\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-200)] focus:[border-color:var(--shk-primary-500)] focus:[--tw-ring-color:var(--shk-primary-500)]': !shouldShowError() && !wasFixedError(),\n }\"\n >\n <span\n [ngClass]=\"value() ? '_shk-text-surface-700 dark:[color:var(--shk-surface-700)]' : '_shk-text-surface-400 dark:[color:var(--shk-surface-400)]'\"\n >\n {{ displayLabel() || placeholder() || label() }}\n </span>\n <svg\n class=\"w-4 h-4 _shk-text-surface-400 dark:[color:var(--shk-surface-400)] shrink-0\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"18\" rx=\"2\"></rect>\n <path d=\"M16 2v4M8 2v4M3 10h18\"></path>\n </svg>\n </button>\n\n @if (isOpen()) {\n <div class=\"fixed inset-0 z-40 bg-black/30\" (click)=\"close()\"></div>\n <div\n class=\"fixed z-50 top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-72 p-4 bg-white dark:[background-color:var(--shk-surface-100)] _shk-border dark:[border-color:var(--shk-surface-200)] rounded-lg shadow-xl\"\n (click)=\"$event.stopPropagation()\"\n >\n @if (view() === 'date') {\n <div class=\"flex items-center justify-between mb-3\">\n <button\n type=\"button\"\n (click)=\"prev()\"\n [disabled]=\"!canGoPrev()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M15 18l-6-6 6-6\"></path>\n </svg>\n </button>\n <span class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-600)]\">\n {{ monthNames()[viewMonth()] }} {{ viewYear() }}\n </span>\n <button\n type=\"button\"\n (click)=\"next()\"\n [disabled]=\"!canGoNext()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M9 18l6-6-6-6\"></path>\n </svg>\n </button>\n </div>\n\n <div class=\"grid grid-cols-7 gap-0 mb-1\">\n @for (name of dayNames(); track $index) {\n <div class=\"text-center text-xs font-medium _shk-text-surface-400 dark:[color:var(--shk-surface-400)] py-1\">\n {{ name }}\n </div>\n }\n </div>\n\n <div class=\"grid grid-cols-7 gap-0\">\n @for (day of calendarDays(); track $index) {\n @if (day !== null) {\n <button\n type=\"button\"\n (click)=\"selectDay(day)\"\n class=\"py-1.5 text-sm rounded transition-colors\"\n [ngClass]=\"{\n '_shk-bg-primary _shk-text-white hover:[background-color:var(--shk-primary-700)]': isSelectedDay(day),\n 'ring-1 [--tw-ring-color:var(--shk-primary-500)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)]': isToday(day) && !isSelectedDay(day),\n '_shk-text-surface-700 dark:[color:var(--shk-surface-700)] hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]': !isSelectedDay(day) && !isToday(day),\n }\"\n >\n {{ day }}\n </button>\n } @else {\n <div></div>\n }\n }\n </div>\n }\n\n @if (view() === 'month') {\n <div class=\"flex items-center justify-between mb-3\">\n <button\n type=\"button\"\n (click)=\"prev()\"\n [disabled]=\"!canGoPrev()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M15 18l-6-6 6-6\"></path>\n </svg>\n </button>\n <span class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-600)]\">{{ viewYear() }}</span>\n <button\n type=\"button\"\n (click)=\"next()\"\n [disabled]=\"!canGoNext()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M9 18l6-6-6-6\"></path>\n </svg>\n </button>\n </div>\n\n <div class=\"grid grid-cols-3 gap-1\">\n @for (name of monthNames(); track $index) {\n <button\n type=\"button\"\n (click)=\"selectMonth($index)\"\n class=\"py-2 text-sm rounded transition-colors\"\n [ngClass]=\"{\n '_shk-bg-primary _shk-text-white hover:[background-color:var(--shk-primary-700)]': isSelectedMonth($index),\n 'ring-1 [--tw-ring-color:var(--shk-primary-500)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)]': isCurrentMonth($index) && !isSelectedMonth($index),\n '_shk-text-surface-700 dark:[color:var(--shk-surface-700)] hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]': !isSelectedMonth($index) && !isCurrentMonth($index),\n }\"\n >\n {{ name }}\n </button>\n }\n </div>\n }\n\n @if (view() === 'year') {\n <div class=\"flex items-center justify-between mb-3\">\n <button\n type=\"button\"\n (click)=\"prev()\"\n [disabled]=\"!canGoPrev()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M15 18l-6-6 6-6\"></path>\n </svg>\n </button>\n <span class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-600)]\">\n {{ viewDecade() }} - {{ viewDecade() + 11 }}\n </span>\n <button\n type=\"button\"\n (click)=\"next()\"\n [disabled]=\"!canGoNext()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M9 18l6-6-6-6\"></path>\n </svg>\n </button>\n </div>\n\n <div class=\"grid grid-cols-3 gap-1\">\n @for (year of decadeYears(); track year) {\n <button\n type=\"button\"\n (click)=\"selectYear(year)\"\n class=\"py-2 text-sm rounded transition-colors\"\n [ngClass]=\"{\n '_shk-bg-primary _shk-text-white hover:[background-color:var(--shk-primary-700)]': isSelectedYear(year),\n 'ring-1 [--tw-ring-color:var(--shk-primary-500)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)]': isCurrentYear(year) && !isSelectedYear(year),\n '_shk-text-surface-700 dark:[color:var(--shk-surface-700)] hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]': !isSelectedYear(year) && !isCurrentYear(year),\n }\"\n >\n {{ year }}\n </button>\n }\n </div>\n }\n </div>\n }\n </div>\n\n @if (shouldShowError()) {\n <div class=\"mt-1 text-xs text-red-500 max-h-20 overflow-y-auto _shk-scrollbar\">\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" }]
|
|
983
983
|
}], ctorParameters: () => [], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], view: [{ type: i0.Input, args: [{ isSignal: true, alias: "view", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", 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 }] }], errorMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessages", required: false }] }], minValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "minValue", required: false }] }], maxValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxValue", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], onDocumentClick: [{
|
|
984
984
|
type: HostListener,
|
|
985
985
|
args: ['document:click', ['$event']]
|
|
@@ -988,7 +988,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImpo
|
|
|
988
988
|
args: ['document:keydown.escape']
|
|
989
989
|
}] } });
|
|
990
990
|
|
|
991
|
-
const icons$
|
|
991
|
+
const icons$7 = {
|
|
992
992
|
info: LucideInfo,
|
|
993
993
|
'triangle-alert': LucideTriangleAlert,
|
|
994
994
|
x: LucideX,
|
|
@@ -997,7 +997,7 @@ const icons$4 = {
|
|
|
997
997
|
};
|
|
998
998
|
class ConfirmDialogComponent {
|
|
999
999
|
constructor() {
|
|
1000
|
-
this.getIcon = (name) => icons$
|
|
1000
|
+
this.getIcon = (name) => icons$7[name] ?? LucideTriangleAlert;
|
|
1001
1001
|
this.title = input('Confirmar acción', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
|
|
1002
1002
|
this.message = input('¿Está seguro de realizar esta acción?', ...(ngDevMode ? [{ debugName: "message" }] : /* istanbul ignore next */ []));
|
|
1003
1003
|
this.confirmLabel = input('Confirmar', ...(ngDevMode ? [{ debugName: "confirmLabel" }] : /* istanbul ignore next */ []));
|
|
@@ -1133,7 +1133,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImpo
|
|
|
1133
1133
|
args: [{ providedIn: 'root' }]
|
|
1134
1134
|
}], ctorParameters: () => [] });
|
|
1135
1135
|
|
|
1136
|
-
const icons$
|
|
1136
|
+
const icons$6 = {
|
|
1137
1137
|
x: LucideX,
|
|
1138
1138
|
check: LucideCheck,
|
|
1139
1139
|
'maximize-2': LucideMaximize2,
|
|
@@ -1142,7 +1142,7 @@ const icons$3 = {
|
|
|
1142
1142
|
};
|
|
1143
1143
|
class ModalComponent {
|
|
1144
1144
|
constructor() {
|
|
1145
|
-
this.getIcon = (name) => icons$
|
|
1145
|
+
this.getIcon = (name) => icons$6[name] ?? LucideX;
|
|
1146
1146
|
this.notificationSrv = inject(NotificationService);
|
|
1147
1147
|
this.destroyRef = inject(DestroyRef);
|
|
1148
1148
|
this.modalSrv = inject(ModalService);
|
|
@@ -1313,14 +1313,14 @@ class ModalComponent {
|
|
|
1313
1313
|
}
|
|
1314
1314
|
}
|
|
1315
1315
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: ModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1316
|
-
static { this.ɵ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 }); }
|
|
1316
|
+
static { this.ɵ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 _shk-scrollbar\"\n (click)=\"closeModal()\"\n >\n <div\n class=\"bg-white dark:[background-color:var(--shk-surface-100)] rounded-xl shadow-2xl overflow-hidden flex flex-col animate-in fade-in zoom-in duration-200\"\n [class.w-[95vw]]=\"isExpanded()\"\n [class.h-[90vh]]=\"isExpanded()\"\n [class.w-full]=\"!isExpanded()\"\n [style.max-width]=\"isExpanded() ? undefined : computedModalWidth()\"\n (click)=\"$event.stopPropagation()\"\n >\n <div class=\"h-1.5 w-full _shk-gradient-emerald shrink-0\"></div>\n\n <div class=\"flex items-center justify-between px-6 pt-4 pb-2 shrink-0\">\n <span class=\"font-semibold text-lg _shk-text-surface-800 dark:[color:var(--shk-surface-800)]\">{{ title() }}</span>\n <div class=\"flex items-center gap-2\">\n @if (showExpandButton()) {\n <button\n type=\"button\"\n (click)=\"toggleExpand()\"\n class=\"p-1.5 rounded-lg hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] _shk-text-surface-500 dark:[color:var(--shk-surface-500)] transition-colors\"\n >\n @if (isExpanded()) {\n <svg [lucideIcon]=\"getIcon('minimize-2')\" class=\"w-4 h-4\"></svg>\n } @else {\n <svg [lucideIcon]=\"getIcon('maximize-2')\" class=\"w-4 h-4\"></svg>\n }\n </button>\n }\n <button\n type=\"button\"\n (click)=\"closeModal()\"\n class=\"p-1.5 rounded-lg hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] _shk-text-surface-500 dark:[color:var(--shk-surface-500)] transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('x')\" class=\"w-4 h-4\"></svg>\n </button>\n </div>\n </div>\n\n <div class=\"overflow-y-auto px-6 py-4 flex-1 max-h-[70vh] _shk-scrollbar\">\n <ng-container #dynamicContent></ng-container>\n </div>\n\n @if (modalButtonsVisible()) {\n <hr class=\"border-t _shk-border dark:[border-color:var(--shk-surface-200)] shrink-0\" />\n <div class=\"flex justify-end gap-3 px-6 py-4 shrink-0\">\n <button\n type=\"button\"\n (click)=\"closeModal()\"\n [disabled]=\"loading()\"\n class=\"px-4 py-2 text-sm font-semibold _shk-text-surface-600 dark:[color:var(--shk-surface-600)] _shk-bg-surface-100 dark:[background-color:var(--shk-surface-200)] hover:[background-color:var(--shk-surface-200)] dark:hover:[background-color:var(--shk-surface-300)] rounded-lg transition-colors flex items-center gap-2 disabled:opacity-50\"\n >\n <svg [lucideIcon]=\"getIcon('x')\" class=\"w-4 h-4\"></svg>\n {{ cancelLabel() }}\n </button>\n <button\n type=\"button\"\n (click)=\"onAccept()\"\n [disabled]=\"loading()\"\n class=\"px-4 py-2 text-sm font-semibold _shk-text-white _shk-bg-emerald hover:[background-color:var(--shk-emerald-700)] rounded-lg shadow-md transition-all flex items-center gap-2 disabled:opacity-50\"\n >\n @if (loading()) {\n <svg [lucideIcon]=\"getIcon('loader-circle')\" class=\"w-4 h-4 animate-spin\"></svg>\n } @else {\n <svg [lucideIcon]=\"getIcon('check')\" class=\"w-4 h-4\"></svg>\n }\n {{ acceptLabel() }}\n </button>\n </div>\n }\n </div>\n </div>\n}\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: LucideDynamicIcon, selector: "svg[lucideIcon]", inputs: ["lucideIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1317
1317
|
}
|
|
1318
1318
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: ModalComponent, decorators: [{
|
|
1319
1319
|
type: Component,
|
|
1320
|
-
args: [{ selector: 'shk-modal', standalone: true, imports: [CommonModule, LucideDynamicIcon], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (visible()) {\n <div\n class=\"fixed inset-0 bg-black/40 backdrop-blur-sm flex items-center justify-center z-40 p-4 pt-4 overflow-y-auto\"\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" }]
|
|
1320
|
+
args: [{ selector: 'shk-modal', standalone: true, imports: [CommonModule, LucideDynamicIcon], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (visible()) {\n <div\n class=\"fixed inset-0 bg-black/40 backdrop-blur-sm flex items-center justify-center z-40 p-4 pt-4 overflow-y-auto _shk-scrollbar\"\n (click)=\"closeModal()\"\n >\n <div\n class=\"bg-white dark:[background-color:var(--shk-surface-100)] rounded-xl shadow-2xl overflow-hidden flex flex-col animate-in fade-in zoom-in duration-200\"\n [class.w-[95vw]]=\"isExpanded()\"\n [class.h-[90vh]]=\"isExpanded()\"\n [class.w-full]=\"!isExpanded()\"\n [style.max-width]=\"isExpanded() ? undefined : computedModalWidth()\"\n (click)=\"$event.stopPropagation()\"\n >\n <div class=\"h-1.5 w-full _shk-gradient-emerald shrink-0\"></div>\n\n <div class=\"flex items-center justify-between px-6 pt-4 pb-2 shrink-0\">\n <span class=\"font-semibold text-lg _shk-text-surface-800 dark:[color:var(--shk-surface-800)]\">{{ title() }}</span>\n <div class=\"flex items-center gap-2\">\n @if (showExpandButton()) {\n <button\n type=\"button\"\n (click)=\"toggleExpand()\"\n class=\"p-1.5 rounded-lg hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] _shk-text-surface-500 dark:[color:var(--shk-surface-500)] transition-colors\"\n >\n @if (isExpanded()) {\n <svg [lucideIcon]=\"getIcon('minimize-2')\" class=\"w-4 h-4\"></svg>\n } @else {\n <svg [lucideIcon]=\"getIcon('maximize-2')\" class=\"w-4 h-4\"></svg>\n }\n </button>\n }\n <button\n type=\"button\"\n (click)=\"closeModal()\"\n class=\"p-1.5 rounded-lg hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] _shk-text-surface-500 dark:[color:var(--shk-surface-500)] transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('x')\" class=\"w-4 h-4\"></svg>\n </button>\n </div>\n </div>\n\n <div class=\"overflow-y-auto px-6 py-4 flex-1 max-h-[70vh] _shk-scrollbar\">\n <ng-container #dynamicContent></ng-container>\n </div>\n\n @if (modalButtonsVisible()) {\n <hr class=\"border-t _shk-border dark:[border-color:var(--shk-surface-200)] shrink-0\" />\n <div class=\"flex justify-end gap-3 px-6 py-4 shrink-0\">\n <button\n type=\"button\"\n (click)=\"closeModal()\"\n [disabled]=\"loading()\"\n class=\"px-4 py-2 text-sm font-semibold _shk-text-surface-600 dark:[color:var(--shk-surface-600)] _shk-bg-surface-100 dark:[background-color:var(--shk-surface-200)] hover:[background-color:var(--shk-surface-200)] dark:hover:[background-color:var(--shk-surface-300)] rounded-lg transition-colors flex items-center gap-2 disabled:opacity-50\"\n >\n <svg [lucideIcon]=\"getIcon('x')\" class=\"w-4 h-4\"></svg>\n {{ cancelLabel() }}\n </button>\n <button\n type=\"button\"\n (click)=\"onAccept()\"\n [disabled]=\"loading()\"\n class=\"px-4 py-2 text-sm font-semibold _shk-text-white _shk-bg-emerald hover:[background-color:var(--shk-emerald-700)] rounded-lg shadow-md transition-all flex items-center gap-2 disabled:opacity-50\"\n >\n @if (loading()) {\n <svg [lucideIcon]=\"getIcon('loader-circle')\" class=\"w-4 h-4 animate-spin\"></svg>\n } @else {\n <svg [lucideIcon]=\"getIcon('check')\" class=\"w-4 h-4\"></svg>\n }\n {{ acceptLabel() }}\n </button>\n </div>\n }\n </div>\n </div>\n}\n" }]
|
|
1321
1321
|
}], ctorParameters: () => [], propDecorators: { container: [{ type: i0.ViewChild, args: ['dynamicContent', { ...{ read: ViewContainerRef }, isSignal: true }] }] } });
|
|
1322
1322
|
|
|
1323
|
-
const icons$
|
|
1323
|
+
const icons$5 = {
|
|
1324
1324
|
'chevron-down': LucideChevronDown,
|
|
1325
1325
|
'chevron-left': LucideChevronLeft,
|
|
1326
1326
|
'chevron-right': LucideChevronRight,
|
|
@@ -1328,7 +1328,7 @@ const icons$2 = {
|
|
|
1328
1328
|
class SelectComponent {
|
|
1329
1329
|
constructor(elementRef) {
|
|
1330
1330
|
this.elementRef = elementRef;
|
|
1331
|
-
this.getIcon = (name) => icons$
|
|
1331
|
+
this.getIcon = (name) => icons$5[name] ?? LucideChevronDown;
|
|
1332
1332
|
this.options = input([], ...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
|
|
1333
1333
|
this.multiple = input(false, ...(ngDevMode ? [{ debugName: "multiple" }] : /* istanbul ignore next */ []));
|
|
1334
1334
|
this.validCombinations = input(undefined, ...(ngDevMode ? [{ debugName: "validCombinations" }] : /* istanbul ignore next */ []));
|
|
@@ -1933,7 +1933,7 @@ class SelectComponent {
|
|
|
1933
1933
|
useExisting: forwardRef(() => SelectComponent),
|
|
1934
1934
|
multi: true,
|
|
1935
1935
|
},
|
|
1936
|
-
], 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 }); }
|
|
1936
|
+
], 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 _shk-scrollbar\"\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 _shk-scrollbar\" 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 }); }
|
|
1937
1937
|
}
|
|
1938
1938
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: SelectComponent, decorators: [{
|
|
1939
1939
|
type: Component,
|
|
@@ -1949,20 +1949,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImpo
|
|
|
1949
1949
|
useExisting: forwardRef(() => SelectComponent),
|
|
1950
1950
|
multi: true,
|
|
1951
1951
|
},
|
|
1952
|
-
], 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"] }]
|
|
1952
|
+
], 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 _shk-scrollbar\"\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 _shk-scrollbar\" 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"] }]
|
|
1953
1953
|
}], 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: [{
|
|
1954
1954
|
type: HostListener,
|
|
1955
1955
|
args: ['document:mousedown', ['$event']]
|
|
1956
1956
|
}] } });
|
|
1957
1957
|
|
|
1958
|
-
const icons$
|
|
1958
|
+
const icons$4 = {
|
|
1959
1959
|
upload: LucideUpload,
|
|
1960
1960
|
file: LucideFile,
|
|
1961
1961
|
x: LucideX,
|
|
1962
1962
|
};
|
|
1963
1963
|
class FileUploadComponent {
|
|
1964
1964
|
constructor() {
|
|
1965
|
-
this.getIcon = (name) => icons$
|
|
1965
|
+
this.getIcon = (name) => icons$4[name] ?? LucideUpload;
|
|
1966
1966
|
this.transloco = inject(TranslocoService);
|
|
1967
1967
|
this.label = input('Cargar archivo', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
1968
1968
|
this.accept = input('image/*', ...(ngDevMode ? [{ debugName: "accept" }] : /* istanbul ignore next */ []));
|
|
@@ -2149,7 +2149,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImpo
|
|
|
2149
2149
|
args: [{ selector: 'shk-file-upload', standalone: true, imports: [CommonModule, LucideDynamicIcon], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"flex flex-col gap-2\">\n @if (label()) {\n <label class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-300)]\">\n {{ label() }}\n </label>\n }\n\n @if (canAddMore()) {\n <div\n class=\"relative border-2 border-dashed _shk-border dark:[border-color:var(--shk-surface-700)] rounded-lg p-4 transition-colors hover:[border-color:var(--shk-primary-400)] dark:hover:[border-color:var(--shk-primary-500)]\"\n [class.border-red-400]=\"errorMessage()\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n >\n <input\n #fileInput\n type=\"file\"\n [accept]=\"accept()\"\n [multiple]=\"multiple()\"\n (change)=\"onFileChange($event)\"\n class=\"hidden\"\n />\n\n <div\n class=\"flex flex-col items-center gap-2 cursor-pointer\"\n (click)=\"fileInput.click()\"\n [class.drag-over]=\"isDragOver()\"\n >\n <svg [lucideIcon]=\"getIcon('upload')\" class=\"w-8 h-8 _shk-icon-subtle dark:[color:var(--shk-surface-600)]\"></svg>\n <span class=\"text-sm _shk-text-surface-700 dark:[color:var(--shk-surface-300)]\">\n {{ fileUploadText() }}\n </span>\n @if (fileRecommendation()) {\n <span class=\"text-xs _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\">\n {{ fileRecommendation() }}\n </span>\n }\n </div>\n </div>\n }\n\n @if (maxReached()) {\n <div class=\"text-xs _shk-text-surface-400 dark:[color:var(--shk-surface-500)] text-center py-2\">\n M\u00E1ximo {{ maxFiles() }} archivos alcanzado\n </div>\n }\n\n @if (selectedFiles().length > 0) {\n <div class=\"flex flex-wrap gap-3\">\n @for (file of selectedFiles(); track file.name + file.size + file.lastModified) {\n <div class=\"relative group\">\n @if (isImageFile(file)) {\n <img\n [src]=\"previewUrl(file)\"\n [alt]=\"file.name\"\n class=\"w-20 h-20 object-cover rounded-lg _shk-border dark:[border-color:var(--shk-surface-700)]\"\n />\n } @else {\n <div class=\"w-20 h-20 rounded-lg _shk-border dark:[border-color:var(--shk-surface-700)] flex flex-col items-center justify-center _shk-bg-surface-50 dark:[background-color:var(--shk-surface-800)] gap-1\">\n <svg [lucideIcon]=\"getIcon('file')\" class=\"w-6 h-6 _shk-text-surface-400\"></svg>\n <span class=\"text-[10px] _shk-text-surface-400 truncate max-w-[70px] px-1 text-center\">{{ file.name }}</span>\n </div>\n }\n <button\n type=\"button\"\n (click)=\"removeFile(file)\"\n class=\"absolute -top-1.5 -right-1.5 w-5 h-5 bg-red-500 text-white rounded-full text-xs flex items-center justify-center opacity-0 group-hover:opacity-100 transition shadow\"\n >\n <svg [lucideIcon]=\"getIcon('x')\" class=\"w-3 h-3\"></svg>\n </button>\n </div>\n }\n </div>\n @if (!multiple()) {\n <button\n type=\"button\"\n (click)=\"changeFiles()\"\n class=\"text-xs _shk-text-primary hover:[color:var(--shk-primary-700)] dark:[color:var(--shk-primary-400)] dark:hover:[color:var(--shk-primary-300)] underline cursor-pointer bg-transparent border-0\"\n >\n {{ changeFilesText() }}\n </button>\n }\n }\n\n @if (errorMessage()) {\n <p class=\"text-xs _shk-text-red-500\">{{ errorMessage() }}</p>\n }\n</div>" }]
|
|
2150
2150
|
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], accept: [{ type: i0.Input, args: [{ isSignal: true, alias: "accept", required: false }] }], maxFileSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFileSize", required: false }] }], maxFiles: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFiles", required: false }] }], fileUploadText: [{ type: i0.Input, args: [{ isSignal: true, alias: "fileUploadText", required: false }] }], fileRecommendation: [{ type: i0.Input, args: [{ isSignal: true, alias: "fileRecommendation", required: false }] }], changeFilesText: [{ type: i0.Input, args: [{ isSignal: true, alias: "changeFilesText", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], fileSelected: [{ type: i0.Output, args: ["fileSelected"] }], fileRemoved: [{ type: i0.Output, args: ["fileRemoved"] }], fileError: [{ type: i0.Output, args: ["fileError"] }], fileWarning: [{ type: i0.Output, args: ["fileWarning"] }] } });
|
|
2151
2151
|
|
|
2152
|
-
const icons = {
|
|
2152
|
+
const icons$3 = {
|
|
2153
2153
|
'chevrons-left': LucideChevronsLeft,
|
|
2154
2154
|
'chevrons-right': LucideChevronsRight,
|
|
2155
2155
|
'chevron-left': LucideChevronLeft,
|
|
@@ -2226,15 +2226,15 @@ const icons = {
|
|
|
2226
2226
|
warehouse: LucideWarehouse,
|
|
2227
2227
|
list: LucideList,
|
|
2228
2228
|
};
|
|
2229
|
-
function getIcon(name) {
|
|
2230
|
-
return icons[name] ?? LucidePlus;
|
|
2229
|
+
function getIcon$5(name) {
|
|
2230
|
+
return icons$3[name] ?? LucidePlus;
|
|
2231
2231
|
}
|
|
2232
2232
|
class TableComponent {
|
|
2233
2233
|
constructor() {
|
|
2234
2234
|
this.fb = inject(FormBuilder);
|
|
2235
2235
|
this.cdr = inject(ChangeDetectorRef);
|
|
2236
2236
|
this.transloco = inject(TranslocoService);
|
|
2237
|
-
this.getIcon = getIcon;
|
|
2237
|
+
this.getIcon = getIcon$5;
|
|
2238
2238
|
this.actionsHeaderLabel = toSignal(this.transloco.selectTranslate('common.actions'), { initialValue: 'Acciones' });
|
|
2239
2239
|
this.data = input([], ...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
|
|
2240
2240
|
this.columns = input([], ...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
|
|
@@ -2689,7 +2689,7 @@ class TableComponent {
|
|
|
2689
2689
|
}
|
|
2690
2690
|
}
|
|
2691
2691
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: TableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2692
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: TableComponent, isStandalone: true, selector: "shk-table", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, rowsPerPage: { classPropertyName: "rowsPerPage", publicName: "rowsPerPage", isSignal: true, isRequired: false, transformFunction: null }, rowsPerPageOptions: { classPropertyName: "rowsPerPageOptions", publicName: "rowsPerPageOptions", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, showActionRow: { classPropertyName: "showActionRow", publicName: "showActionRow", isSignal: true, isRequired: false, transformFunction: null }, customTemplates: { classPropertyName: "customTemplates", publicName: "customTemplates", isSignal: true, isRequired: false, transformFunction: null }, headerActions: { classPropertyName: "headerActions", publicName: "headerActions", isSignal: true, isRequired: false, transformFunction: null }, rowActions: { classPropertyName: "rowActions", publicName: "rowActions", isSignal: true, isRequired: false, transformFunction: null }, hasShadow: { classPropertyName: "hasShadow", publicName: "hasShadow", isSignal: true, isRequired: false, transformFunction: null }, defaultSortField: { classPropertyName: "defaultSortField", publicName: "defaultSortField", isSignal: true, isRequired: false, transformFunction: null }, defaultSortOrder: { classPropertyName: "defaultSortOrder", publicName: "defaultSortOrder", isSignal: true, isRequired: false, transformFunction: null }, showSearch: { classPropertyName: "showSearch", publicName: "showSearch", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, serverSide: { classPropertyName: "serverSide", publicName: "serverSide", isSignal: true, isRequired: false, transformFunction: null }, totalRecords: { classPropertyName: "totalRecords", publicName: "totalRecords", isSignal: true, isRequired: false, transformFunction: null }, filters: { classPropertyName: "filters", publicName: "filters", isSignal: true, isRequired: false, transformFunction: null }, activeFilter: { classPropertyName: "activeFilter", publicName: "activeFilter", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { refresh: "refresh", pageChange: "pageChange", filterChange: "filterChange", searchChange: "searchChange", filterClick: "filterClick" }, ngImport: i0, template: "<div class=\"space-y-2 min-[1440px]:space-y-3 mt-2 min-[1440px]:mt-3 animate-fade-in pb-8\">\n\n @if (showSearch() || filters().length > 0 || headerActions().length > 0) {\n <div class=\"card p-2 min-[1440px]:p-2.5 flex flex-row items-center justify-between gap-2\">\n\n <div class=\"flex items-center gap-2 min-[1440px]:gap-3 flex-1 min-w-0\">\n @if (showSearch()) {\n <div class=\"relative w-full md:w-52 min-[1440px]:w-56\">\n <div class=\"absolute inset-y-0 left-0 pl-2.5 flex items-center pointer-events-none\">\n <svg [lucideIcon]=\"getIcon('search')\" class=\"w-3.5 h-3.5 _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\"></svg>\n </div>\n <input\n type=\"text\"\n [value]=\"searchQuery()\"\n (input)=\"onSearchInput($any($event.target).value)\"\n [placeholder]=\"searchPlaceholder() || ('common.search_placeholder' | transloco)\"\n class=\"block w-full pl-8 pr-3 py-1.5 text-xs border _shk-border dark:[border-color:var(--shk-surface-200)] rounded-md leading-5\n _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] placeholder:[color:var(--shk-surface-400)] dark:placeholder:[color:var(--shk-surface-500)]\n _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\n focus:outline-none focus:bg-white dark:focus:[background-color:var(--shk-surface-800)] focus:[border-color:var(--shk-primary-500)] focus:ring-1\n focus:[--tw-ring-color:var(--shk-primary-500)]\"\n />\n </div>\n }\n\n @if (filters().length > 0) {\n <div class=\"flex _shk-bg-surface-100 dark:[background-color:var(--shk-surface-100)] p-0.5 rounded-md ml-auto\">\n @for (f of filters(); track f.value) {\n <button\n type=\"button\"\n (click)=\"onFilterClick(f.value)\"\n class=\"px-2.5 min-[1440px]:px-3 py-1 text-xs font-medium rounded _shk-text-surface-700 dark:[color:var(--shk-surface-700)] transition-all\"\n [class]=\"f.value === activeFilter() ? 'bg-white shadow-sm dark:[background-color:var(--shk-surface-700)]' : ''\"\n >\n {{ f.label }}\n </button>\n }\n </div>\n }\n </div>\n\n @if (headerActions().length > 0) {\n <div class=\"flex items-center gap-1.5 shrink-0\">\n @for (action of headerActions(); track $index) {\n @if (isHeaderActionVisible(action)) {\n <button\n type=\"button\"\n [class]=\"action.class || 'inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md _shk-bg-primary text-white hover:[background-color:var(--shk-primary-700)] transition-colors disabled:opacity-50 disabled:cursor-not-allowed'\"\n [disabled]=\"isHeaderActionDisabled(action)\"\n (click)=\"action.onClick()\"\n >\n @if (action.icon) {\n <svg\n [lucideIcon]=\"getIcon(action.icon)\"\n class=\"w-3.5 h-3.5\"\n ></svg>\n }\n {{ action.label }}\n </button>\n }\n }\n </div>\n }\n\n </div>\n }\n\n <div\n class=\"card p-0 overflow-hidden\"\n [class.shadow-lg]=\"hasShadow()\"\n >\n\n <div class=\"table-scroll-wrapper _shk-scrollbar\">\n <table class=\"w-full\">\n <thead>\n <tr>\n @for (col of columnsWithActions(); track col.field) {\n <th\n (click)=\"col.field !== 'actions' && col.sortable && toggleSort(col.field)\"\n [style.cursor]=\"col.field !== 'actions' && col.sortable ? 'pointer' : 'default'\"\n [style.width]=\"col.width || 'auto'\"\n [style.min-width]=\"col.field === 'actions' ? '130px' : 'auto'\"\n class=\"px-2 min-[1440px]:px-3 py-2 min-[1440px]:py-2.5 text-left text-[10px] min-[1440px]:text-xs font-bold _shk-text-surface-500 dark:[color:var(--shk-surface-400)] uppercase tracking-wider\n _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] border-b _shk-border dark:[border-color:var(--shk-surface-200)]\"\n >\n @if (col.field !== 'actions') {\n <div class=\"flex items-center justify-between gap-2\">\n <span>{{ col.header }}</span>\n <div class=\"flex items-center gap-1\">\n @if (col.sortable) {\n <div class=\"relative group\">\n @if (sortField() === col.field) {\n <svg [lucideIcon]=\"getIcon(sortOrder() === 1 ? 'arrow-up' : 'arrow-down')\"\n class=\"w-3.5 h-3.5 _shk-text-primary\"></svg>\n } @else {\n <svg [lucideIcon]=\"getIcon('arrow-up-down')\"\n class=\"w-3.5 h-3.5 _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\"></svg>\n }\n <span class=\"absolute top-full left-1/2 -translate-x-1/2 mt-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ 'table.tooltips.sort' | transloco }}\n </span>\n </div>\n }\n @if (col.filter) {\n <div class=\"relative group\">\n <button\n type=\"button\"\n (click)=\"$event.stopPropagation(); toggleFilter(col.field)\"\n class=\"_shk-text-surface-400 dark:[color:var(--shk-surface-500)] hover:[color:var(--shk-surface-600)] dark:hover:[color:var(--shk-surface-300)] transition-colors\"\n >\n <svg\n [lucideIcon]=\"getIcon('filter')\"\n class=\"w-3.5 h-3.5\"\n [class._shk-text-primary]=\"columnFiltersForm.get(col.field)?.value\"\n ></svg>\n <span class=\"absolute top-full left-1/2 -translate-x-1/2 mt-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ 'table.tooltips.filter' | transloco }}\n </span>\n </button>\n </div>\n }\n </div>\n </div>\n\n @if (col.filter && showFilterInput()[col.field]) {\n <div\n class=\"mt-2\"\n [formGroup]=\"columnFiltersForm\"\n (click)=\"$event.stopPropagation()\"\n >\n <div class=\"relative\">\n @if (col.filterType !== 'select') {\n <input\n type=\"text\"\n [formControlName]=\"col.field\"\n class=\"w-full px-3 py-1.5 text-sm rounded-md border _shk-border dark:[border-color:var(--shk-surface-200)] bg-white dark:[background-color:var(--shk-surface-100)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\n focus:[border-color:var(--shk-primary-500)] focus:ring-1 focus:[--tw-ring-color:var(--shk-primary-500)]\n placeholder:[color:var(--shk-surface-400)] dark:placeholder:[color:var(--shk-surface-500)]\"\n [placeholder]=\"col.filterPlaceholder || ('common.search_placeholder' | transloco)\"\n />\n }\n @if (col.filterType === 'select') {\n <select\n [formControlName]=\"col.field\"\n class=\"w-full px-2 py-1 text-xs rounded-md border _shk-border dark:[border-color:var(--shk-surface-200)] bg-white dark:[background-color:var(--shk-surface-100)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)] focus:[border-color:var(--shk-primary-500)] focus:ring-1 focus:[--tw-ring-color:var(--shk-primary-500)] appearance-none\"\n >\n <option [ngValue]=\"null\">A/D</option>\n @for (opt of col.filterOptions || []; track opt.value) {\n <option [ngValue]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n }\n @if (columnFiltersForm.get(col.field)?.value && col.filterType !== 'select') {\n <button\n type=\"button\"\n class=\"absolute right-2 top-1/2 -translate-y-1/2 _shk-text-surface-400 dark:[color:var(--shk-surface-500)] hover:[color:var(--shk-surface-600)] dark:hover:[color:var(--shk-surface-300)]\"\n (click)=\"clearFilter(col.field)\"\n >\n <svg [lucideIcon]=\"getIcon('x')\" class=\"w-3.5 h-3.5\"></svg>\n </button>\n }\n </div>\n </div>\n }\n } @else {\n <div class=\"flex items-center justify-center\">\n <span>{{ col.header }}</span>\n </div>\n }\n </th>\n }\n </tr>\n </thead>\n\n @if (loading()) {\n <tbody class=\"border-b _shk-border dark:[border-color:var(--shk-surface-100)]\">\n <tr>\n <td [attr.colspan]=\"columnsWithActions().length\" class=\"text-center py-12\">\n <div class=\"flex items-center justify-center\">\n <svg [lucideIcon]=\"getIcon('loader')\" class=\"w-6 h-6 animate-spin _shk-text-primary\"></svg>\n </div>\n </td>\n </tr>\n </tbody>\n } @else if (effectiveDisplayedData().length === 0) {\n <tbody class=\"border-b _shk-border dark:[border-color:var(--shk-surface-100)]\">\n <tr>\n <td [attr.colspan]=\"columnsWithActions().length\" class=\"text-center py-12\">\n <div class=\"flex flex-col items-center\">\n <div class=\"w-16 h-16 _shk-bg-surface-100 dark:[background-color:var(--shk-surface-100)] rounded-full flex items-center justify-center mb-4\">\n <svg [lucideIcon]=\"getIcon('inbox')\" class=\"w-8 h-8 _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\"></svg>\n </div>\n <p class=\"text-lg font-semibold _shk-text-surface-600 dark:[color:var(--shk-surface-300)]\">\n {{ emptyMessage() || ('common.no_records' | transloco) }}\n </p>\n </div>\n </td>\n </tr>\n </tbody>\n } @else {\n <tbody>\n @for (rowData of effectiveDisplayedData(); track $index) {\n <tr class=\"hover:[background-color:color-mix(in srgb,var(--shk-primary-50)30%,transparent)] dark:hover:[background-color:color-mix(in srgb,var(--shk-primary-900)10%,transparent)] transition-colors duration-200 border-b _shk-border dark:[border-color:var(--shk-surface-100)]\">\n @for (col of columnsWithActions(); track col.field) {\n <td\n class=\"px-2 min-[1440px]:px-3 py-2 min-[1440px]:py-2.5 text-xs font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-700)] whitespace-nowrap\"\n [style.overflow]=\"col.field === 'actions' ? 'visible' : 'hidden'\"\n [style.text-overflow]=\"col.field === 'actions' ? 'clip' : 'ellipsis'\"\n >\n @if (col.field !== 'actions') {\n @if (col.template === 'tag') {\n <span\n class=\"inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium\"\n [class]=\"getTagClass(col.tagSeverity ? col.tagSeverity(rowData) : undefined)\"\n [style]=\"col.tagStyle ? col.tagStyle(rowData) : undefined\"\n >\n {{ col.tagValue ? col.tagValue(rowData) : rowData[col.field] }}\n </span>\n } @else if (col.format) {\n <span>{{ col.format(rowData) }}</span>\n } @else {\n <ng-container\n *ngTemplateOutlet=\"\n customTemplates()[col.field] || defaultTemplate;\n context: { $implicit: rowData, field: col.field }\n \"\n ></ng-container>\n }\n } @else {\n <div class=\"flex items-center justify-start gap-px\">\n @for (action of rowActions(); track $index) {\n @if (isRowActionVisible(action, rowData)) {\n <div class=\"relative group\">\n <button\n type=\"button\"\n (click)=\"action.onClick(rowData)\"\n [class]=\"'table-action-btn hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] rounded-md ' + getRowActionClass(action, rowData)\"\n [disabled]=\"isRowActionDisabled(action, rowData) || false\"\n >\n <svg\n [lucideIcon]=\"getIcon(getRowActionIconName(action, rowData))\"\n class=\"w-4 h-4\"\n ></svg>\n </button>\n <span class=\"absolute bottom-full left-1/2 -translate-x-1/2 mb-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ getRowActionLabel(action, rowData) }}\n </span>\n </div>\n }\n }\n </div>\n }\n </td>\n }\n </tr>\n }\n </tbody>\n }\n </table>\n\n <ng-template #defaultTemplate let-rowData let-field=\"field\">\n {{ truncate(rowData[field], 30) }}\n </ng-template>\n </div>\n\n <div class=\"flex items-center justify-between gap-4 px-2 min-[1440px]:px-3 py-2 border-t _shk-border dark:[border-color:var(--shk-surface-100)]\">\n <div class=\"text-xs _shk-text-surface-600 dark:[color:var(--shk-surface-400)]\">{{ getPageReport() }}</div>\n <div class=\"flex items-center gap-0.5\">\n <button\n type=\"button\"\n (click)=\"goToFirst()\"\n [disabled]=\"isFirstPage()\"\n class=\"p-1 _shk-text-surface-500 hover:[color:var(--shk-surface-700)] dark:[color:var(--shk-surface-400)] dark:hover:[color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed rounded transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('chevrons-left')\" class=\"w-4 h-4\"></svg>\n </button>\n <button\n type=\"button\"\n (click)=\"prev()\"\n [disabled]=\"isFirstPage()\"\n class=\"p-1 _shk-text-surface-500 hover:[color:var(--shk-surface-700)] dark:[color:var(--shk-surface-400)] dark:hover:[color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed rounded transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('chevron-left')\" class=\"w-4 h-4\"></svg>\n </button>\n <span class=\"px-2 text-xs font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\">{{ currentPage() }} / {{ totalPages() }}</span>\n <button\n type=\"button\"\n (click)=\"next()\"\n [disabled]=\"isLastPage()\"\n class=\"p-1 _shk-text-surface-500 hover:[color:var(--shk-surface-700)] dark:[color:var(--shk-surface-400)] dark:hover:[color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed rounded transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('chevron-right')\" class=\"w-4 h-4\"></svg>\n </button>\n <button\n type=\"button\"\n (click)=\"goToLast()\"\n [disabled]=\"isLastPage()\"\n class=\"p-1 _shk-text-surface-500 hover:[color:var(--shk-surface-700)] dark:[color:var(--shk-surface-400)] dark:hover:[color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed rounded transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('chevrons-right')\" class=\"w-4 h-4\"></svg>\n </button>\n </div>\n <div class=\"flex items-center gap-1.5 text-xs _shk-text-surface-600 dark:[color:var(--shk-surface-400)]\">\n <span>{{ 'table.rows' | transloco }}</span>\n <select\n [value]=\"rowsPerPageLocal()\"\n (change)=\"onRowsPerPageChange($any($event.target).value)\"\n class=\"border _shk-border dark:[border-color:var(--shk-surface-200)] rounded px-2 py-1 text-xs bg-white dark:[background-color:var(--shk-surface-100)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)] focus:outline-none focus:[border-color:var(--shk-primary-500)]\"\n >\n @for (opt of rowsPerPageOptions(); track opt) {\n <option [value]=\"opt\">{{ opt }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n\n</div>\n", styles: ["input:focus{outline:none}input[type=text]{font-weight:400!important}table th{white-space:nowrap}table td{white-space:nowrap;text-overflow:ellipsis}td button svg{width:1.125rem!important;height:1.125rem!important}td button:disabled{opacity:.4;cursor:not-allowed}.table-action-btn svg{width:1rem!important;height:1rem!important;min-width:1rem!important;min-height:1rem!important}.table-action-btn{padding:.5rem!important;min-width:2rem!important;min-height:2rem!important;display:inline-flex!important;align-items:center!important;justify-content:center!important}.table-scroll-wrapper{width:100%}.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 }); }
|
|
2692
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: TableComponent, isStandalone: true, selector: "shk-table", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, rowsPerPage: { classPropertyName: "rowsPerPage", publicName: "rowsPerPage", isSignal: true, isRequired: false, transformFunction: null }, rowsPerPageOptions: { classPropertyName: "rowsPerPageOptions", publicName: "rowsPerPageOptions", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, showActionRow: { classPropertyName: "showActionRow", publicName: "showActionRow", isSignal: true, isRequired: false, transformFunction: null }, customTemplates: { classPropertyName: "customTemplates", publicName: "customTemplates", isSignal: true, isRequired: false, transformFunction: null }, headerActions: { classPropertyName: "headerActions", publicName: "headerActions", isSignal: true, isRequired: false, transformFunction: null }, rowActions: { classPropertyName: "rowActions", publicName: "rowActions", isSignal: true, isRequired: false, transformFunction: null }, hasShadow: { classPropertyName: "hasShadow", publicName: "hasShadow", isSignal: true, isRequired: false, transformFunction: null }, defaultSortField: { classPropertyName: "defaultSortField", publicName: "defaultSortField", isSignal: true, isRequired: false, transformFunction: null }, defaultSortOrder: { classPropertyName: "defaultSortOrder", publicName: "defaultSortOrder", isSignal: true, isRequired: false, transformFunction: null }, showSearch: { classPropertyName: "showSearch", publicName: "showSearch", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, serverSide: { classPropertyName: "serverSide", publicName: "serverSide", isSignal: true, isRequired: false, transformFunction: null }, totalRecords: { classPropertyName: "totalRecords", publicName: "totalRecords", isSignal: true, isRequired: false, transformFunction: null }, filters: { classPropertyName: "filters", publicName: "filters", isSignal: true, isRequired: false, transformFunction: null }, activeFilter: { classPropertyName: "activeFilter", publicName: "activeFilter", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { refresh: "refresh", pageChange: "pageChange", filterChange: "filterChange", searchChange: "searchChange", filterClick: "filterClick" }, ngImport: i0, template: "<div class=\"space-y-2 min-[1440px]:space-y-3 mt-2 min-[1440px]:mt-3 animate-fade-in pb-8\">\n\n @if (showSearch() || filters().length > 0 || headerActions().length > 0) {\n <div class=\"card p-2 min-[1440px]:p-2.5 flex flex-row items-center justify-between gap-2\">\n\n <div class=\"flex items-center gap-2 min-[1440px]:gap-3 flex-1 min-w-0\">\n @if (showSearch()) {\n <div class=\"relative w-full md:w-52 min-[1440px]:w-56\">\n <div class=\"absolute inset-y-0 left-0 pl-2.5 flex items-center pointer-events-none\">\n <svg [lucideIcon]=\"getIcon('search')\" class=\"w-3.5 h-3.5 _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\"></svg>\n </div>\n <input\n type=\"text\"\n [value]=\"searchQuery()\"\n (input)=\"onSearchInput($any($event.target).value)\"\n [placeholder]=\"searchPlaceholder() || ('common.search_placeholder' | transloco)\"\n class=\"block w-full pl-8 pr-3 py-1.5 text-xs border _shk-border dark:[border-color:var(--shk-surface-200)] rounded-md leading-5\n _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] placeholder:[color:var(--shk-surface-400)] dark:placeholder:[color:var(--shk-surface-500)]\n _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\n focus:outline-none focus:bg-white dark:focus:[background-color:var(--shk-surface-800)] focus:[border-color:var(--shk-primary-500)] focus:ring-1\n focus:[--tw-ring-color:var(--shk-primary-500)]\"\n />\n </div>\n }\n\n @if (filters().length > 0) {\n <div class=\"flex _shk-bg-surface-100 dark:[background-color:var(--shk-surface-100)] p-0.5 rounded-md ml-auto\">\n @for (f of filters(); track f.value) {\n <button\n type=\"button\"\n (click)=\"onFilterClick(f.value)\"\n class=\"px-2.5 min-[1440px]:px-3 py-1 text-xs font-medium rounded _shk-text-surface-700 dark:[color:var(--shk-surface-700)] transition-all\"\n [class]=\"f.value === activeFilter() ? 'bg-white shadow-sm dark:[background-color:var(--shk-surface-700)]' : ''\"\n >\n {{ f.label }}\n </button>\n }\n </div>\n }\n </div>\n\n @if (headerActions().length > 0) {\n <div class=\"flex items-center gap-1.5 shrink-0\">\n @for (action of headerActions(); track $index) {\n @if (isHeaderActionVisible(action)) {\n <button\n type=\"button\"\n [class]=\"action.class || 'inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md _shk-bg-primary text-white hover:[background-color:var(--shk-primary-700)] transition-colors disabled:opacity-50 disabled:cursor-not-allowed'\"\n [disabled]=\"isHeaderActionDisabled(action)\"\n (click)=\"action.onClick()\"\n >\n @if (action.icon) {\n <svg\n [lucideIcon]=\"getIcon(action.icon)\"\n class=\"w-3.5 h-3.5\"\n ></svg>\n }\n {{ action.label }}\n </button>\n }\n }\n </div>\n }\n\n </div>\n }\n\n <div\n class=\"card p-0 overflow-hidden\"\n [class.shadow-lg]=\"hasShadow()\"\n >\n\n <div class=\"table-scroll-wrapper _shk-scrollbar\">\n <table class=\"w-full\">\n <thead>\n <tr>\n @for (col of columnsWithActions(); track col.field) {\n <th\n (click)=\"col.field !== 'actions' && col.sortable && toggleSort(col.field)\"\n [style.cursor]=\"col.field !== 'actions' && col.sortable ? 'pointer' : 'default'\"\n [style.width]=\"col.width || 'auto'\"\n [style.min-width]=\"col.field === 'actions' ? '130px' : 'auto'\"\n class=\"px-2 min-[1440px]:px-3 py-2 min-[1440px]:py-2.5 text-left text-[10px] min-[1440px]:text-xs font-bold _shk-text-surface-500 dark:[color:var(--shk-surface-400)] uppercase tracking-wider\n _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] border-b _shk-border dark:[border-color:var(--shk-surface-200)]\"\n >\n @if (col.field !== 'actions') {\n <div class=\"flex items-center justify-between gap-2\">\n <span>{{ col.header }}</span>\n <div class=\"flex items-center gap-1\">\n @if (col.sortable) {\n <div class=\"relative group\">\n @if (sortField() === col.field) {\n <svg [lucideIcon]=\"getIcon(sortOrder() === 1 ? 'arrow-up' : 'arrow-down')\"\n class=\"w-3.5 h-3.5 _shk-text-primary\"></svg>\n } @else {\n <svg [lucideIcon]=\"getIcon('arrow-up-down')\"\n class=\"w-3.5 h-3.5 _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\"></svg>\n }\n <span class=\"absolute top-full left-1/2 -translate-x-1/2 mt-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ 'table.tooltips.sort' | transloco }}\n </span>\n </div>\n }\n @if (col.filter) {\n <div class=\"relative group\">\n <button\n type=\"button\"\n (click)=\"$event.stopPropagation(); toggleFilter(col.field)\"\n class=\"_shk-text-surface-400 dark:[color:var(--shk-surface-500)] hover:[color:var(--shk-surface-600)] dark:hover:[color:var(--shk-surface-300)] transition-colors\"\n >\n <svg\n [lucideIcon]=\"getIcon('filter')\"\n class=\"w-3.5 h-3.5\"\n [class._shk-text-primary]=\"columnFiltersForm.get(col.field)?.value\"\n ></svg>\n <span class=\"absolute top-full left-1/2 -translate-x-1/2 mt-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ 'table.tooltips.filter' | transloco }}\n </span>\n </button>\n </div>\n }\n </div>\n </div>\n\n @if (col.filter && showFilterInput()[col.field]) {\n <div\n class=\"mt-2\"\n [formGroup]=\"columnFiltersForm\"\n (click)=\"$event.stopPropagation()\"\n >\n <div class=\"relative\">\n @if (col.filterType !== 'select') {\n <input\n type=\"text\"\n [formControlName]=\"col.field\"\n class=\"w-full px-3 py-1.5 text-sm rounded-md border _shk-border dark:[border-color:var(--shk-surface-200)] bg-white dark:[background-color:var(--shk-surface-100)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\n focus:[border-color:var(--shk-primary-500)] focus:ring-1 focus:[--tw-ring-color:var(--shk-primary-500)]\n placeholder:[color:var(--shk-surface-400)] dark:placeholder:[color:var(--shk-surface-500)]\"\n [placeholder]=\"col.filterPlaceholder || ('common.search_placeholder' | transloco)\"\n />\n }\n @if (col.filterType === 'select') {\n <select\n [formControlName]=\"col.field\"\n class=\"w-full px-2 py-1 text-xs rounded-md border _shk-border dark:[border-color:var(--shk-surface-200)] bg-white dark:[background-color:var(--shk-surface-100)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)] focus:[border-color:var(--shk-primary-500)] focus:ring-1 focus:[--tw-ring-color:var(--shk-primary-500)] appearance-none\"\n >\n <option [ngValue]=\"null\">A/D</option>\n @for (opt of col.filterOptions || []; track opt.value) {\n <option [ngValue]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n }\n @if (columnFiltersForm.get(col.field)?.value && col.filterType !== 'select') {\n <button\n type=\"button\"\n class=\"absolute right-2 top-1/2 -translate-y-1/2 _shk-text-surface-400 dark:[color:var(--shk-surface-500)] hover:[color:var(--shk-surface-600)] dark:hover:[color:var(--shk-surface-300)]\"\n (click)=\"clearFilter(col.field)\"\n >\n <svg [lucideIcon]=\"getIcon('x')\" class=\"w-3.5 h-3.5\"></svg>\n </button>\n }\n </div>\n </div>\n }\n } @else {\n <div class=\"flex items-center justify-center\">\n <span>{{ col.header }}</span>\n </div>\n }\n </th>\n }\n </tr>\n </thead>\n\n @if (loading()) {\n <tbody class=\"border-b _shk-border dark:[border-color:var(--shk-surface-100)]\">\n <tr>\n <td [attr.colspan]=\"columnsWithActions().length\" class=\"text-center py-12\">\n <div class=\"flex items-center justify-center\">\n <svg [lucideIcon]=\"getIcon('loader')\" class=\"w-6 h-6 animate-spin _shk-text-primary\"></svg>\n </div>\n </td>\n </tr>\n </tbody>\n } @else if (effectiveDisplayedData().length === 0) {\n <tbody class=\"border-b _shk-border dark:[border-color:var(--shk-surface-100)]\">\n <tr>\n <td [attr.colspan]=\"columnsWithActions().length\" class=\"text-center py-12\">\n <div class=\"flex flex-col items-center\">\n <div class=\"w-16 h-16 _shk-bg-surface-100 dark:[background-color:var(--shk-surface-100)] rounded-full flex items-center justify-center mb-4\">\n <svg [lucideIcon]=\"getIcon('inbox')\" class=\"w-8 h-8 _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\"></svg>\n </div>\n <p class=\"text-lg font-semibold _shk-text-surface-600 dark:[color:var(--shk-surface-300)]\">\n {{ emptyMessage() || ('common.no_records' | transloco) }}\n </p>\n </div>\n </td>\n </tr>\n </tbody>\n } @else {\n <tbody>\n @for (rowData of effectiveDisplayedData(); track $index) {\n <tr class=\"hover:[background-color:color-mix(in srgb,var(--shk-primary-50)30%,transparent)] dark:hover:[background-color:color-mix(in srgb,var(--shk-primary-900)10%,transparent)] transition-colors duration-200 border-b _shk-border dark:[border-color:var(--shk-surface-100)]\">\n @for (col of columnsWithActions(); track col.field) {\n <td\n class=\"px-2 min-[1440px]:px-3 py-2 min-[1440px]:py-2.5 text-xs font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-700)] whitespace-nowrap\"\n [style.overflow]=\"col.field === 'actions' ? 'visible' : 'hidden'\"\n [style.text-overflow]=\"col.field === 'actions' ? 'clip' : 'ellipsis'\"\n >\n @if (col.field !== 'actions') {\n @if (col.template === 'tag') {\n <span\n class=\"inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium\"\n [class]=\"getTagClass(col.tagSeverity ? col.tagSeverity(rowData) : undefined)\"\n [style]=\"col.tagStyle ? col.tagStyle(rowData) : undefined\"\n >\n {{ col.tagValue ? col.tagValue(rowData) : rowData[col.field] }}\n </span>\n } @else if (col.format) {\n <span>{{ col.format(rowData) }}</span>\n } @else {\n <ng-container\n *ngTemplateOutlet=\"\n customTemplates()[col.field] || defaultTemplate;\n context: { $implicit: rowData, field: col.field }\n \"\n ></ng-container>\n }\n } @else {\n <div class=\"flex items-center justify-start gap-px\">\n @for (action of rowActions(); track $index) {\n @if (isRowActionVisible(action, rowData)) {\n <div class=\"relative group\">\n <button\n type=\"button\"\n (click)=\"action.onClick(rowData)\"\n [class]=\"'table-action-btn hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] rounded-md ' + getRowActionClass(action, rowData)\"\n [disabled]=\"isRowActionDisabled(action, rowData) || false\"\n >\n <svg\n [lucideIcon]=\"getIcon(getRowActionIconName(action, rowData))\"\n class=\"w-4 h-4\"\n ></svg>\n </button>\n <span class=\"absolute bottom-full left-1/2 -translate-x-1/2 mb-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ getRowActionLabel(action, rowData) }}\n </span>\n </div>\n }\n }\n </div>\n }\n </td>\n }\n </tr>\n }\n </tbody>\n }\n </table>\n\n <ng-template #defaultTemplate let-rowData let-field=\"field\">\n {{ truncate(rowData[field], 30) }}\n </ng-template>\n </div>\n\n <div class=\"flex items-center justify-between gap-4 px-2 min-[1440px]:px-3 py-2 border-t _shk-border dark:[border-color:var(--shk-surface-100)]\">\n <div class=\"text-xs _shk-text-surface-600 dark:[color:var(--shk-surface-400)]\">{{ getPageReport() }}</div>\n <div class=\"flex items-center gap-0.5\">\n <button\n type=\"button\"\n (click)=\"goToFirst()\"\n [disabled]=\"isFirstPage()\"\n class=\"p-1 _shk-text-surface-500 hover:[color:var(--shk-surface-700)] dark:[color:var(--shk-surface-400)] dark:hover:[color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed rounded transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('chevrons-left')\" class=\"w-4 h-4\"></svg>\n </button>\n <button\n type=\"button\"\n (click)=\"prev()\"\n [disabled]=\"isFirstPage()\"\n class=\"p-1 _shk-text-surface-500 hover:[color:var(--shk-surface-700)] dark:[color:var(--shk-surface-400)] dark:hover:[color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed rounded transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('chevron-left')\" class=\"w-4 h-4\"></svg>\n </button>\n <span class=\"px-2 text-xs font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\">{{ currentPage() }} / {{ totalPages() }}</span>\n <button\n type=\"button\"\n (click)=\"next()\"\n [disabled]=\"isLastPage()\"\n class=\"p-1 _shk-text-surface-500 hover:[color:var(--shk-surface-700)] dark:[color:var(--shk-surface-400)] dark:hover:[color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed rounded transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('chevron-right')\" class=\"w-4 h-4\"></svg>\n </button>\n <button\n type=\"button\"\n (click)=\"goToLast()\"\n [disabled]=\"isLastPage()\"\n class=\"p-1 _shk-text-surface-500 hover:[color:var(--shk-surface-700)] dark:[color:var(--shk-surface-400)] dark:hover:[color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed rounded transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('chevrons-right')\" class=\"w-4 h-4\"></svg>\n </button>\n </div>\n <div class=\"flex items-center gap-1.5 text-xs _shk-text-surface-600 dark:[color:var(--shk-surface-400)]\">\n <span>{{ 'table.rows' | transloco }}</span>\n <select\n [value]=\"rowsPerPageLocal()\"\n (change)=\"onRowsPerPageChange($any($event.target).value)\"\n class=\"border _shk-border dark:[border-color:var(--shk-surface-200)] rounded px-2 py-1 text-xs bg-white dark:[background-color:var(--shk-surface-100)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)] focus:outline-none focus:[border-color:var(--shk-primary-500)]\"\n >\n @for (opt of rowsPerPageOptions(); track opt) {\n <option [value]=\"opt\">{{ opt }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n\n</div>\n", styles: ["input:focus{outline:none}input[type=text]{font-weight:400!important}table th{white-space:nowrap}table td{white-space:nowrap;text-overflow:ellipsis}td button svg{width:1.125rem!important;height:1.125rem!important}td button:disabled{opacity:.4;cursor:not-allowed}.table-action-btn svg{width:1rem!important;height:1rem!important;min-width:1rem!important;min-height:1rem!important}.table-action-btn{padding:.5rem!important;min-width:2rem!important;min-height:2rem!important;display:inline-flex!important;align-items:center!important;justify-content:center!important}.table-scroll-wrapper{width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-scroll-wrapper table{table-layout:fixed;min-width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: TranslocoModule }, { kind: "component", type: LucideDynamicIcon, selector: "svg[lucideIcon]", inputs: ["lucideIcon"] }, { kind: "pipe", type: i1$1.TranslocoPipe, name: "transloco" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
2693
2693
|
}
|
|
2694
2694
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: TableComponent, decorators: [{
|
|
2695
2695
|
type: Component,
|
|
@@ -2698,7 +2698,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImpo
|
|
|
2698
2698
|
ReactiveFormsModule,
|
|
2699
2699
|
TranslocoModule,
|
|
2700
2700
|
LucideDynamicIcon,
|
|
2701
|
-
], template: "<div class=\"space-y-2 min-[1440px]:space-y-3 mt-2 min-[1440px]:mt-3 animate-fade-in pb-8\">\n\n @if (showSearch() || filters().length > 0 || headerActions().length > 0) {\n <div class=\"card p-2 min-[1440px]:p-2.5 flex flex-row items-center justify-between gap-2\">\n\n <div class=\"flex items-center gap-2 min-[1440px]:gap-3 flex-1 min-w-0\">\n @if (showSearch()) {\n <div class=\"relative w-full md:w-52 min-[1440px]:w-56\">\n <div class=\"absolute inset-y-0 left-0 pl-2.5 flex items-center pointer-events-none\">\n <svg [lucideIcon]=\"getIcon('search')\" class=\"w-3.5 h-3.5 _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\"></svg>\n </div>\n <input\n type=\"text\"\n [value]=\"searchQuery()\"\n (input)=\"onSearchInput($any($event.target).value)\"\n [placeholder]=\"searchPlaceholder() || ('common.search_placeholder' | transloco)\"\n class=\"block w-full pl-8 pr-3 py-1.5 text-xs border _shk-border dark:[border-color:var(--shk-surface-200)] rounded-md leading-5\n _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] placeholder:[color:var(--shk-surface-400)] dark:placeholder:[color:var(--shk-surface-500)]\n _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\n focus:outline-none focus:bg-white dark:focus:[background-color:var(--shk-surface-800)] focus:[border-color:var(--shk-primary-500)] focus:ring-1\n focus:[--tw-ring-color:var(--shk-primary-500)]\"\n />\n </div>\n }\n\n @if (filters().length > 0) {\n <div class=\"flex _shk-bg-surface-100 dark:[background-color:var(--shk-surface-100)] p-0.5 rounded-md ml-auto\">\n @for (f of filters(); track f.value) {\n <button\n type=\"button\"\n (click)=\"onFilterClick(f.value)\"\n class=\"px-2.5 min-[1440px]:px-3 py-1 text-xs font-medium rounded _shk-text-surface-700 dark:[color:var(--shk-surface-700)] transition-all\"\n [class]=\"f.value === activeFilter() ? 'bg-white shadow-sm dark:[background-color:var(--shk-surface-700)]' : ''\"\n >\n {{ f.label }}\n </button>\n }\n </div>\n }\n </div>\n\n @if (headerActions().length > 0) {\n <div class=\"flex items-center gap-1.5 shrink-0\">\n @for (action of headerActions(); track $index) {\n @if (isHeaderActionVisible(action)) {\n <button\n type=\"button\"\n [class]=\"action.class || 'inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md _shk-bg-primary text-white hover:[background-color:var(--shk-primary-700)] transition-colors disabled:opacity-50 disabled:cursor-not-allowed'\"\n [disabled]=\"isHeaderActionDisabled(action)\"\n (click)=\"action.onClick()\"\n >\n @if (action.icon) {\n <svg\n [lucideIcon]=\"getIcon(action.icon)\"\n class=\"w-3.5 h-3.5\"\n ></svg>\n }\n {{ action.label }}\n </button>\n }\n }\n </div>\n }\n\n </div>\n }\n\n <div\n class=\"card p-0 overflow-hidden\"\n [class.shadow-lg]=\"hasShadow()\"\n >\n\n <div class=\"table-scroll-wrapper _shk-scrollbar\">\n <table class=\"w-full\">\n <thead>\n <tr>\n @for (col of columnsWithActions(); track col.field) {\n <th\n (click)=\"col.field !== 'actions' && col.sortable && toggleSort(col.field)\"\n [style.cursor]=\"col.field !== 'actions' && col.sortable ? 'pointer' : 'default'\"\n [style.width]=\"col.width || 'auto'\"\n [style.min-width]=\"col.field === 'actions' ? '130px' : 'auto'\"\n class=\"px-2 min-[1440px]:px-3 py-2 min-[1440px]:py-2.5 text-left text-[10px] min-[1440px]:text-xs font-bold _shk-text-surface-500 dark:[color:var(--shk-surface-400)] uppercase tracking-wider\n _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] border-b _shk-border dark:[border-color:var(--shk-surface-200)]\"\n >\n @if (col.field !== 'actions') {\n <div class=\"flex items-center justify-between gap-2\">\n <span>{{ col.header }}</span>\n <div class=\"flex items-center gap-1\">\n @if (col.sortable) {\n <div class=\"relative group\">\n @if (sortField() === col.field) {\n <svg [lucideIcon]=\"getIcon(sortOrder() === 1 ? 'arrow-up' : 'arrow-down')\"\n class=\"w-3.5 h-3.5 _shk-text-primary\"></svg>\n } @else {\n <svg [lucideIcon]=\"getIcon('arrow-up-down')\"\n class=\"w-3.5 h-3.5 _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\"></svg>\n }\n <span class=\"absolute top-full left-1/2 -translate-x-1/2 mt-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ 'table.tooltips.sort' | transloco }}\n </span>\n </div>\n }\n @if (col.filter) {\n <div class=\"relative group\">\n <button\n type=\"button\"\n (click)=\"$event.stopPropagation(); toggleFilter(col.field)\"\n class=\"_shk-text-surface-400 dark:[color:var(--shk-surface-500)] hover:[color:var(--shk-surface-600)] dark:hover:[color:var(--shk-surface-300)] transition-colors\"\n >\n <svg\n [lucideIcon]=\"getIcon('filter')\"\n class=\"w-3.5 h-3.5\"\n [class._shk-text-primary]=\"columnFiltersForm.get(col.field)?.value\"\n ></svg>\n <span class=\"absolute top-full left-1/2 -translate-x-1/2 mt-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ 'table.tooltips.filter' | transloco }}\n </span>\n </button>\n </div>\n }\n </div>\n </div>\n\n @if (col.filter && showFilterInput()[col.field]) {\n <div\n class=\"mt-2\"\n [formGroup]=\"columnFiltersForm\"\n (click)=\"$event.stopPropagation()\"\n >\n <div class=\"relative\">\n @if (col.filterType !== 'select') {\n <input\n type=\"text\"\n [formControlName]=\"col.field\"\n class=\"w-full px-3 py-1.5 text-sm rounded-md border _shk-border dark:[border-color:var(--shk-surface-200)] bg-white dark:[background-color:var(--shk-surface-100)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\n focus:[border-color:var(--shk-primary-500)] focus:ring-1 focus:[--tw-ring-color:var(--shk-primary-500)]\n placeholder:[color:var(--shk-surface-400)] dark:placeholder:[color:var(--shk-surface-500)]\"\n [placeholder]=\"col.filterPlaceholder || ('common.search_placeholder' | transloco)\"\n />\n }\n @if (col.filterType === 'select') {\n <select\n [formControlName]=\"col.field\"\n class=\"w-full px-2 py-1 text-xs rounded-md border _shk-border dark:[border-color:var(--shk-surface-200)] bg-white dark:[background-color:var(--shk-surface-100)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)] focus:[border-color:var(--shk-primary-500)] focus:ring-1 focus:[--tw-ring-color:var(--shk-primary-500)] appearance-none\"\n >\n <option [ngValue]=\"null\">A/D</option>\n @for (opt of col.filterOptions || []; track opt.value) {\n <option [ngValue]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n }\n @if (columnFiltersForm.get(col.field)?.value && col.filterType !== 'select') {\n <button\n type=\"button\"\n class=\"absolute right-2 top-1/2 -translate-y-1/2 _shk-text-surface-400 dark:[color:var(--shk-surface-500)] hover:[color:var(--shk-surface-600)] dark:hover:[color:var(--shk-surface-300)]\"\n (click)=\"clearFilter(col.field)\"\n >\n <svg [lucideIcon]=\"getIcon('x')\" class=\"w-3.5 h-3.5\"></svg>\n </button>\n }\n </div>\n </div>\n }\n } @else {\n <div class=\"flex items-center justify-center\">\n <span>{{ col.header }}</span>\n </div>\n }\n </th>\n }\n </tr>\n </thead>\n\n @if (loading()) {\n <tbody class=\"border-b _shk-border dark:[border-color:var(--shk-surface-100)]\">\n <tr>\n <td [attr.colspan]=\"columnsWithActions().length\" class=\"text-center py-12\">\n <div class=\"flex items-center justify-center\">\n <svg [lucideIcon]=\"getIcon('loader')\" class=\"w-6 h-6 animate-spin _shk-text-primary\"></svg>\n </div>\n </td>\n </tr>\n </tbody>\n } @else if (effectiveDisplayedData().length === 0) {\n <tbody class=\"border-b _shk-border dark:[border-color:var(--shk-surface-100)]\">\n <tr>\n <td [attr.colspan]=\"columnsWithActions().length\" class=\"text-center py-12\">\n <div class=\"flex flex-col items-center\">\n <div class=\"w-16 h-16 _shk-bg-surface-100 dark:[background-color:var(--shk-surface-100)] rounded-full flex items-center justify-center mb-4\">\n <svg [lucideIcon]=\"getIcon('inbox')\" class=\"w-8 h-8 _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\"></svg>\n </div>\n <p class=\"text-lg font-semibold _shk-text-surface-600 dark:[color:var(--shk-surface-300)]\">\n {{ emptyMessage() || ('common.no_records' | transloco) }}\n </p>\n </div>\n </td>\n </tr>\n </tbody>\n } @else {\n <tbody>\n @for (rowData of effectiveDisplayedData(); track $index) {\n <tr class=\"hover:[background-color:color-mix(in srgb,var(--shk-primary-50)30%,transparent)] dark:hover:[background-color:color-mix(in srgb,var(--shk-primary-900)10%,transparent)] transition-colors duration-200 border-b _shk-border dark:[border-color:var(--shk-surface-100)]\">\n @for (col of columnsWithActions(); track col.field) {\n <td\n class=\"px-2 min-[1440px]:px-3 py-2 min-[1440px]:py-2.5 text-xs font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-700)] whitespace-nowrap\"\n [style.overflow]=\"col.field === 'actions' ? 'visible' : 'hidden'\"\n [style.text-overflow]=\"col.field === 'actions' ? 'clip' : 'ellipsis'\"\n >\n @if (col.field !== 'actions') {\n @if (col.template === 'tag') {\n <span\n class=\"inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium\"\n [class]=\"getTagClass(col.tagSeverity ? col.tagSeverity(rowData) : undefined)\"\n [style]=\"col.tagStyle ? col.tagStyle(rowData) : undefined\"\n >\n {{ col.tagValue ? col.tagValue(rowData) : rowData[col.field] }}\n </span>\n } @else if (col.format) {\n <span>{{ col.format(rowData) }}</span>\n } @else {\n <ng-container\n *ngTemplateOutlet=\"\n customTemplates()[col.field] || defaultTemplate;\n context: { $implicit: rowData, field: col.field }\n \"\n ></ng-container>\n }\n } @else {\n <div class=\"flex items-center justify-start gap-px\">\n @for (action of rowActions(); track $index) {\n @if (isRowActionVisible(action, rowData)) {\n <div class=\"relative group\">\n <button\n type=\"button\"\n (click)=\"action.onClick(rowData)\"\n [class]=\"'table-action-btn hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] rounded-md ' + getRowActionClass(action, rowData)\"\n [disabled]=\"isRowActionDisabled(action, rowData) || false\"\n >\n <svg\n [lucideIcon]=\"getIcon(getRowActionIconName(action, rowData))\"\n class=\"w-4 h-4\"\n ></svg>\n </button>\n <span class=\"absolute bottom-full left-1/2 -translate-x-1/2 mb-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ getRowActionLabel(action, rowData) }}\n </span>\n </div>\n }\n }\n </div>\n }\n </td>\n }\n </tr>\n }\n </tbody>\n }\n </table>\n\n <ng-template #defaultTemplate let-rowData let-field=\"field\">\n {{ truncate(rowData[field], 30) }}\n </ng-template>\n </div>\n\n <div class=\"flex items-center justify-between gap-4 px-2 min-[1440px]:px-3 py-2 border-t _shk-border dark:[border-color:var(--shk-surface-100)]\">\n <div class=\"text-xs _shk-text-surface-600 dark:[color:var(--shk-surface-400)]\">{{ getPageReport() }}</div>\n <div class=\"flex items-center gap-0.5\">\n <button\n type=\"button\"\n (click)=\"goToFirst()\"\n [disabled]=\"isFirstPage()\"\n class=\"p-1 _shk-text-surface-500 hover:[color:var(--shk-surface-700)] dark:[color:var(--shk-surface-400)] dark:hover:[color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed rounded transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('chevrons-left')\" class=\"w-4 h-4\"></svg>\n </button>\n <button\n type=\"button\"\n (click)=\"prev()\"\n [disabled]=\"isFirstPage()\"\n class=\"p-1 _shk-text-surface-500 hover:[color:var(--shk-surface-700)] dark:[color:var(--shk-surface-400)] dark:hover:[color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed rounded transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('chevron-left')\" class=\"w-4 h-4\"></svg>\n </button>\n <span class=\"px-2 text-xs font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\">{{ currentPage() }} / {{ totalPages() }}</span>\n <button\n type=\"button\"\n (click)=\"next()\"\n [disabled]=\"isLastPage()\"\n class=\"p-1 _shk-text-surface-500 hover:[color:var(--shk-surface-700)] dark:[color:var(--shk-surface-400)] dark:hover:[color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed rounded transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('chevron-right')\" class=\"w-4 h-4\"></svg>\n </button>\n <button\n type=\"button\"\n (click)=\"goToLast()\"\n [disabled]=\"isLastPage()\"\n class=\"p-1 _shk-text-surface-500 hover:[color:var(--shk-surface-700)] dark:[color:var(--shk-surface-400)] dark:hover:[color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed rounded transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('chevrons-right')\" class=\"w-4 h-4\"></svg>\n </button>\n </div>\n <div class=\"flex items-center gap-1.5 text-xs _shk-text-surface-600 dark:[color:var(--shk-surface-400)]\">\n <span>{{ 'table.rows' | transloco }}</span>\n <select\n [value]=\"rowsPerPageLocal()\"\n (change)=\"onRowsPerPageChange($any($event.target).value)\"\n class=\"border _shk-border dark:[border-color:var(--shk-surface-200)] rounded px-2 py-1 text-xs bg-white dark:[background-color:var(--shk-surface-100)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)] focus:outline-none focus:[border-color:var(--shk-primary-500)]\"\n >\n @for (opt of rowsPerPageOptions(); track opt) {\n <option [value]=\"opt\">{{ opt }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n\n</div>\n", styles: ["input:focus{outline:none}input[type=text]{font-weight:400!important}table th{white-space:nowrap}table td{white-space:nowrap;text-overflow:ellipsis}td button svg{width:1.125rem!important;height:1.125rem!important}td button:disabled{opacity:.4;cursor:not-allowed}.table-action-btn svg{width:1rem!important;height:1rem!important;min-width:1rem!important;min-height:1rem!important}.table-action-btn{padding:.5rem!important;min-width:2rem!important;min-height:2rem!important;display:inline-flex!important;align-items:center!important;justify-content:center!important}.table-scroll-wrapper{width:100%}.table-scroll-wrapper table{table-layout:fixed}\n"] }]
|
|
2701
|
+
], template: "<div class=\"space-y-2 min-[1440px]:space-y-3 mt-2 min-[1440px]:mt-3 animate-fade-in pb-8\">\n\n @if (showSearch() || filters().length > 0 || headerActions().length > 0) {\n <div class=\"card p-2 min-[1440px]:p-2.5 flex flex-row items-center justify-between gap-2\">\n\n <div class=\"flex items-center gap-2 min-[1440px]:gap-3 flex-1 min-w-0\">\n @if (showSearch()) {\n <div class=\"relative w-full md:w-52 min-[1440px]:w-56\">\n <div class=\"absolute inset-y-0 left-0 pl-2.5 flex items-center pointer-events-none\">\n <svg [lucideIcon]=\"getIcon('search')\" class=\"w-3.5 h-3.5 _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\"></svg>\n </div>\n <input\n type=\"text\"\n [value]=\"searchQuery()\"\n (input)=\"onSearchInput($any($event.target).value)\"\n [placeholder]=\"searchPlaceholder() || ('common.search_placeholder' | transloco)\"\n class=\"block w-full pl-8 pr-3 py-1.5 text-xs border _shk-border dark:[border-color:var(--shk-surface-200)] rounded-md leading-5\n _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] placeholder:[color:var(--shk-surface-400)] dark:placeholder:[color:var(--shk-surface-500)]\n _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\n focus:outline-none focus:bg-white dark:focus:[background-color:var(--shk-surface-800)] focus:[border-color:var(--shk-primary-500)] focus:ring-1\n focus:[--tw-ring-color:var(--shk-primary-500)]\"\n />\n </div>\n }\n\n @if (filters().length > 0) {\n <div class=\"flex _shk-bg-surface-100 dark:[background-color:var(--shk-surface-100)] p-0.5 rounded-md ml-auto\">\n @for (f of filters(); track f.value) {\n <button\n type=\"button\"\n (click)=\"onFilterClick(f.value)\"\n class=\"px-2.5 min-[1440px]:px-3 py-1 text-xs font-medium rounded _shk-text-surface-700 dark:[color:var(--shk-surface-700)] transition-all\"\n [class]=\"f.value === activeFilter() ? 'bg-white shadow-sm dark:[background-color:var(--shk-surface-700)]' : ''\"\n >\n {{ f.label }}\n </button>\n }\n </div>\n }\n </div>\n\n @if (headerActions().length > 0) {\n <div class=\"flex items-center gap-1.5 shrink-0\">\n @for (action of headerActions(); track $index) {\n @if (isHeaderActionVisible(action)) {\n <button\n type=\"button\"\n [class]=\"action.class || 'inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md _shk-bg-primary text-white hover:[background-color:var(--shk-primary-700)] transition-colors disabled:opacity-50 disabled:cursor-not-allowed'\"\n [disabled]=\"isHeaderActionDisabled(action)\"\n (click)=\"action.onClick()\"\n >\n @if (action.icon) {\n <svg\n [lucideIcon]=\"getIcon(action.icon)\"\n class=\"w-3.5 h-3.5\"\n ></svg>\n }\n {{ action.label }}\n </button>\n }\n }\n </div>\n }\n\n </div>\n }\n\n <div\n class=\"card p-0 overflow-hidden\"\n [class.shadow-lg]=\"hasShadow()\"\n >\n\n <div class=\"table-scroll-wrapper _shk-scrollbar\">\n <table class=\"w-full\">\n <thead>\n <tr>\n @for (col of columnsWithActions(); track col.field) {\n <th\n (click)=\"col.field !== 'actions' && col.sortable && toggleSort(col.field)\"\n [style.cursor]=\"col.field !== 'actions' && col.sortable ? 'pointer' : 'default'\"\n [style.width]=\"col.width || 'auto'\"\n [style.min-width]=\"col.field === 'actions' ? '130px' : 'auto'\"\n class=\"px-2 min-[1440px]:px-3 py-2 min-[1440px]:py-2.5 text-left text-[10px] min-[1440px]:text-xs font-bold _shk-text-surface-500 dark:[color:var(--shk-surface-400)] uppercase tracking-wider\n _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] border-b _shk-border dark:[border-color:var(--shk-surface-200)]\"\n >\n @if (col.field !== 'actions') {\n <div class=\"flex items-center justify-between gap-2\">\n <span>{{ col.header }}</span>\n <div class=\"flex items-center gap-1\">\n @if (col.sortable) {\n <div class=\"relative group\">\n @if (sortField() === col.field) {\n <svg [lucideIcon]=\"getIcon(sortOrder() === 1 ? 'arrow-up' : 'arrow-down')\"\n class=\"w-3.5 h-3.5 _shk-text-primary\"></svg>\n } @else {\n <svg [lucideIcon]=\"getIcon('arrow-up-down')\"\n class=\"w-3.5 h-3.5 _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\"></svg>\n }\n <span class=\"absolute top-full left-1/2 -translate-x-1/2 mt-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ 'table.tooltips.sort' | transloco }}\n </span>\n </div>\n }\n @if (col.filter) {\n <div class=\"relative group\">\n <button\n type=\"button\"\n (click)=\"$event.stopPropagation(); toggleFilter(col.field)\"\n class=\"_shk-text-surface-400 dark:[color:var(--shk-surface-500)] hover:[color:var(--shk-surface-600)] dark:hover:[color:var(--shk-surface-300)] transition-colors\"\n >\n <svg\n [lucideIcon]=\"getIcon('filter')\"\n class=\"w-3.5 h-3.5\"\n [class._shk-text-primary]=\"columnFiltersForm.get(col.field)?.value\"\n ></svg>\n <span class=\"absolute top-full left-1/2 -translate-x-1/2 mt-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ 'table.tooltips.filter' | transloco }}\n </span>\n </button>\n </div>\n }\n </div>\n </div>\n\n @if (col.filter && showFilterInput()[col.field]) {\n <div\n class=\"mt-2\"\n [formGroup]=\"columnFiltersForm\"\n (click)=\"$event.stopPropagation()\"\n >\n <div class=\"relative\">\n @if (col.filterType !== 'select') {\n <input\n type=\"text\"\n [formControlName]=\"col.field\"\n class=\"w-full px-3 py-1.5 text-sm rounded-md border _shk-border dark:[border-color:var(--shk-surface-200)] bg-white dark:[background-color:var(--shk-surface-100)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\n focus:[border-color:var(--shk-primary-500)] focus:ring-1 focus:[--tw-ring-color:var(--shk-primary-500)]\n placeholder:[color:var(--shk-surface-400)] dark:placeholder:[color:var(--shk-surface-500)]\"\n [placeholder]=\"col.filterPlaceholder || ('common.search_placeholder' | transloco)\"\n />\n }\n @if (col.filterType === 'select') {\n <select\n [formControlName]=\"col.field\"\n class=\"w-full px-2 py-1 text-xs rounded-md border _shk-border dark:[border-color:var(--shk-surface-200)] bg-white dark:[background-color:var(--shk-surface-100)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)] focus:[border-color:var(--shk-primary-500)] focus:ring-1 focus:[--tw-ring-color:var(--shk-primary-500)] appearance-none\"\n >\n <option [ngValue]=\"null\">A/D</option>\n @for (opt of col.filterOptions || []; track opt.value) {\n <option [ngValue]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n }\n @if (columnFiltersForm.get(col.field)?.value && col.filterType !== 'select') {\n <button\n type=\"button\"\n class=\"absolute right-2 top-1/2 -translate-y-1/2 _shk-text-surface-400 dark:[color:var(--shk-surface-500)] hover:[color:var(--shk-surface-600)] dark:hover:[color:var(--shk-surface-300)]\"\n (click)=\"clearFilter(col.field)\"\n >\n <svg [lucideIcon]=\"getIcon('x')\" class=\"w-3.5 h-3.5\"></svg>\n </button>\n }\n </div>\n </div>\n }\n } @else {\n <div class=\"flex items-center justify-center\">\n <span>{{ col.header }}</span>\n </div>\n }\n </th>\n }\n </tr>\n </thead>\n\n @if (loading()) {\n <tbody class=\"border-b _shk-border dark:[border-color:var(--shk-surface-100)]\">\n <tr>\n <td [attr.colspan]=\"columnsWithActions().length\" class=\"text-center py-12\">\n <div class=\"flex items-center justify-center\">\n <svg [lucideIcon]=\"getIcon('loader')\" class=\"w-6 h-6 animate-spin _shk-text-primary\"></svg>\n </div>\n </td>\n </tr>\n </tbody>\n } @else if (effectiveDisplayedData().length === 0) {\n <tbody class=\"border-b _shk-border dark:[border-color:var(--shk-surface-100)]\">\n <tr>\n <td [attr.colspan]=\"columnsWithActions().length\" class=\"text-center py-12\">\n <div class=\"flex flex-col items-center\">\n <div class=\"w-16 h-16 _shk-bg-surface-100 dark:[background-color:var(--shk-surface-100)] rounded-full flex items-center justify-center mb-4\">\n <svg [lucideIcon]=\"getIcon('inbox')\" class=\"w-8 h-8 _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\"></svg>\n </div>\n <p class=\"text-lg font-semibold _shk-text-surface-600 dark:[color:var(--shk-surface-300)]\">\n {{ emptyMessage() || ('common.no_records' | transloco) }}\n </p>\n </div>\n </td>\n </tr>\n </tbody>\n } @else {\n <tbody>\n @for (rowData of effectiveDisplayedData(); track $index) {\n <tr class=\"hover:[background-color:color-mix(in srgb,var(--shk-primary-50)30%,transparent)] dark:hover:[background-color:color-mix(in srgb,var(--shk-primary-900)10%,transparent)] transition-colors duration-200 border-b _shk-border dark:[border-color:var(--shk-surface-100)]\">\n @for (col of columnsWithActions(); track col.field) {\n <td\n class=\"px-2 min-[1440px]:px-3 py-2 min-[1440px]:py-2.5 text-xs font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-700)] whitespace-nowrap\"\n [style.overflow]=\"col.field === 'actions' ? 'visible' : 'hidden'\"\n [style.text-overflow]=\"col.field === 'actions' ? 'clip' : 'ellipsis'\"\n >\n @if (col.field !== 'actions') {\n @if (col.template === 'tag') {\n <span\n class=\"inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium\"\n [class]=\"getTagClass(col.tagSeverity ? col.tagSeverity(rowData) : undefined)\"\n [style]=\"col.tagStyle ? col.tagStyle(rowData) : undefined\"\n >\n {{ col.tagValue ? col.tagValue(rowData) : rowData[col.field] }}\n </span>\n } @else if (col.format) {\n <span>{{ col.format(rowData) }}</span>\n } @else {\n <ng-container\n *ngTemplateOutlet=\"\n customTemplates()[col.field] || defaultTemplate;\n context: { $implicit: rowData, field: col.field }\n \"\n ></ng-container>\n }\n } @else {\n <div class=\"flex items-center justify-start gap-px\">\n @for (action of rowActions(); track $index) {\n @if (isRowActionVisible(action, rowData)) {\n <div class=\"relative group\">\n <button\n type=\"button\"\n (click)=\"action.onClick(rowData)\"\n [class]=\"'table-action-btn hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] rounded-md ' + getRowActionClass(action, rowData)\"\n [disabled]=\"isRowActionDisabled(action, rowData) || false\"\n >\n <svg\n [lucideIcon]=\"getIcon(getRowActionIconName(action, rowData))\"\n class=\"w-4 h-4\"\n ></svg>\n </button>\n <span class=\"absolute bottom-full left-1/2 -translate-x-1/2 mb-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ getRowActionLabel(action, rowData) }}\n </span>\n </div>\n }\n }\n </div>\n }\n </td>\n }\n </tr>\n }\n </tbody>\n }\n </table>\n\n <ng-template #defaultTemplate let-rowData let-field=\"field\">\n {{ truncate(rowData[field], 30) }}\n </ng-template>\n </div>\n\n <div class=\"flex items-center justify-between gap-4 px-2 min-[1440px]:px-3 py-2 border-t _shk-border dark:[border-color:var(--shk-surface-100)]\">\n <div class=\"text-xs _shk-text-surface-600 dark:[color:var(--shk-surface-400)]\">{{ getPageReport() }}</div>\n <div class=\"flex items-center gap-0.5\">\n <button\n type=\"button\"\n (click)=\"goToFirst()\"\n [disabled]=\"isFirstPage()\"\n class=\"p-1 _shk-text-surface-500 hover:[color:var(--shk-surface-700)] dark:[color:var(--shk-surface-400)] dark:hover:[color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed rounded transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('chevrons-left')\" class=\"w-4 h-4\"></svg>\n </button>\n <button\n type=\"button\"\n (click)=\"prev()\"\n [disabled]=\"isFirstPage()\"\n class=\"p-1 _shk-text-surface-500 hover:[color:var(--shk-surface-700)] dark:[color:var(--shk-surface-400)] dark:hover:[color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed rounded transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('chevron-left')\" class=\"w-4 h-4\"></svg>\n </button>\n <span class=\"px-2 text-xs font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\">{{ currentPage() }} / {{ totalPages() }}</span>\n <button\n type=\"button\"\n (click)=\"next()\"\n [disabled]=\"isLastPage()\"\n class=\"p-1 _shk-text-surface-500 hover:[color:var(--shk-surface-700)] dark:[color:var(--shk-surface-400)] dark:hover:[color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed rounded transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('chevron-right')\" class=\"w-4 h-4\"></svg>\n </button>\n <button\n type=\"button\"\n (click)=\"goToLast()\"\n [disabled]=\"isLastPage()\"\n class=\"p-1 _shk-text-surface-500 hover:[color:var(--shk-surface-700)] dark:[color:var(--shk-surface-400)] dark:hover:[color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed rounded transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('chevrons-right')\" class=\"w-4 h-4\"></svg>\n </button>\n </div>\n <div class=\"flex items-center gap-1.5 text-xs _shk-text-surface-600 dark:[color:var(--shk-surface-400)]\">\n <span>{{ 'table.rows' | transloco }}</span>\n <select\n [value]=\"rowsPerPageLocal()\"\n (change)=\"onRowsPerPageChange($any($event.target).value)\"\n class=\"border _shk-border dark:[border-color:var(--shk-surface-200)] rounded px-2 py-1 text-xs bg-white dark:[background-color:var(--shk-surface-100)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)] focus:outline-none focus:[border-color:var(--shk-primary-500)]\"\n >\n @for (opt of rowsPerPageOptions(); track opt) {\n <option [value]=\"opt\">{{ opt }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n\n</div>\n", styles: ["input:focus{outline:none}input[type=text]{font-weight:400!important}table th{white-space:nowrap}table td{white-space:nowrap;text-overflow:ellipsis}td button svg{width:1.125rem!important;height:1.125rem!important}td button:disabled{opacity:.4;cursor:not-allowed}.table-action-btn svg{width:1rem!important;height:1rem!important;min-width:1rem!important;min-height:1rem!important}.table-action-btn{padding:.5rem!important;min-width:2rem!important;min-height:2rem!important;display:inline-flex!important;align-items:center!important;justify-content:center!important}.table-scroll-wrapper{width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-scroll-wrapper table{table-layout:fixed;min-width:100%}\n"] }]
|
|
2702
2702
|
}], ctorParameters: () => [], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], rowsPerPage: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowsPerPage", required: false }] }], rowsPerPageOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowsPerPageOptions", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], showActionRow: [{ type: i0.Input, args: [{ isSignal: true, alias: "showActionRow", required: false }] }], customTemplates: [{ type: i0.Input, args: [{ isSignal: true, alias: "customTemplates", required: false }] }], headerActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerActions", required: false }] }], rowActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowActions", required: false }] }], hasShadow: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasShadow", required: false }] }], defaultSortField: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultSortField", required: false }] }], defaultSortOrder: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultSortOrder", required: false }] }], showSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSearch", required: false }] }], searchPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchPlaceholder", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], serverSide: [{ type: i0.Input, args: [{ isSignal: true, alias: "serverSide", required: false }] }], totalRecords: [{ type: i0.Input, args: [{ isSignal: true, alias: "totalRecords", required: false }] }], filters: [{ type: i0.Input, args: [{ isSignal: true, alias: "filters", required: false }] }], activeFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeFilter", required: false }] }], refresh: [{ type: i0.Output, args: ["refresh"] }], pageChange: [{ type: i0.Output, args: ["pageChange"] }], filterChange: [{ type: i0.Output, args: ["filterChange"] }], searchChange: [{ type: i0.Output, args: ["searchChange"] }], filterClick: [{ type: i0.Output, args: ["filterClick"] }] } });
|
|
2703
2703
|
|
|
2704
2704
|
class TooltipComponent {
|
|
@@ -2810,27 +2810,372 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImpo
|
|
|
2810
2810
|
args: ['mouseenter']
|
|
2811
2811
|
}] } });
|
|
2812
2812
|
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2813
|
+
const ICONS$1 = {
|
|
2814
|
+
house: LucideHouse,
|
|
2815
|
+
home: LucideHome,
|
|
2816
|
+
dashboard: LucideLayoutDashboard,
|
|
2817
|
+
warehouse: LucideWarehouse,
|
|
2818
|
+
building: LucideBuilding,
|
|
2819
|
+
'building-2': LucideBuilding2,
|
|
2820
|
+
truck: LucideTruck,
|
|
2821
|
+
users: LucideUsers,
|
|
2822
|
+
user: LucideUser,
|
|
2823
|
+
clients: LucideUsers,
|
|
2824
|
+
box: LucideBox,
|
|
2825
|
+
product: LucidePackage,
|
|
2826
|
+
package: LucidePackage,
|
|
2827
|
+
tags: LucideTags,
|
|
2828
|
+
tag: LucideTag,
|
|
2829
|
+
receipt: LucideReceipt,
|
|
2830
|
+
orders: LucideReceipt,
|
|
2831
|
+
bot: LucideBot,
|
|
2832
|
+
settings: LucideSettings,
|
|
2833
|
+
config: LucideSettings,
|
|
2834
|
+
menu: LucideMenu,
|
|
2835
|
+
'line-chart': LucideLineChart,
|
|
2836
|
+
'bar-chart-3': LucideBarChart3,
|
|
2837
|
+
star: LucideStar,
|
|
2838
|
+
'dollar-sign': LucideDollarSign,
|
|
2839
|
+
percent: LucidePercent,
|
|
2840
|
+
calculator: LucideCalculator,
|
|
2841
|
+
search: LucideSearch,
|
|
2842
|
+
'shield-check': LucideShieldCheck,
|
|
2843
|
+
'user-cog': LucideUserCog,
|
|
2844
|
+
'chevrons-left': LucideChevronsLeft,
|
|
2845
|
+
'chevrons-right': LucideChevronsRight,
|
|
2846
|
+
'chevron-down': LucideChevronDown,
|
|
2847
|
+
'chevron-left': LucideChevronLeft,
|
|
2848
|
+
'chevron-right': LucideChevronRight,
|
|
2849
|
+
'log-out': LucideLogOut,
|
|
2850
|
+
logout: LucideLogOut,
|
|
2851
|
+
x: LucideX,
|
|
2852
|
+
};
|
|
2853
|
+
function getIcon$4(name) {
|
|
2854
|
+
if (!name)
|
|
2855
|
+
return null;
|
|
2856
|
+
return ICONS$1[name] ?? LucideMenu;
|
|
2857
|
+
}
|
|
2858
|
+
class SidebarComponent {
|
|
2859
|
+
constructor(platformId) {
|
|
2860
|
+
this.platformId = platformId;
|
|
2861
|
+
this.items = input([], ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
|
|
2862
|
+
this.groups = input([], ...(ngDevMode ? [{ debugName: "groups" }] : /* istanbul ignore next */ []));
|
|
2863
|
+
this.title = input('', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
|
|
2864
|
+
this.subtitle = input('', ...(ngDevMode ? [{ debugName: "subtitle" }] : /* istanbul ignore next */ []));
|
|
2865
|
+
this.logo = input('', ...(ngDevMode ? [{ debugName: "logo" }] : /* istanbul ignore next */ []));
|
|
2866
|
+
this.activeItemId = input('', ...(ngDevMode ? [{ debugName: "activeItemId" }] : /* istanbul ignore next */ []));
|
|
2867
|
+
this.userRole = input('', ...(ngDevMode ? [{ debugName: "userRole" }] : /* istanbul ignore next */ []));
|
|
2868
|
+
this.collapsible = input(true, ...(ngDevMode ? [{ debugName: "collapsible" }] : /* istanbul ignore next */ []));
|
|
2869
|
+
this.showToggle = input(true, ...(ngDevMode ? [{ debugName: "showToggle" }] : /* istanbul ignore next */ []));
|
|
2870
|
+
this.responsive = input(true, ...(ngDevMode ? [{ debugName: "responsive" }] : /* istanbul ignore next */ []));
|
|
2871
|
+
this.fixed = input(false, ...(ngDevMode ? [{ debugName: "fixed" }] : /* istanbul ignore next */ []));
|
|
2872
|
+
this.hasShadow = input(true, ...(ngDevMode ? [{ debugName: "hasShadow" }] : /* istanbul ignore next */ []));
|
|
2873
|
+
this.expandedWidth = input('16rem', ...(ngDevMode ? [{ debugName: "expandedWidth" }] : /* istanbul ignore next */ []));
|
|
2874
|
+
this.collapsedWidth = input('5rem', ...(ngDevMode ? [{ debugName: "collapsedWidth" }] : /* istanbul ignore next */ []));
|
|
2875
|
+
this.defaultExpanded = input([], ...(ngDevMode ? [{ debugName: "defaultExpanded" }] : /* istanbul ignore next */ []));
|
|
2876
|
+
this.labelPipe = input((label) => label, ...(ngDevMode ? [{ debugName: "labelPipe" }] : /* istanbul ignore next */ []));
|
|
2877
|
+
this.expandTooltip = input('Expandir', ...(ngDevMode ? [{ debugName: "expandTooltip" }] : /* istanbul ignore next */ []));
|
|
2878
|
+
this.collapseTooltip = input('Colapsar', ...(ngDevMode ? [{ debugName: "collapseTooltip" }] : /* istanbul ignore next */ []));
|
|
2879
|
+
this.collapsed = model(false, ...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
|
|
2880
|
+
this.mobileOpen = model(false, ...(ngDevMode ? [{ debugName: "mobileOpen" }] : /* istanbul ignore next */ []));
|
|
2881
|
+
this.itemClick = output();
|
|
2882
|
+
this.toggle = output();
|
|
2883
|
+
this.getIcon = getIcon$4;
|
|
2884
|
+
this.selectedId = signal('', ...(ngDevMode ? [{ debugName: "selectedId" }] : /* istanbul ignore next */ []));
|
|
2885
|
+
this.expandedGroups = signal(new Set(), ...(ngDevMode ? [{ debugName: "expandedGroups" }] : /* istanbul ignore next */ []));
|
|
2886
|
+
this.isBrowser = isPlatformBrowser(this.platformId);
|
|
2887
|
+
this.width = computed(() => this.collapsed() ? this.collapsedWidth() : this.expandedWidth(), ...(ngDevMode ? [{ debugName: "width" }] : /* istanbul ignore next */ []));
|
|
2888
|
+
this.navItems = computed(() => {
|
|
2889
|
+
const role = this.userRole();
|
|
2890
|
+
const base = this.groups().length
|
|
2891
|
+
? this.groups().flatMap((g) => g.items)
|
|
2892
|
+
: this.items();
|
|
2893
|
+
return base.filter((item) => {
|
|
2894
|
+
if (!item.roles || item.roles.length === 0)
|
|
2895
|
+
return true;
|
|
2896
|
+
return role ? item.roles.includes(role) : false;
|
|
2897
|
+
});
|
|
2898
|
+
}, ...(ngDevMode ? [{ debugName: "navItems" }] : /* istanbul ignore next */ []));
|
|
2899
|
+
effect(() => {
|
|
2900
|
+
this.selectedId.set(this.activeItemId());
|
|
2901
|
+
});
|
|
2902
|
+
effect(() => {
|
|
2903
|
+
const active = this.activeItemId();
|
|
2904
|
+
if (!active)
|
|
2905
|
+
return;
|
|
2906
|
+
const parent = this.navItems().find((item) => item.children?.some((c) => c.id === active));
|
|
2907
|
+
if (parent) {
|
|
2908
|
+
this.expandedGroups.update((set) => {
|
|
2909
|
+
if (set.has(parent.id))
|
|
2910
|
+
return set;
|
|
2911
|
+
const next = new Set(set);
|
|
2912
|
+
next.add(parent.id);
|
|
2913
|
+
return next;
|
|
2914
|
+
});
|
|
2915
|
+
}
|
|
2916
|
+
});
|
|
2917
|
+
effect(() => {
|
|
2918
|
+
const defs = this.defaultExpanded();
|
|
2919
|
+
if (!defs.length)
|
|
2920
|
+
return;
|
|
2921
|
+
this.expandedGroups.update((set) => {
|
|
2922
|
+
const next = new Set(set);
|
|
2923
|
+
defs.forEach((id) => next.add(id));
|
|
2924
|
+
return next;
|
|
2925
|
+
});
|
|
2926
|
+
});
|
|
2818
2927
|
}
|
|
2819
|
-
|
|
2820
|
-
this.
|
|
2928
|
+
onResize(_event) {
|
|
2929
|
+
if (this.responsive() && this.isBrowser && window.innerWidth < 1024) {
|
|
2930
|
+
this.mobileOpen.set(false);
|
|
2931
|
+
}
|
|
2821
2932
|
}
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2933
|
+
label(item) {
|
|
2934
|
+
return this.labelPipe()(item.label);
|
|
2935
|
+
}
|
|
2936
|
+
isItemActive(item) {
|
|
2937
|
+
return !!item.id && item.id === this.selectedId();
|
|
2938
|
+
}
|
|
2939
|
+
isGroupActive(item) {
|
|
2940
|
+
return item.children?.some((c) => c.id === this.selectedId()) ?? false;
|
|
2941
|
+
}
|
|
2942
|
+
isGroupExpanded(item) {
|
|
2943
|
+
return this.expandedGroups().has(item.id);
|
|
2944
|
+
}
|
|
2945
|
+
toggleGroup(item) {
|
|
2946
|
+
this.expandedGroups.update((set) => {
|
|
2947
|
+
const next = new Set(set);
|
|
2948
|
+
if (next.has(item.id)) {
|
|
2949
|
+
next.delete(item.id);
|
|
2950
|
+
}
|
|
2951
|
+
else {
|
|
2952
|
+
next.add(item.id);
|
|
2953
|
+
}
|
|
2954
|
+
return next;
|
|
2955
|
+
});
|
|
2956
|
+
}
|
|
2957
|
+
onItemClick(item) {
|
|
2958
|
+
if (item.disabled)
|
|
2826
2959
|
return;
|
|
2827
|
-
|
|
2828
|
-
this.
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2960
|
+
this.selectedId.set(item.id);
|
|
2961
|
+
this.itemClick.emit(item);
|
|
2962
|
+
if (this.responsive() && this.isBrowser && window.innerWidth < 1024) {
|
|
2963
|
+
this.mobileOpen.set(false);
|
|
2964
|
+
}
|
|
2965
|
+
}
|
|
2966
|
+
onToggle() {
|
|
2967
|
+
if (this.responsive() && this.isBrowser && window.innerWidth < 1024) {
|
|
2968
|
+
this.mobileOpen.update((v) => !v);
|
|
2969
|
+
}
|
|
2970
|
+
else {
|
|
2971
|
+
this.collapsed.update((v) => !v);
|
|
2972
|
+
this.toggle.emit(this.collapsed());
|
|
2973
|
+
}
|
|
2974
|
+
}
|
|
2975
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: SidebarComponent, deps: [{ token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2976
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: SidebarComponent, isStandalone: true, selector: "shk-sidebar", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, groups: { classPropertyName: "groups", publicName: "groups", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, subtitle: { classPropertyName: "subtitle", publicName: "subtitle", isSignal: true, isRequired: false, transformFunction: null }, logo: { classPropertyName: "logo", publicName: "logo", isSignal: true, isRequired: false, transformFunction: null }, activeItemId: { classPropertyName: "activeItemId", publicName: "activeItemId", isSignal: true, isRequired: false, transformFunction: null }, userRole: { classPropertyName: "userRole", publicName: "userRole", isSignal: true, isRequired: false, transformFunction: null }, collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null }, showToggle: { classPropertyName: "showToggle", publicName: "showToggle", isSignal: true, isRequired: false, transformFunction: null }, responsive: { classPropertyName: "responsive", publicName: "responsive", isSignal: true, isRequired: false, transformFunction: null }, fixed: { classPropertyName: "fixed", publicName: "fixed", isSignal: true, isRequired: false, transformFunction: null }, hasShadow: { classPropertyName: "hasShadow", publicName: "hasShadow", isSignal: true, isRequired: false, transformFunction: null }, expandedWidth: { classPropertyName: "expandedWidth", publicName: "expandedWidth", isSignal: true, isRequired: false, transformFunction: null }, collapsedWidth: { classPropertyName: "collapsedWidth", publicName: "collapsedWidth", isSignal: true, isRequired: false, transformFunction: null }, defaultExpanded: { classPropertyName: "defaultExpanded", publicName: "defaultExpanded", isSignal: true, isRequired: false, transformFunction: null }, labelPipe: { classPropertyName: "labelPipe", publicName: "labelPipe", isSignal: true, isRequired: false, transformFunction: null }, expandTooltip: { classPropertyName: "expandTooltip", publicName: "expandTooltip", isSignal: true, isRequired: false, transformFunction: null }, collapseTooltip: { classPropertyName: "collapseTooltip", publicName: "collapseTooltip", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, mobileOpen: { classPropertyName: "mobileOpen", publicName: "mobileOpen", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { collapsed: "collapsedChange", mobileOpen: "mobileOpenChange", itemClick: "itemClick", toggle: "toggle" }, host: { listeners: { "window:resize": "onResize($event)" } }, ngImport: i0, template: "@if (responsive() && mobileOpen()) {\n <!-- Mobile overlay backdrop (sibling of aside: must NOT be inside the\n transformed aside, otherwise it becomes its containing block and\n only covers the sidebar, also blocking nav clicks on mobile) -->\n <div\n class=\"fixed inset-0 bg-black/50 z-30 lg:hidden\"\n (click)=\"mobileOpen.set(false)\"\n ></div>\n}\n\n<aside\n [class.fixed]=\"fixed()\"\n [class.relative]=\"!fixed()\"\n [class.h-screen]=\"fixed()\"\n [class.h-full]=\"!fixed()\"\n class=\"top-0 left-0 flex flex-col shrink-0 sidebar-transition sidebar-mobile-transform z-40 _shk-bg-white dark:[background-color:var(--shk-surface-50)] border-r _shk-border dark:[border-color:var(--shk-surface-100)]\"\n [class.shadow-sm]=\"hasShadow()\"\n [style.width]=\"width()\"\n [style.transform]=\"responsive() ? (mobileOpen() ? 'translateX(0)' : 'translateX(-100%)') : null\"\n>\n <!-- Logo / Brand -->\n @if (logo() || title() || subtitle()) {\n <div\n class=\"flex items-center h-20 px-4 border-b _shk-border dark:[border-color:var(--shk-surface-100)] shrink-0\"\n >\n <div class=\"flex items-center gap-3 overflow-hidden\">\n @if (logo()) {\n <img [src]=\"logo()\" alt=\"Logo\" class=\"h-16 w-16 shrink-0 object-contain\" />\n }\n @if (!collapsed() && (title() || subtitle())) {\n <div class=\"flex flex-col leading-tight whitespace-nowrap\">\n @if (title()) {\n <span class=\"text-lg font-bold _shk-text-surface-800 dark:[color:var(--shk-surface-800)]\">\n {{ title() }}\n </span>\n }\n @if (subtitle()) {\n <span class=\"text-sm _shk-text-surface-500 dark:[color:var(--shk-surface-500)]\">\n {{ subtitle() }}\n </span>\n }\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Toggle button -->\n @if (showToggle() && collapsible()) {\n <button\n type=\"button\"\n (click)=\"onToggle()\"\n class=\"group absolute -right-3 top-20 z-50 w-6 h-6 rounded-full bg-white dark:[background-color:var(--shk-surface-100)] border _shk-border dark:[border-color:var(--shk-surface-200)] shadow-md max-lg:hidden flex items-center justify-center _shk-text-surface-600 dark:[color:var(--shk-surface-600)] hover:[background-color:var(--shk-primary-50)] dark:hover:[background-color:var(--shk-surface-200)] hover:[color:var(--shk-primary-600)] dark:hover:[color:var(--shk-primary-400)] transition-colors\"\n >\n @if (collapsed()) {\n <svg [lucideIcon]=\"getIcon('chevron-right')\" class=\"w-3 h-3\"></svg>\n } @else {\n <svg [lucideIcon]=\"getIcon('chevron-left')\" class=\"w-3 h-3\"></svg>\n }\n <span\n class=\"absolute left-full ml-1 top-1/2 -translate-y-1/2 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\"\n >\n {{ collapsed() ? expandTooltip() : collapseTooltip() }}\n </span>\n </button>\n }\n\n <ng-content select=\"[sidebarHeader]\"></ng-content>\n\n <!-- Custom content between header and nav -->\n <ng-content select=\"[sidebarContent]\"></ng-content>\n\n <!-- Navigation -->\n <nav class=\"flex-1 sidebar-scroll _shk-scrollbar py-4 px-3\">\n <ul class=\"space-y-1\">\n @for (item of navItems(); track item.id) {\n @if (item.separator) {\n <li class=\"my-2 border-t _shk-border dark:[border-color:var(--shk-surface-200)]\"></li>\n }\n\n @if (item.children?.length) {\n <!-- Group -->\n <li>\n @if (collapsed()) {\n <shk-tooltip [text]=\"label(item)\" position=\"right\" mode=\"fixed\">\n <div\n class=\"flex items-center justify-center px-3 py-2.5 rounded-lg transition-all duration-200\"\n [class._shk-bg-primary]=\"isGroupActive(item)\"\n [class._shk-text-white]=\"isGroupActive(item)\"\n [class._shk-text-surface-500]=\"!isGroupActive(item)\"\n >\n @if (item.icon) {\n <svg [lucideIcon]=\"getIcon(item.icon)\" class=\"w-5 h-5 shrink-0\"></svg>\n }\n </div>\n </shk-tooltip>\n } @else {\n <button\n type=\"button\"\n (click)=\"toggleGroup(item)\"\n class=\"w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all duration-200 group relative\"\n [class._shk-bg-primary]=\"isGroupActive(item)\"\n [class._shk-text-white]=\"isGroupActive(item)\"\n [class.shadow-md]=\"isGroupActive(item)\"\n [class._shk-text-surface-700]=\"!isGroupActive(item)\"\n [class.dark:[color:var(--shk-surface-600)]]=\"!isGroupActive(item)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isGroupActive(item)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isGroupActive(item)\"\n [class.hover:[color:var(--shk-surface-900)]]=\"!isGroupActive(item)\"\n [class.dark:hover:[color:var(--shk-surface-700)]]=\"!isGroupActive(item)\"\n >\n @if (item.icon) {\n <svg [lucideIcon]=\"getIcon(item.icon)\" class=\"w-5 h-5 shrink-0\"></svg>\n }\n <span class=\"flex-1 text-left whitespace-nowrap overflow-hidden\">{{ label(item) }}</span>\n <svg\n [lucideIcon]=\"getIcon('chevron-down')\"\n class=\"w-4 h-4 transition-transform duration-200 shrink-0\"\n [class.rotate-180]=\"isGroupExpanded(item)\"\n ></svg>\n </button>\n\n @if (isGroupExpanded(item)) {\n <ul class=\"ml-3 mt-1 space-y-1 border-l-2 _shk-border dark:[border-color:var(--shk-surface-200)] pl-2\">\n @for (child of item.children; track child.id) {\n <li>\n <button\n type=\"button\"\n (click)=\"onItemClick(child)\"\n class=\"w-full flex items-center gap-3 px-3 py-2 rounded-lg text-sm font-medium transition-all duration-200\"\n [class._shk-bg-primary-soft]=\"isItemActive(child)\"\n [class._shk-bg-primary-soft-dark]=\"isItemActive(child)\"\n [class._shk-text-primary-700]=\"isItemActive(child)\"\n [class.dark:[color:var(--shk-primary-300)]]=\"isItemActive(child)\"\n [class._shk-text-surface-600]=\"!isItemActive(child)\"\n [class.dark:[color:var(--shk-surface-400)]]=\"!isItemActive(child)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isItemActive(child)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isItemActive(child)\"\n [class.hover:[color:var(--shk-surface-900)]]=\"!isItemActive(child)\"\n [class.dark:hover:[color:var(--shk-surface-700)]]=\"!isItemActive(child)\"\n >\n @if (child.icon) {\n <svg [lucideIcon]=\"getIcon(child.icon)\" class=\"w-4 h-4 shrink-0\"></svg>\n }\n <span class=\"whitespace-nowrap overflow-hidden\">{{ label(child) }}</span>\n @if (isItemActive(child)) {\n <span class=\"w-1.5 h-1.5 rounded-full _shk-bg-primary shrink-0 ml-auto\"></span>\n }\n </button>\n </li>\n }\n </ul>\n }\n }\n </li>\n } @else {\n <!-- Standalone item -->\n <li>\n @if (collapsed()) {\n <shk-tooltip [text]=\"label(item)\" position=\"right\" mode=\"fixed\">\n <button\n type=\"button\"\n (click)=\"onItemClick(item)\"\n class=\"w-full flex items-center justify-center px-3 py-2.5 rounded-lg text-sm font-medium transition-all duration-200\"\n [class._shk-bg-primary]=\"isItemActive(item)\"\n [class._shk-text-white]=\"isItemActive(item)\"\n [class.shadow-md]=\"isItemActive(item)\"\n [class._shk-text-surface-700]=\"!isItemActive(item)\"\n [class.dark:[color:var(--shk-surface-600)]]=\"!isItemActive(item)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isItemActive(item)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isItemActive(item)\"\n [class.hover:[color:var(--shk-surface-900)]]=\"!isItemActive(item)\"\n [class.dark:hover:[color:var(--shk-surface-700)]]=\"!isItemActive(item)\"\n >\n @if (item.icon) {\n <svg [lucideIcon]=\"getIcon(item.icon)\" class=\"w-5 h-5 shrink-0\"></svg>\n }\n </button>\n </shk-tooltip>\n } @else {\n <button\n type=\"button\"\n (click)=\"onItemClick(item)\"\n class=\"w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all duration-200\"\n [class._shk-bg-primary]=\"isItemActive(item)\"\n [class._shk-text-white]=\"isItemActive(item)\"\n [class.shadow-md]=\"isItemActive(item)\"\n [class._shk-text-surface-700]=\"!isItemActive(item)\"\n [class.dark:[color:var(--shk-surface-600)]]=\"!isItemActive(item)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isItemActive(item)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isItemActive(item)\"\n [class.hover:[color:var(--shk-surface-900)]]=\"!isItemActive(item)\"\n [class.dark:hover:[color:var(--shk-surface-700)]]=\"!isItemActive(item)\"\n >\n @if (item.icon) {\n <svg [lucideIcon]=\"getIcon(item.icon)\" class=\"w-5 h-5 shrink-0\"></svg>\n }\n <span class=\"flex-1 text-left whitespace-nowrap overflow-hidden\">{{ label(item) }}</span>\n @if (item.badge !== undefined) {\n <span\n class=\"text-xs font-bold px-2 py-0.5 rounded-full _shk-bg-primary _shk-text-white shrink-0\"\n [class.hidden]=\"collapsed()\"\n >\n {{ item.badge }}\n </span>\n }\n @if (isItemActive(item)) {\n <span class=\"w-1.5 h-1.5 rounded-full bg-white shrink-0\"></span>\n }\n </button>\n }\n </li>\n }\n }\n </ul>\n </nav>\n\n <!-- Footer -->\n <div class=\"shrink-0 p-2 [&:empty]:hidden\">\n <ng-content select=\"[sidebarFooter]\"></ng-content>\n </div>\n</aside>\n", styles: [":host{display:block}.sidebar-transition{transition:width .3s cubic-bezier(.4,0,.2,1),transform .3s cubic-bezier(.4,0,.2,1)}.sidebar-scroll{overflow-y:auto;overflow-x:visible}@media(min-width:1024px){.sidebar-mobile-transform{transform:none!important}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: LucideDynamicIcon, selector: "svg[lucideIcon]", inputs: ["lucideIcon"] }, { kind: "component", type: TooltipComponent, selector: "shk-tooltip", inputs: ["text", "position", "mode", "offset"] }] }); }
|
|
2977
|
+
}
|
|
2978
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: SidebarComponent, decorators: [{
|
|
2979
|
+
type: Component,
|
|
2980
|
+
args: [{ selector: 'shk-sidebar', standalone: true, imports: [CommonModule, LucideDynamicIcon, TooltipComponent], template: "@if (responsive() && mobileOpen()) {\n <!-- Mobile overlay backdrop (sibling of aside: must NOT be inside the\n transformed aside, otherwise it becomes its containing block and\n only covers the sidebar, also blocking nav clicks on mobile) -->\n <div\n class=\"fixed inset-0 bg-black/50 z-30 lg:hidden\"\n (click)=\"mobileOpen.set(false)\"\n ></div>\n}\n\n<aside\n [class.fixed]=\"fixed()\"\n [class.relative]=\"!fixed()\"\n [class.h-screen]=\"fixed()\"\n [class.h-full]=\"!fixed()\"\n class=\"top-0 left-0 flex flex-col shrink-0 sidebar-transition sidebar-mobile-transform z-40 _shk-bg-white dark:[background-color:var(--shk-surface-50)] border-r _shk-border dark:[border-color:var(--shk-surface-100)]\"\n [class.shadow-sm]=\"hasShadow()\"\n [style.width]=\"width()\"\n [style.transform]=\"responsive() ? (mobileOpen() ? 'translateX(0)' : 'translateX(-100%)') : null\"\n>\n <!-- Logo / Brand -->\n @if (logo() || title() || subtitle()) {\n <div\n class=\"flex items-center h-20 px-4 border-b _shk-border dark:[border-color:var(--shk-surface-100)] shrink-0\"\n >\n <div class=\"flex items-center gap-3 overflow-hidden\">\n @if (logo()) {\n <img [src]=\"logo()\" alt=\"Logo\" class=\"h-16 w-16 shrink-0 object-contain\" />\n }\n @if (!collapsed() && (title() || subtitle())) {\n <div class=\"flex flex-col leading-tight whitespace-nowrap\">\n @if (title()) {\n <span class=\"text-lg font-bold _shk-text-surface-800 dark:[color:var(--shk-surface-800)]\">\n {{ title() }}\n </span>\n }\n @if (subtitle()) {\n <span class=\"text-sm _shk-text-surface-500 dark:[color:var(--shk-surface-500)]\">\n {{ subtitle() }}\n </span>\n }\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Toggle button -->\n @if (showToggle() && collapsible()) {\n <button\n type=\"button\"\n (click)=\"onToggle()\"\n class=\"group absolute -right-3 top-20 z-50 w-6 h-6 rounded-full bg-white dark:[background-color:var(--shk-surface-100)] border _shk-border dark:[border-color:var(--shk-surface-200)] shadow-md max-lg:hidden flex items-center justify-center _shk-text-surface-600 dark:[color:var(--shk-surface-600)] hover:[background-color:var(--shk-primary-50)] dark:hover:[background-color:var(--shk-surface-200)] hover:[color:var(--shk-primary-600)] dark:hover:[color:var(--shk-primary-400)] transition-colors\"\n >\n @if (collapsed()) {\n <svg [lucideIcon]=\"getIcon('chevron-right')\" class=\"w-3 h-3\"></svg>\n } @else {\n <svg [lucideIcon]=\"getIcon('chevron-left')\" class=\"w-3 h-3\"></svg>\n }\n <span\n class=\"absolute left-full ml-1 top-1/2 -translate-y-1/2 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\"\n >\n {{ collapsed() ? expandTooltip() : collapseTooltip() }}\n </span>\n </button>\n }\n\n <ng-content select=\"[sidebarHeader]\"></ng-content>\n\n <!-- Custom content between header and nav -->\n <ng-content select=\"[sidebarContent]\"></ng-content>\n\n <!-- Navigation -->\n <nav class=\"flex-1 sidebar-scroll _shk-scrollbar py-4 px-3\">\n <ul class=\"space-y-1\">\n @for (item of navItems(); track item.id) {\n @if (item.separator) {\n <li class=\"my-2 border-t _shk-border dark:[border-color:var(--shk-surface-200)]\"></li>\n }\n\n @if (item.children?.length) {\n <!-- Group -->\n <li>\n @if (collapsed()) {\n <shk-tooltip [text]=\"label(item)\" position=\"right\" mode=\"fixed\">\n <div\n class=\"flex items-center justify-center px-3 py-2.5 rounded-lg transition-all duration-200\"\n [class._shk-bg-primary]=\"isGroupActive(item)\"\n [class._shk-text-white]=\"isGroupActive(item)\"\n [class._shk-text-surface-500]=\"!isGroupActive(item)\"\n >\n @if (item.icon) {\n <svg [lucideIcon]=\"getIcon(item.icon)\" class=\"w-5 h-5 shrink-0\"></svg>\n }\n </div>\n </shk-tooltip>\n } @else {\n <button\n type=\"button\"\n (click)=\"toggleGroup(item)\"\n class=\"w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all duration-200 group relative\"\n [class._shk-bg-primary]=\"isGroupActive(item)\"\n [class._shk-text-white]=\"isGroupActive(item)\"\n [class.shadow-md]=\"isGroupActive(item)\"\n [class._shk-text-surface-700]=\"!isGroupActive(item)\"\n [class.dark:[color:var(--shk-surface-600)]]=\"!isGroupActive(item)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isGroupActive(item)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isGroupActive(item)\"\n [class.hover:[color:var(--shk-surface-900)]]=\"!isGroupActive(item)\"\n [class.dark:hover:[color:var(--shk-surface-700)]]=\"!isGroupActive(item)\"\n >\n @if (item.icon) {\n <svg [lucideIcon]=\"getIcon(item.icon)\" class=\"w-5 h-5 shrink-0\"></svg>\n }\n <span class=\"flex-1 text-left whitespace-nowrap overflow-hidden\">{{ label(item) }}</span>\n <svg\n [lucideIcon]=\"getIcon('chevron-down')\"\n class=\"w-4 h-4 transition-transform duration-200 shrink-0\"\n [class.rotate-180]=\"isGroupExpanded(item)\"\n ></svg>\n </button>\n\n @if (isGroupExpanded(item)) {\n <ul class=\"ml-3 mt-1 space-y-1 border-l-2 _shk-border dark:[border-color:var(--shk-surface-200)] pl-2\">\n @for (child of item.children; track child.id) {\n <li>\n <button\n type=\"button\"\n (click)=\"onItemClick(child)\"\n class=\"w-full flex items-center gap-3 px-3 py-2 rounded-lg text-sm font-medium transition-all duration-200\"\n [class._shk-bg-primary-soft]=\"isItemActive(child)\"\n [class._shk-bg-primary-soft-dark]=\"isItemActive(child)\"\n [class._shk-text-primary-700]=\"isItemActive(child)\"\n [class.dark:[color:var(--shk-primary-300)]]=\"isItemActive(child)\"\n [class._shk-text-surface-600]=\"!isItemActive(child)\"\n [class.dark:[color:var(--shk-surface-400)]]=\"!isItemActive(child)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isItemActive(child)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isItemActive(child)\"\n [class.hover:[color:var(--shk-surface-900)]]=\"!isItemActive(child)\"\n [class.dark:hover:[color:var(--shk-surface-700)]]=\"!isItemActive(child)\"\n >\n @if (child.icon) {\n <svg [lucideIcon]=\"getIcon(child.icon)\" class=\"w-4 h-4 shrink-0\"></svg>\n }\n <span class=\"whitespace-nowrap overflow-hidden\">{{ label(child) }}</span>\n @if (isItemActive(child)) {\n <span class=\"w-1.5 h-1.5 rounded-full _shk-bg-primary shrink-0 ml-auto\"></span>\n }\n </button>\n </li>\n }\n </ul>\n }\n }\n </li>\n } @else {\n <!-- Standalone item -->\n <li>\n @if (collapsed()) {\n <shk-tooltip [text]=\"label(item)\" position=\"right\" mode=\"fixed\">\n <button\n type=\"button\"\n (click)=\"onItemClick(item)\"\n class=\"w-full flex items-center justify-center px-3 py-2.5 rounded-lg text-sm font-medium transition-all duration-200\"\n [class._shk-bg-primary]=\"isItemActive(item)\"\n [class._shk-text-white]=\"isItemActive(item)\"\n [class.shadow-md]=\"isItemActive(item)\"\n [class._shk-text-surface-700]=\"!isItemActive(item)\"\n [class.dark:[color:var(--shk-surface-600)]]=\"!isItemActive(item)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isItemActive(item)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isItemActive(item)\"\n [class.hover:[color:var(--shk-surface-900)]]=\"!isItemActive(item)\"\n [class.dark:hover:[color:var(--shk-surface-700)]]=\"!isItemActive(item)\"\n >\n @if (item.icon) {\n <svg [lucideIcon]=\"getIcon(item.icon)\" class=\"w-5 h-5 shrink-0\"></svg>\n }\n </button>\n </shk-tooltip>\n } @else {\n <button\n type=\"button\"\n (click)=\"onItemClick(item)\"\n class=\"w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all duration-200\"\n [class._shk-bg-primary]=\"isItemActive(item)\"\n [class._shk-text-white]=\"isItemActive(item)\"\n [class.shadow-md]=\"isItemActive(item)\"\n [class._shk-text-surface-700]=\"!isItemActive(item)\"\n [class.dark:[color:var(--shk-surface-600)]]=\"!isItemActive(item)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isItemActive(item)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isItemActive(item)\"\n [class.hover:[color:var(--shk-surface-900)]]=\"!isItemActive(item)\"\n [class.dark:hover:[color:var(--shk-surface-700)]]=\"!isItemActive(item)\"\n >\n @if (item.icon) {\n <svg [lucideIcon]=\"getIcon(item.icon)\" class=\"w-5 h-5 shrink-0\"></svg>\n }\n <span class=\"flex-1 text-left whitespace-nowrap overflow-hidden\">{{ label(item) }}</span>\n @if (item.badge !== undefined) {\n <span\n class=\"text-xs font-bold px-2 py-0.5 rounded-full _shk-bg-primary _shk-text-white shrink-0\"\n [class.hidden]=\"collapsed()\"\n >\n {{ item.badge }}\n </span>\n }\n @if (isItemActive(item)) {\n <span class=\"w-1.5 h-1.5 rounded-full bg-white shrink-0\"></span>\n }\n </button>\n }\n </li>\n }\n }\n </ul>\n </nav>\n\n <!-- Footer -->\n <div class=\"shrink-0 p-2 [&:empty]:hidden\">\n <ng-content select=\"[sidebarFooter]\"></ng-content>\n </div>\n</aside>\n", styles: [":host{display:block}.sidebar-transition{transition:width .3s cubic-bezier(.4,0,.2,1),transform .3s cubic-bezier(.4,0,.2,1)}.sidebar-scroll{overflow-y:auto;overflow-x:visible}@media(min-width:1024px){.sidebar-mobile-transform{transform:none!important}}\n"] }]
|
|
2981
|
+
}], ctorParameters: () => [{ type: Object, decorators: [{
|
|
2982
|
+
type: Inject,
|
|
2983
|
+
args: [PLATFORM_ID]
|
|
2984
|
+
}] }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], groups: [{ type: i0.Input, args: [{ isSignal: true, alias: "groups", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], subtitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "subtitle", required: false }] }], logo: [{ type: i0.Input, args: [{ isSignal: true, alias: "logo", required: false }] }], activeItemId: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeItemId", required: false }] }], userRole: [{ type: i0.Input, args: [{ isSignal: true, alias: "userRole", required: false }] }], collapsible: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsible", required: false }] }], showToggle: [{ type: i0.Input, args: [{ isSignal: true, alias: "showToggle", required: false }] }], responsive: [{ type: i0.Input, args: [{ isSignal: true, alias: "responsive", required: false }] }], fixed: [{ type: i0.Input, args: [{ isSignal: true, alias: "fixed", required: false }] }], hasShadow: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasShadow", required: false }] }], expandedWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandedWidth", required: false }] }], collapsedWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsedWidth", required: false }] }], defaultExpanded: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultExpanded", required: false }] }], labelPipe: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelPipe", required: false }] }], expandTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandTooltip", required: false }] }], collapseTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapseTooltip", required: false }] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }, { type: i0.Output, args: ["collapsedChange"] }], mobileOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "mobileOpen", required: false }] }, { type: i0.Output, args: ["mobileOpenChange"] }], itemClick: [{ type: i0.Output, args: ["itemClick"] }], toggle: [{ type: i0.Output, args: ["toggle"] }], onResize: [{
|
|
2985
|
+
type: HostListener,
|
|
2986
|
+
args: ['window:resize', ['$event']]
|
|
2987
|
+
}] } });
|
|
2988
|
+
|
|
2989
|
+
const ICONS = {
|
|
2990
|
+
shield: LucideShield,
|
|
2991
|
+
building: LucideBuilding,
|
|
2992
|
+
'building-2': LucideBuilding2,
|
|
2993
|
+
'layer-group': LucideLayers,
|
|
2994
|
+
'puzzle-piece': LucidePuzzle,
|
|
2995
|
+
'chart-pie': LucideChartPie,
|
|
2996
|
+
'chart-line': LucideChartLine,
|
|
2997
|
+
'credit-card': LucideCreditCard,
|
|
2998
|
+
'id-card': LucideIdCard,
|
|
2999
|
+
briefcase: LucideBriefcase,
|
|
3000
|
+
truck: LucideTruck,
|
|
3001
|
+
tags: LucideTags,
|
|
3002
|
+
tag: LucideTag,
|
|
3003
|
+
package: LucidePackage,
|
|
3004
|
+
box: LucideBox,
|
|
3005
|
+
'dollar-sign': LucideDollarSign,
|
|
3006
|
+
wallet: LucideWallet,
|
|
3007
|
+
percent: LucidePercent,
|
|
3008
|
+
sliders: LucideSliders,
|
|
3009
|
+
search: LucideSearch,
|
|
3010
|
+
calendar: LucideCalendar,
|
|
3011
|
+
'calendar-check': LucideCalendarCheck,
|
|
3012
|
+
users: LucideUsers,
|
|
3013
|
+
'user-cog': LucideUserCog,
|
|
3014
|
+
globe: LucideGlobe,
|
|
3015
|
+
'log-out': LucideLogOut,
|
|
3016
|
+
logout: LucideLogOut,
|
|
3017
|
+
'panel-right': LucidePanelRight,
|
|
3018
|
+
home: LucideHome,
|
|
3019
|
+
receipt: LucideReceipt,
|
|
3020
|
+
bot: LucideBot,
|
|
3021
|
+
star: LucideStar,
|
|
3022
|
+
'file-invoice-dollar': LucideBanknote,
|
|
3023
|
+
'file-contract': LucideFileText,
|
|
3024
|
+
user: LucideUser,
|
|
3025
|
+
menu: LucideMenu,
|
|
3026
|
+
'chevron-down': LucideChevronDown,
|
|
3027
|
+
x: LucideX,
|
|
3028
|
+
};
|
|
3029
|
+
function getIcon$3(name) {
|
|
3030
|
+
if (!name)
|
|
3031
|
+
return null;
|
|
3032
|
+
return ICONS[name] ?? LucideMenu;
|
|
3033
|
+
}
|
|
3034
|
+
class RailSidebarComponent {
|
|
3035
|
+
constructor() {
|
|
3036
|
+
this.sections = input([], ...(ngDevMode ? [{ debugName: "sections" }] : /* istanbul ignore next */ []));
|
|
3037
|
+
this.activeUrl = input('', ...(ngDevMode ? [{ debugName: "activeUrl" }] : /* istanbul ignore next */ []));
|
|
3038
|
+
this.activeSectionKey = model('', ...(ngDevMode ? [{ debugName: "activeSectionKey" }] : /* istanbul ignore next */ []));
|
|
3039
|
+
this.collapsed = model(false, ...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
|
|
3040
|
+
this.activeLang = input('es', ...(ngDevMode ? [{ debugName: "activeLang" }] : /* istanbul ignore next */ []));
|
|
3041
|
+
this.langs = input(['es', 'en'], ...(ngDevMode ? [{ debugName: "langs" }] : /* istanbul ignore next */ []));
|
|
3042
|
+
this.logo = input('', ...(ngDevMode ? [{ debugName: "logo" }] : /* istanbul ignore next */ []));
|
|
3043
|
+
this.appName = input('', ...(ngDevMode ? [{ debugName: "appName" }] : /* istanbul ignore next */ []));
|
|
3044
|
+
this.userRole = input('', ...(ngDevMode ? [{ debugName: "userRole" }] : /* istanbul ignore next */ []));
|
|
3045
|
+
this.labelPipe = input((label) => label, ...(ngDevMode ? [{ debugName: "labelPipe" }] : /* istanbul ignore next */ []));
|
|
3046
|
+
this.railWidth = input('4.5rem', ...(ngDevMode ? [{ debugName: "railWidth" }] : /* istanbul ignore next */ []));
|
|
3047
|
+
this.expandedWidth = input('16.5rem', ...(ngDevMode ? [{ debugName: "expandedWidth" }] : /* istanbul ignore next */ []));
|
|
3048
|
+
this.workspaceTooltip = input('Inicio', ...(ngDevMode ? [{ debugName: "workspaceTooltip" }] : /* istanbul ignore next */ []));
|
|
3049
|
+
this.logoutTooltip = input('Cerrar sesión', ...(ngDevMode ? [{ debugName: "logoutTooltip" }] : /* istanbul ignore next */ []));
|
|
3050
|
+
this.collapseTooltip = input('Colapsar', ...(ngDevMode ? [{ debugName: "collapseTooltip" }] : /* istanbul ignore next */ []));
|
|
3051
|
+
this.expandTooltip = input('Expandir', ...(ngDevMode ? [{ debugName: "expandTooltip" }] : /* istanbul ignore next */ []));
|
|
3052
|
+
this.sectionSelected = output();
|
|
3053
|
+
this.itemClick = output();
|
|
3054
|
+
this.setLang = output();
|
|
3055
|
+
this.logoutRequested = output();
|
|
3056
|
+
this.toggleSidebar = output();
|
|
3057
|
+
this.workspaceClick = output();
|
|
3058
|
+
this.getIcon = getIcon$3;
|
|
3059
|
+
this.expandedGroups = signal(new Set(), ...(ngDevMode ? [{ debugName: "expandedGroups" }] : /* istanbul ignore next */ []));
|
|
3060
|
+
this.width = computed(() => this.collapsed() ? this.railWidth() : this.expandedWidth(), ...(ngDevMode ? [{ debugName: "width" }] : /* istanbul ignore next */ []));
|
|
3061
|
+
this.activeSection = computed(() => this.sections().find((s) => s.key === this.activeSectionKey()) ?? null, ...(ngDevMode ? [{ debugName: "activeSection" }] : /* istanbul ignore next */ []));
|
|
3062
|
+
this.navItems = computed(() => {
|
|
3063
|
+
const role = this.userRole();
|
|
3064
|
+
const items = this.activeSection()?.items ?? [];
|
|
3065
|
+
return items.filter((item) => {
|
|
3066
|
+
if (!item.roles || item.roles.length === 0)
|
|
3067
|
+
return true;
|
|
3068
|
+
return role ? item.roles.includes(role) : false;
|
|
3069
|
+
});
|
|
3070
|
+
}, ...(ngDevMode ? [{ debugName: "navItems" }] : /* istanbul ignore next */ []));
|
|
3071
|
+
effect(() => {
|
|
3072
|
+
const url = this.activeUrl();
|
|
3073
|
+
if (!url)
|
|
3074
|
+
return;
|
|
3075
|
+
const section = this.sections().find((s) => {
|
|
3076
|
+
if (s.matchPrefixes?.length) {
|
|
3077
|
+
return s.matchPrefixes.some((prefix) => url.startsWith(prefix));
|
|
3078
|
+
}
|
|
3079
|
+
return s.routerLink ? url.startsWith(s.routerLink) : false;
|
|
3080
|
+
});
|
|
3081
|
+
if (section) {
|
|
3082
|
+
this.activeSectionKey.set(section.key);
|
|
3083
|
+
}
|
|
3084
|
+
});
|
|
3085
|
+
}
|
|
3086
|
+
label(label) {
|
|
3087
|
+
return this.labelPipe()(label);
|
|
3088
|
+
}
|
|
3089
|
+
isSectionActive(section) {
|
|
3090
|
+
return section.key === this.activeSectionKey();
|
|
3091
|
+
}
|
|
3092
|
+
isItemActive(item) {
|
|
3093
|
+
if (!item.routerLink)
|
|
3094
|
+
return false;
|
|
3095
|
+
return this.bestMatchItem() === item;
|
|
3096
|
+
}
|
|
3097
|
+
isGroupActive(item) {
|
|
3098
|
+
return (item.children?.some((c) => c.routerLink && this.matchesUrl(c.routerLink, this.activeUrl())) ?? false);
|
|
3099
|
+
}
|
|
3100
|
+
matchesUrl(routerLink, url) {
|
|
3101
|
+
return url === routerLink || url.startsWith(routerLink + '/');
|
|
3102
|
+
}
|
|
3103
|
+
bestMatchItem() {
|
|
3104
|
+
const url = this.activeUrl();
|
|
3105
|
+
let best = null;
|
|
3106
|
+
for (const item of this.navItems()) {
|
|
3107
|
+
if (item.routerLink && this.matchesUrl(item.routerLink, url)) {
|
|
3108
|
+
if (!best || item.routerLink.length > best.routerLink.length) {
|
|
3109
|
+
best = item;
|
|
3110
|
+
}
|
|
3111
|
+
}
|
|
3112
|
+
for (const child of item.children ?? []) {
|
|
3113
|
+
if (!child.routerLink || !this.matchesUrl(child.routerLink, url))
|
|
3114
|
+
continue;
|
|
3115
|
+
if (!best || child.routerLink.length > best.routerLink.length) {
|
|
3116
|
+
best = child;
|
|
3117
|
+
}
|
|
3118
|
+
}
|
|
3119
|
+
}
|
|
3120
|
+
return best;
|
|
3121
|
+
}
|
|
3122
|
+
isGroupExpanded(item) {
|
|
3123
|
+
return this.expandedGroups().has(item.id);
|
|
3124
|
+
}
|
|
3125
|
+
toggleGroup(item) {
|
|
3126
|
+
this.expandedGroups.update((set) => {
|
|
3127
|
+
const next = new Set(set);
|
|
3128
|
+
if (next.has(item.id)) {
|
|
3129
|
+
next.delete(item.id);
|
|
3130
|
+
}
|
|
3131
|
+
else {
|
|
3132
|
+
next.add(item.id);
|
|
3133
|
+
}
|
|
3134
|
+
return next;
|
|
2832
3135
|
});
|
|
2833
3136
|
}
|
|
3137
|
+
onSectionClick(section) {
|
|
3138
|
+
this.activeSectionKey.set(section.key);
|
|
3139
|
+
this.sectionSelected.emit({ key: section.key, routerLink: section.routerLink });
|
|
3140
|
+
if (this.collapsed()) {
|
|
3141
|
+
this.collapsed.set(false);
|
|
3142
|
+
this.toggleSidebar.emit(false);
|
|
3143
|
+
}
|
|
3144
|
+
}
|
|
3145
|
+
onItemClick(item) {
|
|
3146
|
+
if (item.disabled)
|
|
3147
|
+
return;
|
|
3148
|
+
this.itemClick.emit(item);
|
|
3149
|
+
}
|
|
3150
|
+
onWorkspace() {
|
|
3151
|
+
this.workspaceClick.emit();
|
|
3152
|
+
if (this.collapsed()) {
|
|
3153
|
+
this.collapsed.set(false);
|
|
3154
|
+
this.toggleSidebar.emit(false);
|
|
3155
|
+
}
|
|
3156
|
+
}
|
|
3157
|
+
onToggleLang() {
|
|
3158
|
+
const langs = this.langs();
|
|
3159
|
+
if (langs.length === 0)
|
|
3160
|
+
return;
|
|
3161
|
+
const idx = langs.indexOf(this.activeLang());
|
|
3162
|
+
const next = langs[(idx + 1) % langs.length] ?? langs[0];
|
|
3163
|
+
this.setLang.emit(next);
|
|
3164
|
+
}
|
|
3165
|
+
onToggleSidebar() {
|
|
3166
|
+
this.collapsed.update((v) => !v);
|
|
3167
|
+
this.toggleSidebar.emit(this.collapsed());
|
|
3168
|
+
}
|
|
3169
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: RailSidebarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3170
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: RailSidebarComponent, isStandalone: true, selector: "shk-rail-sidebar", inputs: { sections: { classPropertyName: "sections", publicName: "sections", isSignal: true, isRequired: false, transformFunction: null }, activeUrl: { classPropertyName: "activeUrl", publicName: "activeUrl", isSignal: true, isRequired: false, transformFunction: null }, activeSectionKey: { classPropertyName: "activeSectionKey", publicName: "activeSectionKey", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, activeLang: { classPropertyName: "activeLang", publicName: "activeLang", isSignal: true, isRequired: false, transformFunction: null }, langs: { classPropertyName: "langs", publicName: "langs", isSignal: true, isRequired: false, transformFunction: null }, logo: { classPropertyName: "logo", publicName: "logo", isSignal: true, isRequired: false, transformFunction: null }, appName: { classPropertyName: "appName", publicName: "appName", isSignal: true, isRequired: false, transformFunction: null }, userRole: { classPropertyName: "userRole", publicName: "userRole", isSignal: true, isRequired: false, transformFunction: null }, labelPipe: { classPropertyName: "labelPipe", publicName: "labelPipe", isSignal: true, isRequired: false, transformFunction: null }, railWidth: { classPropertyName: "railWidth", publicName: "railWidth", isSignal: true, isRequired: false, transformFunction: null }, expandedWidth: { classPropertyName: "expandedWidth", publicName: "expandedWidth", isSignal: true, isRequired: false, transformFunction: null }, workspaceTooltip: { classPropertyName: "workspaceTooltip", publicName: "workspaceTooltip", isSignal: true, isRequired: false, transformFunction: null }, logoutTooltip: { classPropertyName: "logoutTooltip", publicName: "logoutTooltip", isSignal: true, isRequired: false, transformFunction: null }, collapseTooltip: { classPropertyName: "collapseTooltip", publicName: "collapseTooltip", isSignal: true, isRequired: false, transformFunction: null }, expandTooltip: { classPropertyName: "expandTooltip", publicName: "expandTooltip", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeSectionKey: "activeSectionKeyChange", collapsed: "collapsedChange", sectionSelected: "sectionSelected", itemClick: "itemClick", setLang: "setLang", logoutRequested: "logoutRequested", toggleSidebar: "toggleSidebar", workspaceClick: "workspaceClick" }, ngImport: i0, template: "<aside\n class=\"h-full flex overflow-hidden shrink-0 _shk-bg-white dark:[background-color:var(--shk-surface-50)] border-r _shk-border dark:[border-color:var(--shk-surface-100)]\"\n [style.width]=\"width()\"\n>\n <!-- Rail: vertical icon column -->\n <div\n class=\"h-full flex flex-col items-center shrink-0 px-[0.3rem] py-2 gap-1 border-r _shk-border dark:[border-color:var(--shk-surface-100)]\"\n [style.width]=\"railWidth()\"\n >\n <!-- Workspace / logo -->\n <div class=\"flex items-center justify-center w-full\">\n <button\n type=\"button\"\n (click)=\"onWorkspace()\"\n [class.is-collapsed]=\"collapsed()\"\n class=\"rail-workspace w-[3.2rem] h-[3.2rem] rounded-xl _shk-bg-surface-100 dark:[background-color:var(--shk-surface-200)] border-none grid place-items-center p-0 relative transition-all\"\n [title]=\"workspaceTooltip()\"\n >\n @if (logo()) {\n <img [src]=\"logo()\" alt=\"Logo\" class=\"rail-app-icon w-8 h-8 object-contain\" />\n } @else {\n <svg [lucideIcon]=\"getIcon('menu')\" class=\"rail-app-icon w-6 h-6 _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\"></svg>\n }\n @if (collapsed()) {\n <svg [lucideIcon]=\"getIcon('panel-right')\" class=\"rail-toggle-icon w-5 h-5 _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\"></svg>\n }\n </button>\n </div>\n\n <!-- Section actions -->\n <div class=\"rail-actions flex-1 flex flex-col items-center gap-1 pt-1\">\n @for (section of sections(); track section.key) {\n <shk-tooltip [text]=\"label(section.label)\" position=\"right\" mode=\"fixed\">\n <button\n type=\"button\"\n (click)=\"onSectionClick(section)\"\n class=\"rail-icon w-[3.4rem] h-[3.4rem] rounded-[0.85rem] grid place-items-center transition-all cursor-pointer\"\n [class.is-active]=\"isSectionActive(section)\"\n [attr.aria-label]=\"label(section.label)\"\n >\n <svg [lucideIcon]=\"getIcon(section.icon)\" class=\"w-5 h-5\"></svg>\n </button>\n </shk-tooltip>\n }\n </div>\n\n <!-- Bottom: language + logout -->\n <div class=\"rail-bottom mt-auto flex flex-col items-center gap-1\">\n <button\n type=\"button\"\n (click)=\"onToggleLang()\"\n class=\"rail-icon w-[3.4rem] h-[3.4rem] rounded-[0.85rem] grid place-items-center transition-all cursor-pointer\"\n [title]=\"activeLang()\"\n >\n <div class=\"flex flex-col items-center gap-[0.15rem]\">\n <svg [lucideIcon]=\"getIcon('globe')\" class=\"w-5 h-5\"></svg>\n <span class=\"rail-lang-code text-[0.5rem] font-bold tracking-[0.05em] leading-none\">{{ activeLang() | uppercase }}</span>\n </div>\n </button>\n\n <button\n type=\"button\"\n (click)=\"logoutRequested.emit()\"\n class=\"rail-icon rail-logout w-[3.4rem] h-[3.4rem] rounded-[0.85rem] grid place-items-center transition-all cursor-pointer\"\n [title]=\"logoutTooltip()\"\n >\n <svg [lucideIcon]=\"getIcon('log-out')\" class=\"w-5 h-5\"></svg>\n </button>\n </div>\n </div>\n\n <!-- Nav: section panel (hidden when collapsed) -->\n @if (!collapsed()) {\n <div class=\"flex-1 min-w-0 flex flex-col _shk-bg-white dark:[background-color:var(--shk-surface-50)]\">\n <!-- Brand header -->\n <div class=\"flex items-center justify-between gap-2 px-3 py-4 border-b _shk-border dark:[border-color:var(--shk-surface-100)]\">\n <span class=\"nav-app text-base font-bold whitespace-nowrap overflow-hidden text-ellipsis _shk-text-surface-800 dark:[color:var(--shk-surface-800)]\">\n {{ appName() }}\n </span>\n <button\n type=\"button\"\n (click)=\"onToggleSidebar()\"\n class=\"nav-toggle w-[1.8rem] h-[1.8rem] rounded-lg border-none bg-transparent grid place-items-center cursor-pointer shrink-0 transition-colors _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\"\n [title]=\"collapseTooltip()\"\n >\n <svg [lucideIcon]=\"getIcon('panel-right')\" class=\"w-4 h-4\"></svg>\n </button>\n </div>\n\n <!-- Menu -->\n <nav class=\"flex-1 overflow-y-auto _shk-scrollbar px-2 py-3\">\n @if (activeSection()) {\n <div class=\"px-2 pb-3\">\n <span class=\"nav-section-label text-xs font-bold tracking-[0.08em] uppercase _shk-text-surface-400 dark:[color:var(--shk-surface-500)] block whitespace-nowrap overflow-hidden text-ellipsis\">\n {{ label(activeSection()!.label) }}\n </span>\n </div>\n }\n\n <ul class=\"space-y-1\">\n @for (item of navItems(); track item.id) {\n @if (item.separator) {\n <li class=\"my-2 border-t _shk-border dark:[border-color:var(--shk-surface-200)]\"></li>\n }\n\n @if (item.children?.length) {\n <!-- Expandable group -->\n <li>\n <button\n type=\"button\"\n (click)=\"toggleGroup(item)\"\n class=\"w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all duration-200\"\n [class._shk-bg-primary]=\"isGroupActive(item)\"\n [class._shk-text-white]=\"isGroupActive(item)\"\n [class.shadow-md]=\"isGroupActive(item)\"\n [class._shk-text-surface-700]=\"!isGroupActive(item)\"\n [class.dark:[color:var(--shk-surface-600)]]=\"!isGroupActive(item)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isGroupActive(item)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isGroupActive(item)\"\n >\n @if (item.icon) {\n <svg [lucideIcon]=\"getIcon(item.icon)\" class=\"w-5 h-5 shrink-0\"></svg>\n }\n <span class=\"flex-1 text-left whitespace-nowrap overflow-hidden\">{{ label(item.label) }}</span>\n <svg\n [lucideIcon]=\"getIcon('chevron-down')\"\n class=\"w-4 h-4 transition-transform duration-200 shrink-0\"\n [class.rotate-180]=\"isGroupExpanded(item)\"\n ></svg>\n </button>\n\n @if (isGroupExpanded(item)) {\n <ul class=\"ml-3 mt-1 space-y-1 border-l-2 _shk-border dark:[border-color:var(--shk-surface-200)] pl-2\">\n @for (child of item.children; track child.id) {\n <li>\n <button\n type=\"button\"\n (click)=\"onItemClick(child)\"\n class=\"w-full flex items-center gap-3 px-3 py-2 rounded-lg text-sm font-medium transition-all duration-200\"\n [class._shk-bg-primary-soft]=\"isItemActive(child)\"\n [class._shk-bg-primary-soft-dark]=\"isItemActive(child)\"\n [class._shk-text-primary-700]=\"isItemActive(child)\"\n [class.dark:[color:var(--shk-primary-300)]]=\"isItemActive(child)\"\n [class._shk-text-surface-600]=\"!isItemActive(child)\"\n [class.dark:[color:var(--shk-surface-400)]]=\"!isItemActive(child)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isItemActive(child)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isItemActive(child)\"\n [class.hover:[color:var(--shk-surface-900)]]=\"!isItemActive(child)\"\n [class.dark:hover:[color:var(--shk-surface-700)]]=\"!isItemActive(child)\"\n >\n @if (child.icon) {\n <svg [lucideIcon]=\"getIcon(child.icon)\" class=\"w-4 h-4 shrink-0\"></svg>\n }\n <span class=\"whitespace-nowrap overflow-hidden\">{{ label(child.label) }}</span>\n @if (isItemActive(child)) {\n <span class=\"w-1.5 h-1.5 rounded-full _shk-bg-primary shrink-0 ml-auto\"></span>\n }\n </button>\n </li>\n }\n </ul>\n }\n </li>\n } @else {\n <!-- Standalone item -->\n <li>\n <button\n type=\"button\"\n (click)=\"onItemClick(item)\"\n class=\"w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all duration-200\"\n [class._shk-bg-primary]=\"isItemActive(item)\"\n [class._shk-text-white]=\"isItemActive(item)\"\n [class.shadow-md]=\"isItemActive(item)\"\n [class._shk-text-surface-700]=\"!isItemActive(item)\"\n [class.dark:[color:var(--shk-surface-600)]]=\"!isItemActive(item)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isItemActive(item)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isItemActive(item)\"\n >\n @if (item.icon) {\n <svg [lucideIcon]=\"getIcon(item.icon)\" class=\"w-5 h-5 shrink-0\"></svg>\n }\n <span class=\"flex-1 text-left whitespace-nowrap overflow-hidden\">{{ label(item.label) }}</span>\n @if (item.badge !== undefined) {\n <span class=\"text-xs font-bold px-2 py-0.5 rounded-full _shk-bg-primary _shk-text-white shrink-0\">\n {{ item.badge }}\n </span>\n }\n </button>\n </li>\n }\n }\n </ul>\n </nav>\n </div>\n }\n</aside>\n", styles: [":host{display:block}.rail-workspace{cursor:pointer;transition:opacity .2s ease,box-shadow .2s ease}.rail-workspace.is-collapsed:hover{cursor:col-resize}.rail-workspace .rail-app-icon,.rail-workspace .rail-toggle-icon{grid-area:1 / 1 / 2 / 2;transition:opacity .2s ease}.rail-toggle-icon,.rail-workspace.is-collapsed:hover .rail-app-icon{opacity:0}.rail-workspace.is-collapsed:hover .rail-toggle-icon{opacity:1}.rail-icon{background:transparent;color:var(--shk-surface-700);border:1px solid transparent;transition:transform .18s ease,color .18s ease,background-color .18s ease,box-shadow .18s ease}.rail-icon svg{stroke-width:1.8}.rail-icon:hover{background:var(--shk-surface-100);color:var(--shk-primary-600)}.dark .rail-icon:hover{background:var(--shk-surface-200);color:var(--shk-primary-400)}.rail-icon.is-active{background:var(--shk-primary-600);color:#fff;box-shadow:0 1px 2px #0003}.dark .rail-icon.is-active{background:var(--shk-primary-500);color:#fff}.rail-logout:hover{color:var(--shk-error-500)}.dark .rail-logout:hover{color:var(--shk-error-400)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: LucideDynamicIcon, selector: "svg[lucideIcon]", inputs: ["lucideIcon"] }, { kind: "component", type: TooltipComponent, selector: "shk-tooltip", inputs: ["text", "position", "mode", "offset"] }, { kind: "pipe", type: i1.UpperCasePipe, name: "uppercase" }] }); }
|
|
3171
|
+
}
|
|
3172
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: RailSidebarComponent, decorators: [{
|
|
3173
|
+
type: Component,
|
|
3174
|
+
args: [{ selector: 'shk-rail-sidebar', standalone: true, imports: [CommonModule, LucideDynamicIcon, TooltipComponent], template: "<aside\n class=\"h-full flex overflow-hidden shrink-0 _shk-bg-white dark:[background-color:var(--shk-surface-50)] border-r _shk-border dark:[border-color:var(--shk-surface-100)]\"\n [style.width]=\"width()\"\n>\n <!-- Rail: vertical icon column -->\n <div\n class=\"h-full flex flex-col items-center shrink-0 px-[0.3rem] py-2 gap-1 border-r _shk-border dark:[border-color:var(--shk-surface-100)]\"\n [style.width]=\"railWidth()\"\n >\n <!-- Workspace / logo -->\n <div class=\"flex items-center justify-center w-full\">\n <button\n type=\"button\"\n (click)=\"onWorkspace()\"\n [class.is-collapsed]=\"collapsed()\"\n class=\"rail-workspace w-[3.2rem] h-[3.2rem] rounded-xl _shk-bg-surface-100 dark:[background-color:var(--shk-surface-200)] border-none grid place-items-center p-0 relative transition-all\"\n [title]=\"workspaceTooltip()\"\n >\n @if (logo()) {\n <img [src]=\"logo()\" alt=\"Logo\" class=\"rail-app-icon w-8 h-8 object-contain\" />\n } @else {\n <svg [lucideIcon]=\"getIcon('menu')\" class=\"rail-app-icon w-6 h-6 _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\"></svg>\n }\n @if (collapsed()) {\n <svg [lucideIcon]=\"getIcon('panel-right')\" class=\"rail-toggle-icon w-5 h-5 _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\"></svg>\n }\n </button>\n </div>\n\n <!-- Section actions -->\n <div class=\"rail-actions flex-1 flex flex-col items-center gap-1 pt-1\">\n @for (section of sections(); track section.key) {\n <shk-tooltip [text]=\"label(section.label)\" position=\"right\" mode=\"fixed\">\n <button\n type=\"button\"\n (click)=\"onSectionClick(section)\"\n class=\"rail-icon w-[3.4rem] h-[3.4rem] rounded-[0.85rem] grid place-items-center transition-all cursor-pointer\"\n [class.is-active]=\"isSectionActive(section)\"\n [attr.aria-label]=\"label(section.label)\"\n >\n <svg [lucideIcon]=\"getIcon(section.icon)\" class=\"w-5 h-5\"></svg>\n </button>\n </shk-tooltip>\n }\n </div>\n\n <!-- Bottom: language + logout -->\n <div class=\"rail-bottom mt-auto flex flex-col items-center gap-1\">\n <button\n type=\"button\"\n (click)=\"onToggleLang()\"\n class=\"rail-icon w-[3.4rem] h-[3.4rem] rounded-[0.85rem] grid place-items-center transition-all cursor-pointer\"\n [title]=\"activeLang()\"\n >\n <div class=\"flex flex-col items-center gap-[0.15rem]\">\n <svg [lucideIcon]=\"getIcon('globe')\" class=\"w-5 h-5\"></svg>\n <span class=\"rail-lang-code text-[0.5rem] font-bold tracking-[0.05em] leading-none\">{{ activeLang() | uppercase }}</span>\n </div>\n </button>\n\n <button\n type=\"button\"\n (click)=\"logoutRequested.emit()\"\n class=\"rail-icon rail-logout w-[3.4rem] h-[3.4rem] rounded-[0.85rem] grid place-items-center transition-all cursor-pointer\"\n [title]=\"logoutTooltip()\"\n >\n <svg [lucideIcon]=\"getIcon('log-out')\" class=\"w-5 h-5\"></svg>\n </button>\n </div>\n </div>\n\n <!-- Nav: section panel (hidden when collapsed) -->\n @if (!collapsed()) {\n <div class=\"flex-1 min-w-0 flex flex-col _shk-bg-white dark:[background-color:var(--shk-surface-50)]\">\n <!-- Brand header -->\n <div class=\"flex items-center justify-between gap-2 px-3 py-4 border-b _shk-border dark:[border-color:var(--shk-surface-100)]\">\n <span class=\"nav-app text-base font-bold whitespace-nowrap overflow-hidden text-ellipsis _shk-text-surface-800 dark:[color:var(--shk-surface-800)]\">\n {{ appName() }}\n </span>\n <button\n type=\"button\"\n (click)=\"onToggleSidebar()\"\n class=\"nav-toggle w-[1.8rem] h-[1.8rem] rounded-lg border-none bg-transparent grid place-items-center cursor-pointer shrink-0 transition-colors _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\"\n [title]=\"collapseTooltip()\"\n >\n <svg [lucideIcon]=\"getIcon('panel-right')\" class=\"w-4 h-4\"></svg>\n </button>\n </div>\n\n <!-- Menu -->\n <nav class=\"flex-1 overflow-y-auto _shk-scrollbar px-2 py-3\">\n @if (activeSection()) {\n <div class=\"px-2 pb-3\">\n <span class=\"nav-section-label text-xs font-bold tracking-[0.08em] uppercase _shk-text-surface-400 dark:[color:var(--shk-surface-500)] block whitespace-nowrap overflow-hidden text-ellipsis\">\n {{ label(activeSection()!.label) }}\n </span>\n </div>\n }\n\n <ul class=\"space-y-1\">\n @for (item of navItems(); track item.id) {\n @if (item.separator) {\n <li class=\"my-2 border-t _shk-border dark:[border-color:var(--shk-surface-200)]\"></li>\n }\n\n @if (item.children?.length) {\n <!-- Expandable group -->\n <li>\n <button\n type=\"button\"\n (click)=\"toggleGroup(item)\"\n class=\"w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all duration-200\"\n [class._shk-bg-primary]=\"isGroupActive(item)\"\n [class._shk-text-white]=\"isGroupActive(item)\"\n [class.shadow-md]=\"isGroupActive(item)\"\n [class._shk-text-surface-700]=\"!isGroupActive(item)\"\n [class.dark:[color:var(--shk-surface-600)]]=\"!isGroupActive(item)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isGroupActive(item)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isGroupActive(item)\"\n >\n @if (item.icon) {\n <svg [lucideIcon]=\"getIcon(item.icon)\" class=\"w-5 h-5 shrink-0\"></svg>\n }\n <span class=\"flex-1 text-left whitespace-nowrap overflow-hidden\">{{ label(item.label) }}</span>\n <svg\n [lucideIcon]=\"getIcon('chevron-down')\"\n class=\"w-4 h-4 transition-transform duration-200 shrink-0\"\n [class.rotate-180]=\"isGroupExpanded(item)\"\n ></svg>\n </button>\n\n @if (isGroupExpanded(item)) {\n <ul class=\"ml-3 mt-1 space-y-1 border-l-2 _shk-border dark:[border-color:var(--shk-surface-200)] pl-2\">\n @for (child of item.children; track child.id) {\n <li>\n <button\n type=\"button\"\n (click)=\"onItemClick(child)\"\n class=\"w-full flex items-center gap-3 px-3 py-2 rounded-lg text-sm font-medium transition-all duration-200\"\n [class._shk-bg-primary-soft]=\"isItemActive(child)\"\n [class._shk-bg-primary-soft-dark]=\"isItemActive(child)\"\n [class._shk-text-primary-700]=\"isItemActive(child)\"\n [class.dark:[color:var(--shk-primary-300)]]=\"isItemActive(child)\"\n [class._shk-text-surface-600]=\"!isItemActive(child)\"\n [class.dark:[color:var(--shk-surface-400)]]=\"!isItemActive(child)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isItemActive(child)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isItemActive(child)\"\n [class.hover:[color:var(--shk-surface-900)]]=\"!isItemActive(child)\"\n [class.dark:hover:[color:var(--shk-surface-700)]]=\"!isItemActive(child)\"\n >\n @if (child.icon) {\n <svg [lucideIcon]=\"getIcon(child.icon)\" class=\"w-4 h-4 shrink-0\"></svg>\n }\n <span class=\"whitespace-nowrap overflow-hidden\">{{ label(child.label) }}</span>\n @if (isItemActive(child)) {\n <span class=\"w-1.5 h-1.5 rounded-full _shk-bg-primary shrink-0 ml-auto\"></span>\n }\n </button>\n </li>\n }\n </ul>\n }\n </li>\n } @else {\n <!-- Standalone item -->\n <li>\n <button\n type=\"button\"\n (click)=\"onItemClick(item)\"\n class=\"w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all duration-200\"\n [class._shk-bg-primary]=\"isItemActive(item)\"\n [class._shk-text-white]=\"isItemActive(item)\"\n [class.shadow-md]=\"isItemActive(item)\"\n [class._shk-text-surface-700]=\"!isItemActive(item)\"\n [class.dark:[color:var(--shk-surface-600)]]=\"!isItemActive(item)\"\n [class.hover:[background-color:var(--shk-surface-100)]]=\"!isItemActive(item)\"\n [class.dark:hover:[background-color:var(--shk-surface-200)]]=\"!isItemActive(item)\"\n >\n @if (item.icon) {\n <svg [lucideIcon]=\"getIcon(item.icon)\" class=\"w-5 h-5 shrink-0\"></svg>\n }\n <span class=\"flex-1 text-left whitespace-nowrap overflow-hidden\">{{ label(item.label) }}</span>\n @if (item.badge !== undefined) {\n <span class=\"text-xs font-bold px-2 py-0.5 rounded-full _shk-bg-primary _shk-text-white shrink-0\">\n {{ item.badge }}\n </span>\n }\n </button>\n </li>\n }\n }\n </ul>\n </nav>\n </div>\n }\n</aside>\n", styles: [":host{display:block}.rail-workspace{cursor:pointer;transition:opacity .2s ease,box-shadow .2s ease}.rail-workspace.is-collapsed:hover{cursor:col-resize}.rail-workspace .rail-app-icon,.rail-workspace .rail-toggle-icon{grid-area:1 / 1 / 2 / 2;transition:opacity .2s ease}.rail-toggle-icon,.rail-workspace.is-collapsed:hover .rail-app-icon{opacity:0}.rail-workspace.is-collapsed:hover .rail-toggle-icon{opacity:1}.rail-icon{background:transparent;color:var(--shk-surface-700);border:1px solid transparent;transition:transform .18s ease,color .18s ease,background-color .18s ease,box-shadow .18s ease}.rail-icon svg{stroke-width:1.8}.rail-icon:hover{background:var(--shk-surface-100);color:var(--shk-primary-600)}.dark .rail-icon:hover{background:var(--shk-surface-200);color:var(--shk-primary-400)}.rail-icon.is-active{background:var(--shk-primary-600);color:#fff;box-shadow:0 1px 2px #0003}.dark .rail-icon.is-active{background:var(--shk-primary-500);color:#fff}.rail-logout:hover{color:var(--shk-error-500)}.dark .rail-logout:hover{color:var(--shk-error-400)}\n"] }]
|
|
3175
|
+
}], ctorParameters: () => [], propDecorators: { sections: [{ type: i0.Input, args: [{ isSignal: true, alias: "sections", required: false }] }], activeUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeUrl", required: false }] }], activeSectionKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeSectionKey", required: false }] }, { type: i0.Output, args: ["activeSectionKeyChange"] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }, { type: i0.Output, args: ["collapsedChange"] }], activeLang: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeLang", required: false }] }], langs: [{ type: i0.Input, args: [{ isSignal: true, alias: "langs", required: false }] }], logo: [{ type: i0.Input, args: [{ isSignal: true, alias: "logo", required: false }] }], appName: [{ type: i0.Input, args: [{ isSignal: true, alias: "appName", required: false }] }], userRole: [{ type: i0.Input, args: [{ isSignal: true, alias: "userRole", required: false }] }], labelPipe: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelPipe", required: false }] }], railWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "railWidth", required: false }] }], expandedWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandedWidth", required: false }] }], workspaceTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "workspaceTooltip", required: false }] }], logoutTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "logoutTooltip", required: false }] }], collapseTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapseTooltip", required: false }] }], expandTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandTooltip", required: false }] }], sectionSelected: [{ type: i0.Output, args: ["sectionSelected"] }], itemClick: [{ type: i0.Output, args: ["itemClick"] }], setLang: [{ type: i0.Output, args: ["setLang"] }], logoutRequested: [{ type: i0.Output, args: ["logoutRequested"] }], toggleSidebar: [{ type: i0.Output, args: ["toggleSidebar"] }], workspaceClick: [{ type: i0.Output, args: ["workspaceClick"] }] } });
|
|
3176
|
+
|
|
3177
|
+
class ChartComponent {
|
|
3178
|
+
static { this.registered = false; }
|
|
2834
3179
|
constructor() {
|
|
2835
3180
|
this.type = input('bar', ...(ngDevMode ? [{ debugName: "type" }] : /* istanbul ignore next */ []));
|
|
2836
3181
|
this.data = input({ datasets: [] }, ...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
|
|
@@ -2853,6 +3198,38 @@ class ChartComponent {
|
|
|
2853
3198
|
});
|
|
2854
3199
|
});
|
|
2855
3200
|
}
|
|
3201
|
+
ngAfterViewInit() {
|
|
3202
|
+
this.initialized = true;
|
|
3203
|
+
this.initChart();
|
|
3204
|
+
}
|
|
3205
|
+
ngOnDestroy() {
|
|
3206
|
+
this.chartInstance?.destroy();
|
|
3207
|
+
}
|
|
3208
|
+
resetCanvas() {
|
|
3209
|
+
const canvas = this.canvasRef().nativeElement;
|
|
3210
|
+
canvas.width = canvas.width;
|
|
3211
|
+
}
|
|
3212
|
+
initChart() {
|
|
3213
|
+
this.resetCanvas();
|
|
3214
|
+
const canvas = this.canvasRef().nativeElement;
|
|
3215
|
+
const ctx = canvas.getContext('2d');
|
|
3216
|
+
if (!ctx)
|
|
3217
|
+
return;
|
|
3218
|
+
this.chartInstance = new Chart(ctx, {
|
|
3219
|
+
type: this.type(),
|
|
3220
|
+
data: this.deepClone(this.data()),
|
|
3221
|
+
options: this.deepClone(this.options()),
|
|
3222
|
+
});
|
|
3223
|
+
this.chartInstance.resize();
|
|
3224
|
+
}
|
|
3225
|
+
deepClone(value) {
|
|
3226
|
+
try {
|
|
3227
|
+
if (typeof structuredClone === 'function')
|
|
3228
|
+
return structuredClone(value);
|
|
3229
|
+
}
|
|
3230
|
+
catch { }
|
|
3231
|
+
return JSON.parse(JSON.stringify(value));
|
|
3232
|
+
}
|
|
2856
3233
|
updateChart(type, data, options) {
|
|
2857
3234
|
if (!this.chartInstance) {
|
|
2858
3235
|
this.initChart();
|
|
@@ -2860,8 +3237,10 @@ class ChartComponent {
|
|
|
2860
3237
|
}
|
|
2861
3238
|
const config = this.chartInstance.config;
|
|
2862
3239
|
if (type !== config.type) {
|
|
3240
|
+
this.chartInstance.stop();
|
|
2863
3241
|
this.chartInstance.destroy();
|
|
2864
3242
|
this.chartInstance = null;
|
|
3243
|
+
this.resetCanvas();
|
|
2865
3244
|
this.initChart();
|
|
2866
3245
|
return;
|
|
2867
3246
|
}
|
|
@@ -2906,6 +3285,473 @@ function readThemeColors() {
|
|
|
2906
3285
|
};
|
|
2907
3286
|
}
|
|
2908
3287
|
|
|
3288
|
+
const icons$2 = {
|
|
3289
|
+
plus: LucidePlus,
|
|
3290
|
+
pencil: LucidePencil,
|
|
3291
|
+
'trash-2': LucideTrash2,
|
|
3292
|
+
delete: LucideTrash2,
|
|
3293
|
+
'circle-plus': LucideCirclePlus,
|
|
3294
|
+
'circle-help': LucideCircleHelp,
|
|
3295
|
+
calendar: LucideCalendar,
|
|
3296
|
+
'calendar-days': LucideCalendarDays,
|
|
3297
|
+
clock: LucideClock,
|
|
3298
|
+
tag: LucideTag,
|
|
3299
|
+
package: LucidePackage,
|
|
3300
|
+
info: LucideInfo,
|
|
3301
|
+
inbox: LucideInbox,
|
|
3302
|
+
hotel: LucideHotel,
|
|
3303
|
+
ticket: LucideTicket,
|
|
3304
|
+
car: LucideCar,
|
|
3305
|
+
mountain: LucideMountain,
|
|
3306
|
+
bus: LucideBus,
|
|
3307
|
+
ship: LucideShip,
|
|
3308
|
+
shield: LucideShield,
|
|
3309
|
+
utensils: LucideUtensils,
|
|
3310
|
+
'map-pin': LucideMapPin,
|
|
3311
|
+
'user-round': LucideUserRound,
|
|
3312
|
+
};
|
|
3313
|
+
function getIcon$2(name) {
|
|
3314
|
+
return icons$2[name] ?? LucideCircleHelp;
|
|
3315
|
+
}
|
|
3316
|
+
const DEFAULT_MARKER_GRADIENTS = [
|
|
3317
|
+
'bg-gradient-to-br from-blue-500 to-blue-600',
|
|
3318
|
+
'bg-gradient-to-br from-emerald-500 to-emerald-600',
|
|
3319
|
+
'bg-gradient-to-br from-violet-500 to-violet-600',
|
|
3320
|
+
'bg-gradient-to-br from-orange-500 to-orange-600',
|
|
3321
|
+
'bg-gradient-to-br from-rose-500 to-rose-600',
|
|
3322
|
+
'bg-gradient-to-br from-cyan-500 to-cyan-600',
|
|
3323
|
+
'bg-gradient-to-br from-amber-500 to-amber-600',
|
|
3324
|
+
'bg-gradient-to-br from-indigo-500 to-indigo-600',
|
|
3325
|
+
'bg-gradient-to-br from-teal-500 to-teal-600',
|
|
3326
|
+
'bg-gradient-to-br from-pink-500 to-pink-600',
|
|
3327
|
+
];
|
|
3328
|
+
/** Supplier-type style palette used by the original wac-app timeline. */
|
|
3329
|
+
const DEFAULT_SUPPLIER_ICON_COLORS = {
|
|
3330
|
+
accommodation: { bg: '#3d5a80', text: '#ffffff' },
|
|
3331
|
+
air_tickets: { bg: '#98c1d9', text: '#293241' },
|
|
3332
|
+
rent_a_car: { bg: '#ee6c4d', text: '#ffffff' },
|
|
3333
|
+
excursion: { bg: '#e0fbfc', text: '#293241' },
|
|
3334
|
+
transfer: { bg: '#293241', text: '#ffffff' },
|
|
3335
|
+
cruise: { bg: '#3d5a80', text: '#ffffff' },
|
|
3336
|
+
insurance: { bg: '#98c1d9', text: '#293241' },
|
|
3337
|
+
restaurant: { bg: '#6b7280', text: '#ffffff' },
|
|
3338
|
+
visit: { bg: '#14b8a6', text: '#ffffff' },
|
|
3339
|
+
guide: { bg: '#06b6d4', text: '#ffffff' },
|
|
3340
|
+
package: { bg: '#84cc16', text: '#ffffff' },
|
|
3341
|
+
other: { bg: '#e0fbfc', text: '#293241' },
|
|
3342
|
+
};
|
|
3343
|
+
/** Maps a sub-item `type` to a lucide icon name. */
|
|
3344
|
+
const DEFAULT_SUPPLIER_TYPE_ICONS = {
|
|
3345
|
+
accommodation: 'hotel',
|
|
3346
|
+
air_tickets: 'ticket',
|
|
3347
|
+
rent_a_car: 'car',
|
|
3348
|
+
excursion: 'mountain',
|
|
3349
|
+
transfer: 'bus',
|
|
3350
|
+
cruise: 'ship',
|
|
3351
|
+
insurance: 'shield',
|
|
3352
|
+
restaurant: 'utensils',
|
|
3353
|
+
visit: 'map-pin',
|
|
3354
|
+
guide: 'user-round',
|
|
3355
|
+
package: 'package',
|
|
3356
|
+
other: 'tag',
|
|
3357
|
+
};
|
|
3358
|
+
class TimelineComponent {
|
|
3359
|
+
constructor() {
|
|
3360
|
+
this.getIcon = getIcon$2;
|
|
3361
|
+
/** Timeline data. */
|
|
3362
|
+
this.items = input([], ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
|
|
3363
|
+
// ---------- Layout ----------
|
|
3364
|
+
/** 'left' = line and markers on the left; 'alternate' = cards alternate around a centered line on lg+. */
|
|
3365
|
+
this.alignment = input('alternate', ...(ngDevMode ? [{ debugName: "alignment" }] : /* istanbul ignore next */ []));
|
|
3366
|
+
/** Shows/hides the vertical connector line. */
|
|
3367
|
+
this.showLine = input(true, ...(ngDevMode ? [{ debugName: "showLine" }] : /* istanbul ignore next */ []));
|
|
3368
|
+
/** Marker diameter. */
|
|
3369
|
+
this.markerSize = input('md', ...(ngDevMode ? [{ debugName: "markerSize" }] : /* istanbul ignore next */ []));
|
|
3370
|
+
/** Gradient classes cycled across markers when the item has no `color`. */
|
|
3371
|
+
this.markerGradients = input(DEFAULT_MARKER_GRADIENTS, ...(ngDevMode ? [{ debugName: "markerGradients" }] : /* istanbul ignore next */ []));
|
|
3372
|
+
/** Shows the info column on the opposite side of the card (alternate mode, lg+). */
|
|
3373
|
+
this.showOpposite = input(true, ...(ngDevMode ? [{ debugName: "showOpposite" }] : /* istanbul ignore next */ []));
|
|
3374
|
+
/** Shows the item description. */
|
|
3375
|
+
this.showDescription = input(true, ...(ngDevMode ? [{ debugName: "showDescription" }] : /* istanbul ignore next */ []));
|
|
3376
|
+
/** Shows meta chips inside sub items. */
|
|
3377
|
+
this.showSubItemMeta = input(true, ...(ngDevMode ? [{ debugName: "showSubItemMeta" }] : /* istanbul ignore next */ []));
|
|
3378
|
+
/** Shows the price of each sub item. */
|
|
3379
|
+
this.showSubItemPrice = input(true, ...(ngDevMode ? [{ debugName: "showSubItemPrice" }] : /* istanbul ignore next */ []));
|
|
3380
|
+
/** Auto-append "N {subItemCountLabel}" under the title when the item has no subtitle. */
|
|
3381
|
+
this.showSubItemCount = input(false, ...(ngDevMode ? [{ debugName: "showSubItemCount" }] : /* istanbul ignore next */ []));
|
|
3382
|
+
this.subItemCountLabel = input('elementos', ...(ngDevMode ? [{ debugName: "subItemCountLabel" }] : /* istanbul ignore next */ []));
|
|
3383
|
+
// ---------- Header ----------
|
|
3384
|
+
this.showHeader = input(true, ...(ngDevMode ? [{ debugName: "showHeader" }] : /* istanbul ignore next */ []));
|
|
3385
|
+
this.headerTitle = input('', ...(ngDevMode ? [{ debugName: "headerTitle" }] : /* istanbul ignore next */ []));
|
|
3386
|
+
/** Convenience "add" button in the header. */
|
|
3387
|
+
this.showAddItem = input(false, ...(ngDevMode ? [{ debugName: "showAddItem" }] : /* istanbul ignore next */ []));
|
|
3388
|
+
this.addItemLabel = input('Añadir', ...(ngDevMode ? [{ debugName: "addItemLabel" }] : /* istanbul ignore next */ []));
|
|
3389
|
+
this.addItemIcon = input('plus', ...(ngDevMode ? [{ debugName: "addItemIcon" }] : /* istanbul ignore next */ []));
|
|
3390
|
+
this.addItemTooltip = input('Añadir elemento', ...(ngDevMode ? [{ debugName: "addItemTooltip" }] : /* istanbul ignore next */ []));
|
|
3391
|
+
this.headerActions = input([], ...(ngDevMode ? [{ debugName: "headerActions" }] : /* istanbul ignore next */ []));
|
|
3392
|
+
// ---------- Actions ----------
|
|
3393
|
+
/** Renders "+ Añadir sub-elemento" in each card footer. */
|
|
3394
|
+
this.showAddSubItem = input(false, ...(ngDevMode ? [{ debugName: "showAddSubItem" }] : /* istanbul ignore next */ []));
|
|
3395
|
+
this.addSubItemLabel = input('Añadir', ...(ngDevMode ? [{ debugName: "addSubItemLabel" }] : /* istanbul ignore next */ []));
|
|
3396
|
+
this.addSubItemTooltip = input('Añadir sub-elemento', ...(ngDevMode ? [{ debugName: "addSubItemTooltip" }] : /* istanbul ignore next */ []));
|
|
3397
|
+
this.itemActions = input([], ...(ngDevMode ? [{ debugName: "itemActions" }] : /* istanbul ignore next */ []));
|
|
3398
|
+
this.subItemActions = input([], ...(ngDevMode ? [{ debugName: "subItemActions" }] : /* istanbul ignore next */ []));
|
|
3399
|
+
// ---------- Sub-item icon mapping ----------
|
|
3400
|
+
/** Maps a sub-item `type` to a lucide icon name. */
|
|
3401
|
+
this.iconMap = input({}, ...(ngDevMode ? [{ debugName: "iconMap" }] : /* istanbul ignore next */ []));
|
|
3402
|
+
/** Maps a sub-item `type` to its icon-box colors. */
|
|
3403
|
+
this.iconColors = input({}, ...(ngDevMode ? [{ debugName: "iconColors" }] : /* istanbul ignore next */ []));
|
|
3404
|
+
/** Icon used when nothing matches. */
|
|
3405
|
+
this.fallbackIcon = input('circle-help', ...(ngDevMode ? [{ debugName: "fallbackIcon" }] : /* istanbul ignore next */ []));
|
|
3406
|
+
// ---------- Empty state ----------
|
|
3407
|
+
this.showEmptyState = input(true, ...(ngDevMode ? [{ debugName: "showEmptyState" }] : /* istanbul ignore next */ []));
|
|
3408
|
+
this.emptyMessage = input('Sin elementos', ...(ngDevMode ? [{ debugName: "emptyMessage" }] : /* istanbul ignore next */ []));
|
|
3409
|
+
this.emptyIcon = input('calendar-days', ...(ngDevMode ? [{ debugName: "emptyIcon" }] : /* istanbul ignore next */ []));
|
|
3410
|
+
// ---------- Labels ----------
|
|
3411
|
+
this.editTooltip = input('Editar', ...(ngDevMode ? [{ debugName: "editTooltip" }] : /* istanbul ignore next */ []));
|
|
3412
|
+
this.deleteTooltip = input('Eliminar', ...(ngDevMode ? [{ debugName: "deleteTooltip" }] : /* istanbul ignore next */ []));
|
|
3413
|
+
this.optionalLabel = input('Opcional', ...(ngDevMode ? [{ debugName: "optionalLabel" }] : /* istanbul ignore next */ []));
|
|
3414
|
+
this.noSubItemsMessage = input('', ...(ngDevMode ? [{ debugName: "noSubItemsMessage" }] : /* istanbul ignore next */ []));
|
|
3415
|
+
/** Custom content templates: keys 'marker', 'opposite', 'content', 'description', 'subItem', 'empty'. */
|
|
3416
|
+
this.customTemplates = input({}, ...(ngDevMode ? [{ debugName: "customTemplates" }] : /* istanbul ignore next */ []));
|
|
3417
|
+
// ---------- Outputs ----------
|
|
3418
|
+
this.addItem = output();
|
|
3419
|
+
this.addSubItem = output();
|
|
3420
|
+
this.itemClick = output();
|
|
3421
|
+
this.subItemClick = output();
|
|
3422
|
+
}
|
|
3423
|
+
// ---------- Helpers ----------
|
|
3424
|
+
markerText(item, index) {
|
|
3425
|
+
return item.markerText ?? index + 1;
|
|
3426
|
+
}
|
|
3427
|
+
markerClass(item, index) {
|
|
3428
|
+
const base = 'flex items-center justify-center rounded-full text-white shadow-md';
|
|
3429
|
+
const size = this.markerSize() === 'sm'
|
|
3430
|
+
? 'w-8 h-8 text-xs'
|
|
3431
|
+
: this.markerSize() === 'lg'
|
|
3432
|
+
? 'w-12 h-12 text-base'
|
|
3433
|
+
: 'w-10 h-10 text-sm';
|
|
3434
|
+
const color = item.color || this.markerGradients()[index % this.markerGradients().length];
|
|
3435
|
+
return `${base} ${size} ${color}`;
|
|
3436
|
+
}
|
|
3437
|
+
markerColumnClass() {
|
|
3438
|
+
const size = this.markerSize() === 'sm' ? 'w-8' : this.markerSize() === 'lg' ? 'w-12' : 'w-10';
|
|
3439
|
+
return `relative z-10 flex justify-center shrink-0 ${size}`;
|
|
3440
|
+
}
|
|
3441
|
+
alternateMarkerColumnClass() {
|
|
3442
|
+
return `${this.markerColumnClass()} lg:absolute lg:left-1/2 lg:-translate-x-1/2 lg:top-0`;
|
|
3443
|
+
}
|
|
3444
|
+
lineClass() {
|
|
3445
|
+
const pos = this.markerSize() === 'sm' ? 'left-4' : this.markerSize() === 'lg' ? 'left-6' : 'left-5';
|
|
3446
|
+
const base = `absolute top-4 bottom-4 w-px _shk-bg-surface-200 dark:[background-color:var(--shk-surface-200)] ${pos}`;
|
|
3447
|
+
if (this.alignment() === 'alternate') {
|
|
3448
|
+
return `${base} lg:left-1/2 lg:-translate-x-1/2`;
|
|
3449
|
+
}
|
|
3450
|
+
return base;
|
|
3451
|
+
}
|
|
3452
|
+
subItemIconName(sub) {
|
|
3453
|
+
const type = sub.type || '';
|
|
3454
|
+
return sub.icon || this.iconMap()[type] || this.fallbackIcon();
|
|
3455
|
+
}
|
|
3456
|
+
subItemStyle(sub) {
|
|
3457
|
+
const palette = this.iconColors()[sub.type || ''];
|
|
3458
|
+
if (palette)
|
|
3459
|
+
return { 'background-color': palette.bg, color: palette.text };
|
|
3460
|
+
return {
|
|
3461
|
+
'background-color': sub.color || '#6b7280',
|
|
3462
|
+
color: sub.colorText || '#ffffff',
|
|
3463
|
+
};
|
|
3464
|
+
}
|
|
3465
|
+
// ---------- Header actions ----------
|
|
3466
|
+
isHeaderActionVisible(action) {
|
|
3467
|
+
return action.isVisible ? action.isVisible() : true;
|
|
3468
|
+
}
|
|
3469
|
+
isHeaderActionDisabled(action) {
|
|
3470
|
+
return action.isDisabled ? action.isDisabled() : false;
|
|
3471
|
+
}
|
|
3472
|
+
// ---------- Item actions ----------
|
|
3473
|
+
getItemActionLabel(action, item) {
|
|
3474
|
+
return typeof action.label === 'function' ? action.label(item) : action.label;
|
|
3475
|
+
}
|
|
3476
|
+
getItemActionIconName(action, item) {
|
|
3477
|
+
return typeof action.icon === 'function' ? action.icon(item) : action.icon;
|
|
3478
|
+
}
|
|
3479
|
+
getItemActionClass(action, item) {
|
|
3480
|
+
if (!action.class)
|
|
3481
|
+
return '';
|
|
3482
|
+
return typeof action.class === 'function' ? action.class(item) : action.class;
|
|
3483
|
+
}
|
|
3484
|
+
isItemActionVisible(action, item) {
|
|
3485
|
+
return action.isVisible ? action.isVisible(item) : true;
|
|
3486
|
+
}
|
|
3487
|
+
isItemActionDisabled(action, item) {
|
|
3488
|
+
return action.isDisabled ? action.isDisabled(item) : false;
|
|
3489
|
+
}
|
|
3490
|
+
// ---------- Sub-item actions ----------
|
|
3491
|
+
getSubItemActionLabel(action, item, sub) {
|
|
3492
|
+
return typeof action.label === 'function' ? action.label(item, sub) : action.label;
|
|
3493
|
+
}
|
|
3494
|
+
getSubItemActionIconName(action, item, sub) {
|
|
3495
|
+
return typeof action.icon === 'function' ? action.icon(item, sub) : action.icon;
|
|
3496
|
+
}
|
|
3497
|
+
isSubItemActionVisible(action, item, sub) {
|
|
3498
|
+
return action.isVisible ? action.isVisible(item, sub) : true;
|
|
3499
|
+
}
|
|
3500
|
+
isSubItemActionDisabled(action, item, sub) {
|
|
3501
|
+
return action.isDisabled ? action.isDisabled(item, sub) : false;
|
|
3502
|
+
}
|
|
3503
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: TimelineComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3504
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: TimelineComponent, isStandalone: true, selector: "shk-timeline", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, alignment: { classPropertyName: "alignment", publicName: "alignment", isSignal: true, isRequired: false, transformFunction: null }, showLine: { classPropertyName: "showLine", publicName: "showLine", isSignal: true, isRequired: false, transformFunction: null }, markerSize: { classPropertyName: "markerSize", publicName: "markerSize", isSignal: true, isRequired: false, transformFunction: null }, markerGradients: { classPropertyName: "markerGradients", publicName: "markerGradients", isSignal: true, isRequired: false, transformFunction: null }, showOpposite: { classPropertyName: "showOpposite", publicName: "showOpposite", isSignal: true, isRequired: false, transformFunction: null }, showDescription: { classPropertyName: "showDescription", publicName: "showDescription", isSignal: true, isRequired: false, transformFunction: null }, showSubItemMeta: { classPropertyName: "showSubItemMeta", publicName: "showSubItemMeta", isSignal: true, isRequired: false, transformFunction: null }, showSubItemPrice: { classPropertyName: "showSubItemPrice", publicName: "showSubItemPrice", isSignal: true, isRequired: false, transformFunction: null }, showSubItemCount: { classPropertyName: "showSubItemCount", publicName: "showSubItemCount", isSignal: true, isRequired: false, transformFunction: null }, subItemCountLabel: { classPropertyName: "subItemCountLabel", publicName: "subItemCountLabel", isSignal: true, isRequired: false, transformFunction: null }, showHeader: { classPropertyName: "showHeader", publicName: "showHeader", isSignal: true, isRequired: false, transformFunction: null }, headerTitle: { classPropertyName: "headerTitle", publicName: "headerTitle", isSignal: true, isRequired: false, transformFunction: null }, showAddItem: { classPropertyName: "showAddItem", publicName: "showAddItem", isSignal: true, isRequired: false, transformFunction: null }, addItemLabel: { classPropertyName: "addItemLabel", publicName: "addItemLabel", isSignal: true, isRequired: false, transformFunction: null }, addItemIcon: { classPropertyName: "addItemIcon", publicName: "addItemIcon", isSignal: true, isRequired: false, transformFunction: null }, addItemTooltip: { classPropertyName: "addItemTooltip", publicName: "addItemTooltip", isSignal: true, isRequired: false, transformFunction: null }, headerActions: { classPropertyName: "headerActions", publicName: "headerActions", isSignal: true, isRequired: false, transformFunction: null }, showAddSubItem: { classPropertyName: "showAddSubItem", publicName: "showAddSubItem", isSignal: true, isRequired: false, transformFunction: null }, addSubItemLabel: { classPropertyName: "addSubItemLabel", publicName: "addSubItemLabel", isSignal: true, isRequired: false, transformFunction: null }, addSubItemTooltip: { classPropertyName: "addSubItemTooltip", publicName: "addSubItemTooltip", isSignal: true, isRequired: false, transformFunction: null }, itemActions: { classPropertyName: "itemActions", publicName: "itemActions", isSignal: true, isRequired: false, transformFunction: null }, subItemActions: { classPropertyName: "subItemActions", publicName: "subItemActions", isSignal: true, isRequired: false, transformFunction: null }, iconMap: { classPropertyName: "iconMap", publicName: "iconMap", isSignal: true, isRequired: false, transformFunction: null }, iconColors: { classPropertyName: "iconColors", publicName: "iconColors", isSignal: true, isRequired: false, transformFunction: null }, fallbackIcon: { classPropertyName: "fallbackIcon", publicName: "fallbackIcon", isSignal: true, isRequired: false, transformFunction: null }, showEmptyState: { classPropertyName: "showEmptyState", publicName: "showEmptyState", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, emptyIcon: { classPropertyName: "emptyIcon", publicName: "emptyIcon", isSignal: true, isRequired: false, transformFunction: null }, editTooltip: { classPropertyName: "editTooltip", publicName: "editTooltip", isSignal: true, isRequired: false, transformFunction: null }, deleteTooltip: { classPropertyName: "deleteTooltip", publicName: "deleteTooltip", isSignal: true, isRequired: false, transformFunction: null }, optionalLabel: { classPropertyName: "optionalLabel", publicName: "optionalLabel", isSignal: true, isRequired: false, transformFunction: null }, noSubItemsMessage: { classPropertyName: "noSubItemsMessage", publicName: "noSubItemsMessage", isSignal: true, isRequired: false, transformFunction: null }, customTemplates: { classPropertyName: "customTemplates", publicName: "customTemplates", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { addItem: "addItem", addSubItem: "addSubItem", itemClick: "itemClick", subItemClick: "subItemClick" }, ngImport: i0, template: "<div class=\"space-y-4\">\n\n <!-- ============ Header ============ -->\n @if (showHeader() && (headerTitle() || showAddItem() || headerActions().length > 0)) {\n <div class=\"flex flex-wrap items-center justify-between gap-2\">\n @if (headerTitle()) {\n <div class=\"text-sm font-semibold _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\">\n {{ headerTitle() }}\n </div>\n }\n <div class=\"flex items-center gap-1.5 ml-auto\">\n @if (showAddItem()) {\n <button\n type=\"button\"\n (click)=\"addItem.emit()\"\n [attr.aria-label]=\"addItemTooltip()\"\n class=\"inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md _shk-bg-primary text-white hover:[background-color:var(--shk-primary-700)] transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon(addItemIcon())\" class=\"w-3.5 h-3.5\"></svg>\n {{ addItemLabel() }}\n </button>\n }\n @for (action of headerActions(); track $index) {\n @if (isHeaderActionVisible(action)) {\n <button\n type=\"button\"\n [class]=\"action.class || 'inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md _shk-bg-primary text-white hover:[background-color:var(--shk-primary-700)] transition-colors disabled:opacity-50 disabled:cursor-not-allowed'\"\n [disabled]=\"isHeaderActionDisabled(action)\"\n (click)=\"action.onClick()\"\n >\n @if (action.icon) {\n <svg [lucideIcon]=\"getIcon(action.icon)\" class=\"w-3.5 h-3.5\"></svg>\n }\n {{ action.label }}\n </button>\n }\n }\n </div>\n </div>\n }\n\n <!-- ============ Timeline ============ -->\n @if (items().length > 0) {\n <div class=\"relative\">\n @if (showLine()) {\n <div [class]=\"lineClass()\" aria-hidden=\"true\"></div>\n }\n\n @for (item of items(); track item.id; let i = $index) {\n @if (alignment() === 'alternate') {\n <div class=\"relative flex items-start gap-4 lg:grid lg:grid-cols-2 lg:gap-0\">\n <!-- Marker (centered on desktop) -->\n <div [class]=\"alternateMarkerColumnClass()\">\n <span [class]=\"markerClass(item, i)\">\n <ng-container\n *ngTemplateOutlet=\"customTemplates()['marker'] || defaultMarker; context: { $implicit: item, index: i }\"\n ></ng-container>\n </span>\n </div>\n\n <!-- Content card -->\n <div\n class=\"flex-1 min-w-0\"\n [class.lg:order-1]=\"$even\"\n [class.lg:order-2]=\"!$even\"\n [class.lg:pr-12]=\"$even\"\n [class.lg:pl-12]=\"!$even\"\n >\n <ng-container\n *ngTemplateOutlet=\"customTemplates()['content'] || card; context: { $implicit: item, index: i }\"\n ></ng-container>\n </div>\n\n <!-- Opposite info -->\n @if (showOpposite()) {\n <div\n class=\"hidden lg:flex lg:items-center\"\n [class.lg:order-2]=\"$even\"\n [class.lg:order-1]=\"!$even\"\n [class.lg:justify-end]=\"$even\"\n [class.lg:pl-12]=\"!$even\"\n >\n <ng-container\n *ngTemplateOutlet=\"customTemplates()['opposite'] || itemInfo; context: { $implicit: item, index: i }\"\n ></ng-container>\n </div>\n }\n </div>\n } @else {\n <!-- Left alignment -->\n <div class=\"relative flex items-start gap-4\">\n <div [class]=\"markerColumnClass()\">\n <span [class]=\"markerClass(item, i)\">\n <ng-container\n *ngTemplateOutlet=\"customTemplates()['marker'] || defaultMarker; context: { $implicit: item, index: i }\"\n ></ng-container>\n </span>\n </div>\n <div class=\"flex-1 min-w-0\">\n <ng-container\n *ngTemplateOutlet=\"customTemplates()['content'] || card; context: { $implicit: item, index: i }\"\n ></ng-container>\n </div>\n </div>\n }\n }\n </div>\n } @else if (showEmptyState()) {\n <!-- ============ Empty state ============ -->\n <div class=\"text-center py-12\">\n @if (customTemplates()['empty']) {\n <ng-container *ngTemplateOutlet=\"customTemplates()['empty']\"></ng-container>\n } @else {\n <div class=\"w-16 h-16 mx-auto mb-4 _shk-bg-surface-100 dark:[background-color:var(--shk-surface-100)] rounded-full flex items-center justify-center\">\n <svg [lucideIcon]=\"getIcon(emptyIcon())\" class=\"w-8 h-8 _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\"></svg>\n </div>\n <p class=\"text-sm _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\">{{ emptyMessage() }}</p>\n }\n </div>\n }\n\n <!-- ============ Templates ============ -->\n\n <ng-template #defaultMarker let-item let-index=\"index\">\n <span class=\"font-bold\">{{ markerText(item, index) }}</span>\n </ng-template>\n\n <ng-template #itemInfo let-item>\n <div>\n @if (item.badge !== undefined && item.badge !== null && item.badge !== '') {\n <div class=\"mb-2\">\n <span class=\"inline-flex items-center gap-1 px-2.5 py-1 rounded-full text-xs font-semibold _shk-bg-surface-100 dark:[background-color:var(--shk-surface-200)] _shk-text-surface-600 dark:[color:var(--shk-surface-600)]\">\n @if (item.badgeIcon) {\n <svg [lucideIcon]=\"getIcon(item.badgeIcon)\" class=\"w-3 h-3\"></svg>\n }\n {{ item.badge }}\n </span>\n </div>\n }\n @if (item.title) {\n <div class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\">{{ item.title }}</div>\n }\n @let subCount = (item.subItems?.length || 0);\n @if (item.subtitle || (showSubItemCount() && subCount > 0)) {\n <div class=\"text-xs _shk-text-surface-400 dark:[color:var(--shk-surface-500)] mt-1\">\n {{ item.subtitle || (subCount + ' ' + subItemCountLabel()) }}\n </div>\n }\n </div>\n </ng-template>\n\n <ng-template #card let-item>\n @let subItems = item.subItems || [];\n <div class=\"shk-timeline-card mb-4 bg-white dark:[background-color:var(--shk-surface-50)] rounded-xl border _shk-border dark:[border-color:var(--shk-surface-200)] shadow-sm overflow-hidden\">\n <!-- Header (mobile in alternate, always in left) -->\n <div class=\"flex items-center gap-2 px-4 pt-4 pb-2\" [class.lg:hidden]=\"alignment() === 'alternate'\">\n <ng-container *ngTemplateOutlet=\"itemInfo; context: { $implicit: item }\"></ng-container>\n </div>\n\n <!-- Description -->\n @if (showDescription() && item.description) {\n <div class=\"px-4 pt-3\">\n @if (customTemplates()['description']) {\n <ng-container *ngTemplateOutlet=\"customTemplates()['description']; context: { $implicit: item }\"></ng-container>\n } @else {\n <p class=\"text-sm _shk-text-surface-600 dark:[color:var(--shk-surface-600)] leading-relaxed\">{{ item.description }}</p>\n }\n </div>\n }\n\n <!-- Sub items -->\n @if (subItems.length > 0) {\n <div class=\"mt-2\">\n @for (sub of subItems; track sub.id) {\n <ng-container\n *ngTemplateOutlet=\"customTemplates()['subItem'] || defaultSubItem; context: { $implicit: item, subItem: sub }\"\n ></ng-container>\n }\n </div>\n } @else if (noSubItemsMessage()) {\n <div class=\"px-4 py-6 text-center\">\n <div class=\"inline-flex items-center gap-2 text-sm _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\">\n <svg [lucideIcon]=\"getIcon('info')\" class=\"w-4 h-4\"></svg>\n <span class=\"italic\">{{ noSubItemsMessage() }}</span>\n </div>\n </div>\n }\n\n <!-- Footer actions -->\n @if (showAddSubItem() || itemActions().length > 0) {\n <div class=\"flex items-center gap-1 px-4 py-2 _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] border-t _shk-border dark:[border-color:var(--shk-surface-100)]\">\n @if (showAddSubItem()) {\n <button\n type=\"button\"\n (click)=\"addSubItem.emit(item)\"\n class=\"relative group inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium _shk-text-primary hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] rounded-lg transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('circle-plus')\" class=\"w-3.5 h-3.5\"></svg>\n {{ addSubItemLabel() }}\n <span class=\"absolute bottom-full left-1/2 -translate-x-1/2 mb-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ addSubItemTooltip() }}\n </span>\n </button>\n }\n <div class=\"flex-1\"></div>\n @for (action of itemActions(); track $index) {\n @if (isItemActionVisible(action, item)) {\n <div class=\"relative group\">\n <button\n type=\"button\"\n (click)=\"action.onClick(item)\"\n [class]=\"'timeline-icon-btn ' + getItemActionClass(action, item)\"\n [disabled]=\"isItemActionDisabled(action, item)\"\n [attr.aria-label]=\"getItemActionLabel(action, item)\"\n >\n <svg [lucideIcon]=\"getIcon(getItemActionIconName(action, item))\" class=\"w-3.5 h-3.5\"></svg>\n </button>\n <span class=\"absolute bottom-full left-1/2 -translate-x-1/2 mb-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ getItemActionLabel(action, item) }}\n </span>\n </div>\n }\n }\n </div>\n }\n </div>\n </ng-template>\n\n <ng-template #defaultSubItem let-item let-sub=\"subItem\">\n <div class=\"px-4 py-3 border-t [border-color:var(--shk-surface-100)] dark:[border-color:var(--shk-surface-700)] hover:[background-color:color-mix(in srgb,var(--shk-primary-50)30%,transparent)] dark:hover:[background-color:color-mix(in srgb,var(--shk-primary-900)10%,transparent)] transition-colors duration-200 group\">\n <div class=\"flex items-start gap-3\">\n <span\n [class]=\"sub.iconClass || 'flex items-center justify-center w-9 h-9 rounded-lg shrink-0 mt-0.5'\"\n [style]=\"sub.iconClass ? undefined : subItemStyle(sub)\"\n >\n <svg [lucideIcon]=\"getIcon(subItemIconName(sub))\" class=\"w-4 h-4\"></svg>\n </span>\n\n <div class=\"flex-1 min-w-0\">\n <div class=\"flex items-center gap-2 flex-wrap\">\n @if (sub.optional) {\n <span class=\"text-[10px] font-semibold uppercase tracking-wide px-1.5 py-0.5 rounded _shk-bg-amber-soft _shk-text-amber-600 dark:[color:var(--shk-amber-400)]\">\n {{ sub.optionalLabel || optionalLabel() }}\n </span>\n }\n <span class=\"font-medium _shk-text-surface-800 dark:[color:var(--shk-surface-800)] text-sm truncate\">{{ sub.title }}</span>\n @if (sub.subtitle) {\n <span class=\"text-xs _shk-text-surface-400 dark:[color:var(--shk-surface-500)] truncate\">\u00B7 {{ sub.subtitle }}</span>\n }\n </div>\n\n @if (showSubItemMeta() && (sub.meta?.length || 0) > 0) {\n <div class=\"flex flex-wrap items-center gap-x-3 gap-y-1 mt-1.5 text-xs _shk-text-surface-500 dark:[color:var(--shk-surface-500)]\">\n @for (m of sub.meta!; track $index) {\n <span class=\"flex items-center gap-1\">\n <svg [lucideIcon]=\"getIcon(m.icon)\" class=\"w-3 h-3\"></svg>\n @if (m.label) {\n <span class=\"font-medium\">{{ m.label }}:</span>\n }\n {{ m.value }}\n </span>\n }\n </div>\n }\n </div>\n\n <div class=\"flex items-center gap-0.5 shrink-0\">\n @if (showSubItemPrice() && sub.price !== undefined && sub.price !== null && sub.price !== '') {\n <span class=\"font-semibold _shk-text-surface-700 dark:[color:var(--shk-surface-700)] text-xs mr-1\">{{ sub.price }}</span>\n }\n @for (action of subItemActions(); track $index) {\n @if (isSubItemActionVisible(action, item, sub)) {\n <div class=\"relative group\">\n <button\n type=\"button\"\n (click)=\"action.onClick(item, sub)\"\n class=\"timeline-icon-btn opacity-100 lg:opacity-0 lg:group-hover:opacity-100 transition-opacity\"\n [disabled]=\"isSubItemActionDisabled(action, item, sub)\"\n [attr.aria-label]=\"getSubItemActionLabel(action, item, sub)\"\n >\n <svg [lucideIcon]=\"getIcon(getSubItemActionIconName(action, item, sub))\" class=\"w-3.5 h-3.5\"></svg>\n </button>\n <span class=\"absolute top-full left-1/2 -translate-x-1/2 mt-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ getSubItemActionLabel(action, item, sub) }}\n </span>\n </div>\n }\n }\n </div>\n </div>\n </div>\n </ng-template>\n\n</div>\n", styles: [":host{display:block}.timeline-icon-btn{padding:.375rem;display:inline-flex;align-items:center;justify-content:center;border-radius:.5rem;color:var(--shk-primary-600);transition:background-color .15s ease-in-out,color .15s ease-in-out,opacity .15s ease-in-out}.timeline-icon-btn:hover:not(:disabled){background-color:color-mix(in srgb,var(--shk-primary-50) 60%,transparent);color:var(--shk-primary-700)}.timeline-icon-btn:disabled{opacity:.4;cursor:not-allowed}.timeline-icon-btn svg{width:.875rem!important;height:.875rem!important}.shk-timeline-card{animation:shk-timeline-fade-in .3s ease-out}@keyframes shk-timeline-fade-in{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: LucideDynamicIcon, selector: "svg[lucideIcon]", inputs: ["lucideIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
3505
|
+
}
|
|
3506
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: TimelineComponent, decorators: [{
|
|
3507
|
+
type: Component,
|
|
3508
|
+
args: [{ selector: 'shk-timeline', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, LucideDynamicIcon], template: "<div class=\"space-y-4\">\n\n <!-- ============ Header ============ -->\n @if (showHeader() && (headerTitle() || showAddItem() || headerActions().length > 0)) {\n <div class=\"flex flex-wrap items-center justify-between gap-2\">\n @if (headerTitle()) {\n <div class=\"text-sm font-semibold _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\">\n {{ headerTitle() }}\n </div>\n }\n <div class=\"flex items-center gap-1.5 ml-auto\">\n @if (showAddItem()) {\n <button\n type=\"button\"\n (click)=\"addItem.emit()\"\n [attr.aria-label]=\"addItemTooltip()\"\n class=\"inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md _shk-bg-primary text-white hover:[background-color:var(--shk-primary-700)] transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon(addItemIcon())\" class=\"w-3.5 h-3.5\"></svg>\n {{ addItemLabel() }}\n </button>\n }\n @for (action of headerActions(); track $index) {\n @if (isHeaderActionVisible(action)) {\n <button\n type=\"button\"\n [class]=\"action.class || 'inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md _shk-bg-primary text-white hover:[background-color:var(--shk-primary-700)] transition-colors disabled:opacity-50 disabled:cursor-not-allowed'\"\n [disabled]=\"isHeaderActionDisabled(action)\"\n (click)=\"action.onClick()\"\n >\n @if (action.icon) {\n <svg [lucideIcon]=\"getIcon(action.icon)\" class=\"w-3.5 h-3.5\"></svg>\n }\n {{ action.label }}\n </button>\n }\n }\n </div>\n </div>\n }\n\n <!-- ============ Timeline ============ -->\n @if (items().length > 0) {\n <div class=\"relative\">\n @if (showLine()) {\n <div [class]=\"lineClass()\" aria-hidden=\"true\"></div>\n }\n\n @for (item of items(); track item.id; let i = $index) {\n @if (alignment() === 'alternate') {\n <div class=\"relative flex items-start gap-4 lg:grid lg:grid-cols-2 lg:gap-0\">\n <!-- Marker (centered on desktop) -->\n <div [class]=\"alternateMarkerColumnClass()\">\n <span [class]=\"markerClass(item, i)\">\n <ng-container\n *ngTemplateOutlet=\"customTemplates()['marker'] || defaultMarker; context: { $implicit: item, index: i }\"\n ></ng-container>\n </span>\n </div>\n\n <!-- Content card -->\n <div\n class=\"flex-1 min-w-0\"\n [class.lg:order-1]=\"$even\"\n [class.lg:order-2]=\"!$even\"\n [class.lg:pr-12]=\"$even\"\n [class.lg:pl-12]=\"!$even\"\n >\n <ng-container\n *ngTemplateOutlet=\"customTemplates()['content'] || card; context: { $implicit: item, index: i }\"\n ></ng-container>\n </div>\n\n <!-- Opposite info -->\n @if (showOpposite()) {\n <div\n class=\"hidden lg:flex lg:items-center\"\n [class.lg:order-2]=\"$even\"\n [class.lg:order-1]=\"!$even\"\n [class.lg:justify-end]=\"$even\"\n [class.lg:pl-12]=\"!$even\"\n >\n <ng-container\n *ngTemplateOutlet=\"customTemplates()['opposite'] || itemInfo; context: { $implicit: item, index: i }\"\n ></ng-container>\n </div>\n }\n </div>\n } @else {\n <!-- Left alignment -->\n <div class=\"relative flex items-start gap-4\">\n <div [class]=\"markerColumnClass()\">\n <span [class]=\"markerClass(item, i)\">\n <ng-container\n *ngTemplateOutlet=\"customTemplates()['marker'] || defaultMarker; context: { $implicit: item, index: i }\"\n ></ng-container>\n </span>\n </div>\n <div class=\"flex-1 min-w-0\">\n <ng-container\n *ngTemplateOutlet=\"customTemplates()['content'] || card; context: { $implicit: item, index: i }\"\n ></ng-container>\n </div>\n </div>\n }\n }\n </div>\n } @else if (showEmptyState()) {\n <!-- ============ Empty state ============ -->\n <div class=\"text-center py-12\">\n @if (customTemplates()['empty']) {\n <ng-container *ngTemplateOutlet=\"customTemplates()['empty']\"></ng-container>\n } @else {\n <div class=\"w-16 h-16 mx-auto mb-4 _shk-bg-surface-100 dark:[background-color:var(--shk-surface-100)] rounded-full flex items-center justify-center\">\n <svg [lucideIcon]=\"getIcon(emptyIcon())\" class=\"w-8 h-8 _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\"></svg>\n </div>\n <p class=\"text-sm _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\">{{ emptyMessage() }}</p>\n }\n </div>\n }\n\n <!-- ============ Templates ============ -->\n\n <ng-template #defaultMarker let-item let-index=\"index\">\n <span class=\"font-bold\">{{ markerText(item, index) }}</span>\n </ng-template>\n\n <ng-template #itemInfo let-item>\n <div>\n @if (item.badge !== undefined && item.badge !== null && item.badge !== '') {\n <div class=\"mb-2\">\n <span class=\"inline-flex items-center gap-1 px-2.5 py-1 rounded-full text-xs font-semibold _shk-bg-surface-100 dark:[background-color:var(--shk-surface-200)] _shk-text-surface-600 dark:[color:var(--shk-surface-600)]\">\n @if (item.badgeIcon) {\n <svg [lucideIcon]=\"getIcon(item.badgeIcon)\" class=\"w-3 h-3\"></svg>\n }\n {{ item.badge }}\n </span>\n </div>\n }\n @if (item.title) {\n <div class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\">{{ item.title }}</div>\n }\n @let subCount = (item.subItems?.length || 0);\n @if (item.subtitle || (showSubItemCount() && subCount > 0)) {\n <div class=\"text-xs _shk-text-surface-400 dark:[color:var(--shk-surface-500)] mt-1\">\n {{ item.subtitle || (subCount + ' ' + subItemCountLabel()) }}\n </div>\n }\n </div>\n </ng-template>\n\n <ng-template #card let-item>\n @let subItems = item.subItems || [];\n <div class=\"shk-timeline-card mb-4 bg-white dark:[background-color:var(--shk-surface-50)] rounded-xl border _shk-border dark:[border-color:var(--shk-surface-200)] shadow-sm overflow-hidden\">\n <!-- Header (mobile in alternate, always in left) -->\n <div class=\"flex items-center gap-2 px-4 pt-4 pb-2\" [class.lg:hidden]=\"alignment() === 'alternate'\">\n <ng-container *ngTemplateOutlet=\"itemInfo; context: { $implicit: item }\"></ng-container>\n </div>\n\n <!-- Description -->\n @if (showDescription() && item.description) {\n <div class=\"px-4 pt-3\">\n @if (customTemplates()['description']) {\n <ng-container *ngTemplateOutlet=\"customTemplates()['description']; context: { $implicit: item }\"></ng-container>\n } @else {\n <p class=\"text-sm _shk-text-surface-600 dark:[color:var(--shk-surface-600)] leading-relaxed\">{{ item.description }}</p>\n }\n </div>\n }\n\n <!-- Sub items -->\n @if (subItems.length > 0) {\n <div class=\"mt-2\">\n @for (sub of subItems; track sub.id) {\n <ng-container\n *ngTemplateOutlet=\"customTemplates()['subItem'] || defaultSubItem; context: { $implicit: item, subItem: sub }\"\n ></ng-container>\n }\n </div>\n } @else if (noSubItemsMessage()) {\n <div class=\"px-4 py-6 text-center\">\n <div class=\"inline-flex items-center gap-2 text-sm _shk-text-surface-400 dark:[color:var(--shk-surface-500)]\">\n <svg [lucideIcon]=\"getIcon('info')\" class=\"w-4 h-4\"></svg>\n <span class=\"italic\">{{ noSubItemsMessage() }}</span>\n </div>\n </div>\n }\n\n <!-- Footer actions -->\n @if (showAddSubItem() || itemActions().length > 0) {\n <div class=\"flex items-center gap-1 px-4 py-2 _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] border-t _shk-border dark:[border-color:var(--shk-surface-100)]\">\n @if (showAddSubItem()) {\n <button\n type=\"button\"\n (click)=\"addSubItem.emit(item)\"\n class=\"relative group inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium _shk-text-primary hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] rounded-lg transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('circle-plus')\" class=\"w-3.5 h-3.5\"></svg>\n {{ addSubItemLabel() }}\n <span class=\"absolute bottom-full left-1/2 -translate-x-1/2 mb-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ addSubItemTooltip() }}\n </span>\n </button>\n }\n <div class=\"flex-1\"></div>\n @for (action of itemActions(); track $index) {\n @if (isItemActionVisible(action, item)) {\n <div class=\"relative group\">\n <button\n type=\"button\"\n (click)=\"action.onClick(item)\"\n [class]=\"'timeline-icon-btn ' + getItemActionClass(action, item)\"\n [disabled]=\"isItemActionDisabled(action, item)\"\n [attr.aria-label]=\"getItemActionLabel(action, item)\"\n >\n <svg [lucideIcon]=\"getIcon(getItemActionIconName(action, item))\" class=\"w-3.5 h-3.5\"></svg>\n </button>\n <span class=\"absolute bottom-full left-1/2 -translate-x-1/2 mb-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ getItemActionLabel(action, item) }}\n </span>\n </div>\n }\n }\n </div>\n }\n </div>\n </ng-template>\n\n <ng-template #defaultSubItem let-item let-sub=\"subItem\">\n <div class=\"px-4 py-3 border-t [border-color:var(--shk-surface-100)] dark:[border-color:var(--shk-surface-700)] hover:[background-color:color-mix(in srgb,var(--shk-primary-50)30%,transparent)] dark:hover:[background-color:color-mix(in srgb,var(--shk-primary-900)10%,transparent)] transition-colors duration-200 group\">\n <div class=\"flex items-start gap-3\">\n <span\n [class]=\"sub.iconClass || 'flex items-center justify-center w-9 h-9 rounded-lg shrink-0 mt-0.5'\"\n [style]=\"sub.iconClass ? undefined : subItemStyle(sub)\"\n >\n <svg [lucideIcon]=\"getIcon(subItemIconName(sub))\" class=\"w-4 h-4\"></svg>\n </span>\n\n <div class=\"flex-1 min-w-0\">\n <div class=\"flex items-center gap-2 flex-wrap\">\n @if (sub.optional) {\n <span class=\"text-[10px] font-semibold uppercase tracking-wide px-1.5 py-0.5 rounded _shk-bg-amber-soft _shk-text-amber-600 dark:[color:var(--shk-amber-400)]\">\n {{ sub.optionalLabel || optionalLabel() }}\n </span>\n }\n <span class=\"font-medium _shk-text-surface-800 dark:[color:var(--shk-surface-800)] text-sm truncate\">{{ sub.title }}</span>\n @if (sub.subtitle) {\n <span class=\"text-xs _shk-text-surface-400 dark:[color:var(--shk-surface-500)] truncate\">\u00B7 {{ sub.subtitle }}</span>\n }\n </div>\n\n @if (showSubItemMeta() && (sub.meta?.length || 0) > 0) {\n <div class=\"flex flex-wrap items-center gap-x-3 gap-y-1 mt-1.5 text-xs _shk-text-surface-500 dark:[color:var(--shk-surface-500)]\">\n @for (m of sub.meta!; track $index) {\n <span class=\"flex items-center gap-1\">\n <svg [lucideIcon]=\"getIcon(m.icon)\" class=\"w-3 h-3\"></svg>\n @if (m.label) {\n <span class=\"font-medium\">{{ m.label }}:</span>\n }\n {{ m.value }}\n </span>\n }\n </div>\n }\n </div>\n\n <div class=\"flex items-center gap-0.5 shrink-0\">\n @if (showSubItemPrice() && sub.price !== undefined && sub.price !== null && sub.price !== '') {\n <span class=\"font-semibold _shk-text-surface-700 dark:[color:var(--shk-surface-700)] text-xs mr-1\">{{ sub.price }}</span>\n }\n @for (action of subItemActions(); track $index) {\n @if (isSubItemActionVisible(action, item, sub)) {\n <div class=\"relative group\">\n <button\n type=\"button\"\n (click)=\"action.onClick(item, sub)\"\n class=\"timeline-icon-btn opacity-100 lg:opacity-0 lg:group-hover:opacity-100 transition-opacity\"\n [disabled]=\"isSubItemActionDisabled(action, item, sub)\"\n [attr.aria-label]=\"getSubItemActionLabel(action, item, sub)\"\n >\n <svg [lucideIcon]=\"getIcon(getSubItemActionIconName(action, item, sub))\" class=\"w-3.5 h-3.5\"></svg>\n </button>\n <span class=\"absolute top-full left-1/2 -translate-x-1/2 mt-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ getSubItemActionLabel(action, item, sub) }}\n </span>\n </div>\n }\n }\n </div>\n </div>\n </div>\n </ng-template>\n\n</div>\n", styles: [":host{display:block}.timeline-icon-btn{padding:.375rem;display:inline-flex;align-items:center;justify-content:center;border-radius:.5rem;color:var(--shk-primary-600);transition:background-color .15s ease-in-out,color .15s ease-in-out,opacity .15s ease-in-out}.timeline-icon-btn:hover:not(:disabled){background-color:color-mix(in srgb,var(--shk-primary-50) 60%,transparent);color:var(--shk-primary-700)}.timeline-icon-btn:disabled{opacity:.4;cursor:not-allowed}.timeline-icon-btn svg{width:.875rem!important;height:.875rem!important}.shk-timeline-card{animation:shk-timeline-fade-in .3s ease-out}@keyframes shk-timeline-fade-in{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}\n"] }]
|
|
3509
|
+
}], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], alignment: [{ type: i0.Input, args: [{ isSignal: true, alias: "alignment", required: false }] }], showLine: [{ type: i0.Input, args: [{ isSignal: true, alias: "showLine", required: false }] }], markerSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "markerSize", required: false }] }], markerGradients: [{ type: i0.Input, args: [{ isSignal: true, alias: "markerGradients", required: false }] }], showOpposite: [{ type: i0.Input, args: [{ isSignal: true, alias: "showOpposite", required: false }] }], showDescription: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDescription", required: false }] }], showSubItemMeta: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSubItemMeta", required: false }] }], showSubItemPrice: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSubItemPrice", required: false }] }], showSubItemCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSubItemCount", required: false }] }], subItemCountLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "subItemCountLabel", required: false }] }], showHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "showHeader", required: false }] }], headerTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerTitle", required: false }] }], showAddItem: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAddItem", required: false }] }], addItemLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "addItemLabel", required: false }] }], addItemIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "addItemIcon", required: false }] }], addItemTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "addItemTooltip", required: false }] }], headerActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerActions", required: false }] }], showAddSubItem: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAddSubItem", required: false }] }], addSubItemLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "addSubItemLabel", required: false }] }], addSubItemTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "addSubItemTooltip", required: false }] }], itemActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemActions", required: false }] }], subItemActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "subItemActions", required: false }] }], iconMap: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconMap", required: false }] }], iconColors: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconColors", required: false }] }], fallbackIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "fallbackIcon", required: false }] }], showEmptyState: [{ type: i0.Input, args: [{ isSignal: true, alias: "showEmptyState", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], emptyIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyIcon", required: false }] }], editTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "editTooltip", required: false }] }], deleteTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "deleteTooltip", required: false }] }], optionalLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionalLabel", required: false }] }], noSubItemsMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "noSubItemsMessage", required: false }] }], customTemplates: [{ type: i0.Input, args: [{ isSignal: true, alias: "customTemplates", required: false }] }], addItem: [{ type: i0.Output, args: ["addItem"] }], addSubItem: [{ type: i0.Output, args: ["addSubItem"] }], itemClick: [{ type: i0.Output, args: ["itemClick"] }], subItemClick: [{ type: i0.Output, args: ["subItemClick"] }] } });
|
|
3510
|
+
|
|
3511
|
+
const icons$1 = {
|
|
3512
|
+
'chevron-down': LucideChevronDown,
|
|
3513
|
+
'chevron-right': LucideChevronRight,
|
|
3514
|
+
plus: LucidePlus,
|
|
3515
|
+
pencil: LucidePencil,
|
|
3516
|
+
'trash-2': LucideTrash2,
|
|
3517
|
+
info: LucideInfo,
|
|
3518
|
+
};
|
|
3519
|
+
function getIcon$1(name) {
|
|
3520
|
+
return icons$1[name] ?? LucideChevronRight;
|
|
3521
|
+
}
|
|
3522
|
+
let fieldsetCounter = 0;
|
|
3523
|
+
class FieldsetComponent {
|
|
3524
|
+
constructor() {
|
|
3525
|
+
this.getIcon = getIcon$1;
|
|
3526
|
+
/** Title shown in the header. */
|
|
3527
|
+
this.legend = input('', ...(ngDevMode ? [{ debugName: "legend" }] : /* istanbul ignore next */ []));
|
|
3528
|
+
/** Collapsed state (default: collapsed). Two-way bindable with [(collapsed)]. */
|
|
3529
|
+
this.collapsed = model(true, ...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
|
|
3530
|
+
/** Whether the header toggles the content. */
|
|
3531
|
+
this.toggleable = input(true, ...(ngDevMode ? [{ debugName: "toggleable" }] : /* istanbul ignore next */ []));
|
|
3532
|
+
/** Shows the expand/collapse icon button. */
|
|
3533
|
+
this.showToggleIcon = input(true, ...(ngDevMode ? [{ debugName: "showToggleIcon" }] : /* istanbul ignore next */ []));
|
|
3534
|
+
/** Optional leading icon shown next to the legend. */
|
|
3535
|
+
this.icon = input('', ...(ngDevMode ? [{ debugName: "icon" }] : /* istanbul ignore next */ []));
|
|
3536
|
+
/** Optional badge/count shown after the legend. */
|
|
3537
|
+
this.badge = input('', ...(ngDevMode ? [{ debugName: "badge" }] : /* istanbul ignore next */ []));
|
|
3538
|
+
/** CSS classes for the badge (override). */
|
|
3539
|
+
this.badgeClass = input('', ...(ngDevMode ? [{ debugName: "badgeClass" }] : /* istanbul ignore next */ []));
|
|
3540
|
+
/** Icon shown when collapsed. */
|
|
3541
|
+
this.collapsedIcon = input('chevron-right', ...(ngDevMode ? [{ debugName: "collapsedIcon" }] : /* istanbul ignore next */ []));
|
|
3542
|
+
/** Icon shown when expanded. */
|
|
3543
|
+
this.expandedIcon = input('chevron-down', ...(ngDevMode ? [{ debugName: "expandedIcon" }] : /* istanbul ignore next */ []));
|
|
3544
|
+
/** Action buttons rendered on the right side of the header. */
|
|
3545
|
+
this.headerActions = input([], ...(ngDevMode ? [{ debugName: "headerActions" }] : /* istanbul ignore next */ []));
|
|
3546
|
+
/** Custom content templates: key 'legend' (context: $implicit collapsed, expanded). */
|
|
3547
|
+
this.customTemplates = input({}, ...(ngDevMode ? [{ debugName: "customTemplates" }] : /* istanbul ignore next */ []));
|
|
3548
|
+
this.hasShadow = input(true, ...(ngDevMode ? [{ debugName: "hasShadow" }] : /* istanbul ignore next */ []));
|
|
3549
|
+
this.expandLabel = input('Expandir', ...(ngDevMode ? [{ debugName: "expandLabel" }] : /* istanbul ignore next */ []));
|
|
3550
|
+
this.collapseLabel = input('Colapsar', ...(ngDevMode ? [{ debugName: "collapseLabel" }] : /* istanbul ignore next */ []));
|
|
3551
|
+
/** Emits the new expanded state when toggled. */
|
|
3552
|
+
this.toggle = output();
|
|
3553
|
+
this.expand = output();
|
|
3554
|
+
this.collapse = output();
|
|
3555
|
+
this.contentId = `shk-fieldset-content-${++fieldsetCounter}`;
|
|
3556
|
+
}
|
|
3557
|
+
onToggle() {
|
|
3558
|
+
if (!this.toggleable())
|
|
3559
|
+
return;
|
|
3560
|
+
const wasCollapsed = this.collapsed();
|
|
3561
|
+
const nowExpanded = wasCollapsed;
|
|
3562
|
+
this.collapsed.set(!wasCollapsed);
|
|
3563
|
+
this.toggle.emit(nowExpanded);
|
|
3564
|
+
if (nowExpanded) {
|
|
3565
|
+
this.expand.emit();
|
|
3566
|
+
}
|
|
3567
|
+
else {
|
|
3568
|
+
this.collapse.emit();
|
|
3569
|
+
}
|
|
3570
|
+
}
|
|
3571
|
+
isHeaderActionVisible(action) {
|
|
3572
|
+
return action.isVisible ? action.isVisible() : true;
|
|
3573
|
+
}
|
|
3574
|
+
isHeaderActionDisabled(action) {
|
|
3575
|
+
return action.isDisabled ? action.isDisabled() : false;
|
|
3576
|
+
}
|
|
3577
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: FieldsetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3578
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: FieldsetComponent, isStandalone: true, selector: "shk-fieldset", inputs: { legend: { classPropertyName: "legend", publicName: "legend", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, toggleable: { classPropertyName: "toggleable", publicName: "toggleable", isSignal: true, isRequired: false, transformFunction: null }, showToggleIcon: { classPropertyName: "showToggleIcon", publicName: "showToggleIcon", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, badge: { classPropertyName: "badge", publicName: "badge", isSignal: true, isRequired: false, transformFunction: null }, badgeClass: { classPropertyName: "badgeClass", publicName: "badgeClass", isSignal: true, isRequired: false, transformFunction: null }, collapsedIcon: { classPropertyName: "collapsedIcon", publicName: "collapsedIcon", isSignal: true, isRequired: false, transformFunction: null }, expandedIcon: { classPropertyName: "expandedIcon", publicName: "expandedIcon", isSignal: true, isRequired: false, transformFunction: null }, headerActions: { classPropertyName: "headerActions", publicName: "headerActions", isSignal: true, isRequired: false, transformFunction: null }, customTemplates: { classPropertyName: "customTemplates", publicName: "customTemplates", isSignal: true, isRequired: false, transformFunction: null }, hasShadow: { classPropertyName: "hasShadow", publicName: "hasShadow", isSignal: true, isRequired: false, transformFunction: null }, expandLabel: { classPropertyName: "expandLabel", publicName: "expandLabel", isSignal: true, isRequired: false, transformFunction: null }, collapseLabel: { classPropertyName: "collapseLabel", publicName: "collapseLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { collapsed: "collapsedChange", toggle: "toggle", expand: "expand", collapse: "collapse" }, ngImport: i0, template: "<div\n class=\"rounded-xl bg-white dark:[background-color:var(--shk-surface-50)] border _shk-border dark:[border-color:var(--shk-surface-200)] overflow-hidden\"\n [class.shadow-sm]=\"hasShadow()\"\n>\n <div\n class=\"flex items-center gap-2 px-4 py-3\"\n [class.border-b]=\"!collapsed()\"\n [class._shk-border]=\"!collapsed()\"\n [class.dark:[border-color:var(--shk-surface-200)]]=\"!collapsed()\"\n >\n <button\n type=\"button\"\n (click)=\"onToggle()\"\n [disabled]=\"!toggleable()\"\n [attr.aria-expanded]=\"!collapsed()\"\n [attr.aria-controls]=\"contentId\"\n class=\"flex items-center gap-2 flex-1 min-w-0 text-left group disabled:cursor-default\"\n >\n @if (customTemplates()['legend']) {\n <ng-container\n *ngTemplateOutlet=\"customTemplates()['legend']; context: { $implicit: collapsed(), expanded: !collapsed() }\"\n ></ng-container>\n } @else {\n @if (icon()) {\n <svg [lucideIcon]=\"getIcon(icon())\" class=\"w-4 h-4 _shk-text-primary shrink-0\"></svg>\n }\n <span class=\"font-semibold text-sm _shk-text-surface-800 dark:[color:var(--shk-surface-800)] truncate\">\n {{ legend() }}\n </span>\n @if (badge() !== undefined && badge() !== null && badge() !== '') {\n <span\n [class]=\"badgeClass() || 'inline-flex items-center px-2 py-0.5 rounded-full text-xs font-semibold _shk-bg-primary-soft _shk-text-primary-700 dark:[background-color:var(--shk-primary-900)] dark:[color:var(--shk-primary-300)] shrink-0'\"\n >\n {{ badge() }}\n </span>\n }\n }\n </button>\n\n @if (headerActions().length > 0) {\n <div class=\"flex items-center gap-0.5 shrink-0\">\n @for (action of headerActions(); track $index) {\n @if (isHeaderActionVisible(action)) {\n <div class=\"relative group\">\n <button\n type=\"button\"\n (click)=\"action.onClick()\"\n [class]=\"'fieldset-action-btn ' + (action.class || '')\"\n [disabled]=\"isHeaderActionDisabled(action)\"\n [attr.aria-label]=\"action.label\"\n >\n <svg [lucideIcon]=\"getIcon(action.icon)\" class=\"w-3.5 h-3.5\"></svg>\n </button>\n <span class=\"absolute bottom-full left-1/2 -translate-x-1/2 mb-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ action.label }}\n </span>\n </div>\n }\n }\n </div>\n }\n\n @if (toggleable() && showToggleIcon()) {\n <button\n type=\"button\"\n (click)=\"onToggle()\"\n [attr.aria-label]=\"collapsed() ? expandLabel() : collapseLabel()\"\n class=\"shk-fieldset-toggle shrink-0\"\n [disabled]=\"!toggleable()\"\n >\n <svg [lucideIcon]=\"getIcon(collapsed() ? collapsedIcon() : expandedIcon())\" class=\"w-4 h-4 transition-transform\"></svg>\n </button>\n }\n </div>\n\n @if (!collapsed()) {\n <div [id]=\"contentId\" class=\"shk-fieldset-content px-4 py-3.5\">\n <ng-content></ng-content>\n </div>\n }\n</div>\n", styles: [":host{display:block}.shk-fieldset-toggle{display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border-radius:.5rem;color:var(--shk-surface-400);transition:background-color .15s ease-in-out,color .15s ease-in-out}.shk-fieldset-toggle:hover:not(:disabled){background-color:var(--shk-surface-100);color:var(--shk-surface-700)}.shk-fieldset-toggle:disabled{cursor:default}.shk-fieldset-toggle svg{width:1rem!important;height:1rem!important}.fieldset-action-btn{display:inline-flex;align-items:center;justify-content:center;padding:.375rem;border-radius:.5rem;color:var(--shk-primary-600);transition:background-color .15s ease-in-out,color .15s ease-in-out,opacity .15s ease-in-out}.fieldset-action-btn:hover:not(:disabled){background-color:color-mix(in srgb,var(--shk-primary-50) 60%,transparent);color:var(--shk-primary-700)}.fieldset-action-btn:disabled{opacity:.4;cursor:not-allowed}.fieldset-action-btn svg{width:.875rem!important;height:.875rem!important}.shk-fieldset-content{animation:shk-fieldset-fade .25s ease-out}@keyframes shk-fieldset-fade{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: LucideDynamicIcon, selector: "svg[lucideIcon]", inputs: ["lucideIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
3579
|
+
}
|
|
3580
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: FieldsetComponent, decorators: [{
|
|
3581
|
+
type: Component,
|
|
3582
|
+
args: [{ selector: 'shk-fieldset', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, LucideDynamicIcon], template: "<div\n class=\"rounded-xl bg-white dark:[background-color:var(--shk-surface-50)] border _shk-border dark:[border-color:var(--shk-surface-200)] overflow-hidden\"\n [class.shadow-sm]=\"hasShadow()\"\n>\n <div\n class=\"flex items-center gap-2 px-4 py-3\"\n [class.border-b]=\"!collapsed()\"\n [class._shk-border]=\"!collapsed()\"\n [class.dark:[border-color:var(--shk-surface-200)]]=\"!collapsed()\"\n >\n <button\n type=\"button\"\n (click)=\"onToggle()\"\n [disabled]=\"!toggleable()\"\n [attr.aria-expanded]=\"!collapsed()\"\n [attr.aria-controls]=\"contentId\"\n class=\"flex items-center gap-2 flex-1 min-w-0 text-left group disabled:cursor-default\"\n >\n @if (customTemplates()['legend']) {\n <ng-container\n *ngTemplateOutlet=\"customTemplates()['legend']; context: { $implicit: collapsed(), expanded: !collapsed() }\"\n ></ng-container>\n } @else {\n @if (icon()) {\n <svg [lucideIcon]=\"getIcon(icon())\" class=\"w-4 h-4 _shk-text-primary shrink-0\"></svg>\n }\n <span class=\"font-semibold text-sm _shk-text-surface-800 dark:[color:var(--shk-surface-800)] truncate\">\n {{ legend() }}\n </span>\n @if (badge() !== undefined && badge() !== null && badge() !== '') {\n <span\n [class]=\"badgeClass() || 'inline-flex items-center px-2 py-0.5 rounded-full text-xs font-semibold _shk-bg-primary-soft _shk-text-primary-700 dark:[background-color:var(--shk-primary-900)] dark:[color:var(--shk-primary-300)] shrink-0'\"\n >\n {{ badge() }}\n </span>\n }\n }\n </button>\n\n @if (headerActions().length > 0) {\n <div class=\"flex items-center gap-0.5 shrink-0\">\n @for (action of headerActions(); track $index) {\n @if (isHeaderActionVisible(action)) {\n <div class=\"relative group\">\n <button\n type=\"button\"\n (click)=\"action.onClick()\"\n [class]=\"'fieldset-action-btn ' + (action.class || '')\"\n [disabled]=\"isHeaderActionDisabled(action)\"\n [attr.aria-label]=\"action.label\"\n >\n <svg [lucideIcon]=\"getIcon(action.icon)\" class=\"w-3.5 h-3.5\"></svg>\n </button>\n <span class=\"absolute bottom-full left-1/2 -translate-x-1/2 mb-1 px-2 py-1 text-xs _shk-bg-tooltip _shk-text-tooltip rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition pointer-events-none z-[9999] shadow-lg\">\n {{ action.label }}\n </span>\n </div>\n }\n }\n </div>\n }\n\n @if (toggleable() && showToggleIcon()) {\n <button\n type=\"button\"\n (click)=\"onToggle()\"\n [attr.aria-label]=\"collapsed() ? expandLabel() : collapseLabel()\"\n class=\"shk-fieldset-toggle shrink-0\"\n [disabled]=\"!toggleable()\"\n >\n <svg [lucideIcon]=\"getIcon(collapsed() ? collapsedIcon() : expandedIcon())\" class=\"w-4 h-4 transition-transform\"></svg>\n </button>\n }\n </div>\n\n @if (!collapsed()) {\n <div [id]=\"contentId\" class=\"shk-fieldset-content px-4 py-3.5\">\n <ng-content></ng-content>\n </div>\n }\n</div>\n", styles: [":host{display:block}.shk-fieldset-toggle{display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border-radius:.5rem;color:var(--shk-surface-400);transition:background-color .15s ease-in-out,color .15s ease-in-out}.shk-fieldset-toggle:hover:not(:disabled){background-color:var(--shk-surface-100);color:var(--shk-surface-700)}.shk-fieldset-toggle:disabled{cursor:default}.shk-fieldset-toggle svg{width:1rem!important;height:1rem!important}.fieldset-action-btn{display:inline-flex;align-items:center;justify-content:center;padding:.375rem;border-radius:.5rem;color:var(--shk-primary-600);transition:background-color .15s ease-in-out,color .15s ease-in-out,opacity .15s ease-in-out}.fieldset-action-btn:hover:not(:disabled){background-color:color-mix(in srgb,var(--shk-primary-50) 60%,transparent);color:var(--shk-primary-700)}.fieldset-action-btn:disabled{opacity:.4;cursor:not-allowed}.fieldset-action-btn svg{width:.875rem!important;height:.875rem!important}.shk-fieldset-content{animation:shk-fieldset-fade .25s ease-out}@keyframes shk-fieldset-fade{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}\n"] }]
|
|
3583
|
+
}], propDecorators: { legend: [{ type: i0.Input, args: [{ isSignal: true, alias: "legend", required: false }] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }, { type: i0.Output, args: ["collapsedChange"] }], toggleable: [{ type: i0.Input, args: [{ isSignal: true, alias: "toggleable", required: false }] }], showToggleIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "showToggleIcon", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], badge: [{ type: i0.Input, args: [{ isSignal: true, alias: "badge", required: false }] }], badgeClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "badgeClass", required: false }] }], collapsedIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsedIcon", required: false }] }], expandedIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandedIcon", required: false }] }], headerActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerActions", required: false }] }], customTemplates: [{ type: i0.Input, args: [{ isSignal: true, alias: "customTemplates", required: false }] }], hasShadow: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasShadow", required: false }] }], expandLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandLabel", required: false }] }], collapseLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapseLabel", required: false }] }], toggle: [{ type: i0.Output, args: ["toggle"] }], expand: [{ type: i0.Output, args: ["expand"] }], collapse: [{ type: i0.Output, args: ["collapse"] }] } });
|
|
3584
|
+
|
|
3585
|
+
const icons = {
|
|
3586
|
+
check: LucideCheck,
|
|
3587
|
+
'chevron-left': LucideChevronLeft,
|
|
3588
|
+
'chevron-right': LucideChevronRight,
|
|
3589
|
+
'arrow-left': LucideArrowLeft,
|
|
3590
|
+
x: LucideX,
|
|
3591
|
+
'loader-circle': LucideLoaderCircle,
|
|
3592
|
+
'file-contract': LucideScrollText,
|
|
3593
|
+
building: LucideBuilding,
|
|
3594
|
+
'user-round': LucideUserRound,
|
|
3595
|
+
info: LucideInfo,
|
|
3596
|
+
'clipboard-check': LucideClipboardCheck,
|
|
3597
|
+
package: LucidePackage,
|
|
3598
|
+
hotel: LucideHotel,
|
|
3599
|
+
map: LucideMap,
|
|
3600
|
+
tag: LucideTag,
|
|
3601
|
+
utensils: LucideUtensils,
|
|
3602
|
+
coins: LucideCoins,
|
|
3603
|
+
'sticky-note': LucideStickyNote,
|
|
3604
|
+
'circle-exclamation': LucideCircleAlert,
|
|
3605
|
+
'circle-alert': LucideCircleAlert,
|
|
3606
|
+
};
|
|
3607
|
+
function getIcon(name) {
|
|
3608
|
+
return icons[name] ?? LucideChevronRight;
|
|
3609
|
+
}
|
|
3610
|
+
/** Declares a step's content template: <ng-template shkWizardStepContent="stepId">…</ng-template>. */
|
|
3611
|
+
class ShkWizardStepContent {
|
|
3612
|
+
constructor(templateRef) {
|
|
3613
|
+
this.templateRef = templateRef;
|
|
3614
|
+
this.stepId = input.required({ ...(ngDevMode ? { debugName: "stepId" } : /* istanbul ignore next */ {}), alias: 'shkWizardStepContent' });
|
|
3615
|
+
}
|
|
3616
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: ShkWizardStepContent, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
3617
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.18", type: ShkWizardStepContent, isStandalone: true, selector: "ng-template[shkWizardStepContent]", inputs: { stepId: { classPropertyName: "stepId", publicName: "shkWizardStepContent", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 }); }
|
|
3618
|
+
}
|
|
3619
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: ShkWizardStepContent, decorators: [{
|
|
3620
|
+
type: Directive,
|
|
3621
|
+
args: [{
|
|
3622
|
+
selector: 'ng-template[shkWizardStepContent]',
|
|
3623
|
+
standalone: true,
|
|
3624
|
+
}]
|
|
3625
|
+
}], ctorParameters: () => [{ type: i0.TemplateRef }], propDecorators: { stepId: [{ type: i0.Input, args: [{ isSignal: true, alias: "shkWizardStepContent", required: true }] }] } });
|
|
3626
|
+
let wizardCounter = 0;
|
|
3627
|
+
class WizardComponent {
|
|
3628
|
+
constructor() {
|
|
3629
|
+
this.getIcon = getIcon;
|
|
3630
|
+
/** Steps definition shown in the stepper and used to resolve step content. */
|
|
3631
|
+
this.steps = input([], ...(ngDevMode ? [{ debugName: "steps" }] : /* istanbul ignore next */ []));
|
|
3632
|
+
/** Active step id. Two-way bindable with [(currentStep)]. Null resolves to the first step. */
|
|
3633
|
+
this.currentStep = model(null, ...(ngDevMode ? [{ debugName: "currentStep" }] : /* istanbul ignore next */ []));
|
|
3634
|
+
// Header
|
|
3635
|
+
/** Shows the sticky header (back button + title). */
|
|
3636
|
+
this.showHeader = input(true, ...(ngDevMode ? [{ debugName: "showHeader" }] : /* istanbul ignore next */ []));
|
|
3637
|
+
this.headerTitle = input('', ...(ngDevMode ? [{ debugName: "headerTitle" }] : /* istanbul ignore next */ []));
|
|
3638
|
+
this.headerSubtitle = input('', ...(ngDevMode ? [{ debugName: "headerSubtitle" }] : /* istanbul ignore next */ []));
|
|
3639
|
+
/** Shows the round back button in the header. */
|
|
3640
|
+
this.showBackButton = input(true, ...(ngDevMode ? [{ debugName: "showBackButton" }] : /* istanbul ignore next */ []));
|
|
3641
|
+
this.backTooltip = input('Atrás', ...(ngDevMode ? [{ debugName: "backTooltip" }] : /* istanbul ignore next */ []));
|
|
3642
|
+
/** Optional lucide icon shown before the title. */
|
|
3643
|
+
this.headerIcon = input('', ...(ngDevMode ? [{ debugName: "headerIcon" }] : /* istanbul ignore next */ []));
|
|
3644
|
+
// Stepper
|
|
3645
|
+
/** Shows the progress stepper (hide it for edit mode, like wac-app does). */
|
|
3646
|
+
this.showStepper = input(true, ...(ngDevMode ? [{ debugName: "showStepper" }] : /* istanbul ignore next */ []));
|
|
3647
|
+
/** Lets the user click on previous steps to jump back. */
|
|
3648
|
+
this.stepperClickable = input(false, ...(ngDevMode ? [{ debugName: "stepperClickable" }] : /* istanbul ignore next */ []));
|
|
3649
|
+
// Footer
|
|
3650
|
+
this.showFooter = input(true, ...(ngDevMode ? [{ debugName: "showFooter" }] : /* istanbul ignore next */ []));
|
|
3651
|
+
/** Shows a "Paso X / N" counter on the left of the footer. */
|
|
3652
|
+
this.showStepCounter = input(false, ...(ngDevMode ? [{ debugName: "showStepCounter" }] : /* istanbul ignore next */ []));
|
|
3653
|
+
this.stepCounterPrefix = input('Paso', ...(ngDevMode ? [{ debugName: "stepCounterPrefix" }] : /* istanbul ignore next */ []));
|
|
3654
|
+
/** Shows the Cancel button on the first step (instead of a back button). */
|
|
3655
|
+
this.showCancel = input(true, ...(ngDevMode ? [{ debugName: "showCancel" }] : /* istanbul ignore next */ []));
|
|
3656
|
+
/** Auto-advances to the next step on the primary button when it is not the last step. */
|
|
3657
|
+
this.advanceOnNext = input(true, ...(ngDevMode ? [{ debugName: "advanceOnNext" }] : /* istanbul ignore next */ []));
|
|
3658
|
+
this.prevLabel = input('Atrás', ...(ngDevMode ? [{ debugName: "prevLabel" }] : /* istanbul ignore next */ []));
|
|
3659
|
+
this.prevIcon = input('chevron-left', ...(ngDevMode ? [{ debugName: "prevIcon" }] : /* istanbul ignore next */ []));
|
|
3660
|
+
this.cancelLabel = input('Cancelar', ...(ngDevMode ? [{ debugName: "cancelLabel" }] : /* istanbul ignore next */ []));
|
|
3661
|
+
this.cancelIcon = input('x', ...(ngDevMode ? [{ debugName: "cancelIcon" }] : /* istanbul ignore next */ []));
|
|
3662
|
+
this.nextLabel = input('Continuar', ...(ngDevMode ? [{ debugName: "nextLabel" }] : /* istanbul ignore next */ []));
|
|
3663
|
+
this.nextIcon = input('chevron-right', ...(ngDevMode ? [{ debugName: "nextIcon" }] : /* istanbul ignore next */ []));
|
|
3664
|
+
this.finishLabel = input('Finalizar', ...(ngDevMode ? [{ debugName: "finishLabel" }] : /* istanbul ignore next */ []));
|
|
3665
|
+
this.finishIcon = input('check', ...(ngDevMode ? [{ debugName: "finishIcon" }] : /* istanbul ignore next */ []));
|
|
3666
|
+
/** Overrides the primary footer button label for every step. */
|
|
3667
|
+
this.primaryLabel = input(null, ...(ngDevMode ? [{ debugName: "primaryLabel" }] : /* istanbul ignore next */ []));
|
|
3668
|
+
/** Overrides the primary footer button icon for every step. */
|
|
3669
|
+
this.primaryIcon = input(null, ...(ngDevMode ? [{ debugName: "primaryIcon" }] : /* istanbul ignore next */ []));
|
|
3670
|
+
/** Shows a loading spinner on the primary button and disables it. */
|
|
3671
|
+
this.primaryLoading = input(false, ...(ngDevMode ? [{ debugName: "primaryLoading" }] : /* istanbul ignore next */ []));
|
|
3672
|
+
/** Disables the primary footer button (e.g. while the step form is invalid). */
|
|
3673
|
+
this.primaryDisabled = input(false, ...(ngDevMode ? [{ debugName: "primaryDisabled" }] : /* istanbul ignore next */ []));
|
|
3674
|
+
// Outputs
|
|
3675
|
+
this.back = output();
|
|
3676
|
+
this.cancel = output();
|
|
3677
|
+
this.prev = output();
|
|
3678
|
+
this.next = output();
|
|
3679
|
+
this.finish = output();
|
|
3680
|
+
this.stepChange = output();
|
|
3681
|
+
this.stepContents = contentChildren(ShkWizardStepContent, ...(ngDevMode ? [{ debugName: "stepContents" }] : /* istanbul ignore next */ []));
|
|
3682
|
+
this.currentIndex = computed(() => {
|
|
3683
|
+
const id = this.currentStep();
|
|
3684
|
+
if (id == null)
|
|
3685
|
+
return this.steps().length > 0 ? 0 : -1;
|
|
3686
|
+
return this.steps().findIndex((s) => s.id === id);
|
|
3687
|
+
}, ...(ngDevMode ? [{ debugName: "currentIndex" }] : /* istanbul ignore next */ []));
|
|
3688
|
+
this.currentStepObj = computed(() => this.steps()[this.currentIndex()] ?? null, ...(ngDevMode ? [{ debugName: "currentStepObj" }] : /* istanbul ignore next */ []));
|
|
3689
|
+
this.isFirstStep = computed(() => this.currentIndex() === 0, ...(ngDevMode ? [{ debugName: "isFirstStep" }] : /* istanbul ignore next */ []));
|
|
3690
|
+
this.isLastStep = computed(() => this.currentIndex() === this.steps().length - 1, ...(ngDevMode ? [{ debugName: "isLastStep" }] : /* istanbul ignore next */ []));
|
|
3691
|
+
this.primaryActionLabel = computed(() => {
|
|
3692
|
+
if (this.primaryLabel())
|
|
3693
|
+
return this.primaryLabel();
|
|
3694
|
+
const step = this.currentStepObj();
|
|
3695
|
+
if (step?.primaryLabel)
|
|
3696
|
+
return step.primaryLabel;
|
|
3697
|
+
return this.isLastStep() ? this.finishLabel() : this.nextLabel();
|
|
3698
|
+
}, ...(ngDevMode ? [{ debugName: "primaryActionLabel" }] : /* istanbul ignore next */ []));
|
|
3699
|
+
this.primaryActionIcon = computed(() => {
|
|
3700
|
+
if (this.primaryIcon())
|
|
3701
|
+
return this.primaryIcon();
|
|
3702
|
+
const step = this.currentStepObj();
|
|
3703
|
+
if (step?.primaryIcon)
|
|
3704
|
+
return step.primaryIcon;
|
|
3705
|
+
return this.isLastStep() ? this.finishIcon() : this.nextIcon();
|
|
3706
|
+
}, ...(ngDevMode ? [{ debugName: "primaryActionIcon" }] : /* istanbul ignore next */ []));
|
|
3707
|
+
}
|
|
3708
|
+
getStepTemplate(id) {
|
|
3709
|
+
return this.stepContents().find((c) => c.stepId() === id)?.templateRef;
|
|
3710
|
+
}
|
|
3711
|
+
goTo(stepId) {
|
|
3712
|
+
const idx = this.steps().findIndex((s) => s.id === stepId);
|
|
3713
|
+
if (idx < 0)
|
|
3714
|
+
return;
|
|
3715
|
+
if (this.currentStep() === stepId)
|
|
3716
|
+
return;
|
|
3717
|
+
this.currentStep.set(stepId);
|
|
3718
|
+
this.stepChange.emit({ step: this.steps()[idx], index: idx });
|
|
3719
|
+
}
|
|
3720
|
+
onPrev() {
|
|
3721
|
+
const idx = this.currentIndex();
|
|
3722
|
+
if (idx <= 0)
|
|
3723
|
+
return;
|
|
3724
|
+
this.prev.emit();
|
|
3725
|
+
this.goTo(this.steps()[idx - 1].id);
|
|
3726
|
+
}
|
|
3727
|
+
onNext() {
|
|
3728
|
+
const idx = this.currentIndex();
|
|
3729
|
+
const next = this.steps()[idx + 1];
|
|
3730
|
+
if (!next)
|
|
3731
|
+
return;
|
|
3732
|
+
this.next.emit();
|
|
3733
|
+
if (this.advanceOnNext()) {
|
|
3734
|
+
this.goTo(next.id);
|
|
3735
|
+
}
|
|
3736
|
+
}
|
|
3737
|
+
onPrimary() {
|
|
3738
|
+
if (this.primaryLoading() || this.primaryDisabled())
|
|
3739
|
+
return;
|
|
3740
|
+
if (this.isLastStep()) {
|
|
3741
|
+
this.finish.emit();
|
|
3742
|
+
}
|
|
3743
|
+
else {
|
|
3744
|
+
this.onNext();
|
|
3745
|
+
}
|
|
3746
|
+
}
|
|
3747
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: WizardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3748
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: WizardComponent, isStandalone: true, selector: "shk-wizard", inputs: { steps: { classPropertyName: "steps", publicName: "steps", isSignal: true, isRequired: false, transformFunction: null }, currentStep: { classPropertyName: "currentStep", publicName: "currentStep", isSignal: true, isRequired: false, transformFunction: null }, showHeader: { classPropertyName: "showHeader", publicName: "showHeader", isSignal: true, isRequired: false, transformFunction: null }, headerTitle: { classPropertyName: "headerTitle", publicName: "headerTitle", isSignal: true, isRequired: false, transformFunction: null }, headerSubtitle: { classPropertyName: "headerSubtitle", publicName: "headerSubtitle", isSignal: true, isRequired: false, transformFunction: null }, showBackButton: { classPropertyName: "showBackButton", publicName: "showBackButton", isSignal: true, isRequired: false, transformFunction: null }, backTooltip: { classPropertyName: "backTooltip", publicName: "backTooltip", isSignal: true, isRequired: false, transformFunction: null }, headerIcon: { classPropertyName: "headerIcon", publicName: "headerIcon", isSignal: true, isRequired: false, transformFunction: null }, showStepper: { classPropertyName: "showStepper", publicName: "showStepper", isSignal: true, isRequired: false, transformFunction: null }, stepperClickable: { classPropertyName: "stepperClickable", publicName: "stepperClickable", isSignal: true, isRequired: false, transformFunction: null }, showFooter: { classPropertyName: "showFooter", publicName: "showFooter", isSignal: true, isRequired: false, transformFunction: null }, showStepCounter: { classPropertyName: "showStepCounter", publicName: "showStepCounter", isSignal: true, isRequired: false, transformFunction: null }, stepCounterPrefix: { classPropertyName: "stepCounterPrefix", publicName: "stepCounterPrefix", isSignal: true, isRequired: false, transformFunction: null }, showCancel: { classPropertyName: "showCancel", publicName: "showCancel", isSignal: true, isRequired: false, transformFunction: null }, advanceOnNext: { classPropertyName: "advanceOnNext", publicName: "advanceOnNext", isSignal: true, isRequired: false, transformFunction: null }, prevLabel: { classPropertyName: "prevLabel", publicName: "prevLabel", isSignal: true, isRequired: false, transformFunction: null }, prevIcon: { classPropertyName: "prevIcon", publicName: "prevIcon", isSignal: true, isRequired: false, transformFunction: null }, cancelLabel: { classPropertyName: "cancelLabel", publicName: "cancelLabel", isSignal: true, isRequired: false, transformFunction: null }, cancelIcon: { classPropertyName: "cancelIcon", publicName: "cancelIcon", isSignal: true, isRequired: false, transformFunction: null }, nextLabel: { classPropertyName: "nextLabel", publicName: "nextLabel", isSignal: true, isRequired: false, transformFunction: null }, nextIcon: { classPropertyName: "nextIcon", publicName: "nextIcon", isSignal: true, isRequired: false, transformFunction: null }, finishLabel: { classPropertyName: "finishLabel", publicName: "finishLabel", isSignal: true, isRequired: false, transformFunction: null }, finishIcon: { classPropertyName: "finishIcon", publicName: "finishIcon", isSignal: true, isRequired: false, transformFunction: null }, primaryLabel: { classPropertyName: "primaryLabel", publicName: "primaryLabel", isSignal: true, isRequired: false, transformFunction: null }, primaryIcon: { classPropertyName: "primaryIcon", publicName: "primaryIcon", isSignal: true, isRequired: false, transformFunction: null }, primaryLoading: { classPropertyName: "primaryLoading", publicName: "primaryLoading", isSignal: true, isRequired: false, transformFunction: null }, primaryDisabled: { classPropertyName: "primaryDisabled", publicName: "primaryDisabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { currentStep: "currentStepChange", back: "back", cancel: "cancel", prev: "prev", next: "next", finish: "finish", stepChange: "stepChange" }, queries: [{ propertyName: "stepContents", predicate: ShkWizardStepContent, isSignal: true }], ngImport: i0, template: "<div class=\"min-h-full bg-transparent\">\n\n <!-- ============ Sticky Header + Stepper ============ -->\n @if (showHeader()) {\n <div\n class=\"sticky top-0 z-20 bg-white dark:[background-color:var(--shk-surface-50)] border-b _shk-border dark:[border-color:var(--shk-surface-200)] shadow-sm\"\n >\n <div class=\"w-full px-4 sm:px-6 lg:px-8 py-4\">\n <div class=\"flex items-center gap-4 mb-4\">\n @if (showBackButton()) {\n <button\n type=\"button\"\n (click)=\"back.emit()\"\n [attr.aria-label]=\"backTooltip()\"\n [attr.title]=\"backTooltip()\"\n class=\"shk-wizard-icon-btn shrink-0\"\n >\n <svg [lucideIcon]=\"getIcon('arrow-left')\" class=\"w-4 h-4\"></svg>\n </button>\n }\n <div class=\"flex-1 min-w-0 flex items-center gap-2.5\">\n @if (headerIcon()) {\n <span class=\"w-9 h-9 rounded-lg _shk-bg-primary-soft _shk-text-primary flex items-center justify-center shrink-0\">\n <svg [lucideIcon]=\"getIcon(headerIcon())\" class=\"w-4 h-4\"></svg>\n </span>\n }\n <div class=\"min-w-0\">\n <h1 class=\"text-xl font-bold _shk-text-surface-800 dark:[color:var(--shk-surface-800)] truncate\">\n {{ headerTitle() }}\n </h1>\n @if (headerSubtitle()) {\n <p class=\"text-xs _shk-text-surface-500 dark:[color:var(--shk-surface-500)] mt-0.5 truncate\">\n {{ headerSubtitle() }}\n </p>\n }\n </div>\n </div>\n <ng-content select=\"[shkWizardHeaderActions]\"></ng-content>\n </div>\n\n <!-- Stepper -->\n @if (showStepper() && steps().length > 1) {\n <div class=\"flex items-center gap-2 w-full max-w-3xl mx-auto\">\n @for (step of steps(); track step.id; let i = $index, last = $last) {\n <div class=\"flex items-center gap-3 shrink-0\">\n <button\n type=\"button\"\n (click)=\"goTo(step.id)\"\n [disabled]=\"!stepperClickable() || currentIndex() < i\"\n [attr.aria-label]=\"step.label\"\n class=\"shk-wizard-stepper-dot\"\n [class._shk-bg-primary]=\"currentIndex() > i || currentIndex() === i\"\n [class.text-white]=\"currentIndex() > i || currentIndex() === i\"\n [class._shk-bg-surface-200]=\"currentIndex() < i\"\n [class._shk-text-surface-500]=\"currentIndex() < i\"\n [class.cursor-pointer]=\"stepperClickable() && currentIndex() >= i\"\n [class.cursor-default]=\"!stepperClickable() || currentIndex() < i\"\n >\n @if (currentIndex() > i) {\n <svg [lucideIcon]=\"getIcon(step.icon || 'check')\" class=\"w-4 h-4\"></svg>\n } @else if (step.icon) {\n <svg [lucideIcon]=\"getIcon(step.icon)\" class=\"w-4 h-4\"></svg>\n } @else {\n {{ i + 1 }}\n }\n </button>\n <span\n class=\"text-sm font-semibold transition-colors whitespace-nowrap hidden sm:inline\"\n [class._shk-text-surface-800]=\"currentIndex() === i\"\n [class._shk-text-surface-500]=\"currentIndex() !== i\"\n [class.dark:[color:var(--shk-surface-800)]]=\"currentIndex() === i\"\n [class.dark:[color:var(--shk-surface-500)]]=\"currentIndex() !== i\"\n >\n {{ step.label }}\n </span>\n </div>\n\n @if (!last) {\n <div class=\"flex-1 h-0.5 _shk-bg-surface-200 dark:[background-color:var(--shk-surface-200)] relative overflow-hidden rounded-full\">\n <div\n class=\"absolute inset-y-0 left-0 _shk-bg-primary transition-all duration-300\"\n [class.w-full]=\"currentIndex() > i\"\n [class.w-0]=\"currentIndex() <= i\"\n ></div>\n </div>\n }\n }\n </div>\n }\n </div>\n </div>\n }\n\n <!-- ============ Active step content ============ -->\n <div class=\"w-full px-4 sm:px-6 lg:px-8 py-6 pb-28\">\n @if (currentIndex() >= 0) {\n @if (getStepTemplate(steps()[currentIndex()].id); as tpl) {\n <div class=\"shk-wizard-fade\" [style.view-transition-name]=\"'shk-wizard-step'\">\n <ng-container\n *ngTemplateOutlet=\"tpl; context: { step: currentStepObj(), index: currentIndex() }\"\n ></ng-container>\n </div>\n } @else {\n <p class=\"text-sm _shk-text-surface-400 dark:[color:var(--shk-surface-400)]\">\n No hay contenido definido para el paso \u00AB{{ steps()[currentIndex()].label }}\u00BB.\n </p>\n }\n }\n </div>\n\n <!-- ============ Sticky Footer ============ -->\n @if (showFooter() && steps().length > 0) {\n <div\n class=\"sticky bottom-0 z-20 bg-white dark:[background-color:var(--shk-surface-50)] border-t _shk-border dark:[border-color:var(--shk-surface-200)] shadow-[0_-4px_12px_rgba(0,0,0,0.04)] mt-8\"\n >\n <div class=\"w-full px-4 sm:px-6 lg:px-8 py-4 flex items-center justify-end gap-3\">\n @if (showStepCounter()) {\n <span class=\"text-sm _shk-text-surface-500 dark:[color:var(--shk-surface-500)] mr-auto\">\n {{ stepCounterPrefix() }} {{ currentIndex() + 1 }} / {{ steps().length }}\n </span>\n }\n\n @if (isFirstStep()) {\n @if (showCancel()) {\n <button type=\"button\" (click)=\"cancel.emit()\" class=\"shk-wizard-btn-secondary\">\n @if (cancelIcon()) {\n <svg [lucideIcon]=\"getIcon(cancelIcon())\" class=\"w-4 h-4\"></svg>\n }\n {{ cancelLabel() }}\n </button>\n }\n } @else {\n <button type=\"button\" (click)=\"onPrev()\" class=\"shk-wizard-btn-secondary\">\n <svg [lucideIcon]=\"getIcon(prevIcon())\" class=\"w-4 h-4\"></svg>\n {{ prevLabel() }}\n </button>\n }\n\n <button\n type=\"button\"\n (click)=\"onPrimary()\"\n [disabled]=\"primaryDisabled() || primaryLoading()\"\n class=\"shk-wizard-btn-primary\"\n >\n @if (primaryLoading()) {\n <svg [lucideIcon]=\"getIcon('loader-circle')\" class=\"w-4 h-4 shk-wizard-spin\"></svg>\n } @else {\n @if (primaryActionIcon()) {\n <svg [lucideIcon]=\"getIcon(primaryActionIcon())\" class=\"w-4 h-4\"></svg>\n }\n }\n {{ primaryActionLabel() }}\n </button>\n </div>\n </div>\n }\n</div>\n", styles: [":host{display:block}.shk-wizard-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border-radius:9999px;color:var(--shk-surface-600);transition:background-color .15s ease-in-out,color .15s ease-in-out}.shk-wizard-icon-btn:hover:not(:disabled){background-color:var(--shk-surface-100);color:var(--shk-surface-800)}.shk-wizard-icon-btn:disabled{cursor:default}.shk-wizard-icon-btn svg{width:1rem!important;height:1rem!important}.shk-wizard-stepper-dot{display:flex;align-items:center;justify-content:center;width:2.25rem;height:2.25rem;border-radius:9999px;font-size:.875rem;font-weight:700;flex-shrink:0;transition:background-color .15s ease-in-out,color .15s ease-in-out}.shk-wizard-stepper-dot svg{width:1rem!important;height:1rem!important}.shk-wizard-btn-secondary{display:inline-flex;align-items:center;gap:.5rem;padding:.5rem 1rem;border-radius:.5rem;font-size:.875rem;font-weight:500;color:var(--shk-surface-700);background-color:transparent;border:1px solid var(--shk-surface-200);transition:background-color .15s ease-in-out,border-color .15s ease-in-out,color .15s ease-in-out}.shk-wizard-btn-secondary:hover:not(:disabled){background-color:var(--shk-surface-100);border-color:var(--shk-surface-300);color:var(--shk-surface-900)}.shk-wizard-btn-secondary:disabled{opacity:.5;cursor:not-allowed}.shk-wizard-btn-secondary svg{width:1rem!important;height:1rem!important}.shk-wizard-btn-primary{display:inline-flex;align-items:center;gap:.5rem;padding:.5rem 1rem;border-radius:.5rem;font-size:.875rem;font-weight:500;color:#fff;background-color:var(--shk-primary-600);box-shadow:0 6px 20px -6px color-mix(in srgb,var(--shk-primary-600) 55%,transparent);transition:background-color .15s ease-in-out,opacity .15s ease-in-out}.shk-wizard-btn-primary:hover:not(:disabled){background-color:var(--shk-primary-700)}.shk-wizard-btn-primary:disabled{opacity:.5;cursor:not-allowed;box-shadow:none}.shk-wizard-btn-primary svg{width:1rem!important;height:1rem!important}.shk-wizard-spin{animation:shk-wizard-spin .8s linear infinite}@keyframes shk-wizard-spin{to{transform:rotate(360deg)}}.shk-wizard-fade{animation:shk-wizard-fade .25s ease-out}@keyframes shk-wizard-fade{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: LucideDynamicIcon, selector: "svg[lucideIcon]", inputs: ["lucideIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
3749
|
+
}
|
|
3750
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: WizardComponent, decorators: [{
|
|
3751
|
+
type: Component,
|
|
3752
|
+
args: [{ selector: 'shk-wizard', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, LucideDynamicIcon], template: "<div class=\"min-h-full bg-transparent\">\n\n <!-- ============ Sticky Header + Stepper ============ -->\n @if (showHeader()) {\n <div\n class=\"sticky top-0 z-20 bg-white dark:[background-color:var(--shk-surface-50)] border-b _shk-border dark:[border-color:var(--shk-surface-200)] shadow-sm\"\n >\n <div class=\"w-full px-4 sm:px-6 lg:px-8 py-4\">\n <div class=\"flex items-center gap-4 mb-4\">\n @if (showBackButton()) {\n <button\n type=\"button\"\n (click)=\"back.emit()\"\n [attr.aria-label]=\"backTooltip()\"\n [attr.title]=\"backTooltip()\"\n class=\"shk-wizard-icon-btn shrink-0\"\n >\n <svg [lucideIcon]=\"getIcon('arrow-left')\" class=\"w-4 h-4\"></svg>\n </button>\n }\n <div class=\"flex-1 min-w-0 flex items-center gap-2.5\">\n @if (headerIcon()) {\n <span class=\"w-9 h-9 rounded-lg _shk-bg-primary-soft _shk-text-primary flex items-center justify-center shrink-0\">\n <svg [lucideIcon]=\"getIcon(headerIcon())\" class=\"w-4 h-4\"></svg>\n </span>\n }\n <div class=\"min-w-0\">\n <h1 class=\"text-xl font-bold _shk-text-surface-800 dark:[color:var(--shk-surface-800)] truncate\">\n {{ headerTitle() }}\n </h1>\n @if (headerSubtitle()) {\n <p class=\"text-xs _shk-text-surface-500 dark:[color:var(--shk-surface-500)] mt-0.5 truncate\">\n {{ headerSubtitle() }}\n </p>\n }\n </div>\n </div>\n <ng-content select=\"[shkWizardHeaderActions]\"></ng-content>\n </div>\n\n <!-- Stepper -->\n @if (showStepper() && steps().length > 1) {\n <div class=\"flex items-center gap-2 w-full max-w-3xl mx-auto\">\n @for (step of steps(); track step.id; let i = $index, last = $last) {\n <div class=\"flex items-center gap-3 shrink-0\">\n <button\n type=\"button\"\n (click)=\"goTo(step.id)\"\n [disabled]=\"!stepperClickable() || currentIndex() < i\"\n [attr.aria-label]=\"step.label\"\n class=\"shk-wizard-stepper-dot\"\n [class._shk-bg-primary]=\"currentIndex() > i || currentIndex() === i\"\n [class.text-white]=\"currentIndex() > i || currentIndex() === i\"\n [class._shk-bg-surface-200]=\"currentIndex() < i\"\n [class._shk-text-surface-500]=\"currentIndex() < i\"\n [class.cursor-pointer]=\"stepperClickable() && currentIndex() >= i\"\n [class.cursor-default]=\"!stepperClickable() || currentIndex() < i\"\n >\n @if (currentIndex() > i) {\n <svg [lucideIcon]=\"getIcon(step.icon || 'check')\" class=\"w-4 h-4\"></svg>\n } @else if (step.icon) {\n <svg [lucideIcon]=\"getIcon(step.icon)\" class=\"w-4 h-4\"></svg>\n } @else {\n {{ i + 1 }}\n }\n </button>\n <span\n class=\"text-sm font-semibold transition-colors whitespace-nowrap hidden sm:inline\"\n [class._shk-text-surface-800]=\"currentIndex() === i\"\n [class._shk-text-surface-500]=\"currentIndex() !== i\"\n [class.dark:[color:var(--shk-surface-800)]]=\"currentIndex() === i\"\n [class.dark:[color:var(--shk-surface-500)]]=\"currentIndex() !== i\"\n >\n {{ step.label }}\n </span>\n </div>\n\n @if (!last) {\n <div class=\"flex-1 h-0.5 _shk-bg-surface-200 dark:[background-color:var(--shk-surface-200)] relative overflow-hidden rounded-full\">\n <div\n class=\"absolute inset-y-0 left-0 _shk-bg-primary transition-all duration-300\"\n [class.w-full]=\"currentIndex() > i\"\n [class.w-0]=\"currentIndex() <= i\"\n ></div>\n </div>\n }\n }\n </div>\n }\n </div>\n </div>\n }\n\n <!-- ============ Active step content ============ -->\n <div class=\"w-full px-4 sm:px-6 lg:px-8 py-6 pb-28\">\n @if (currentIndex() >= 0) {\n @if (getStepTemplate(steps()[currentIndex()].id); as tpl) {\n <div class=\"shk-wizard-fade\" [style.view-transition-name]=\"'shk-wizard-step'\">\n <ng-container\n *ngTemplateOutlet=\"tpl; context: { step: currentStepObj(), index: currentIndex() }\"\n ></ng-container>\n </div>\n } @else {\n <p class=\"text-sm _shk-text-surface-400 dark:[color:var(--shk-surface-400)]\">\n No hay contenido definido para el paso \u00AB{{ steps()[currentIndex()].label }}\u00BB.\n </p>\n }\n }\n </div>\n\n <!-- ============ Sticky Footer ============ -->\n @if (showFooter() && steps().length > 0) {\n <div\n class=\"sticky bottom-0 z-20 bg-white dark:[background-color:var(--shk-surface-50)] border-t _shk-border dark:[border-color:var(--shk-surface-200)] shadow-[0_-4px_12px_rgba(0,0,0,0.04)] mt-8\"\n >\n <div class=\"w-full px-4 sm:px-6 lg:px-8 py-4 flex items-center justify-end gap-3\">\n @if (showStepCounter()) {\n <span class=\"text-sm _shk-text-surface-500 dark:[color:var(--shk-surface-500)] mr-auto\">\n {{ stepCounterPrefix() }} {{ currentIndex() + 1 }} / {{ steps().length }}\n </span>\n }\n\n @if (isFirstStep()) {\n @if (showCancel()) {\n <button type=\"button\" (click)=\"cancel.emit()\" class=\"shk-wizard-btn-secondary\">\n @if (cancelIcon()) {\n <svg [lucideIcon]=\"getIcon(cancelIcon())\" class=\"w-4 h-4\"></svg>\n }\n {{ cancelLabel() }}\n </button>\n }\n } @else {\n <button type=\"button\" (click)=\"onPrev()\" class=\"shk-wizard-btn-secondary\">\n <svg [lucideIcon]=\"getIcon(prevIcon())\" class=\"w-4 h-4\"></svg>\n {{ prevLabel() }}\n </button>\n }\n\n <button\n type=\"button\"\n (click)=\"onPrimary()\"\n [disabled]=\"primaryDisabled() || primaryLoading()\"\n class=\"shk-wizard-btn-primary\"\n >\n @if (primaryLoading()) {\n <svg [lucideIcon]=\"getIcon('loader-circle')\" class=\"w-4 h-4 shk-wizard-spin\"></svg>\n } @else {\n @if (primaryActionIcon()) {\n <svg [lucideIcon]=\"getIcon(primaryActionIcon())\" class=\"w-4 h-4\"></svg>\n }\n }\n {{ primaryActionLabel() }}\n </button>\n </div>\n </div>\n }\n</div>\n", styles: [":host{display:block}.shk-wizard-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border-radius:9999px;color:var(--shk-surface-600);transition:background-color .15s ease-in-out,color .15s ease-in-out}.shk-wizard-icon-btn:hover:not(:disabled){background-color:var(--shk-surface-100);color:var(--shk-surface-800)}.shk-wizard-icon-btn:disabled{cursor:default}.shk-wizard-icon-btn svg{width:1rem!important;height:1rem!important}.shk-wizard-stepper-dot{display:flex;align-items:center;justify-content:center;width:2.25rem;height:2.25rem;border-radius:9999px;font-size:.875rem;font-weight:700;flex-shrink:0;transition:background-color .15s ease-in-out,color .15s ease-in-out}.shk-wizard-stepper-dot svg{width:1rem!important;height:1rem!important}.shk-wizard-btn-secondary{display:inline-flex;align-items:center;gap:.5rem;padding:.5rem 1rem;border-radius:.5rem;font-size:.875rem;font-weight:500;color:var(--shk-surface-700);background-color:transparent;border:1px solid var(--shk-surface-200);transition:background-color .15s ease-in-out,border-color .15s ease-in-out,color .15s ease-in-out}.shk-wizard-btn-secondary:hover:not(:disabled){background-color:var(--shk-surface-100);border-color:var(--shk-surface-300);color:var(--shk-surface-900)}.shk-wizard-btn-secondary:disabled{opacity:.5;cursor:not-allowed}.shk-wizard-btn-secondary svg{width:1rem!important;height:1rem!important}.shk-wizard-btn-primary{display:inline-flex;align-items:center;gap:.5rem;padding:.5rem 1rem;border-radius:.5rem;font-size:.875rem;font-weight:500;color:#fff;background-color:var(--shk-primary-600);box-shadow:0 6px 20px -6px color-mix(in srgb,var(--shk-primary-600) 55%,transparent);transition:background-color .15s ease-in-out,opacity .15s ease-in-out}.shk-wizard-btn-primary:hover:not(:disabled){background-color:var(--shk-primary-700)}.shk-wizard-btn-primary:disabled{opacity:.5;cursor:not-allowed;box-shadow:none}.shk-wizard-btn-primary svg{width:1rem!important;height:1rem!important}.shk-wizard-spin{animation:shk-wizard-spin .8s linear infinite}@keyframes shk-wizard-spin{to{transform:rotate(360deg)}}.shk-wizard-fade{animation:shk-wizard-fade .25s ease-out}@keyframes shk-wizard-fade{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}\n"] }]
|
|
3753
|
+
}], propDecorators: { steps: [{ type: i0.Input, args: [{ isSignal: true, alias: "steps", required: false }] }], currentStep: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentStep", required: false }] }, { type: i0.Output, args: ["currentStepChange"] }], showHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "showHeader", required: false }] }], headerTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerTitle", required: false }] }], headerSubtitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerSubtitle", required: false }] }], showBackButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showBackButton", required: false }] }], backTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "backTooltip", required: false }] }], headerIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerIcon", required: false }] }], showStepper: [{ type: i0.Input, args: [{ isSignal: true, alias: "showStepper", required: false }] }], stepperClickable: [{ type: i0.Input, args: [{ isSignal: true, alias: "stepperClickable", required: false }] }], showFooter: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFooter", required: false }] }], showStepCounter: [{ type: i0.Input, args: [{ isSignal: true, alias: "showStepCounter", required: false }] }], stepCounterPrefix: [{ type: i0.Input, args: [{ isSignal: true, alias: "stepCounterPrefix", required: false }] }], showCancel: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCancel", required: false }] }], advanceOnNext: [{ type: i0.Input, args: [{ isSignal: true, alias: "advanceOnNext", required: false }] }], prevLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "prevLabel", required: false }] }], prevIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "prevIcon", required: false }] }], cancelLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "cancelLabel", required: false }] }], cancelIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "cancelIcon", required: false }] }], nextLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "nextLabel", required: false }] }], nextIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "nextIcon", required: false }] }], finishLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "finishLabel", required: false }] }], finishIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "finishIcon", required: false }] }], primaryLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "primaryLabel", required: false }] }], primaryIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "primaryIcon", required: false }] }], primaryLoading: [{ type: i0.Input, args: [{ isSignal: true, alias: "primaryLoading", required: false }] }], primaryDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "primaryDisabled", required: false }] }], back: [{ type: i0.Output, args: ["back"] }], cancel: [{ type: i0.Output, args: ["cancel"] }], prev: [{ type: i0.Output, args: ["prev"] }], next: [{ type: i0.Output, args: ["next"] }], finish: [{ type: i0.Output, args: ["finish"] }], stepChange: [{ type: i0.Output, args: ["stepChange"] }], stepContents: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => ShkWizardStepContent), { isSignal: true }] }] } });
|
|
3754
|
+
|
|
2909
3755
|
/* Theme — import theme.css in your global styles.css:
|
|
2910
3756
|
@import '@shirkasoft/ui-components/theme.css';
|
|
2911
3757
|
Override --shk-* CSS variables at :root or .dark to theme.
|
|
@@ -2915,5 +3761,5 @@ function readThemeColors() {
|
|
|
2915
3761
|
* Generated bundle index. Do not edit.
|
|
2916
3762
|
*/
|
|
2917
3763
|
|
|
2918
|
-
export { COLOR_PALETTE, ChartComponent, ConfirmDialogComponent, ConfirmDialogService, DatePickerComponent, FileUploadComponent, ModalComponent, ModalService, NotificationComponent, NotificationService, PriceInputComponent, SelectComponent, TableComponent, TextFieldComponent, ToggleComponent, TooltipComponent, readThemeColors };
|
|
3764
|
+
export { COLOR_PALETTE, ChartComponent, ConfirmDialogComponent, ConfirmDialogService, DEFAULT_MARKER_GRADIENTS, DEFAULT_SUPPLIER_ICON_COLORS, DEFAULT_SUPPLIER_TYPE_ICONS, DatePickerComponent, FieldsetComponent, FileUploadComponent, ModalComponent, ModalService, NotificationComponent, NotificationService, PriceInputComponent, RailSidebarComponent, SelectComponent, ShkWizardStepContent, SidebarComponent, TableComponent, TextFieldComponent, TimelineComponent, ToggleComponent, TooltipComponent, WizardComponent, readThemeColors };
|
|
2919
3765
|
//# sourceMappingURL=shirkasoft-ui-components.mjs.map
|