tecnualng 21.1.0 → 21.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -384,6 +384,7 @@ class TecnualDatepickerComponent {
384
384
  id = input(`tng-datepicker-${Math.random().toString(36).substr(2, 9)}`, ...(ngDevMode ? [{ debugName: "id" }] : []));
385
385
  isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
386
386
  currentViewDate = signal(new Date(), ...(ngDevMode ? [{ debugName: "currentViewDate" }] : [])); // The month we are looking at
387
+ viewMode = signal('day', ...(ngDevMode ? [{ debugName: "viewMode" }] : []));
387
388
  // Value storage
388
389
  singleValue = null;
389
390
  rangeValue = { start: null, end: null };
@@ -394,6 +395,10 @@ class TecnualDatepickerComponent {
394
395
  }
395
396
  // Calendar Logic
396
397
  daysOfWeek = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
398
+ monthNames = [
399
+ 'January', 'February', 'March', 'April', 'May', 'June',
400
+ 'July', 'August', 'September', 'October', 'November', 'December'
401
+ ];
397
402
  calendarDays = computed(() => {
398
403
  const year = this.currentViewDate().getFullYear();
399
404
  const month = this.currentViewDate().getMonth();
@@ -416,6 +421,16 @@ class TecnualDatepickerComponent {
416
421
  }
417
422
  return days;
418
423
  }, ...(ngDevMode ? [{ debugName: "calendarDays" }] : []));
424
+ yearsList = computed(() => {
425
+ // Generate a 12-year grid centered somewhat around the current view date
426
+ const centerYear = this.currentViewDate().getFullYear();
427
+ const startYear = centerYear - 6;
428
+ const years = [];
429
+ for (let i = 0; i < 12; i++) {
430
+ years.push(startYear + i);
431
+ }
432
+ return years;
433
+ }, ...(ngDevMode ? [{ debugName: "yearsList" }] : []));
419
434
  get formattedValue() {
420
435
  if (this.mode() === 'single') {
421
436
  return this.singleValue ? this.singleValue.toLocaleDateString() : '';
@@ -430,29 +445,76 @@ class TecnualDatepickerComponent {
430
445
  return '';
431
446
  }
432
447
  }
433
- get currentMonthYear() {
434
- return this.currentViewDate().toLocaleString('default', { month: 'long', year: 'numeric' });
448
+ get headerLabel() {
449
+ const d = this.currentViewDate();
450
+ if (this.viewMode() === 'day') {
451
+ return d.toLocaleString('default', { month: 'long', year: 'numeric' });
452
+ }
453
+ else if (this.viewMode() === 'month') {
454
+ return d.getFullYear().toString();
455
+ }
456
+ else {
457
+ // Year range
458
+ const years = this.yearsList();
459
+ return `${years[0]} - ${years[years.length - 1]}`;
460
+ }
435
461
  }
436
462
  toggleCalendar() {
437
463
  if (this.disabled())
438
464
  return;
439
- this.isOpen.update(v => !v);
440
- if (this.isOpen()) {
441
- // Focus logic if needed
465
+ if (!this.isOpen()) {
466
+ // Reset to day view when opening
467
+ this.viewMode.set('day');
442
468
  }
443
- else {
469
+ this.isOpen.update(v => !v);
470
+ if (!this.isOpen()) {
444
471
  this.onTouched();
445
472
  }
446
473
  }
447
- prevMonth(e) {
474
+ onHeaderClick() {
475
+ // Drill up: Day -> Month -> Year
476
+ if (this.viewMode() === 'day') {
477
+ this.viewMode.set('month');
478
+ }
479
+ else if (this.viewMode() === 'month') {
480
+ this.viewMode.set('year');
481
+ }
482
+ }
483
+ prev(e) {
448
484
  e.stopPropagation();
449
485
  const d = this.currentViewDate();
450
- this.currentViewDate.set(new Date(d.getFullYear(), d.getMonth() - 1, 1));
486
+ if (this.viewMode() === 'day') {
487
+ this.currentViewDate.set(new Date(d.getFullYear(), d.getMonth() - 1, 1));
488
+ }
489
+ else if (this.viewMode() === 'month') {
490
+ this.currentViewDate.set(new Date(d.getFullYear() - 1, d.getMonth(), 1));
491
+ }
492
+ else {
493
+ this.currentViewDate.set(new Date(d.getFullYear() - 12, d.getMonth(), 1));
494
+ }
451
495
  }
452
- nextMonth(e) {
496
+ next(e) {
453
497
  e.stopPropagation();
454
498
  const d = this.currentViewDate();
455
- this.currentViewDate.set(new Date(d.getFullYear(), d.getMonth() + 1, 1));
499
+ if (this.viewMode() === 'day') {
500
+ this.currentViewDate.set(new Date(d.getFullYear(), d.getMonth() + 1, 1));
501
+ }
502
+ else if (this.viewMode() === 'month') {
503
+ this.currentViewDate.set(new Date(d.getFullYear() + 1, d.getMonth(), 1));
504
+ }
505
+ else {
506
+ this.currentViewDate.set(new Date(d.getFullYear() + 12, d.getMonth(), 1));
507
+ }
508
+ }
509
+ selectMonth(monthIndex) {
510
+ const d = this.currentViewDate();
511
+ this.currentViewDate.set(new Date(d.getFullYear(), monthIndex, 1));
512
+ this.viewMode.set('day');
513
+ }
514
+ selectYear(year) {
515
+ const d = this.currentViewDate();
516
+ this.currentViewDate.set(new Date(year, d.getMonth(), 1));
517
+ this.viewMode.set('month');
456
518
  }
457
519
  selectDate(date) {
458
520
  if (this.isDisabled(date))
@@ -560,7 +622,7 @@ class TecnualDatepickerComponent {
560
622
  useExisting: forwardRef(() => TecnualDatepickerComponent),
561
623
  multi: true
562
624
  }
563
- ], ngImport: i0, template: "<div class=\"tng-datepicker-container\" [class.focused]=\"isOpen()\" [class.has-value]=\"formattedValue\" [class.disabled]=\"disabled()\">\n <!-- Trigger Field (Reusing Input Style) -->\n <div class=\"tng-input-trigger\" (click)=\"toggleCalendar()\">\n <fieldset class=\"tng-fieldset\" aria-hidden=\"true\">\n <legend class=\"tng-legend\"><span>{{ label() }}</span></legend>\n </fieldset>\n <label class=\"tng-label\">{{ label() }}</label>\n <div class=\"tng-input-display\">\n {{ formattedValue || (isOpen() ? placeholder() : '') }}\n </div>\n <span class=\"material-icons tng-icon\">calendar_today</span>\n </div>\n\n <!-- Calendar Popup -->\n @if (isOpen()) {\n <div class=\"tng-calendar-popup\">\n <div class=\"tng-calendar-header\">\n <button type=\"button\" class=\"nav-btn\" (click)=\"prevMonth($event)\">\n <span class=\"material-icons\">chevron_left</span>\n </button>\n <span class=\"current-month\">{{ currentMonthYear }}</span>\n <button type=\"button\" class=\"nav-btn\" (click)=\"nextMonth($event)\">\n <span class=\"material-icons\">chevron_right</span>\n </button>\n </div>\n\n <div class=\"tng-calendar-grid\">\n @for (day of daysOfWeek; track day) {\n <div class=\"day-name\">{{ day }}</div>\n }\n @for (date of calendarDays(); track date.getTime()) {\n <div\n class=\"day-cell\"\n [class.not-current-month]=\"!isCurrentMonth(date)\"\n [class.today]=\"isToday(date)\"\n [class.selected]=\"isSelected(date)\"\n [class.in-range]=\"isInRange(date)\"\n [class.range-start]=\"mode() === 'range' && isSameDay(date, rangeValue.start)\"\n [class.range-end]=\"mode() === 'range' && isSameDay(date, rangeValue.end)\"\n [class.disabled]=\"isDisabled(date)\"\n (click)=\"selectDate(date)\"\n >\n {{ date.getDate() }}\n </div>\n }\n </div>\n </div>\n }\n</div>\n", styles: [":host{display:block;margin-bottom:1.5rem;font-family:var(--tng-font-family, \"Inter\", sans-serif);position:relative}.tng-datepicker-container{position:relative}.tng-datepicker-container.disabled{opacity:.6;pointer-events:none}.tng-datepicker-container.disabled .tng-fieldset{border-color:var(--tng-border, #ccc);background-color:var(--tng-background, #f9f9f9)}.tng-input-trigger{position:relative;border-radius:var(--tng-border-radius, 4px);padding:0 16px;height:48px;display:flex;align-items:center;cursor:pointer}.tng-input-trigger:hover .tng-fieldset{border-color:color-mix(in srgb,var(--tng-border, #999),black 20%)}.tng-fieldset{position:absolute;inset:0 0 5px;margin:0;padding:0 12px;border:1px solid var(--tng-border, #999);border-radius:var(--tng-border-radius, 4px);background-color:var(--tng-surface);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);pointer-events:none;transition:border-color .2s ease}.tng-legend{width:auto;max-width:0;height:11px;font-size:.75em;visibility:hidden;white-space:nowrap;padding-inline:0px}.tng-legend span{padding:0 2px;visibility:visible;opacity:0}.tng-label{position:absolute;top:50%;left:16px;transform:translateY(-50%);color:var(--tng-text-secondary, #666);font-size:16px;font-weight:400;pointer-events:none;transform-origin:left top;transition:transform .2s cubic-bezier(.4,0,.2,1),color .2s ease}.tng-input-display{flex:1;font-size:16px;color:var(--tng-text, #333);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;height:100%;display:flex;align-items:center}.tng-icon{color:var(--tng-text-secondary, #666);font-size:20px;margin-left:8px}.tng-datepicker-container.focused .tng-fieldset,.tng-datepicker-container.has-value .tng-fieldset{border-color:var(--tng-primary, #6200ee);border-width:2px}.tng-datepicker-container.focused .tng-label,.tng-datepicker-container.has-value .tng-label{color:var(--tng-primary, #6200ee);transform:translateY(-24px) scale(.75)}.tng-datepicker-container.focused .tng-legend,.tng-datepicker-container.has-value .tng-legend{max-width:100%}.tng-datepicker-container.focused .tng-label{color:var(--tng-primary, #6200ee)}.tng-calendar-popup{position:absolute;top:100%;left:0;z-index:1000;margin-top:4px;background:var(--tng-surface, #fff);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border-radius:8px;box-shadow:var(--tng-shadow-md, 0 4px 20px rgba(0, 0, 0, .15));padding:16px;width:300px;animation:fadeIn .2s ease;border:1px solid var(--tng-border, #eee)}@keyframes fadeIn{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.tng-calendar-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}.tng-calendar-header .current-month{font-weight:600;font-size:16px;color:var(--tng-text, #333)}.tng-calendar-header .nav-btn{background:none;border:none;cursor:pointer;padding:4px;border-radius:50%;display:flex;align-items:center;justify-content:center;color:var(--tng-text-secondary, #666)}.tng-calendar-header .nav-btn:hover{background-color:var(--tng-background, #f5f5f5)}.tng-calendar-grid{display:grid;grid-template-columns:repeat(7,1fr);gap:2px;text-align:center}.day-name{font-size:12px;color:var(--tng-text-secondary, #666);font-weight:500;margin-bottom:8px}.day-cell{height:36px;display:flex;align-items:center;justify-content:center;font-size:14px;cursor:pointer;border-radius:50%;transition:all .2s ease;position:relative;color:var(--tng-text, #333)}.day-cell:hover:not(.disabled):not(.selected):not(.range-start):not(.range-end){background-color:var(--tng-background, #f5f5f5)}.day-cell.not-current-month{color:#ccc}.day-cell.today{font-weight:600;color:var(--tng-primary, #6200ee);border:1px solid var(--tng-primary, #6200ee)}.day-cell.selected,.day-cell.range-start,.day-cell.range-end{background-color:var(--tng-primary, #6200ee);color:var(--tng-primary-contrast, #fff)}.day-cell.selected.today,.day-cell.range-start.today,.day-cell.range-end.today{border-color:transparent}.day-cell.in-range{background-color:color-mix(in srgb,var(--tng-primary, #6200ee),white 80%);border-radius:0;color:var(--tng-primary, #6200ee)}.day-cell.in-range.range-start{border-top-right-radius:0;border-bottom-right-radius:0}.day-cell.in-range.range-end{border-top-left-radius:0;border-bottom-left-radius:0}.day-cell.range-start{border-radius:50% 0 0 50%;position:relative}.day-cell.range-start:after{content:\"\";position:absolute;inset:0 0 0 50%;background-color:color-mix(in srgb,var(--tng-primary, #6200ee),white 80%);z-index:-1}.day-cell.range-end{border-radius:0 50% 50% 0;position:relative}.day-cell.range-end:after{content:\"\";position:absolute;inset:0 50% 0 0;background-color:color-mix(in srgb,var(--tng-primary, #6200ee),white 80%);z-index:-1}.day-cell.selected{border-radius:50%}.day-cell.disabled{opacity:.3;pointer-events:none;cursor:not-allowed}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }] });
625
+ ], ngImport: i0, template: "<div class=\"tng-datepicker-container\" [class.focused]=\"isOpen()\" [class.has-value]=\"formattedValue\" [class.disabled]=\"disabled()\">\n <!-- Trigger Field (Reusing Input Style) -->\n <div class=\"tng-input-trigger\" (click)=\"toggleCalendar()\">\n <fieldset class=\"tng-fieldset\" aria-hidden=\"true\">\n <legend class=\"tng-legend\"><span>{{ label() }}</span></legend>\n </fieldset>\n <label class=\"tng-label\">{{ label() }}</label>\n <div class=\"tng-input-display\">\n {{ formattedValue || (isOpen() ? placeholder() : '') }}\n </div>\n <i class=\"fa-solid fa-calendar tng-icon\"></i>\n </div>\n\n <!-- Calendar Popup -->\n @if (isOpen()) {\n <div class=\"tng-calendar-popup\">\n <div class=\"tng-calendar-header\">\n <button type=\"button\" class=\"nav-btn\" (click)=\"prev($event)\">\n <i class=\"fa-solid fa-chevron-left\"></i>\n </button>\n <button type=\"button\" class=\"header-label-btn\" (click)=\"onHeaderClick()\">\n {{ headerLabel }}\n </button>\n <button type=\"button\" class=\"nav-btn\" (click)=\"next($event)\">\n <i class=\"fa-solid fa-chevron-right\"></i>\n </button>\n </div>\n\n @switch (viewMode()) {\n @case ('day') {\n <div class=\"tng-calendar-grid\">\n @for (day of daysOfWeek; track day) {\n <div class=\"day-name\">{{ day }}</div>\n }\n @for (date of calendarDays(); track date.getTime()) {\n <div\n class=\"day-cell\"\n [class.not-current-month]=\"!isCurrentMonth(date)\"\n [class.today]=\"isToday(date)\"\n [class.selected]=\"isSelected(date)\"\n [class.in-range]=\"isInRange(date)\"\n [class.range-start]=\"mode() === 'range' && isSameDay(date, rangeValue.start)\"\n [class.range-end]=\"mode() === 'range' && isSameDay(date, rangeValue.end)\"\n [class.disabled]=\"isDisabled(date)\"\n (click)=\"selectDate(date)\"\n >\n {{ date.getDate() }}\n </div>\n }\n </div>\n }\n @case ('month') {\n <div class=\"tng-month-grid\">\n @for (month of monthNames; track $index) {\n <div \n class=\"month-cell\"\n [class.current]=\"currentViewDate().getMonth() === $index\"\n (click)=\"selectMonth($index)\"\n >\n {{ month.substring(0, 3) }}\n </div>\n }\n </div>\n }\n @case ('year') {\n <div class=\"tng-year-grid\">\n @for (year of yearsList(); track year) {\n <div \n class=\"year-cell\"\n [class.current]=\"currentViewDate().getFullYear() === year\"\n (click)=\"selectYear(year)\"\n >\n {{ year }}\n </div>\n }\n </div>\n }\n }\n </div>\n }\n</div>\n", styles: [":host{display:block;margin-bottom:1.5rem;font-family:var(--tng-font-family, \"Inter\", sans-serif);position:relative}.tng-datepicker-container{position:relative}.tng-datepicker-container.disabled{opacity:.6;pointer-events:none}.tng-datepicker-container.disabled .tng-fieldset{border-color:var(--tng-border, #e0e0e0);background-color:var(--tng-background, #fafafa)}.tng-input-trigger{position:relative;padding:0 16px;height:48px;display:flex;align-items:center;cursor:pointer}.tng-input-trigger:hover .tng-fieldset{border-color:var(--tng-text-secondary, #757575)}.tng-fieldset{position:absolute;inset:0 0 5px;margin:0;padding:0 12px;border:1px solid var(--tng-border, #999);border-radius:var(--tng-border-radius, 4px);background-color:var(--tng-surface);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);pointer-events:none;transition:border-color .2s ease,border-width .1s ease;z-index:0}.tng-legend{width:auto;max-width:0;height:11px;font-size:.75em;visibility:hidden;white-space:nowrap;padding-inline:0px;transition:max-width .1s cubic-bezier(.4,0,.2,1)}.tng-legend span{padding:0 2px;visibility:visible;opacity:0}.tng-label{position:absolute;top:50%;left:16px;transform:translateY(-50%);color:var(--tng-text-secondary, #666);font-size:16px;font-weight:400;pointer-events:none;transform-origin:left top;transition:transform .2s cubic-bezier(.4,0,.2,1),color .2s ease;z-index:1}.tng-input-display{flex:1;font-size:16px;color:var(--tng-text, #333);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;height:100%;display:flex;align-items:center;z-index:1;padding-bottom:5px}.tng-icon{color:var(--tng-text-secondary, #666);font-size:16px;margin-left:8px;z-index:1;padding-bottom:5px}.tng-datepicker-container.focused .tng-fieldset,.tng-datepicker-container.has-value .tng-fieldset{border-color:var(--tng-primary, #6200ee);border-width:2px}.tng-datepicker-container.focused .tng-label,.tng-datepicker-container.has-value .tng-label{transform:translateY(-24px) scale(.75)}.tng-datepicker-container.focused .tng-legend,.tng-datepicker-container.has-value .tng-legend{max-width:100%}.tng-datepicker-container.focused .tng-label{color:var(--tng-primary, #6200ee)}.tng-calendar-popup{position:absolute;top:100%;left:0;z-index:1000;margin-top:4px;background:var(--tng-surface, #fff);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border-radius:var(--tng-border-radius, 4px);box-shadow:var(--tng-shadow-md, 0 4px 20px rgba(0, 0, 0, .15));padding:16px;width:320px;animation:fadeIn .2s ease;border:1px solid var(--tng-border, #eee);color:var(--tng-text, #333)}@keyframes fadeIn{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.tng-calendar-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}.tng-calendar-header .header-label-btn{background:none;border:none;font-weight:600;font-size:16px;color:var(--tng-text, #333);text-transform:capitalize;cursor:pointer;padding:4px 8px;border-radius:var(--tng-border-radius, 4px);transition:background-color .2s ease}.tng-calendar-header .header-label-btn:hover{background-color:var(--tng-background, #f5f5f5);color:var(--tng-primary, #6200ee)}.tng-calendar-header .nav-btn{background:none;border:none;cursor:pointer;padding:8px;border-radius:50%;display:flex;align-items:center;justify-content:center;color:var(--tng-text-secondary, #666);transition:background-color .2s ease}.tng-calendar-header .nav-btn:hover{background-color:var(--tng-background, #f5f5f5);color:var(--tng-primary, #6200ee)}.tng-calendar-header .nav-btn i{font-size:14px}.tng-calendar-grid{display:grid;grid-template-columns:repeat(7,1fr);gap:2px;text-align:center}.day-name{font-size:12px;color:var(--tng-text-secondary, #666);font-weight:500;margin-bottom:8px}.day-cell{height:36px;display:flex;align-items:center;justify-content:center;font-size:14px;cursor:pointer;border-radius:50%;transition:all .2s ease;position:relative;color:var(--tng-text, #333)}.day-cell:hover:not(.disabled):not(.selected):not(.range-start):not(.range-end){background-color:var(--tng-background, #f5f5f5)}.day-cell.not-current-month{color:var(--tng-text-secondary, #ccc);opacity:.5}.day-cell.today{font-weight:600;color:var(--tng-primary, #6200ee)}.day-cell.selected,.day-cell.range-start,.day-cell.range-end{background-color:var(--tng-primary, #6200ee);color:var(--tng-primary-contrast, #fff)}.day-cell.selected.today,.day-cell.range-start.today,.day-cell.range-end.today{border-color:transparent}.day-cell.in-range{background-color:color-mix(in srgb,var(--tng-primary, #6200ee),var(--tng-surface));border-radius:0;color:var(--tng-primary, #6200ee)}.day-cell.in-range.range-start{border-top-right-radius:0;border-bottom-right-radius:0}.day-cell.in-range.range-end{border-top-left-radius:0;border-bottom-left-radius:0}.day-cell.range-start{border-radius:50% 0 0 50%;position:relative}.day-cell.range-start:after{content:\"\";position:absolute;inset:0 0 0 50%;background-color:color-mix(in srgb,var(--tng-primary, #6200ee),var(--tng-surface));z-index:-1}.day-cell.range-end{border-radius:0 50% 50% 0;position:relative}.day-cell.range-end:after{content:\"\";position:absolute;inset:0 50% 0 0;background-color:color-mix(in srgb,var(--tng-primary, #6200ee),white 85%);z-index:-1}.day-cell.selected{border-radius:50%}.day-cell.disabled{opacity:.3;pointer-events:none;cursor:not-allowed}.tng-month-grid,.tng-year-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;padding:8px 0}.month-cell,.year-cell{height:48px;display:flex;align-items:center;justify-content:center;font-size:14px;cursor:pointer;border-radius:var(--tng-border-radius, 4px);transition:all .2s ease;color:var(--tng-text, #333)}.month-cell:hover,.year-cell:hover{background-color:var(--tng-background, #f5f5f5);color:var(--tng-primary, #6200ee)}.month-cell.current,.year-cell.current{font-weight:600;color:var(--tng-primary, #6200ee);border:1px solid var(--tng-primary, #6200ee)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
564
626
  }
565
627
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: TecnualDatepickerComponent, decorators: [{
566
628
  type: Component,
@@ -570,7 +632,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.0", ngImpor
570
632
  useExisting: forwardRef(() => TecnualDatepickerComponent),
571
633
  multi: true
572
634
  }
573
- ], template: "<div class=\"tng-datepicker-container\" [class.focused]=\"isOpen()\" [class.has-value]=\"formattedValue\" [class.disabled]=\"disabled()\">\n <!-- Trigger Field (Reusing Input Style) -->\n <div class=\"tng-input-trigger\" (click)=\"toggleCalendar()\">\n <fieldset class=\"tng-fieldset\" aria-hidden=\"true\">\n <legend class=\"tng-legend\"><span>{{ label() }}</span></legend>\n </fieldset>\n <label class=\"tng-label\">{{ label() }}</label>\n <div class=\"tng-input-display\">\n {{ formattedValue || (isOpen() ? placeholder() : '') }}\n </div>\n <span class=\"material-icons tng-icon\">calendar_today</span>\n </div>\n\n <!-- Calendar Popup -->\n @if (isOpen()) {\n <div class=\"tng-calendar-popup\">\n <div class=\"tng-calendar-header\">\n <button type=\"button\" class=\"nav-btn\" (click)=\"prevMonth($event)\">\n <span class=\"material-icons\">chevron_left</span>\n </button>\n <span class=\"current-month\">{{ currentMonthYear }}</span>\n <button type=\"button\" class=\"nav-btn\" (click)=\"nextMonth($event)\">\n <span class=\"material-icons\">chevron_right</span>\n </button>\n </div>\n\n <div class=\"tng-calendar-grid\">\n @for (day of daysOfWeek; track day) {\n <div class=\"day-name\">{{ day }}</div>\n }\n @for (date of calendarDays(); track date.getTime()) {\n <div\n class=\"day-cell\"\n [class.not-current-month]=\"!isCurrentMonth(date)\"\n [class.today]=\"isToday(date)\"\n [class.selected]=\"isSelected(date)\"\n [class.in-range]=\"isInRange(date)\"\n [class.range-start]=\"mode() === 'range' && isSameDay(date, rangeValue.start)\"\n [class.range-end]=\"mode() === 'range' && isSameDay(date, rangeValue.end)\"\n [class.disabled]=\"isDisabled(date)\"\n (click)=\"selectDate(date)\"\n >\n {{ date.getDate() }}\n </div>\n }\n </div>\n </div>\n }\n</div>\n", styles: [":host{display:block;margin-bottom:1.5rem;font-family:var(--tng-font-family, \"Inter\", sans-serif);position:relative}.tng-datepicker-container{position:relative}.tng-datepicker-container.disabled{opacity:.6;pointer-events:none}.tng-datepicker-container.disabled .tng-fieldset{border-color:var(--tng-border, #ccc);background-color:var(--tng-background, #f9f9f9)}.tng-input-trigger{position:relative;border-radius:var(--tng-border-radius, 4px);padding:0 16px;height:48px;display:flex;align-items:center;cursor:pointer}.tng-input-trigger:hover .tng-fieldset{border-color:color-mix(in srgb,var(--tng-border, #999),black 20%)}.tng-fieldset{position:absolute;inset:0 0 5px;margin:0;padding:0 12px;border:1px solid var(--tng-border, #999);border-radius:var(--tng-border-radius, 4px);background-color:var(--tng-surface);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);pointer-events:none;transition:border-color .2s ease}.tng-legend{width:auto;max-width:0;height:11px;font-size:.75em;visibility:hidden;white-space:nowrap;padding-inline:0px}.tng-legend span{padding:0 2px;visibility:visible;opacity:0}.tng-label{position:absolute;top:50%;left:16px;transform:translateY(-50%);color:var(--tng-text-secondary, #666);font-size:16px;font-weight:400;pointer-events:none;transform-origin:left top;transition:transform .2s cubic-bezier(.4,0,.2,1),color .2s ease}.tng-input-display{flex:1;font-size:16px;color:var(--tng-text, #333);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;height:100%;display:flex;align-items:center}.tng-icon{color:var(--tng-text-secondary, #666);font-size:20px;margin-left:8px}.tng-datepicker-container.focused .tng-fieldset,.tng-datepicker-container.has-value .tng-fieldset{border-color:var(--tng-primary, #6200ee);border-width:2px}.tng-datepicker-container.focused .tng-label,.tng-datepicker-container.has-value .tng-label{color:var(--tng-primary, #6200ee);transform:translateY(-24px) scale(.75)}.tng-datepicker-container.focused .tng-legend,.tng-datepicker-container.has-value .tng-legend{max-width:100%}.tng-datepicker-container.focused .tng-label{color:var(--tng-primary, #6200ee)}.tng-calendar-popup{position:absolute;top:100%;left:0;z-index:1000;margin-top:4px;background:var(--tng-surface, #fff);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border-radius:8px;box-shadow:var(--tng-shadow-md, 0 4px 20px rgba(0, 0, 0, .15));padding:16px;width:300px;animation:fadeIn .2s ease;border:1px solid var(--tng-border, #eee)}@keyframes fadeIn{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.tng-calendar-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}.tng-calendar-header .current-month{font-weight:600;font-size:16px;color:var(--tng-text, #333)}.tng-calendar-header .nav-btn{background:none;border:none;cursor:pointer;padding:4px;border-radius:50%;display:flex;align-items:center;justify-content:center;color:var(--tng-text-secondary, #666)}.tng-calendar-header .nav-btn:hover{background-color:var(--tng-background, #f5f5f5)}.tng-calendar-grid{display:grid;grid-template-columns:repeat(7,1fr);gap:2px;text-align:center}.day-name{font-size:12px;color:var(--tng-text-secondary, #666);font-weight:500;margin-bottom:8px}.day-cell{height:36px;display:flex;align-items:center;justify-content:center;font-size:14px;cursor:pointer;border-radius:50%;transition:all .2s ease;position:relative;color:var(--tng-text, #333)}.day-cell:hover:not(.disabled):not(.selected):not(.range-start):not(.range-end){background-color:var(--tng-background, #f5f5f5)}.day-cell.not-current-month{color:#ccc}.day-cell.today{font-weight:600;color:var(--tng-primary, #6200ee);border:1px solid var(--tng-primary, #6200ee)}.day-cell.selected,.day-cell.range-start,.day-cell.range-end{background-color:var(--tng-primary, #6200ee);color:var(--tng-primary-contrast, #fff)}.day-cell.selected.today,.day-cell.range-start.today,.day-cell.range-end.today{border-color:transparent}.day-cell.in-range{background-color:color-mix(in srgb,var(--tng-primary, #6200ee),white 80%);border-radius:0;color:var(--tng-primary, #6200ee)}.day-cell.in-range.range-start{border-top-right-radius:0;border-bottom-right-radius:0}.day-cell.in-range.range-end{border-top-left-radius:0;border-bottom-left-radius:0}.day-cell.range-start{border-radius:50% 0 0 50%;position:relative}.day-cell.range-start:after{content:\"\";position:absolute;inset:0 0 0 50%;background-color:color-mix(in srgb,var(--tng-primary, #6200ee),white 80%);z-index:-1}.day-cell.range-end{border-radius:0 50% 50% 0;position:relative}.day-cell.range-end:after{content:\"\";position:absolute;inset:0 50% 0 0;background-color:color-mix(in srgb,var(--tng-primary, #6200ee),white 80%);z-index:-1}.day-cell.selected{border-radius:50%}.day-cell.disabled{opacity:.3;pointer-events:none;cursor:not-allowed}\n"] }]
635
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"tng-datepicker-container\" [class.focused]=\"isOpen()\" [class.has-value]=\"formattedValue\" [class.disabled]=\"disabled()\">\n <!-- Trigger Field (Reusing Input Style) -->\n <div class=\"tng-input-trigger\" (click)=\"toggleCalendar()\">\n <fieldset class=\"tng-fieldset\" aria-hidden=\"true\">\n <legend class=\"tng-legend\"><span>{{ label() }}</span></legend>\n </fieldset>\n <label class=\"tng-label\">{{ label() }}</label>\n <div class=\"tng-input-display\">\n {{ formattedValue || (isOpen() ? placeholder() : '') }}\n </div>\n <i class=\"fa-solid fa-calendar tng-icon\"></i>\n </div>\n\n <!-- Calendar Popup -->\n @if (isOpen()) {\n <div class=\"tng-calendar-popup\">\n <div class=\"tng-calendar-header\">\n <button type=\"button\" class=\"nav-btn\" (click)=\"prev($event)\">\n <i class=\"fa-solid fa-chevron-left\"></i>\n </button>\n <button type=\"button\" class=\"header-label-btn\" (click)=\"onHeaderClick()\">\n {{ headerLabel }}\n </button>\n <button type=\"button\" class=\"nav-btn\" (click)=\"next($event)\">\n <i class=\"fa-solid fa-chevron-right\"></i>\n </button>\n </div>\n\n @switch (viewMode()) {\n @case ('day') {\n <div class=\"tng-calendar-grid\">\n @for (day of daysOfWeek; track day) {\n <div class=\"day-name\">{{ day }}</div>\n }\n @for (date of calendarDays(); track date.getTime()) {\n <div\n class=\"day-cell\"\n [class.not-current-month]=\"!isCurrentMonth(date)\"\n [class.today]=\"isToday(date)\"\n [class.selected]=\"isSelected(date)\"\n [class.in-range]=\"isInRange(date)\"\n [class.range-start]=\"mode() === 'range' && isSameDay(date, rangeValue.start)\"\n [class.range-end]=\"mode() === 'range' && isSameDay(date, rangeValue.end)\"\n [class.disabled]=\"isDisabled(date)\"\n (click)=\"selectDate(date)\"\n >\n {{ date.getDate() }}\n </div>\n }\n </div>\n }\n @case ('month') {\n <div class=\"tng-month-grid\">\n @for (month of monthNames; track $index) {\n <div \n class=\"month-cell\"\n [class.current]=\"currentViewDate().getMonth() === $index\"\n (click)=\"selectMonth($index)\"\n >\n {{ month.substring(0, 3) }}\n </div>\n }\n </div>\n }\n @case ('year') {\n <div class=\"tng-year-grid\">\n @for (year of yearsList(); track year) {\n <div \n class=\"year-cell\"\n [class.current]=\"currentViewDate().getFullYear() === year\"\n (click)=\"selectYear(year)\"\n >\n {{ year }}\n </div>\n }\n </div>\n }\n }\n </div>\n }\n</div>\n", styles: [":host{display:block;margin-bottom:1.5rem;font-family:var(--tng-font-family, \"Inter\", sans-serif);position:relative}.tng-datepicker-container{position:relative}.tng-datepicker-container.disabled{opacity:.6;pointer-events:none}.tng-datepicker-container.disabled .tng-fieldset{border-color:var(--tng-border, #e0e0e0);background-color:var(--tng-background, #fafafa)}.tng-input-trigger{position:relative;padding:0 16px;height:48px;display:flex;align-items:center;cursor:pointer}.tng-input-trigger:hover .tng-fieldset{border-color:var(--tng-text-secondary, #757575)}.tng-fieldset{position:absolute;inset:0 0 5px;margin:0;padding:0 12px;border:1px solid var(--tng-border, #999);border-radius:var(--tng-border-radius, 4px);background-color:var(--tng-surface);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);pointer-events:none;transition:border-color .2s ease,border-width .1s ease;z-index:0}.tng-legend{width:auto;max-width:0;height:11px;font-size:.75em;visibility:hidden;white-space:nowrap;padding-inline:0px;transition:max-width .1s cubic-bezier(.4,0,.2,1)}.tng-legend span{padding:0 2px;visibility:visible;opacity:0}.tng-label{position:absolute;top:50%;left:16px;transform:translateY(-50%);color:var(--tng-text-secondary, #666);font-size:16px;font-weight:400;pointer-events:none;transform-origin:left top;transition:transform .2s cubic-bezier(.4,0,.2,1),color .2s ease;z-index:1}.tng-input-display{flex:1;font-size:16px;color:var(--tng-text, #333);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;height:100%;display:flex;align-items:center;z-index:1;padding-bottom:5px}.tng-icon{color:var(--tng-text-secondary, #666);font-size:16px;margin-left:8px;z-index:1;padding-bottom:5px}.tng-datepicker-container.focused .tng-fieldset,.tng-datepicker-container.has-value .tng-fieldset{border-color:var(--tng-primary, #6200ee);border-width:2px}.tng-datepicker-container.focused .tng-label,.tng-datepicker-container.has-value .tng-label{transform:translateY(-24px) scale(.75)}.tng-datepicker-container.focused .tng-legend,.tng-datepicker-container.has-value .tng-legend{max-width:100%}.tng-datepicker-container.focused .tng-label{color:var(--tng-primary, #6200ee)}.tng-calendar-popup{position:absolute;top:100%;left:0;z-index:1000;margin-top:4px;background:var(--tng-surface, #fff);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border-radius:var(--tng-border-radius, 4px);box-shadow:var(--tng-shadow-md, 0 4px 20px rgba(0, 0, 0, .15));padding:16px;width:320px;animation:fadeIn .2s ease;border:1px solid var(--tng-border, #eee);color:var(--tng-text, #333)}@keyframes fadeIn{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.tng-calendar-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}.tng-calendar-header .header-label-btn{background:none;border:none;font-weight:600;font-size:16px;color:var(--tng-text, #333);text-transform:capitalize;cursor:pointer;padding:4px 8px;border-radius:var(--tng-border-radius, 4px);transition:background-color .2s ease}.tng-calendar-header .header-label-btn:hover{background-color:var(--tng-background, #f5f5f5);color:var(--tng-primary, #6200ee)}.tng-calendar-header .nav-btn{background:none;border:none;cursor:pointer;padding:8px;border-radius:50%;display:flex;align-items:center;justify-content:center;color:var(--tng-text-secondary, #666);transition:background-color .2s ease}.tng-calendar-header .nav-btn:hover{background-color:var(--tng-background, #f5f5f5);color:var(--tng-primary, #6200ee)}.tng-calendar-header .nav-btn i{font-size:14px}.tng-calendar-grid{display:grid;grid-template-columns:repeat(7,1fr);gap:2px;text-align:center}.day-name{font-size:12px;color:var(--tng-text-secondary, #666);font-weight:500;margin-bottom:8px}.day-cell{height:36px;display:flex;align-items:center;justify-content:center;font-size:14px;cursor:pointer;border-radius:50%;transition:all .2s ease;position:relative;color:var(--tng-text, #333)}.day-cell:hover:not(.disabled):not(.selected):not(.range-start):not(.range-end){background-color:var(--tng-background, #f5f5f5)}.day-cell.not-current-month{color:var(--tng-text-secondary, #ccc);opacity:.5}.day-cell.today{font-weight:600;color:var(--tng-primary, #6200ee)}.day-cell.selected,.day-cell.range-start,.day-cell.range-end{background-color:var(--tng-primary, #6200ee);color:var(--tng-primary-contrast, #fff)}.day-cell.selected.today,.day-cell.range-start.today,.day-cell.range-end.today{border-color:transparent}.day-cell.in-range{background-color:color-mix(in srgb,var(--tng-primary, #6200ee),var(--tng-surface));border-radius:0;color:var(--tng-primary, #6200ee)}.day-cell.in-range.range-start{border-top-right-radius:0;border-bottom-right-radius:0}.day-cell.in-range.range-end{border-top-left-radius:0;border-bottom-left-radius:0}.day-cell.range-start{border-radius:50% 0 0 50%;position:relative}.day-cell.range-start:after{content:\"\";position:absolute;inset:0 0 0 50%;background-color:color-mix(in srgb,var(--tng-primary, #6200ee),var(--tng-surface));z-index:-1}.day-cell.range-end{border-radius:0 50% 50% 0;position:relative}.day-cell.range-end:after{content:\"\";position:absolute;inset:0 50% 0 0;background-color:color-mix(in srgb,var(--tng-primary, #6200ee),white 85%);z-index:-1}.day-cell.selected{border-radius:50%}.day-cell.disabled{opacity:.3;pointer-events:none;cursor:not-allowed}.tng-month-grid,.tng-year-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;padding:8px 0}.month-cell,.year-cell{height:48px;display:flex;align-items:center;justify-content:center;font-size:14px;cursor:pointer;border-radius:var(--tng-border-radius, 4px);transition:all .2s ease;color:var(--tng-text, #333)}.month-cell:hover,.year-cell:hover{background-color:var(--tng-background, #f5f5f5);color:var(--tng-primary, #6200ee)}.month-cell.current,.year-cell.current{font-weight:600;color:var(--tng-primary, #6200ee);border:1px solid var(--tng-primary, #6200ee)}\n"] }]
574
636
  }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], minDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "minDate", required: false }] }], maxDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDate", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], onClickOutside: [{
