shirkasoft-ui-components 1.3.0 → 1.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"shirkasoft-ui-components-price-input.mjs","sources":["../../../projects/ui-components/price-input/price-input.component.ts","../../../projects/ui-components/price-input/price-input.component.html","../../../projects/ui-components/price-input/shirkasoft-ui-components-price-input.ts"],"sourcesContent":["import { Component, model, input, ChangeDetectionStrategy } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\n\n/**\n * Shirkasoft UI Components.\n * Authors: Roberto Valladares Martin (Ansem13), Julio César García García (Sanjuli14).\n * Belongs to Shirkasoft.\n */\n\n/**\n * Numeric input tailored for currency values with a optional percentage mode.\n * Uses two-way bindable models: `value` and `isPercentage`.\n */\n@Component({\n selector: 'shk-price-input',\n standalone: true,\n imports: [CommonModule, FormsModule],\n templateUrl: './price-input.component.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class PriceInputComponent {\n /** Numeric value, bindable with [(value)]. */\n value = model.required<number>();\n /** Whether the input works as a percentage, bindable with [(isPercentage)]. */\n isPercentage = model<boolean>(false);\n /** Label displayed above the field. */\n label = input<string>('');\n /** id attribute applied to the native input. */\n inputId = input<string>('');\n /** Marks the field as required. */\n required = input<boolean>(false);\n /** Disables the input. */\n disabled = input<boolean>(false);\n /** Minimum allowed value. */\n min = input<number>(0);\n /** Maximum allowed value. */\n max = input<number>(Infinity);\n /** Shows the error styling on the field. */\n showError = input<boolean>(false);\n /** Message rendered when the field is in error state. */\n errorMessage = input<string>('');\n\n /** Toggles between amount and percentage modes (unless disabled). */\n toggleMode(): void {\n if (this.disabled()) return;\n this.isPercentage.update(v => !v);\n }\n\n /** Parses the user input and updates the bound `value`. */\n onInput(event: Event): void {\n const input = event.target as HTMLInputElement;\n this.value.set(parseFloat(input.value) || 0);\n }\n}\n","<div>\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 @if (required()) {\n <span class=\"text-red-400\">*</span>\n }\n </div>\n }\n <div class=\"flex\">\n <input\n [id]=\"inputId()\"\n type=\"number\"\n [ngModel]=\"value()\"\n (ngModelChange)=\"value.set($event ?? 0)\"\n (input)=\"onInput($event)\"\n [disabled]=\"disabled()\"\n [min]=\"min()\"\n [max]=\"max()\"\n step=\"0.01\"\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: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': showError(),\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)]': !showError()\n }\"\n />\n <button\n type=\"button\"\n (click)=\"toggleMode()\"\n [disabled]=\"disabled()\"\n class=\"px-3 py-2 text-sm font-medium border rounded-r-lg transition-colors shrink-0\"\n [ngClass]=\"{\n '_shk-bg-primary-soft _shk-border-primary-200 _shk-text-primary-700 dark:[background-color:var(--shk-primary-900)] dark:[border-color:var(--shk-primary-700)] dark:[color:var(--shk-primary-300)]': isPercentage(),\n '_shk-bg-white _shk-border _shk-text-surface-500 dark:[background-color:var(--shk-surface-100)] dark:[border-color:var(--shk-surface-200)] dark:[color:var(--shk-surface-400)]': !isPercentage(),\n 'cursor-not-allowed opacity-50': disabled()\n }\"\n >\n {{ isPercentage() ? '%' : '$' }}\n </button>\n </div>\n @if (showError()) {\n <div class=\"text-xs _shk-text-red-500 mt-1\">\n {{ errorMessage() }}\n </div>\n }\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"shirkasoft-ui-components-price-input.mjs","sources":["../../../projects/ui-components/price-input/price-input.component.ts","../../../projects/ui-components/price-input/price-input.component.html","../../../projects/ui-components/price-input/shirkasoft-ui-components-price-input.ts"],"sourcesContent":["import {\n Component,\n model,\n input,\n signal,\n computed,\n effect,\n inject,\n forwardRef,\n DestroyRef,\n ChangeDetectionStrategy,\n} from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport {\n ControlValueAccessor,\n FormControl,\n NG_VALUE_ACCESSOR,\n ReactiveFormsModule,\n} from '@angular/forms';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\n/**\n * Shirkasoft UI Components.\n * Authors: Roberto Valladares Martin (Ansem13), Julio César García García (Sanjuli14).\n * Belongs to Shirkasoft.\n */\n\n/**\n * Currency/percentage numeric input with reactive forms support.\n *\n * Binding modes (highest precedence first):\n * - `control`: a FormControl (or use it inside a form with `formControlName`).\n * - `value`/`valueChange` or `[(value)]`: two-way model signals.\n *\n * Text-based input (`type=\"text\"` + `inputmode=\"decimal\"`) with decimal\n * precision control, min/max clamping on blur and thousands formatting.\n */\n@Component({\n selector: 'shk-price-input',\n standalone: true,\n imports: [CommonModule, ReactiveFormsModule],\n templateUrl: './price-input.component.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => PriceInputComponent),\n multi: true,\n },\n ],\n})\nexport class PriceInputComponent implements ControlValueAccessor {\n /** Reactive control. When provided it takes precedence over `value`/`valueChange`. */\n control = input<FormControl<number | null> | undefined>(undefined);\n /** Numeric value (two-way), used when no `control` is bound. */\n value = model<number | null>(0);\n /** Whether the input works as a percentage (two-way). */\n isPercentage = model<boolean>(false);\n /** Label displayed above the field. */\n label = input<string>('');\n /** id attribute applied to the native input. */\n inputId = input<string>('');\n /** Marks the field as required. */\n required = input<boolean>(false);\n /** Disables the input. */\n disabled = input<boolean>(false);\n /** Minimum allowed value (clamped on blur). */\n min = input<number>(0);\n /** Maximum allowed value (clamped on blur). */\n max = input<number>(Infinity);\n /** Maximum number of decimal places (0 = integer). */\n decimals = input<number>(2);\n /** Symbol shown in the mode toggle button when not a percentage. */\n currency = input<string>('$');\n /** Placeholder text of the native input. */\n placeholder = input<string>('');\n /** Accessible label; falls back to `label`. */\n ariaLabel = input<string>('');\n /** Blocks the minus sign from being typed. */\n preventNegative = input<boolean>(false);\n /** Shows the error styling on the field. */\n showError = input<boolean>(false);\n /** Message rendered when the field is in error state. */\n errorMessage = input<string>('');\n\n private destroyRef = inject(DestroyRef);\n\n /** Text currently shown in the input (raw while focused, formatted on blur). */\n displayText = signal<string>('');\n /** Whether the native input currently has focus. */\n focused = signal<boolean>(false);\n /** Disabled state coming from the reactive control. */\n private controlDisabled = signal<boolean>(false);\n /** Prevents re-subscribing to the same form control. */\n private ctrlSubscribed = false;\n\n /** Effective disabled state combining the input and the form binding. */\n isDisabled = computed(() => this.disabled() || this.controlDisabled());\n\n /** Callbacks used by the ControlValueAccessor contract. */\n private onChange: (value: number | null) => void = () => {};\n private onTouched: () => void = () => {};\n\n constructor() {\n // Subscribe once to the bound control for change/status tracking.\n effect(() => {\n const ctrl = this.control();\n if (!ctrl || this.ctrlSubscribed) return;\n this.ctrlSubscribed = true;\n this.controlDisabled.set(ctrl.disabled);\n\n ctrl.valueChanges.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((v) => {\n if (!this.focused()) {\n this.displayText.set(this.formatNumber(v ?? 0));\n }\n });\n ctrl.statusChanges.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {\n this.controlDisabled.set(ctrl.disabled);\n });\n });\n\n // Reflect the effective value into the display (unless the user is typing).\n effect(() => {\n const ctrl = this.control();\n const v = ctrl ? (ctrl.value as number | null) : this.value();\n if (!this.focused()) {\n this.displayText.set(this.formatNumber(v ?? 0));\n }\n });\n }\n\n /** Toggles between amount and percentage modes (unless disabled). */\n toggleMode(): void {\n if (this.isDisabled()) return;\n this.isPercentage.update((v) => !v);\n }\n\n /** Selects the whole value on focus so the user can type over it. */\n onFocus(event: FocusEvent): void {\n this.focused.set(true);\n (event.target as HTMLInputElement).select();\n }\n\n /** Clamps, rounds and formats the value when the field loses focus. */\n onBlur(): void {\n this.focused.set(false);\n this.onTouched();\n\n let v = parseFloat(this.displayText().replace(/,/g, ''));\n if (isNaN(v)) v = 0;\n\n const min = this.min();\n const max = this.max();\n if (isFinite(min) && v < min) v = min;\n if (isFinite(max) && v > max) v = max;\n\n v = this.roundTo(v);\n this.setValue(v);\n this.displayText.set(this.formatNumber(v));\n }\n\n /** Blocks characters that would break the numeric format. */\n onKeydown(event: KeyboardEvent): void {\n const allowed = [\n 'Backspace',\n 'Tab',\n 'End',\n 'Home',\n 'ArrowLeft',\n 'ArrowRight',\n 'Delete',\n 'Enter',\n 'Escape',\n ];\n if (allowed.includes(event.key)) return;\n if (/^\\d$/.test(event.key)) return;\n\n if (event.key === '.' || event.key === ',') {\n const input = event.target as HTMLInputElement;\n if (input.value.includes('.') || input.value.includes(',')) event.preventDefault();\n return;\n }\n\n if (event.key === '-') {\n const input = event.target as HTMLInputElement;\n if (this.preventNegative() || this.min() >= 0) {\n event.preventDefault();\n } else if (input.value.includes('-')) {\n event.preventDefault();\n }\n return;\n }\n\n event.preventDefault();\n }\n\n /** Sanitizes the raw input (digits + one separator + optional sign) and writes the value once. */\n onInput(event: Event): void {\n const input = event.target as HTMLInputElement;\n const pos = input.selectionStart ?? input.value.length;\n\n let cleaned = input.value.replace(/[^0-9.,-]/g, '');\n if (this.preventNegative() || this.min() >= 0) cleaned = cleaned.replace(/-/g, '');\n cleaned = cleaned.replace(/,/g, '.');\n\n const dot = cleaned.indexOf('.');\n if (dot >= 0) {\n const dec = Math.max(0, this.decimals());\n const intPart = cleaned.slice(0, dot);\n const decPart = cleaned.slice(dot + 1, dot + 1 + dec);\n cleaned = intPart + '.' + decPart;\n }\n\n input.value = cleaned;\n const newPos = Math.min(pos, cleaned.length);\n input.setSelectionRange(newPos, newPos);\n this.displayText.set(cleaned);\n\n const num = parseFloat(cleaned);\n this.setValue(isNaN(num) ? 0 : num);\n }\n\n /** Writes the value to the effective binding source. */\n private setValue(v: number): void {\n const ctrl = this.control();\n if (ctrl) {\n ctrl.setValue(v, { emitEvent: true });\n } else {\n this.value.set(v);\n }\n this.onChange(v);\n }\n\n private roundTo(v: number): number {\n const factor = Math.pow(10, Math.max(0, this.decimals()));\n return Math.round(v * factor) / factor;\n }\n\n /** Formats a number with thousands separator and up to `decimals` places. */\n private formatNumber(v: number): string {\n if (v == null || isNaN(v)) return '0';\n const dec = Math.max(0, this.decimals());\n return v.toLocaleString('en-US', { minimumFractionDigits: 0, maximumFractionDigits: dec });\n }\n\n // ── ControlValueAccessor ───────────────────────────────────────────────────\n\n writeValue(value: any): void {\n if (!this.focused()) {\n this.displayText.set(this.formatNumber(value ?? 0));\n }\n }\n\n registerOnChange(fn: any): void {\n this.onChange = fn;\n }\n\n registerOnTouched(fn: any): void {\n this.onTouched = fn;\n }\n\n setDisabledState(isDisabled: boolean): void {\n this.controlDisabled.set(isDisabled);\n }\n}\n","<div>\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 @if (required()) {\n <span class=\"text-red-400\">*</span>\n }\n </div>\n }\n <div class=\"flex\">\n <input\n [id]=\"inputId()\"\n type=\"text\"\n inputmode=\"decimal\"\n autocomplete=\"off\"\n [value]=\"displayText()\"\n [placeholder]=\"placeholder()\"\n [attr.aria-label]=\"ariaLabel() || label()\"\n [attr.aria-invalid]=\"showError() || null\"\n [disabled]=\"isDisabled()\"\n (focus)=\"onFocus($event)\"\n (blur)=\"onBlur()\"\n (keydown)=\"onKeydown($event)\"\n (input)=\"onInput($event)\"\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: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': showError(),\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)]': !showError()\n }\"\n />\n <button\n type=\"button\"\n (click)=\"toggleMode()\"\n [disabled]=\"isDisabled()\"\n class=\"px-3 py-2 text-sm font-medium border rounded-r-lg transition-colors shrink-0\"\n [ngClass]=\"{\n '_shk-bg-primary-soft _shk-border-primary-200 _shk-text-primary-700 dark:[background-color:var(--shk-primary-900)] dark:[border-color:var(--shk-primary-700)] dark:[color:var(--shk-primary-300)]': isPercentage(),\n '_shk-bg-white _shk-border _shk-text-surface-500 dark:[background-color:var(--shk-surface-100)] dark:[border-color:var(--shk-surface-200)] dark:[color:var(--shk-surface-400)]': !isPercentage(),\n 'cursor-not-allowed opacity-50': isDisabled()\n }\"\n >\n {{ isPercentage() ? '%' : currency() }}\n </button>\n </div>\n @if (showError()) {\n <div class=\"text-xs _shk-text-red-500 mt-1\">\n {{ errorMessage() }}\n </div>\n }\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -53,7 +53,7 @@ class TimelineComponent {
53
53
  /** Timeline data. */
54
54
  this.items = input([], ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
55
55
  // ---------- Layout ----------
56
- /** 'left' = line and markers on the left; 'alternate' = cards alternate around a centered line on lg+. */
56
+ /** 'left' = line and markers on the left; 'alternate' = cards alternate around a centered line on lg+; 'split' = markers centered with days on the left and activities on the right. */
57
57
  this.alignment = input('alternate', ...(ngDevMode ? [{ debugName: "alignment" }] : /* istanbul ignore next */ []));
58
58
  /** Shows/hides the vertical connector line. */
59
59
  this.showLine = input(true, ...(ngDevMode ? [{ debugName: "showLine" }] : /* istanbul ignore next */ []));
@@ -136,7 +136,7 @@ class TimelineComponent {
136
136
  lineClass() {
137
137
  const pos = this.markerSize() === 'sm' ? 'left-4' : this.markerSize() === 'lg' ? 'left-6' : 'left-5';
138
138
  const base = `absolute top-4 bottom-4 w-px _shk-bg-surface-200 dark:[background-color:var(--shk-surface-200)] ${pos}`;
139
- if (this.alignment() === 'alternate') {
139
+ if (this.alignment() === 'alternate' || this.alignment() === 'split') {
140
140
  return `${base} lg:left-1/2 lg:-translate-x-1/2`;
141
141
  }
142
142
  return base;
@@ -207,11 +207,11 @@ class TimelineComponent {
207
207
  return action.isDisabled ? action.isDisabled(item, sub) : false;
208
208
  }
209
209
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: TimelineComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
210
- 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:pl-12]=\"$even\"\n [class.lg:justify-end]=\"!$even\"\n [class.lg:pr-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 }); }
210
+ 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:pl-12]=\"$even\"\n [class.lg:justify-end]=\"!$even\"\n [class.lg:pr-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 if (alignment() === 'split') {\n <!-- Split: markers centered, days on the left, activities on the right -->\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 <!-- Day info (always left) -->\n @if (showOpposite()) {\n <div class=\"hidden lg:flex lg:items-center lg:justify-end lg:pr-12 lg:order-1 lg:text-right\">\n <ng-container\n *ngTemplateOutlet=\"customTemplates()['opposite'] || itemInfo; context: { $implicit: item, index: i, showDescription: true }\"\n ></ng-container>\n </div>\n }\n\n <!-- Content card (always right) -->\n <div class=\"flex-1 min-w-0 lg:order-2 lg:pl-12\">\n <ng-container\n *ngTemplateOutlet=\"customTemplates()['content'] || card; context: { $implicit: item, index: i }\"\n ></ng-container>\n </div>\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 let-showDescription=\"showDescription\">\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 @if (showDescription && item.description) {\n <div class=\"text-xs _shk-text-surface-400 dark:[color:var(--shk-surface-500)] mt-1 leading-relaxed\">{{ item.description }}</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\">\n <!-- Header (mobile in alternate/split, always in left) -->\n <div class=\"flex items-center gap-2 px-4 pt-4 pb-2\" [class.lg:hidden]=\"alignment() === 'alternate' || alignment() === 'split'\">\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, last: $last, hasFooter: showAddSubItem() || itemActions().length > 0 }\"\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 rounded-b-xl _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\" let-last=\"last\" let-hasFooter=\"hasFooter\">\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\" [class.rounded-b-xl]=\"last && !hasFooter\">\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/action\">\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/action: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 }); }
211
211
  }
212
212
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: TimelineComponent, decorators: [{
213
213
  type: Component,
214
- 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:pl-12]=\"$even\"\n [class.lg:justify-end]=\"!$even\"\n [class.lg:pr-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"] }]
214
+ 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:pl-12]=\"$even\"\n [class.lg:justify-end]=\"!$even\"\n [class.lg:pr-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 if (alignment() === 'split') {\n <!-- Split: markers centered, days on the left, activities on the right -->\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 <!-- Day info (always left) -->\n @if (showOpposite()) {\n <div class=\"hidden lg:flex lg:items-center lg:justify-end lg:pr-12 lg:order-1 lg:text-right\">\n <ng-container\n *ngTemplateOutlet=\"customTemplates()['opposite'] || itemInfo; context: { $implicit: item, index: i, showDescription: true }\"\n ></ng-container>\n </div>\n }\n\n <!-- Content card (always right) -->\n <div class=\"flex-1 min-w-0 lg:order-2 lg:pl-12\">\n <ng-container\n *ngTemplateOutlet=\"customTemplates()['content'] || card; context: { $implicit: item, index: i }\"\n ></ng-container>\n </div>\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 let-showDescription=\"showDescription\">\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 @if (showDescription && item.description) {\n <div class=\"text-xs _shk-text-surface-400 dark:[color:var(--shk-surface-500)] mt-1 leading-relaxed\">{{ item.description }}</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\">\n <!-- Header (mobile in alternate/split, always in left) -->\n <div class=\"flex items-center gap-2 px-4 pt-4 pb-2\" [class.lg:hidden]=\"alignment() === 'alternate' || alignment() === 'split'\">\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, last: $last, hasFooter: showAddSubItem() || itemActions().length > 0 }\"\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 rounded-b-xl _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\" let-last=\"last\" let-hasFooter=\"hasFooter\">\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\" [class.rounded-b-xl]=\"last && !hasFooter\">\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/action\">\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/action: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"] }]
215
215
  }], 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"] }] } });
