@open-rlb/ng-bootstrap 3.3.11 → 3.3.13

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.
@@ -3,13 +3,13 @@ import { input, booleanAttribute, output, viewChild, ChangeDetectionStrategy, Co
3
3
  import * as i2$1 from '@angular/router';
4
4
  import { RouterLink, RouterLinkActive, RouterModule } from '@angular/router';
5
5
  import { Collapse, Carousel, Dropdown, Modal, Toast, Offcanvas, ScrollSpy, Popover, Tooltip } from 'bootstrap';
6
- import { NgTemplateOutlet, TitleCasePipe, NgClass, formatDate, JsonPipe, CommonModule } from '@angular/common';
6
+ import { NgTemplateOutlet, NgClass, formatDate, TitleCasePipe, JsonPipe, CommonModule } from '@angular/common';
7
7
  import { Subject, of, map, shareReplay, take, filter, switchMap, Subscription, debounceTime, distinctUntilChanged, Observable, lastValueFrom, takeUntil } from 'rxjs';
8
8
  import * as i2 from '@angular/cdk/layout';
9
9
  import * as i1 from '@angular/forms';
10
10
  import { FormsModule, NgControl, FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
11
- import { DateTz } from '@open-rlb/date-tz';
12
11
  import { DateTz as DateTz$1 } from '@open-rlb/date-tz/date-tz';
12
+ import { DateTz } from '@open-rlb/date-tz';
13
13
  import { CdkDropListGroup, CdkDropList, CdkDrag, CdkDragPlaceholder, CdkDragPreview } from '@angular/cdk/drag-drop';
14
14
  import { toSignal, takeUntilDestroyed } from '@angular/core/rxjs-interop';
15
15
  import { TranslatePipe, TranslateModule } from '@ngx-translate/core';
@@ -2513,12 +2513,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
2513
2513
  args: [{ selector: 'rlb-fab', changeDetection: ChangeDetectionStrategy.OnPush, imports: [ButtonComponent], template: "<button rlb-button [color]=\"color()\" [disabled]=\"disabled()\" [outline]=\"outline()\"\n class=\"fab-button d-flex align-items-center justify-content-center\" [class]=\"[sizeClass(), positionClass()]\">\n <ng-content></ng-content>\n</button>", styles: [".fab-button{border-radius:50%;box-shadow:0 4px 12px #00000040;z-index:1050;transition:transform .2s ease,box-shadow .2s ease;padding:0}.fab-button:hover{transform:scale(1.08);box-shadow:0 6px 18px #00000059}.fab-button:active{transform:scale(.95)}:host{width:fit-content;display:block}.fab-xs{width:32px;height:32px;font-size:1rem}.fab-sm{width:44px;height:44px;font-size:1.2rem}.fab-md{width:56px;height:56px;font-size:1.4rem}.fab-lg{width:68px;height:68px;font-size:1.7rem}.fab-bottom-right{bottom:24px;right:24px}.fab-bottom-left{bottom:24px;left:24px}.fab-top-right{top:24px;right:24px}.fab-top-left{top:24px;left:24px}\n"] }]
2514
2514
  }], propDecorators: { color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], outline: [{ type: i0.Input, args: [{ isSignal: true, alias: "outline", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }] } });
2515
2515
 
2516
- const DEFAULT_CALENDAR_LAYOUT = {
2517
- rowHeight: 110,
2518
- maxBodyHeight: 30,
2519
- minHeaderHeight: 3.5
2520
- };
2521
-
2522
2516
  function isSameDay(a, b) {
2523
2517
  return a.yearUTC === b.yearUTC &&
2524
2518
  a.monthUTC === b.monthUTC &&
@@ -2566,105 +2560,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
2566
2560
  args: [{ name: 'dtz' }]
2567
2561
  }] });
2568
2562
 