575
637
  type: HostListener,
576
638
  args: ['document:click', ['$event']]
@@ -1592,11 +1654,11 @@ class TngSelectPanelComponent {
1592
1654
  this.optionSelected.emit(index);
1593
1655
  }
1594
1656
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: TngSelectPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1595
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.0", type: TngSelectPanelComponent, isStandalone: true, selector: "tng-select-panel", outputs: { optionSelected: "optionSelected", searchQueryChanged: "searchQueryChanged", closeRequested: "closeRequested" }, ngImport: i0, template: "<div class=\"tng-select-panel\" \n role=\"listbox\"\n [attr.aria-multiselectable]=\"enableMulti()\">\n \n @if (enableSearch()) {\n <div class=\"tng-select-search\">\n <input \n type=\"text\"\n class=\"tng-select-search-input\"\n [value]=\"searchQuery()\"\n (input)=\"onSearchInput($event)\"\n placeholder=\"Search...\"\n aria-label=\"Search options\"\n (click)=\"$event.stopPropagation()\"\n />\n <i class=\"fa fa-search tng-select-search-icon\"></i>\n </div>\n }\n \n <div class=\"tng-select-options\" role=\"list\">\n @if (options().length === 0) {\n <div class=\"tng-select-no-results\">\n No options found\n </div>\n }\n \n @for (option of options(); track $index) {\n <div \n class=\"tng-select-option\"\n [class.selected]=\"isSelected($index)\"\n [class.disabled]=\"option.disabled\"\n role=\"option\"\n [attr.aria-selected]=\"isSelected($index)\"\n [attr.aria-disabled]=\"option.disabled\"\n (click)=\"onOptionClick($index, option)\"\n >\n @if (enableMulti()) {\n <input \n type=\"checkbox\"\n class=\"tng-select-checkbox\"\n [checked]=\"isSelected($index)\"\n [disabled]=\"option.disabled\"\n tabindex=\"-1\"\n />\n }\n <span class=\"tng-select-option-label\">{{ option.label }}</span>\n </div>\n }\n </div>\n</div>\n", styles: [":host{display:block}.tng-select-panel{background:var(--tng-surface, #ffffff);border:1px solid var(--tng-border, #e0e0e0);border-radius:var(--tng-border-radius, 4px);box-shadow:var(--tng-shadow-md, 0 4px 8px rgba(0, 0, 0, .12));overflow:hidden;animation:slideDown .2s cubic-bezier(.4,0,.2,1)}@keyframes slideDown{0%{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}.tng-select-search{position:relative;padding:.75rem;border-bottom:1px solid var(--tng-border, #e0e0e0)}.tng-select-search-input{width:100%;padding:.5rem 2rem .5rem .75rem;border:1px solid var(--tng-border, #e0e0e0);border-radius:var(--tng-border-radius, 4px);font-size:.9rem;color:var(--tng-text, #333);outline:none;transition:border-color .2s ease}.tng-select-search-input:focus{border-color:var(--tng-primary, #00f2ff)}.tng-select-search-icon{position:absolute;right:1.5rem;top:50%;transform:translateY(-50%);color:var(--tng-text-secondary, #757575);pointer-events:none}.tng-select-options{max-height:300px;overflow-y:auto;padding:.25rem 0}.tng-select-options::-webkit-scrollbar{width:8px}.tng-select-options::-webkit-scrollbar-track{background:var(--tng-background, #fafafa)}.tng-select-options::-webkit-scrollbar-thumb{background:var(--tng-border, #e0e0e0);border-radius:4px}.tng-select-options::-webkit-scrollbar-thumb:hover{background:var(--tng-text-secondary, #757575)}.tng-select-option{display:flex;align-items:center;gap:.75rem;padding:.75rem 1rem;cursor:pointer;transition:background-color .15s ease;-webkit-user-select:none;user-select:none}.tng-select-option:hover:not(.disabled){background:var(--tng-background, #fafafa)}.tng-select-option.selected{background:#00f2ff1a;color:var(--tng-primary, #00f2ff)}.tng-select-option.disabled{opacity:.5;cursor:not-allowed}.tng-select-checkbox{appearance:none;-webkit-appearance:none;-moz-appearance:none;width:18px;height:18px;min-width:18px;min-height:18px;border:2px solid var(--tng-border, #999);border-radius:var(--tng-border-radius, 4px);background-color:var(--tng-surface, #ffffff);cursor:pointer;position:relative;transition:all .2s cubic-bezier(.4,0,.2,1);margin:0;pointer-events:none}.tng-select-checkbox:checked{background-color:var(--tng-primary, #00f2ff);border-color:var(--tng-primary, #00f2ff)}.tng-select-checkbox:checked:before{content:\"\";position:absolute;width:4px;height:8px;border:solid var(--tng-primary-contrast, #000000);border-width:0 2px 2px 0;transform:rotate(45deg);top:2px;left:5px}.tng-select-checkbox:disabled{opacity:.5;cursor:not-allowed}.tng-select-option-label{flex:1;font-size:.95rem}.tng-select-no-results{padding:1.5rem 1rem;text-align:center;color:var(--tng-text-secondary, #757575);font-size:.9rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1657
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.0", type: TngSelectPanelComponent, isStandalone: true, selector: "tng-select-panel", outputs: { optionSelected: "optionSelected", searchQueryChanged: "searchQueryChanged", closeRequested: "closeRequested" }, ngImport: i0, template: "<div class=\"tng-select-panel\" \n role=\"listbox\"\n [attr.aria-multiselectable]=\"enableMulti()\">\n \n @if (enableSearch()) {\n <div class=\"tng-select-search\">\n <input \n type=\"text\"\n class=\"tng-select-search-input\"\n [value]=\"searchQuery()\"\n (input)=\"onSearchInput($event)\"\n placeholder=\"Search...\"\n aria-label=\"Search options\"\n (click)=\"$event.stopPropagation()\"\n />\n <i class=\"fa fa-search tng-select-search-icon\"></i>\n </div>\n }\n \n <div class=\"tng-select-options\" role=\"list\">\n @if (options().length === 0) {\n <div class=\"tng-select-no-results\">\n No options found\n </div>\n }\n \n @for (option of options(); track $index) {\n <div \n class=\"tng-select-option\"\n [class.selected]=\"isSelected($index)\"\n [class.disabled]=\"option.disabled\"\n role=\"option\"\n [attr.aria-selected]=\"isSelected($index)\"\n [attr.aria-disabled]=\"option.disabled\"\n (click)=\"onOptionClick($index, option)\"\n >\n @if (enableMulti()) {\n <input \n type=\"checkbox\"\n class=\"tng-select-checkbox\"\n [checked]=\"isSelected($index)\"\n [disabled]=\"option.disabled\"\n tabindex=\"-1\"\n />\n }\n <span class=\"tng-select-option-label\">{{ option.label }}</span>\n </div>\n }\n </div>\n</div>\n", styles: [":host{display:block;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)}.tng-select-panel{background:var(--tng-surface, #ffffff);border:1px solid var(--tng-border, #e0e0e0);border-radius:var(--tng-border-radius, 4px);box-shadow:var(--tng-shadow-md, 0 4px 8px rgba(0, 0, 0, .12));overflow:hidden;animation:slideDown .2s cubic-bezier(.4,0,.2,1)}@keyframes slideDown{0%{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}.tng-select-search{position:relative;padding:.75rem;border-bottom:1px solid var(--tng-border, #e0e0e0)}.tng-select-search-input{width:100%;padding:.5rem 2rem .5rem .75rem;border:1px solid var(--tng-border, #e0e0e0);border-radius:var(--tng-border-radius, 4px);font-size:.9rem;color:var(--tng-text, #333);outline:none;transition:border-color .2s ease}.tng-select-search-input:focus{border-color:var(--tng-primary, #00f2ff)}.tng-select-search-icon{position:absolute;right:1.5rem;top:50%;transform:translateY(-50%);color:var(--tng-text-secondary, #757575);pointer-events:none}.tng-select-options{max-height:300px;overflow-y:auto;padding:.25rem 0}.tng-select-options::-webkit-scrollbar{width:8px}.tng-select-options::-webkit-scrollbar-track{background:var(--tng-background, #fafafa)}.tng-select-options::-webkit-scrollbar-thumb{background:var(--tng-border, #e0e0e0);border-radius:4px}.tng-select-options::-webkit-scrollbar-thumb:hover{background:var(--tng-text-secondary, #757575)}.tng-select-option{display:flex;align-items:center;gap:.75rem;padding:.75rem 1rem;cursor:pointer;transition:background-color .15s ease;-webkit-user-select:none;user-select:none}.tng-select-option:hover:not(.disabled){background:var(--tng-background, #fafafa)}.tng-select-option.selected{background:#00f2ff1a;color:var(--tng-primary, #00f2ff)}.tng-select-option.disabled{opacity:.5;cursor:not-allowed}.tng-select-checkbox{appearance:none;-webkit-appearance:none;-moz-appearance:none;width:18px;height:18px;min-width:18px;min-height:18px;border:2px solid var(--tng-border, #999);border-radius:var(--tng-border-radius, 4px);background-color:var(--tng-surface, #ffffff);cursor:pointer;position:relative;transition:all .2s cubic-bezier(.4,0,.2,1);margin:0;pointer-events:none}.tng-select-checkbox:checked{background-color:var(--tng-primary, #00f2ff);border-color:var(--tng-primary, #00f2ff)}.tng-select-checkbox:checked:before{content:\"\";position:absolute;width:4px;height:8px;border:solid var(--tng-primary-contrast, #000000);border-width:0 2px 2px 0;transform:rotate(45deg);top:2px;left:5px}.tng-select-checkbox:disabled{opacity:.5;cursor:not-allowed}.tng-select-option-label{flex:1;font-size:.95rem}.tng-select-no-results{padding:1.5rem 1rem;text-align:center;color:var(--tng-text-secondary, #757575);font-size:.9rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1596
1658
  }
1597
1659
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: TngSelectPanelComponent, decorators: [{
1598
1660
  type: Component,
1599
- args: [{ selector: 'tng-select-panel', standalone: true, imports: [CommonModule, FormsModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"tng-select-panel\" \n role=\"listbox\"\n [attr.aria-multiselectable]=\"enableMulti()\">\n \n @if (enableSearch()) {\n <div class=\"tng-select-search\">\n <input \n type=\"text\"\n class=\"tng-select-search-input\"\n [value]=\"searchQuery()\"\n (input)=\"onSearchInput($event)\"\n placeholder=\"Search...\"\n aria-label=\"Search options\"\n (click)=\"$event.stopPropagation()\"\n />\n <i class=\"fa fa-search tng-select-search-icon\"></i>\n </div>\n }\n \n <div class=\"tng-select-options\" role=\"list\">\n @if (options().length === 0) {\n <div class=\"tng-select-no-results\">\n No options found\n </div>\n }\n \n @for (option of options(); track $index) {\n <div \n class=\"tng-select-option\"\n [class.selected]=\"isSelected($index)\"\n [class.disabled]=\"option.disabled\"\n role=\"option\"\n [attr.aria-selected]=\"isSelected($index)\"\n [attr.aria-disabled]=\"option.disabled\"\n (click)=\"onOptionClick($index, option)\"\n >\n @if (enableMulti()) {\n <input \n type=\"checkbox\"\n class=\"tng-select-checkbox\"\n [checked]=\"isSelected($index)\"\n [disabled]=\"option.disabled\"\n tabindex=\"-1\"\n />\n }\n <span class=\"tng-select-option-label\">{{ option.label }}</span>\n </div>\n }\n </div>\n</div>\n", styles: [":host{display:block}.tng-select-panel{background:var(--tng-surface, #ffffff);border:1px solid var(--tng-border, #e0e0e0);border-radius:var(--tng-border-radius, 4px);box-shadow:var(--tng-shadow-md, 0 4px 8px rgba(0, 0, 0, .12));overflow:hidden;animation:slideDown .2s cubic-bezier(.4,0,.2,1)}@keyframes slideDown{0%{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}.tng-select-search{position:relative;padding:.75rem;border-bottom:1px solid var(--tng-border, #e0e0e0)}.tng-select-search-input{width:100%;padding:.5rem 2rem .5rem .75rem;border:1px solid var(--tng-border, #e0e0e0);border-radius:var(--tng-border-radius, 4px);font-size:.9rem;color:var(--tng-text, #333);outline:none;transition:border-color .2s ease}.tng-select-search-input:focus{border-color:var(--tng-primary, #00f2ff)}.tng-select-search-icon{position:absolute;right:1.5rem;top:50%;transform:translateY(-50%);color:var(--tng-text-secondary, #757575);pointer-events:none}.tng-select-options{max-height:300px;overflow-y:auto;padding:.25rem 0}.tng-select-options::-webkit-scrollbar{width:8px}.tng-select-options::-webkit-scrollbar-track{background:var(--tng-background, #fafafa)}.tng-select-options::-webkit-scrollbar-thumb{background:var(--tng-border, #e0e0e0);border-radius:4px}.tng-select-options::-webkit-scrollbar-thumb:hover{background:var(--tng-text-secondary, #757575)}.tng-select-option{display:flex;align-items:center;gap:.75rem;padding:.75rem 1rem;cursor:pointer;transition:background-color .15s ease;-webkit-user-select:none;user-select:none}.tng-select-option:hover:not(.disabled){background:var(--tng-background, #fafafa)}.tng-select-option.selected{background:#00f2ff1a;color:var(--tng-primary, #00f2ff)}.tng-select-option.disabled{opacity:.5;cursor:not-allowed}.tng-select-checkbox{appearance:none;-webkit-appearance:none;-moz-appearance:none;width:18px;height:18px;min-width:18px;min-height:18px;border:2px solid var(--tng-border, #999);border-radius:var(--tng-border-radius, 4px);background-color:var(--tng-surface, #ffffff);cursor:pointer;position:relative;transition:all .2s cubic-bezier(.4,0,.2,1);margin:0;pointer-events:none}.tng-select-checkbox:checked{background-color:var(--tng-primary, #00f2ff);border-color:var(--tng-primary, #00f2ff)}.tng-select-checkbox:checked:before{content:\"\";position:absolute;width:4px;height:8px;border:solid var(--tng-primary-contrast, #000000);border-width:0 2px 2px 0;transform:rotate(45deg);top:2px;left:5px}.tng-select-checkbox:disabled{opacity:.5;cursor:not-allowed}.tng-select-option-label{flex:1;font-size:.95rem}.tng-select-no-results{padding:1.5rem 1rem;text-align:center;color:var(--tng-text-secondary, #757575);font-size:.9rem}\n"] }]
1661
+ args: [{ selector: 'tng-select-panel', standalone: true, imports: [CommonModule, FormsModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"tng-select-panel\" \n role=\"listbox\"\n [attr.aria-multiselectable]=\"enableMulti()\">\n \n @if (enableSearch()) {\n <div class=\"tng-select-search\">\n <input \n type=\"text\"\n class=\"tng-select-search-input\"\n [value]=\"searchQuery()\"\n (input)=\"onSearchInput($event)\"\n placeholder=\"Search...\"\n aria-label=\"Search options\"\n (click)=\"$event.stopPropagation()\"\n />\n <i class=\"fa fa-search tng-select-search-icon\"></i>\n </div>\n }\n \n <div class=\"tng-select-options\" role=\"list\">\n @if (options().length === 0) {\n <div class=\"tng-select-no-results\">\n No options found\n </div>\n }\n \n @for (option of options(); track $index) {\n <div \n class=\"tng-select-option\"\n [class.selected]=\"isSelected($index)\"\n [class.disabled]=\"option.disabled\"\n role=\"option\"\n [attr.aria-selected]=\"isSelected($index)\"\n [attr.aria-disabled]=\"option.disabled\"\n (click)=\"onOptionClick($index, option)\"\n >\n @if (enableMulti()) {\n <input \n type=\"checkbox\"\n class=\"tng-select-checkbox\"\n [checked]=\"isSelected($index)\"\n [disabled]=\"option.disabled\"\n tabindex=\"-1\"\n />\n }\n <span class=\"tng-select-option-label\">{{ option.label }}</span>\n </div>\n }\n </div>\n</div>\n", styles: [":host{display:block;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)}.tng-select-panel{background:var(--tng-surface, #ffffff);border:1px solid var(--tng-border, #e0e0e0);border-radius:var(--tng-border-radius, 4px);box-shadow:var(--tng-shadow-md, 0 4px 8px rgba(0, 0, 0, .12));overflow:hidden;animation:slideDown .2s cubic-bezier(.4,0,.2,1)}@keyframes slideDown{0%{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}.tng-select-search{position:relative;padding:.75rem;border-bottom:1px solid var(--tng-border, #e0e0e0)}.tng-select-search-input{width:100%;padding:.5rem 2rem .5rem .75rem;border:1px solid var(--tng-border, #e0e0e0);border-radius:var(--tng-border-radius, 4px);font-size:.9rem;color:var(--tng-text, #333);outline:none;transition:border-color .2s ease}.tng-select-search-input:focus{border-color:var(--tng-primary, #00f2ff)}.tng-select-search-icon{position:absolute;right:1.5rem;top:50%;transform:translateY(-50%);color:var(--tng-text-secondary, #757575);pointer-events:none}.tng-select-options{max-height:300px;overflow-y:auto;padding:.25rem 0}.tng-select-options::-webkit-scrollbar{width:8px}.tng-select-options::-webkit-scrollbar-track{background:var(--tng-background, #fafafa)}.tng-select-options::-webkit-scrollbar-thumb{background:var(--tng-border, #e0e0e0);border-radius:4px}.tng-select-options::-webkit-scrollbar-thumb:hover{background:var(--tng-text-secondary, #757575)}.tng-select-option{display:flex;align-items:center;gap:.75rem;padding:.75rem 1rem;cursor:pointer;transition:background-color .15s ease;-webkit-user-select:none;user-select:none}.tng-select-option:hover:not(.disabled){background:var(--tng-background, #fafafa)}.tng-select-option.selected{background:#00f2ff1a;color:var(--tng-primary, #00f2ff)}.tng-select-option.disabled{opacity:.5;cursor:not-allowed}.tng-select-checkbox{appearance:none;-webkit-appearance:none;-moz-appearance:none;width:18px;height:18px;min-width:18px;min-height:18px;border:2px solid var(--tng-border, #999);border-radius:var(--tng-border-radius, 4px);background-color:var(--tng-surface, #ffffff);cursor:pointer;position:relative;transition:all .2s cubic-bezier(.4,0,.2,1);margin:0;pointer-events:none}.tng-select-checkbox:checked{background-color:var(--tng-primary, #00f2ff);border-color:var(--tng-primary, #00f2ff)}.tng-select-checkbox:checked:before{content:\"\";position:absolute;width:4px;height:8px;border:solid var(--tng-primary-contrast, #000000);border-width:0 2px 2px 0;transform:rotate(45deg);top:2px;left:5px}.tng-select-checkbox:disabled{opacity:.5;cursor:not-allowed}.tng-select-option-label{flex:1;font-size:.95rem}.tng-select-no-results{padding:1.5rem 1rem;text-align:center;color:var(--tng-text-secondary, #757575);font-size:.9rem}\n"] }]
1600
1662
  }], propDecorators: { optionSelected: [{ type: i0.Output, args: ["optionSelected"] }], searchQueryChanged: [{ type: i0.Output, args: ["searchQueryChanged"] }], closeRequested: [{ type: i0.Output, args: ["closeRequested"] }] } });
1601
1663
 
1602
1664
  class TngSelectDirective {