216
216
 
217
217
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"shirkasoft-ui-components-timeline.mjs","sources":["../../../projects/ui-components/timeline/timeline.component.ts","../../../projects/ui-components/timeline/timeline.component.html","../../../projects/ui-components/timeline/shirkasoft-ui-components-timeline.ts"],"sourcesContent":["import { Component, input, output, ChangeDetectionStrategy } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport {\n LucideDynamicIcon,\n LucideCircleQuestionMark,\n LucideBus,\n LucideCar,\n LucideHotel,\n LucideMapPin,\n LucideMountain,\n LucidePackage,\n LucideShield,\n LucideShip,\n LucideTag,\n LucideTicket,\n LucideUserRound,\n LucideUtensils,\n} from '@lucide/angular';\nimport { getIcon as getIconFromCentral } from 'shirkasoft-ui-components/utils';\n\n/**\n * Shirkasoft UI Components.\n * Authors: Roberto Valladares Martin (Ansem13), Julio César García García (Sanjuli14).\n * Belongs to Shirkasoft.\n */\n\n/** A chip shown under a sub item (time, pricing model, quantity, etc). */\nexport interface TimelineMeta {\n icon: string | any;\n label?: string;\n value: string;\n}\n\n/** A row inside a timeline item (e.g. an activity of a tour day). */\nexport interface TimelineSubItem {\n id: string | number;\n title: string;\n subtitle?: string;\n /** Used to look up icon / color in `iconMap` and `iconColors`. */\n type?: string;\n /** Overrides the resolved icon (name or component). */\n icon?: string | any;\n /** Hex background for the icon box (fallback). */\n color?: string;\n /** Hex text color for the icon (fallback). */\n colorText?: string;\n /** Custom CSS classes for the icon box (takes precedence over inline colors). */\n iconClass?: string;\n optional?: boolean;\n optionalLabel?: string;\n meta?: TimelineMeta[];\n price?: string | number;\n}\n\n/** A single event in the timeline (e.g. a tour day). */\nexport interface TimelineItem {\n id: string | number;\n /** Text shown inside the marker (falls back to the auto index). */\n markerText?: string | number;\n title?: string;\n subtitle?: string;\n description?: string;\n /** Small pill shown above the title (e.g. \"Día 1\"). */\n badge?: string | number;\n badgeIcon?: string | any;\n /** CSS classes for the marker (falls back to the cycled gradient palette). */\n color?: string;\n subItems?: TimelineSubItem[];\n}\n\n/** A button rendered in the header. */\nexport interface TimelineAction {\n label: string;\n icon: string | any;\n onClick: () => void;\n class?: string;\n isVisible?: () => boolean;\n isDisabled?: () => boolean;\n}\n\n/** An action rendered in the item card footer. */\nexport interface TimelineItemAction {\n label: string | ((item: TimelineItem) => string);\n icon: string | any | ((item: TimelineItem) => string | any);\n onClick: (item: TimelineItem) => void;\n class?: string | ((item: TimelineItem) => string);\n isVisible?: (item: TimelineItem) => boolean;\n isDisabled?: (item: TimelineItem) => boolean;\n}\n\n/** An action rendered on hover over a sub item. */\nexport interface TimelineSubItemAction {\n label: string | ((item: TimelineItem, subItem: TimelineSubItem) => string);\n icon: string | any | ((item: TimelineItem, subItem: TimelineSubItem) => string | any);\n onClick: (item: TimelineItem, subItem: TimelineSubItem) => void;\n isVisible?: (item: TimelineItem, subItem: TimelineSubItem) => boolean;\n isDisabled?: (item: TimelineItem, subItem: TimelineSubItem) => boolean;\n}\n\nexport type TimelineAlignment = 'left' | 'alternate';\nexport type TimelineMarkerSize = 'sm' | 'md' | 'lg';\n\nexport const DEFAULT_MARKER_GRADIENTS: string[] = [\n 'bg-gradient-to-br from-blue-500 to-blue-600',\n 'bg-gradient-to-br from-emerald-500 to-emerald-600',\n 'bg-gradient-to-br from-violet-500 to-violet-600',\n 'bg-gradient-to-br from-orange-500 to-orange-600',\n 'bg-gradient-to-br from-rose-500 to-rose-600',\n 'bg-gradient-to-br from-cyan-500 to-cyan-600',\n 'bg-gradient-to-br from-amber-500 to-amber-600',\n 'bg-gradient-to-br from-indigo-500 to-indigo-600',\n 'bg-gradient-to-br from-teal-500 to-teal-600',\n 'bg-gradient-to-br from-pink-500 to-pink-600',\n];\n\n/** Supplier-type style palette used by the original wac-app timeline. */\nexport const DEFAULT_SUPPLIER_ICON_COLORS: Record<\n string,\n { bg: string; text: string }\n> = {\n accommodation: { bg: '#3d5a80', text: '#ffffff' },\n air_tickets: { bg: '#98c1d9', text: '#293241' },\n rent_a_car: { bg: '#ee6c4d', text: '#ffffff' },\n excursion: { bg: '#e0fbfc', text: '#293241' },\n transfer: { bg: '#293241', text: '#ffffff' },\n cruise: { bg: '#3d5a80', text: '#ffffff' },\n insurance: { bg: '#98c1d9', text: '#293241' },\n restaurant: { bg: '#6b7280', text: '#ffffff' },\n visit: { bg: '#14b8a6', text: '#ffffff' },\n guide: { bg: '#06b6d4', text: '#ffffff' },\n package: { bg: '#84cc16', text: '#ffffff' },\n other: { bg: '#e0fbfc', text: '#293241' },\n};\n\n/** Maps a sub-item `type` to a lucide icon component. */\nexport const DEFAULT_SUPPLIER_TYPE_ICONS: Record<string, any> = {\n accommodation: LucideHotel,\n air_tickets: LucideTicket,\n rent_a_car: LucideCar,\n excursion: LucideMountain,\n transfer: LucideBus,\n cruise: LucideShip,\n insurance: LucideShield,\n restaurant: LucideUtensils,\n visit: LucideMapPin,\n guide: LucideUserRound,\n package: LucidePackage,\n other: LucideTag,\n};\n\n@Component({\n selector: 'shk-timeline',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [CommonModule, LucideDynamicIcon],\n templateUrl: './timeline.component.html',\n styles: [\n `\n :host {\n display: block;\n }\n .timeline-icon-btn {\n padding: 0.375rem;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: 0.5rem;\n color: var(--shk-primary-600);\n transition: background-color 0.15s ease-in-out, color 0.15s ease-in-out,\n opacity 0.15s ease-in-out;\n }\n .timeline-icon-btn:hover:not(:disabled) {\n background-color: color-mix(in srgb, var(--shk-primary-50) 60%, transparent);\n color: var(--shk-primary-700);\n }\n .timeline-icon-btn:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n }\n .timeline-icon-btn svg {\n width: 0.875rem !important;\n height: 0.875rem !important;\n }\n .shk-timeline-card {\n animation: shk-timeline-fade-in 0.3s ease-out;\n }\n @keyframes shk-timeline-fade-in {\n from {\n opacity: 0;\n transform: translateY(4px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n }\n `,\n ],\n})\nexport class TimelineComponent {\n protected getIcon = (name: any) => getIconFromCentral(name, LucideCircleQuestionMark);\n\n /** Timeline data. */\n items = input<TimelineItem[]>([]);\n\n // ---------- Layout ----------\n /** 'left' = line and markers on the left; 'alternate' = cards alternate around a centered line on lg+. */\n alignment = input<TimelineAlignment>('alternate');\n /** Shows/hides the vertical connector line. */\n showLine = input<boolean>(true);\n /** Marker diameter. */\n markerSize = input<TimelineMarkerSize>('md');\n /** Gradient classes cycled across markers when the item has no `color`. */\n markerGradients = input<string[]>(DEFAULT_MARKER_GRADIENTS);\n /** Shows the info column on the opposite side of the card (alternate mode, lg+). */\n showOpposite = input<boolean>(true);\n /** Shows the item description. */\n showDescription = input<boolean>(true);\n /** Shows meta chips inside sub items. */\n showSubItemMeta = input<boolean>(true);\n /** Shows the price of each sub item. */\n showSubItemPrice = input<boolean>(true);\n /** Auto-append \"N {subItemCountLabel}\" under the title when the item has no subtitle. */\n showSubItemCount = input<boolean>(false);\n subItemCountLabel = input<string>('elementos');\n\n // ---------- Header ----------\n showHeader = input<boolean>(true);\n headerTitle = input<string>('');\n /** Convenience \"add\" button in the header. */\n showAddItem = input<boolean>(false);\n addItemLabel = input<string>('Añadir');\n addItemIcon = input<string>('plus');\n addItemTooltip = input<string>('Añadir elemento');\n headerActions = input<TimelineAction[]>([]);\n\n // ---------- Actions ----------\n /** Renders \"+ Añadir sub-elemento\" in each card footer. */\n showAddSubItem = input<boolean>(false);\n addSubItemLabel = input<string>('Añadir');\n addSubItemTooltip = input<string>('Añadir sub-elemento');\n itemActions = input<TimelineItemAction[]>([]);\n subItemActions = input<TimelineSubItemAction[]>([]);\n\n // ---------- Sub-item icon mapping ----------\n /** Maps a sub-item `type` to a lucide icon (name or component). */\n iconMap = input<{ [type: string]: string | any }>({});\n /** Maps a sub-item `type` to its icon-box colors. */\n iconColors = input<{ [type: string]: { bg: string; text: string } }>({});\n /** Icon used when nothing matches. */\n fallbackIcon = input<string | any>('circle-help');\n\n // ---------- Empty state ----------\n showEmptyState = input<boolean>(true);\n emptyMessage = input<string>('Sin elementos');\n emptyIcon = input<string | any>('calendar-days');\n\n // ---------- Labels ----------\n editTooltip = input<string>('Editar');\n deleteTooltip = input<string>('Eliminar');\n optionalLabel = input<string>('Opcional');\n noSubItemsMessage = input<string>('');\n\n /** Custom content templates: keys 'marker', 'opposite', 'content', 'description', 'subItem', 'empty'. */\n customTemplates = input<{ [key: string]: any }>({});\n\n // ---------- Outputs ----------\n addItem = output<void>();\n addSubItem = output<TimelineItem>();\n itemClick = output<TimelineItem>();\n subItemClick = output<{ item: TimelineItem; subItem: TimelineSubItem }>();\n\n // ---------- Helpers ----------\n markerText(item: TimelineItem, index: number): string | number {\n return item.markerText ?? index + 1;\n }\n\n markerClass(item: TimelineItem, index: number): string {\n const base = 'flex items-center justify-center rounded-full text-white shadow-md';\n const size =\n this.markerSize() === 'sm'\n ? 'w-8 h-8 text-xs'\n : this.markerSize() === 'lg'\n ? 'w-12 h-12 text-base'\n : 'w-10 h-10 text-sm';\n const color = item.color || this.markerGradients()[index % this.markerGradients().length];\n return `${base} ${size} ${color}`;\n }\n\n markerColumnClass(): string {\n const size =\n this.markerSize() === 'sm' ? 'w-8' : this.markerSize() === 'lg' ? 'w-12' : 'w-10';\n return `relative z-10 flex justify-center shrink-0 ${size}`;\n }\n\n alternateMarkerColumnClass(): string {\n return `${this.markerColumnClass()} lg:absolute lg:left-1/2 lg:-translate-x-1/2 lg:top-0`;\n }\n\n lineClass(): string {\n const pos =\n this.markerSize() === 'sm' ? 'left-4' : this.markerSize() === 'lg' ? 'left-6' : 'left-5';\n const base = `absolute top-4 bottom-4 w-px _shk-bg-surface-200 dark:[background-color:var(--shk-surface-200)] ${pos}`;\n if (this.alignment() === 'alternate') {\n return `${base} lg:left-1/2 lg:-translate-x-1/2`;\n }\n return base;\n }\n\n subItemIconName(sub: TimelineSubItem): string {\n const type = sub.type || '';\n return sub.icon || this.iconMap()[type] || this.fallbackIcon();\n }\n\n subItemStyle(sub: TimelineSubItem): { [key: string]: string } | undefined {\n const palette = this.iconColors()[sub.type || ''];\n if (palette) return { 'background-color': palette.bg, color: palette.text };\n return {\n 'background-color': sub.color || '#6b7280',\n color: sub.colorText || '#ffffff',\n };\n }\n\n // ---------- Header actions ----------\n isHeaderActionVisible(action: TimelineAction): boolean {\n return action.isVisible ? action.isVisible() : true;\n }\n\n isHeaderActionDisabled(action: TimelineAction): boolean {\n return action.isDisabled ? action.isDisabled() : false;\n }\n\n // ---------- Item actions ----------\n getItemActionLabel(action: TimelineItemAction, item: TimelineItem): string {\n return typeof action.label === 'function' ? action.label(item) : action.label;\n }\n\n getItemActionIconName(action: TimelineItemAction, item: TimelineItem): any {\n const icon = action.icon;\n if (typeof icon === 'function') {\n if (icon.prototype === undefined) {\n return icon(item);\n }\n return icon;\n }\n return icon;\n }\n\n getItemActionClass(action: TimelineItemAction, item: TimelineItem): string {\n if (!action.class) return '';\n return typeof action.class === 'function' ? action.class(item) : action.class;\n }\n\n isItemActionVisible(action: TimelineItemAction, item: TimelineItem): boolean {\n return action.isVisible ? action.isVisible(item) : true;\n }\n\n isItemActionDisabled(action: TimelineItemAction, item: TimelineItem): boolean {\n return action.isDisabled ? action.isDisabled(item) : false;\n }\n\n // ---------- Sub-item actions ----------\n getSubItemActionLabel(action: TimelineSubItemAction, item: TimelineItem, sub: TimelineSubItem): string {\n return typeof action.label === 'function' ? action.label(item, sub) : action.label;\n }\n\n getSubItemActionIconName(action: TimelineSubItemAction, item: TimelineItem, sub: TimelineSubItem): any {\n const icon = action.icon;\n if (typeof icon === 'function') {\n if (icon.prototype === undefined) {\n return icon(item, sub);\n }\n return icon;\n }\n return icon;\n }\n\n isSubItemActionVisible(action: TimelineSubItemAction, item: TimelineItem, sub: TimelineSubItem): boolean {\n return action.isVisible ? action.isVisible(item, sub) : true;\n }\n\n isSubItemActionDisabled(action: TimelineSubItemAction, item: TimelineItem, sub: TimelineSubItem): boolean {\n return action.isDisabled ? action.isDisabled(item, sub) : false;\n }\n}\n","<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:pl-12]=\"$even\"\n [class.lg:justify-end]=\"!$even\"\n [class.lg:pr-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\">· {{ 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","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["getIconFromCentral"],"mappings":"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"}
1
+ {"version":3,"file":"shirkasoft-ui-components-timeline.mjs","sources":["../../../projects/ui-components/timeline/timeline.component.ts","../../../projects/ui-components/timeline/timeline.component.html","../../../projects/ui-components/timeline/shirkasoft-ui-components-timeline.ts"],"sourcesContent":["import { Component, input, output, ChangeDetectionStrategy } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport {\n LucideDynamicIcon,\n LucideCircleQuestionMark,\n LucideBus,\n LucideCar,\n LucideHotel,\n LucideMapPin,\n LucideMountain,\n LucidePackage,\n LucideShield,\n LucideShip,\n LucideTag,\n LucideTicket,\n LucideUserRound,\n LucideUtensils,\n} from '@lucide/angular';\nimport { getIcon as getIconFromCentral } from 'shirkasoft-ui-components/utils';\n\n/**\n * Shirkasoft UI Components.\n * Authors: Roberto Valladares Martin (Ansem13), Julio César García García (Sanjuli14).\n * Belongs to Shirkasoft.\n */\n\n/** A chip shown under a sub item (time, pricing model, quantity, etc). */\nexport interface TimelineMeta {\n icon: string | any;\n label?: string;\n value: string;\n}\n\n/** A row inside a timeline item (e.g. an activity of a tour day). */\nexport interface TimelineSubItem {\n id: string | number;\n title: string;\n subtitle?: string;\n /** Used to look up icon / color in `iconMap` and `iconColors`. */\n type?: string;\n /** Overrides the resolved icon (name or component). */\n icon?: string | any;\n /** Hex background for the icon box (fallback). */\n color?: string;\n /** Hex text color for the icon (fallback). */\n colorText?: string;\n /** Custom CSS classes for the icon box (takes precedence over inline colors). */\n iconClass?: string;\n optional?: boolean;\n optionalLabel?: string;\n meta?: TimelineMeta[];\n price?: string | number;\n}\n\n/** A single event in the timeline (e.g. a tour day). */\nexport interface TimelineItem {\n id: string | number;\n /** Text shown inside the marker (falls back to the auto index). */\n markerText?: string | number;\n title?: string;\n subtitle?: string;\n description?: string;\n /** Small pill shown above the title (e.g. \"Día 1\"). */\n badge?: string | number;\n badgeIcon?: string | any;\n /** CSS classes for the marker (falls back to the cycled gradient palette). */\n color?: string;\n subItems?: TimelineSubItem[];\n}\n\n/** A button rendered in the header. */\nexport interface TimelineAction {\n label: string;\n icon: string | any;\n onClick: () => void;\n class?: string;\n isVisible?: () => boolean;\n isDisabled?: () => boolean;\n}\n\n/** An action rendered in the item card footer. */\nexport interface TimelineItemAction {\n label: string | ((item: TimelineItem) => string);\n icon: string | any | ((item: TimelineItem) => string | any);\n onClick: (item: TimelineItem) => void;\n class?: string | ((item: TimelineItem) => string);\n isVisible?: (item: TimelineItem) => boolean;\n isDisabled?: (item: TimelineItem) => boolean;\n}\n\n/** An action rendered on hover over a sub item. */\nexport interface TimelineSubItemAction {\n label: string | ((item: TimelineItem, subItem: TimelineSubItem) => string);\n icon: string | any | ((item: TimelineItem, subItem: TimelineSubItem) => string | any);\n onClick: (item: TimelineItem, subItem: TimelineSubItem) => void;\n isVisible?: (item: TimelineItem, subItem: TimelineSubItem) => boolean;\n isDisabled?: (item: TimelineItem, subItem: TimelineSubItem) => boolean;\n}\n\nexport type TimelineAlignment = 'left' | 'alternate' | 'split';\nexport type TimelineMarkerSize = 'sm' | 'md' | 'lg';\n\nexport const DEFAULT_MARKER_GRADIENTS: string[] = [\n 'bg-gradient-to-br from-blue-500 to-blue-600',\n 'bg-gradient-to-br from-emerald-500 to-emerald-600',\n 'bg-gradient-to-br from-violet-500 to-violet-600',\n 'bg-gradient-to-br from-orange-500 to-orange-600',\n 'bg-gradient-to-br from-rose-500 to-rose-600',\n 'bg-gradient-to-br from-cyan-500 to-cyan-600',\n 'bg-gradient-to-br from-amber-500 to-amber-600',\n 'bg-gradient-to-br from-indigo-500 to-indigo-600',\n 'bg-gradient-to-br from-teal-500 to-teal-600',\n 'bg-gradient-to-br from-pink-500 to-pink-600',\n];\n\n/** Supplier-type style palette used by the original wac-app timeline. */\nexport const DEFAULT_SUPPLIER_ICON_COLORS: Record<\n string,\n { bg: string; text: string }\n> = {\n accommodation: { bg: '#3d5a80', text: '#ffffff' },\n air_tickets: { bg: '#98c1d9', text: '#293241' },\n rent_a_car: { bg: '#ee6c4d', text: '#ffffff' },\n excursion: { bg: '#e0fbfc', text: '#293241' },\n transfer: { bg: '#293241', text: '#ffffff' },\n cruise: { bg: '#3d5a80', text: '#ffffff' },\n insurance: { bg: '#98c1d9', text: '#293241' },\n restaurant: { bg: '#6b7280', text: '#ffffff' },\n visit: { bg: '#14b8a6', text: '#ffffff' },\n guide: { bg: '#06b6d4', text: '#ffffff' },\n package: { bg: '#84cc16', text: '#ffffff' },\n other: { bg: '#e0fbfc', text: '#293241' },\n};\n\n/** Maps a sub-item `type` to a lucide icon component. */\nexport const DEFAULT_SUPPLIER_TYPE_ICONS: Record<string, any> = {\n accommodation: LucideHotel,\n air_tickets: LucideTicket,\n rent_a_car: LucideCar,\n excursion: LucideMountain,\n transfer: LucideBus,\n cruise: LucideShip,\n insurance: LucideShield,\n restaurant: LucideUtensils,\n visit: LucideMapPin,\n guide: LucideUserRound,\n package: LucidePackage,\n other: LucideTag,\n};\n\n@Component({\n selector: 'shk-timeline',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [CommonModule, LucideDynamicIcon],\n templateUrl: './timeline.component.html',\n styles: [\n `\n :host {\n display: block;\n }\n .timeline-icon-btn {\n padding: 0.375rem;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: 0.5rem;\n color: var(--shk-primary-600);\n transition: background-color 0.15s ease-in-out, color 0.15s ease-in-out,\n opacity 0.15s ease-in-out;\n }\n .timeline-icon-btn:hover:not(:disabled) {\n background-color: color-mix(in srgb, var(--shk-primary-50) 60%, transparent);\n color: var(--shk-primary-700);\n }\n .timeline-icon-btn:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n }\n .timeline-icon-btn svg {\n width: 0.875rem !important;\n height: 0.875rem !important;\n }\n .shk-timeline-card {\n animation: shk-timeline-fade-in 0.3s ease-out;\n }\n @keyframes shk-timeline-fade-in {\n from {\n opacity: 0;\n transform: translateY(4px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n }\n `,\n ],\n})\nexport class TimelineComponent {\n protected getIcon = (name: any) => getIconFromCentral(name, LucideCircleQuestionMark);\n\n /** Timeline data. */\n items = input<TimelineItem[]>([]);\n\n // ---------- Layout ----------\n /** 'left' = line and markers on the left; 'alternate' = cards alternate around a centered line on lg+; 'split' = markers centered with days on the left and activities on the right. */\n alignment = input<TimelineAlignment>('alternate');\n /** Shows/hides the vertical connector line. */\n showLine = input<boolean>(true);\n /** Marker diameter. */\n markerSize = input<TimelineMarkerSize>('md');\n /** Gradient classes cycled across markers when the item has no `color`. */\n markerGradients = input<string[]>(DEFAULT_MARKER_GRADIENTS);\n /** Shows the info column on the opposite side of the card (alternate mode, lg+). */\n showOpposite = input<boolean>(true);\n /** Shows the item description. */\n showDescription = input<boolean>(true);\n /** Shows meta chips inside sub items. */\n showSubItemMeta = input<boolean>(true);\n /** Shows the price of each sub item. */\n showSubItemPrice = input<boolean>(true);\n /** Auto-append \"N {subItemCountLabel}\" under the title when the item has no subtitle. */\n showSubItemCount = input<boolean>(false);\n subItemCountLabel = input<string>('elementos');\n\n // ---------- Header ----------\n showHeader = input<boolean>(true);\n headerTitle = input<string>('');\n /** Convenience \"add\" button in the header. */\n showAddItem = input<boolean>(false);\n addItemLabel = input<string>('Añadir');\n addItemIcon = input<string>('plus');\n addItemTooltip = input<string>('Añadir elemento');\n headerActions = input<TimelineAction[]>([]);\n\n // ---------- Actions ----------\n /** Renders \"+ Añadir sub-elemento\" in each card footer. */\n showAddSubItem = input<boolean>(false);\n addSubItemLabel = input<string>('Añadir');\n addSubItemTooltip = input<string>('Añadir sub-elemento');\n itemActions = input<TimelineItemAction[]>([]);\n subItemActions = input<TimelineSubItemAction[]>([]);\n\n // ---------- Sub-item icon mapping ----------\n /** Maps a sub-item `type` to a lucide icon (name or component). */\n iconMap = input<{ [type: string]: string | any }>({});\n /** Maps a sub-item `type` to its icon-box colors. */\n iconColors = input<{ [type: string]: { bg: string; text: string } }>({});\n /** Icon used when nothing matches. */\n fallbackIcon = input<string | any>('circle-help');\n\n // ---------- Empty state ----------\n showEmptyState = input<boolean>(true);\n emptyMessage = input<string>('Sin elementos');\n emptyIcon = input<string | any>('calendar-days');\n\n // ---------- Labels ----------\n editTooltip = input<string>('Editar');\n deleteTooltip = input<string>('Eliminar');\n optionalLabel = input<string>('Opcional');\n noSubItemsMessage = input<string>('');\n\n /** Custom content templates: keys 'marker', 'opposite', 'content', 'description', 'subItem', 'empty'. */\n customTemplates = input<{ [key: string]: any }>({});\n\n // ---------- Outputs ----------\n addItem = output<void>();\n addSubItem = output<TimelineItem>();\n itemClick = output<TimelineItem>();\n subItemClick = output<{ item: TimelineItem; subItem: TimelineSubItem }>();\n\n // ---------- Helpers ----------\n markerText(item: TimelineItem, index: number): string | number {\n return item.markerText ?? index + 1;\n }\n\n markerClass(item: TimelineItem, index: number): string {\n const base = 'flex items-center justify-center rounded-full text-white shadow-md';\n const size =\n this.markerSize() === 'sm'\n ? 'w-8 h-8 text-xs'\n : this.markerSize() === 'lg'\n ? 'w-12 h-12 text-base'\n : 'w-10 h-10 text-sm';\n const color = item.color || this.markerGradients()[index % this.markerGradients().length];\n return `${base} ${size} ${color}`;\n }\n\n markerColumnClass(): string {\n const size =\n this.markerSize() === 'sm' ? 'w-8' : this.markerSize() === 'lg' ? 'w-12' : 'w-10';\n return `relative z-10 flex justify-center shrink-0 ${size}`;\n }\n\n alternateMarkerColumnClass(): string {\n return `${this.markerColumnClass()} lg:absolute lg:left-1/2 lg:-translate-x-1/2 lg:top-0`;\n }\n\n lineClass(): string {\n const pos =\n this.markerSize() === 'sm' ? 'left-4' : this.markerSize() === 'lg' ? 'left-6' : 'left-5';\n const base = `absolute top-4 bottom-4 w-px _shk-bg-surface-200 dark:[background-color:var(--shk-surface-200)] ${pos}`;\n if (this.alignment() === 'alternate' || this.alignment() === 'split') {\n return `${base} lg:left-1/2 lg:-translate-x-1/2`;\n }\n return base;\n }\n\n subItemIconName(sub: TimelineSubItem): string {\n const type = sub.type || '';\n return sub.icon || this.iconMap()[type] || this.fallbackIcon();\n }\n\n subItemStyle(sub: TimelineSubItem): { [key: string]: string } | undefined {\n const palette = this.iconColors()[sub.type || ''];\n if (palette) return { 'background-color': palette.bg, color: palette.text };\n return {\n 'background-color': sub.color || '#6b7280',\n color: sub.colorText || '#ffffff',\n };\n }\n\n // ---------- Header actions ----------\n isHeaderActionVisible(action: TimelineAction): boolean {\n return action.isVisible ? action.isVisible() : true;\n }\n\n isHeaderActionDisabled(action: TimelineAction): boolean {\n return action.isDisabled ? action.isDisabled() : false;\n }\n\n // ---------- Item actions ----------\n getItemActionLabel(action: TimelineItemAction, item: TimelineItem): string {\n return typeof action.label === 'function' ? action.label(item) : action.label;\n }\n\n getItemActionIconName(action: TimelineItemAction, item: TimelineItem): any {\n const icon = action.icon;\n if (typeof icon === 'function') {\n if (icon.prototype === undefined) {\n return icon(item);\n }\n return icon;\n }\n return icon;\n }\n\n getItemActionClass(action: TimelineItemAction, item: TimelineItem): string {\n if (!action.class) return '';\n return typeof action.class === 'function' ? action.class(item) : action.class;\n }\n\n isItemActionVisible(action: TimelineItemAction, item: TimelineItem): boolean {\n return action.isVisible ? action.isVisible(item) : true;\n }\n\n isItemActionDisabled(action: TimelineItemAction, item: TimelineItem): boolean {\n return action.isDisabled ? action.isDisabled(item) : false;\n }\n\n // ---------- Sub-item actions ----------\n getSubItemActionLabel(action: TimelineSubItemAction, item: TimelineItem, sub: TimelineSubItem): string {\n return typeof action.label === 'function' ? action.label(item, sub) : action.label;\n }\n\n getSubItemActionIconName(action: TimelineSubItemAction, item: TimelineItem, sub: TimelineSubItem): any {\n const icon = action.icon;\n if (typeof icon === 'function') {\n if (icon.prototype === undefined) {\n return icon(item, sub);\n }\n return icon;\n }\n return icon;\n }\n\n isSubItemActionVisible(action: TimelineSubItemAction, item: TimelineItem, sub: TimelineSubItem): boolean {\n return action.isVisible ? action.isVisible(item, sub) : true;\n }\n\n isSubItemActionDisabled(action: TimelineSubItemAction, item: TimelineItem, sub: TimelineSubItem): boolean {\n return action.isDisabled ? action.isDisabled(item, sub) : false;\n }\n}\n","<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:pl-12]=\"$even\"\n [class.lg:justify-end]=\"!$even\"\n [class.lg:pr-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 if (alignment() === 'split') {\n <!-- Split: markers centered, days on the left, activities on the right -->\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 <!-- Day info (always left) -->\n @if (showOpposite()) {\n <div class=\"hidden lg:flex lg:items-center lg:justify-end lg:pr-12 lg:order-1 lg:text-right\">\n <ng-container\n *ngTemplateOutlet=\"customTemplates()['opposite'] || itemInfo; context: { $implicit: item, index: i, showDescription: true }\"\n ></ng-container>\n </div>\n }\n\n <!-- Content card (always right) -->\n <div class=\"flex-1 min-w-0 lg:order-2 lg:pl-12\">\n <ng-container\n *ngTemplateOutlet=\"customTemplates()['content'] || card; context: { $implicit: item, index: i }\"\n ></ng-container>\n </div>\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 let-showDescription=\"showDescription\">\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 @if (showDescription && item.description) {\n <div class=\"text-xs _shk-text-surface-400 dark:[color:var(--shk-surface-500)] mt-1 leading-relaxed\">{{ item.description }}</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\">\n <!-- Header (mobile in alternate/split, always in left) -->\n <div class=\"flex items-center gap-2 px-4 pt-4 pb-2\" [class.lg:hidden]=\"alignment() === 'alternate' || alignment() === 'split'\">\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, last: $last, hasFooter: showAddSubItem() || itemActions().length > 0 }\"\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 rounded-b-xl _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\" let-last=\"last\" let-hasFooter=\"hasFooter\">\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\" [class.rounded-b-xl]=\"last && !hasFooter\">\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\">· {{ 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/action\">\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/action: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","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["getIconFromCentral"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { LucideX, LucideUpload, LucideTriangleAlert, LucideTrash2, LucideSearch, LucideRefreshCw, LucidePlus, LucidePanelRight, LucideMinimize2, LucideMenu, LucideMaximize2, LucideLogOut, LucideLoaderCircle, LucideLoader, LucideInfo, LucideInbox, LucideGlobe, LucideFunnel, LucideFile, LucideEyeOff, LucideEye, LucideCirclePlus, LucideCircleQuestionMark, LucideChevronsRight, LucideChevronsLeft, LucideChevronRight, LucideChevronLeft, LucideChevronDown, LucideCalendarDays, LucideCheck, LucideArrowUpDown, LucideArrowLeft } from '@lucide/angular';
1
+ import { LucideX, LucideUpload, LucideTriangleAlert, LucideTrash2, LucideSearch, LucideRefreshCw, LucidePlus, LucidePanelRight, LucideMinimize2, LucideMenu, LucideMaximize2, LucideLogOut, LucideLoaderCircle, LucideLoader, LucideInfo, LucideInbox, LucideGlobe, LucideFunnel, LucideFileText, LucideFileSpreadsheet, LucideFile, LucideEyeOff, LucideEye, LucideDownload, LucideCirclePlus, LucideCircleQuestionMark, LucideChevronsRight, LucideChevronsLeft, LucideChevronRight, LucideChevronLeft, LucideChevronDown, LucideCalendarDays, LucideCheck, LucideArrowUpDown, LucideArrowUp, LucideArrowDown, LucideArrowLeft } from '@lucide/angular';
2
2
 
3
3
  /**
4
4
  * Shirkasoft UI Components.
@@ -8,6 +8,8 @@ import { LucideX, LucideUpload, LucideTriangleAlert, LucideTrash2, LucideSearch,
8
8
  /** Maps the icon names used across the library to their Lucide component. */
9
9
  const ICONS = {
10
10
  'arrow-left': LucideArrowLeft,
11
+ 'arrow-down': LucideArrowDown,
12
+ 'arrow-up': LucideArrowUp,
11
13
  'arrow-up-down': LucideArrowUpDown,
12
14
  check: LucideCheck,
13
15
  'calendar-days': LucideCalendarDays,
@@ -18,9 +20,12 @@ const ICONS = {
18
20
  'chevrons-right': LucideChevronsRight,
19
21
  'circle-help': LucideCircleQuestionMark,
20
22
  'circle-plus': LucideCirclePlus,
23
+ download: LucideDownload,
21
24
  eye: LucideEye,
22
25
  'eye-off': LucideEyeOff,
23
26
  file: LucideFile,
27
+ 'file-spreadsheet': LucideFileSpreadsheet,
28
+ 'file-text': LucideFileText,
24
29
  filter: LucideFunnel,
25
30
  globe: LucideGlobe,
26
31
  inbox: LucideInbox,
@@ -1 +1 @@
1
- {"version":3,"file":"shirkasoft-ui-components-utils.mjs","sources":["../../../projects/ui-components/utils/icons.ts","../../../projects/ui-components/utils/shirkasoft-ui-components-utils.ts"],"sourcesContent":["/**\n * Shirkasoft UI Components.\n * Authors: Roberto Valladares Martin (Ansem13), Julio César García García (Sanjuli14).\n * Belongs to Shirkasoft.\n */\nimport {\n LucideArrowLeft,\n LucideArrowUpDown,\n LucideCalendarDays,\n LucideCheck,\n LucideChevronDown,\n LucideChevronLeft,\n LucideChevronRight,\n LucideChevronsLeft,\n LucideChevronsRight,\n LucideCircleQuestionMark,\n LucideCirclePlus,\n LucideEye,\n LucideEyeOff,\n LucideFile,\n LucideFunnel,\n LucideGlobe,\n LucideInbox,\n LucideInfo,\n LucideLoader,\n LucideLoaderCircle,\n LucideLogOut,\n LucideMaximize2,\n LucideMenu,\n LucideMinimize2,\n LucidePanelRight,\n LucidePlus,\n LucideRefreshCw,\n LucideSearch,\n LucideTrash2,\n LucideTriangleAlert,\n LucideUpload,\n LucideX,\n} from '@lucide/angular';\n\n/** Maps the icon names used across the library to their Lucide component. */\nexport const ICONS: Record<string, any> = {\n 'arrow-left': LucideArrowLeft,\n 'arrow-up-down': LucideArrowUpDown,\n check: LucideCheck,\n 'calendar-days': LucideCalendarDays,\n 'chevron-down': LucideChevronDown,\n 'chevron-left': LucideChevronLeft,\n 'chevron-right': LucideChevronRight,\n 'chevrons-left': LucideChevronsLeft,\n 'chevrons-right': LucideChevronsRight,\n 'circle-help': LucideCircleQuestionMark,\n 'circle-plus': LucideCirclePlus,\n eye: LucideEye,\n 'eye-off': LucideEyeOff,\n file: LucideFile,\n filter: LucideFunnel,\n globe: LucideGlobe,\n inbox: LucideInbox,\n info: LucideInfo,\n loader: LucideLoader,\n 'loader-circle': LucideLoaderCircle,\n 'log-out': LucideLogOut,\n 'maximize-2': LucideMaximize2,\n menu: LucideMenu,\n 'minimize-2': LucideMinimize2,\n 'panel-right': LucidePanelRight,\n plus: LucidePlus,\n refresh: LucideRefreshCw,\n search: LucideSearch,\n 'trash-2': LucideTrash2,\n 'triangle-alert': LucideTriangleAlert,\n upload: LucideUpload,\n x: LucideX,\n};\n\n/**\n * Resolves the icon passed to a component into a lucide component.\n * Accepts a registered string name, an existing lucide component or a LucideIconData object.\n */\nexport function getIcon(icon?: any, fallback: any = LucideCircleQuestionMark): any {\n if (!icon) return null;\n if (typeof icon === 'string') {\n return ICONS[icon] ?? fallback;\n }\n if (typeof icon === 'function') {\n return icon;\n }\n return fallback;\n}","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;AAAA;;;;AAIG;AAoCH;AACO,MAAM,KAAK,GAAwB;AACxC,IAAA,YAAY,EAAE,eAAe;AAC7B,IAAA,eAAe,EAAE,iBAAiB;AAClC,IAAA,KAAK,EAAE,WAAW;AAClB,IAAA,eAAe,EAAE,kBAAkB;AACnC,IAAA,cAAc,EAAE,iBAAiB;AACjC,IAAA,cAAc,EAAE,iBAAiB;AACjC,IAAA,eAAe,EAAE,kBAAkB;AACnC,IAAA,eAAe,EAAE,kBAAkB;AACnC,IAAA,gBAAgB,EAAE,mBAAmB;AACrC,IAAA,aAAa,EAAE,wBAAwB;AACvC,IAAA,aAAa,EAAE,gBAAgB;AAC/B,IAAA,GAAG,EAAE,SAAS;AACd,IAAA,SAAS,EAAE,YAAY;AACvB,IAAA,IAAI,EAAE,UAAU;AAChB,IAAA,MAAM,EAAE,YAAY;AACpB,IAAA,KAAK,EAAE,WAAW;AAClB,IAAA,KAAK,EAAE,WAAW;AAClB,IAAA,IAAI,EAAE,UAAU;AAChB,IAAA,MAAM,EAAE,YAAY;AACpB,IAAA,eAAe,EAAE,kBAAkB;AACnC,IAAA,SAAS,EAAE,YAAY;AACvB,IAAA,YAAY,EAAE,eAAe;AAC7B,IAAA,IAAI,EAAE,UAAU;AAChB,IAAA,YAAY,EAAE,eAAe;AAC7B,IAAA,aAAa,EAAE,gBAAgB;AAC/B,IAAA,IAAI,EAAE,UAAU;AAChB,IAAA,OAAO,EAAE,eAAe;AACxB,IAAA,MAAM,EAAE,YAAY;AACpB,IAAA,SAAS,EAAE,YAAY;AACvB,IAAA,gBAAgB,EAAE,mBAAmB;AACrC,IAAA,MAAM,EAAE,YAAY;AACpB,IAAA,CAAC,EAAE,OAAO;;AAGZ;;;AAGG;SACa,OAAO,CAAC,IAAU,EAAE,WAAgB,wBAAwB,EAAA;AAC1E,IAAA,IAAI,CAAC,IAAI;AAAE,QAAA,OAAO,IAAI;AACtB,IAAA,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE;AAC5B,QAAA,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,QAAQ;IAChC;AACA,IAAA,IAAI,OAAO,IAAI,KAAK,UAAU,EAAE;AAC9B,QAAA,OAAO,IAAI;IACb;AACA,IAAA,OAAO,QAAQ;AACjB;;ACzFA;;AAEG;;;;"}
1
+ {"version":3,"file":"shirkasoft-ui-components-utils.mjs","sources":["../../../projects/ui-components/utils/icons.ts","../../../projects/ui-components/utils/shirkasoft-ui-components-utils.ts"],"sourcesContent":["/**\n * Shirkasoft UI Components.\n * Authors: Roberto Valladares Martin (Ansem13), Julio César García García (Sanjuli14).\n * Belongs to Shirkasoft.\n */\nimport {\n LucideArrowDown,\n LucideArrowLeft,\n LucideArrowUp,\n LucideArrowUpDown,\n LucideCalendarDays,\n LucideCheck,\n LucideChevronDown,\n LucideChevronLeft,\n LucideChevronRight,\n LucideChevronsLeft,\n LucideChevronsRight,\n LucideCircleQuestionMark,\n LucideCirclePlus,\nLucideDownload,\n LucideEye,\n LucideEyeOff,\n LucideFile,\n LucideFileSpreadsheet,\n LucideFileText,\n LucideFunnel,\n LucideGlobe,\n LucideInbox,\n LucideInfo,\n LucideLoader,\n LucideLoaderCircle,\n LucideLogOut,\n LucideMaximize2,\n LucideMenu,\n LucideMinimize2,\n LucidePanelRight,\n LucidePlus,\n LucideRefreshCw,\n LucideSearch,\n LucideTrash2,\n LucideTriangleAlert,\n LucideUpload,\n LucideX,\n} from '@lucide/angular';\n\n/** Maps the icon names used across the library to their Lucide component. */\nexport const ICONS: Record<string, any> = {\n 'arrow-left': LucideArrowLeft,\n 'arrow-down': LucideArrowDown,\n 'arrow-up': LucideArrowUp,\n 'arrow-up-down': LucideArrowUpDown,\n check: LucideCheck,\n 'calendar-days': LucideCalendarDays,\n 'chevron-down': LucideChevronDown,\n 'chevron-left': LucideChevronLeft,\n 'chevron-right': LucideChevronRight,\n 'chevrons-left': LucideChevronsLeft,\n 'chevrons-right': LucideChevronsRight,\n 'circle-help': LucideCircleQuestionMark,\n 'circle-plus': LucideCirclePlus,\n download: LucideDownload,\n eye: LucideEye,\n 'eye-off': LucideEyeOff,\n file: LucideFile,\n 'file-spreadsheet': LucideFileSpreadsheet,\n 'file-text': LucideFileText,\n filter: LucideFunnel,\n globe: LucideGlobe,\n inbox: LucideInbox,\n info: LucideInfo,\n loader: LucideLoader,\n 'loader-circle': LucideLoaderCircle,\n 'log-out': LucideLogOut,\n 'maximize-2': LucideMaximize2,\n menu: LucideMenu,\n 'minimize-2': LucideMinimize2,\n 'panel-right': LucidePanelRight,\n plus: LucidePlus,\n refresh: LucideRefreshCw,\n search: LucideSearch,\n 'trash-2': LucideTrash2,\n 'triangle-alert': LucideTriangleAlert,\n upload: LucideUpload,\n x: LucideX,\n};\n\n/**\n * Resolves the icon passed to a component into a lucide component.\n * Accepts a registered string name, an existing lucide component or a LucideIconData object.\n */\nexport function getIcon(icon?: any, fallback: any = LucideCircleQuestionMark): any {\n if (!icon) return null;\n if (typeof icon === 'string') {\n return ICONS[icon] ?? fallback;\n }\n if (typeof icon === 'function') {\n return icon;\n }\n return fallback;\n}","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;AAAA;;;;AAIG;AAyCH;AACO,MAAM,KAAK,GAAwB;AACxC,IAAA,YAAY,EAAE,eAAe;AAC7B,IAAA,YAAY,EAAE,eAAe;AAC7B,IAAA,UAAU,EAAE,aAAa;AACzB,IAAA,eAAe,EAAE,iBAAiB;AAClC,IAAA,KAAK,EAAE,WAAW;AAClB,IAAA,eAAe,EAAE,kBAAkB;AACnC,IAAA,cAAc,EAAE,iBAAiB;AACjC,IAAA,cAAc,EAAE,iBAAiB;AACjC,IAAA,eAAe,EAAE,kBAAkB;AACnC,IAAA,eAAe,EAAE,kBAAkB;AACnC,IAAA,gBAAgB,EAAE,mBAAmB;AACrC,IAAA,aAAa,EAAE,wBAAwB;AACvC,IAAA,aAAa,EAAE,gBAAgB;AAC/B,IAAA,QAAQ,EAAE,cAAc;AACxB,IAAA,GAAG,EAAE,SAAS;AACd,IAAA,SAAS,EAAE,YAAY;AACvB,IAAA,IAAI,EAAE,UAAU;AAChB,IAAA,kBAAkB,EAAE,qBAAqB;AACzC,IAAA,WAAW,EAAE,cAAc;AAC3B,IAAA,MAAM,EAAE,YAAY;AACpB,IAAA,KAAK,EAAE,WAAW;AAClB,IAAA,KAAK,EAAE,WAAW;AAClB,IAAA,IAAI,EAAE,UAAU;AAChB,IAAA,MAAM,EAAE,YAAY;AACpB,IAAA,eAAe,EAAE,kBAAkB;AACnC,IAAA,SAAS,EAAE,YAAY;AACvB,IAAA,YAAY,EAAE,eAAe;AAC7B,IAAA,IAAI,EAAE,UAAU;AAChB,IAAA,YAAY,EAAE,eAAe;AAC7B,IAAA,aAAa,EAAE,gBAAgB;AAC/B,IAAA,IAAI,EAAE,UAAU;AAChB,IAAA,OAAO,EAAE,eAAe;AACxB,IAAA,MAAM,EAAE,YAAY;AACpB,IAAA,SAAS,EAAE,YAAY;AACvB,IAAA,gBAAgB,EAAE,mBAAmB;AACrC,IAAA,MAAM,EAAE,YAAY;AACpB,IAAA,CAAC,EAAE,OAAO;;AAGZ;;;AAGG;SACa,OAAO,CAAC,IAAU,EAAE,WAAgB,wBAAwB,EAAA;AAC1E,IAAA,IAAI,CAAC,IAAI;AAAE,QAAA,OAAO,IAAI;AACtB,IAAA,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE;AAC5B,QAAA,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,QAAQ;IAChC;AACA,IAAA,IAAI,OAAO,IAAI,KAAK,UAAU,EAAE;AAC9B,QAAA,OAAO,IAAI;IACb;AACA,IAAA,OAAO,QAAQ;AACjB;;ACnGA;;AAEG;;;;"}