2569
- class MonthFormatterPipe {
2570
- constructor() {
2571
- this.months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
2572
- }
2573
- transform(value) {
2574
- if (!value)
2575
- return '';
2576
- const parts = value.trim().split(' ');
2577
- if (parts.length < 2)
2578
- return value;
2579
- const day = parts[0];
2580
- const monthIndex = parseInt(parts[1], 10) - 1;
2581
- if (isNaN(monthIndex) || monthIndex < 0 || monthIndex > 11) {
2582
- return value;
2583
- }
2584
- const month = this.months[monthIndex];
2585
- const rest = parts.slice(2).join(' ');
2586
- return `${day} ${month}${rest ? ' ' + rest : ''}`;
2587
- }
2588
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: MonthFormatterPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
2589
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.14", ngImport: i0, type: MonthFormatterPipe, isStandalone: true, name: "monthFormatter" }); }
2590
- }
2591
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: MonthFormatterPipe, decorators: [{
2592
- type: Pipe,
2593
- args: [{ name: 'monthFormatter' }]
2594
- }] });
2595
-
2596
- class CalendarHeaderComponent {
2597
- constructor() {
2598
- this.view = input('month', ...(ngDevMode ? [{ debugName: "view" }] : /* istanbul ignore next */ []));
2599
- this.currentDate = input.required(...(ngDevMode ? [{ debugName: "currentDate" }] : /* istanbul ignore next */ []));
2600
- this.dateChange = output();
2601
- this.viewChange = output();
2602
- }
2603
- next() {
2604
- switch (this.view()) {
2605
- case 'week':
2606
- const nextWeek = addDays(this.currentDate(), 7);
2607
- this.dateChange.emit(new DateTz(nextWeek));
2608
- break;
2609
- case 'month':
2610
- const nextMonth = new DateTz(this.currentDate()).set(1, 'day').add(1, 'month');
2611
- this.dateChange.emit(new DateTz(nextMonth));
2612
- break;
2613
- case 'day':
2614
- const nextDay = addDays(this.currentDate(), 1);
2615
- this.dateChange.emit(new DateTz(nextDay));
2616
- break;
2617
- default:
2618
- break;
2619
- }
2620
- }
2621
- prev() {
2622
- switch (this.view()) {
2623
- case 'week':
2624
- const pastWeek = addDays(this.currentDate(), -7);
2625
- this.dateChange.emit(new DateTz(pastWeek));
2626
- break;
2627
- case 'month':
2628
- const pastMonth = new DateTz(this.currentDate()).set(1, 'day').add(-1, 'month');
2629
- this.dateChange.emit(new DateTz(pastMonth));
2630
- break;
2631
- case 'day':
2632
- const nextDay = addDays(this.currentDate(), -1);
2633
- this.dateChange.emit(new DateTz(nextDay));
2634
- break;
2635
- default:
2636
- break;
2637
- }
2638
- }
2639
- today() {
2640
- switch (this.view()) {
2641
- case 'week':
2642
- default:
2643
- const today = getToday();
2644
- this.dateChange.emit(today);
2645
- break;
2646
- }
2647
- }
2648
- setView(view) {
2649
- this.viewChange.emit(view);
2650
- }
2651
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CalendarHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2652
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.14", type: CalendarHeaderComponent, isStandalone: true, selector: "rlb-calendar-header", inputs: { view: { classPropertyName: "view", publicName: "view", isSignal: true, isRequired: false, transformFunction: null }, currentDate: { classPropertyName: "currentDate", publicName: "currentDate", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { dateChange: "dateChange", viewChange: "viewChange" }, ngImport: i0, template: "<div class=\"d-flex justify-content-between align-items-center mb-3\">\n\t<div class=\"d-flex gap-1\">\n\t\t<button rlb-button outline (click)=\"prev()\">\n\t\t\t<i class=\"bi bi-chevron-left\"></i>\n\t\t</button>\n\t\t<button rlb-button outline (click)=\"today()\">Today</button>\n\t\t<button rlb-button outline (click)=\"next()\">\n\t\t\t<i class=\"bi-chevron-right\"></i>\n\t\t</button>\n\t</div>\n\n\t<h5 class=\"mb-0\">{{ currentDate() | dtz:'DD MM yyyy' | monthFormatter }} {{ currentDate().timezone }}</h5>\n\n\t<rlb-dropdown>\n\t\t<button rlb-button outline rlb-dropdown>{{ view() | titlecase }}</button>\n\t\t<ul rlb-dropdown-menu [placement]=\"'right'\">\n\t\t\t<li rlb-dropdown-item (click)=\"setView('day')\">Day</li>\n\t\t\t<li rlb-dropdown-item (click)=\"setView('week')\">Week</li>\n\t\t\t<li rlb-dropdown-item (click)=\"setView('month')\">Month</li>\n\t\t</ul>\n\t</rlb-dropdown>\n</div>", styles: [""], dependencies: [{ kind: "component", type: ButtonComponent, selector: "button[rlb-button], a[rlb-button]", inputs: ["color", "size", "disabled", "outline", "isLink"] }, { kind: "component", type: DropdownComponent, selector: "rlb-dropdown", inputs: ["direction"] }, { kind: "directive", type: DropdownDirective, selector: "a[rlb-dropdown], button[rlb-dropdown], span[rlb-badge][rlb-dropdown]", inputs: ["offset", "auto-close"], outputs: ["status-changed"] }, { kind: "component", type: DropdownContainerComponent, selector: "ul[rlb-dropdown-menu], rlb-dropdown-container", inputs: ["placement", "placement-sm", "placement-md", "placement-lg", "placement-xl", "placement-xxl"] }, { kind: "component", type: DropdownMenuItemComponent, selector: "li[rlb-dropdown-item]", inputs: ["active", "disabled", "header", "divider", "link", "text-wrap"] }, { kind: "pipe", type: TitleCasePipe, name: "titlecase" }, { kind: "pipe", type: DateTzPipe, name: "dtz" }, { kind: "pipe", type: MonthFormatterPipe, name: "monthFormatter" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2653
- }
2654
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CalendarHeaderComponent, decorators: [{
2655
- type: Component,
2656
- args: [{ selector: 'rlb-calendar-header', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
2657
- ButtonComponent,
2658
- DropdownComponent,
2659
- DropdownDirective,
2660
- DropdownContainerComponent,
2661
- DropdownMenuItemComponent,
2662
- TitleCasePipe,
2663
- DateTzPipe,
2664
- MonthFormatterPipe,
2665
- ], template: "<div class=\"d-flex justify-content-between align-items-center mb-3\">\n\t<div class=\"d-flex gap-1\">\n\t\t<button rlb-button outline (click)=\"prev()\">\n\t\t\t<i class=\"bi bi-chevron-left\"></i>\n\t\t</button>\n\t\t<button rlb-button outline (click)=\"today()\">Today</button>\n\t\t<button rlb-button outline (click)=\"next()\">\n\t\t\t<i class=\"bi-chevron-right\"></i>\n\t\t</button>\n\t</div>\n\n\t<h5 class=\"mb-0\">{{ currentDate() | dtz:'DD MM yyyy' | monthFormatter }} {{ currentDate().timezone }}</h5>\n\n\t<rlb-dropdown>\n\t\t<button rlb-button outline rlb-dropdown>{{ view() | titlecase }}</button>\n\t\t<ul rlb-dropdown-menu [placement]=\"'right'\">\n\t\t\t<li rlb-dropdown-item (click)=\"setView('day')\">Day</li>\n\t\t\t<li rlb-dropdown-item (click)=\"setView('week')\">Week</li>\n\t\t\t<li rlb-dropdown-item (click)=\"setView('month')\">Month</li>\n\t\t</ul>\n\t</rlb-dropdown>\n</div>" }]
2666
- }], propDecorators: { view: [{ type: i0.Input, args: [{ isSignal: true, alias: "view", required: false }] }], currentDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentDate", required: true }] }], dateChange: [{ type: i0.Output, args: ["dateChange"] }], viewChange: [{ type: i0.Output, args: ["viewChange"] }] } });
2667
-
2668
2563
  class CalendarEventComponent {
2669
2564
  constructor() {
2670
2565
  this.event = input.required(...(ngDevMode ? [{ debugName: "event" }] : /* istanbul ignore next */ []));
@@ -2763,6 +2658,7 @@ class CalendarWeekGridComponent {
2763
2658
  this.view = input.required(...(ngDevMode ? [{ debugName: "view" }] : /* istanbul ignore next */ []));
2764
2659
  this.currentDate = input.required(...(ngDevMode ? [{ debugName: "currentDate" }] : /* istanbul ignore next */ []));
2765
2660
  this.events = input([], ...(ngDevMode ? [{ debugName: "events" }] : /* istanbul ignore next */ []));
2661
+ this.intervals = input([], ...(ngDevMode ? [{ debugName: "intervals" }] : /* istanbul ignore next */ []));
2766
2662
  this.layout = input.required(...(ngDevMode ? [{ debugName: "layout" }] : /* istanbul ignore next */ []));
2767
2663
  this.eventClick = output({ alias: 'event-click' });
2768
2664
  this.eventContainerClick = output({ alias: 'event-container-click' });
@@ -2878,6 +2774,22 @@ class CalendarWeekGridComponent {
2878
2774
  this.nowInterval = null;
2879
2775
  }
2880
2776
  }
2777
+ getIntervalsForDay(day) {
2778
+ const dayOfWeek = new DateTz$1(day).dayOfWeek; // 0=Sun, 1=Mon...
2779
+ return this.intervals().filter(interval => interval.dayWeek === dayOfWeek);
2780
+ }
2781
+ getIntervalTop(interval) {
2782
+ const seconds = interval.hourStart ?? 0;
2783
+ return (seconds / 3600) * this.layout().rowHeight;
2784
+ }
2785
+ getIntervalHeight(interval) {
2786
+ const start = interval.hourStart ?? 0;
2787
+ const stop = interval.hourStop ?? 86400;
2788
+ return ((stop - start) / 3600) * this.layout().rowHeight;
2789
+ }
2790
+ getIntervalColor(interval) {
2791
+ return `var(--bs-${interval.color || 'success'})`;
2792
+ }
2881
2793
  buildWeekGrid(currentDate) {
2882
2794
  const dayOfWeek = currentDate.dayOfWeek; // 0 = Sunday, 1 = Monday ...
2883
2795
  // Week init (monday)
@@ -3073,12 +2985,12 @@ class CalendarWeekGridComponent {
3073
2985
  });
3074
2986
  }
3075
2987
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CalendarWeekGridComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3076
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: CalendarWeekGridComponent, isStandalone: true, selector: "rlb-calendar-week-grid", inputs: { view: { classPropertyName: "view", publicName: "view", isSignal: true, isRequired: true, transformFunction: null }, currentDate: { classPropertyName: "currentDate", publicName: "currentDate", isSignal: true, isRequired: true, transformFunction: null }, events: { classPropertyName: "events", publicName: "events", isSignal: true, isRequired: false, transformFunction: null }, layout: { classPropertyName: "layout", publicName: "layout", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { eventClick: "event-click", eventContainerClick: "event-container-click", eventChange: "event-change" }, viewQueries: [{ propertyName: "scrollBodyRef", first: true, predicate: ["scrollBody"], descendants: true, isSignal: true }, { propertyName: "headerRowRef", first: true, predicate: ["headerRow"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"calendar-wrapper d-flex flex-column\">\n\n <!-- HEADER WRAPPER -->\n <div #headerRow class=\"header-container overflow-hidden flex-shrink-0 border-bottom bg-body-tertiary\"\n [style.padding-right.px]=\"scrollbarWidth()\">\n\n <div class=\"header-row d-flex\" [style.min-height.rem]=\"layout().minHeaderHeight\">\n\n <div class=\"time-gutter border-end flex-shrink-0\"></div>\n\n <div class=\"days-header d-flex flex-grow-1\">\n @for (day of days(); track day.timestamp) {\n <div class=\"day-cell text-center p-2 border-end\" [class.text-primary]=\"isToday(day)\"\n [class.fw-bold]=\"isToday(day)\" [class.bg-primary]=\"isToday(day)\">\n <div class=\"small text-uppercase text-body-secondary\">{{ day | dayOfWeek: 'short' }}</div>\n <div class=\"h5 m-0\">{{ day | dtz:'DD' }}</div>\n </div>\n }\n </div>\n </div>\n </div>\n\n <!-- BODY WRAPPER -->\n <div #scrollBody class=\"calendar-body flex-grow-1 overflow-auto bg-body position-relative\"\n (scroll)=\"onBodyScroll($event)\" [style.max-height.rem]=\"layout().maxBodyHeight\">\n\n <div class=\"body-row d-flex position-relative\">\n\n <!-- SIDEBAR (Sticky Left) -->\n <div class=\"time-sidebar sticky-start flex-shrink-0 border-end\">\n @for (time of timeSlots(); track time; let i = $index) {\n <div class=\"time-slot-label small text-body-secondary d-flex align-items-start justify-content-center\"\n [style.height.px]=\"layout().rowHeight\">\n @if (i !== 0) {\n <span style=\"transform: translateY(-50%)\">\n {{ time }}\n </span>\n }\n </div>\n }\n </div>\n\n <!-- GRID AND EVENTS -->\n <div class=\"grid-layer flex-grow-1 position-relative\">\n\n <!-- LAYER 1: Grid -->\n <div class=\"background-grid position-absolute w-100 h-100 top-0 start-0 z-0\">\n @for (time of timeSlots(); track time) {\n <div class=\"grid-row border-bottom\" [style.height.px]=\"layout().rowHeight\">\n </div>\n }\n </div>\n\n <!-- Layer 2: Events -->\n <div class=\"events-container d-flex h-100 w-100 position-relative z-1\" cdkDropListGroup>\n @for (day of days(); track day.timestamp) {\n <div class=\"day-column position-relative border-end h-100\" cdkDropList [cdkDropListSortingDisabled]=\"true\"\n [cdkDropListData]=\"day\" (cdkDropListDropped)=\"onEventDrop($event)\" (click)=\"eventClick.emit(undefined)\">\n @for (event of getEventsForDay(day); track trackByEventId($index, event)) {\n <rlb-calendar-event [view]=\"view()\" [event]=\"event\" [style.top.px]=\"calculateEventTop(event)\"\n [style.height.px]=\"calculateEventHeight(event)\" [style.left.%]=\"event.left\" [style.width.%]=\"event.width\"\n (event-click)=\"eventClick.emit($event)\" (event-container-click)=\"eventContainerClick.emit($event)\" cdkDrag\n [cdkDragData]=\"event\" [cdkDragDisabled]=\"event.isOverflowIndicator\" class=\"position-absolute\">\n <div *cdkDragPlaceholder style=\"opacity: 0\"></div>\n </rlb-calendar-event>\n }\n @if (isToday(day)) {\n <div class=\"now-line\" [style.top.px]=\"getNowTop()\">\n </div>\n }\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n</div>\n", styles: [":host{display:block;height:100%}.calendar-wrapper{background-color:var(--bs-body-bg);border:1px solid var(--bs-border-color);border-radius:var(--bs-border-radius);overflow:hidden;height:100%}.header-container{background-color:var(--bs-body-bg);z-index:102;box-shadow:0 4px 6px -4px #0000001a}.header-row{width:fit-content;min-width:100%}.time-gutter{width:60px;border-color:var(--bs-border-color)!important}.day-cell{border-color:var(--bs-border-color)!important;flex:1 1 0px;width:0;min-width:120px;overflow:hidden}.day-cell:last-child{border-right:none!important}.calendar-body{scroll-behavior:auto}.body-row{width:fit-content;min-width:100%}.sticky-start{position:sticky;left:0;z-index:50;background-color:var(--bs-body-bg)}.time-sidebar{width:60px;border-color:var(--bs-border-color)!important}.grid-row{border-color:var(--bs-border-color)!important;box-sizing:border-box}.grid-row:after{content:\"\";position:absolute;width:100%;border-bottom:1px dotted currentColor;opacity:.15;top:50%;left:0;pointer-events:none}.day-column{border-color:var(--bs-border-color)!important;flex:1 1 0px;width:0;min-width:120px}.day-column:last-child{border-right:none!important}.now-line{position:absolute;left:0;right:0;height:2px;background-color:var(--bs-danger);z-index:10;pointer-events:none}.now-line:before{content:\"\";position:absolute;left:-5px;top:-4px;width:10px;height:10px;background-color:var(--bs-danger);border-radius:50%}.z-0{z-index:0}.z-1{z-index:1}\n"], dependencies: [{ kind: "directive", type: CdkDropListGroup, selector: "[cdkDropListGroup]", inputs: ["cdkDropListGroupDisabled"], exportAs: ["cdkDropListGroup"] }, { kind: "directive", type: CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "component", type: CalendarEventComponent, selector: "rlb-calendar-event", inputs: ["event", "view"], outputs: ["event-click", "event-container-click"] }, { kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: CdkDragPlaceholder, selector: "ng-template[cdkDragPlaceholder]", inputs: ["data"] }, { kind: "pipe", type: DateTzPipe, name: "dtz" }, { kind: "pipe", type: DayOfWeekPipe, name: "dayOfWeek" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2988
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: CalendarWeekGridComponent, isStandalone: true, selector: "rlb-calendar-week-grid", inputs: { view: { classPropertyName: "view", publicName: "view", isSignal: true, isRequired: true, transformFunction: null }, currentDate: { classPropertyName: "currentDate", publicName: "currentDate", isSignal: true, isRequired: true, transformFunction: null }, events: { classPropertyName: "events", publicName: "events", isSignal: true, isRequired: false, transformFunction: null }, intervals: { classPropertyName: "intervals", publicName: "intervals", isSignal: true, isRequired: false, transformFunction: null }, layout: { classPropertyName: "layout", publicName: "layout", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { eventClick: "event-click", eventContainerClick: "event-container-click", eventChange: "event-change" }, viewQueries: [{ propertyName: "scrollBodyRef", first: true, predicate: ["scrollBody"], descendants: true, isSignal: true }, { propertyName: "headerRowRef", first: true, predicate: ["headerRow"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"calendar-wrapper d-flex flex-column\">\n\n <!-- HEADER WRAPPER -->\n <div #headerRow class=\"header-container overflow-hidden flex-shrink-0 border-bottom bg-body-tertiary\"\n [style.padding-right.px]=\"scrollbarWidth()\">\n\n <div class=\"header-row d-flex\" [style.min-height.rem]=\"layout().minHeaderHeight\">\n\n <div class=\"time-gutter border-end flex-shrink-0\"></div>\n\n <div class=\"days-header d-flex flex-grow-1\">\n @for (day of days(); track day.timestamp) {\n <div class=\"day-cell text-center p-2 border-end\" [class.text-primary]=\"isToday(day)\"\n [class.fw-bold]=\"isToday(day)\" [class.bg-primary]=\"isToday(day)\">\n <div class=\"small text-uppercase text-body-secondary\">{{ day | dayOfWeek: 'short' }}</div>\n <div class=\"h5 m-0\">{{ day | dtz:'DD' }}</div>\n </div>\n }\n </div>\n </div>\n </div>\n\n <!-- BODY WRAPPER -->\n <div #scrollBody class=\"calendar-body flex-grow-1 overflow-auto bg-body position-relative\"\n (scroll)=\"onBodyScroll($event)\" [style.max-height.rem]=\"layout().maxBodyHeight\">\n\n <div class=\"body-row d-flex position-relative\">\n\n <!-- SIDEBAR (Sticky Left) -->\n <div class=\"time-sidebar sticky-start flex-shrink-0 border-end\">\n @for (time of timeSlots(); track time; let i = $index) {\n <div class=\"time-slot-label small text-body-secondary d-flex align-items-start justify-content-center\"\n [style.height.px]=\"layout().rowHeight\">\n @if (i !== 0) {\n <span style=\"transform: translateY(-50%)\">\n {{ time }}\n </span>\n }\n </div>\n }\n </div>\n\n <!-- GRID AND EVENTS -->\n <div class=\"grid-layer flex-grow-1 position-relative\">\n\n <!-- LAYER 1: Grid -->\n <div class=\"background-grid position-absolute w-100 h-100 top-0 start-0 z-0\">\n @for (time of timeSlots(); track time) {\n <div class=\"grid-row border-bottom\" [style.height.px]=\"layout().rowHeight\">\n </div>\n }\n </div>\n\n <!-- Layer 1.5: Intervals (background highlights) -->\n <div class=\"intervals-container d-flex h-100 w-100 position-absolute top-0 start-0 z-0\" style=\"z-index: 0; pointer-events: none;\">\n @for (day of days(); track day.timestamp) {\n <div class=\"day-column position-relative border-end h-100\">\n @for (interval of getIntervalsForDay(day); track $index) {\n <div class=\"calendar-interval position-absolute w-100\"\n [style.top.px]=\"getIntervalTop(interval)\"\n [style.height.px]=\"getIntervalHeight(interval)\"\n [style.background-color]=\"getIntervalColor(interval)\">\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Layer 2: Events -->\n <div class=\"events-container d-flex h-100 w-100 position-relative z-1\" cdkDropListGroup>\n @for (day of days(); track day.timestamp) {\n <div class=\"day-column position-relative border-end h-100\" cdkDropList [cdkDropListSortingDisabled]=\"true\"\n [cdkDropListData]=\"day\" (cdkDropListDropped)=\"onEventDrop($event)\" (click)=\"eventClick.emit(undefined)\">\n @for (event of getEventsForDay(day); track trackByEventId($index, event)) {\n <rlb-calendar-event [view]=\"view()\" [event]=\"event\" [style.top.px]=\"calculateEventTop(event)\"\n [style.height.px]=\"calculateEventHeight(event)\" [style.left.%]=\"event.left\" [style.width.%]=\"event.width\"\n (event-click)=\"eventClick.emit($event)\" (event-container-click)=\"eventContainerClick.emit($event)\" cdkDrag\n [cdkDragData]=\"event\" [cdkDragDisabled]=\"event.isOverflowIndicator\" class=\"position-absolute\">\n <div *cdkDragPlaceholder style=\"opacity: 0\"></div>\n </rlb-calendar-event>\n }\n @if (isToday(day)) {\n <div class=\"now-line\" [style.top.px]=\"getNowTop()\">\n </div>\n }\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n</div>\n", styles: [":host{display:block;height:100%}.calendar-wrapper{background-color:var(--bs-body-bg);border:1px solid var(--bs-border-color);border-radius:var(--bs-border-radius);overflow:hidden;height:100%}.header-container{background-color:var(--bs-body-bg);z-index:102;box-shadow:0 4px 6px -4px #0000001a}.header-row{width:fit-content;min-width:100%}.time-gutter{width:60px;border-color:var(--bs-border-color)!important}.day-cell{border-color:var(--bs-border-color)!important;flex:1 1 0px;width:0;min-width:120px;overflow:hidden}.day-cell:last-child{border-right:none!important}.calendar-body{scroll-behavior:auto}.body-row{width:fit-content;min-width:100%}.sticky-start{position:sticky;left:0;z-index:50;background-color:var(--bs-body-bg)}.time-sidebar{width:60px;border-color:var(--bs-border-color)!important}.grid-row{border-color:var(--bs-border-color)!important;box-sizing:border-box}.grid-row:after{content:\"\";position:absolute;width:100%;border-bottom:1px dotted currentColor;opacity:.15;top:50%;left:0;pointer-events:none}.day-column{border-color:var(--bs-border-color)!important;flex:1 1 0px;width:0;min-width:120px}.day-column:last-child{border-right:none!important}.now-line{position:absolute;left:0;right:0;height:2px;background-color:var(--bs-danger);z-index:10;pointer-events:none}.now-line:before{content:\"\";position:absolute;left:-5px;top:-4px;width:10px;height:10px;background-color:var(--bs-danger);border-radius:50%}.calendar-interval{opacity:.1;pointer-events:none;border-radius:0}.intervals-container .day-column{flex:1 1 0px;width:0;min-width:120px}.intervals-container .day-column:last-child{border-right:none!important}.z-0{z-index:0}.z-1{z-index:1}\n"], dependencies: [{ kind: "directive", type: CdkDropListGroup, selector: "[cdkDropListGroup]", inputs: ["cdkDropListGroupDisabled"], exportAs: ["cdkDropListGroup"] }, { kind: "directive", type: CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "component", type: CalendarEventComponent, selector: "rlb-calendar-event", inputs: ["event", "view"], outputs: ["event-click", "event-container-click"] }, { kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: CdkDragPlaceholder, selector: "ng-template[cdkDragPlaceholder]", inputs: ["data"] }, { kind: "pipe", type: DateTzPipe, name: "dtz" }, { kind: "pipe", type: DayOfWeekPipe, name: "dayOfWeek" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3077
2989
  }
3078
2990
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CalendarWeekGridComponent, decorators: [{
3079
2991
  type: Component,
3080
- args: [{ selector: 'rlb-calendar-week-grid', changeDetection: ChangeDetectionStrategy.OnPush, imports: [CdkDropListGroup, CdkDropList, CalendarEventComponent, CdkDrag, CdkDragPlaceholder, DateTzPipe, DayOfWeekPipe], template: "<div class=\"calendar-wrapper d-flex flex-column\">\n\n <!-- HEADER WRAPPER -->\n <div #headerRow class=\"header-container overflow-hidden flex-shrink-0 border-bottom bg-body-tertiary\"\n [style.padding-right.px]=\"scrollbarWidth()\">\n\n <div class=\"header-row d-flex\" [style.min-height.rem]=\"layout().minHeaderHeight\">\n\n <div class=\"time-gutter border-end flex-shrink-0\"></div>\n\n <div class=\"days-header d-flex flex-grow-1\">\n @for (day of days(); track day.timestamp) {\n <div class=\"day-cell text-center p-2 border-end\" [class.text-primary]=\"isToday(day)\"\n [class.fw-bold]=\"isToday(day)\" [class.bg-primary]=\"isToday(day)\">\n <div class=\"small text-uppercase text-body-secondary\">{{ day | dayOfWeek: 'short' }}</div>\n <div class=\"h5 m-0\">{{ day | dtz:'DD' }}</div>\n </div>\n }\n </div>\n </div>\n </div>\n\n <!-- BODY WRAPPER -->\n <div #scrollBody class=\"calendar-body flex-grow-1 overflow-auto bg-body position-relative\"\n (scroll)=\"onBodyScroll($event)\" [style.max-height.rem]=\"layout().maxBodyHeight\">\n\n <div class=\"body-row d-flex position-relative\">\n\n <!-- SIDEBAR (Sticky Left) -->\n <div class=\"time-sidebar sticky-start flex-shrink-0 border-end\">\n @for (time of timeSlots(); track time; let i = $index) {\n <div class=\"time-slot-label small text-body-secondary d-flex align-items-start justify-content-center\"\n [style.height.px]=\"layout().rowHeight\">\n @if (i !== 0) {\n <span style=\"transform: translateY(-50%)\">\n {{ time }}\n </span>\n }\n </div>\n }\n </div>\n\n <!-- GRID AND EVENTS -->\n <div class=\"grid-layer flex-grow-1 position-relative\">\n\n <!-- LAYER 1: Grid -->\n <div class=\"background-grid position-absolute w-100 h-100 top-0 start-0 z-0\">\n @for (time of timeSlots(); track time) {\n <div class=\"grid-row border-bottom\" [style.height.px]=\"layout().rowHeight\">\n </div>\n }\n </div>\n\n <!-- Layer 2: Events -->\n <div class=\"events-container d-flex h-100 w-100 position-relative z-1\" cdkDropListGroup>\n @for (day of days(); track day.timestamp) {\n <div class=\"day-column position-relative border-end h-100\" cdkDropList [cdkDropListSortingDisabled]=\"true\"\n [cdkDropListData]=\"day\" (cdkDropListDropped)=\"onEventDrop($event)\" (click)=\"eventClick.emit(undefined)\">\n @for (event of getEventsForDay(day); track trackByEventId($index, event)) {\n <rlb-calendar-event [view]=\"view()\" [event]=\"event\" [style.top.px]=\"calculateEventTop(event)\"\n [style.height.px]=\"calculateEventHeight(event)\" [style.left.%]=\"event.left\" [style.width.%]=\"event.width\"\n (event-click)=\"eventClick.emit($event)\" (event-container-click)=\"eventContainerClick.emit($event)\" cdkDrag\n [cdkDragData]=\"event\" [cdkDragDisabled]=\"event.isOverflowIndicator\" class=\"position-absolute\">\n <div *cdkDragPlaceholder style=\"opacity: 0\"></div>\n </rlb-calendar-event>\n }\n @if (isToday(day)) {\n <div class=\"now-line\" [style.top.px]=\"getNowTop()\">\n </div>\n }\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n</div>\n", styles: [":host{display:block;height:100%}.calendar-wrapper{background-color:var(--bs-body-bg);border:1px solid var(--bs-border-color);border-radius:var(--bs-border-radius);overflow:hidden;height:100%}.header-container{background-color:var(--bs-body-bg);z-index:102;box-shadow:0 4px 6px -4px #0000001a}.header-row{width:fit-content;min-width:100%}.time-gutter{width:60px;border-color:var(--bs-border-color)!important}.day-cell{border-color:var(--bs-border-color)!important;flex:1 1 0px;width:0;min-width:120px;overflow:hidden}.day-cell:last-child{border-right:none!important}.calendar-body{scroll-behavior:auto}.body-row{width:fit-content;min-width:100%}.sticky-start{position:sticky;left:0;z-index:50;background-color:var(--bs-body-bg)}.time-sidebar{width:60px;border-color:var(--bs-border-color)!important}.grid-row{border-color:var(--bs-border-color)!important;box-sizing:border-box}.grid-row:after{content:\"\";position:absolute;width:100%;border-bottom:1px dotted currentColor;opacity:.15;top:50%;left:0;pointer-events:none}.day-column{border-color:var(--bs-border-color)!important;flex:1 1 0px;width:0;min-width:120px}.day-column:last-child{border-right:none!important}.now-line{position:absolute;left:0;right:0;height:2px;background-color:var(--bs-danger);z-index:10;pointer-events:none}.now-line:before{content:\"\";position:absolute;left:-5px;top:-4px;width:10px;height:10px;background-color:var(--bs-danger);border-radius:50%}.z-0{z-index:0}.z-1{z-index:1}\n"] }]
3081
- }], ctorParameters: () => [], propDecorators: { view: [{ type: i0.Input, args: [{ isSignal: true, alias: "view", required: true }] }], currentDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentDate", required: true }] }], events: [{ type: i0.Input, args: [{ isSignal: true, alias: "events", required: false }] }], layout: [{ type: i0.Input, args: [{ isSignal: true, alias: "layout", required: true }] }], eventClick: [{ type: i0.Output, args: ["event-click"] }], eventContainerClick: [{ type: i0.Output, args: ["event-container-click"] }], eventChange: [{ type: i0.Output, args: ["event-change"] }], scrollBodyRef: [{ type: i0.ViewChild, args: ['scrollBody', { isSignal: true }] }], headerRowRef: [{ type: i0.ViewChild, args: ['headerRow', { isSignal: true }] }] } });
2992
+ args: [{ selector: 'rlb-calendar-week-grid', changeDetection: ChangeDetectionStrategy.OnPush, imports: [CdkDropListGroup, CdkDropList, CalendarEventComponent, CdkDrag, CdkDragPlaceholder, DateTzPipe, DayOfWeekPipe], template: "<div class=\"calendar-wrapper d-flex flex-column\">\n\n <!-- HEADER WRAPPER -->\n <div #headerRow class=\"header-container overflow-hidden flex-shrink-0 border-bottom bg-body-tertiary\"\n [style.padding-right.px]=\"scrollbarWidth()\">\n\n <div class=\"header-row d-flex\" [style.min-height.rem]=\"layout().minHeaderHeight\">\n\n <div class=\"time-gutter border-end flex-shrink-0\"></div>\n\n <div class=\"days-header d-flex flex-grow-1\">\n @for (day of days(); track day.timestamp) {\n <div class=\"day-cell text-center p-2 border-end\" [class.text-primary]=\"isToday(day)\"\n [class.fw-bold]=\"isToday(day)\" [class.bg-primary]=\"isToday(day)\">\n <div class=\"small text-uppercase text-body-secondary\">{{ day | dayOfWeek: 'short' }}</div>\n <div class=\"h5 m-0\">{{ day | dtz:'DD' }}</div>\n </div>\n }\n </div>\n </div>\n </div>\n\n <!-- BODY WRAPPER -->\n <div #scrollBody class=\"calendar-body flex-grow-1 overflow-auto bg-body position-relative\"\n (scroll)=\"onBodyScroll($event)\" [style.max-height.rem]=\"layout().maxBodyHeight\">\n\n <div class=\"body-row d-flex position-relative\">\n\n <!-- SIDEBAR (Sticky Left) -->\n <div class=\"time-sidebar sticky-start flex-shrink-0 border-end\">\n @for (time of timeSlots(); track time; let i = $index) {\n <div class=\"time-slot-label small text-body-secondary d-flex align-items-start justify-content-center\"\n [style.height.px]=\"layout().rowHeight\">\n @if (i !== 0) {\n <span style=\"transform: translateY(-50%)\">\n {{ time }}\n </span>\n }\n </div>\n }\n </div>\n\n <!-- GRID AND EVENTS -->\n <div class=\"grid-layer flex-grow-1 position-relative\">\n\n <!-- LAYER 1: Grid -->\n <div class=\"background-grid position-absolute w-100 h-100 top-0 start-0 z-0\">\n @for (time of timeSlots(); track time) {\n <div class=\"grid-row border-bottom\" [style.height.px]=\"layout().rowHeight\">\n </div>\n }\n </div>\n\n <!-- Layer 1.5: Intervals (background highlights) -->\n <div class=\"intervals-container d-flex h-100 w-100 position-absolute top-0 start-0 z-0\" style=\"z-index: 0; pointer-events: none;\">\n @for (day of days(); track day.timestamp) {\n <div class=\"day-column position-relative border-end h-100\">\n @for (interval of getIntervalsForDay(day); track $index) {\n <div class=\"calendar-interval position-absolute w-100\"\n [style.top.px]=\"getIntervalTop(interval)\"\n [style.height.px]=\"getIntervalHeight(interval)\"\n [style.background-color]=\"getIntervalColor(interval)\">\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Layer 2: Events -->\n <div class=\"events-container d-flex h-100 w-100 position-relative z-1\" cdkDropListGroup>\n @for (day of days(); track day.timestamp) {\n <div class=\"day-column position-relative border-end h-100\" cdkDropList [cdkDropListSortingDisabled]=\"true\"\n [cdkDropListData]=\"day\" (cdkDropListDropped)=\"onEventDrop($event)\" (click)=\"eventClick.emit(undefined)\">\n @for (event of getEventsForDay(day); track trackByEventId($index, event)) {\n <rlb-calendar-event [view]=\"view()\" [event]=\"event\" [style.top.px]=\"calculateEventTop(event)\"\n [style.height.px]=\"calculateEventHeight(event)\" [style.left.%]=\"event.left\" [style.width.%]=\"event.width\"\n (event-click)=\"eventClick.emit($event)\" (event-container-click)=\"eventContainerClick.emit($event)\" cdkDrag\n [cdkDragData]=\"event\" [cdkDragDisabled]=\"event.isOverflowIndicator\" class=\"position-absolute\">\n <div *cdkDragPlaceholder style=\"opacity: 0\"></div>\n </rlb-calendar-event>\n }\n @if (isToday(day)) {\n <div class=\"now-line\" [style.top.px]=\"getNowTop()\">\n </div>\n }\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n</div>\n", styles: [":host{display:block;height:100%}.calendar-wrapper{background-color:var(--bs-body-bg);border:1px solid var(--bs-border-color);border-radius:var(--bs-border-radius);overflow:hidden;height:100%}.header-container{background-color:var(--bs-body-bg);z-index:102;box-shadow:0 4px 6px -4px #0000001a}.header-row{width:fit-content;min-width:100%}.time-gutter{width:60px;border-color:var(--bs-border-color)!important}.day-cell{border-color:var(--bs-border-color)!important;flex:1 1 0px;width:0;min-width:120px;overflow:hidden}.day-cell:last-child{border-right:none!important}.calendar-body{scroll-behavior:auto}.body-row{width:fit-content;min-width:100%}.sticky-start{position:sticky;left:0;z-index:50;background-color:var(--bs-body-bg)}.time-sidebar{width:60px;border-color:var(--bs-border-color)!important}.grid-row{border-color:var(--bs-border-color)!important;box-sizing:border-box}.grid-row:after{content:\"\";position:absolute;width:100%;border-bottom:1px dotted currentColor;opacity:.15;top:50%;left:0;pointer-events:none}.day-column{border-color:var(--bs-border-color)!important;flex:1 1 0px;width:0;min-width:120px}.day-column:last-child{border-right:none!important}.now-line{position:absolute;left:0;right:0;height:2px;background-color:var(--bs-danger);z-index:10;pointer-events:none}.now-line:before{content:\"\";position:absolute;left:-5px;top:-4px;width:10px;height:10px;background-color:var(--bs-danger);border-radius:50%}.calendar-interval{opacity:.1;pointer-events:none;border-radius:0}.intervals-container .day-column{flex:1 1 0px;width:0;min-width:120px}.intervals-container .day-column:last-child{border-right:none!important}.z-0{z-index:0}.z-1{z-index:1}\n"] }]
2993
+ }], ctorParameters: () => [], propDecorators: { view: [{ type: i0.Input, args: [{ isSignal: true, alias: "view", required: true }] }], currentDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentDate", required: true }] }], events: [{ type: i0.Input, args: [{ isSignal: true, alias: "events", required: false }] }], intervals: [{ type: i0.Input, args: [{ isSignal: true, alias: "intervals", required: false }] }], layout: [{ type: i0.Input, args: [{ isSignal: true, alias: "layout", required: true }] }], eventClick: [{ type: i0.Output, args: ["event-click"] }], eventContainerClick: [{ type: i0.Output, args: ["event-container-click"] }], eventChange: [{ type: i0.Output, args: ["event-change"] }], scrollBodyRef: [{ type: i0.ViewChild, args: ['scrollBody', { isSignal: true }] }], headerRowRef: [{ type: i0.ViewChild, args: ['headerRow', { isSignal: true }] }] } });
3082
2994
 
3083
2995
  const MAX_EVENTS_PER_CELL = 3;
3084
2996
  const DAYS_IN_GRID = 42; // 6 weeks * 7 days
@@ -3087,6 +2999,7 @@ class CalendarMonthGridComponent {
3087
2999
  this.view = input.required(...(ngDevMode ? [{ debugName: "view" }] : /* istanbul ignore next */ []));
3088
3000
  this.currentDate = input.required(...(ngDevMode ? [{ debugName: "currentDate" }] : /* istanbul ignore next */ []));
3089
3001
  this.events = input([], ...(ngDevMode ? [{ debugName: "events" }] : /* istanbul ignore next */ []));
3002
+ this.intervals = input([], ...(ngDevMode ? [{ debugName: "intervals" }] : /* istanbul ignore next */ []));
3090
3003
  this.layout = input.required(...(ngDevMode ? [{ debugName: "layout" }] : /* istanbul ignore next */ []));
3091
3004
  this.eventClick = output({ alias: 'event-click' });
3092
3005
  this.eventContainerClick = output({ alias: 'event-container-click' });
@@ -3132,6 +3045,15 @@ class CalendarMonthGridComponent {
3132
3045
  isToday(date) {
3133
3046
  return isToday(date);
3134
3047
  }
3048
+ hasInterval(date) {
3049
+ const dayOfWeek = new DateTz(date).dayOfWeek;
3050
+ return this.intervals().some(interval => interval.dayWeek === dayOfWeek);
3051
+ }
3052
+ getIntervalColor(date) {
3053
+ const dayOfWeek = new DateTz(date).dayOfWeek;
3054
+ const interval = this.intervals().find(i => i.dayWeek === dayOfWeek);
3055
+ return interval ? `var(--bs-${interval.color || 'success'})` : '';
3056
+ }
3135
3057
  isCurrentMonth(date) {
3136
3058
  return date.month === this.currentDate().month;
3137
3059
  }
@@ -3333,18 +3255,19 @@ class CalendarMonthGridComponent {
3333
3255
  this.eventChange.emit(updatedEvent);
3334
3256
  }
3335
3257
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CalendarMonthGridComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3336
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: CalendarMonthGridComponent, isStandalone: true, selector: "rlb-calendar-month-grid", inputs: { view: { classPropertyName: "view", publicName: "view", isSignal: true, isRequired: true, transformFunction: null }, currentDate: { classPropertyName: "currentDate", publicName: "currentDate", isSignal: true, isRequired: true, transformFunction: null }, events: { classPropertyName: "events", publicName: "events", isSignal: true, isRequired: false, transformFunction: null }, layout: { classPropertyName: "layout", publicName: "layout", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { eventClick: "event-click", eventContainerClick: "event-container-click", eventChange: "event-change" }, viewQueries: [{ propertyName: "scrollBodyRef", first: true, predicate: ["scrollBody"], descendants: true, isSignal: true }, { propertyName: "headerRowRef", first: true, predicate: ["headerRow"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"d-flex flex-column w-100 bg-body user-select-none month-view-root\">\n <!-- 1. Header Row (Fixed) -->\n <div #headerRow class=\"d-flex flex-shrink-0 border-bottom bg-body-tertiary overflow-hidden\"\n [style.min-height.rem]=\"layout().minHeaderHeight\" [style.padding-right.px]=\"scrollbarWidth()\">\n @for (day of weekDaysHeader(); track day) {\n <div class=\"flex-fill text-center py-2 border-end fw-bold text-secondary text-uppercase w-0 my-auto h6\">\n {{ day | dayOfWeek:'short' }}\n </div>\n }\n </div>\n\n <!-- SCROLL CONTAINER -->\n <div #scrollBody class=\"calendar-scroller flex-grow-1 overflow-auto bg-body position-relative\"\n [style.max-height.rem]=\"layout().maxBodyHeight\" (scroll)=\"onBodyScroll($event)\">\n\n <!-- 2. Grid Body (Scrollable) -->\n <div class=\"d-flex flex-column flex-grow-1 border-start min-height-0\">\n\n <div class=\"d-flex flex-column\" cdkDropListGroup>\n @for (week of weeks(); track week) {\n <div class=\"d-flex border-bottom min-h-row\" style=\"flex: 1 0 auto;\" [style.min-height.px]=\"layout().rowHeight\">\n @for (slot of week; track slot) {\n <div class=\"flex-fill border-end p-1 d-flex flex-column position-relative\" style=\"width: 0\"\n [class.bg-light]=\"!isCurrentMonth(slot.date)\" cdkDropList [cdkDropListData]=\"slot.date\"\n (cdkDropListDropped)=\"onEventDrop($event)\" (click)=\"eventClick.emit(undefined)\">\n <!-- Date Number -->\n <div class=\"d-flex justify-content-center mb-1\">\n <span class=\"day-number d-flex align-items-center justify-content-center\"\n [class.today]=\"isToday(slot.date)\">\n {{ slot.date | dtz:'DD' }}\n </span>\n </div>\n <!-- Events Stack -->\n <div class=\"d-flex flex-column gap-1 w-100\">\n @for (event of slot.events; track trackByEvent($index, event)) {\n <!-- Spacer -->\n @if (event.isSpacer) {\n <div class=\"event-spacer\"></div>\n }\n <!-- Event -->\n @if (!event.isSpacer) {\n <rlb-calendar-event [event]=\"event\" class=\"w-100\" cdkDrag [cdkDragData]=\"event\"\n (event-click)=\"eventClick.emit($event)\" [view]=\"view()\">\n <!-- Drag Preview (Optional but nice) -->\n <div *cdkDragPlaceholder style=\"opacity: 0\"></div>\n <ng-template cdkDragPreview matchSize class=\"rlb-calendar-drag-preview\">\n <rlb-calendar-event [event]=\"event\" [view]=\"view()\" style=\"box-sizing: border-box;\">\n </rlb-calendar-event>\n </ng-template>\n </rlb-calendar-event>\n }\n }\n </div>\n <!-- Overflow (+N more) -->\n @if (slot.hasOverflow) {\n <div class=\"mt-1 small text-secondary text-center cursor-pointer p-1 rounded hover-bg\"\n (click)=\"$event.stopPropagation(); eventContainerClick.emit(slot.overflowEvents)\">\n +{{ slot.overflowCount }} more\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n </div>\n\n </div>\n</div>\n", styles: [":host{display:block;height:100%}.min-height-0{min-height:0!important}.border-end:last-child{border-right:0!important}.day-number{width:24px;height:24px;border-radius:50%;font-size:.85rem;font-weight:500;transition:background-color .2s}.day-number.today{background-color:var(--bs-primary);color:#fff}.event-spacer{height:20px;width:100%;pointer-events:none}.hover-bg:hover{background-color:var(--bs-secondary-bg-subtle)}.cursor-pointer{cursor:pointer}.cdk-drag-preview{box-shadow:0 .5rem 1rem #0000004d;border-radius:var(--bs-border-radius-sm)}\n"], dependencies: [{ kind: "directive", type: CdkDropListGroup, selector: "[cdkDropListGroup]", inputs: ["cdkDropListGroupDisabled"], exportAs: ["cdkDropListGroup"] }, { kind: "directive", type: CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "component", type: CalendarEventComponent, selector: "rlb-calendar-event", inputs: ["event", "view"], outputs: ["event-click", "event-container-click"] }, { kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: CdkDragPlaceholder, selector: "ng-template[cdkDragPlaceholder]", inputs: ["data"] }, { kind: "directive", type: CdkDragPreview, selector: "ng-template[cdkDragPreview]", inputs: ["data", "matchSize"] }, { kind: "pipe", type: DateTzPipe, name: "dtz" }, { kind: "pipe", type: DayOfWeekPipe, name: "dayOfWeek" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3258
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: CalendarMonthGridComponent, isStandalone: true, selector: "rlb-calendar-month-grid", inputs: { view: { classPropertyName: "view", publicName: "view", isSignal: true, isRequired: true, transformFunction: null }, currentDate: { classPropertyName: "currentDate", publicName: "currentDate", isSignal: true, isRequired: true, transformFunction: null }, events: { classPropertyName: "events", publicName: "events", isSignal: true, isRequired: false, transformFunction: null }, intervals: { classPropertyName: "intervals", publicName: "intervals", isSignal: true, isRequired: false, transformFunction: null }, layout: { classPropertyName: "layout", publicName: "layout", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { eventClick: "event-click", eventContainerClick: "event-container-click", eventChange: "event-change" }, viewQueries: [{ propertyName: "scrollBodyRef", first: true, predicate: ["scrollBody"], descendants: true, isSignal: true }, { propertyName: "headerRowRef", first: true, predicate: ["headerRow"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"d-flex flex-column w-100 bg-body user-select-none month-view-root\">\n <!-- 1. Header Row (Fixed) -->\n <div #headerRow class=\"d-flex flex-shrink-0 border-bottom bg-body-tertiary overflow-hidden\"\n [style.min-height.rem]=\"layout().minHeaderHeight\" [style.padding-right.px]=\"scrollbarWidth()\">\n @for (day of weekDaysHeader(); track day) {\n <div class=\"flex-fill text-center py-2 border-end fw-bold text-secondary text-uppercase w-0 my-auto h6\">\n {{ day | dayOfWeek:'short' }}\n </div>\n }\n </div>\n\n <!-- SCROLL CONTAINER -->\n <div #scrollBody class=\"calendar-scroller flex-grow-1 overflow-auto bg-body position-relative\"\n [style.max-height.rem]=\"layout().maxBodyHeight\" (scroll)=\"onBodyScroll($event)\">\n\n <!-- 2. Grid Body (Scrollable) -->\n <div class=\"d-flex flex-column flex-grow-1 border-start min-height-0\">\n\n <div class=\"d-flex flex-column\" cdkDropListGroup>\n @for (week of weeks(); track week) {\n <div class=\"d-flex border-bottom min-h-row\" style=\"flex: 1 0 auto;\" [style.min-height.px]=\"layout().rowHeight\">\n @for (slot of week; track slot) {\n <div class=\"flex-fill border-end p-1 d-flex flex-column position-relative\" style=\"width: 0\"\n [class.bg-light]=\"!isCurrentMonth(slot.date)\"\n [class.has-interval]=\"hasInterval(slot.date)\"\n [style.--interval-color]=\"getIntervalColor(slot.date)\"\n cdkDropList [cdkDropListData]=\"slot.date\"\n (cdkDropListDropped)=\"onEventDrop($event)\" (click)=\"eventClick.emit(undefined)\">\n <!-- Date Number -->\n <div class=\"d-flex justify-content-center mb-1\">\n <span class=\"day-number d-flex align-items-center justify-content-center\"\n [class.today]=\"isToday(slot.date)\">\n {{ slot.date | dtz:'DD' }}\n </span>\n </div>\n <!-- Events Stack -->\n <div class=\"d-flex flex-column gap-1 w-100\">\n @for (event of slot.events; track trackByEvent($index, event)) {\n <!-- Spacer -->\n @if (event.isSpacer) {\n <div class=\"event-spacer\"></div>\n }\n <!-- Event -->\n @if (!event.isSpacer) {\n <rlb-calendar-event [event]=\"event\" class=\"w-100\" cdkDrag [cdkDragData]=\"event\"\n (event-click)=\"eventClick.emit($event)\" [view]=\"view()\">\n <!-- Drag Preview (Optional but nice) -->\n <div *cdkDragPlaceholder style=\"opacity: 0\"></div>\n <ng-template cdkDragPreview matchSize class=\"rlb-calendar-drag-preview\">\n <rlb-calendar-event [event]=\"event\" [view]=\"view()\" style=\"box-sizing: border-box;\">\n </rlb-calendar-event>\n </ng-template>\n </rlb-calendar-event>\n }\n }\n </div>\n <!-- Overflow (+N more) -->\n @if (slot.hasOverflow) {\n <div class=\"mt-1 small text-secondary text-center cursor-pointer p-1 rounded hover-bg\"\n (click)=\"$event.stopPropagation(); eventContainerClick.emit(slot.overflowEvents)\">\n +{{ slot.overflowCount }} more\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n </div>\n\n </div>\n</div>\n", styles: [":host{display:block;height:100%}.min-height-0{min-height:0!important}.border-end:last-child{border-right:0!important}.day-number{width:24px;height:24px;border-radius:50%;font-size:.85rem;font-weight:500;transition:background-color .2s}.day-number.today{background-color:var(--bs-primary);color:#fff}.event-spacer{height:20px;width:100%;pointer-events:none}.hover-bg:hover{background-color:var(--bs-secondary-bg-subtle)}.cursor-pointer{cursor:pointer}.has-interval{background-image:linear-gradient(to right,color-mix(in srgb,var(--interval-color) 12%,transparent) 0%,transparent 100%);border-left:3px solid var(--interval-color)!important}.cdk-drag-preview{box-shadow:0 .5rem 1rem #0000004d;border-radius:var(--bs-border-radius-sm)}\n"], dependencies: [{ kind: "directive", type: CdkDropListGroup, selector: "[cdkDropListGroup]", inputs: ["cdkDropListGroupDisabled"], exportAs: ["cdkDropListGroup"] }, { kind: "directive", type: CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "component", type: CalendarEventComponent, selector: "rlb-calendar-event", inputs: ["event", "view"], outputs: ["event-click", "event-container-click"] }, { kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: CdkDragPlaceholder, selector: "ng-template[cdkDragPlaceholder]", inputs: ["data"] }, { kind: "directive", type: CdkDragPreview, selector: "ng-template[cdkDragPreview]", inputs: ["data", "matchSize"] }, { kind: "pipe", type: DateTzPipe, name: "dtz" }, { kind: "pipe", type: DayOfWeekPipe, name: "dayOfWeek" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3337
3259
  }
3338
3260
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CalendarMonthGridComponent, decorators: [{
3339
3261
  type: Component,
3340
- args: [{ selector: 'rlb-calendar-month-grid', changeDetection: ChangeDetectionStrategy.OnPush, imports: [CdkDropListGroup, CdkDropList, CalendarEventComponent, CdkDrag, CdkDragPlaceholder, CdkDragPreview, DateTzPipe, DayOfWeekPipe], template: "<div class=\"d-flex flex-column w-100 bg-body user-select-none month-view-root\">\n <!-- 1. Header Row (Fixed) -->\n <div #headerRow class=\"d-flex flex-shrink-0 border-bottom bg-body-tertiary overflow-hidden\"\n [style.min-height.rem]=\"layout().minHeaderHeight\" [style.padding-right.px]=\"scrollbarWidth()\">\n @for (day of weekDaysHeader(); track day) {\n <div class=\"flex-fill text-center py-2 border-end fw-bold text-secondary text-uppercase w-0 my-auto h6\">\n {{ day | dayOfWeek:'short' }}\n </div>\n }\n </div>\n\n <!-- SCROLL CONTAINER -->\n <div #scrollBody class=\"calendar-scroller flex-grow-1 overflow-auto bg-body position-relative\"\n [style.max-height.rem]=\"layout().maxBodyHeight\" (scroll)=\"onBodyScroll($event)\">\n\n <!-- 2. Grid Body (Scrollable) -->\n <div class=\"d-flex flex-column flex-grow-1 border-start min-height-0\">\n\n <div class=\"d-flex flex-column\" cdkDropListGroup>\n @for (week of weeks(); track week) {\n <div class=\"d-flex border-bottom min-h-row\" style=\"flex: 1 0 auto;\" [style.min-height.px]=\"layout().rowHeight\">\n @for (slot of week; track slot) {\n <div class=\"flex-fill border-end p-1 d-flex flex-column position-relative\" style=\"width: 0\"\n [class.bg-light]=\"!isCurrentMonth(slot.date)\" cdkDropList [cdkDropListData]=\"slot.date\"\n (cdkDropListDropped)=\"onEventDrop($event)\" (click)=\"eventClick.emit(undefined)\">\n <!-- Date Number -->\n <div class=\"d-flex justify-content-center mb-1\">\n <span class=\"day-number d-flex align-items-center justify-content-center\"\n [class.today]=\"isToday(slot.date)\">\n {{ slot.date | dtz:'DD' }}\n </span>\n </div>\n <!-- Events Stack -->\n <div class=\"d-flex flex-column gap-1 w-100\">\n @for (event of slot.events; track trackByEvent($index, event)) {\n <!-- Spacer -->\n @if (event.isSpacer) {\n <div class=\"event-spacer\"></div>\n }\n <!-- Event -->\n @if (!event.isSpacer) {\n <rlb-calendar-event [event]=\"event\" class=\"w-100\" cdkDrag [cdkDragData]=\"event\"\n (event-click)=\"eventClick.emit($event)\" [view]=\"view()\">\n <!-- Drag Preview (Optional but nice) -->\n <div *cdkDragPlaceholder style=\"opacity: 0\"></div>\n <ng-template cdkDragPreview matchSize class=\"rlb-calendar-drag-preview\">\n <rlb-calendar-event [event]=\"event\" [view]=\"view()\" style=\"box-sizing: border-box;\">\n </rlb-calendar-event>\n </ng-template>\n </rlb-calendar-event>\n }\n }\n </div>\n <!-- Overflow (+N more) -->\n @if (slot.hasOverflow) {\n <div class=\"mt-1 small text-secondary text-center cursor-pointer p-1 rounded hover-bg\"\n (click)=\"$event.stopPropagation(); eventContainerClick.emit(slot.overflowEvents)\">\n +{{ slot.overflowCount }} more\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n </div>\n\n </div>\n</div>\n", styles: [":host{display:block;height:100%}.min-height-0{min-height:0!important}.border-end:last-child{border-right:0!important}.day-number{width:24px;height:24px;border-radius:50%;font-size:.85rem;font-weight:500;transition:background-color .2s}.day-number.today{background-color:var(--bs-primary);color:#fff}.event-spacer{height:20px;width:100%;pointer-events:none}.hover-bg:hover{background-color:var(--bs-secondary-bg-subtle)}.cursor-pointer{cursor:pointer}.cdk-drag-preview{box-shadow:0 .5rem 1rem #0000004d;border-radius:var(--bs-border-radius-sm)}\n"] }]
3341
- }], ctorParameters: () => [], propDecorators: { view: [{ type: i0.Input, args: [{ isSignal: true, alias: "view", required: true }] }], currentDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentDate", required: true }] }], events: [{ type: i0.Input, args: [{ isSignal: true, alias: "events", required: false }] }], layout: [{ type: i0.Input, args: [{ isSignal: true, alias: "layout", required: true }] }], eventClick: [{ type: i0.Output, args: ["event-click"] }], eventContainerClick: [{ type: i0.Output, args: ["event-container-click"] }], eventChange: [{ type: i0.Output, args: ["event-change"] }], scrollBodyRef: [{ type: i0.ViewChild, args: ['scrollBody', { isSignal: true }] }], headerRowRef: [{ type: i0.ViewChild, args: ['headerRow', { isSignal: true }] }] } });
3262
+ args: [{ selector: 'rlb-calendar-month-grid', changeDetection: ChangeDetectionStrategy.OnPush, imports: [CdkDropListGroup, CdkDropList, CalendarEventComponent, CdkDrag, CdkDragPlaceholder, CdkDragPreview, DateTzPipe, DayOfWeekPipe], template: "<div class=\"d-flex flex-column w-100 bg-body user-select-none month-view-root\">\n <!-- 1. Header Row (Fixed) -->\n <div #headerRow class=\"d-flex flex-shrink-0 border-bottom bg-body-tertiary overflow-hidden\"\n [style.min-height.rem]=\"layout().minHeaderHeight\" [style.padding-right.px]=\"scrollbarWidth()\">\n @for (day of weekDaysHeader(); track day) {\n <div class=\"flex-fill text-center py-2 border-end fw-bold text-secondary text-uppercase w-0 my-auto h6\">\n {{ day | dayOfWeek:'short' }}\n </div>\n }\n </div>\n\n <!-- SCROLL CONTAINER -->\n <div #scrollBody class=\"calendar-scroller flex-grow-1 overflow-auto bg-body position-relative\"\n [style.max-height.rem]=\"layout().maxBodyHeight\" (scroll)=\"onBodyScroll($event)\">\n\n <!-- 2. Grid Body (Scrollable) -->\n <div class=\"d-flex flex-column flex-grow-1 border-start min-height-0\">\n\n <div class=\"d-flex flex-column\" cdkDropListGroup>\n @for (week of weeks(); track week) {\n <div class=\"d-flex border-bottom min-h-row\" style=\"flex: 1 0 auto;\" [style.min-height.px]=\"layout().rowHeight\">\n @for (slot of week; track slot) {\n <div class=\"flex-fill border-end p-1 d-flex flex-column position-relative\" style=\"width: 0\"\n [class.bg-light]=\"!isCurrentMonth(slot.date)\"\n [class.has-interval]=\"hasInterval(slot.date)\"\n [style.--interval-color]=\"getIntervalColor(slot.date)\"\n cdkDropList [cdkDropListData]=\"slot.date\"\n (cdkDropListDropped)=\"onEventDrop($event)\" (click)=\"eventClick.emit(undefined)\">\n <!-- Date Number -->\n <div class=\"d-flex justify-content-center mb-1\">\n <span class=\"day-number d-flex align-items-center justify-content-center\"\n [class.today]=\"isToday(slot.date)\">\n {{ slot.date | dtz:'DD' }}\n </span>\n </div>\n <!-- Events Stack -->\n <div class=\"d-flex flex-column gap-1 w-100\">\n @for (event of slot.events; track trackByEvent($index, event)) {\n <!-- Spacer -->\n @if (event.isSpacer) {\n <div class=\"event-spacer\"></div>\n }\n <!-- Event -->\n @if (!event.isSpacer) {\n <rlb-calendar-event [event]=\"event\" class=\"w-100\" cdkDrag [cdkDragData]=\"event\"\n (event-click)=\"eventClick.emit($event)\" [view]=\"view()\">\n <!-- Drag Preview (Optional but nice) -->\n <div *cdkDragPlaceholder style=\"opacity: 0\"></div>\n <ng-template cdkDragPreview matchSize class=\"rlb-calendar-drag-preview\">\n <rlb-calendar-event [event]=\"event\" [view]=\"view()\" style=\"box-sizing: border-box;\">\n </rlb-calendar-event>\n </ng-template>\n </rlb-calendar-event>\n }\n }\n </div>\n <!-- Overflow (+N more) -->\n @if (slot.hasOverflow) {\n <div class=\"mt-1 small text-secondary text-center cursor-pointer p-1 rounded hover-bg\"\n (click)=\"$event.stopPropagation(); eventContainerClick.emit(slot.overflowEvents)\">\n +{{ slot.overflowCount }} more\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n </div>\n\n </div>\n</div>\n", styles: [":host{display:block;height:100%}.min-height-0{min-height:0!important}.border-end:last-child{border-right:0!important}.day-number{width:24px;height:24px;border-radius:50%;font-size:.85rem;font-weight:500;transition:background-color .2s}.day-number.today{background-color:var(--bs-primary);color:#fff}.event-spacer{height:20px;width:100%;pointer-events:none}.hover-bg:hover{background-color:var(--bs-secondary-bg-subtle)}.cursor-pointer{cursor:pointer}.has-interval{background-image:linear-gradient(to right,color-mix(in srgb,var(--interval-color) 12%,transparent) 0%,transparent 100%);border-left:3px solid var(--interval-color)!important}.cdk-drag-preview{box-shadow:0 .5rem 1rem #0000004d;border-radius:var(--bs-border-radius-sm)}\n"] }]
3263
+ }], ctorParameters: () => [], propDecorators: { view: [{ type: i0.Input, args: [{ isSignal: true, alias: "view", required: true }] }], currentDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentDate", required: true }] }], events: [{ type: i0.Input, args: [{ isSignal: true, alias: "events", required: false }] }], intervals: [{ type: i0.Input, args: [{ isSignal: true, alias: "intervals", required: false }] }], layout: [{ type: i0.Input, args: [{ isSignal: true, alias: "layout", required: true }] }], eventClick: [{ type: i0.Output, args: ["event-click"] }], eventContainerClick: [{ type: i0.Output, args: ["event-container-click"] }], eventChange: [{ type: i0.Output, args: ["event-change"] }], scrollBodyRef: [{ type: i0.ViewChild, args: ['scrollBody', { isSignal: true }] }], headerRowRef: [{ type: i0.ViewChild, args: ['headerRow', { isSignal: true }] }] } });
3342
3264
 
3343
3265
  class CalendarDayGridComponent {
3344
3266
  constructor() {
3345
3267
  this.view = input.required(...(ngDevMode ? [{ debugName: "view" }] : /* istanbul ignore next */ []));
3346
3268
  this.currentDate = input.required(...(ngDevMode ? [{ debugName: "currentDate" }] : /* istanbul ignore next */ []));
3347
3269
  this.events = input([], ...(ngDevMode ? [{ debugName: "events" }] : /* istanbul ignore next */ []));
3270
+ this.intervals = input([], ...(ngDevMode ? [{ debugName: "intervals" }] : /* istanbul ignore next */ []));
3348
3271
  this.layout = input.required(...(ngDevMode ? [{ debugName: "layout" }] : /* istanbul ignore next */ []));
3349
3272
  this.eventClick = output({ alias: 'event-click' });
3350
3273
  this.eventContainerClick = output({ alias: 'event-container-click' });
@@ -3440,6 +3363,22 @@ class CalendarDayGridComponent {
3440
3363
  clearInterval(this.nowInterval);
3441
3364
  }
3442
3365
  }
3366
+ getIntervalsForDay() {
3367
+ const dayOfWeek = new DateTz$1(this.day()).dayOfWeek;
3368
+ return this.intervals().filter(interval => interval.dayWeek === dayOfWeek);
3369
+ }
3370
+ getIntervalTop(interval) {
3371
+ const seconds = interval.hourStart ?? 0;
3372
+ return (seconds / 3600) * this.layout().rowHeight;
3373
+ }
3374
+ getIntervalHeight(interval) {
3375
+ const start = interval.hourStart ?? 0;
3376
+ const stop = interval.hourStop ?? 86400;
3377
+ return ((stop - start) / 3600) * this.layout().rowHeight;
3378
+ }
3379
+ getIntervalColor(interval) {
3380
+ return `var(--bs-${interval.color || 'success'})`;
3381
+ }
3443
3382
  buildDayGrid(currentDate) {
3444
3383
  this.day.set(new DateTz$1(currentDate.timestamp, 'UTC'));
3445
3384
  this.startNowTimer();
@@ -3577,18 +3516,19 @@ class CalendarDayGridComponent {
3577
3516
  });
3578
3517
  }
3579
3518
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CalendarDayGridComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3580
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: CalendarDayGridComponent, isStandalone: true, selector: "rlb-calendar-day-grid", inputs: { view: { classPropertyName: "view", publicName: "view", isSignal: true, isRequired: true, transformFunction: null }, currentDate: { classPropertyName: "currentDate", publicName: "currentDate", isSignal: true, isRequired: true, transformFunction: null }, events: { classPropertyName: "events", publicName: "events", isSignal: true, isRequired: false, transformFunction: null }, layout: { classPropertyName: "layout", publicName: "layout", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { eventClick: "event-click", eventContainerClick: "event-container-click", eventChange: "event-change" }, viewQueries: [{ propertyName: "scrollBodyRef", first: true, predicate: ["scrollBody"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (day()) {\n<div class=\"calendar-wrapper d-flex flex-column\">\n <!-- HEADER WRAPPER -->\n <!-- For day view, we just show the date at top? Or maybe just keep it simple with body since main header has date -->\n <!-- Mimicking structure of Week View but single column -->\n <div class=\"header-container overflow-hidden flex-shrink-0 border-bottom bg-body-tertiary\">\n <div class=\"header-row d-flex\" [style.min-height.rem]=\"layout().minHeaderHeight\">\n <div class=\"time-gutter border-end flex-shrink-0\"></div>\n <div class=\"day-cell p-2 flex-grow-1\" [class.text-primary]=\"isToday(day())\" [class.fw-bold]=\"isToday(day())\"\n [class.bg-primary]=\"isToday(day())\">\n <div class=\"small text-uppercase text-body-secondary h-100 d-flex align-items-center justify-content-center\">{{\n day() | dayOfWeek: 'long' }}</div>\n </div>\n </div>\n </div>\n <!-- BODY WRAPPER -->\n <div #scrollBody class=\"calendar-body flex-grow-1 overflow-auto bg-body position-relative\"\n [style.max-height.rem]=\"layout().maxBodyHeight\">\n <div class=\"body-row d-flex position-relative\">\n <!-- SIDEBAR (Sticky Left) -->\n <div class=\"time-sidebar sticky-start flex-shrink-0 border-end\">\n @for (time of timeSlots(); track time; let i = $index) {\n <div class=\"time-slot-label small text-body-secondary d-flex align-items-start justify-content-center\"\n [style.height.px]=\"layout().rowHeight\">\n @if (i !== 0) {\n <span style=\"transform: translateY(-50%)\">\n {{ time }}\n </span>\n }\n </div>\n }\n </div>\n <!-- GRID AND EVENTS -->\n <div class=\"grid-layer flex-grow-1 position-relative\">\n <!-- LAYER 1: Grid -->\n <div class=\"background-grid position-absolute w-100 h-100 top-0 start-0 z-0\">\n @for (time of timeSlots(); track time) {\n <div class=\"grid-row border-bottom\" [style.height.px]=\"layout().rowHeight\">\n </div>\n }\n </div>\n <!-- Layer 2: Events -->\n <div class=\"events-container d-flex h-100 w-100 position-relative z-1\" cdkDropListGroup>\n <div class=\"day-column position-relative h-100 w-100\" cdkDropList [cdkDropListSortingDisabled]=\"true\"\n [cdkDropListData]=\"day()\" (cdkDropListDropped)=\"onEventDrop($event)\" (click)=\"eventClick.emit(undefined)\">\n @for (event of processedEvents(); track trackByEventId($index, event)) {\n <rlb-calendar-event [view]=\"view()\" [event]=\"event\" [style.top.px]=\"calculateEventTop(event)\"\n [style.height.px]=\"calculateEventHeight(event)\" [style.left.%]=\"event.left\" [style.width.%]=\"event.width\"\n (event-click)=\"eventClick.emit($event)\" (event-container-click)=\"eventContainerClick.emit($event)\" cdkDrag\n [cdkDragData]=\"event\" class=\"position-absolute\">\n <div *cdkDragPlaceholder style=\"opacity: 0\"></div>\n </rlb-calendar-event>\n }\n @if (isToday(day())) {\n <div class=\"now-line\" [style.top.px]=\"getNowTop()\">\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n</div>\n}\n", styles: [":host{display:block;height:100%}.calendar-wrapper{background-color:var(--bs-body-bg);border:1px solid var(--bs-border-color);border-radius:var(--bs-border-radius);overflow:hidden;height:100%}.header-container{background-color:var(--bs-body-bg);z-index:102}.header-row{width:100%}.time-gutter{width:60px;border-color:var(--bs-border-color)!important}.day-cell{border-color:var(--bs-border-color)!important}.calendar-body{scroll-behavior:auto}.body-row{width:100%}.sticky-start{position:sticky;left:0;z-index:50;background-color:var(--bs-body-bg)}.time-sidebar{width:60px;border-color:var(--bs-border-color)!important}.grid-row{border-color:var(--bs-border-color)!important;box-sizing:border-box}.grid-row:after{content:\"\";position:absolute;width:100%;border-bottom:1px dotted currentColor;opacity:.15;top:50%;left:0;pointer-events:none}.now-line{position:absolute;left:0;right:0;height:2px;background-color:var(--bs-danger);z-index:10;pointer-events:none}.now-line:before{content:\"\";position:absolute;left:-5px;top:-4px;width:10px;height:10px;background-color:var(--bs-danger);border-radius:50%}.z-0{z-index:0}.z-1{z-index:1}\n"], dependencies: [{ kind: "directive", type: CdkDropListGroup, selector: "[cdkDropListGroup]", inputs: ["cdkDropListGroupDisabled"], exportAs: ["cdkDropListGroup"] }, { kind: "directive", type: CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "component", type: CalendarEventComponent, selector: "rlb-calendar-event", inputs: ["event", "view"], outputs: ["event-click", "event-container-click"] }, { kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: CdkDragPlaceholder, selector: "ng-template[cdkDragPlaceholder]", inputs: ["data"] }, { kind: "pipe", type: DayOfWeekPipe, name: "dayOfWeek" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3519
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: CalendarDayGridComponent, isStandalone: true, selector: "rlb-calendar-day-grid", inputs: { view: { classPropertyName: "view", publicName: "view", isSignal: true, isRequired: true, transformFunction: null }, currentDate: { classPropertyName: "currentDate", publicName: "currentDate", isSignal: true, isRequired: true, transformFunction: null }, events: { classPropertyName: "events", publicName: "events", isSignal: true, isRequired: false, transformFunction: null }, intervals: { classPropertyName: "intervals", publicName: "intervals", isSignal: true, isRequired: false, transformFunction: null }, layout: { classPropertyName: "layout", publicName: "layout", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { eventClick: "event-click", eventContainerClick: "event-container-click", eventChange: "event-change" }, viewQueries: [{ propertyName: "scrollBodyRef", first: true, predicate: ["scrollBody"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (day()) {\n<div class=\"calendar-wrapper d-flex flex-column\">\n <!-- HEADER WRAPPER -->\n <!-- For day view, we just show the date at top? Or maybe just keep it simple with body since main header has date -->\n <!-- Mimicking structure of Week View but single column -->\n <div class=\"header-container overflow-hidden flex-shrink-0 border-bottom bg-body-tertiary\">\n <div class=\"header-row d-flex\" [style.min-height.rem]=\"layout().minHeaderHeight\">\n <div class=\"time-gutter border-end flex-shrink-0\"></div>\n <div class=\"day-cell p-2 flex-grow-1\" [class.text-primary]=\"isToday(day())\" [class.fw-bold]=\"isToday(day())\"\n [class.bg-primary]=\"isToday(day())\">\n <div class=\"small text-uppercase text-body-secondary h-100 d-flex align-items-center justify-content-center\">{{\n day() | dayOfWeek: 'long' }}</div>\n </div>\n </div>\n </div>\n <!-- BODY WRAPPER -->\n <div #scrollBody class=\"calendar-body flex-grow-1 overflow-auto bg-body position-relative\"\n [style.max-height.rem]=\"layout().maxBodyHeight\">\n <div class=\"body-row d-flex position-relative\">\n <!-- SIDEBAR (Sticky Left) -->\n <div class=\"time-sidebar sticky-start flex-shrink-0 border-end\">\n @for (time of timeSlots(); track time; let i = $index) {\n <div class=\"time-slot-label small text-body-secondary d-flex align-items-start justify-content-center\"\n [style.height.px]=\"layout().rowHeight\">\n @if (i !== 0) {\n <span style=\"transform: translateY(-50%)\">\n {{ time }}\n </span>\n }\n </div>\n }\n </div>\n <!-- GRID AND EVENTS -->\n <div class=\"grid-layer flex-grow-1 position-relative\">\n <!-- LAYER 1: Grid -->\n <div class=\"background-grid position-absolute w-100 h-100 top-0 start-0 z-0\">\n @for (time of timeSlots(); track time) {\n <div class=\"grid-row border-bottom\" [style.height.px]=\"layout().rowHeight\">\n </div>\n }\n </div>\n <!-- Layer 1.5: Intervals (background highlights) -->\n <div class=\"intervals-container position-absolute w-100 h-100 top-0 start-0\" style=\"z-index: 0; pointer-events: none;\">\n @for (interval of getIntervalsForDay(); track $index) {\n <div class=\"calendar-interval position-absolute w-100\"\n [style.top.px]=\"getIntervalTop(interval)\"\n [style.height.px]=\"getIntervalHeight(interval)\"\n [style.background-color]=\"getIntervalColor(interval)\">\n </div>\n }\n </div>\n\n <!-- Layer 2: Events -->\n <div class=\"events-container d-flex h-100 w-100 position-relative z-1\" cdkDropListGroup>\n <div class=\"day-column position-relative h-100 w-100\" cdkDropList [cdkDropListSortingDisabled]=\"true\"\n [cdkDropListData]=\"day()\" (cdkDropListDropped)=\"onEventDrop($event)\" (click)=\"eventClick.emit(undefined)\">\n @for (event of processedEvents(); track trackByEventId($index, event)) {\n <rlb-calendar-event [view]=\"view()\" [event]=\"event\" [style.top.px]=\"calculateEventTop(event)\"\n [style.height.px]=\"calculateEventHeight(event)\" [style.left.%]=\"event.left\" [style.width.%]=\"event.width\"\n (event-click)=\"eventClick.emit($event)\" (event-container-click)=\"eventContainerClick.emit($event)\" cdkDrag\n [cdkDragData]=\"event\" class=\"position-absolute\">\n <div *cdkDragPlaceholder style=\"opacity: 0\"></div>\n </rlb-calendar-event>\n }\n @if (isToday(day())) {\n <div class=\"now-line\" [style.top.px]=\"getNowTop()\">\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n</div>\n}\n", styles: [":host{display:block;height:100%}.calendar-wrapper{background-color:var(--bs-body-bg);border:1px solid var(--bs-border-color);border-radius:var(--bs-border-radius);overflow:hidden;height:100%}.header-container{background-color:var(--bs-body-bg);z-index:102}.header-row{width:100%}.time-gutter{width:60px;border-color:var(--bs-border-color)!important}.day-cell{border-color:var(--bs-border-color)!important}.calendar-body{scroll-behavior:auto}.body-row{width:100%}.sticky-start{position:sticky;left:0;z-index:50;background-color:var(--bs-body-bg)}.time-sidebar{width:60px;border-color:var(--bs-border-color)!important}.grid-row{border-color:var(--bs-border-color)!important;box-sizing:border-box}.grid-row:after{content:\"\";position:absolute;width:100%;border-bottom:1px dotted currentColor;opacity:.15;top:50%;left:0;pointer-events:none}.now-line{position:absolute;left:0;right:0;height:2px;background-color:var(--bs-danger);z-index:10;pointer-events:none}.now-line:before{content:\"\";position:absolute;left:-5px;top:-4px;width:10px;height:10px;background-color:var(--bs-danger);border-radius:50%}.calendar-interval{opacity:.1;pointer-events:none;border-radius:0}.z-0{z-index:0}.z-1{z-index:1}\n"], dependencies: [{ kind: "directive", type: CdkDropListGroup, selector: "[cdkDropListGroup]", inputs: ["cdkDropListGroupDisabled"], exportAs: ["cdkDropListGroup"] }, { kind: "directive", type: CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "component", type: CalendarEventComponent, selector: "rlb-calendar-event", inputs: ["event", "view"], outputs: ["event-click", "event-container-click"] }, { kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: CdkDragPlaceholder, selector: "ng-template[cdkDragPlaceholder]", inputs: ["data"] }, { kind: "pipe", type: DayOfWeekPipe, name: "dayOfWeek" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3581
3520
  }
3582
3521
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CalendarDayGridComponent, decorators: [{
3583
3522
  type: Component,
3584
- args: [{ selector: 'rlb-calendar-day-grid', changeDetection: ChangeDetectionStrategy.OnPush, imports: [CdkDropListGroup, CdkDropList, CalendarEventComponent, CdkDrag, CdkDragPlaceholder, DayOfWeekPipe], template: "@if (day()) {\n<div class=\"calendar-wrapper d-flex flex-column\">\n <!-- HEADER WRAPPER -->\n <!-- For day view, we just show the date at top? Or maybe just keep it simple with body since main header has date -->\n <!-- Mimicking structure of Week View but single column -->\n <div class=\"header-container overflow-hidden flex-shrink-0 border-bottom bg-body-tertiary\">\n <div class=\"header-row d-flex\" [style.min-height.rem]=\"layout().minHeaderHeight\">\n <div class=\"time-gutter border-end flex-shrink-0\"></div>\n <div class=\"day-cell p-2 flex-grow-1\" [class.text-primary]=\"isToday(day())\" [class.fw-bold]=\"isToday(day())\"\n [class.bg-primary]=\"isToday(day())\">\n <div class=\"small text-uppercase text-body-secondary h-100 d-flex align-items-center justify-content-center\">{{\n day() | dayOfWeek: 'long' }}</div>\n </div>\n </div>\n </div>\n <!-- BODY WRAPPER -->\n <div #scrollBody class=\"calendar-body flex-grow-1 overflow-auto bg-body position-relative\"\n [style.max-height.rem]=\"layout().maxBodyHeight\">\n <div class=\"body-row d-flex position-relative\">\n <!-- SIDEBAR (Sticky Left) -->\n <div class=\"time-sidebar sticky-start flex-shrink-0 border-end\">\n @for (time of timeSlots(); track time; let i = $index) {\n <div class=\"time-slot-label small text-body-secondary d-flex align-items-start justify-content-center\"\n [style.height.px]=\"layout().rowHeight\">\n @if (i !== 0) {\n <span style=\"transform: translateY(-50%)\">\n {{ time }}\n </span>\n }\n </div>\n }\n </div>\n <!-- GRID AND EVENTS -->\n <div class=\"grid-layer flex-grow-1 position-relative\">\n <!-- LAYER 1: Grid -->\n <div class=\"background-grid position-absolute w-100 h-100 top-0 start-0 z-0\">\n @for (time of timeSlots(); track time) {\n <div class=\"grid-row border-bottom\" [style.height.px]=\"layout().rowHeight\">\n </div>\n }\n </div>\n <!-- Layer 2: Events -->\n <div class=\"events-container d-flex h-100 w-100 position-relative z-1\" cdkDropListGroup>\n <div class=\"day-column position-relative h-100 w-100\" cdkDropList [cdkDropListSortingDisabled]=\"true\"\n [cdkDropListData]=\"day()\" (cdkDropListDropped)=\"onEventDrop($event)\" (click)=\"eventClick.emit(undefined)\">\n @for (event of processedEvents(); track trackByEventId($index, event)) {\n <rlb-calendar-event [view]=\"view()\" [event]=\"event\" [style.top.px]=\"calculateEventTop(event)\"\n [style.height.px]=\"calculateEventHeight(event)\" [style.left.%]=\"event.left\" [style.width.%]=\"event.width\"\n (event-click)=\"eventClick.emit($event)\" (event-container-click)=\"eventContainerClick.emit($event)\" cdkDrag\n [cdkDragData]=\"event\" class=\"position-absolute\">\n <div *cdkDragPlaceholder style=\"opacity: 0\"></div>\n </rlb-calendar-event>\n }\n @if (isToday(day())) {\n <div class=\"now-line\" [style.top.px]=\"getNowTop()\">\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n</div>\n}\n", styles: [":host{display:block;height:100%}.calendar-wrapper{background-color:var(--bs-body-bg);border:1px solid var(--bs-border-color);border-radius:var(--bs-border-radius);overflow:hidden;height:100%}.header-container{background-color:var(--bs-body-bg);z-index:102}.header-row{width:100%}.time-gutter{width:60px;border-color:var(--bs-border-color)!important}.day-cell{border-color:var(--bs-border-color)!important}.calendar-body{scroll-behavior:auto}.body-row{width:100%}.sticky-start{position:sticky;left:0;z-index:50;background-color:var(--bs-body-bg)}.time-sidebar{width:60px;border-color:var(--bs-border-color)!important}.grid-row{border-color:var(--bs-border-color)!important;box-sizing:border-box}.grid-row:after{content:\"\";position:absolute;width:100%;border-bottom:1px dotted currentColor;opacity:.15;top:50%;left:0;pointer-events:none}.now-line{position:absolute;left:0;right:0;height:2px;background-color:var(--bs-danger);z-index:10;pointer-events:none}.now-line:before{content:\"\";position:absolute;left:-5px;top:-4px;width:10px;height:10px;background-color:var(--bs-danger);border-radius:50%}.z-0{z-index:0}.z-1{z-index:1}\n"] }]
3585
- }], ctorParameters: () => [], propDecorators: { view: [{ type: i0.Input, args: [{ isSignal: true, alias: "view", required: true }] }], currentDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentDate", required: true }] }], events: [{ type: i0.Input, args: [{ isSignal: true, alias: "events", required: false }] }], layout: [{ type: i0.Input, args: [{ isSignal: true, alias: "layout", required: true }] }], eventClick: [{ type: i0.Output, args: ["event-click"] }], eventContainerClick: [{ type: i0.Output, args: ["event-container-click"] }], eventChange: [{ type: i0.Output, args: ["event-change"] }], scrollBodyRef: [{ type: i0.ViewChild, args: ['scrollBody', { isSignal: true }] }] } });
3523
+ args: [{ selector: 'rlb-calendar-day-grid', changeDetection: ChangeDetectionStrategy.OnPush, imports: [CdkDropListGroup, CdkDropList, CalendarEventComponent, CdkDrag, CdkDragPlaceholder, DayOfWeekPipe], template: "@if (day()) {\n<div class=\"calendar-wrapper d-flex flex-column\">\n <!-- HEADER WRAPPER -->\n <!-- For day view, we just show the date at top? Or maybe just keep it simple with body since main header has date -->\n <!-- Mimicking structure of Week View but single column -->\n <div class=\"header-container overflow-hidden flex-shrink-0 border-bottom bg-body-tertiary\">\n <div class=\"header-row d-flex\" [style.min-height.rem]=\"layout().minHeaderHeight\">\n <div class=\"time-gutter border-end flex-shrink-0\"></div>\n <div class=\"day-cell p-2 flex-grow-1\" [class.text-primary]=\"isToday(day())\" [class.fw-bold]=\"isToday(day())\"\n [class.bg-primary]=\"isToday(day())\">\n <div class=\"small text-uppercase text-body-secondary h-100 d-flex align-items-center justify-content-center\">{{\n day() | dayOfWeek: 'long' }}</div>\n </div>\n </div>\n </div>\n <!-- BODY WRAPPER -->\n <div #scrollBody class=\"calendar-body flex-grow-1 overflow-auto bg-body position-relative\"\n [style.max-height.rem]=\"layout().maxBodyHeight\">\n <div class=\"body-row d-flex position-relative\">\n <!-- SIDEBAR (Sticky Left) -->\n <div class=\"time-sidebar sticky-start flex-shrink-0 border-end\">\n @for (time of timeSlots(); track time; let i = $index) {\n <div class=\"time-slot-label small text-body-secondary d-flex align-items-start justify-content-center\"\n [style.height.px]=\"layout().rowHeight\">\n @if (i !== 0) {\n <span style=\"transform: translateY(-50%)\">\n {{ time }}\n </span>\n }\n </div>\n }\n </div>\n <!-- GRID AND EVENTS -->\n <div class=\"grid-layer flex-grow-1 position-relative\">\n <!-- LAYER 1: Grid -->\n <div class=\"background-grid position-absolute w-100 h-100 top-0 start-0 z-0\">\n @for (time of timeSlots(); track time) {\n <div class=\"grid-row border-bottom\" [style.height.px]=\"layout().rowHeight\">\n </div>\n }\n </div>\n <!-- Layer 1.5: Intervals (background highlights) -->\n <div class=\"intervals-container position-absolute w-100 h-100 top-0 start-0\" style=\"z-index: 0; pointer-events: none;\">\n @for (interval of getIntervalsForDay(); track $index) {\n <div class=\"calendar-interval position-absolute w-100\"\n [style.top.px]=\"getIntervalTop(interval)\"\n [style.height.px]=\"getIntervalHeight(interval)\"\n [style.background-color]=\"getIntervalColor(interval)\">\n </div>\n }\n </div>\n\n <!-- Layer 2: Events -->\n <div class=\"events-container d-flex h-100 w-100 position-relative z-1\" cdkDropListGroup>\n <div class=\"day-column position-relative h-100 w-100\" cdkDropList [cdkDropListSortingDisabled]=\"true\"\n [cdkDropListData]=\"day()\" (cdkDropListDropped)=\"onEventDrop($event)\" (click)=\"eventClick.emit(undefined)\">\n @for (event of processedEvents(); track trackByEventId($index, event)) {\n <rlb-calendar-event [view]=\"view()\" [event]=\"event\" [style.top.px]=\"calculateEventTop(event)\"\n [style.height.px]=\"calculateEventHeight(event)\" [style.left.%]=\"event.left\" [style.width.%]=\"event.width\"\n (event-click)=\"eventClick.emit($event)\" (event-container-click)=\"eventContainerClick.emit($event)\" cdkDrag\n [cdkDragData]=\"event\" class=\"position-absolute\">\n <div *cdkDragPlaceholder style=\"opacity: 0\"></div>\n </rlb-calendar-event>\n }\n @if (isToday(day())) {\n <div class=\"now-line\" [style.top.px]=\"getNowTop()\">\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n</div>\n}\n", styles: [":host{display:block;height:100%}.calendar-wrapper{background-color:var(--bs-body-bg);border:1px solid var(--bs-border-color);border-radius:var(--bs-border-radius);overflow:hidden;height:100%}.header-container{background-color:var(--bs-body-bg);z-index:102}.header-row{width:100%}.time-gutter{width:60px;border-color:var(--bs-border-color)!important}.day-cell{border-color:var(--bs-border-color)!important}.calendar-body{scroll-behavior:auto}.body-row{width:100%}.sticky-start{position:sticky;left:0;z-index:50;background-color:var(--bs-body-bg)}.time-sidebar{width:60px;border-color:var(--bs-border-color)!important}.grid-row{border-color:var(--bs-border-color)!important;box-sizing:border-box}.grid-row:after{content:\"\";position:absolute;width:100%;border-bottom:1px dotted currentColor;opacity:.15;top:50%;left:0;pointer-events:none}.now-line{position:absolute;left:0;right:0;height:2px;background-color:var(--bs-danger);z-index:10;pointer-events:none}.now-line:before{content:\"\";position:absolute;left:-5px;top:-4px;width:10px;height:10px;background-color:var(--bs-danger);border-radius:50%}.calendar-interval{opacity:.1;pointer-events:none;border-radius:0}.z-0{z-index:0}.z-1{z-index:1}\n"] }]
3524
+ }], ctorParameters: () => [], propDecorators: { view: [{ type: i0.Input, args: [{ isSignal: true, alias: "view", required: true }] }], currentDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentDate", required: true }] }], events: [{ type: i0.Input, args: [{ isSignal: true, alias: "events", required: false }] }], intervals: [{ type: i0.Input, args: [{ isSignal: true, alias: "intervals", required: false }] }], layout: [{ type: i0.Input, args: [{ isSignal: true, alias: "layout", required: true }] }], eventClick: [{ type: i0.Output, args: ["event-click"] }], eventContainerClick: [{ type: i0.Output, args: ["event-container-click"] }], eventChange: [{ type: i0.Output, args: ["event-change"] }], scrollBodyRef: [{ type: i0.ViewChild, args: ['scrollBody', { isSignal: true }] }] } });
3586
3525
 
3587
3526
  class CalendarGrid {
3588
3527
  constructor() {
3589
3528
  this.view = input.required(...(ngDevMode ? [{ debugName: "view" }] : /* istanbul ignore next */ []));
3590
3529
  this.currentDate = input.required(...(ngDevMode ? [{ debugName: "currentDate" }] : /* istanbul ignore next */ []));
3591
3530
  this.events = input([], ...(ngDevMode ? [{ debugName: "events" }] : /* istanbul ignore next */ []));
3531
+ this.intervals = input([], ...(ngDevMode ? [{ debugName: "intervals" }] : /* istanbul ignore next */ []));
3592
3532
  this.layout = input.required(...(ngDevMode ? [{ debugName: "layout" }] : /* istanbul ignore next */ []));
3593
3533
  this.eventClick = output({ alias: 'event-click' });
3594
3534
  this.eventContainerClick = output({ alias: 'event-container-click' });
@@ -3596,7 +3536,7 @@ class CalendarGrid {
3596
3536
  }
3597
3537
  ngOnDestroy() { }
3598
3538
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CalendarGrid, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3599
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: CalendarGrid, isStandalone: true, selector: "rlb-calendar-grid", inputs: { view: { classPropertyName: "view", publicName: "view", isSignal: true, isRequired: true, transformFunction: null }, currentDate: { classPropertyName: "currentDate", publicName: "currentDate", isSignal: true, isRequired: true, transformFunction: null }, events: { classPropertyName: "events", publicName: "events", isSignal: true, isRequired: false, transformFunction: null }, layout: { classPropertyName: "layout", publicName: "layout", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { eventClick: "event-click", eventContainerClick: "event-container-click", eventChange: "event-change" }, ngImport: i0, template: "@switch (view()) {\n@case ('week') {\n<rlb-calendar-week-grid [view]=\"view()\" [currentDate]=\"currentDate()\" [events]=\"events()\" [layout]=\"layout()\"\n (event-click)=\"eventClick.emit($event)\" (event-container-click)=\"eventContainerClick.emit($event)\"\n (event-change)=\"eventChange.emit($event)\" />\n}\n@case ('month') {\n<rlb-calendar-month-grid [view]=\"view()\" [currentDate]=\"currentDate()\" [events]=\"events()\" [layout]=\"layout()\"\n (event-click)=\"eventClick.emit($event)\" (event-container-click)=\"eventContainerClick.emit($event)\"\n (event-change)=\"eventChange.emit($event)\" />\n}\n@case ('day') {\n<rlb-calendar-day-grid [view]=\"view()\" [currentDate]=\"currentDate()\" [events]=\"events()\" [layout]=\"layout()\"\n (event-click)=\"eventClick.emit($event)\" (event-container-click)=\"eventContainerClick.emit($event)\"\n (event-change)=\"eventChange.emit($event)\" />\n}\n@default {\nnot implemented yet\n}\n}\n", styles: [""], dependencies: [{ kind: "component", type: CalendarWeekGridComponent, selector: "rlb-calendar-week-grid", inputs: ["view", "currentDate", "events", "layout"], outputs: ["event-click", "event-container-click", "event-change"] }, { kind: "component", type: CalendarMonthGridComponent, selector: "rlb-calendar-month-grid", inputs: ["view", "currentDate", "events", "layout"], outputs: ["event-click", "event-container-click", "event-change"] }, { kind: "component", type: CalendarDayGridComponent, selector: "rlb-calendar-day-grid", inputs: ["view", "currentDate", "events", "layout"], outputs: ["event-click", "event-container-click", "event-change"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3539
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: CalendarGrid, isStandalone: true, selector: "rlb-calendar-grid", inputs: { view: { classPropertyName: "view", publicName: "view", isSignal: true, isRequired: true, transformFunction: null }, currentDate: { classPropertyName: "currentDate", publicName: "currentDate", isSignal: true, isRequired: true, transformFunction: null }, events: { classPropertyName: "events", publicName: "events", isSignal: true, isRequired: false, transformFunction: null }, intervals: { classPropertyName: "intervals", publicName: "intervals", isSignal: true, isRequired: false, transformFunction: null }, layout: { classPropertyName: "layout", publicName: "layout", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { eventClick: "event-click", eventContainerClick: "event-container-click", eventChange: "event-change" }, ngImport: i0, template: "@switch (view()) {\n@case ('week') {\n<rlb-calendar-week-grid [view]=\"view()\" [currentDate]=\"currentDate()\" [events]=\"events()\" [intervals]=\"intervals()\" [layout]=\"layout()\"\n (event-click)=\"eventClick.emit($event)\" (event-container-click)=\"eventContainerClick.emit($event)\"\n (event-change)=\"eventChange.emit($event)\" />\n}\n@case ('month') {\n<rlb-calendar-month-grid [view]=\"view()\" [currentDate]=\"currentDate()\" [events]=\"events()\" [intervals]=\"intervals()\" [layout]=\"layout()\"\n (event-click)=\"eventClick.emit($event)\" (event-container-click)=\"eventContainerClick.emit($event)\"\n (event-change)=\"eventChange.emit($event)\" />\n}\n@case ('day') {\n<rlb-calendar-day-grid [view]=\"view()\" [currentDate]=\"currentDate()\" [events]=\"events()\" [intervals]=\"intervals()\" [layout]=\"layout()\"\n (event-click)=\"eventClick.emit($event)\" (event-container-click)=\"eventContainerClick.emit($event)\"\n (event-change)=\"eventChange.emit($event)\" />\n}\n@default {\nnot implemented yet\n}\n}\n", styles: [""], dependencies: [{ kind: "component", type: CalendarWeekGridComponent, selector: "rlb-calendar-week-grid", inputs: ["view", "currentDate", "events", "intervals", "layout"], outputs: ["event-click", "event-container-click", "event-change"] }, { kind: "component", type: CalendarMonthGridComponent, selector: "rlb-calendar-month-grid", inputs: ["view", "currentDate", "events", "intervals", "layout"], outputs: ["event-click", "event-container-click", "event-change"] }, { kind: "component", type: CalendarDayGridComponent, selector: "rlb-calendar-day-grid", inputs: ["view", "currentDate", "events", "intervals", "layout"], outputs: ["event-click", "event-container-click", "event-change"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3600
3540
  }
3601
3541
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CalendarGrid, decorators: [{
3602
3542
  type: Component,
@@ -3604,8 +3544,113 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
3604
3544
  CalendarWeekGridComponent,
3605
3545
  CalendarMonthGridComponent,
3606
3546
  CalendarDayGridComponent,
3607
- ], template: "@switch (view()) {\n@case ('week') {\n<rlb-calendar-week-grid [view]=\"view()\" [currentDate]=\"currentDate()\" [events]=\"events()\" [layout]=\"layout()\"\n (event-click)=\"eventClick.emit($event)\" (event-container-click)=\"eventContainerClick.emit($event)\"\n (event-change)=\"eventChange.emit($event)\" />\n}\n@case ('month') {\n<rlb-calendar-month-grid [view]=\"view()\" [currentDate]=\"currentDate()\" [events]=\"events()\" [layout]=\"layout()\"\n (event-click)=\"eventClick.emit($event)\" (event-container-click)=\"eventContainerClick.emit($event)\"\n (event-change)=\"eventChange.emit($event)\" />\n}\n@case ('day') {\n<rlb-calendar-day-grid [view]=\"view()\" [currentDate]=\"currentDate()\" [events]=\"events()\" [layout]=\"layout()\"\n (event-click)=\"eventClick.emit($event)\" (event-container-click)=\"eventContainerClick.emit($event)\"\n (event-change)=\"eventChange.emit($event)\" />\n}\n@default {\nnot implemented yet\n}\n}\n" }]
3608
- }], ctorParameters: () => [], propDecorators: { view: [{ type: i0.Input, args: [{ isSignal: true, alias: "view", required: true }] }], currentDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentDate", required: true }] }], events: [{ type: i0.Input, args: [{ isSignal: true, alias: "events", required: false }] }], layout: [{ type: i0.Input, args: [{ isSignal: true, alias: "layout", required: true }] }], eventClick: [{ type: i0.Output, args: ["event-click"] }], eventContainerClick: [{ type: i0.Output, args: ["event-container-click"] }], eventChange: [{ type: i0.Output, args: ["event-change"] }] } });
3547
+ ], template: "@switch (view()) {\n@case ('week') {\n<rlb-calendar-week-grid [view]=\"view()\" [currentDate]=\"currentDate()\" [events]=\"events()\" [intervals]=\"intervals()\" [layout]=\"layout()\"\n (event-click)=\"eventClick.emit($event)\" (event-container-click)=\"eventContainerClick.emit($event)\"\n (event-change)=\"eventChange.emit($event)\" />\n}\n@case ('month') {\n<rlb-calendar-month-grid [view]=\"view()\" [currentDate]=\"currentDate()\" [events]=\"events()\" [intervals]=\"intervals()\" [layout]=\"layout()\"\n (event-click)=\"eventClick.emit($event)\" (event-container-click)=\"eventContainerClick.emit($event)\"\n (event-change)=\"eventChange.emit($event)\" />\n}\n@case ('day') {\n<rlb-calendar-day-grid [view]=\"view()\" [currentDate]=\"currentDate()\" [events]=\"events()\" [intervals]=\"intervals()\" [layout]=\"layout()\"\n (event-click)=\"eventClick.emit($event)\" (event-container-click)=\"eventContainerClick.emit($event)\"\n (event-change)=\"eventChange.emit($event)\" />\n}\n@default {\nnot implemented yet\n}\n}\n" }]
3548
+ }], ctorParameters: () => [], propDecorators: { view: [{ type: i0.Input, args: [{ isSignal: true, alias: "view", required: true }] }], currentDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentDate", required: true }] }], events: [{ type: i0.Input, args: [{ isSignal: true, alias: "events", required: false }] }], intervals: [{ type: i0.Input, args: [{ isSignal: true, alias: "intervals", required: false }] }], layout: [{ type: i0.Input, args: [{ isSignal: true, alias: "layout", required: true }] }], eventClick: [{ type: i0.Output, args: ["event-click"] }], eventContainerClick: [{ type: i0.Output, args: ["event-container-click"] }], eventChange: [{ type: i0.Output, args: ["event-change"] }] } });
3549
+
3550
+ class MonthFormatterPipe {
3551
+ constructor() {
3552
+ this.months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
3553
+ }
3554
+ transform(value) {
3555
+ if (!value)
3556
+ return '';
3557
+ const parts = value.trim().split(' ');
3558
+ if (parts.length < 2)
3559
+ return value;
3560
+ const day = parts[0];
3561
+ const monthIndex = parseInt(parts[1], 10) - 1;
3562
+ if (isNaN(monthIndex) || monthIndex < 0 || monthIndex > 11) {
3563
+ return value;
3564
+ }
3565
+ const month = this.months[monthIndex];
3566
+ const rest = parts.slice(2).join(' ');
3567
+ return `${day} ${month}${rest ? ' ' + rest : ''}`;
3568
+ }
3569
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: MonthFormatterPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
3570
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.14", ngImport: i0, type: MonthFormatterPipe, isStandalone: true, name: "monthFormatter" }); }
3571
+ }
3572
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: MonthFormatterPipe, decorators: [{
3573
+ type: Pipe,
3574
+ args: [{ name: 'monthFormatter' }]
3575
+ }] });
3576
+
3577
+ class CalendarHeaderComponent {
3578
+ constructor() {
3579
+ this.view = input('month', ...(ngDevMode ? [{ debugName: "view" }] : /* istanbul ignore next */ []));
3580
+ this.currentDate = input.required(...(ngDevMode ? [{ debugName: "currentDate" }] : /* istanbul ignore next */ []));
3581
+ this.dateChange = output();
3582
+ this.viewChange = output();
3583
+ }
3584
+ next() {
3585
+ switch (this.view()) {
3586
+ case 'week':
3587
+ const nextWeek = addDays(this.currentDate(), 7);
3588
+ this.dateChange.emit(new DateTz(nextWeek));
3589
+ break;
3590
+ case 'month':
3591
+ const nextMonth = new DateTz(this.currentDate()).set(1, 'day').add(1, 'month');
3592
+ this.dateChange.emit(new DateTz(nextMonth));
3593
+ break;
3594
+ case 'day':
3595
+ const nextDay = addDays(this.currentDate(), 1);
3596
+ this.dateChange.emit(new DateTz(nextDay));
3597
+ break;
3598
+ default:
3599
+ break;
3600
+ }
3601
+ }
3602
+ prev() {
3603
+ switch (this.view()) {
3604
+ case 'week':
3605
+ const pastWeek = addDays(this.currentDate(), -7);
3606
+ this.dateChange.emit(new DateTz(pastWeek));
3607
+ break;
3608
+ case 'month':
3609
+ const pastMonth = new DateTz(this.currentDate()).set(1, 'day').add(-1, 'month');
3610
+ this.dateChange.emit(new DateTz(pastMonth));
3611
+ break;
3612
+ case 'day':
3613
+ const nextDay = addDays(this.currentDate(), -1);
3614
+ this.dateChange.emit(new DateTz(nextDay));
3615
+ break;
3616
+ default:
3617
+ break;
3618
+ }
3619
+ }
3620
+ today() {
3621
+ switch (this.view()) {
3622
+ case 'week':
3623
+ default:
3624
+ const today = getToday();
3625
+ this.dateChange.emit(today);
3626
+ break;
3627
+ }
3628
+ }
3629
+ setView(view) {
3630
+ this.viewChange.emit(view);
3631
+ }
3632
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CalendarHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3633
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.14", type: CalendarHeaderComponent, isStandalone: true, selector: "rlb-calendar-header", inputs: { view: { classPropertyName: "view", publicName: "view", isSignal: true, isRequired: false, transformFunction: null }, currentDate: { classPropertyName: "currentDate", publicName: "currentDate", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { dateChange: "dateChange", viewChange: "viewChange" }, ngImport: i0, template: "<div class=\"d-flex justify-content-between align-items-center mb-3\">\n\t<div class=\"d-flex gap-1\">\n\t\t<button rlb-button outline (click)=\"prev()\">\n\t\t\t<i class=\"bi bi-chevron-left\"></i>\n\t\t</button>\n\t\t<button rlb-button outline (click)=\"today()\">Today</button>\n\t\t<button rlb-button outline (click)=\"next()\">\n\t\t\t<i class=\"bi-chevron-right\"></i>\n\t\t</button>\n\t</div>\n\n\t<h5 class=\"mb-0\">{{ currentDate() | dtz:'DD MM yyyy' | monthFormatter }} {{ currentDate().timezone }}</h5>\n\n\t<rlb-dropdown>\n\t\t<button rlb-button outline rlb-dropdown>{{ view() | titlecase }}</button>\n\t\t<ul rlb-dropdown-menu [placement]=\"'right'\">\n\t\t\t<li rlb-dropdown-item (click)=\"setView('day')\">Day</li>\n\t\t\t<li rlb-dropdown-item (click)=\"setView('week')\">Week</li>\n\t\t\t<li rlb-dropdown-item (click)=\"setView('month')\">Month</li>\n\t\t</ul>\n\t</rlb-dropdown>\n</div>", styles: [""], dependencies: [{ kind: "component", type: ButtonComponent, selector: "button[rlb-button], a[rlb-button]", inputs: ["color", "size", "disabled", "outline", "isLink"] }, { kind: "component", type: DropdownComponent, selector: "rlb-dropdown", inputs: ["direction"] }, { kind: "directive", type: DropdownDirective, selector: "a[rlb-dropdown], button[rlb-dropdown], span[rlb-badge][rlb-dropdown]", inputs: ["offset", "auto-close"], outputs: ["status-changed"] }, { kind: "component", type: DropdownContainerComponent, selector: "ul[rlb-dropdown-menu], rlb-dropdown-container", inputs: ["placement", "placement-sm", "placement-md", "placement-lg", "placement-xl", "placement-xxl"] }, { kind: "component", type: DropdownMenuItemComponent, selector: "li[rlb-dropdown-item]", inputs: ["active", "disabled", "header", "divider", "link", "text-wrap"] }, { kind: "pipe", type: TitleCasePipe, name: "titlecase" }, { kind: "pipe", type: DateTzPipe, name: "dtz" }, { kind: "pipe", type: MonthFormatterPipe, name: "monthFormatter" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3634
+ }
3635
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CalendarHeaderComponent, decorators: [{
3636
+ type: Component,
3637
+ args: [{ selector: 'rlb-calendar-header', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
3638
+ ButtonComponent,
3639
+ DropdownComponent,
3640
+ DropdownDirective,
3641
+ DropdownContainerComponent,
3642
+ DropdownMenuItemComponent,
3643
+ TitleCasePipe,
3644
+ DateTzPipe,
3645
+ MonthFormatterPipe,
3646
+ ], template: "<div class=\"d-flex justify-content-between align-items-center mb-3\">\n\t<div class=\"d-flex gap-1\">\n\t\t<button rlb-button outline (click)=\"prev()\">\n\t\t\t<i class=\"bi bi-chevron-left\"></i>\n\t\t</button>\n\t\t<button rlb-button outline (click)=\"today()\">Today</button>\n\t\t<button rlb-button outline (click)=\"next()\">\n\t\t\t<i class=\"bi-chevron-right\"></i>\n\t\t</button>\n\t</div>\n\n\t<h5 class=\"mb-0\">{{ currentDate() | dtz:'DD MM yyyy' | monthFormatter }} {{ currentDate().timezone }}</h5>\n\n\t<rlb-dropdown>\n\t\t<button rlb-button outline rlb-dropdown>{{ view() | titlecase }}</button>\n\t\t<ul rlb-dropdown-menu [placement]=\"'right'\">\n\t\t\t<li rlb-dropdown-item (click)=\"setView('day')\">Day</li>\n\t\t\t<li rlb-dropdown-item (click)=\"setView('week')\">Week</li>\n\t\t\t<li rlb-dropdown-item (click)=\"setView('month')\">Month</li>\n\t\t</ul>\n\t</rlb-dropdown>\n</div>" }]
3647
+ }], propDecorators: { view: [{ type: i0.Input, args: [{ isSignal: true, alias: "view", required: false }] }], currentDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentDate", required: true }] }], dateChange: [{ type: i0.Output, args: ["dateChange"] }], viewChange: [{ type: i0.Output, args: ["viewChange"] }] } });
3648
+
3649
+ const DEFAULT_CALENDAR_LAYOUT = {
3650
+ rowHeight: 110,
3651
+ maxBodyHeight: 30,
3652
+ minHeaderHeight: 3.5
3653
+ };
3609
3654
 
3610
3655
  class ToastRegistryOptions {
3611
3656
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: ToastRegistryOptions, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
@@ -3848,6 +3893,8 @@ class CalendarComponent {
3848
3893
  this.loading = input(false, { ...(ngDevMode ? { debugName: "loading" } : /* istanbul ignore next */ {}), alias: 'loading', transform: booleanAttribute });
3849
3894
  this.showToolbar = input(true, { ...(ngDevMode ? { debugName: "showToolbar" } : /* istanbul ignore next */ {}), alias: 'show-toolbar',
3850
3895
  transform: booleanAttribute });
3896
+ this.intervals = input([], { ...(ngDevMode ? { debugName: "intervals" } : /* istanbul ignore next */ {}), alias: 'intervals' });
3897
+ this.manageEvents = input(true, { ...(ngDevMode ? { debugName: "manageEvents" } : /* istanbul ignore next */ {}), alias: 'manage-events', transform: booleanAttribute });
3851
3898
  this.layout = input({}, { ...(ngDevMode ? { debugName: "layout" } : /* istanbul ignore next */ {}), alias: 'layout' });
3852
3899
  this.mergedLayout = computed(() => ({
3853
3900
  ...DEFAULT_CALENDAR_LAYOUT,
@@ -3856,6 +3903,7 @@ class CalendarComponent {
3856
3903
  this.dateChange = output({ alias: 'date-change' });
3857
3904
  this.viewChange = output({ alias: 'view-change' });
3858
3905
  this.eventClick = output({ alias: 'event-click' });
3906
+ this.containerEventClick = output({ alias: 'container-event-click' });
3859
3907
  }
3860
3908
  // DnD event
3861
3909
  onEventChange(eventToEdit) {
@@ -3875,6 +3923,11 @@ class CalendarComponent {
3875
3923
  }
3876
3924
  }
3877
3925
  onEventContainerClick(events) {
3926
+ if (events) {
3927
+ this.containerEventClick.emit(events);
3928
+ }
3929
+ if (!this.manageEvents())
3930
+ return;
3878
3931
  this.modals
3879
3932
  .openModal('rlb-calendar-overlow-events-container', {
3880
3933
  title: 'Overflow events',
@@ -3942,6 +3995,8 @@ class CalendarComponent {
3942
3995
  if (eventToEdit) {
3943
3996
  this.eventClick.emit(eventToEdit);
3944
3997
  }
3998
+ if (!this.manageEvents())
3999
+ return;
3945
4000
  this.openEditEventDialog(eventToEdit)
3946
4001
  .pipe(switchMap(modalResult => {
3947
4002
  const newEvent = modalResult.result;
@@ -4018,7 +4073,7 @@ class CalendarComponent {
4018
4073
  .pipe(take(1));
4019
4074
  }
4020
4075
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CalendarComponent, deps: [{ token: ModalService }, { token: UniqueIdService }, { token: ToastService }], target: i0.ɵɵFactoryTarget.Component }); }
4021
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: CalendarComponent, isStandalone: true, selector: "rlb-calendar", inputs: { view: { classPropertyName: "view", publicName: "view", isSignal: true, isRequired: false, transformFunction: null }, events: { classPropertyName: "events", publicName: "events", isSignal: true, isRequired: false, transformFunction: null }, currentDate: { classPropertyName: "currentDate", publicName: "current-date", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, showToolbar: { classPropertyName: "showToolbar", publicName: "show-toolbar", isSignal: true, isRequired: false, transformFunction: null }, layout: { classPropertyName: "layout", publicName: "layout", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { view: "viewChange", events: "eventsChange", currentDate: "current-dateChange", dateChange: "date-change", viewChange: "view-change", eventClick: "event-click" }, ngImport: i0, template: "<div class=\"rlb-calendar\">\n\n @if (showToolbar()) {\n <rlb-calendar-header\n [view]=\"view()\"\n [currentDate]=\"currentDate()\"\n (viewChange)=\"setView($event)\"\n (dateChange)=\"setDate($event)\"\n >\n </rlb-calendar-header>\n }\n\n @if (loading()) {\n <rlb-progress [infinite]=\"true\" [animated]=\"true\" [height]=\"3\" [showValue]=\"false\">\n </rlb-progress>\n } @else {\n <rlb-calendar-grid\n [events]=\"events()\"\n [view]=\"view()\"\n [currentDate]=\"currentDate()\"\n [layout]=\"mergedLayout()\"\n (event-click)=\"onEventClick($event)\"\n (event-container-click)=\"onEventContainerClick($event)\"\n (event-change)=\"onEventChange($event)\"\n >\n </rlb-calendar-grid>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "component", type: CalendarHeaderComponent, selector: "rlb-calendar-header", inputs: ["view", "currentDate"], outputs: ["dateChange", "viewChange"] }, { kind: "component", type: ProgressComponent, selector: "rlb-progress", inputs: ["max", "min", "value", "height", "animated", "striped", "infinite", "aria-label", "showValue", "color", "text-color"] }, { kind: "component", type: CalendarGrid, selector: "rlb-calendar-grid", inputs: ["view", "currentDate", "events", "layout"], outputs: ["event-click", "event-container-click", "event-change"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4076
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: CalendarComponent, isStandalone: true, selector: "rlb-calendar", inputs: { view: { classPropertyName: "view", publicName: "view", isSignal: true, isRequired: false, transformFunction: null }, events: { classPropertyName: "events", publicName: "events", isSignal: true, isRequired: false, transformFunction: null }, currentDate: { classPropertyName: "currentDate", publicName: "current-date", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, showToolbar: { classPropertyName: "showToolbar", publicName: "show-toolbar", isSignal: true, isRequired: false, transformFunction: null }, intervals: { classPropertyName: "intervals", publicName: "intervals", isSignal: true, isRequired: false, transformFunction: null }, manageEvents: { classPropertyName: "manageEvents", publicName: "manage-events", isSignal: true, isRequired: false, transformFunction: null }, layout: { classPropertyName: "layout", publicName: "layout", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { view: "viewChange", events: "eventsChange", currentDate: "current-dateChange", dateChange: "date-change", viewChange: "view-change", eventClick: "event-click", containerEventClick: "container-event-click" }, ngImport: i0, template: "<div class=\"rlb-calendar\">\n\n @if (showToolbar()) {\n <rlb-calendar-header\n [view]=\"view()\"\n [currentDate]=\"currentDate()\"\n (viewChange)=\"setView($event)\"\n (dateChange)=\"setDate($event)\"\n >\n </rlb-calendar-header>\n }\n\n @if (loading()) {\n <rlb-progress [infinite]=\"true\" [animated]=\"true\" [height]=\"3\" [showValue]=\"false\">\n </rlb-progress>\n } @else {\n <rlb-calendar-grid\n [events]=\"events()\"\n [intervals]=\"intervals()\"\n [view]=\"view()\"\n [currentDate]=\"currentDate()\"\n [layout]=\"mergedLayout()\"\n (event-click)=\"onEventClick($event)\"\n (event-container-click)=\"onEventContainerClick($event)\"\n (event-change)=\"onEventChange($event)\"\n >\n </rlb-calendar-grid>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "component", type: CalendarHeaderComponent, selector: "rlb-calendar-header", inputs: ["view", "currentDate"], outputs: ["dateChange", "viewChange"] }, { kind: "component", type: ProgressComponent, selector: "rlb-progress", inputs: ["max", "min", "value", "height", "animated", "striped", "infinite", "aria-label", "showValue", "color", "text-color"] }, { kind: "component", type: CalendarGrid, selector: "rlb-calendar-grid", inputs: ["view", "currentDate", "events", "intervals", "layout"], outputs: ["event-click", "event-container-click", "event-change"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4022
4077
  }
4023
4078
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: CalendarComponent, decorators: [{
4024
4079
  type: Component,
@@ -4026,8 +4081,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
4026
4081
  CalendarHeaderComponent,
4027
4082
  ProgressComponent,
4028
4083
  CalendarGrid,
4029
- ], template: "<div class=\"rlb-calendar\">\n\n @if (showToolbar()) {\n <rlb-calendar-header\n [view]=\"view()\"\n [currentDate]=\"currentDate()\"\n (viewChange)=\"setView($event)\"\n (dateChange)=\"setDate($event)\"\n >\n </rlb-calendar-header>\n }\n\n @if (loading()) {\n <rlb-progress [infinite]=\"true\" [animated]=\"true\" [height]=\"3\" [showValue]=\"false\">\n </rlb-progress>\n } @else {\n <rlb-calendar-grid\n [events]=\"events()\"\n [view]=\"view()\"\n [currentDate]=\"currentDate()\"\n [layout]=\"mergedLayout()\"\n (event-click)=\"onEventClick($event)\"\n (event-container-click)=\"onEventContainerClick($event)\"\n (event-change)=\"onEventChange($event)\"\n >\n </rlb-calendar-grid>\n }\n</div>\n" }]
4030
- }], ctorParameters: () => [{ type: ModalService }, { type: UniqueIdService }, { type: ToastService }], propDecorators: { view: [{ type: i0.Input, args: [{ isSignal: true, alias: "view", required: false }] }, { type: i0.Output, args: ["viewChange"] }], events: [{ type: i0.Input, args: [{ isSignal: true, alias: "events", required: false }] }, { type: i0.Output, args: ["eventsChange"] }], currentDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "current-date", required: false }] }, { type: i0.Output, args: ["current-dateChange"] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], showToolbar: [{ type: i0.Input, args: [{ isSignal: true, alias: "show-toolbar", required: false }] }], layout: [{ type: i0.Input, args: [{ isSignal: true, alias: "layout", required: false }] }], dateChange: [{ type: i0.Output, args: ["date-change"] }], viewChange: [{ type: i0.Output, args: ["view-change"] }], eventClick: [{ type: i0.Output, args: ["event-click"] }] } });
4084
+ ], template: "<div class=\"rlb-calendar\">\n\n @if (showToolbar()) {\n <rlb-calendar-header\n [view]=\"view()\"\n [currentDate]=\"currentDate()\"\n (viewChange)=\"setView($event)\"\n (dateChange)=\"setDate($event)\"\n >\n </rlb-calendar-header>\n }\n\n @if (loading()) {\n <rlb-progress [infinite]=\"true\" [animated]=\"true\" [height]=\"3\" [showValue]=\"false\">\n </rlb-progress>\n } @else {\n <rlb-calendar-grid\n [events]=\"events()\"\n [intervals]=\"intervals()\"\n [view]=\"view()\"\n [currentDate]=\"currentDate()\"\n [layout]=\"mergedLayout()\"\n (event-click)=\"onEventClick($event)\"\n (event-container-click)=\"onEventContainerClick($event)\"\n (event-change)=\"onEventChange($event)\"\n >\n </rlb-calendar-grid>\n }\n</div>\n" }]
4085
+ }], ctorParameters: () => [{ type: ModalService }, { type: UniqueIdService }, { type: ToastService }], propDecorators: { view: [{ type: i0.Input, args: [{ isSignal: true, alias: "view", required: false }] }, { type: i0.Output, args: ["viewChange"] }], events: [{ type: i0.Input, args: [{ isSignal: true, alias: "events", required: false }] }, { type: i0.Output, args: ["eventsChange"] }], currentDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "current-date", required: false }] }, { type: i0.Output, args: ["current-dateChange"] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], showToolbar: [{ type: i0.Input, args: [{ isSignal: true, alias: "show-toolbar", required: false }] }], intervals: [{ type: i0.Input, args: [{ isSignal: true, alias: "intervals", required: false }] }], manageEvents: [{ type: i0.Input, args: [{ isSignal: true, alias: "manage-events", required: false }] }], layout: [{ type: i0.Input, args: [{ isSignal: true, alias: "layout", required: false }] }], dateChange: [{ type: i0.Output, args: ["date-change"] }], viewChange: [{ type: i0.Output, args: ["view-change"] }], eventClick: [{ type: i0.Output, args: ["event-click"] }], containerEventClick: [{ type: i0.Output, args: ["container-event-click"] }] } });
4031
4086
 
4032
4087
  const CALENDAR_COMPONENTS = [
4033
4088
  CalendarComponent,
@@ -6370,6 +6425,8 @@ class AutocompleteCountryDialCodeComponent extends AbstractComponent {
6370
6425
  this.userDefinedId = input('', { ...(ngDevMode ? { debugName: "userDefinedId" } : /* istanbul ignore next */ {}), alias: 'id', transform: (v) => v || '' });
6371
6426
  this.enableFlagIcons = input(true, { ...(ngDevMode ? { debugName: "enableFlagIcons" } : /* istanbul ignore next */ {}), transform: booleanAttribute, alias: 'enable-flag-icons' });
6372
6427
  this.enableValidation = input(false, { ...(ngDevMode ? { debugName: "enableValidation" } : /* istanbul ignore next */ {}), transform: booleanAttribute, alias: 'enable-validation' });
6428
+ this.openOnFocus = input(false, { ...(ngDevMode ? { debugName: "openOnFocus" } : /* istanbul ignore next */ {}), transform: booleanAttribute, alias: 'open-on-focus' });
6429
+ this.detectLocale = input(false, { ...(ngDevMode ? { debugName: "detectLocale" } : /* istanbul ignore next */ {}), transform: booleanAttribute, alias: 'detect-locale' });
6373
6430
  this.el = viewChild('field', ...(ngDevMode ? [{ debugName: "el" }] : /* istanbul ignore next */ []));
6374
6431
  this.dropdown = viewChild('autocomplete', ...(ngDevMode ? [{ debugName: "dropdown" }] : /* istanbul ignore next */ []));
6375
6432
  this.selected = output();
@@ -7591,6 +7648,16 @@ class AutocompleteCountryDialCodeComponent extends AbstractComponent {
7591
7648
  data: 'ZW',
7592
7649
  },
7593
7650
  ];
7651
+ const destroyRef = inject(DestroyRef);
7652
+ const onScroll = (event) => {
7653
+ if (!this.isOpen())
7654
+ return;
7655
+ if (this.dropdown()?.nativeElement.contains(event.target))
7656
+ return;
7657
+ this.closeDropdown();
7658
+ };
7659
+ document.addEventListener('scroll', onScroll, { capture: true });
7660
+ destroyRef.onDestroy(() => document.removeEventListener('scroll', onScroll, { capture: true }));
7594
7661
  }
7595
7662
  onEscape(event) {
7596
7663
  if (this.isOpen()) {
@@ -7598,6 +7665,11 @@ class AutocompleteCountryDialCodeComponent extends AbstractComponent {
7598
7665
  this.el()?.nativeElement?.blur();
7599
7666
  }
7600
7667
  }
7668
+ onFocus() {
7669
+ if (this.openOnFocus() && !this.isOpen()) {
7670
+ this.manageSuggestions('', true);
7671
+ }
7672
+ }
7601
7673
  update(ev) {
7602
7674
  if (this.typingTimeout)
7603
7675
  clearTimeout(this.typingTimeout);
@@ -7616,16 +7688,33 @@ class AutocompleteCountryDialCodeComponent extends AbstractComponent {
7616
7688
  }
7617
7689
  return `${d.text} (${d.value})`;
7618
7690
  }
7619
- manageSuggestions(query) {
7620
- if (query && query.length > 0) {
7691
+ manageSuggestions(query, showAll = false) {
7692
+ if (showAll || (query && query.length > 0)) {
7621
7693
  this.openDropdown();
7622
- const rawSuggestions = this.getCountries().filter(c => c.text.toLowerCase().includes(query.toLowerCase()) || c.value.includes(query));
7623
- this.suggestions.set(rawSuggestions);
7694
+ let results = showAll && !query
7695
+ ? this.getCountries()
7696
+ : this.getCountries().filter(c => c.text.toLowerCase().includes(query.toLowerCase()) || c.value.includes(query));
7697
+ if (this.detectLocale()) {
7698
+ const code = this._localeCountryCode();
7699
+ if (code) {
7700
+ const idx = results.findIndex(c => c.data === code);
7701
+ if (idx > 0)
7702
+ results = [results[idx], ...results.filter((_, i) => i !== idx)];
7703
+ }
7704
+ }
7705
+ this.suggestions.set(results);
7624
7706
  }
7625
7707
  else {
7626
7708
  this.closeDropdown();
7627
7709
  }
7628
7710
  }
7711
+ _localeCountryCode() {
7712
+ const lang = navigator.languages?.[0] ?? navigator.language;
7713
+ if (!lang)
7714
+ return null;
7715
+ const parts = lang.split('-');
7716
+ return parts.length > 1 ? parts[parts.length - 1].toUpperCase() : null;
7717
+ }
7629
7718
  selectItem(item, ev) {
7630
7719
  ev?.preventDefault();
7631
7720
  ev?.stopPropagation();
@@ -7669,7 +7758,7 @@ class AutocompleteCountryDialCodeComponent extends AbstractComponent {
7669
7758
  }));
7670
7759
  }
7671
7760
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: AutocompleteCountryDialCodeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7672
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: AutocompleteCountryDialCodeComponent, isStandalone: true, selector: "rlb-autocomplete-country-dial-code", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "max-height", isSignal: true, isRequired: false, transformFunction: null }, menuMaxWidth: { classPropertyName: "menuMaxWidth", publicName: "menu-max-width", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, userDefinedId: { classPropertyName: "userDefinedId", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, enableFlagIcons: { classPropertyName: "enableFlagIcons", publicName: "enable-flag-icons", isSignal: true, isRequired: false, transformFunction: null }, enableValidation: { classPropertyName: "enableValidation", publicName: "enable-validation", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { disabled: "disabledChange", selected: "selected" }, host: { listeners: { "document:pointerdown": "handleOutsideEvent($event)", "document:keydown.escape": "onEscape($event)" }, properties: { "attr.id": "null" } }, viewQueries: [{ propertyName: "el", first: true, predicate: ["field"], descendants: true, isSignal: true }, { propertyName: "dropdown", first: true, predicate: ["autocomplete"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
7761
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: AutocompleteCountryDialCodeComponent, isStandalone: true, selector: "rlb-autocomplete-country-dial-code", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "max-height", isSignal: true, isRequired: false, transformFunction: null }, menuMaxWidth: { classPropertyName: "menuMaxWidth", publicName: "menu-max-width", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, userDefinedId: { classPropertyName: "userDefinedId", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, enableFlagIcons: { classPropertyName: "enableFlagIcons", publicName: "enable-flag-icons", isSignal: true, isRequired: false, transformFunction: null }, enableValidation: { classPropertyName: "enableValidation", publicName: "enable-validation", isSignal: true, isRequired: false, transformFunction: null }, openOnFocus: { classPropertyName: "openOnFocus", publicName: "open-on-focus", isSignal: true, isRequired: false, transformFunction: null }, detectLocale: { classPropertyName: "detectLocale", publicName: "detect-locale", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { disabled: "disabledChange", selected: "selected" }, host: { listeners: { "document:pointerdown": "handleOutsideEvent($event)", "document:keydown.escape": "onEscape($event)" }, properties: { "attr.id": "null" } }, viewQueries: [{ propertyName: "el", first: true, predicate: ["field"], descendants: true, isSignal: true }, { propertyName: "dropdown", first: true, predicate: ["autocomplete"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
7673
7762
  <ng-content select="[before]"></ng-content>
7674
7763
  <div class="input-group has-validation position-relative">
7675
7764
  <input
@@ -7684,6 +7773,7 @@ class AutocompleteCountryDialCodeComponent extends AbstractComponent {
7684
7773
  [attr.placeholder]="placeholder()"
7685
7774
  [class.form-control-lg]="size() === 'large'"
7686
7775
  [class.form-control-sm]="size() === 'small'"
7776
+ (focus)="onFocus()"
7687
7777
  (blur)="touch()"
7688
7778
  [ngClass]="{
7689
7779
  'is-invalid': controlTouched() && invalid() && enableValidation(),
@@ -7765,6 +7855,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
7765
7855
  [attr.placeholder]="placeholder()"
7766
7856
  [class.form-control-lg]="size() === 'large'"
7767
7857
  [class.form-control-sm]="size() === 'small'"
7858
+ (focus)="onFocus()"
7768
7859
  (blur)="touch()"
7769
7860
  [ngClass]="{
7770
7861
  'is-invalid': controlTouched() && invalid() && enableValidation(),
@@ -7834,7 +7925,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
7834
7925
  changeDetection: ChangeDetectionStrategy.OnPush,
7835
7926
  imports: [NgClass, InputValidationComponent, ProgressComponent],
7836
7927
  }]
7837
- }], ctorParameters: () => [], propDecorators: { disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], maxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "max-height", required: false }] }], menuMaxWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "menu-max-width", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], userDefinedId: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], enableFlagIcons: [{ type: i0.Input, args: [{ isSignal: true, alias: "enable-flag-icons", required: false }] }], enableValidation: [{ type: i0.Input, args: [{ isSignal: true, alias: "enable-validation", required: false }] }], el: [{ type: i0.ViewChild, args: ['field', { isSignal: true }] }], dropdown: [{ type: i0.ViewChild, args: ['autocomplete', { isSignal: true }] }], selected: [{ type: i0.Output, args: ["selected"] }] } });
7928
+ }], ctorParameters: () => [], propDecorators: { disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], maxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "max-height", required: false }] }], menuMaxWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "menu-max-width", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], userDefinedId: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], enableFlagIcons: [{ type: i0.Input, args: [{ isSignal: true, alias: "enable-flag-icons", required: false }] }], enableValidation: [{ type: i0.Input, args: [{ isSignal: true, alias: "enable-validation", required: false }] }], openOnFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "open-on-focus", required: false }] }], detectLocale: [{ type: i0.Input, args: [{ isSignal: true, alias: "detect-locale", required: false }] }], el: [{ type: i0.ViewChild, args: ['field', { isSignal: true }] }], dropdown: [{ type: i0.ViewChild, args: ['autocomplete', { isSignal: true }] }], selected: [{ type: i0.Output, args: ["selected"] }] } });
7838
7929
 
7839
7930
  class AutocompleteCountryComponent extends AbstractComponent {
7840
7931
  constructor() {
@@ -7854,6 +7945,8 @@ class AutocompleteCountryComponent extends AbstractComponent {
7854
7945
  this.userDefinedId = input('', { ...(ngDevMode ? { debugName: "userDefinedId" } : /* istanbul ignore next */ {}), alias: 'id', transform: (v) => v || '' });
7855
7946
  this.enableFlagIcons = input(false, { ...(ngDevMode ? { debugName: "enableFlagIcons" } : /* istanbul ignore next */ {}), transform: booleanAttribute, alias: 'enable-flag-icons' });
7856
7947
  this.enableValidation = input(false, { ...(ngDevMode ? { debugName: "enableValidation" } : /* istanbul ignore next */ {}), transform: booleanAttribute, alias: 'enable-validation' });
7948
+ this.openOnFocus = input(false, { ...(ngDevMode ? { debugName: "openOnFocus" } : /* istanbul ignore next */ {}), transform: booleanAttribute, alias: 'open-on-focus' });
7949
+ this.detectLocale = input(false, { ...(ngDevMode ? { debugName: "detectLocale" } : /* istanbul ignore next */ {}), transform: booleanAttribute, alias: 'detect-locale' });
7857
7950
  this.el = viewChild('field', ...(ngDevMode ? [{ debugName: "el" }] : /* istanbul ignore next */ []));
7858
7951
  this.dropdown = viewChild('autocomplete', ...(ngDevMode ? [{ debugName: "dropdown" }] : /* istanbul ignore next */ []));
7859
7952
  this.selected = output();
@@ -8058,6 +8151,16 @@ class AutocompleteCountryComponent extends AbstractComponent {
8058
8151
  { text: 'Zambia', value: 'ZM' },
8059
8152
  { text: 'Zimbabwe', value: 'ZW' },
8060
8153
  ];
8154
+ const destroyRef = inject(DestroyRef);
8155
+ const onScroll = (event) => {
8156
+ if (!this.isOpen())
8157
+ return;
8158
+ if (this.dropdown()?.nativeElement.contains(event.target))
8159
+ return;
8160
+ this.closeDropdown();
8161
+ };
8162
+ document.addEventListener('scroll', onScroll, { capture: true });
8163
+ destroyRef.onDestroy(() => document.removeEventListener('scroll', onScroll, { capture: true }));
8061
8164
  }
8062
8165
  onEscape(event) {
8063
8166
  if (this.isOpen()) {
@@ -8065,6 +8168,11 @@ class AutocompleteCountryComponent extends AbstractComponent {
8065
8168
  this.el()?.nativeElement?.blur();
8066
8169
  }
8067
8170
  }
8171
+ onFocus() {
8172
+ if (this.openOnFocus() && !this.isOpen()) {
8173
+ this.manageSuggestions('', true);
8174
+ }
8175
+ }
8068
8176
  update(ev) {
8069
8177
  if (this.typingTimeout)
8070
8178
  clearTimeout(this.typingTimeout);
@@ -8083,16 +8191,33 @@ class AutocompleteCountryComponent extends AbstractComponent {
8083
8191
  }
8084
8192
  return d?.text;
8085
8193
  }
8086
- manageSuggestions(query) {
8087
- if (query && query.length > 0) {
8194
+ manageSuggestions(query, showAll = false) {
8195
+ if (showAll || (query && query.length > 0)) {
8088
8196
  this.openDropdown();
8089
- const rawSuggestions = this.getCountries().filter(c => c.text.toLowerCase().includes(query.toLowerCase()));
8090
- this.suggestions.set(rawSuggestions);
8197
+ let results = showAll && !query
8198
+ ? this.getCountries()
8199
+ : this.getCountries().filter(c => c.text.toLowerCase().includes(query.toLowerCase()));
8200
+ if (this.detectLocale()) {
8201
+ const code = this._localeCountryCode();
8202
+ if (code) {
8203
+ const idx = results.findIndex(c => c.value === code);
8204
+ if (idx > 0)
8205
+ results = [results[idx], ...results.filter((_, i) => i !== idx)];
8206
+ }
8207
+ }
8208
+ this.suggestions.set(results);
8091
8209
  }
8092
8210
  else {
8093
8211
  this.closeDropdown();
8094
8212
  }
8095
8213
  }
8214
+ _localeCountryCode() {
8215
+ const lang = navigator.languages?.[0] ?? navigator.language;
8216
+ if (!lang)
8217
+ return null;
8218
+ const parts = lang.split('-');
8219
+ return parts.length > 1 ? parts[parts.length - 1].toUpperCase() : null;
8220
+ }
8096
8221
  selectItem(item, ev) {
8097
8222
  ev?.preventDefault();
8098
8223
  ev?.stopPropagation();
@@ -8139,7 +8264,7 @@ class AutocompleteCountryComponent extends AbstractComponent {
8139
8264
  }));
8140
8265
  }
8141
8266
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: AutocompleteCountryComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
8142
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: AutocompleteCountryComponent, isStandalone: true, selector: "rlb-autocomplete-country", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "max-height", isSignal: true, isRequired: false, transformFunction: null }, menuMaxWidth: { classPropertyName: "menuMaxWidth", publicName: "menu-max-width", isSignal: true, isRequired: false, transformFunction: null }, userDefinedId: { classPropertyName: "userDefinedId", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, enableFlagIcons: { classPropertyName: "enableFlagIcons", publicName: "enable-flag-icons", isSignal: true, isRequired: false, transformFunction: null }, enableValidation: { classPropertyName: "enableValidation", publicName: "enable-validation", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { disabled: "disabledChange", selected: "selected" }, host: { listeners: { "document:pointerdown": "handleOutsideEvent($event)", "document:keydown.escape": "onEscape($event)" }, properties: { "attr.id": "null" } }, viewQueries: [{ propertyName: "el", first: true, predicate: ["field"], descendants: true, isSignal: true }, { propertyName: "dropdown", first: true, predicate: ["autocomplete"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
8267
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: AutocompleteCountryComponent, isStandalone: true, selector: "rlb-autocomplete-country", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "max-height", isSignal: true, isRequired: false, transformFunction: null }, menuMaxWidth: { classPropertyName: "menuMaxWidth", publicName: "menu-max-width", isSignal: true, isRequired: false, transformFunction: null }, userDefinedId: { classPropertyName: "userDefinedId", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, enableFlagIcons: { classPropertyName: "enableFlagIcons", publicName: "enable-flag-icons", isSignal: true, isRequired: false, transformFunction: null }, enableValidation: { classPropertyName: "enableValidation", publicName: "enable-validation", isSignal: true, isRequired: false, transformFunction: null }, openOnFocus: { classPropertyName: "openOnFocus", publicName: "open-on-focus", isSignal: true, isRequired: false, transformFunction: null }, detectLocale: { classPropertyName: "detectLocale", publicName: "detect-locale", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { disabled: "disabledChange", selected: "selected" }, host: { listeners: { "document:pointerdown": "handleOutsideEvent($event)", "document:keydown.escape": "onEscape($event)" }, properties: { "attr.id": "null" } }, viewQueries: [{ propertyName: "el", first: true, predicate: ["field"], descendants: true, isSignal: true }, { propertyName: "dropdown", first: true, predicate: ["autocomplete"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
8143
8268
  <ng-content select="[before]"></ng-content>
8144
8269
  <div class="input-group has-validation position-relative">
8145
8270
  <input
@@ -8154,6 +8279,7 @@ class AutocompleteCountryComponent extends AbstractComponent {
8154
8279
  [attr.placeholder]="placeholder()"
8155
8280
  [class.form-control-lg]="size() === 'large'"
8156
8281
  [class.form-control-sm]="size() === 'small'"
8282
+ (focus)="onFocus()"
8157
8283
  (blur)="touch()"
8158
8284
  [ngClass]="{
8159
8285
  'is-invalid': controlTouched() && invalid() && enableValidation(),
@@ -8224,6 +8350,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
8224
8350
  [attr.placeholder]="placeholder()"
8225
8351
  [class.form-control-lg]="size() === 'large'"
8226
8352
  [class.form-control-sm]="size() === 'small'"
8353
+ (focus)="onFocus()"
8227
8354
  (blur)="touch()"
8228
8355
  [ngClass]="{
8229
8356
  'is-invalid': controlTouched() && invalid() && enableValidation(),
@@ -8283,12 +8410,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
8283
8410
  changeDetection: ChangeDetectionStrategy.OnPush,
8284
8411
  imports: [NgClass, InputValidationComponent],
8285
8412
  }]
8286
- }], ctorParameters: () => [], propDecorators: { disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], maxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "max-height", required: false }] }], menuMaxWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "menu-max-width", required: false }] }], userDefinedId: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], enableFlagIcons: [{ type: i0.Input, args: [{ isSignal: true, alias: "enable-flag-icons", required: false }] }], enableValidation: [{ type: i0.Input, args: [{ isSignal: true, alias: "enable-validation", required: false }] }], el: [{ type: i0.ViewChild, args: ['field', { isSignal: true }] }], dropdown: [{ type: i0.ViewChild, args: ['autocomplete', { isSignal: true }] }], selected: [{ type: i0.Output, args: ["selected"] }] } });
8413
+ }], ctorParameters: () => [], propDecorators: { disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], maxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "max-height", required: false }] }], menuMaxWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "menu-max-width", required: false }] }], userDefinedId: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], enableFlagIcons: [{ type: i0.Input, args: [{ isSignal: true, alias: "enable-flag-icons", required: false }] }], enableValidation: [{ type: i0.Input, args: [{ isSignal: true, alias: "enable-validation", required: false }] }], openOnFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "open-on-focus", required: false }] }], detectLocale: [{ type: i0.Input, args: [{ isSignal: true, alias: "detect-locale", required: false }] }], el: [{ type: i0.ViewChild, args: ['field', { isSignal: true }] }], dropdown: [{ type: i0.ViewChild, args: ['autocomplete', { isSignal: true }] }], selected: [{ type: i0.Output, args: ["selected"] }] } });
8287
8414
 
8288
8415
  class AutocompleteTimezonesComponent extends AbstractComponent {
8289
8416
  constructor() {
8290
8417
  super();
8291
8418
  this.isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
8419
+ this.dropdownTop = signal(0, ...(ngDevMode ? [{ debugName: "dropdownTop" }] : /* istanbul ignore next */ []));
8420
+ this.dropdownLeft = signal(0, ...(ngDevMode ? [{ debugName: "dropdownLeft" }] : /* istanbul ignore next */ []));
8421
+ this.dropdownWidth = signal(0, ...(ngDevMode ? [{ debugName: "dropdownWidth" }] : /* istanbul ignore next */ []));
8292
8422
  this.suggestions = signal([], ...(ngDevMode ? [{ debugName: "suggestions" }] : /* istanbul ignore next */ []));
8293
8423
  this.hasSuggestions = computed(() => this.suggestions().length > 0, ...(ngDevMode ? [{ debugName: "hasSuggestions" }] : /* istanbul ignore next */ []));
8294
8424
  this.disabled = model(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
@@ -8300,10 +8430,21 @@ class AutocompleteTimezonesComponent extends AbstractComponent {
8300
8430
  this.loading = input(false, { ...(ngDevMode ? { debugName: "loading" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
8301
8431
  this.userDefinedId = input('', { ...(ngDevMode ? { debugName: "userDefinedId" } : /* istanbul ignore next */ {}), alias: 'id', transform: (v) => v || '' });
8302
8432
  this.enableValidation = input(false, { ...(ngDevMode ? { debugName: "enableValidation" } : /* istanbul ignore next */ {}), transform: booleanAttribute, alias: 'enable-validation' });
8433
+ this.openOnFocus = input(false, { ...(ngDevMode ? { debugName: "openOnFocus" } : /* istanbul ignore next */ {}), transform: booleanAttribute, alias: 'open-on-focus' });
8303
8434
  this.el = viewChild('field', ...(ngDevMode ? [{ debugName: "el" }] : /* istanbul ignore next */ []));
8304
8435
  this.dropdown = viewChild('autocomplete', ...(ngDevMode ? [{ debugName: "dropdown" }] : /* istanbul ignore next */ []));
8305
8436
  this.selected = output();
8306
8437
  this.hostRef = inject((ElementRef));
8438
+ const destroyRef = inject(DestroyRef);
8439
+ const onScroll = (event) => {
8440
+ if (!this.isOpen())
8441
+ return;
8442
+ if (this.dropdown()?.nativeElement.contains(event.target))
8443
+ return;
8444
+ this.closeDropdown();
8445
+ };
8446
+ document.addEventListener('scroll', onScroll, { capture: true });
8447
+ destroyRef.onDestroy(() => document.removeEventListener('scroll', onScroll, { capture: true }));
8307
8448
  }
8308
8449
  onEscape(event) {
8309
8450
  if (this.isOpen()) {
@@ -8311,6 +8452,11 @@ class AutocompleteTimezonesComponent extends AbstractComponent {
8311
8452
  this.el()?.nativeElement?.blur();
8312
8453
  }
8313
8454
  }
8455
+ onFocus() {
8456
+ if (this.openOnFocus() && !this.isOpen()) {
8457
+ this.manageSuggestions('', true);
8458
+ }
8459
+ }
8314
8460
  update(ev) {
8315
8461
  if (this.typingTimeout)
8316
8462
  clearTimeout(this.typingTimeout);
@@ -8323,11 +8469,13 @@ class AutocompleteTimezonesComponent extends AbstractComponent {
8323
8469
  // We leave onWrite empty because [value]="value() || ''" in the template
8324
8470
  // handles the synchronization automatically in a Zoneless/Signal world.
8325
8471
  onWrite(data) { }
8326
- manageSuggestions(query) {
8327
- if (query && query.length > 0) {
8472
+ manageSuggestions(query, showAll = false) {
8473
+ if (showAll || (query && query.length > 0)) {
8328
8474
  this.openDropdown();
8329
8475
  const timezones = DateTz.timezones();
8330
- const filtered = timezones.filter(tz => tz.toLowerCase().includes(query.toLowerCase()));
8476
+ const filtered = showAll && !query
8477
+ ? timezones
8478
+ : timezones.filter(tz => tz.toLowerCase().includes(query.toLowerCase()));
8331
8479
  this.suggestions.set(filtered.map(tz => ({ text: tz, value: tz })));
8332
8480
  }
8333
8481
  else {
@@ -8359,13 +8507,19 @@ class AutocompleteTimezonesComponent extends AbstractComponent {
8359
8507
  this.closeDropdown();
8360
8508
  }
8361
8509
  openDropdown() {
8510
+ const rect = this.el()?.nativeElement.getBoundingClientRect();
8511
+ if (rect) {
8512
+ this.dropdownTop.set(rect.bottom);
8513
+ this.dropdownLeft.set(rect.left);
8514
+ this.dropdownWidth.set(rect.width);
8515
+ }
8362
8516
  this.isOpen.set(true);
8363
8517
  }
8364
8518
  closeDropdown() {
8365
8519
  this.isOpen.set(false);
8366
8520
  }
8367
8521
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: AutocompleteTimezonesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
8368
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: AutocompleteTimezonesComponent, isStandalone: true, selector: "rlb-autocomplete-timezones", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "max-height", isSignal: true, isRequired: false, transformFunction: null }, menuMaxWidth: { classPropertyName: "menuMaxWidth", publicName: "menu-max-width", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, userDefinedId: { classPropertyName: "userDefinedId", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, enableValidation: { classPropertyName: "enableValidation", publicName: "enable-validation", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { disabled: "disabledChange", selected: "selected" }, host: { listeners: { "document:pointerdown": "handleOutsideEvent($event)", "document:keydown.escape": "onEscape($event)" }, properties: { "attr.id": "null" } }, viewQueries: [{ propertyName: "el", first: true, predicate: ["field"], descendants: true, isSignal: true }, { propertyName: "dropdown", first: true, predicate: ["autocomplete"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
8522
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: AutocompleteTimezonesComponent, isStandalone: true, selector: "rlb-autocomplete-timezones", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "max-height", isSignal: true, isRequired: false, transformFunction: null }, menuMaxWidth: { classPropertyName: "menuMaxWidth", publicName: "menu-max-width", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, userDefinedId: { classPropertyName: "userDefinedId", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, enableValidation: { classPropertyName: "enableValidation", publicName: "enable-validation", isSignal: true, isRequired: false, transformFunction: null }, openOnFocus: { classPropertyName: "openOnFocus", publicName: "open-on-focus", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { disabled: "disabledChange", selected: "selected" }, host: { listeners: { "document:pointerdown": "handleOutsideEvent($event)", "document:keydown.escape": "onEscape($event)" }, properties: { "attr.id": "null" } }, viewQueries: [{ propertyName: "el", first: true, predicate: ["field"], descendants: true, isSignal: true }, { propertyName: "dropdown", first: true, predicate: ["autocomplete"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
8369
8523
  <ng-content select="[before]"></ng-content>
8370
8524
  <div class="input-group has-validation position-relative">
8371
8525
  <input
@@ -8380,6 +8534,7 @@ class AutocompleteTimezonesComponent extends AbstractComponent {
8380
8534
  [attr.placeholder]="placeholder()"
8381
8535
  [class.form-control-lg]="size() === 'large'"
8382
8536
  [class.form-control-sm]="size() === 'small'"
8537
+ (focus)="onFocus()"
8383
8538
  (blur)="touch()"
8384
8539
  [ngClass]="{
8385
8540
  'is-invalid': controlTouched() && invalid() && enableValidation(),
@@ -8397,10 +8552,13 @@ class AutocompleteTimezonesComponent extends AbstractComponent {
8397
8552
  @if (isOpen()) {
8398
8553
  <div
8399
8554
  #autocomplete
8400
- class="dropdown-menu show w-100 position-absolute overflow-y-auto shadow"
8555
+ class="dropdown-menu show overflow-y-auto shadow"
8401
8556
  [style.max-height.px]="maxHeight()"
8402
8557
  [style.max-width.px]="menuMaxWidth()"
8403
- style="z-index: 1000; top: 100%;"
8558
+ [style.top.px]="dropdownTop()"
8559
+ [style.left.px]="dropdownLeft()"
8560
+ [style.width.px]="dropdownWidth()"
8561
+ style="z-index: 1050; position: fixed;"
8404
8562
  >
8405
8563
  @if (!hasSuggestions()) {
8406
8564
  <a class="dropdown-item disabled text-center italic">No suggestions</a>
@@ -8448,6 +8606,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
8448
8606
  [attr.placeholder]="placeholder()"
8449
8607
  [class.form-control-lg]="size() === 'large'"
8450
8608
  [class.form-control-sm]="size() === 'small'"
8609
+ (focus)="onFocus()"
8451
8610
  (blur)="touch()"
8452
8611
  [ngClass]="{
8453
8612
  'is-invalid': controlTouched() && invalid() && enableValidation(),
@@ -8465,10 +8624,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
8465
8624
  @if (isOpen()) {
8466
8625
  <div
8467
8626
  #autocomplete
8468
- class="dropdown-menu show w-100 position-absolute overflow-y-auto shadow"
8627
+ class="dropdown-menu show overflow-y-auto shadow"
8469
8628
  [style.max-height.px]="maxHeight()"
8470
8629
  [style.max-width.px]="menuMaxWidth()"
8471
- style="z-index: 1000; top: 100%;"
8630
+ [style.top.px]="dropdownTop()"
8631
+ [style.left.px]="dropdownLeft()"
8632
+ [style.width.px]="dropdownWidth()"
8633
+ style="z-index: 1050; position: fixed;"
8472
8634
  >
8473
8635
  @if (!hasSuggestions()) {
8474
8636
  <a class="dropdown-item disabled text-center italic">No suggestions</a>
@@ -8504,7 +8666,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
8504
8666
  changeDetection: ChangeDetectionStrategy.OnPush,
8505
8667
  imports: [NgClass, InputValidationComponent, ProgressComponent],
8506
8668
  }]
8507
- }], ctorParameters: () => [], propDecorators: { disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], maxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "max-height", required: false }] }], menuMaxWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "menu-max-width", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], userDefinedId: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], enableValidation: [{ type: i0.Input, args: [{ isSignal: true, alias: "enable-validation", required: false }] }], el: [{ type: i0.ViewChild, args: ['field', { isSignal: true }] }], dropdown: [{ type: i0.ViewChild, args: ['autocomplete', { isSignal: true }] }], selected: [{ type: i0.Output, args: ["selected"] }] } });
8669
+ }], ctorParameters: () => [], propDecorators: { disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], maxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "max-height", required: false }] }], menuMaxWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "menu-max-width", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], userDefinedId: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], enableValidation: [{ type: i0.Input, args: [{ isSignal: true, alias: "enable-validation", required: false }] }], openOnFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "open-on-focus", required: false }] }], el: [{ type: i0.ViewChild, args: ['field', { isSignal: true }] }], dropdown: [{ type: i0.ViewChild, args: ['autocomplete', { isSignal: true }] }], selected: [{ type: i0.Output, args: ["selected"] }] } });
8508
8670
 
8509
8671
  class AutocompleteComponent extends AbstractComponent {
8510
8672
  onDocumentPointerDown(event) {
@@ -8540,17 +8702,32 @@ class AutocompleteComponent extends AbstractComponent {
8540
8702
  this.userDefinedId = input('', { ...(ngDevMode ? { debugName: "userDefinedId" } : /* istanbul ignore next */ {}), alias: 'id', transform: (v) => v || '' });
8541
8703
  this.enableValidation = input(false, { ...(ngDevMode ? { debugName: "enableValidation" } : /* istanbul ignore next */ {}), transform: booleanAttribute, alias: 'enable-validation' });
8542
8704
  this.inputAutocomplete = input('off', ...(ngDevMode ? [{ debugName: "inputAutocomplete" }] : /* istanbul ignore next */ []));
8705
+ this.openOnFocus = input(false, { ...(ngDevMode ? { debugName: "openOnFocus" } : /* istanbul ignore next */ {}), transform: booleanAttribute, alias: 'open-on-focus' });
8543
8706
  this.el = viewChild('field', ...(ngDevMode ? [{ debugName: "el" }] : /* istanbul ignore next */ []));
8544
8707
  this.dropdown = viewChild('autocomplete', ...(ngDevMode ? [{ debugName: "dropdown" }] : /* istanbul ignore next */ []));
8545
8708
  this.selected = output();
8546
8709
  this.hostRef = inject((ElementRef));
8547
8710
  this.searchSubject = new Subject();
8548
- // Use RxJS for cleaner debouncing
8549
8711
  this.searchSubject
8550
8712
  .pipe(debounceTime(300), distinctUntilChanged(), takeUntilDestroyed())
8551
8713
  .subscribe(val => {
8552
8714
  this.manageSuggestions(val);
8553
8715
  });
8716
+ const destroyRef = inject(DestroyRef);
8717
+ const onScroll = (event) => {
8718
+ if (!this.isOpen())
8719
+ return;
8720
+ if (this.dropdown()?.nativeElement.contains(event.target))
8721
+ return;
8722
+ this.closeDropdown();
8723
+ };
8724
+ document.addEventListener('scroll', onScroll, { capture: true });
8725
+ destroyRef.onDestroy(() => document.removeEventListener('scroll', onScroll, { capture: true }));
8726
+ }
8727
+ onFocus() {
8728
+ if (this.openOnFocus() && !this.isOpen()) {
8729
+ this.manageSuggestions('', true);
8730
+ }
8554
8731
  }
8555
8732
  update(ev) {
8556
8733
  if (this.disabled())
@@ -8571,10 +8748,10 @@ class AutocompleteComponent extends AbstractComponent {
8571
8748
  // }
8572
8749
  // }
8573
8750
  }
8574
- manageSuggestions(data) {
8751
+ manageSuggestions(data, showAll = false) {
8575
8752
  // 1. Reset suggestions but keep dropdown state logic clean
8576
8753
  this.suggestions.set([]);
8577
- if (data && data.length >= this.charsToSearch()) {
8754
+ if (showAll || (data && data.length >= this.charsToSearch())) {
8578
8755
  this.openDropdown();
8579
8756
  try {
8580
8757
  const result = this.autocomplete()(data);
@@ -8668,7 +8845,7 @@ class AutocompleteComponent extends AbstractComponent {
8668
8845
  this.acLoading.set(false);
8669
8846
  }
8670
8847
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: AutocompleteComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
8671
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: AutocompleteComponent, isStandalone: true, selector: "rlb-autocomplete", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "max-height", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, autocomplete: { classPropertyName: "autocomplete", publicName: "autocomplete", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, charsToSearch: { classPropertyName: "charsToSearch", publicName: "chars-to-search", isSignal: true, isRequired: false, transformFunction: null }, menuMaxWidth: { classPropertyName: "menuMaxWidth", publicName: "menu-max-width", isSignal: true, isRequired: false, transformFunction: null }, userDefinedId: { classPropertyName: "userDefinedId", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, enableValidation: { classPropertyName: "enableValidation", publicName: "enable-validation", isSignal: true, isRequired: false, transformFunction: null }, inputAutocomplete: { classPropertyName: "inputAutocomplete", publicName: "inputAutocomplete", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { disabled: "disabledChange", selected: "selected" }, host: { listeners: { "document:pointerdown": "onDocumentPointerDown($event)", "document:keydown.escape": "onEscape($event)" }, properties: { "attr.id": "null" } }, viewQueries: [{ propertyName: "el", first: true, predicate: ["field"], descendants: true, isSignal: true }, { propertyName: "dropdown", first: true, predicate: ["autocomplete"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
8848
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: AutocompleteComponent, isStandalone: true, selector: "rlb-autocomplete", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "max-height", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, autocomplete: { classPropertyName: "autocomplete", publicName: "autocomplete", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, charsToSearch: { classPropertyName: "charsToSearch", publicName: "chars-to-search", isSignal: true, isRequired: false, transformFunction: null }, menuMaxWidth: { classPropertyName: "menuMaxWidth", publicName: "menu-max-width", isSignal: true, isRequired: false, transformFunction: null }, userDefinedId: { classPropertyName: "userDefinedId", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, enableValidation: { classPropertyName: "enableValidation", publicName: "enable-validation", isSignal: true, isRequired: false, transformFunction: null }, inputAutocomplete: { classPropertyName: "inputAutocomplete", publicName: "inputAutocomplete", isSignal: true, isRequired: false, transformFunction: null }, openOnFocus: { classPropertyName: "openOnFocus", publicName: "open-on-focus", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { disabled: "disabledChange", selected: "selected" }, host: { listeners: { "document:pointerdown": "onDocumentPointerDown($event)", "document:keydown.escape": "onEscape($event)" }, properties: { "attr.id": "null" } }, viewQueries: [{ propertyName: "el", first: true, predicate: ["field"], descendants: true, isSignal: true }, { propertyName: "dropdown", first: true, predicate: ["autocomplete"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
8672
8849
  <ng-content select="[before]"></ng-content>
8673
8850
  <div class="input-group has-validation position-relative">
8674
8851
  <input
@@ -8678,6 +8855,7 @@ class AutocompleteComponent extends AbstractComponent {
8678
8855
  [value]="getText(value())"
8679
8856
  (input)="update($event.target)"
8680
8857
  (keyup.enter)="onEnter($event.target)"
8858
+ (focus)="onFocus()"
8681
8859
  (blur)="touch()"
8682
8860
  [id]="id()"
8683
8861
  [type]="type()"
@@ -8749,6 +8927,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
8749
8927
  [value]="getText(value())"
8750
8928
  (input)="update($event.target)"
8751
8929
  (keyup.enter)="onEnter($event.target)"
8930
+ (focus)="onFocus()"
8752
8931
  (blur)="touch()"
8753
8932
  [id]="id()"
8754
8933
  [type]="type()"
@@ -8813,7 +8992,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
8813
8992
  changeDetection: ChangeDetectionStrategy.OnPush,
8814
8993
  imports: [NgClass, InputValidationComponent],
8815
8994
  }]
8816
- }], ctorParameters: () => [], propDecorators: { disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], maxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "max-height", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], autocomplete: [{ type: i0.Input, args: [{ isSignal: true, alias: "autocomplete", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], charsToSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "chars-to-search", required: false }] }], menuMaxWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "menu-max-width", required: false }] }], userDefinedId: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], enableValidation: [{ type: i0.Input, args: [{ isSignal: true, alias: "enable-validation", required: false }] }], inputAutocomplete: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputAutocomplete", required: false }] }], el: [{ type: i0.ViewChild, args: ['field', { isSignal: true }] }], dropdown: [{ type: i0.ViewChild, args: ['autocomplete', { isSignal: true }] }], selected: [{ type: i0.Output, args: ["selected"] }] } });
8995
+ }], ctorParameters: () => [], propDecorators: { disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], maxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "max-height", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], autocomplete: [{ type: i0.Input, args: [{ isSignal: true, alias: "autocomplete", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], charsToSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "chars-to-search", required: false }] }], menuMaxWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "menu-max-width", required: false }] }], userDefinedId: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], enableValidation: [{ type: i0.Input, args: [{ isSignal: true, alias: "enable-validation", required: false }] }], inputAutocomplete: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputAutocomplete", required: false }] }], openOnFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "open-on-focus", required: false }] }], el: [{ type: i0.ViewChild, args: ['field', { isSignal: true }] }], dropdown: [{ type: i0.ViewChild, args: ['autocomplete', { isSignal: true }] }], selected: [{ type: i0.Output, args: ["selected"] }] } });
8817
8996
 
8818
8997
  class CheckboxComponent extends AbstractComponent {
8819
8998
  setExtValidation(val) {