@brickclay-org/ui 0.0.38 → 0.0.39

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.
Files changed (56) hide show
  1. package/fesm2022/brickclay-org-ui.mjs +4035 -0
  2. package/fesm2022/brickclay-org-ui.mjs.map +1 -0
  3. package/index.d.ts +857 -0
  4. package/package.json +26 -15
  5. package/ASSETS_SETUP.md +0 -59
  6. package/ng-package.json +0 -29
  7. package/src/lib/assets/icons.ts +0 -8
  8. package/src/lib/badge/badge.html +0 -24
  9. package/src/lib/badge/badge.ts +0 -42
  10. package/src/lib/brickclay-lib.spec.ts +0 -23
  11. package/src/lib/brickclay-lib.ts +0 -15
  12. package/src/lib/button-group/button-group.html +0 -12
  13. package/src/lib/button-group/button-group.ts +0 -73
  14. package/src/lib/calender/calendar.module.ts +0 -35
  15. package/src/lib/calender/components/custom-calendar/custom-calendar.component.css +0 -698
  16. package/src/lib/calender/components/custom-calendar/custom-calendar.component.html +0 -230
  17. package/src/lib/calender/components/custom-calendar/custom-calendar.component.spec.ts +0 -23
  18. package/src/lib/calender/components/custom-calendar/custom-calendar.component.ts +0 -1554
  19. package/src/lib/calender/components/scheduled-date-picker/scheduled-date-picker.component.css +0 -373
  20. package/src/lib/calender/components/scheduled-date-picker/scheduled-date-picker.component.html +0 -210
  21. package/src/lib/calender/components/scheduled-date-picker/scheduled-date-picker.component.ts +0 -361
  22. package/src/lib/calender/components/time-picker/time-picker.component.css +0 -174
  23. package/src/lib/calender/components/time-picker/time-picker.component.html +0 -60
  24. package/src/lib/calender/components/time-picker/time-picker.component.ts +0 -283
  25. package/src/lib/calender/services/calendar-manager.service.ts +0 -45
  26. package/src/lib/checkbox/checkbox.html +0 -42
  27. package/src/lib/checkbox/checkbox.ts +0 -67
  28. package/src/lib/chips/chips.html +0 -74
  29. package/src/lib/chips/chips.ts +0 -222
  30. package/src/lib/grid/components/grid/grid.html +0 -97
  31. package/src/lib/grid/components/grid/grid.ts +0 -139
  32. package/src/lib/grid/models/grid.model.ts +0 -20
  33. package/src/lib/input/input.html +0 -125
  34. package/src/lib/input/input.ts +0 -394
  35. package/src/lib/pill/pill.html +0 -24
  36. package/src/lib/pill/pill.ts +0 -39
  37. package/src/lib/radio/radio.html +0 -58
  38. package/src/lib/radio/radio.ts +0 -72
  39. package/src/lib/select/select.html +0 -111
  40. package/src/lib/select/select.ts +0 -401
  41. package/src/lib/spinner/spinner.html +0 -5
  42. package/src/lib/spinner/spinner.ts +0 -22
  43. package/src/lib/tabs/tabs.html +0 -28
  44. package/src/lib/tabs/tabs.ts +0 -48
  45. package/src/lib/textarea/textarea.html +0 -80
  46. package/src/lib/textarea/textarea.ts +0 -172
  47. package/src/lib/toggle/toggle.html +0 -24
  48. package/src/lib/toggle/toggle.ts +0 -62
  49. package/src/lib/ui-button/ui-button.html +0 -25
  50. package/src/lib/ui-button/ui-button.ts +0 -55
  51. package/src/lib/ui-icon-button/ui-icon-button.html +0 -7
  52. package/src/lib/ui-icon-button/ui-icon-button.ts +0 -38
  53. package/src/public-api.ts +0 -43
  54. package/tsconfig.lib.json +0 -19
  55. package/tsconfig.lib.prod.json +0 -11
  56. package/tsconfig.spec.json +0 -15
@@ -0,0 +1,4035 @@
1
+ import * as i0 from '@angular/core';
2
+ import { Component, EventEmitter, HostListener, ViewChildren, Output, Input, Injectable, NgModule, forwardRef, ViewEncapsulation, Optional, Self, ViewChild, input, model, output, signal, computed, effect, inject, ElementRef } from '@angular/core';
3
+ import * as i1 from '@angular/common';
4
+ import { CommonModule } from '@angular/common';
5
+ import * as i1$1 from '@angular/forms';
6
+ import { FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
7
+ import moment from 'moment';
8
+ import { Subject } from 'rxjs';
9
+ import * as i2 from '@angular/cdk/drag-drop';
10
+ import { moveItemInArray, DragDropModule } from '@angular/cdk/drag-drop';
11
+ import { ScrollingModule } from '@angular/cdk/scrolling';
12
+ import { NgxMaskDirective, provideNgxMask } from 'ngx-mask';
13
+
14
+ // Icon paths that will be resolved relative to the library's assets folder
15
+ // When published to npm, users will need to configure their angular.json to include these assets
16
+ const BrickclayIcons = {
17
+ arrowleft: 'assets/icons/chevron-left.svg',
18
+ arrowRight: 'assets/icons/chevron-right.svg',
19
+ calenderIcon: 'assets/icons/calender.svg',
20
+ timerIcon: 'assets/icons/timer.svg',
21
+ };
22
+
23
+ class BrickclayLib {
24
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BrickclayLib, deps: [], target: i0.ɵɵFactoryTarget.Component });
25
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: BrickclayLib, isStandalone: true, selector: "lib-brickclay-lib", ngImport: i0, template: `
26
+ <p>
27
+ brickclay-lib works!
28
+ </p>
29
+ `, isInline: true, styles: [""] });
30
+ }
31
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BrickclayLib, decorators: [{
32
+ type: Component,
33
+ args: [{ selector: 'lib-brickclay-lib', imports: [], template: `
34
+ <p>
35
+ brickclay-lib works!
36
+ </p>
37
+ ` }]
38
+ }] });
39
+
40
+ class BkTimePicker {
41
+ value = '1:00 AM'; // Time in format "H:MM AM/PM"
42
+ label = 'Time';
43
+ placeholder = 'Select time';
44
+ position = 'left';
45
+ pickerId = ''; // Unique ID for this picker
46
+ closePicker = 0; // Close counter from parent (triggers close when changed)
47
+ timeFormat = 12; // Visual mode: 12h or 24h
48
+ showSeconds = false; // Whether to show/edit seconds
49
+ timeChange = new EventEmitter();
50
+ pickerOpened = new EventEmitter(); // Notify parent when opened
51
+ pickerClosed = new EventEmitter(); // Notify parent when closed
52
+ timeScrollElements;
53
+ showPicker = false;
54
+ currentHour = 1;
55
+ currentMinute = 0;
56
+ currentAMPM = 'AM';
57
+ currentSecond = 0;
58
+ brickclayIcons = BrickclayIcons;
59
+ ngOnInit() {
60
+ this.parseTimeValue();
61
+ }
62
+ ngAfterViewInit() {
63
+ if (this.showPicker) {
64
+ setTimeout(() => {
65
+ this.scrollToSelectedTimes();
66
+ }, 100);
67
+ }
68
+ }
69
+ parseTimeValue() {
70
+ const parsed = this.parseTimeStringToComponents(this.value);
71
+ this.currentHour = parsed.hour;
72
+ this.currentMinute = parsed.minute;
73
+ this.currentSecond = parsed.second;
74
+ this.currentAMPM = parsed.ampm;
75
+ }
76
+ getHours() {
77
+ // 12-hour: 1-12, 24-hour: 0-23
78
+ if (this.timeFormat === 24) {
79
+ return Array.from({ length: 24 }, (_, i) => i);
80
+ }
81
+ return Array.from({ length: 12 }, (_, i) => i + 1);
82
+ }
83
+ getMinutes() {
84
+ return Array.from({ length: 60 }, (_, i) => i);
85
+ }
86
+ getSeconds() {
87
+ return Array.from({ length: 60 }, (_, i) => i);
88
+ }
89
+ getAMPMOptions() {
90
+ return ['AM', 'PM'];
91
+ }
92
+ parseTimeStringToComponents(timeStr) {
93
+ // Supports:
94
+ // - "H:MM AM/PM"
95
+ // - "H:MM:SS AM/PM"
96
+ // - "HH:MM" (24h)
97
+ // - "HH:MM:SS" (24h)
98
+ if (!timeStr) {
99
+ return {
100
+ hour: this.timeFormat === 24 ? 0 : 12,
101
+ minute: 0,
102
+ second: 0,
103
+ ampm: this.timeFormat === 24 ? '' : 'AM'
104
+ };
105
+ }
106
+ const parts = timeStr.trim().split(' ');
107
+ const timePart = parts[0] || (this.timeFormat === 24 ? '00:00' : '12:00');
108
+ let ampm = (parts[1] || '').toUpperCase();
109
+ const [hoursStr, minutesStr, secondsStr] = timePart.split(':');
110
+ let hour = parseInt(hoursStr || (this.timeFormat === 24 ? '0' : '12'), 10);
111
+ const minute = parseInt(minutesStr || '0', 10);
112
+ const second = parseInt(secondsStr || '0', 10);
113
+ if (this.timeFormat === 24) {
114
+ // In 24-hour mode we ignore AM/PM and keep hour as 0-23
115
+ return {
116
+ hour: isNaN(hour) ? 0 : Math.min(Math.max(hour, 0), 23),
117
+ minute: isNaN(minute) ? 0 : Math.min(Math.max(minute, 0), 59),
118
+ second: isNaN(second) ? 0 : Math.min(Math.max(second, 0), 59),
119
+ ampm: ''
120
+ };
121
+ }
122
+ // 12-hour mode: normalize AM/PM and convert 24h inputs if needed
123
+ let ampmValue = ampm === 'PM' || ampm === 'AM' ? ampm : '';
124
+ if (!ampmValue) {
125
+ // No AM/PM provided -> interpret as 24-hour and convert to 12-hour with AM/PM
126
+ if (hour >= 12) {
127
+ ampmValue = 'PM';
128
+ if (hour > 12)
129
+ hour -= 12;
130
+ }
131
+ else {
132
+ ampmValue = 'AM';
133
+ if (hour === 0)
134
+ hour = 12;
135
+ }
136
+ }
137
+ // Clamp to 1-12 range
138
+ if (hour < 1)
139
+ hour = 1;
140
+ if (hour > 12)
141
+ hour = 12;
142
+ return {
143
+ hour,
144
+ minute: isNaN(minute) ? 0 : Math.min(Math.max(minute, 0), 59),
145
+ second: isNaN(second) ? 0 : Math.min(Math.max(second, 0), 59),
146
+ ampm: ampmValue
147
+ };
148
+ }
149
+ formatTimeFromComponents(hour, minute, second, ampm) {
150
+ const hStr = hour.toString().padStart(2, '0');
151
+ const minuteStr = minute.toString().padStart(2, '0');
152
+ const secondStr = second.toString().padStart(2, '0');
153
+ if (this.timeFormat === 24) {
154
+ // "HH:mm" or "HH:mm:ss"
155
+ return this.showSeconds
156
+ ? `${hStr}:${minuteStr}:${secondStr}`
157
+ : `${hStr}:${minuteStr}`;
158
+ }
159
+ // 12-hour: "H:MM" or "H:MM:SS" with AM/PM
160
+ const displayHour = hour; // already 1-12
161
+ return this.showSeconds
162
+ ? `${displayHour}:${minuteStr}:${secondStr} ${ampm}`
163
+ : `${displayHour}:${minuteStr} ${ampm}`;
164
+ }
165
+ togglePicker() {
166
+ if (!this.showPicker) {
167
+ this.showPicker = true;
168
+ this.parseTimeValue();
169
+ this.pickerOpened.emit(this.pickerId);
170
+ setTimeout(() => {
171
+ this.scrollToSelectedTimes();
172
+ }, 100);
173
+ }
174
+ else {
175
+ this.showPicker = false;
176
+ this.pickerClosed.emit(this.pickerId);
177
+ }
178
+ }
179
+ onHourChange(hour) {
180
+ this.currentHour = hour;
181
+ this.updateTime();
182
+ setTimeout(() => {
183
+ this.scrollToSelectedTimes();
184
+ }, 50);
185
+ }
186
+ onMinuteChange(minute) {
187
+ this.currentMinute = minute;
188
+ this.updateTime();
189
+ setTimeout(() => {
190
+ this.scrollToSelectedTimes();
191
+ }, 50);
192
+ }
193
+ onSecondChange(second) {
194
+ this.currentSecond = second;
195
+ this.updateTime();
196
+ setTimeout(() => {
197
+ this.scrollToSelectedTimes();
198
+ }, 50);
199
+ }
200
+ onAMPMChange(ampm) {
201
+ this.currentAMPM = ampm;
202
+ this.updateTime();
203
+ setTimeout(() => {
204
+ this.scrollToSelectedTimes();
205
+ }, 50);
206
+ }
207
+ updateTime() {
208
+ const newTime = this.formatTimeFromComponents(this.currentHour, this.currentMinute, this.currentSecond, this.currentAMPM);
209
+ this.value = newTime;
210
+ this.timeChange.emit(newTime);
211
+ }
212
+ scrollToSelectedTimes() {
213
+ this.timeScrollElements.forEach((elementRef) => {
214
+ const element = elementRef.nativeElement;
215
+ const selectedItem = element.querySelector('.time-item.selected');
216
+ if (selectedItem) {
217
+ const scrollTop = selectedItem.offsetTop - element.offsetHeight / 40 + selectedItem.offsetHeight / 40;
218
+ element.scrollTop = scrollTop;
219
+ }
220
+ });
221
+ }
222
+ onDocumentClick(event) {
223
+ const target = event.target;
224
+ if (!target.closest('.time-picker-wrapper') && this.showPicker) {
225
+ this.showPicker = false;
226
+ this.pickerClosed.emit(this.pickerId);
227
+ }
228
+ }
229
+ previousCloseCounter = 0;
230
+ ngOnChanges(changes) {
231
+ if (changes['value'] && changes['value'].currentValue) {
232
+ this.parseTimeValue();
233
+ }
234
+ if (changes['closePicker'] && this.showPicker) {
235
+ const newCounter = changes['closePicker'].currentValue;
236
+ // If counter increased, close the picker
237
+ if (newCounter > this.previousCloseCounter) {
238
+ this.showPicker = false;
239
+ this.pickerClosed.emit(this.pickerId);
240
+ this.previousCloseCounter = newCounter;
241
+ }
242
+ }
243
+ }
244
+ // Basic keyboard support on the input (combobox behavior)
245
+ onInputKeydown(event) {
246
+ const key = event.key;
247
+ if (key === 'Enter' || key === ' ') {
248
+ event.preventDefault();
249
+ this.togglePicker();
250
+ return;
251
+ }
252
+ if (key === 'Escape' && this.showPicker) {
253
+ this.showPicker = false;
254
+ this.pickerClosed.emit(this.pickerId);
255
+ return;
256
+ }
257
+ // Simple hour increment/decrement when closed
258
+ if (!this.showPicker && (key === 'ArrowUp' || key === 'ArrowDown')) {
259
+ event.preventDefault();
260
+ if (this.timeFormat === 24) {
261
+ if (key === 'ArrowUp') {
262
+ this.currentHour = (this.currentHour + 1) % 24;
263
+ }
264
+ else {
265
+ this.currentHour = this.currentHour <= 0 ? 23 : this.currentHour - 1;
266
+ }
267
+ }
268
+ else {
269
+ if (key === 'ArrowUp') {
270
+ this.currentHour = this.currentHour >= 12 ? 1 : this.currentHour + 1;
271
+ }
272
+ else {
273
+ this.currentHour = this.currentHour <= 1 ? 12 : this.currentHour - 1;
274
+ }
275
+ }
276
+ this.updateTime();
277
+ }
278
+ }
279
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTimePicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
280
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: BkTimePicker, isStandalone: true, selector: "bk-time-picker", inputs: { value: "value", label: "label", placeholder: "placeholder", position: "position", pickerId: "pickerId", closePicker: "closePicker", timeFormat: "timeFormat", showSeconds: "showSeconds" }, outputs: { timeChange: "timeChange", pickerOpened: "pickerOpened", pickerClosed: "pickerClosed" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, viewQueries: [{ propertyName: "timeScrollElements", predicate: ["timeScroll"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"time-picker-wrapper\">\r\n <div class=\"time-input-group\">\r\n <label *ngIf=\"label\">{{ label }}</label>\r\n <div class=\"time-input-wrapper\">\r\n <input\r\n type=\"text\"\r\n class=\"time-input\"\r\n [value]=\"value\"\r\n [placeholder]=\"placeholder\"\r\n readonly\r\n (click)=\"togglePicker()\">\r\n <span class=\"time-icon\">\r\n <img alt=\"timer\" class=\"timer-icon\" [src]='brickclayIcons.timerIcon'/>\r\n </span>\r\n <div class=\"custom-time-picker-dropdown\" *ngIf=\"showPicker\">\r\n <div class=\"custom-time-picker\" [ngClass]=\"position === 'left' ? 'left-position' : 'right-position'\">\r\n <!-- Hours Column -->\r\n <div class=\"time-column\">\r\n <div class=\"time-scroll\" #timeScroll>\r\n <div\r\n *ngFor=\"let h of getHours()\"\r\n class=\"time-item\"\r\n [class.selected]=\"currentHour === h\"\r\n (click)=\"onHourChange(h)\">\r\n {{ h.toString().padStart(2, '0') }}\r\n </div>\r\n </div>\r\n </div>\r\n <span class=\"time-separator\">:</span>\r\n <!-- Minutes Column -->\r\n <div class=\"time-column\">\r\n <div class=\"time-scroll\" #timeScroll>\r\n <div\r\n *ngFor=\"let m of getMinutes()\"\r\n class=\"time-item\"\r\n [class.selected]=\"currentMinute === m\"\r\n (click)=\"onMinuteChange(m)\">\r\n {{ m.toString().padStart(2, '0') }}\r\n </div>\r\n </div>\r\n </div>\r\n <span class=\"time-separator\">:</span>\r\n <!-- AM/PM Column -->\r\n <div class=\"time-column ampm-column\">\r\n <div class=\"time-scroll\" #timeScroll>\r\n <div\r\n *ngFor=\"let ap of getAMPMOptions()\"\r\n class=\"time-item\"\r\n [class.selected]=\"currentAMPM === ap\"\r\n (click)=\"onAMPMChange(ap)\">\r\n {{ ap }}\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n", styles: [".time-picker-wrapper{width:100%;font-family:Inter,sans-serif}.time-input-group{display:flex;flex-direction:column;gap:4px}.time-input-group label{font-size:11px;font-weight:500;color:#15191e;text-transform:uppercase;letter-spacing:-.28px}.time-input-wrapper{position:relative;display:flex;align-items:center}.time-input{padding:8px 40px 8px 12px;border:1px solid #d1d5db;border-radius:4px;font-size:12px;font-family:Inter,sans-serif;color:#6f737b;background:#fff;transition:all .2s;width:100%;box-sizing:border-box;cursor:pointer}.time-input:focus{outline:none;border-color:#111827;box-shadow:0 0 0 3px #1118271a}.time-input:hover{border-color:#9ca3af}.time-icon{position:absolute;right:12px;font-size:16px;pointer-events:none;color:#9ca3af;cursor:pointer}.custom-time-picker-wrapper{width:100%;display:flex;justify-content:center}.custom-time-picker{display:flex;gap:8px;background:#fff;border:1px solid #e5e7eb;border-radius:8px;padding:10px;box-shadow:0 4px 12px #00000026;width:182px;position:absolute;top:calc(100% + 4px);z-index:1000}.custom-time-picker.left-position{left:0}.custom-time-picker.right-position{right:0}.time-column{display:flex;flex-direction:column;position:relative}.time-scroll{display:flex;flex-direction:column;max-height:95px;overflow-y:auto;overflow-x:hidden;scrollbar-width:thin;scrollbar-color:#cbd5e1 transparent;scrollbar-width:none;-ms-overflow-style:none}.time-scroll::-webkit-scrollbar{display:none}.time-scroll::-webkit-scrollbar-track{background:transparent}.time-scroll::-webkit-scrollbar-thumb{background:#cbd5e1;border-radius:2px}.time-scroll::-webkit-scrollbar-thumb:hover{background:#94a3b8}.time-item{min-width:40px;width:40px;height:32px;min-height:32px;display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:400;color:#374151;cursor:pointer;border-radius:4px;transition:all .15s ease;-webkit-user-select:none;user-select:none;font-family:Inter,sans-serif}.time-item:hover{background:#f3f4f6}.time-item.selected{background:#111827;color:#fff;font-weight:500;box-shadow:0 1px 2px #2563eb4d}.ampm-column .time-item{min-width:40px;width:40px}.time-separator{font-size:16px;font-weight:600;color:#6b7280;margin:5px 0 0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
281
+ }
282
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTimePicker, decorators: [{
283
+ type: Component,
284
+ args: [{ selector: 'bk-time-picker', standalone: true, imports: [CommonModule], template: "<div class=\"time-picker-wrapper\">\r\n <div class=\"time-input-group\">\r\n <label *ngIf=\"label\">{{ label }}</label>\r\n <div class=\"time-input-wrapper\">\r\n <input\r\n type=\"text\"\r\n class=\"time-input\"\r\n [value]=\"value\"\r\n [placeholder]=\"placeholder\"\r\n readonly\r\n (click)=\"togglePicker()\">\r\n <span class=\"time-icon\">\r\n <img alt=\"timer\" class=\"timer-icon\" [src]='brickclayIcons.timerIcon'/>\r\n </span>\r\n <div class=\"custom-time-picker-dropdown\" *ngIf=\"showPicker\">\r\n <div class=\"custom-time-picker\" [ngClass]=\"position === 'left' ? 'left-position' : 'right-position'\">\r\n <!-- Hours Column -->\r\n <div class=\"time-column\">\r\n <div class=\"time-scroll\" #timeScroll>\r\n <div\r\n *ngFor=\"let h of getHours()\"\r\n class=\"time-item\"\r\n [class.selected]=\"currentHour === h\"\r\n (click)=\"onHourChange(h)\">\r\n {{ h.toString().padStart(2, '0') }}\r\n </div>\r\n </div>\r\n </div>\r\n <span class=\"time-separator\">:</span>\r\n <!-- Minutes Column -->\r\n <div class=\"time-column\">\r\n <div class=\"time-scroll\" #timeScroll>\r\n <div\r\n *ngFor=\"let m of getMinutes()\"\r\n class=\"time-item\"\r\n [class.selected]=\"currentMinute === m\"\r\n (click)=\"onMinuteChange(m)\">\r\n {{ m.toString().padStart(2, '0') }}\r\n </div>\r\n </div>\r\n </div>\r\n <span class=\"time-separator\">:</span>\r\n <!-- AM/PM Column -->\r\n <div class=\"time-column ampm-column\">\r\n <div class=\"time-scroll\" #timeScroll>\r\n <div\r\n *ngFor=\"let ap of getAMPMOptions()\"\r\n class=\"time-item\"\r\n [class.selected]=\"currentAMPM === ap\"\r\n (click)=\"onAMPMChange(ap)\">\r\n {{ ap }}\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n", styles: [".time-picker-wrapper{width:100%;font-family:Inter,sans-serif}.time-input-group{display:flex;flex-direction:column;gap:4px}.time-input-group label{font-size:11px;font-weight:500;color:#15191e;text-transform:uppercase;letter-spacing:-.28px}.time-input-wrapper{position:relative;display:flex;align-items:center}.time-input{padding:8px 40px 8px 12px;border:1px solid #d1d5db;border-radius:4px;font-size:12px;font-family:Inter,sans-serif;color:#6f737b;background:#fff;transition:all .2s;width:100%;box-sizing:border-box;cursor:pointer}.time-input:focus{outline:none;border-color:#111827;box-shadow:0 0 0 3px #1118271a}.time-input:hover{border-color:#9ca3af}.time-icon{position:absolute;right:12px;font-size:16px;pointer-events:none;color:#9ca3af;cursor:pointer}.custom-time-picker-wrapper{width:100%;display:flex;justify-content:center}.custom-time-picker{display:flex;gap:8px;background:#fff;border:1px solid #e5e7eb;border-radius:8px;padding:10px;box-shadow:0 4px 12px #00000026;width:182px;position:absolute;top:calc(100% + 4px);z-index:1000}.custom-time-picker.left-position{left:0}.custom-time-picker.right-position{right:0}.time-column{display:flex;flex-direction:column;position:relative}.time-scroll{display:flex;flex-direction:column;max-height:95px;overflow-y:auto;overflow-x:hidden;scrollbar-width:thin;scrollbar-color:#cbd5e1 transparent;scrollbar-width:none;-ms-overflow-style:none}.time-scroll::-webkit-scrollbar{display:none}.time-scroll::-webkit-scrollbar-track{background:transparent}.time-scroll::-webkit-scrollbar-thumb{background:#cbd5e1;border-radius:2px}.time-scroll::-webkit-scrollbar-thumb:hover{background:#94a3b8}.time-item{min-width:40px;width:40px;height:32px;min-height:32px;display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:400;color:#374151;cursor:pointer;border-radius:4px;transition:all .15s ease;-webkit-user-select:none;user-select:none;font-family:Inter,sans-serif}.time-item:hover{background:#f3f4f6}.time-item.selected{background:#111827;color:#fff;font-weight:500;box-shadow:0 1px 2px #2563eb4d}.ampm-column .time-item{min-width:40px;width:40px}.time-separator{font-size:16px;font-weight:600;color:#6b7280;margin:5px 0 0}\n"] }]
285
+ }], propDecorators: { value: [{
286
+ type: Input
287
+ }], label: [{
288
+ type: Input
289
+ }], placeholder: [{
290
+ type: Input
291
+ }], position: [{
292
+ type: Input
293
+ }], pickerId: [{
294
+ type: Input
295
+ }], closePicker: [{
296
+ type: Input
297
+ }], timeFormat: [{
298
+ type: Input
299
+ }], showSeconds: [{
300
+ type: Input
301
+ }], timeChange: [{
302
+ type: Output
303
+ }], pickerOpened: [{
304
+ type: Output
305
+ }], pickerClosed: [{
306
+ type: Output
307
+ }], timeScrollElements: [{
308
+ type: ViewChildren,
309
+ args: ['timeScroll']
310
+ }], onDocumentClick: [{
311
+ type: HostListener,
312
+ args: ['document:click', ['$event']]
313
+ }] } });
314
+
315
+ class CalendarManagerService {
316
+ calendarInstances = new Set();
317
+ closeAllSubject = new Subject();
318
+ closeAll$ = this.closeAllSubject.asObservable();
319
+ /**
320
+ * Register a calendar instance with its close function
321
+ */
322
+ register(closeFn) {
323
+ this.calendarInstances.add(closeFn);
324
+ // Return unregister function
325
+ return () => {
326
+ this.calendarInstances.delete(closeFn);
327
+ };
328
+ }
329
+ /**
330
+ * Close all calendars except the one being opened
331
+ */
332
+ closeAllExcept(exceptCloseFn) {
333
+ this.calendarInstances.forEach(closeFn => {
334
+ if (closeFn !== exceptCloseFn) {
335
+ closeFn();
336
+ }
337
+ });
338
+ }
339
+ /**
340
+ * Close all calendars
341
+ */
342
+ closeAll() {
343
+ this.closeAllSubject.next();
344
+ this.calendarInstances.forEach(closeFn => closeFn());
345
+ }
346
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CalendarManagerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
347
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CalendarManagerService, providedIn: 'root' });
348
+ }
349
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CalendarManagerService, decorators: [{
350
+ type: Injectable,
351
+ args: [{
352
+ providedIn: 'root'
353
+ }]
354
+ }] });
355
+
356
+ class BkCustomCalendar {
357
+ calendarManager;
358
+ // Basic Options
359
+ enableTimepicker = false;
360
+ autoApply = false;
361
+ closeOnAutoApply = false;
362
+ showCancel = true;
363
+ linkedCalendars = false;
364
+ singleDatePicker = false;
365
+ showWeekNumbers = false;
366
+ showISOWeekNumbers = false;
367
+ customRangeDirection = false;
368
+ lockStartDate = false;
369
+ position = 'left';
370
+ drop = 'down';
371
+ dualCalendar = false;
372
+ showRanges = true;
373
+ timeFormat = 24;
374
+ enableSeconds = false;
375
+ customRanges;
376
+ multiDateSelection = false; // NEW: Enable multi-date selection
377
+ maxDate; // NEW: Maximum selectable date
378
+ minDate; // NEW: Minimum selectable date
379
+ placeholder = 'Select date range'; // NEW: Custom placeholder
380
+ opens = 'left'; // NEW: Popup position
381
+ inline = false; // NEW: Always show calendar inline (no popup)
382
+ isDisplayCrossIcon = true; // NEW: Show/Hide clear (X) icon
383
+ selected = new EventEmitter();
384
+ opened = new EventEmitter();
385
+ closed = new EventEmitter();
386
+ /**
387
+ * External value passed from parent. If provided, component will select these dates on init / change.
388
+ * Accepts { startDate: Date|null, endDate: Date|null, selectedDates?: Date[] }
389
+ */
390
+ selectedValue = null;
391
+ /** Optional display format for the input value. Uses moment formatting tokens. */
392
+ displayFormat = 'MM/DD/YYYY';
393
+ brickclayIcons = BrickclayIcons;
394
+ show = false;
395
+ today = new Date();
396
+ month = this.today.getMonth();
397
+ year = this.today.getFullYear();
398
+ calendar = [];
399
+ leftMonth;
400
+ leftYear;
401
+ rightMonth;
402
+ rightYear;
403
+ leftCalendar = [];
404
+ rightCalendar = [];
405
+ startDate = null;
406
+ endDate = null;
407
+ selectedDates = []; // NEW: For multi-date selection
408
+ disableHighlight = false;
409
+ hoveredDate = null; // For hover preview
410
+ // Track raw input values for minutes to allow free typing
411
+ minuteInputValues = {};
412
+ // Time picker for single calendar (12-hour format: 1-12)
413
+ selectedHour = 1;
414
+ selectedMinute = 0;
415
+ selectedSecond = 0;
416
+ selectedAMPM = 'AM';
417
+ // NEW: Separate time pickers for dual calendar (12-hour format: 1-12)
418
+ startHour = 1;
419
+ startMinute = 0;
420
+ startSecond = 0;
421
+ startAMPM = 'AM';
422
+ endHour = 2;
423
+ endMinute = 0;
424
+ endSecond = 0;
425
+ endAMPM = 'AM';
426
+ // Track open time-picker within this calendar (for single-open behavior)
427
+ openTimePickerId = null;
428
+ closePickerCounter = {};
429
+ defaultRanges = {};
430
+ activeRange = null; // Track which range is currently active
431
+ rangeOrder = []; // Maintain order of ranges
432
+ unregisterFn;
433
+ closeAllSubscription;
434
+ closeFn;
435
+ constructor(calendarManager) {
436
+ this.calendarManager = calendarManager;
437
+ }
438
+ onClickOutside(event) {
439
+ // Don't handle click outside if inline mode is enabled
440
+ if (this.inline) {
441
+ return;
442
+ }
443
+ const target = event.target;
444
+ if (this.show && !target.closest('.calendar-container')) {
445
+ this.close();
446
+ }
447
+ }
448
+ ngOnInit() {
449
+ if (!this.customRanges) {
450
+ this.initializeDefaultRanges();
451
+ }
452
+ else {
453
+ // If customRanges is provided via @Input, set the order based on the keys
454
+ // Maintain the desired order if keys match, otherwise use provided order
455
+ const desiredOrder = ['Today', 'Yesterday', 'Last 7 Days', 'Last 30 Days', 'This Month', 'Last Month', 'Custom Range'];
456
+ const providedKeys = Object.keys(this.customRanges);
457
+ // Check if Custom Range exists, if not add it
458
+ if (!this.customRanges['Custom Range']) {
459
+ this.customRanges['Custom Range'] = { start: new Date(), end: new Date() };
460
+ }
461
+ // Build order: first add desired order items that exist, then add any remaining
462
+ this.rangeOrder = desiredOrder.filter(key => providedKeys.includes(key) || key === 'Custom Range');
463
+ const remaining = providedKeys.filter(key => !this.rangeOrder.includes(key));
464
+ this.rangeOrder = [...this.rangeOrder, ...remaining];
465
+ }
466
+ if (this.dualCalendar)
467
+ this.initializeDual();
468
+ else
469
+ this.generateCalendar();
470
+ // Initialize time from existing dates if available
471
+ if (this.startDate) {
472
+ this.initializeTimeFromDate(this.startDate, true);
473
+ }
474
+ if (this.endDate) {
475
+ this.initializeTimeFromDate(this.endDate, false);
476
+ }
477
+ // Check if current dates match any predefined range
478
+ if (this.startDate && this.endDate) {
479
+ this.checkAndSetActiveRange();
480
+ }
481
+ // If inline mode, always show calendar
482
+ if (this.inline) {
483
+ this.show = true;
484
+ }
485
+ // Register this calendar instance with the manager service
486
+ this.closeFn = () => {
487
+ if (this.show && !this.inline) {
488
+ this.close();
489
+ }
490
+ };
491
+ this.unregisterFn = this.calendarManager.register(this.closeFn);
492
+ // Subscribe to close all events (skip if inline)
493
+ this.closeAllSubscription = this.calendarManager.closeAll$.subscribe(() => {
494
+ if (this.show && !this.inline) {
495
+ this.close();
496
+ }
497
+ });
498
+ }
499
+ ngOnChanges(changes) {
500
+ if (changes['selectedValue'] && this.selectedValue) {
501
+ // Normalize incoming values to Date or null
502
+ const s = this.selectedValue;
503
+ this.startDate = s.startDate ? new Date(s.startDate) : null;
504
+ this.endDate = s.endDate ? new Date(s.endDate) : null;
505
+ this.selectedDates = (s.selectedDates || []).map((d) => new Date(d));
506
+ // Update calendar month/year to show the start date (or end date if start missing)
507
+ const focusDate = this.startDate ?? this.endDate ?? new Date();
508
+ this.month = focusDate.getMonth();
509
+ this.year = focusDate.getFullYear();
510
+ if (this.dualCalendar) {
511
+ this.initializeDual();
512
+ }
513
+ else {
514
+ this.generateCalendar();
515
+ }
516
+ // Re-evaluate active range if any
517
+ this.checkAndSetActiveRange();
518
+ }
519
+ }
520
+ ngOnDestroy() {
521
+ // Unregister this calendar instance
522
+ if (this.unregisterFn) {
523
+ this.unregisterFn();
524
+ }
525
+ // Unsubscribe from close all events
526
+ if (this.closeAllSubscription) {
527
+ this.closeAllSubscription.unsubscribe();
528
+ }
529
+ }
530
+ checkAndSetActiveRange() {
531
+ if (!this.customRanges || !this.startDate || !this.endDate)
532
+ return;
533
+ // Normalize dates for comparison (ignore time)
534
+ const normalizeDate = (date) => {
535
+ const d = new Date(date);
536
+ d.setHours(0, 0, 0, 0);
537
+ return d;
538
+ };
539
+ const start = normalizeDate(this.startDate);
540
+ const end = normalizeDate(this.endDate);
541
+ // Check each range (except Custom Range)
542
+ for (const key of this.rangeOrder) {
543
+ if (key === 'Custom Range')
544
+ continue;
545
+ const range = this.customRanges[key];
546
+ if (range) {
547
+ const rangeStart = normalizeDate(range.start);
548
+ const rangeEnd = normalizeDate(range.end);
549
+ if (start.getTime() === rangeStart.getTime() && end.getTime() === rangeEnd.getTime()) {
550
+ this.activeRange = key;
551
+ return;
552
+ }
553
+ }
554
+ }
555
+ // If no match found, it's a custom range
556
+ this.activeRange = 'Custom Range';
557
+ }
558
+ initializeDefaultRanges() {
559
+ const today = new Date();
560
+ this.customRanges = {
561
+ 'Today': { start: new Date(today.getFullYear(), today.getMonth(), today.getDate()), end: new Date(today.getFullYear(), today.getMonth(), today.getDate()) },
562
+ 'Yesterday': { start: this.addDays(today, -1), end: this.addDays(today, -1) },
563
+ 'Last 7 Days': { start: this.addDays(today, -6), end: today },
564
+ 'Last 30 Days': { start: this.addDays(today, -29), end: today },
565
+ 'This Month': { start: new Date(today.getFullYear(), today.getMonth(), 1), end: today },
566
+ 'Last Month': { start: new Date(today.getFullYear(), today.getMonth() - 1, 1), end: new Date(today.getFullYear(), today.getMonth(), 0) },
567
+ 'Custom Range': { start: new Date(), end: new Date() }, // Placeholder, won't be used for selection
568
+ };
569
+ // Set the order of ranges
570
+ this.rangeOrder = ['Today', 'Yesterday', 'Last 7 Days', 'Last 30 Days', 'This Month', 'Last Month', 'Custom Range'];
571
+ }
572
+ initializeTimeFromDate(date, isStart) {
573
+ // Always use 12-hour format
574
+ const hours24 = date.getHours();
575
+ const minutes = date.getMinutes();
576
+ const seconds = date.getSeconds();
577
+ if (isStart) {
578
+ this.startMinute = minutes;
579
+ this.startSecond = seconds;
580
+ if (hours24 >= 12) {
581
+ this.startAMPM = 'PM';
582
+ this.startHour = hours24 > 12 ? hours24 - 12 : 12;
583
+ }
584
+ else {
585
+ this.startAMPM = 'AM';
586
+ this.startHour = hours24 === 0 ? 12 : hours24;
587
+ }
588
+ }
589
+ else {
590
+ this.endMinute = minutes;
591
+ this.endSecond = seconds;
592
+ if (hours24 >= 12) {
593
+ this.endAMPM = 'PM';
594
+ this.endHour = hours24 > 12 ? hours24 - 12 : 12;
595
+ }
596
+ else {
597
+ this.endAMPM = 'AM';
598
+ this.endHour = hours24 === 0 ? 12 : hours24;
599
+ }
600
+ }
601
+ }
602
+ toggle() {
603
+ // Don't toggle if inline mode is enabled
604
+ if (this.inline) {
605
+ return;
606
+ }
607
+ const wasOpen = this.show;
608
+ this.show = !this.show;
609
+ if (this.show) {
610
+ // If opening, close all other calendars first
611
+ if (!wasOpen && this.closeFn) {
612
+ this.calendarManager.closeAllExcept(this.closeFn);
613
+ }
614
+ this.disableHighlight = false;
615
+ this.opened.emit();
616
+ }
617
+ else {
618
+ this.closed.emit();
619
+ }
620
+ }
621
+ close() {
622
+ // Don't close if inline mode is enabled
623
+ if (this.inline) {
624
+ return;
625
+ }
626
+ this.show = false;
627
+ this.closed.emit();
628
+ }
629
+ onDateHover(day, fromRight = false) {
630
+ if (!day || this.singleDatePicker || this.multiDateSelection) {
631
+ this.hoveredDate = null;
632
+ return;
633
+ }
634
+ // Only show hover preview if start date is selected but end date is not
635
+ if (!this.startDate || this.endDate) {
636
+ this.hoveredDate = null;
637
+ return;
638
+ }
639
+ if (!this.dualCalendar) {
640
+ this.hoveredDate = new Date(this.year, this.month, day);
641
+ }
642
+ else {
643
+ this.hoveredDate = fromRight
644
+ ? new Date(this.rightYear, this.rightMonth, day)
645
+ : new Date(this.leftYear, this.leftMonth, day);
646
+ }
647
+ }
648
+ onDateLeave() {
649
+ this.hoveredDate = null;
650
+ }
651
+ selectDate(day, fromRight = false) {
652
+ if (!day)
653
+ return;
654
+ let selected;
655
+ if (!this.dualCalendar) {
656
+ selected = new Date(this.year, this.month, day);
657
+ }
658
+ else {
659
+ selected = fromRight
660
+ ? new Date(this.rightYear, this.rightMonth, day)
661
+ : new Date(this.leftYear, this.leftMonth, day);
662
+ }
663
+ // Clear hover on selection
664
+ this.hoveredDate = null;
665
+ // Check min/max date constraints
666
+ if (this.minDate && selected < this.minDate)
667
+ return;
668
+ if (this.maxDate && selected > this.maxDate)
669
+ return;
670
+ // Multi-date selection mode
671
+ if (this.multiDateSelection) {
672
+ this.handleMultiDateSelection(selected);
673
+ return;
674
+ }
675
+ // Apply time if timepicker is enabled (convert 12-hour to 24-hour)
676
+ if (this.enableTimepicker) {
677
+ if (this.dualCalendar) {
678
+ // For dual calendar, use separate start/end times
679
+ // If no startDate OR endDate exists, we're selecting start date
680
+ const isStart = !this.startDate || !!this.endDate;
681
+ this.applyTimeToDate(selected, isStart);
682
+ }
683
+ else {
684
+ // For single calendar, always use selected time for start
685
+ this.applyTimeToDate(selected, true);
686
+ }
687
+ }
688
+ // Single date picker mode
689
+ if (this.singleDatePicker) {
690
+ this.startDate = selected;
691
+ this.endDate = null;
692
+ // Activate Custom Range when manually selecting dates
693
+ this.activeRange = 'Custom Range';
694
+ // Apply time immediately if timepicker is enabled
695
+ if (this.enableTimepicker) {
696
+ this.applyTimeToDate(this.startDate, true);
697
+ }
698
+ if (this.autoApply) {
699
+ this.apply();
700
+ if (this.closeOnAutoApply && !this.inline)
701
+ this.close();
702
+ }
703
+ else {
704
+ // Always emit selection event even if autoApply is false (especially for inline calendars)
705
+ this.emitSelection();
706
+ }
707
+ return;
708
+ }
709
+ // Range selection mode
710
+ if (!this.startDate || this.endDate) {
711
+ this.startDate = selected;
712
+ this.endDate = null;
713
+ // Activate Custom Range when manually selecting dates
714
+ this.activeRange = 'Custom Range';
715
+ // Keep left calendar on the selected month for better UX
716
+ if (this.dualCalendar) {
717
+ this.leftMonth = selected.getMonth();
718
+ this.leftYear = selected.getFullYear();
719
+ // Reset right calendar to original position (next month after left) when end date is cleared
720
+ this.rightMonth = this.leftMonth + 1;
721
+ this.rightYear = this.leftYear;
722
+ if (this.rightMonth > 11) {
723
+ this.rightMonth = 0;
724
+ this.rightYear++;
725
+ }
726
+ this.generateDualCalendars();
727
+ }
728
+ // Don't overwrite time picker values - keep current values and apply them to the date
729
+ // Time picker values are already set by user, we just apply them to the selected date
730
+ }
731
+ else {
732
+ if (selected < this.startDate && !this.customRangeDirection) {
733
+ this.endDate = this.startDate;
734
+ this.startDate = selected;
735
+ // Activate Custom Range when manually selecting dates
736
+ this.activeRange = 'Custom Range';
737
+ // Swap times if needed
738
+ if (this.dualCalendar && this.enableTimepicker) {
739
+ [this.startHour, this.endHour] = [this.endHour, this.startHour];
740
+ [this.startMinute, this.endMinute] = [this.endMinute, this.startMinute];
741
+ [this.startSecond, this.endSecond] = [this.endSecond, this.startSecond];
742
+ [this.startAMPM, this.endAMPM] = [this.endAMPM, this.startAMPM];
743
+ }
744
+ // Keep left calendar on the selected month
745
+ if (this.dualCalendar) {
746
+ this.leftMonth = selected.getMonth();
747
+ this.leftYear = selected.getFullYear();
748
+ this.leftCalendar = this.buildCalendar(this.leftYear, this.leftMonth);
749
+ }
750
+ }
751
+ else {
752
+ this.endDate = selected;
753
+ // Activate Custom Range when manually selecting dates
754
+ this.activeRange = 'Custom Range';
755
+ // Only move right calendar if end date is in a different month than start date
756
+ if (this.dualCalendar) {
757
+ if (this.startDate) {
758
+ const startMonth = this.startDate.getMonth();
759
+ const startYear = this.startDate.getFullYear();
760
+ const endMonth = selected.getMonth();
761
+ const endYear = selected.getFullYear();
762
+ // Only move right calendar if end date is in a different month
763
+ if (endMonth !== startMonth || endYear !== startYear) {
764
+ this.rightMonth = endMonth;
765
+ this.rightYear = endYear;
766
+ this.rightCalendar = this.buildCalendar(this.rightYear, this.rightMonth);
767
+ }
768
+ // If both dates are in same month, keep right calendar in its current position
769
+ }
770
+ else {
771
+ // If no start date, move right calendar to end date month
772
+ this.rightMonth = selected.getMonth();
773
+ this.rightYear = selected.getFullYear();
774
+ this.rightCalendar = this.buildCalendar(this.rightYear, this.rightMonth);
775
+ }
776
+ }
777
+ // Don't overwrite time picker values - keep current end time values
778
+ // Time picker values are already set by user
779
+ }
780
+ if (this.autoApply) {
781
+ this.apply();
782
+ if (this.closeOnAutoApply && !this.inline)
783
+ this.close();
784
+ }
785
+ else {
786
+ // Check if the selection matches a predefined range
787
+ this.checkAndSetActiveRange();
788
+ // Always emit selection event for inline calendars
789
+ if (this.inline) {
790
+ this.emitSelection();
791
+ }
792
+ }
793
+ }
794
+ }
795
+ handleMultiDateSelection(selected) {
796
+ const dateStr = this.getDateString(selected);
797
+ const existingIndex = this.selectedDates.findIndex(d => this.getDateString(d) === dateStr);
798
+ if (existingIndex >= 0) {
799
+ // Deselect if already selected
800
+ this.selectedDates.splice(existingIndex, 1);
801
+ }
802
+ else {
803
+ // Add to selection
804
+ this.selectedDates.push(new Date(selected));
805
+ this.selectedDates.sort((a, b) => a.getTime() - b.getTime());
806
+ }
807
+ // Update startDate and endDate for compatibility
808
+ if (this.selectedDates.length > 0) {
809
+ this.startDate = new Date(this.selectedDates[0]);
810
+ this.endDate = new Date(this.selectedDates[this.selectedDates.length - 1]);
811
+ // Activate Custom Range when manually selecting dates
812
+ this.activeRange = 'Custom Range';
813
+ }
814
+ else {
815
+ this.startDate = null;
816
+ this.endDate = null;
817
+ this.activeRange = null;
818
+ }
819
+ // Always emit selection event for inline calendars or when autoApply is true
820
+ if (this.autoApply || this.inline) {
821
+ this.emitSelection();
822
+ if (this.closeOnAutoApply && !this.inline)
823
+ this.close();
824
+ }
825
+ }
826
+ getDateString(date) {
827
+ return `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`;
828
+ }
829
+ isDateInMultiSelection(year, month, day) {
830
+ if (!this.multiDateSelection || this.selectedDates.length === 0)
831
+ return false;
832
+ const cellDate = new Date(year, month, day);
833
+ return this.selectedDates.some(d => this.getDateString(d) === this.getDateString(cellDate));
834
+ }
835
+ apply() {
836
+ // Format minute inputs to 2 digits before applying
837
+ this.formatAllMinuteInputs();
838
+ // Apply time to dates
839
+ if (this.enableTimepicker) {
840
+ if (this.dualCalendar) {
841
+ // Dual calendar with separate start/end times (always 12-hour format)
842
+ if (this.startDate) {
843
+ this.applyTimeToDate(this.startDate, true);
844
+ }
845
+ if (this.endDate) {
846
+ this.applyTimeToDate(this.endDate, false);
847
+ }
848
+ }
849
+ else {
850
+ // Single calendar with time (always 12-hour format)
851
+ if (this.startDate) {
852
+ this.applyTimeToDate(this.startDate, true);
853
+ }
854
+ if (this.endDate && !this.singleDatePicker) {
855
+ this.applyTimeToDate(this.endDate, true);
856
+ }
857
+ }
858
+ }
859
+ // Check if the selection matches a predefined range
860
+ this.checkAndSetActiveRange();
861
+ this.emitSelection();
862
+ this.disableHighlight = true;
863
+ this.close();
864
+ }
865
+ cancel() {
866
+ this.startDate = null;
867
+ this.endDate = null;
868
+ this.selectedDates = [];
869
+ this.close();
870
+ }
871
+ clear() {
872
+ this.startDate = null;
873
+ this.endDate = null;
874
+ this.selectedDates = [];
875
+ this.activeRange = null; // Clear active range
876
+ // Reset right calendar to original position (next month after left) when end date is cleared
877
+ if (this.dualCalendar && !this.endDate) {
878
+ this.rightMonth = this.leftMonth + 1;
879
+ this.rightYear = this.leftYear;
880
+ if (this.rightMonth > 11) {
881
+ this.rightMonth = 0;
882
+ this.rightYear++;
883
+ }
884
+ this.generateDualCalendars();
885
+ }
886
+ this.emitSelection();
887
+ }
888
+ chooseRange(key) {
889
+ if (!this.customRanges)
890
+ return;
891
+ // Don't allow selecting "Custom Range" directly - it's only activated when manually selecting dates
892
+ if (key === 'Custom Range')
893
+ return;
894
+ const r = this.customRanges[key];
895
+ if (!r)
896
+ return;
897
+ this.startDate = new Date(r.start);
898
+ this.endDate = new Date(r.end);
899
+ this.selectedDates = [];
900
+ this.activeRange = key; // Set active range
901
+ // Navigate calendars to show the selected date range
902
+ if (this.dualCalendar) {
903
+ // For dual calendar: left always shows start date month
904
+ if (this.startDate) {
905
+ this.leftMonth = this.startDate.getMonth();
906
+ this.leftYear = this.startDate.getFullYear();
907
+ }
908
+ // Right calendar logic
909
+ if (this.endDate && this.startDate) {
910
+ const startMonth = this.startDate.getMonth();
911
+ const startYear = this.startDate.getFullYear();
912
+ const endMonth = this.endDate.getMonth();
913
+ const endYear = this.endDate.getFullYear();
914
+ // Only move right calendar if end date is in a different month than start date
915
+ if (endMonth !== startMonth || endYear !== startYear) {
916
+ this.rightMonth = endMonth;
917
+ this.rightYear = endYear;
918
+ }
919
+ else {
920
+ // If both dates are in same month, reset right calendar to default position (next month after left)
921
+ this.rightMonth = this.leftMonth + 1;
922
+ this.rightYear = this.leftYear;
923
+ if (this.rightMonth > 11) {
924
+ this.rightMonth = 0;
925
+ this.rightYear++;
926
+ }
927
+ }
928
+ }
929
+ else if (this.endDate && !this.startDate) {
930
+ // If only end date exists, show it in right calendar
931
+ this.rightMonth = this.endDate.getMonth();
932
+ this.rightYear = this.endDate.getFullYear();
933
+ }
934
+ else {
935
+ // If no end date, reset right calendar to default position
936
+ this.rightMonth = this.leftMonth + 1;
937
+ this.rightYear = this.leftYear;
938
+ if (this.rightMonth > 11) {
939
+ this.rightMonth = 0;
940
+ this.rightYear++;
941
+ }
942
+ }
943
+ this.generateDualCalendars();
944
+ }
945
+ else {
946
+ // For single calendar: show the start date month (or end date if only end date exists)
947
+ if (this.startDate) {
948
+ this.month = this.startDate.getMonth();
949
+ this.year = this.startDate.getFullYear();
950
+ }
951
+ else if (this.endDate) {
952
+ this.month = this.endDate.getMonth();
953
+ this.year = this.endDate.getFullYear();
954
+ }
955
+ this.generateCalendar();
956
+ }
957
+ this.emitSelection();
958
+ if (this.autoApply || this.closeOnAutoApply) {
959
+ this.close();
960
+ }
961
+ }
962
+ // emitSelection() {
963
+ // const selection: CalendarSelection = {
964
+ // startDate: this.startDate,
965
+ // endDate: this.endDate
966
+ // };
967
+ // if (this.multiDateSelection) {
968
+ // selection.selectedDates = [...this.selectedDates];
969
+ // }
970
+ // this.selected.emit(selection);
971
+ // }
972
+ emitSelection() {
973
+ const selection = {
974
+ startDate: this.startDate ? this.formatDateToString(this.startDate) : null,
975
+ endDate: this.endDate ? this.formatDateToString(this.endDate) : null,
976
+ };
977
+ if (this.multiDateSelection && this.selectedDates.length > 0) {
978
+ selection.selectedDates = this.selectedDates.map(d => this.formatDateToString(d));
979
+ }
980
+ this.selected.emit(selection);
981
+ }
982
+ addDays(date, days) {
983
+ const d = new Date(date);
984
+ d.setDate(d.getDate() + days);
985
+ return d;
986
+ }
987
+ generateCalendar() {
988
+ this.calendar = this.buildCalendar(this.year, this.month);
989
+ }
990
+ nextMonth() {
991
+ if (!this.dualCalendar) {
992
+ this.month++;
993
+ if (this.month > 11) {
994
+ this.month = 0;
995
+ this.year++;
996
+ }
997
+ this.generateCalendar();
998
+ return;
999
+ }
1000
+ // For dual calendar, this should not be used - use nextLeftMonth or nextRightMonth instead
1001
+ this.nextLeftMonth();
1002
+ }
1003
+ prevMonth() {
1004
+ if (!this.dualCalendar) {
1005
+ this.month--;
1006
+ if (this.month < 0) {
1007
+ this.month = 11;
1008
+ this.year--;
1009
+ }
1010
+ this.generateCalendar();
1011
+ return;
1012
+ }
1013
+ // For dual calendar, this should not be used - use prevLeftMonth or prevRightMonth instead
1014
+ this.prevLeftMonth();
1015
+ }
1016
+ // Independent navigation for left calendar
1017
+ nextLeftMonth() {
1018
+ this.leftMonth++;
1019
+ if (this.leftMonth > 11) {
1020
+ this.leftMonth = 0;
1021
+ this.leftYear++;
1022
+ }
1023
+ this.leftCalendar = this.buildCalendar(this.leftYear, this.leftMonth);
1024
+ }
1025
+ prevLeftMonth() {
1026
+ this.leftMonth--;
1027
+ if (this.leftMonth < 0) {
1028
+ this.leftMonth = 11;
1029
+ this.leftYear--;
1030
+ }
1031
+ this.leftCalendar = this.buildCalendar(this.leftYear, this.leftMonth);
1032
+ }
1033
+ // Independent navigation for right calendar
1034
+ nextRightMonth() {
1035
+ this.rightMonth++;
1036
+ if (this.rightMonth > 11) {
1037
+ this.rightMonth = 0;
1038
+ this.rightYear++;
1039
+ }
1040
+ this.rightCalendar = this.buildCalendar(this.rightYear, this.rightMonth);
1041
+ }
1042
+ prevRightMonth() {
1043
+ this.rightMonth--;
1044
+ if (this.rightMonth < 0) {
1045
+ this.rightMonth = 11;
1046
+ this.rightYear--;
1047
+ }
1048
+ this.rightCalendar = this.buildCalendar(this.rightYear, this.rightMonth);
1049
+ }
1050
+ initializeDual() {
1051
+ this.leftMonth = this.today.getMonth();
1052
+ this.leftYear = this.today.getFullYear();
1053
+ // Initialize right calendar to next month, but they can move independently
1054
+ this.rightMonth = this.leftMonth + 1;
1055
+ this.rightYear = this.leftYear;
1056
+ if (this.rightMonth > 11) {
1057
+ this.rightMonth = 0;
1058
+ this.rightYear++;
1059
+ }
1060
+ this.generateDualCalendars();
1061
+ }
1062
+ generateDualCalendars() {
1063
+ this.leftCalendar = this.buildCalendar(this.leftYear, this.leftMonth);
1064
+ this.rightCalendar = this.buildCalendar(this.rightYear, this.rightMonth);
1065
+ }
1066
+ buildCalendar(year, month) {
1067
+ const firstDay = new Date(year, month, 1).getDay();
1068
+ const daysInMonth = new Date(year, month + 1, 0).getDate();
1069
+ const prevMonthDays = new Date(year, month, 0).getDate();
1070
+ const grid = [];
1071
+ let row = [];
1072
+ // Adjust first day (0 = Sunday, 1 = Monday, etc.)
1073
+ const adjustedFirstDay = firstDay === 0 ? 6 : firstDay - 1; // Make Monday = 0
1074
+ for (let i = adjustedFirstDay - 1; i >= 0; i--) {
1075
+ row.push({ day: prevMonthDays - i, currentMonth: false });
1076
+ }
1077
+ for (let d = 1; d <= daysInMonth; d++) {
1078
+ row.push({ day: d, currentMonth: true });
1079
+ if (row.length === 7) {
1080
+ grid.push(row);
1081
+ row = [];
1082
+ }
1083
+ }
1084
+ let nextMonthDay = 1;
1085
+ while (row.length > 0 && row.length < 7) {
1086
+ row.push({ day: nextMonthDay++, currentMonth: false });
1087
+ }
1088
+ if (row.length)
1089
+ grid.push(row);
1090
+ // Ensure we always have 6 rows (42 cells total) for consistent layout
1091
+ while (grid.length < 6) {
1092
+ const newRow = [];
1093
+ for (let i = 0; i < 7; i++) {
1094
+ newRow.push({ day: nextMonthDay++, currentMonth: false });
1095
+ }
1096
+ grid.push(newRow);
1097
+ }
1098
+ return grid;
1099
+ }
1100
+ isDateSelected(year, month, day) {
1101
+ if (this.disableHighlight)
1102
+ return false;
1103
+ if (!day)
1104
+ return false;
1105
+ // Multi-date selection
1106
+ if (this.multiDateSelection) {
1107
+ return this.isDateInMultiSelection(year, month, day);
1108
+ }
1109
+ const cellDate = new Date(year, month, day);
1110
+ // Check if it's today (highlight today by default if no date selected)
1111
+ const today = new Date();
1112
+ const isToday = cellDate.getFullYear() === today.getFullYear() &&
1113
+ cellDate.getMonth() === today.getMonth() &&
1114
+ cellDate.getDate() === today.getDate();
1115
+ // If no startDate is set and it's today, highlight it
1116
+ if (!this.startDate && isToday) {
1117
+ return true;
1118
+ }
1119
+ if (!this.startDate)
1120
+ return false;
1121
+ // Check if date is disabled
1122
+ if (this.minDate && cellDate < this.minDate)
1123
+ return false;
1124
+ if (this.maxDate && cellDate > this.maxDate)
1125
+ return false;
1126
+ const sameDay = cellDate.getFullYear() === this.startDate.getFullYear() &&
1127
+ cellDate.getMonth() === this.startDate.getMonth() &&
1128
+ cellDate.getDate() === this.startDate.getDate();
1129
+ if (this.singleDatePicker)
1130
+ return sameDay;
1131
+ // For range selection: only highlight start and end dates (not in-between)
1132
+ if (this.startDate && this.endDate) {
1133
+ const start = new Date(this.startDate.getFullYear(), this.startDate.getMonth(), this.startDate.getDate());
1134
+ const end = new Date(this.endDate.getFullYear(), this.endDate.getMonth(), this.endDate.getDate());
1135
+ return cellDate.getTime() === start.getTime() || cellDate.getTime() === end.getTime();
1136
+ }
1137
+ // If only start date is selected and hovering, check if this is start or hovered end
1138
+ if (this.startDate && !this.endDate && this.hoveredDate) {
1139
+ const start = new Date(this.startDate.getFullYear(), this.startDate.getMonth(), this.startDate.getDate());
1140
+ const hovered = new Date(this.hoveredDate.getFullYear(), this.hoveredDate.getMonth(), this.hoveredDate.getDate());
1141
+ // Show both start and hovered date as selected (circular black)
1142
+ return cellDate.getTime() === start.getTime() || cellDate.getTime() === hovered.getTime();
1143
+ }
1144
+ return sameDay;
1145
+ }
1146
+ isDateInRange(year, month, day) {
1147
+ if (this.disableHighlight || !day)
1148
+ return false;
1149
+ if (this.singleDatePicker)
1150
+ return false;
1151
+ if (this.multiDateSelection)
1152
+ return false;
1153
+ const cellDate = new Date(year, month, day);
1154
+ // If both start and end are selected, show gray background for dates in between
1155
+ if (this.startDate && this.endDate) {
1156
+ const start = new Date(this.startDate.getFullYear(), this.startDate.getMonth(), this.startDate.getDate());
1157
+ const end = new Date(this.endDate.getFullYear(), this.endDate.getMonth(), this.endDate.getDate());
1158
+ return cellDate > start && cellDate < end;
1159
+ }
1160
+ // If only start is selected and hovering, show preview range
1161
+ if (this.startDate && !this.endDate && this.hoveredDate) {
1162
+ const start = new Date(this.startDate.getFullYear(), this.startDate.getMonth(), this.startDate.getDate());
1163
+ const hovered = new Date(this.hoveredDate.getFullYear(), this.hoveredDate.getMonth(), this.hoveredDate.getDate());
1164
+ // Determine which is earlier - show gray background for dates between them
1165
+ const minDate = hovered < start ? hovered : start;
1166
+ const maxDate = hovered >= start ? hovered : start;
1167
+ return cellDate > minDate && cellDate < maxDate;
1168
+ }
1169
+ return false;
1170
+ }
1171
+ isDateDisabled(year, month, day) {
1172
+ if (!day)
1173
+ return false;
1174
+ const cellDate = new Date(year, month, day);
1175
+ if (this.minDate && cellDate < this.minDate)
1176
+ return true;
1177
+ if (this.maxDate && cellDate > this.maxDate)
1178
+ return true;
1179
+ return false;
1180
+ }
1181
+ isToday(year, month, day) {
1182
+ if (!day)
1183
+ return false;
1184
+ const today = new Date();
1185
+ const cellDate = new Date(year, month, day);
1186
+ return cellDate.getFullYear() === today.getFullYear() &&
1187
+ cellDate.getMonth() === today.getMonth() &&
1188
+ cellDate.getDate() === today.getDate();
1189
+ }
1190
+ getDisplayValue() {
1191
+ if (this.multiDateSelection && this.selectedDates.length > 0) {
1192
+ if (this.selectedDates.length === 1) {
1193
+ return moment(this.selectedDates[0]).format(this.displayFormat);
1194
+ }
1195
+ return `${this.selectedDates.length} dates selected`;
1196
+ }
1197
+ if (!this.startDate)
1198
+ return '';
1199
+ // Prefer moment formatting for consistent display
1200
+ let dateStr = moment(this.startDate).format(this.displayFormat);
1201
+ if (this.enableTimepicker && !this.dualCalendar) {
1202
+ const hr = this.startDate.getHours().toString().padStart(2, '0');
1203
+ const min = this.startDate.getMinutes().toString().padStart(2, '0');
1204
+ dateStr += ` ${hr}:${min}`;
1205
+ if (this.enableSeconds) {
1206
+ const sec = this.startDate.getSeconds().toString().padStart(2, '0');
1207
+ dateStr += `:${sec}`;
1208
+ }
1209
+ }
1210
+ if (this.endDate && !this.singleDatePicker) {
1211
+ let endStr = moment(this.endDate).format(this.displayFormat);
1212
+ if (this.enableTimepicker) {
1213
+ if (this.dualCalendar) {
1214
+ const startHr = this.startDate.getHours().toString().padStart(2, '0');
1215
+ const startMin = this.startDate.getMinutes().toString().padStart(2, '0');
1216
+ dateStr += ` ${startHr}:${startMin}`;
1217
+ if (this.enableSeconds) {
1218
+ const startSec = this.startDate.getSeconds().toString().padStart(2, '0');
1219
+ dateStr += `:${startSec}`;
1220
+ }
1221
+ }
1222
+ const endHr = this.endDate.getHours().toString().padStart(2, '0');
1223
+ const endMin = this.endDate.getMinutes().toString().padStart(2, '0');
1224
+ endStr += ` ${endHr}:${endMin}`;
1225
+ if (this.enableSeconds) {
1226
+ const endSec = this.endDate.getSeconds().toString().padStart(2, '0');
1227
+ endStr += `:${endSec}`;
1228
+ }
1229
+ }
1230
+ return `${dateStr} - ${endStr}`;
1231
+ }
1232
+ return dateStr;
1233
+ }
1234
+ // Time picker helpers
1235
+ getTimeInputValue(isStart = true) {
1236
+ const h = isStart ? this.startHour : this.endHour;
1237
+ const m = isStart ? this.startMinute : this.endMinute;
1238
+ return `${h.toString().padStart(2, '0')}:${m.toString().padStart(2, '0')}`;
1239
+ }
1240
+ getSingleTimeInputValue() {
1241
+ return `${this.selectedHour.toString().padStart(2, '0')}:${this.selectedMinute.toString().padStart(2, '0')}`;
1242
+ }
1243
+ // NEW: Helper to build display value for BkTimePicker (single calendar)
1244
+ getSingleTimePickerDisplay() {
1245
+ const hour = this.selectedHour || 12;
1246
+ const minuteStr = this.selectedMinute.toString().padStart(2, '0');
1247
+ const ampm = this.selectedAMPM || 'AM';
1248
+ return `${hour}:${minuteStr} ${ampm}`;
1249
+ }
1250
+ // NEW: Helper to build display value for BkTimePicker (dual calendar)
1251
+ getDualTimePickerDisplay(isStart = true) {
1252
+ const hour = isStart ? (this.startHour || 12) : (this.endHour || 12);
1253
+ const minute = isStart ? this.startMinute : this.endMinute;
1254
+ const ampm = isStart ? (this.startAMPM || 'AM') : (this.endAMPM || 'AM');
1255
+ const minuteStr = minute.toString().padStart(2, '0');
1256
+ return `${hour}:${minuteStr} ${ampm}`;
1257
+ }
1258
+ // Coordination helpers for embedded BkTimePicker instances
1259
+ onTimePickerOpened(pickerId) {
1260
+ // Close previously open picker inside this calendar
1261
+ if (this.openTimePickerId && this.openTimePickerId !== pickerId) {
1262
+ if (!this.closePickerCounter[this.openTimePickerId]) {
1263
+ this.closePickerCounter[this.openTimePickerId] = 0;
1264
+ }
1265
+ this.closePickerCounter[this.openTimePickerId]++;
1266
+ }
1267
+ this.openTimePickerId = pickerId;
1268
+ }
1269
+ onTimePickerClosed(pickerId) {
1270
+ if (this.openTimePickerId === pickerId) {
1271
+ this.openTimePickerId = null;
1272
+ }
1273
+ }
1274
+ shouldClosePicker(pickerId) {
1275
+ return this.closePickerCounter[pickerId] || 0;
1276
+ }
1277
+ // NEW: Parse "H:MM AM/PM" (or "HH:MM" 24h) from BkTimePicker
1278
+ parsePickerTimeString(timeStr) {
1279
+ if (!timeStr) {
1280
+ return { hour12: 12, minute: 0, ampm: 'AM' };
1281
+ }
1282
+ const parts = timeStr.trim().split(' ');
1283
+ const timePart = parts[0] || '12:00';
1284
+ let ampmPart = (parts[1] || '').toUpperCase();
1285
+ const [hourStr, minuteStr] = timePart.split(':');
1286
+ let hour = parseInt(hourStr || '12', 10);
1287
+ const minute = parseInt(minuteStr || '0', 10);
1288
+ if (ampmPart !== 'AM' && ampmPart !== 'PM') {
1289
+ // Interpret as 24-hour input and convert
1290
+ if (hour >= 12) {
1291
+ ampmPart = 'PM';
1292
+ if (hour > 12)
1293
+ hour -= 12;
1294
+ }
1295
+ else {
1296
+ ampmPart = 'AM';
1297
+ if (hour === 0)
1298
+ hour = 12;
1299
+ }
1300
+ }
1301
+ // Clamp to 1-12 range just in case
1302
+ if (hour < 1)
1303
+ hour = 1;
1304
+ if (hour > 12)
1305
+ hour = 12;
1306
+ return { hour12: hour, minute, ampm: ampmPart };
1307
+ }
1308
+ // NEW: Handle BkTimePicker change for single calendar
1309
+ onSingleTimePickerChange(time) {
1310
+ const { hour12, minute, ampm } = this.parsePickerTimeString(time);
1311
+ this.selectedHour = hour12;
1312
+ this.selectedMinute = minute;
1313
+ this.selectedAMPM = ampm;
1314
+ if (this.startDate) {
1315
+ let h24 = hour12;
1316
+ if (ampm === 'PM' && h24 < 12)
1317
+ h24 += 12;
1318
+ if (ampm === 'AM' && h24 === 12)
1319
+ h24 = 0;
1320
+ this.startDate.setHours(h24, minute, this.selectedSecond);
1321
+ this.emitSelection();
1322
+ }
1323
+ }
1324
+ // NEW: Handle BkTimePicker change for dual calendar
1325
+ onDualTimePickerChange(time, isStart = true) {
1326
+ const { hour12, minute, ampm } = this.parsePickerTimeString(time);
1327
+ if (isStart) {
1328
+ this.startHour = hour12;
1329
+ this.startMinute = minute;
1330
+ this.startAMPM = ampm;
1331
+ if (this.startDate) {
1332
+ let h24 = hour12;
1333
+ if (ampm === 'PM' && h24 < 12)
1334
+ h24 += 12;
1335
+ if (ampm === 'AM' && h24 === 12)
1336
+ h24 = 0;
1337
+ this.startDate.setHours(h24, minute, this.startSecond);
1338
+ }
1339
+ }
1340
+ else {
1341
+ this.endHour = hour12;
1342
+ this.endMinute = minute;
1343
+ this.endAMPM = ampm;
1344
+ if (this.endDate) {
1345
+ let h24 = hour12;
1346
+ if (ampm === 'PM' && h24 < 12)
1347
+ h24 += 12;
1348
+ if (ampm === 'AM' && h24 === 12)
1349
+ h24 = 0;
1350
+ this.endDate.setHours(h24, minute, this.endSecond);
1351
+ }
1352
+ }
1353
+ this.emitSelection();
1354
+ }
1355
+ onTimeChange(event, isStart = true) {
1356
+ const [h, m] = event.target.value.split(':').map(Number);
1357
+ if (isStart) {
1358
+ this.startHour = h;
1359
+ this.startMinute = m;
1360
+ if (this.startDate) {
1361
+ this.startDate.setHours(h, m, this.startSecond);
1362
+ this.emitSelection();
1363
+ }
1364
+ }
1365
+ else {
1366
+ this.endHour = h;
1367
+ this.endMinute = m;
1368
+ if (this.endDate) {
1369
+ this.endDate.setHours(h, m, this.endSecond);
1370
+ this.emitSelection();
1371
+ }
1372
+ }
1373
+ }
1374
+ onSingleTimeChange(event) {
1375
+ const [h, m] = event.target.value.split(':').map(Number);
1376
+ this.selectedHour = h;
1377
+ this.selectedMinute = m;
1378
+ if (this.startDate) {
1379
+ this.startDate.setHours(h, m, this.selectedSecond);
1380
+ this.emitSelection();
1381
+ }
1382
+ }
1383
+ // Custom time picker controls
1384
+ incrementHour(isStart = true) {
1385
+ // 12-hour format: 1-12
1386
+ if (isStart) {
1387
+ this.startHour = this.startHour >= 12 ? 1 : this.startHour + 1;
1388
+ // Toggle AM/PM at 12
1389
+ if (this.startHour === 12) {
1390
+ this.startAMPM = this.startAMPM === 'AM' ? 'PM' : 'AM';
1391
+ }
1392
+ if (this.startDate) {
1393
+ let h = this.startHour;
1394
+ if (this.startAMPM === 'PM' && h < 12)
1395
+ h += 12;
1396
+ if (this.startAMPM === 'AM' && h === 12)
1397
+ h = 0;
1398
+ this.startDate.setHours(h, this.startMinute, this.startSecond);
1399
+ }
1400
+ }
1401
+ else {
1402
+ this.endHour = this.endHour >= 12 ? 1 : this.endHour + 1;
1403
+ // Toggle AM/PM at 12
1404
+ if (this.endHour === 12) {
1405
+ this.endAMPM = this.endAMPM === 'AM' ? 'PM' : 'AM';
1406
+ }
1407
+ if (this.endDate) {
1408
+ let h = this.endHour;
1409
+ if (this.endAMPM === 'PM' && h < 12)
1410
+ h += 12;
1411
+ if (this.endAMPM === 'AM' && h === 12)
1412
+ h = 0;
1413
+ this.endDate.setHours(h, this.endMinute, this.endSecond);
1414
+ }
1415
+ }
1416
+ this.emitSelection();
1417
+ }
1418
+ decrementHour(isStart = true) {
1419
+ // 12-hour format: 1-12
1420
+ if (isStart) {
1421
+ this.startHour = this.startHour <= 1 ? 12 : this.startHour - 1;
1422
+ // Toggle AM/PM at 12
1423
+ if (this.startHour === 12) {
1424
+ this.startAMPM = this.startAMPM === 'AM' ? 'PM' : 'AM';
1425
+ }
1426
+ if (this.startDate) {
1427
+ let h = this.startHour;
1428
+ if (this.startAMPM === 'PM' && h < 12)
1429
+ h += 12;
1430
+ if (this.startAMPM === 'AM' && h === 12)
1431
+ h = 0;
1432
+ this.startDate.setHours(h, this.startMinute, this.startSecond);
1433
+ }
1434
+ }
1435
+ else {
1436
+ this.endHour = this.endHour <= 1 ? 12 : this.endHour - 1;
1437
+ // Toggle AM/PM at 12
1438
+ if (this.endHour === 12) {
1439
+ this.endAMPM = this.endAMPM === 'AM' ? 'PM' : 'AM';
1440
+ }
1441
+ if (this.endDate) {
1442
+ let h = this.endHour;
1443
+ if (this.endAMPM === 'PM' && h < 12)
1444
+ h += 12;
1445
+ if (this.endAMPM === 'AM' && h === 12)
1446
+ h = 0;
1447
+ this.endDate.setHours(h, this.endMinute, this.endSecond);
1448
+ }
1449
+ }
1450
+ this.emitSelection();
1451
+ }
1452
+ incrementMinute(isStart = true) {
1453
+ if (isStart) {
1454
+ this.startMinute = (this.startMinute + 1) % 60;
1455
+ if (this.startDate) {
1456
+ let h = this.startHour;
1457
+ if (this.startAMPM === 'PM' && h < 12)
1458
+ h += 12;
1459
+ if (this.startAMPM === 'AM' && h === 12)
1460
+ h = 0;
1461
+ this.startDate.setHours(h, this.startMinute, this.startSecond);
1462
+ }
1463
+ }
1464
+ else {
1465
+ this.endMinute = (this.endMinute + 1) % 60;
1466
+ if (this.endDate) {
1467
+ let h = this.endHour;
1468
+ if (this.endAMPM === 'PM' && h < 12)
1469
+ h += 12;
1470
+ if (this.endAMPM === 'AM' && h === 12)
1471
+ h = 0;
1472
+ this.endDate.setHours(h, this.endMinute, this.endSecond);
1473
+ }
1474
+ }
1475
+ this.emitSelection();
1476
+ }
1477
+ decrementMinute(isStart = true) {
1478
+ if (isStart) {
1479
+ this.startMinute = this.startMinute <= 0 ? 59 : this.startMinute - 1;
1480
+ if (this.startDate) {
1481
+ let h = this.startHour;
1482
+ if (this.startAMPM === 'PM' && h < 12)
1483
+ h += 12;
1484
+ if (this.startAMPM === 'AM' && h === 12)
1485
+ h = 0;
1486
+ this.startDate.setHours(h, this.startMinute, this.startSecond);
1487
+ }
1488
+ }
1489
+ else {
1490
+ this.endMinute = this.endMinute <= 0 ? 59 : this.endMinute - 1;
1491
+ if (this.endDate) {
1492
+ let h = this.endHour;
1493
+ if (this.endAMPM === 'PM' && h < 12)
1494
+ h += 12;
1495
+ if (this.endAMPM === 'AM' && h === 12)
1496
+ h = 0;
1497
+ this.endDate.setHours(h, this.endMinute, this.endSecond);
1498
+ }
1499
+ }
1500
+ this.emitSelection();
1501
+ }
1502
+ toggleAMPM(isStart = true) {
1503
+ if (isStart) {
1504
+ this.startAMPM = this.startAMPM === 'AM' ? 'PM' : 'AM';
1505
+ if (this.startDate) {
1506
+ let h = this.startHour;
1507
+ if (this.startAMPM === 'PM' && h < 12)
1508
+ h += 12;
1509
+ if (this.startAMPM === 'AM' && h === 12)
1510
+ h = 0;
1511
+ this.startDate.setHours(h, this.startMinute, this.startSecond);
1512
+ }
1513
+ }
1514
+ else {
1515
+ this.endAMPM = this.endAMPM === 'AM' ? 'PM' : 'AM';
1516
+ if (this.endDate) {
1517
+ let h = this.endHour;
1518
+ if (this.endAMPM === 'PM' && h < 12)
1519
+ h += 12;
1520
+ if (this.endAMPM === 'AM' && h === 12)
1521
+ h = 0;
1522
+ this.endDate.setHours(h, this.endMinute, this.endSecond);
1523
+ }
1524
+ }
1525
+ this.emitSelection();
1526
+ }
1527
+ // Single calendar time picker controls (12-hour format: 1-12)
1528
+ incrementSingleHour() {
1529
+ this.selectedHour = this.selectedHour >= 12 ? 1 : this.selectedHour + 1;
1530
+ // Toggle AM/PM at 12
1531
+ if (this.selectedHour === 12) {
1532
+ this.selectedAMPM = this.selectedAMPM === 'AM' ? 'PM' : 'AM';
1533
+ }
1534
+ if (this.startDate) {
1535
+ let h = this.selectedHour;
1536
+ if (this.selectedAMPM === 'PM' && h < 12)
1537
+ h += 12;
1538
+ if (this.selectedAMPM === 'AM' && h === 12)
1539
+ h = 0;
1540
+ this.startDate.setHours(h, this.selectedMinute, this.selectedSecond);
1541
+ this.emitSelection();
1542
+ }
1543
+ }
1544
+ decrementSingleHour() {
1545
+ this.selectedHour = this.selectedHour <= 1 ? 12 : this.selectedHour - 1;
1546
+ // Toggle AM/PM at 12
1547
+ if (this.selectedHour === 12) {
1548
+ this.selectedAMPM = this.selectedAMPM === 'AM' ? 'PM' : 'AM';
1549
+ }
1550
+ if (this.startDate) {
1551
+ let h = this.selectedHour;
1552
+ if (this.selectedAMPM === 'PM' && h < 12)
1553
+ h += 12;
1554
+ if (this.selectedAMPM === 'AM' && h === 12)
1555
+ h = 0;
1556
+ this.startDate.setHours(h, this.selectedMinute, this.selectedSecond);
1557
+ this.emitSelection();
1558
+ }
1559
+ }
1560
+ incrementSingleMinute() {
1561
+ this.selectedMinute = (this.selectedMinute + 1) % 60;
1562
+ if (this.startDate) {
1563
+ let h = this.selectedHour;
1564
+ if (this.selectedAMPM === 'PM' && h < 12)
1565
+ h += 12;
1566
+ if (this.selectedAMPM === 'AM' && h === 12)
1567
+ h = 0;
1568
+ this.startDate.setHours(h, this.selectedMinute, this.selectedSecond);
1569
+ this.emitSelection();
1570
+ }
1571
+ }
1572
+ decrementSingleMinute() {
1573
+ this.selectedMinute = this.selectedMinute <= 0 ? 59 : this.selectedMinute - 1;
1574
+ if (this.startDate) {
1575
+ let h = this.selectedHour;
1576
+ if (this.selectedAMPM === 'PM' && h < 12)
1577
+ h += 12;
1578
+ if (this.selectedAMPM === 'AM' && h === 12)
1579
+ h = 0;
1580
+ this.startDate.setHours(h, this.selectedMinute, this.selectedSecond);
1581
+ this.emitSelection();
1582
+ }
1583
+ }
1584
+ toggleSingleAMPM() {
1585
+ this.selectedAMPM = this.selectedAMPM === 'AM' ? 'PM' : 'AM';
1586
+ if (this.startDate) {
1587
+ let h = this.selectedHour;
1588
+ if (this.selectedAMPM === 'PM' && h < 12)
1589
+ h += 12;
1590
+ if (this.selectedAMPM === 'AM' && h === 12)
1591
+ h = 0;
1592
+ this.startDate.setHours(h, this.selectedMinute, this.selectedSecond);
1593
+ this.emitSelection();
1594
+ }
1595
+ }
1596
+ getMonthName(month) {
1597
+ const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
1598
+ return months[month];
1599
+ }
1600
+ // Input handlers for direct hour/minute input (12-hour format only)
1601
+ onHourInput(event, isStart = true, isSingle = false) {
1602
+ const inputValue = event.target.value;
1603
+ // Allow empty input while typing
1604
+ if (inputValue === '' || inputValue === null || inputValue === undefined) {
1605
+ return;
1606
+ }
1607
+ let value = parseInt(inputValue) || 0;
1608
+ // Validate: 1-12 for 12-hour format
1609
+ if (value < 1)
1610
+ value = 1;
1611
+ if (value > 12)
1612
+ value = 12;
1613
+ if (isSingle) {
1614
+ this.selectedHour = value;
1615
+ if (this.startDate) {
1616
+ let h = value;
1617
+ if (this.selectedAMPM === 'PM' && h < 12)
1618
+ h += 12;
1619
+ if (this.selectedAMPM === 'AM' && h === 12)
1620
+ h = 0;
1621
+ this.startDate.setHours(h, this.selectedMinute, this.selectedSecond);
1622
+ this.emitSelection();
1623
+ }
1624
+ }
1625
+ else if (isStart) {
1626
+ this.startHour = value;
1627
+ if (this.startDate) {
1628
+ let h = value;
1629
+ if (this.startAMPM === 'PM' && h < 12)
1630
+ h += 12;
1631
+ if (this.startAMPM === 'AM' && h === 12)
1632
+ h = 0;
1633
+ this.startDate.setHours(h, this.startMinute, this.startSecond);
1634
+ this.emitSelection();
1635
+ }
1636
+ }
1637
+ else {
1638
+ this.endHour = value;
1639
+ if (this.endDate) {
1640
+ let h = value;
1641
+ if (this.endAMPM === 'PM' && h < 12)
1642
+ h += 12;
1643
+ if (this.endAMPM === 'AM' && h === 12)
1644
+ h = 0;
1645
+ this.endDate.setHours(h, this.endMinute, this.endSecond);
1646
+ this.emitSelection();
1647
+ }
1648
+ }
1649
+ // Don't format during input, only on blur
1650
+ event.target.value = value.toString();
1651
+ }
1652
+ onHourBlur(event, isStart = true, isSingle = false) {
1653
+ const inputValue = event.target.value;
1654
+ if (inputValue === '' || inputValue === null || inputValue === undefined) {
1655
+ // If empty, set to current value
1656
+ const currentValue = isSingle ? this.selectedHour : (isStart ? this.startHour : this.endHour);
1657
+ event.target.value = currentValue.toString();
1658
+ return;
1659
+ }
1660
+ let value = parseInt(inputValue) || 0;
1661
+ if (value < 1)
1662
+ value = 1;
1663
+ if (value > 12)
1664
+ value = 12;
1665
+ // Format to single digit (no padding for hours in 12-hour format)
1666
+ event.target.value = value.toString();
1667
+ // Update the value
1668
+ if (isSingle) {
1669
+ this.selectedHour = value;
1670
+ if (this.startDate) {
1671
+ let h = value;
1672
+ if (this.selectedAMPM === 'PM' && h < 12)
1673
+ h += 12;
1674
+ if (this.selectedAMPM === 'AM' && h === 12)
1675
+ h = 0;
1676
+ this.startDate.setHours(h, this.selectedMinute, this.selectedSecond);
1677
+ this.emitSelection();
1678
+ }
1679
+ }
1680
+ else if (isStart) {
1681
+ this.startHour = value;
1682
+ if (this.startDate) {
1683
+ let h = value;
1684
+ if (this.startAMPM === 'PM' && h < 12)
1685
+ h += 12;
1686
+ if (this.startAMPM === 'AM' && h === 12)
1687
+ h = 0;
1688
+ this.startDate.setHours(h, this.startMinute, this.startSecond);
1689
+ this.emitSelection();
1690
+ }
1691
+ }
1692
+ else {
1693
+ this.endHour = value;
1694
+ if (this.endDate) {
1695
+ let h = value;
1696
+ if (this.endAMPM === 'PM' && h < 12)
1697
+ h += 12;
1698
+ if (this.endAMPM === 'AM' && h === 12)
1699
+ h = 0;
1700
+ this.endDate.setHours(h, this.endMinute, this.endSecond);
1701
+ this.emitSelection();
1702
+ }
1703
+ }
1704
+ }
1705
+ onMinuteInput(event, isStart = true, isSingle = false) {
1706
+ const inputValue = event.target.value;
1707
+ const key = `${isStart ? 'start' : 'end'}_${isSingle ? 'single' : 'dual'}`;
1708
+ // Remove any non-digit characters
1709
+ const digitsOnly = inputValue.replace(/\D/g, '');
1710
+ // Store raw input value for display
1711
+ this.minuteInputValues[key] = digitsOnly;
1712
+ // Allow empty input while typing
1713
+ if (digitsOnly === '' || digitsOnly === null || digitsOnly === undefined) {
1714
+ return; // Don't modify the input, let user clear it
1715
+ }
1716
+ // Allow typing up to 2 digits without formatting
1717
+ let value = parseInt(digitsOnly) || 0;
1718
+ // If user types more than 2 digits, take only first 2
1719
+ if (digitsOnly.length > 2) {
1720
+ value = parseInt(digitsOnly.substring(0, 2));
1721
+ this.minuteInputValues[key] = digitsOnly.substring(0, 2);
1722
+ event.target.value = digitsOnly.substring(0, 2);
1723
+ }
1724
+ // If value exceeds 59, clamp it to 59
1725
+ if (value > 59) {
1726
+ value = 59;
1727
+ this.minuteInputValues[key] = '59';
1728
+ event.target.value = '59';
1729
+ }
1730
+ // Update the internal value silently (don't emit during typing to avoid re-rendering)
1731
+ if (isSingle) {
1732
+ this.selectedMinute = value;
1733
+ }
1734
+ else if (isStart) {
1735
+ this.startMinute = value;
1736
+ }
1737
+ else {
1738
+ this.endMinute = value;
1739
+ }
1740
+ // Don't update dates or emit during typing - wait for blur or apply
1741
+ }
1742
+ onMinuteBlur(event, isStart = true, isSingle = false) {
1743
+ const key = `${isStart ? 'start' : 'end'}_${isSingle ? 'single' : 'dual'}`;
1744
+ const inputValue = event.target.value;
1745
+ if (inputValue === '' || inputValue === null || inputValue === undefined) {
1746
+ // If empty, set to current value
1747
+ const currentValue = isSingle ? this.selectedMinute : (isStart ? this.startMinute : this.endMinute);
1748
+ event.target.value = currentValue.toString().padStart(2, '0');
1749
+ delete this.minuteInputValues[key];
1750
+ return;
1751
+ }
1752
+ const digitsOnly = inputValue.replace(/\D/g, '');
1753
+ let value = parseInt(digitsOnly) || 0;
1754
+ if (value < 0)
1755
+ value = 0;
1756
+ if (value > 59)
1757
+ value = 59;
1758
+ // Format to 2 digits on blur (01-09 becomes 01-09, 10-59 stays as is)
1759
+ event.target.value = value.toString().padStart(2, '0');
1760
+ delete this.minuteInputValues[key]; // Clear raw input, use formatted value
1761
+ // Update the value
1762
+ if (isSingle) {
1763
+ this.selectedMinute = value;
1764
+ if (this.startDate) {
1765
+ let h = this.selectedHour;
1766
+ if (this.selectedAMPM === 'PM' && h < 12)
1767
+ h += 12;
1768
+ if (this.selectedAMPM === 'AM' && h === 12)
1769
+ h = 0;
1770
+ this.startDate.setHours(h, this.selectedMinute, this.selectedSecond);
1771
+ this.emitSelection();
1772
+ }
1773
+ }
1774
+ else if (isStart) {
1775
+ this.startMinute = value;
1776
+ if (this.startDate) {
1777
+ let h = this.startHour;
1778
+ if (this.startAMPM === 'PM' && h < 12)
1779
+ h += 12;
1780
+ if (this.startAMPM === 'AM' && h === 12)
1781
+ h = 0;
1782
+ this.startDate.setHours(h, this.startMinute, this.startSecond);
1783
+ this.emitSelection();
1784
+ }
1785
+ }
1786
+ else {
1787
+ this.endMinute = value;
1788
+ if (this.endDate) {
1789
+ let h = this.endHour;
1790
+ if (this.endAMPM === 'PM' && h < 12)
1791
+ h += 12;
1792
+ if (this.endAMPM === 'AM' && h === 12)
1793
+ h = 0;
1794
+ this.endDate.setHours(h, this.endMinute, this.endSecond);
1795
+ this.emitSelection();
1796
+ }
1797
+ }
1798
+ }
1799
+ // Get display value for hour (always 12-hour format)
1800
+ getDisplayHour(hour) {
1801
+ if (hour === 0)
1802
+ return 12;
1803
+ if (hour > 12)
1804
+ return hour - 12;
1805
+ return hour;
1806
+ }
1807
+ // Get display value for minute (formatted only when not actively typing)
1808
+ getMinuteDisplayValue(isStart, isSingle) {
1809
+ const key = `${isStart ? 'start' : 'end'}_${isSingle ? 'single' : 'dual'}`;
1810
+ // If user is typing (has raw input), show that, otherwise show formatted value
1811
+ if (this.minuteInputValues[key] !== undefined) {
1812
+ return this.minuteInputValues[key];
1813
+ }
1814
+ // Otherwise return formatted value
1815
+ const value = isSingle ? this.selectedMinute : (isStart ? this.startMinute : this.endMinute);
1816
+ return value.toString().padStart(2, '0');
1817
+ }
1818
+ // Helper method to apply time picker values to a date
1819
+ applyTimeToDate(date, isStart) {
1820
+ if (this.dualCalendar) {
1821
+ if (isStart) {
1822
+ let h = this.startHour;
1823
+ if (this.startAMPM === 'PM' && h < 12)
1824
+ h += 12;
1825
+ if (this.startAMPM === 'AM' && h === 12)
1826
+ h = 0;
1827
+ date.setHours(h, this.startMinute, this.startSecond);
1828
+ }
1829
+ else {
1830
+ let h = this.endHour;
1831
+ if (this.endAMPM === 'PM' && h < 12)
1832
+ h += 12;
1833
+ if (this.endAMPM === 'AM' && h === 12)
1834
+ h = 0;
1835
+ date.setHours(h, this.endMinute, this.endSecond);
1836
+ }
1837
+ }
1838
+ else {
1839
+ let h = this.selectedHour;
1840
+ if (this.selectedAMPM === 'PM' && h < 12)
1841
+ h += 12;
1842
+ if (this.selectedAMPM === 'AM' && h === 12)
1843
+ h = 0;
1844
+ date.setHours(h, this.selectedMinute, this.selectedSecond);
1845
+ }
1846
+ }
1847
+ // Select all text on focus for easy replacement
1848
+ onTimeInputFocus(event) {
1849
+ event.target.select();
1850
+ }
1851
+ // Format all minute inputs to 2 digits (called before Apply)
1852
+ formatAllMinuteInputs() {
1853
+ // Format minute inputs in the DOM - find all minute inputs and format single digits
1854
+ const inputs = document.querySelectorAll('.time-input');
1855
+ inputs.forEach((input) => {
1856
+ const value = parseInt(input.value);
1857
+ // If it's a valid minute value (0-59) and not already formatted (single digit or 2 digits without leading zero)
1858
+ if (!isNaN(value) && value >= 0 && value <= 59) {
1859
+ // Format if it's a single digit (1-9) or if it's 2 digits but the first is not 0
1860
+ if (input.value.length === 1 || (input.value.length === 2 && !input.value.startsWith('0') && value < 10)) {
1861
+ input.value = value.toString().padStart(2, '0');
1862
+ }
1863
+ }
1864
+ });
1865
+ }
1866
+ formatDateToString(date) {
1867
+ const yyyy = date.getFullYear();
1868
+ const mm = (date.getMonth() + 1).toString().padStart(2, '0'); // month is 0-based
1869
+ const dd = date.getDate().toString().padStart(2, '0');
1870
+ return `${yyyy}-${mm}-${dd}`;
1871
+ }
1872
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkCustomCalendar, deps: [{ token: CalendarManagerService }], target: i0.ɵɵFactoryTarget.Component });
1873
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: BkCustomCalendar, isStandalone: true, selector: "bk-custom-calendar", inputs: { enableTimepicker: "enableTimepicker", autoApply: "autoApply", closeOnAutoApply: "closeOnAutoApply", showCancel: "showCancel", linkedCalendars: "linkedCalendars", singleDatePicker: "singleDatePicker", showWeekNumbers: "showWeekNumbers", showISOWeekNumbers: "showISOWeekNumbers", customRangeDirection: "customRangeDirection", lockStartDate: "lockStartDate", position: "position", drop: "drop", dualCalendar: "dualCalendar", showRanges: "showRanges", timeFormat: "timeFormat", enableSeconds: "enableSeconds", customRanges: "customRanges", multiDateSelection: "multiDateSelection", maxDate: "maxDate", minDate: "minDate", placeholder: "placeholder", opens: "opens", inline: "inline", isDisplayCrossIcon: "isDisplayCrossIcon", selectedValue: "selectedValue", displayFormat: "displayFormat", startDate: "startDate", endDate: "endDate" }, outputs: { selected: "selected", opened: "opened", closed: "closed" }, host: { listeners: { "document:click": "onClickOutside($event)" } }, usesOnChanges: true, ngImport: i0, template: "<div class=\"calendar-container relative\" [class.open]=\"show\" [class.inline-mode]=\"inline\">\r\n <!-- Input field -->\r\n <div class=\"input-wrapper\" *ngIf=\"!inline\">\r\n <input\r\n type=\"text\"\r\n (click)=\"toggle()\"\r\n readonly\r\n [value]=\"getDisplayValue()\"\r\n [placeholder]=\"placeholder\"\r\n class=\"calendar-input\">\r\n <!-- *ngIf=\"!getDisplayValue()\" -->\r\n\r\n <span class=\"calendar-icon\" >\r\n <img alt=\"calendar\" class=\"calendar-icon-img\" [src]='brickclayIcons.calenderIcon'/>\r\n </span>\r\n <button class=\"clear-btn\" *ngIf=\"getDisplayValue() && isDisplayCrossIcon\" (click)=\"clear(); $event.stopPropagation()\" title=\"Clear\">\u00D7</button>\r\n </div>\r\n\r\n <!-- Calendar Popup / Inline -->\r\n <div class=\"calendar-popup\"\r\n [class.inline-calendar]=\"inline\"\r\n [ngClass]=\"{\r\n 'position-right': !inline && opens === 'right',\r\n 'position-center': !inline && opens === 'center',\r\n 'drop-up': !inline && drop === 'up',\r\n 'has-ranges': showRanges && customRanges,\r\n 'dual-calendar-mode': dualCalendar\r\n }\"\r\n *ngIf=\"inline || show\">\r\n\r\n <!-- RANGES -->\r\n <div class=\"ranges\" *ngIf=\"showRanges && customRanges\">\r\n <button\r\n *ngFor=\"let rangeKey of rangeOrder\"\r\n (click)=\"chooseRange(rangeKey)\"\r\n [class.active]=\"activeRange === rangeKey\"\r\n [class.custom-range]=\"rangeKey === 'Custom Range'\"\r\n class=\"range-btn\"\r\n [disabled]=\"rangeKey === 'Custom Range'\">\r\n {{ rangeKey }}\r\n </button>\r\n </div>\r\n<div class=\"\" [ngClass]=\"showRanges ? 'w-100 flex-grow-1' : ''\">\r\n\r\n\r\n <!-- SINGLE CALENDAR -->\r\n <div *ngIf=\"!dualCalendar\" class=\"calendar-wrapper\">\r\n <div class=\"header\">\r\n <!-- <button (click)=\"prevMonth()\" class=\"nav-btn\" type=\"button\">\r\n <img src=\"assets/calender/pagination-left-gray.svg\" alt=\"arrow-left\" class=\"arrow-left\">\r\n </button> -->\r\n <button class=\"nav-btn\" type=\"button\" (click)=\"prevMonth()\" matTooltip=\"Prev month\"\r\n >\r\n <img alt=\"prev\" class=\"h-3 w-3\" [src]=\"brickclayIcons.arrowleft\"/>\r\n </button>\r\n <span class=\"month-year\">{{ getMonthName(month) }} {{ year }}</span>\r\n <!-- <button (click)=\"nextMonth()\" class=\"nav-btn\" type=\"button\">\r\n <img src=\"assets/calender/pagination-right-gray.svg\" alt=\"arrow-right\" class=\"arrow-right\">\r\n </button> -->\r\n <button class=\"nav-btn\" type=\"button\" (click)=\"nextMonth()\" matTooltip=\"Next month\"\r\n >\r\n <img alt=\"next\" class=\"h-3 w-3\" [src]='brickclayIcons.arrowRight'/>\r\n <!--<img src=\"assets/calender/pagination-right-gray.svg\" alt=\"next\" class=\"h-3 w-3\" /> -->\r\n </button>\r\n </div>\r\n\r\n <table class=\"calendar-table\">\r\n <thead>\r\n <tr>\r\n <th *ngFor=\"let d of ['Mo','Tu','We','Th','Fr','Sa','Su']\" class=\"weekday-header\">{{ d }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let week of calendar\">\r\n <td\r\n *ngFor=\"let dayObj of week\"\r\n (click)=\"dayObj.currentMonth && !isDateDisabled(year, month, dayObj.day) && selectDate(dayObj.day)\"\r\n (mouseenter)=\"dayObj.currentMonth && !isDateDisabled(year, month, dayObj.day) && onDateHover(dayObj.day, false)\"\r\n (mouseleave)=\"onDateLeave()\"\r\n [class.active]=\"dayObj.currentMonth && isDateSelected(year, month, dayObj.day)\"\r\n [class.in-range]=\"dayObj.currentMonth && isDateInRange(year, month, dayObj.day)\"\r\n [class.other-month]=\"!dayObj.currentMonth\"\r\n [class.disabled]=\"isDateDisabled(year, month, dayObj.day)\"\r\n [class.multi-selected]=\"multiDateSelection && isDateInMultiSelection(year, month, dayObj.day)\"\r\n [class.today]=\"dayObj.currentMonth && isToday(year, month, dayObj.day)\"\r\n class=\"calendar-day\">\r\n {{ dayObj.day }}\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n\r\n <!-- Single Calendar Time Picker -->\r\n <div *ngIf=\"enableTimepicker\" class=\"timepicker-section\">\r\n <div class=\"timepicker-label\">Time</div>\r\n <div class=\"timepicker-controls\">\r\n <bk-time-picker\r\n pickerId=\"single-time\"\r\n [label]=\"''\"\r\n [value]=\"getSingleTimePickerDisplay()\"\r\n [closePicker]=\"shouldClosePicker('single-time')\"\r\n (timeChange)=\"onSingleTimePickerChange($event)\"\r\n (pickerOpened)=\"onTimePickerOpened($event)\"\r\n (pickerClosed)=\"onTimePickerClosed($event)\">\r\n </bk-time-picker>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- DUAL CALENDAR -->\r\n <div class=\"dual-calendar\" *ngIf=\"dualCalendar\">\r\n <!-- LEFT CALENDAR -->\r\n <div class=\"calendar-left\">\r\n <div class=\"header\">\r\n <button (click)=\"prevLeftMonth()\" class=\"nav-btn\" type=\"button\">\r\n <img alt=\"arrow-left\" class=\"arrow-left\" [src]=\"brickclayIcons.arrowleft\"/>\r\n </button>\r\n <span class=\"month-year\">{{ getMonthName(leftMonth) }} {{ leftYear }}</span>\r\n <button (click)=\"nextLeftMonth()\" class=\"nav-btn\" type=\"button\">\r\n <img alt=\"arrow-right\" class=\"arrow-right\" [src]='brickclayIcons.arrowRight'/>\r\n </button>\r\n </div>\r\n <table class=\"calendar-table\">\r\n <thead>\r\n <tr>\r\n <th *ngFor=\"let d of ['Mo','Tu','We','Th','Fr','Sa','Su']\" class=\"weekday-header\">{{ d }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let week of leftCalendar\">\r\n <td\r\n *ngFor=\"let dayObj of week\"\r\n (click)=\"dayObj.currentMonth && !isDateDisabled(leftYear, leftMonth, dayObj.day) && selectDate(dayObj.day, false)\"\r\n (mouseenter)=\"dayObj.currentMonth && !isDateDisabled(leftYear, leftMonth, dayObj.day) && onDateHover(dayObj.day, false)\"\r\n (mouseleave)=\"onDateLeave()\"\r\n [class.active]=\"dayObj.currentMonth && isDateSelected(leftYear, leftMonth, dayObj.day)\"\r\n [class.in-range]=\"dayObj.currentMonth && isDateInRange(leftYear, leftMonth, dayObj.day)\"\r\n [class.other-month]=\"!dayObj.currentMonth\"\r\n [class.disabled]=\"isDateDisabled(leftYear, leftMonth, dayObj.day)\"\r\n [class.multi-selected]=\"multiDateSelection && isDateInMultiSelection(leftYear, leftMonth, dayObj.day)\"\r\n [class.today]=\"dayObj.currentMonth && isToday(leftYear, leftMonth, dayObj.day)\"\r\n class=\"calendar-day\">\r\n {{ dayObj.day }}\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n\r\n <!-- Start Time Picker for Dual Calendar -->\r\n <div *ngIf=\"enableTimepicker\" class=\"timepicker-section\">\r\n <div class=\"timepicker-label\">Start Time</div>\r\n <div class=\"timepicker-controls\">\r\n <bk-time-picker\r\n pickerId=\"dual-start\"\r\n [label]=\"''\"\r\n [value]=\"getDualTimePickerDisplay(true)\"\r\n [closePicker]=\"shouldClosePicker('dual-start')\"\r\n (timeChange)=\"onDualTimePickerChange($event, true)\"\r\n (pickerOpened)=\"onTimePickerOpened($event)\"\r\n (pickerClosed)=\"onTimePickerClosed($event)\">\r\n </bk-time-picker>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- RIGHT CALENDAR -->\r\n <div class=\"calendar-right\">\r\n <div class=\"header\">\r\n <button (click)=\"prevRightMonth()\" class=\"nav-btn\" type=\"button\">\r\n <img alt=\"arrow-left\" class=\"arrow-left\" [src]=\"brickclayIcons.arrowleft\"/>\r\n </button>\r\n <span class=\"month-year\">{{ getMonthName(rightMonth) }} {{ rightYear }}</span>\r\n <button (click)=\"nextRightMonth()\" class=\"nav-btn\" type=\"button\">\r\n <img alt=\"arrow-right\" class=\"arrow-right\" [src]='brickclayIcons.arrowRight'/>\r\n </button>\r\n </div>\r\n <table class=\"calendar-table\">\r\n <thead>\r\n <tr>\r\n <th *ngFor=\"let d of ['Mo','Tu','We','Th','Fr','Sa','Su']\" class=\"weekday-header\">{{ d }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let week of rightCalendar\">\r\n <td\r\n *ngFor=\"let dayObj of week\"\r\n (click)=\"dayObj.currentMonth && !isDateDisabled(rightYear, rightMonth, dayObj.day) && selectDate(dayObj.day, true)\"\r\n (mouseenter)=\"dayObj.currentMonth && !isDateDisabled(rightYear, rightMonth, dayObj.day) && onDateHover(dayObj.day, true)\"\r\n (mouseleave)=\"onDateLeave()\"\r\n [class.active]=\"dayObj.currentMonth && isDateSelected(rightYear, rightMonth, dayObj.day)\"\r\n [class.in-range]=\"dayObj.currentMonth && isDateInRange(rightYear, rightMonth, dayObj.day)\"\r\n [class.other-month]=\"!dayObj.currentMonth\"\r\n [class.disabled]=\"isDateDisabled(rightYear, rightMonth, dayObj.day)\"\r\n [class.multi-selected]=\"multiDateSelection && isDateInMultiSelection(rightYear, rightMonth, dayObj.day)\"\r\n [class.today]=\"dayObj.currentMonth && isToday(rightYear, rightMonth, dayObj.day)\"\r\n class=\"calendar-day\">\r\n {{ dayObj.day }}\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n\r\n <!-- End Time Picker for Dual Calendar -->\r\n <div *ngIf=\"enableTimepicker\" class=\"timepicker-section\">\r\n <div class=\"timepicker-label\">End Time</div>\r\n <div class=\"timepicker-controls\">\r\n <bk-time-picker\r\n pickerId=\"dual-end\"\r\n [label]=\"''\"\r\n [value]=\"getDualTimePickerDisplay(false)\"\r\n [closePicker]=\"shouldClosePicker('dual-end')\"\r\n (timeChange)=\"onDualTimePickerChange($event, false)\"\r\n (pickerOpened)=\"onTimePickerOpened($event)\"\r\n (pickerClosed)=\"onTimePickerClosed($event)\">\r\n </bk-time-picker>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- FOOTER -->\r\n <div class=\"footer\" *ngIf=\"!inline\">\r\n <button *ngIf=\"showCancel\" (click)=\"cancel()\" class=\"btn-cancel\" type=\"button\">Cancel</button>\r\n <button (click)=\"apply()\" class=\"btn-apply\" type=\"button\">Apply</button>\r\n </div>\r\n\r\n </div>\r\n\r\n </div>\r\n</div>\r\n", styles: [".calendar-container,.calendar-container *{font-family:Inter,sans-serif!important}.calendar-container{position:relative;display:inline-block;width:100%}.input-wrapper{position:relative;display:flex;align-items:center}.calendar-input{width:100%;padding:9px 14px 9px 40px;border:1px solid #ddd;border-radius:8px;font-size:14px;cursor:pointer;background:#fff;transition:all .2s}.calendar-input:hover{border-color:#999}.calendar-input:focus{outline:none;border-color:#999;box-shadow:0 0 0 3px #6a6a6a1a}.calendar-icon{position:absolute;left:12px;pointer-events:none;font-size:18px}.clear-btn{position:absolute;right:9px;background:none;border:none;font-size:20px;color:#999;cursor:pointer;padding:0;width:20px;height:20px;display:flex;align-items:center;justify-content:center;line-height:1;transition:color .2s;top:8px}.clear-btn:hover{color:#333}.calendar-popup{position:absolute;top:110%;left:0;width:320px;background:#fff;border-radius:12px;box-shadow:0 10px 40px #00000026;z-index:1000;animation:slideDown .2s ease-out}.calendar-popup.inline-calendar{position:relative;top:0;left:0;width:100%;margin-top:0;animation:none;box-shadow:0 2px 8px #0000001a}.calendar-container.inline-mode{display:block;width:100%}.calendar-popup.dual-calendar-mode{width:600px}.calendar-popup.dual-calendar-mode.has-ranges{width:730px}.calendar-popup.has-ranges{width:450px}.calendar-popup.dual-calendar-mode.has-ranges .dual-calendar{border-left:1px solid #eee}.calendar-popup.drop-up{top:auto;bottom:110%;animation:slideUp .2s ease-out}.calendar-popup.position-right{left:auto;right:0}.calendar-popup.position-center{left:50%;transform:translate(-50%)}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes slideUp{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.ranges{display:flex;flex-direction:column;gap:4px;margin-bottom:16px;padding-bottom:16px;border-bottom:1px solid #eee;min-width:150px;padding-right:8px}.range-btn{padding:7px 10px;border:1px solid transparent;background:transparent;border-radius:4px;cursor:pointer;text-align:left;font-size:14px;transition:all .2s;color:#838383;font-weight:500}.range-btn:hover{background:#f5f5f5;color:#000}.range-btn.active{background:#f0f0f0;color:#000;font-weight:500}.calendar-wrapper{padding:0 12px 12px;border-left:1px solid #eee}.header{display:flex;justify-content:space-between;align-items:center;padding:12px 0}.month-year{font-size:15px;font-weight:500;color:#333;flex:1;text-align:center;text-transform:capitalize}.nav-btn{background:none;border:none;font-size:24px;cursor:pointer;padding:11.5px 14px;color:#666;border-radius:4px;transition:all .2s;line-height:1;height:30px;width:30px;display:flex;justify-content:center;align-items:center}.nav-btn:hover{background:#f0f0f0;color:#000}.nav-btn img{width:auto;max-width:none!important}.calendar-table{width:100%;border-collapse:collapse;text-align:center}.weekday-header{font-size:12px;color:#7e7e7e;font-weight:600;padding:8px 4px;letter-spacing:.3px}.calendar-day{padding:8px 4px;font-size:14px;cursor:pointer;border-radius:6px;transition:all .2s;position:relative;color:#333;font-weight:500;line-height:1.5}.calendar-day:hover:not(.disabled):not(.other-month){background:#efefef;color:#000}.calendar-day.other-month{color:#ccc;cursor:default}.calendar-day.disabled{color:#ddd;cursor:not-allowed;opacity:.5}.calendar-day.active{background:#000!important;color:#fff!important;font-weight:600}.calendar-day.today{font-weight:600}.calendar-day.today:not(.active){background:#e5e4e4}.calendar-day.active:hover{background:#000!important}.calendar-day.in-range{background:#f5f5f5;color:#333;border-radius:0;position:relative}.calendar-day.in-range:hover{background:#e8e8e8}.calendar-day.in-range:before{content:\"\";position:absolute;inset:0;background:#f5f5f5;z-index:-1}.calendar-day.in-range:hover:before{background:#e8e8e8}.calendar-day.multi-selected{background:#4caf50;color:#fff;font-weight:600;border-radius:6px}.calendar-day.multi-selected:hover{background:#45a049}.dual-calendar{display:flex;width:100%;border-left:1px solid #eee}.calendar-left,.calendar-right{flex:1;min-width:0;padding:0 12px 12px}.calendar-popup.has-ranges{display:flex;flex-direction:row}.calendar-popup.has-ranges .ranges{margin-bottom:0;border-bottom:none;padding:10px}.calendar-popup.has-ranges .dual-calendar,.calendar-popup.has-ranges .calendar-wrapper{flex:1}.calendar-right .header{justify-content:space-between}.calendar-right .header .month-year{text-align:center;flex:1}.timepicker-section{margin-top:12px;padding-top:12px;border-top:1px solid #eee}.timepicker-label{font-size:12px;font-weight:500;color:#000;margin-bottom:4px;letter-spacing:-.28px}.custom-time-picker{display:flex;flex-direction:column;gap:8px;align-items:start}.time-input-group{display:flex;align-items:center;justify-content:center;gap:8px;background:#f8f9fa;padding:12px;border-radius:8px;border:1px solid #e0e0e0}.time-control{display:flex;flex-direction:column;align-items:center}.time-btn{background:#fff;border:1px solid #ddd;width:28px;height:20px;cursor:pointer;font-size:10px;color:#666;border-radius:4px;transition:all .2s;display:flex;align-items:center;justify-content:center;padding:0;line-height:1}.time-btn:hover{background:#e4e4e4;color:#fff;border-color:#e4e4e4}.time-btn.up{border-bottom-left-radius:0;border-bottom-right-radius:0;border-bottom:none}.time-btn.down{border-top-left-radius:0;border-top-right-radius:0;border-top:none}.time-input{width:40px;height:32px;text-align:center;border:1px solid #ddd;border-radius:4px;font-size:16px;font-weight:600;background:#fff;color:#333}.time-separator{font-size:18px;font-weight:600;color:#666;margin:0 2px}.ampm-control{display:flex;flex-direction:column;gap:4px;margin-left:8px}.ampm-btn{padding:6px 12px;border:1px solid #ddd;background:#fff;border-radius:4px;cursor:pointer;font-size:12px;font-weight:600;color:#666;transition:all .2s;min-width:45px}.ampm-btn:hover{background:#f0f0f0}.ampm-btn.active{background:#000;color:#fff;border-color:#000}.html5-time-input{margin-top:8px;padding:8px;border:1px solid #ddd;border-radius:6px;font-size:14px;width:100%;max-width:120px}.footer{padding:12px;display:flex;justify-content:flex-end;gap:8px;border-top:1px solid #eee}.btn-cancel,.btn-apply{padding:8px 16px;border:none;border-radius:4px;font-size:14px;font-weight:500;cursor:pointer;transition:all .2s;min-width:80px}.btn-cancel{background:#fff;color:#666;border:1px solid #ddd}.btn-cancel:hover{background:#f5f5f5;border-color:#bbb}.btn-apply{background:#000;color:#fff}.btn-apply:hover{background:#333}.btn-apply:active{transform:translateY(0)}@media (max-width: 768px){.calendar-popup{width:100%;max-width:320px}.calendar-popup.dual-calendar-mode{width:100%;max-width:100%}.calendar-popup.has-ranges{flex-direction:column}.calendar-popup.has-ranges .ranges{border-right:none;border-bottom:1px solid #eee;padding-right:0;margin-right:0;padding-bottom:16px;margin-bottom:16px}.dual-calendar{flex-direction:column}.time-input-group{flex-wrap:wrap;justify-content:center}}.ranges::-webkit-scrollbar{width:6px}.ranges::-webkit-scrollbar-track{background:#f1f1f1;border-radius:3px}.ranges::-webkit-scrollbar-thumb{background:#888;border-radius:3px}.ranges::-webkit-scrollbar-thumb:hover{background:#555}.w-100{width:100%}.flex-grow-1{flex-grow:1}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: BkTimePicker, selector: "bk-time-picker", inputs: ["value", "label", "placeholder", "position", "pickerId", "closePicker", "timeFormat", "showSeconds"], outputs: ["timeChange", "pickerOpened", "pickerClosed"] }] });
1874
+ }
1875
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkCustomCalendar, decorators: [{
1876
+ type: Component,
1877
+ args: [{ selector: 'bk-custom-calendar', standalone: true, imports: [CommonModule, FormsModule, BkTimePicker], template: "<div class=\"calendar-container relative\" [class.open]=\"show\" [class.inline-mode]=\"inline\">\r\n <!-- Input field -->\r\n <div class=\"input-wrapper\" *ngIf=\"!inline\">\r\n <input\r\n type=\"text\"\r\n (click)=\"toggle()\"\r\n readonly\r\n [value]=\"getDisplayValue()\"\r\n [placeholder]=\"placeholder\"\r\n class=\"calendar-input\">\r\n <!-- *ngIf=\"!getDisplayValue()\" -->\r\n\r\n <span class=\"calendar-icon\" >\r\n <img alt=\"calendar\" class=\"calendar-icon-img\" [src]='brickclayIcons.calenderIcon'/>\r\n </span>\r\n <button class=\"clear-btn\" *ngIf=\"getDisplayValue() && isDisplayCrossIcon\" (click)=\"clear(); $event.stopPropagation()\" title=\"Clear\">\u00D7</button>\r\n </div>\r\n\r\n <!-- Calendar Popup / Inline -->\r\n <div class=\"calendar-popup\"\r\n [class.inline-calendar]=\"inline\"\r\n [ngClass]=\"{\r\n 'position-right': !inline && opens === 'right',\r\n 'position-center': !inline && opens === 'center',\r\n 'drop-up': !inline && drop === 'up',\r\n 'has-ranges': showRanges && customRanges,\r\n 'dual-calendar-mode': dualCalendar\r\n }\"\r\n *ngIf=\"inline || show\">\r\n\r\n <!-- RANGES -->\r\n <div class=\"ranges\" *ngIf=\"showRanges && customRanges\">\r\n <button\r\n *ngFor=\"let rangeKey of rangeOrder\"\r\n (click)=\"chooseRange(rangeKey)\"\r\n [class.active]=\"activeRange === rangeKey\"\r\n [class.custom-range]=\"rangeKey === 'Custom Range'\"\r\n class=\"range-btn\"\r\n [disabled]=\"rangeKey === 'Custom Range'\">\r\n {{ rangeKey }}\r\n </button>\r\n </div>\r\n<div class=\"\" [ngClass]=\"showRanges ? 'w-100 flex-grow-1' : ''\">\r\n\r\n\r\n <!-- SINGLE CALENDAR -->\r\n <div *ngIf=\"!dualCalendar\" class=\"calendar-wrapper\">\r\n <div class=\"header\">\r\n <!-- <button (click)=\"prevMonth()\" class=\"nav-btn\" type=\"button\">\r\n <img src=\"assets/calender/pagination-left-gray.svg\" alt=\"arrow-left\" class=\"arrow-left\">\r\n </button> -->\r\n <button class=\"nav-btn\" type=\"button\" (click)=\"prevMonth()\" matTooltip=\"Prev month\"\r\n >\r\n <img alt=\"prev\" class=\"h-3 w-3\" [src]=\"brickclayIcons.arrowleft\"/>\r\n </button>\r\n <span class=\"month-year\">{{ getMonthName(month) }} {{ year }}</span>\r\n <!-- <button (click)=\"nextMonth()\" class=\"nav-btn\" type=\"button\">\r\n <img src=\"assets/calender/pagination-right-gray.svg\" alt=\"arrow-right\" class=\"arrow-right\">\r\n </button> -->\r\n <button class=\"nav-btn\" type=\"button\" (click)=\"nextMonth()\" matTooltip=\"Next month\"\r\n >\r\n <img alt=\"next\" class=\"h-3 w-3\" [src]='brickclayIcons.arrowRight'/>\r\n <!--<img src=\"assets/calender/pagination-right-gray.svg\" alt=\"next\" class=\"h-3 w-3\" /> -->\r\n </button>\r\n </div>\r\n\r\n <table class=\"calendar-table\">\r\n <thead>\r\n <tr>\r\n <th *ngFor=\"let d of ['Mo','Tu','We','Th','Fr','Sa','Su']\" class=\"weekday-header\">{{ d }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let week of calendar\">\r\n <td\r\n *ngFor=\"let dayObj of week\"\r\n (click)=\"dayObj.currentMonth && !isDateDisabled(year, month, dayObj.day) && selectDate(dayObj.day)\"\r\n (mouseenter)=\"dayObj.currentMonth && !isDateDisabled(year, month, dayObj.day) && onDateHover(dayObj.day, false)\"\r\n (mouseleave)=\"onDateLeave()\"\r\n [class.active]=\"dayObj.currentMonth && isDateSelected(year, month, dayObj.day)\"\r\n [class.in-range]=\"dayObj.currentMonth && isDateInRange(year, month, dayObj.day)\"\r\n [class.other-month]=\"!dayObj.currentMonth\"\r\n [class.disabled]=\"isDateDisabled(year, month, dayObj.day)\"\r\n [class.multi-selected]=\"multiDateSelection && isDateInMultiSelection(year, month, dayObj.day)\"\r\n [class.today]=\"dayObj.currentMonth && isToday(year, month, dayObj.day)\"\r\n class=\"calendar-day\">\r\n {{ dayObj.day }}\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n\r\n <!-- Single Calendar Time Picker -->\r\n <div *ngIf=\"enableTimepicker\" class=\"timepicker-section\">\r\n <div class=\"timepicker-label\">Time</div>\r\n <div class=\"timepicker-controls\">\r\n <bk-time-picker\r\n pickerId=\"single-time\"\r\n [label]=\"''\"\r\n [value]=\"getSingleTimePickerDisplay()\"\r\n [closePicker]=\"shouldClosePicker('single-time')\"\r\n (timeChange)=\"onSingleTimePickerChange($event)\"\r\n (pickerOpened)=\"onTimePickerOpened($event)\"\r\n (pickerClosed)=\"onTimePickerClosed($event)\">\r\n </bk-time-picker>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- DUAL CALENDAR -->\r\n <div class=\"dual-calendar\" *ngIf=\"dualCalendar\">\r\n <!-- LEFT CALENDAR -->\r\n <div class=\"calendar-left\">\r\n <div class=\"header\">\r\n <button (click)=\"prevLeftMonth()\" class=\"nav-btn\" type=\"button\">\r\n <img alt=\"arrow-left\" class=\"arrow-left\" [src]=\"brickclayIcons.arrowleft\"/>\r\n </button>\r\n <span class=\"month-year\">{{ getMonthName(leftMonth) }} {{ leftYear }}</span>\r\n <button (click)=\"nextLeftMonth()\" class=\"nav-btn\" type=\"button\">\r\n <img alt=\"arrow-right\" class=\"arrow-right\" [src]='brickclayIcons.arrowRight'/>\r\n </button>\r\n </div>\r\n <table class=\"calendar-table\">\r\n <thead>\r\n <tr>\r\n <th *ngFor=\"let d of ['Mo','Tu','We','Th','Fr','Sa','Su']\" class=\"weekday-header\">{{ d }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let week of leftCalendar\">\r\n <td\r\n *ngFor=\"let dayObj of week\"\r\n (click)=\"dayObj.currentMonth && !isDateDisabled(leftYear, leftMonth, dayObj.day) && selectDate(dayObj.day, false)\"\r\n (mouseenter)=\"dayObj.currentMonth && !isDateDisabled(leftYear, leftMonth, dayObj.day) && onDateHover(dayObj.day, false)\"\r\n (mouseleave)=\"onDateLeave()\"\r\n [class.active]=\"dayObj.currentMonth && isDateSelected(leftYear, leftMonth, dayObj.day)\"\r\n [class.in-range]=\"dayObj.currentMonth && isDateInRange(leftYear, leftMonth, dayObj.day)\"\r\n [class.other-month]=\"!dayObj.currentMonth\"\r\n [class.disabled]=\"isDateDisabled(leftYear, leftMonth, dayObj.day)\"\r\n [class.multi-selected]=\"multiDateSelection && isDateInMultiSelection(leftYear, leftMonth, dayObj.day)\"\r\n [class.today]=\"dayObj.currentMonth && isToday(leftYear, leftMonth, dayObj.day)\"\r\n class=\"calendar-day\">\r\n {{ dayObj.day }}\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n\r\n <!-- Start Time Picker for Dual Calendar -->\r\n <div *ngIf=\"enableTimepicker\" class=\"timepicker-section\">\r\n <div class=\"timepicker-label\">Start Time</div>\r\n <div class=\"timepicker-controls\">\r\n <bk-time-picker\r\n pickerId=\"dual-start\"\r\n [label]=\"''\"\r\n [value]=\"getDualTimePickerDisplay(true)\"\r\n [closePicker]=\"shouldClosePicker('dual-start')\"\r\n (timeChange)=\"onDualTimePickerChange($event, true)\"\r\n (pickerOpened)=\"onTimePickerOpened($event)\"\r\n (pickerClosed)=\"onTimePickerClosed($event)\">\r\n </bk-time-picker>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- RIGHT CALENDAR -->\r\n <div class=\"calendar-right\">\r\n <div class=\"header\">\r\n <button (click)=\"prevRightMonth()\" class=\"nav-btn\" type=\"button\">\r\n <img alt=\"arrow-left\" class=\"arrow-left\" [src]=\"brickclayIcons.arrowleft\"/>\r\n </button>\r\n <span class=\"month-year\">{{ getMonthName(rightMonth) }} {{ rightYear }}</span>\r\n <button (click)=\"nextRightMonth()\" class=\"nav-btn\" type=\"button\">\r\n <img alt=\"arrow-right\" class=\"arrow-right\" [src]='brickclayIcons.arrowRight'/>\r\n </button>\r\n </div>\r\n <table class=\"calendar-table\">\r\n <thead>\r\n <tr>\r\n <th *ngFor=\"let d of ['Mo','Tu','We','Th','Fr','Sa','Su']\" class=\"weekday-header\">{{ d }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let week of rightCalendar\">\r\n <td\r\n *ngFor=\"let dayObj of week\"\r\n (click)=\"dayObj.currentMonth && !isDateDisabled(rightYear, rightMonth, dayObj.day) && selectDate(dayObj.day, true)\"\r\n (mouseenter)=\"dayObj.currentMonth && !isDateDisabled(rightYear, rightMonth, dayObj.day) && onDateHover(dayObj.day, true)\"\r\n (mouseleave)=\"onDateLeave()\"\r\n [class.active]=\"dayObj.currentMonth && isDateSelected(rightYear, rightMonth, dayObj.day)\"\r\n [class.in-range]=\"dayObj.currentMonth && isDateInRange(rightYear, rightMonth, dayObj.day)\"\r\n [class.other-month]=\"!dayObj.currentMonth\"\r\n [class.disabled]=\"isDateDisabled(rightYear, rightMonth, dayObj.day)\"\r\n [class.multi-selected]=\"multiDateSelection && isDateInMultiSelection(rightYear, rightMonth, dayObj.day)\"\r\n [class.today]=\"dayObj.currentMonth && isToday(rightYear, rightMonth, dayObj.day)\"\r\n class=\"calendar-day\">\r\n {{ dayObj.day }}\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n\r\n <!-- End Time Picker for Dual Calendar -->\r\n <div *ngIf=\"enableTimepicker\" class=\"timepicker-section\">\r\n <div class=\"timepicker-label\">End Time</div>\r\n <div class=\"timepicker-controls\">\r\n <bk-time-picker\r\n pickerId=\"dual-end\"\r\n [label]=\"''\"\r\n [value]=\"getDualTimePickerDisplay(false)\"\r\n [closePicker]=\"shouldClosePicker('dual-end')\"\r\n (timeChange)=\"onDualTimePickerChange($event, false)\"\r\n (pickerOpened)=\"onTimePickerOpened($event)\"\r\n (pickerClosed)=\"onTimePickerClosed($event)\">\r\n </bk-time-picker>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- FOOTER -->\r\n <div class=\"footer\" *ngIf=\"!inline\">\r\n <button *ngIf=\"showCancel\" (click)=\"cancel()\" class=\"btn-cancel\" type=\"button\">Cancel</button>\r\n <button (click)=\"apply()\" class=\"btn-apply\" type=\"button\">Apply</button>\r\n </div>\r\n\r\n </div>\r\n\r\n </div>\r\n</div>\r\n", styles: [".calendar-container,.calendar-container *{font-family:Inter,sans-serif!important}.calendar-container{position:relative;display:inline-block;width:100%}.input-wrapper{position:relative;display:flex;align-items:center}.calendar-input{width:100%;padding:9px 14px 9px 40px;border:1px solid #ddd;border-radius:8px;font-size:14px;cursor:pointer;background:#fff;transition:all .2s}.calendar-input:hover{border-color:#999}.calendar-input:focus{outline:none;border-color:#999;box-shadow:0 0 0 3px #6a6a6a1a}.calendar-icon{position:absolute;left:12px;pointer-events:none;font-size:18px}.clear-btn{position:absolute;right:9px;background:none;border:none;font-size:20px;color:#999;cursor:pointer;padding:0;width:20px;height:20px;display:flex;align-items:center;justify-content:center;line-height:1;transition:color .2s;top:8px}.clear-btn:hover{color:#333}.calendar-popup{position:absolute;top:110%;left:0;width:320px;background:#fff;border-radius:12px;box-shadow:0 10px 40px #00000026;z-index:1000;animation:slideDown .2s ease-out}.calendar-popup.inline-calendar{position:relative;top:0;left:0;width:100%;margin-top:0;animation:none;box-shadow:0 2px 8px #0000001a}.calendar-container.inline-mode{display:block;width:100%}.calendar-popup.dual-calendar-mode{width:600px}.calendar-popup.dual-calendar-mode.has-ranges{width:730px}.calendar-popup.has-ranges{width:450px}.calendar-popup.dual-calendar-mode.has-ranges .dual-calendar{border-left:1px solid #eee}.calendar-popup.drop-up{top:auto;bottom:110%;animation:slideUp .2s ease-out}.calendar-popup.position-right{left:auto;right:0}.calendar-popup.position-center{left:50%;transform:translate(-50%)}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes slideUp{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.ranges{display:flex;flex-direction:column;gap:4px;margin-bottom:16px;padding-bottom:16px;border-bottom:1px solid #eee;min-width:150px;padding-right:8px}.range-btn{padding:7px 10px;border:1px solid transparent;background:transparent;border-radius:4px;cursor:pointer;text-align:left;font-size:14px;transition:all .2s;color:#838383;font-weight:500}.range-btn:hover{background:#f5f5f5;color:#000}.range-btn.active{background:#f0f0f0;color:#000;font-weight:500}.calendar-wrapper{padding:0 12px 12px;border-left:1px solid #eee}.header{display:flex;justify-content:space-between;align-items:center;padding:12px 0}.month-year{font-size:15px;font-weight:500;color:#333;flex:1;text-align:center;text-transform:capitalize}.nav-btn{background:none;border:none;font-size:24px;cursor:pointer;padding:11.5px 14px;color:#666;border-radius:4px;transition:all .2s;line-height:1;height:30px;width:30px;display:flex;justify-content:center;align-items:center}.nav-btn:hover{background:#f0f0f0;color:#000}.nav-btn img{width:auto;max-width:none!important}.calendar-table{width:100%;border-collapse:collapse;text-align:center}.weekday-header{font-size:12px;color:#7e7e7e;font-weight:600;padding:8px 4px;letter-spacing:.3px}.calendar-day{padding:8px 4px;font-size:14px;cursor:pointer;border-radius:6px;transition:all .2s;position:relative;color:#333;font-weight:500;line-height:1.5}.calendar-day:hover:not(.disabled):not(.other-month){background:#efefef;color:#000}.calendar-day.other-month{color:#ccc;cursor:default}.calendar-day.disabled{color:#ddd;cursor:not-allowed;opacity:.5}.calendar-day.active{background:#000!important;color:#fff!important;font-weight:600}.calendar-day.today{font-weight:600}.calendar-day.today:not(.active){background:#e5e4e4}.calendar-day.active:hover{background:#000!important}.calendar-day.in-range{background:#f5f5f5;color:#333;border-radius:0;position:relative}.calendar-day.in-range:hover{background:#e8e8e8}.calendar-day.in-range:before{content:\"\";position:absolute;inset:0;background:#f5f5f5;z-index:-1}.calendar-day.in-range:hover:before{background:#e8e8e8}.calendar-day.multi-selected{background:#4caf50;color:#fff;font-weight:600;border-radius:6px}.calendar-day.multi-selected:hover{background:#45a049}.dual-calendar{display:flex;width:100%;border-left:1px solid #eee}.calendar-left,.calendar-right{flex:1;min-width:0;padding:0 12px 12px}.calendar-popup.has-ranges{display:flex;flex-direction:row}.calendar-popup.has-ranges .ranges{margin-bottom:0;border-bottom:none;padding:10px}.calendar-popup.has-ranges .dual-calendar,.calendar-popup.has-ranges .calendar-wrapper{flex:1}.calendar-right .header{justify-content:space-between}.calendar-right .header .month-year{text-align:center;flex:1}.timepicker-section{margin-top:12px;padding-top:12px;border-top:1px solid #eee}.timepicker-label{font-size:12px;font-weight:500;color:#000;margin-bottom:4px;letter-spacing:-.28px}.custom-time-picker{display:flex;flex-direction:column;gap:8px;align-items:start}.time-input-group{display:flex;align-items:center;justify-content:center;gap:8px;background:#f8f9fa;padding:12px;border-radius:8px;border:1px solid #e0e0e0}.time-control{display:flex;flex-direction:column;align-items:center}.time-btn{background:#fff;border:1px solid #ddd;width:28px;height:20px;cursor:pointer;font-size:10px;color:#666;border-radius:4px;transition:all .2s;display:flex;align-items:center;justify-content:center;padding:0;line-height:1}.time-btn:hover{background:#e4e4e4;color:#fff;border-color:#e4e4e4}.time-btn.up{border-bottom-left-radius:0;border-bottom-right-radius:0;border-bottom:none}.time-btn.down{border-top-left-radius:0;border-top-right-radius:0;border-top:none}.time-input{width:40px;height:32px;text-align:center;border:1px solid #ddd;border-radius:4px;font-size:16px;font-weight:600;background:#fff;color:#333}.time-separator{font-size:18px;font-weight:600;color:#666;margin:0 2px}.ampm-control{display:flex;flex-direction:column;gap:4px;margin-left:8px}.ampm-btn{padding:6px 12px;border:1px solid #ddd;background:#fff;border-radius:4px;cursor:pointer;font-size:12px;font-weight:600;color:#666;transition:all .2s;min-width:45px}.ampm-btn:hover{background:#f0f0f0}.ampm-btn.active{background:#000;color:#fff;border-color:#000}.html5-time-input{margin-top:8px;padding:8px;border:1px solid #ddd;border-radius:6px;font-size:14px;width:100%;max-width:120px}.footer{padding:12px;display:flex;justify-content:flex-end;gap:8px;border-top:1px solid #eee}.btn-cancel,.btn-apply{padding:8px 16px;border:none;border-radius:4px;font-size:14px;font-weight:500;cursor:pointer;transition:all .2s;min-width:80px}.btn-cancel{background:#fff;color:#666;border:1px solid #ddd}.btn-cancel:hover{background:#f5f5f5;border-color:#bbb}.btn-apply{background:#000;color:#fff}.btn-apply:hover{background:#333}.btn-apply:active{transform:translateY(0)}@media (max-width: 768px){.calendar-popup{width:100%;max-width:320px}.calendar-popup.dual-calendar-mode{width:100%;max-width:100%}.calendar-popup.has-ranges{flex-direction:column}.calendar-popup.has-ranges .ranges{border-right:none;border-bottom:1px solid #eee;padding-right:0;margin-right:0;padding-bottom:16px;margin-bottom:16px}.dual-calendar{flex-direction:column}.time-input-group{flex-wrap:wrap;justify-content:center}}.ranges::-webkit-scrollbar{width:6px}.ranges::-webkit-scrollbar-track{background:#f1f1f1;border-radius:3px}.ranges::-webkit-scrollbar-thumb{background:#888;border-radius:3px}.ranges::-webkit-scrollbar-thumb:hover{background:#555}.w-100{width:100%}.flex-grow-1{flex-grow:1}\n"] }]
1878
+ }], ctorParameters: () => [{ type: CalendarManagerService }], propDecorators: { enableTimepicker: [{
1879
+ type: Input
1880
+ }], autoApply: [{
1881
+ type: Input
1882
+ }], closeOnAutoApply: [{
1883
+ type: Input
1884
+ }], showCancel: [{
1885
+ type: Input
1886
+ }], linkedCalendars: [{
1887
+ type: Input
1888
+ }], singleDatePicker: [{
1889
+ type: Input
1890
+ }], showWeekNumbers: [{
1891
+ type: Input
1892
+ }], showISOWeekNumbers: [{
1893
+ type: Input
1894
+ }], customRangeDirection: [{
1895
+ type: Input
1896
+ }], lockStartDate: [{
1897
+ type: Input
1898
+ }], position: [{
1899
+ type: Input
1900
+ }], drop: [{
1901
+ type: Input
1902
+ }], dualCalendar: [{
1903
+ type: Input
1904
+ }], showRanges: [{
1905
+ type: Input
1906
+ }], timeFormat: [{
1907
+ type: Input
1908
+ }], enableSeconds: [{
1909
+ type: Input
1910
+ }], customRanges: [{
1911
+ type: Input
1912
+ }], multiDateSelection: [{
1913
+ type: Input
1914
+ }], maxDate: [{
1915
+ type: Input
1916
+ }], minDate: [{
1917
+ type: Input
1918
+ }], placeholder: [{
1919
+ type: Input
1920
+ }], opens: [{
1921
+ type: Input
1922
+ }], inline: [{
1923
+ type: Input
1924
+ }], isDisplayCrossIcon: [{
1925
+ type: Input
1926
+ }], selected: [{
1927
+ type: Output
1928
+ }], opened: [{
1929
+ type: Output
1930
+ }], closed: [{
1931
+ type: Output
1932
+ }], selectedValue: [{
1933
+ type: Input
1934
+ }], displayFormat: [{
1935
+ type: Input
1936
+ }], startDate: [{
1937
+ type: Input
1938
+ }], endDate: [{
1939
+ type: Input
1940
+ }], onClickOutside: [{
1941
+ type: HostListener,
1942
+ args: ['document:click', ['$event']]
1943
+ }] } });
1944
+
1945
+ class BkScheduledDatePicker {
1946
+ timeFormat = 12;
1947
+ enableSeconds = false;
1948
+ scheduled = new EventEmitter();
1949
+ cleared = new EventEmitter();
1950
+ activeTab = 'single';
1951
+ openTimePickerId = null; // Track which time picker is currently open
1952
+ closePickerCounter = {}; // Track close signals for each picker
1953
+ // Single Date
1954
+ singleDate = null;
1955
+ singleAllDay = false;
1956
+ singleStartTime = '1:00 AM';
1957
+ singleEndTime = '2:00 AM';
1958
+ // Multiple Dates
1959
+ multipleDates = [];
1960
+ // Date Range
1961
+ rangeStartDate = null;
1962
+ rangeEndDate = null;
1963
+ rangeAllDay = false;
1964
+ rangeStartTime = '1:00 AM';
1965
+ rangeEndTime = '2:00 AM';
1966
+ ngOnInit() {
1967
+ // Initialize with default time if needed
1968
+ }
1969
+ onTabChange(tab) {
1970
+ this.activeTab = tab;
1971
+ this.openTimePickerId = null; // Close any open pickers when switching tabs
1972
+ }
1973
+ onTimePickerOpened(pickerId) {
1974
+ // Close all other pickers when one opens
1975
+ if (this.openTimePickerId && this.openTimePickerId !== pickerId) {
1976
+ // Increment close counter for the previously open picker
1977
+ if (!this.closePickerCounter[this.openTimePickerId]) {
1978
+ this.closePickerCounter[this.openTimePickerId] = 0;
1979
+ }
1980
+ this.closePickerCounter[this.openTimePickerId]++;
1981
+ }
1982
+ this.openTimePickerId = pickerId;
1983
+ }
1984
+ onTimePickerClosed(pickerId) {
1985
+ // Reset open picker ID if this was the open one
1986
+ if (this.openTimePickerId === pickerId) {
1987
+ this.openTimePickerId = null;
1988
+ }
1989
+ }
1990
+ shouldClosePicker(pickerId) {
1991
+ // Return the counter value for this picker (triggers change detection)
1992
+ return this.closePickerCounter[pickerId] || 0;
1993
+ }
1994
+ // Single Date Handlers
1995
+ onSingleDateSelected(event) {
1996
+ if (event.startDate) {
1997
+ this.singleDate = new Date(event.startDate);
1998
+ // Initialize time if not all day
1999
+ if (!this.singleAllDay) {
2000
+ this.updateSingleDateTimes();
2001
+ }
2002
+ this.emitScheduled();
2003
+ }
2004
+ else {
2005
+ this.singleDate = null;
2006
+ }
2007
+ }
2008
+ onSingleAllDayChange() {
2009
+ this.singleAllDay = !this.singleAllDay;
2010
+ if (this.singleDate) {
2011
+ this.updateSingleDateTimes();
2012
+ this.emitScheduled();
2013
+ }
2014
+ }
2015
+ onSingleStartTimeChange(time) {
2016
+ this.singleStartTime = time;
2017
+ if (this.singleDate) {
2018
+ this.updateSingleDateTimes();
2019
+ this.emitScheduled();
2020
+ }
2021
+ }
2022
+ onSingleEndTimeChange(time) {
2023
+ this.singleEndTime = time;
2024
+ if (this.singleDate) {
2025
+ this.updateSingleDateTimes();
2026
+ this.emitScheduled();
2027
+ }
2028
+ }
2029
+ updateSingleDateTimes() {
2030
+ if (!this.singleDate)
2031
+ return;
2032
+ if (this.singleAllDay) {
2033
+ this.singleDate.setHours(0, 0, 0, 0);
2034
+ }
2035
+ else {
2036
+ const startTime = this.parseTimeString(this.singleStartTime);
2037
+ const endTime = this.parseTimeString(this.singleEndTime);
2038
+ this.singleDate.setHours(startTime.hours, startTime.minutes, 0, 0);
2039
+ }
2040
+ }
2041
+ // Multiple Dates Handlers
2042
+ onMultipleDatesSelected(event) {
2043
+ if (event.selectedDates && event.selectedDates.length > 0) {
2044
+ const newDates = [];
2045
+ event.selectedDates.forEach(date => {
2046
+ // const dateStr = this.getDateString(date);
2047
+ const dateStr = date;
2048
+ const existing = this.multipleDates.find(d => this.getDateString(d.date) === dateStr);
2049
+ if (existing) {
2050
+ newDates.push(existing);
2051
+ }
2052
+ else {
2053
+ // Create new time configuration for this date
2054
+ newDates.push({
2055
+ date: new Date(date),
2056
+ allDay: false,
2057
+ startTime: '1:00 AM',
2058
+ endTime: '2:00 AM'
2059
+ });
2060
+ }
2061
+ });
2062
+ this.multipleDates = newDates;
2063
+ this.emitScheduled();
2064
+ }
2065
+ else {
2066
+ this.multipleDates = [];
2067
+ this.emitScheduled();
2068
+ }
2069
+ }
2070
+ onMultipleDateAllDayChange(index) {
2071
+ if (this.multipleDates[index]) {
2072
+ this.multipleDates[index].allDay = !this.multipleDates[index].allDay;
2073
+ if (this.multipleDates[index].allDay) {
2074
+ this.multipleDates[index].date.setHours(0, 0, 0, 0);
2075
+ }
2076
+ else {
2077
+ const time = this.parseTimeString(this.multipleDates[index].startTime);
2078
+ this.multipleDates[index].date.setHours(time.hours, time.minutes, 0, 0);
2079
+ }
2080
+ this.emitScheduled();
2081
+ }
2082
+ }
2083
+ onMultipleDateStartTimeChange(index, time) {
2084
+ if (this.multipleDates[index]) {
2085
+ this.multipleDates[index].startTime = time;
2086
+ if (!this.multipleDates[index].allDay) {
2087
+ const parsed = this.parseTimeString(time);
2088
+ this.multipleDates[index].date.setHours(parsed.hours, parsed.minutes, 0, 0);
2089
+ }
2090
+ this.emitScheduled();
2091
+ }
2092
+ }
2093
+ onMultipleDateEndTimeChange(index, time) {
2094
+ if (this.multipleDates[index]) {
2095
+ this.multipleDates[index].endTime = time;
2096
+ this.emitScheduled();
2097
+ }
2098
+ }
2099
+ // Date Range Handlers
2100
+ onRangeSelected(event) {
2101
+ if (event.startDate && event.endDate) {
2102
+ this.rangeStartDate = new Date(event.startDate);
2103
+ this.rangeEndDate = new Date(event.endDate);
2104
+ if (!this.rangeAllDay) {
2105
+ this.updateRangeTimes();
2106
+ }
2107
+ this.emitScheduled();
2108
+ }
2109
+ else {
2110
+ this.rangeStartDate = null;
2111
+ this.rangeEndDate = null;
2112
+ }
2113
+ }
2114
+ onRangeAllDayChange() {
2115
+ this.rangeAllDay = !this.rangeAllDay;
2116
+ if (this.rangeStartDate && this.rangeEndDate) {
2117
+ this.updateRangeTimes();
2118
+ this.emitScheduled();
2119
+ }
2120
+ }
2121
+ onRangeStartTimeChange(time) {
2122
+ this.rangeStartTime = time;
2123
+ if (this.rangeStartDate && !this.rangeAllDay) {
2124
+ this.updateRangeTimes();
2125
+ this.emitScheduled();
2126
+ }
2127
+ }
2128
+ onRangeEndTimeChange(time) {
2129
+ this.rangeEndTime = time;
2130
+ if (this.rangeEndDate && !this.rangeAllDay) {
2131
+ this.updateRangeTimes();
2132
+ this.emitScheduled();
2133
+ }
2134
+ }
2135
+ updateRangeTimes() {
2136
+ if (!this.rangeStartDate || !this.rangeEndDate)
2137
+ return;
2138
+ if (this.rangeAllDay) {
2139
+ this.rangeStartDate.setHours(0, 0, 0, 0);
2140
+ this.rangeEndDate.setHours(23, 59, 59, 999);
2141
+ }
2142
+ else {
2143
+ const startTime = this.parseTimeString(this.rangeStartTime);
2144
+ const endTime = this.parseTimeString(this.rangeEndTime);
2145
+ this.rangeStartDate.setHours(startTime.hours, startTime.minutes, 0, 0);
2146
+ this.rangeEndDate.setHours(endTime.hours, endTime.minutes, 0, 0);
2147
+ }
2148
+ }
2149
+ // Utility Methods
2150
+ parseTimeString(timeStr) {
2151
+ // Parse time string like "7:01 AM" or "19:01"
2152
+ const parts = timeStr.split(' ');
2153
+ let timePart = parts[0];
2154
+ const ampm = parts[1];
2155
+ const [hoursStr, minutesStr] = timePart.split(':');
2156
+ let hours = parseInt(hoursStr, 10);
2157
+ const minutes = parseInt(minutesStr || '0', 10);
2158
+ if (ampm) {
2159
+ if (ampm.toUpperCase() === 'PM' && hours !== 12) {
2160
+ hours += 12;
2161
+ }
2162
+ else if (ampm.toUpperCase() === 'AM' && hours === 12) {
2163
+ hours = 0;
2164
+ }
2165
+ }
2166
+ return { hours, minutes };
2167
+ }
2168
+ getDateString(date) {
2169
+ return `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`;
2170
+ }
2171
+ formatDate(date) {
2172
+ const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
2173
+ return `${months[date.getMonth()]} ${date.getDate()}, ${date.getFullYear()}`;
2174
+ }
2175
+ emitScheduled() {
2176
+ const selection = {
2177
+ mode: this.activeTab
2178
+ };
2179
+ if (this.activeTab === 'single' && this.singleDate) {
2180
+ // For single date, create startDate and endDate with same date but different times
2181
+ const startDate = new Date(this.singleDate);
2182
+ const endDate = new Date(this.singleDate);
2183
+ if (!this.singleAllDay) {
2184
+ const startTime = this.parseTimeString(this.singleStartTime);
2185
+ const endTime = this.parseTimeString(this.singleEndTime);
2186
+ startDate.setHours(startTime.hours, startTime.minutes, 0, 0);
2187
+ endDate.setHours(endTime.hours, endTime.minutes, 0, 0);
2188
+ }
2189
+ else {
2190
+ startDate.setHours(0, 0, 0, 0);
2191
+ endDate.setHours(23, 59, 59, 999);
2192
+ }
2193
+ selection.singleDate = {
2194
+ startDate: startDate,
2195
+ endDate: endDate,
2196
+ allDay: this.singleAllDay,
2197
+ startTime: this.singleStartTime,
2198
+ endTime: this.singleEndTime
2199
+ };
2200
+ }
2201
+ else if (this.activeTab === 'multiple') {
2202
+ selection.multipleDates = this.multipleDates.map(d => ({
2203
+ date: new Date(d.date),
2204
+ allDay: d.allDay,
2205
+ startTime: d.startTime,
2206
+ endTime: d.endTime
2207
+ }));
2208
+ }
2209
+ else if (this.activeTab === 'range' && this.rangeStartDate && this.rangeEndDate) {
2210
+ selection.dateRange = {
2211
+ startDate: new Date(this.rangeStartDate),
2212
+ endDate: new Date(this.rangeEndDate),
2213
+ allDay: this.rangeAllDay,
2214
+ startTime: this.rangeStartTime,
2215
+ endTime: this.rangeEndTime
2216
+ };
2217
+ }
2218
+ this.scheduled.emit(selection);
2219
+ }
2220
+ clear() {
2221
+ this.singleDate = null;
2222
+ this.multipleDates = [];
2223
+ this.rangeStartDate = null;
2224
+ this.rangeEndDate = null;
2225
+ this.singleAllDay = false;
2226
+ this.rangeAllDay = false;
2227
+ this.singleStartTime = '1:00 AM';
2228
+ this.singleEndTime = '2:00 AM';
2229
+ this.rangeStartTime = '1:00 AM';
2230
+ this.rangeEndTime = '2:00 AM';
2231
+ this.cleared.emit();
2232
+ }
2233
+ apply() {
2234
+ this.emitScheduled();
2235
+ }
2236
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkScheduledDatePicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
2237
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: BkScheduledDatePicker, isStandalone: true, selector: "bk-scheduled-date-picker", inputs: { timeFormat: "timeFormat", enableSeconds: "enableSeconds" }, outputs: { scheduled: "scheduled", cleared: "cleared" }, ngImport: i0, template: "<div class=\"scheduled-date-picker-container\">\r\n <!-- Header with Tabs -->\r\n\r\n\r\n <!-- Main Content Area -->\r\n\r\n <div class=\"scheduled-content\">\r\n <!-- Left Side: Calendar -->\r\n <div class=\"calendar-section\">\r\n <h2 class=\"scheduled-title\">Scheduled Dates</h2>\r\n <div class=\"tabs\">\r\n <button\r\n class=\"tab-button\"\r\n [class.active]=\"activeTab === 'single'\"\r\n (click)=\"onTabChange('single')\">\r\n Single Date\r\n </button>\r\n <button\r\n class=\"tab-button\"\r\n [class.active]=\"activeTab === 'multiple'\"\r\n (click)=\"onTabChange('multiple')\">\r\n Multiple Dates\r\n </button>\r\n <button\r\n class=\"tab-button\"\r\n [class.active]=\"activeTab === 'range'\"\r\n (click)=\"onTabChange('range')\">\r\n Date Range\r\n </button>\r\n </div>\r\n <!-- Single Date Calendar -->\r\n <div *ngIf=\"activeTab === 'single'\" class=\"calendar-wrapper-inline\">\r\n <bk-custom-calendar\r\n [inline]=\"true\"\r\n [dualCalendar]=\"false\"\r\n [singleDatePicker]=\"true\"\r\n [showRanges]=\"false\"\r\n [enableTimepicker]=\"false\"\r\n [showCancel]=\"false\"\r\n placeholder=\"Select a date\"\r\n (selected)=\"onSingleDateSelected($event)\">\r\n </bk-custom-calendar>\r\n </div>\r\n\r\n <!-- Multiple Dates Calendar -->\r\n <div *ngIf=\"activeTab === 'multiple'\" class=\"calendar-wrapper-inline\">\r\n <bk-custom-calendar\r\n [inline]=\"true\"\r\n [dualCalendar]=\"false\"\r\n [singleDatePicker]=\"false\"\r\n [showRanges]=\"false\"\r\n [enableTimepicker]=\"false\"\r\n [multiDateSelection]=\"true\"\r\n [showCancel]=\"false\"\r\n placeholder=\"Select multiple dates\"\r\n (selected)=\"onMultipleDatesSelected($event)\">\r\n </bk-custom-calendar>\r\n </div>\r\n\r\n <!-- Date Range Calendar -->\r\n <div *ngIf=\"activeTab === 'range'\" class=\"calendar-wrapper-inline\">\r\n <bk-custom-calendar\r\n [inline]=\"true\"\r\n [dualCalendar]=\"false\"\r\n [singleDatePicker]=\"false\"\r\n [showRanges]=\"false\"\r\n [enableTimepicker]=\"false\"\r\n [showCancel]=\"false\"\r\n placeholder=\"Select date range\"\r\n (selected)=\"onRangeSelected($event)\">\r\n </bk-custom-calendar>\r\n </div>\r\n </div>\r\n\r\n <!-- Right Side: Time Configuration -->\r\n <div class=\"time-config-section\">\r\n <h3 class=\"time-config-title\">Time Configuration</h3>\r\n\r\n <!-- Single Date Time Configuration -->\r\n <div *ngIf=\"activeTab === 'single'\">\r\n <div *ngIf=\"singleDate\" class=\"time-config-item\">\r\n <div class=\"time-config-header\">\r\n <span class=\"date-label\">{{ formatDate(singleDate) }}</span>\r\n <label class=\"all-day-toggle\">\r\n <span class=\"toggle-label\">All Day</span>\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"singleAllDay\"\r\n (change)=\"onSingleAllDayChange()\">\r\n </label>\r\n </div>\r\n <div *ngIf=\"!singleAllDay\" class=\"time-inputs\">\r\n <bk-time-picker\r\n pickerId=\"single-start\"\r\n label=\"Start Time\"\r\n [value]=\"singleStartTime\"\r\n [position]=\"'left'\"\r\n [closePicker]=\"shouldClosePicker('single-start')\"\r\n (timeChange)=\"onSingleStartTimeChange($event)\"\r\n (pickerOpened)=\"onTimePickerOpened($event)\"\r\n (pickerClosed)=\"onTimePickerClosed($event)\">\r\n </bk-time-picker>\r\n <bk-time-picker\r\n pickerId=\"single-end\"\r\n label=\"End Time\"\r\n [value]=\"singleEndTime\"\r\n [position]=\"'right'\"\r\n [closePicker]=\"shouldClosePicker('single-end')\"\r\n (timeChange)=\"onSingleEndTimeChange($event)\"\r\n (pickerOpened)=\"onTimePickerOpened($event)\"\r\n (pickerClosed)=\"onTimePickerClosed($event)\">\r\n </bk-time-picker>\r\n </div>\r\n </div>\r\n <div *ngIf=\"!singleDate\" class=\"no-selection\">\r\n <p>No date selected. Select a date from the calendar.</p>\r\n </div>\r\n </div>\r\n\r\n <!-- Multiple Dates Time Configuration -->\r\n <div *ngIf=\"activeTab === 'multiple'\" class=\"time-config-list\">\r\n <div\r\n *ngFor=\"let dateConfig of multipleDates; let i = index\"\r\n class=\"time-config-item\">\r\n <div class=\"time-config-header\">\r\n <span class=\"date-label\">{{ formatDate(dateConfig.date) }}</span>\r\n <label class=\"all-day-toggle\">\r\n <span class=\"toggle-label\">All Day</span>\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"dateConfig.allDay\"\r\n (change)=\"onMultipleDateAllDayChange(i)\">\r\n </label>\r\n </div>\r\n <div *ngIf=\"!dateConfig.allDay\" class=\"time-inputs\">\r\n <bk-time-picker\r\n [pickerId]=\"'multiple-' + i + '-start'\"\r\n label=\"Start Time\"\r\n [value]=\"dateConfig.startTime\"\r\n [position]=\"'left'\"\r\n [closePicker]=\"shouldClosePicker('multiple-' + i + '-start')\"\r\n (timeChange)=\"onMultipleDateStartTimeChange(i, $event)\"\r\n (pickerOpened)=\"onTimePickerOpened($event)\"\r\n (pickerClosed)=\"onTimePickerClosed($event)\">\r\n </bk-time-picker>\r\n <bk-time-picker\r\n [pickerId]=\"'multiple-' + i + '-end'\"\r\n label=\"End Time\"\r\n [value]=\"dateConfig.endTime\"\r\n [position]=\"'right'\"\r\n [closePicker]=\"shouldClosePicker('multiple-' + i + '-end')\"\r\n (timeChange)=\"onMultipleDateEndTimeChange(i, $event)\"\r\n (pickerOpened)=\"onTimePickerOpened($event)\"\r\n (pickerClosed)=\"onTimePickerClosed($event)\">\r\n </bk-time-picker>\r\n </div>\r\n </div>\r\n <div *ngIf=\"multipleDates.length === 0\" class=\"no-selection\">\r\n <p>No dates selected. Select dates from the calendar.</p>\r\n </div>\r\n </div>\r\n\r\n <!-- Date Range Time Configuration -->\r\n <div *ngIf=\"activeTab === 'range' && rangeStartDate && rangeEndDate\" class=\"time-config-item\">\r\n <div class=\"time-config-header\">\r\n <span class=\"date-label\">{{ formatDate(rangeStartDate) }} - {{ formatDate(rangeEndDate) }}</span>\r\n <label class=\"all-day-toggle\">\r\n <span class=\"toggle-label\">All Day</span>\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"rangeAllDay\"\r\n (change)=\"onRangeAllDayChange()\">\r\n </label>\r\n </div>\r\n <div *ngIf=\"!rangeAllDay\" class=\"time-inputs\">\r\n <bk-time-picker\r\n pickerId=\"range-start\"\r\n label=\"Start Time\"\r\n [value]=\"rangeStartTime\"\r\n [position]=\"'left'\"\r\n [closePicker]=\"shouldClosePicker('range-start')\"\r\n (timeChange)=\"onRangeStartTimeChange($event)\"\r\n (pickerOpened)=\"onTimePickerOpened($event)\"\r\n (pickerClosed)=\"onTimePickerClosed($event)\">\r\n </bk-time-picker>\r\n <bk-time-picker\r\n pickerId=\"range-end\"\r\n label=\"End Time\"\r\n [value]=\"rangeEndTime\"\r\n [position]=\"'right'\"\r\n [closePicker]=\"shouldClosePicker('range-end')\"\r\n (timeChange)=\"onRangeEndTimeChange($event)\"\r\n (pickerOpened)=\"onTimePickerOpened($event)\"\r\n (pickerClosed)=\"onTimePickerClosed($event)\">\r\n </bk-time-picker>\r\n </div>\r\n </div>\r\n <div *ngIf=\"activeTab === 'range' && (!rangeStartDate || !rangeEndDate)\" class=\"no-selection\">\r\n <p>No date range selected. Select a date range from the calendar.</p>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Action Buttons -->\r\n <div class=\"action-buttons\">\r\n <button class=\"btn-clear\" (click)=\"clear()\">Clear</button>\r\n <button class=\"btn-apply\" (click)=\"apply()\">Apply</button>\r\n </div>\r\n</div>\r\n\r\n", styles: [".scheduled-date-picker-container{font-family:Inter,sans-serif;background:#fff;border-radius:12px;padding:0;box-shadow:0 2px 8px #0000001a;overflow:hidden;width:100%;max-width:100%;box-sizing:border-box}.scheduled-header{padding:24px 24px 16px;border-bottom:1px solid #e5e7eb;background:#fff}.scheduled-title{font-size:18px;font-weight:500;line-height:26px;color:#111827;letter-spacing:-.28px;margin:0 0 16px}.tabs{display:flex;margin-bottom:16px;border-radius:6px;padding:3px;background-color:#54578e12}.tab-button{padding:5px 11px;border:none;background:transparent;color:#6b7080;font-size:11px;font-weight:500;cursor:pointer;border:1px solid transparent;transition:all .2s;font-family:Inter,sans-serif;flex:1;border-radius:4px}.tab-button.active{color:#15191e;border-color:#42578a26;background:#fff}.scheduled-content{display:flex;gap:0;align-items:stretch}.calendar-section{flex:0 0 55%;max-width:55%;padding:12px;border-right:1px solid #e5e7eb;background:#fff;box-sizing:border-box}.calendar-wrapper-inline{width:100%}.calendar-wrapper-inline app-custom-calendar{width:100%}.time-config-section{flex:0 0 45%;max-width:45%;padding:12px;background:#fff;overflow-y:auto;max-height:600px;box-sizing:border-box}.time-config-title{font-size:16px;font-weight:600;color:#111827;margin:17px 0 14px}.time-config-item{padding:14px;border:1px solid #e5e7eb;border-radius:8px;background:#fff}.time-config-header{display:flex;justify-content:space-between;align-items:center}.date-label{font-size:12px;font-weight:500;color:#15191e;letter-spacing:-.28px}.all-day-toggle{display:flex;align-items:center;gap:5px;cursor:pointer;-webkit-user-select:none;user-select:none}.all-day-toggle input[type=checkbox]{width:28px;height:16px;appearance:none;background:#bbbdc5;border-radius:10px;position:relative;cursor:pointer;transition:background .2s;margin:0}.all-day-toggle input[type=checkbox]:checked{background:#22973f}.all-day-toggle input[type=checkbox]:before{content:\"\";position:absolute;width:12px;height:12px;border-radius:50%;background:#fff;top:1.5px;left:2.5px;transition:transform .2s;box-shadow:0 1px 3px #0003}.all-day-toggle input[type=checkbox]:checked:before{transform:translate(12px)}.toggle-label{font-size:12px;font-weight:500;color:#111827}.all-day-toggle input[type=checkbox]:checked+.toggle-label{color:#111827}.time-inputs{display:flex;gap:14px;margin-top:12px}.time-config-list{display:flex;flex-direction:column;gap:14px;max-height:350px;overflow-y:auto;padding-right:4px}.time-config-list::-webkit-scrollbar{width:6px;height:6px}.time-config-list::-webkit-scrollbar-track{background:#f1f1f1;border-radius:3px}.time-config-list::-webkit-scrollbar-thumb{background:#b4b4b4;border-radius:3px}.time-config-list::-webkit-scrollbar-thumb:hover{background:#9b9b9b}.no-selection{padding:24px;text-align:center;color:#9ca3af;font-size:14px}.action-buttons{display:flex;justify-content:flex-end;gap:12px;padding:12px;border-top:1px solid #e5e7eb;background:#fff}.btn-clear,.btn-apply{padding:10px 20px;border:none;border-radius:6px;font-size:14px;font-weight:500;cursor:pointer;transition:all .2s;font-family:Inter,sans-serif;min-width:80px}.btn-clear{background:#fff;color:#6b7280;border:1px solid #d1d5db}.btn-clear:hover{background:#f9fafb;border-color:#9ca3af}.btn-apply{background:#111827;color:#fff}.btn-apply:hover{background:#374151}@media (max-width: 1200px){.calendar-section{flex:0 0 52%;max-width:52%}.time-config-section{flex:0 0 48%;max-width:48%}}@media (max-width: 1024px){.scheduled-content{flex-direction:column}.calendar-section{flex:1 1 auto;max-width:100%;border-right:none;border-bottom:1px solid #e5e7eb}.time-config-section{flex:1 1 auto;max-width:100%;max-height:none}.time-config-list{max-height:320px}}@media (max-width: 768px){.scheduled-date-picker-container{border-radius:0}.scheduled-header{padding:16px}.calendar-section,.time-config-section{padding:12px 16px}.tabs{overflow-x:auto}.tab-button{white-space:nowrap;font-size:12px;padding:6px 10px}.time-inputs{flex-direction:column}.time-config-item{padding:12px}.action-buttons{padding:10px}}@media (max-width: 480px){.scheduled-title{font-size:16px}.time-config-title{font-size:14px}.date-label{font-size:11px}.time-config-list{max-height:260px}.btn-clear,.btn-apply{padding:8px 14px;font-size:13px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: BkCustomCalendar, selector: "bk-custom-calendar", inputs: ["enableTimepicker", "autoApply", "closeOnAutoApply", "showCancel", "linkedCalendars", "singleDatePicker", "showWeekNumbers", "showISOWeekNumbers", "customRangeDirection", "lockStartDate", "position", "drop", "dualCalendar", "showRanges", "timeFormat", "enableSeconds", "customRanges", "multiDateSelection", "maxDate", "minDate", "placeholder", "opens", "inline", "isDisplayCrossIcon", "selectedValue", "displayFormat", "startDate", "endDate"], outputs: ["selected", "opened", "closed"] }, { kind: "component", type: BkTimePicker, selector: "bk-time-picker", inputs: ["value", "label", "placeholder", "position", "pickerId", "closePicker", "timeFormat", "showSeconds"], outputs: ["timeChange", "pickerOpened", "pickerClosed"] }] });
2238
+ }
2239
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkScheduledDatePicker, decorators: [{
2240
+ type: Component,
2241
+ args: [{ selector: 'bk-scheduled-date-picker', standalone: true, imports: [CommonModule, FormsModule, BkCustomCalendar, BkTimePicker], template: "<div class=\"scheduled-date-picker-container\">\r\n <!-- Header with Tabs -->\r\n\r\n\r\n <!-- Main Content Area -->\r\n\r\n <div class=\"scheduled-content\">\r\n <!-- Left Side: Calendar -->\r\n <div class=\"calendar-section\">\r\n <h2 class=\"scheduled-title\">Scheduled Dates</h2>\r\n <div class=\"tabs\">\r\n <button\r\n class=\"tab-button\"\r\n [class.active]=\"activeTab === 'single'\"\r\n (click)=\"onTabChange('single')\">\r\n Single Date\r\n </button>\r\n <button\r\n class=\"tab-button\"\r\n [class.active]=\"activeTab === 'multiple'\"\r\n (click)=\"onTabChange('multiple')\">\r\n Multiple Dates\r\n </button>\r\n <button\r\n class=\"tab-button\"\r\n [class.active]=\"activeTab === 'range'\"\r\n (click)=\"onTabChange('range')\">\r\n Date Range\r\n </button>\r\n </div>\r\n <!-- Single Date Calendar -->\r\n <div *ngIf=\"activeTab === 'single'\" class=\"calendar-wrapper-inline\">\r\n <bk-custom-calendar\r\n [inline]=\"true\"\r\n [dualCalendar]=\"false\"\r\n [singleDatePicker]=\"true\"\r\n [showRanges]=\"false\"\r\n [enableTimepicker]=\"false\"\r\n [showCancel]=\"false\"\r\n placeholder=\"Select a date\"\r\n (selected)=\"onSingleDateSelected($event)\">\r\n </bk-custom-calendar>\r\n </div>\r\n\r\n <!-- Multiple Dates Calendar -->\r\n <div *ngIf=\"activeTab === 'multiple'\" class=\"calendar-wrapper-inline\">\r\n <bk-custom-calendar\r\n [inline]=\"true\"\r\n [dualCalendar]=\"false\"\r\n [singleDatePicker]=\"false\"\r\n [showRanges]=\"false\"\r\n [enableTimepicker]=\"false\"\r\n [multiDateSelection]=\"true\"\r\n [showCancel]=\"false\"\r\n placeholder=\"Select multiple dates\"\r\n (selected)=\"onMultipleDatesSelected($event)\">\r\n </bk-custom-calendar>\r\n </div>\r\n\r\n <!-- Date Range Calendar -->\r\n <div *ngIf=\"activeTab === 'range'\" class=\"calendar-wrapper-inline\">\r\n <bk-custom-calendar\r\n [inline]=\"true\"\r\n [dualCalendar]=\"false\"\r\n [singleDatePicker]=\"false\"\r\n [showRanges]=\"false\"\r\n [enableTimepicker]=\"false\"\r\n [showCancel]=\"false\"\r\n placeholder=\"Select date range\"\r\n (selected)=\"onRangeSelected($event)\">\r\n </bk-custom-calendar>\r\n </div>\r\n </div>\r\n\r\n <!-- Right Side: Time Configuration -->\r\n <div class=\"time-config-section\">\r\n <h3 class=\"time-config-title\">Time Configuration</h3>\r\n\r\n <!-- Single Date Time Configuration -->\r\n <div *ngIf=\"activeTab === 'single'\">\r\n <div *ngIf=\"singleDate\" class=\"time-config-item\">\r\n <div class=\"time-config-header\">\r\n <span class=\"date-label\">{{ formatDate(singleDate) }}</span>\r\n <label class=\"all-day-toggle\">\r\n <span class=\"toggle-label\">All Day</span>\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"singleAllDay\"\r\n (change)=\"onSingleAllDayChange()\">\r\n </label>\r\n </div>\r\n <div *ngIf=\"!singleAllDay\" class=\"time-inputs\">\r\n <bk-time-picker\r\n pickerId=\"single-start\"\r\n label=\"Start Time\"\r\n [value]=\"singleStartTime\"\r\n [position]=\"'left'\"\r\n [closePicker]=\"shouldClosePicker('single-start')\"\r\n (timeChange)=\"onSingleStartTimeChange($event)\"\r\n (pickerOpened)=\"onTimePickerOpened($event)\"\r\n (pickerClosed)=\"onTimePickerClosed($event)\">\r\n </bk-time-picker>\r\n <bk-time-picker\r\n pickerId=\"single-end\"\r\n label=\"End Time\"\r\n [value]=\"singleEndTime\"\r\n [position]=\"'right'\"\r\n [closePicker]=\"shouldClosePicker('single-end')\"\r\n (timeChange)=\"onSingleEndTimeChange($event)\"\r\n (pickerOpened)=\"onTimePickerOpened($event)\"\r\n (pickerClosed)=\"onTimePickerClosed($event)\">\r\n </bk-time-picker>\r\n </div>\r\n </div>\r\n <div *ngIf=\"!singleDate\" class=\"no-selection\">\r\n <p>No date selected. Select a date from the calendar.</p>\r\n </div>\r\n </div>\r\n\r\n <!-- Multiple Dates Time Configuration -->\r\n <div *ngIf=\"activeTab === 'multiple'\" class=\"time-config-list\">\r\n <div\r\n *ngFor=\"let dateConfig of multipleDates; let i = index\"\r\n class=\"time-config-item\">\r\n <div class=\"time-config-header\">\r\n <span class=\"date-label\">{{ formatDate(dateConfig.date) }}</span>\r\n <label class=\"all-day-toggle\">\r\n <span class=\"toggle-label\">All Day</span>\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"dateConfig.allDay\"\r\n (change)=\"onMultipleDateAllDayChange(i)\">\r\n </label>\r\n </div>\r\n <div *ngIf=\"!dateConfig.allDay\" class=\"time-inputs\">\r\n <bk-time-picker\r\n [pickerId]=\"'multiple-' + i + '-start'\"\r\n label=\"Start Time\"\r\n [value]=\"dateConfig.startTime\"\r\n [position]=\"'left'\"\r\n [closePicker]=\"shouldClosePicker('multiple-' + i + '-start')\"\r\n (timeChange)=\"onMultipleDateStartTimeChange(i, $event)\"\r\n (pickerOpened)=\"onTimePickerOpened($event)\"\r\n (pickerClosed)=\"onTimePickerClosed($event)\">\r\n </bk-time-picker>\r\n <bk-time-picker\r\n [pickerId]=\"'multiple-' + i + '-end'\"\r\n label=\"End Time\"\r\n [value]=\"dateConfig.endTime\"\r\n [position]=\"'right'\"\r\n [closePicker]=\"shouldClosePicker('multiple-' + i + '-end')\"\r\n (timeChange)=\"onMultipleDateEndTimeChange(i, $event)\"\r\n (pickerOpened)=\"onTimePickerOpened($event)\"\r\n (pickerClosed)=\"onTimePickerClosed($event)\">\r\n </bk-time-picker>\r\n </div>\r\n </div>\r\n <div *ngIf=\"multipleDates.length === 0\" class=\"no-selection\">\r\n <p>No dates selected. Select dates from the calendar.</p>\r\n </div>\r\n </div>\r\n\r\n <!-- Date Range Time Configuration -->\r\n <div *ngIf=\"activeTab === 'range' && rangeStartDate && rangeEndDate\" class=\"time-config-item\">\r\n <div class=\"time-config-header\">\r\n <span class=\"date-label\">{{ formatDate(rangeStartDate) }} - {{ formatDate(rangeEndDate) }}</span>\r\n <label class=\"all-day-toggle\">\r\n <span class=\"toggle-label\">All Day</span>\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"rangeAllDay\"\r\n (change)=\"onRangeAllDayChange()\">\r\n </label>\r\n </div>\r\n <div *ngIf=\"!rangeAllDay\" class=\"time-inputs\">\r\n <bk-time-picker\r\n pickerId=\"range-start\"\r\n label=\"Start Time\"\r\n [value]=\"rangeStartTime\"\r\n [position]=\"'left'\"\r\n [closePicker]=\"shouldClosePicker('range-start')\"\r\n (timeChange)=\"onRangeStartTimeChange($event)\"\r\n (pickerOpened)=\"onTimePickerOpened($event)\"\r\n (pickerClosed)=\"onTimePickerClosed($event)\">\r\n </bk-time-picker>\r\n <bk-time-picker\r\n pickerId=\"range-end\"\r\n label=\"End Time\"\r\n [value]=\"rangeEndTime\"\r\n [position]=\"'right'\"\r\n [closePicker]=\"shouldClosePicker('range-end')\"\r\n (timeChange)=\"onRangeEndTimeChange($event)\"\r\n (pickerOpened)=\"onTimePickerOpened($event)\"\r\n (pickerClosed)=\"onTimePickerClosed($event)\">\r\n </bk-time-picker>\r\n </div>\r\n </div>\r\n <div *ngIf=\"activeTab === 'range' && (!rangeStartDate || !rangeEndDate)\" class=\"no-selection\">\r\n <p>No date range selected. Select a date range from the calendar.</p>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Action Buttons -->\r\n <div class=\"action-buttons\">\r\n <button class=\"btn-clear\" (click)=\"clear()\">Clear</button>\r\n <button class=\"btn-apply\" (click)=\"apply()\">Apply</button>\r\n </div>\r\n</div>\r\n\r\n", styles: [".scheduled-date-picker-container{font-family:Inter,sans-serif;background:#fff;border-radius:12px;padding:0;box-shadow:0 2px 8px #0000001a;overflow:hidden;width:100%;max-width:100%;box-sizing:border-box}.scheduled-header{padding:24px 24px 16px;border-bottom:1px solid #e5e7eb;background:#fff}.scheduled-title{font-size:18px;font-weight:500;line-height:26px;color:#111827;letter-spacing:-.28px;margin:0 0 16px}.tabs{display:flex;margin-bottom:16px;border-radius:6px;padding:3px;background-color:#54578e12}.tab-button{padding:5px 11px;border:none;background:transparent;color:#6b7080;font-size:11px;font-weight:500;cursor:pointer;border:1px solid transparent;transition:all .2s;font-family:Inter,sans-serif;flex:1;border-radius:4px}.tab-button.active{color:#15191e;border-color:#42578a26;background:#fff}.scheduled-content{display:flex;gap:0;align-items:stretch}.calendar-section{flex:0 0 55%;max-width:55%;padding:12px;border-right:1px solid #e5e7eb;background:#fff;box-sizing:border-box}.calendar-wrapper-inline{width:100%}.calendar-wrapper-inline app-custom-calendar{width:100%}.time-config-section{flex:0 0 45%;max-width:45%;padding:12px;background:#fff;overflow-y:auto;max-height:600px;box-sizing:border-box}.time-config-title{font-size:16px;font-weight:600;color:#111827;margin:17px 0 14px}.time-config-item{padding:14px;border:1px solid #e5e7eb;border-radius:8px;background:#fff}.time-config-header{display:flex;justify-content:space-between;align-items:center}.date-label{font-size:12px;font-weight:500;color:#15191e;letter-spacing:-.28px}.all-day-toggle{display:flex;align-items:center;gap:5px;cursor:pointer;-webkit-user-select:none;user-select:none}.all-day-toggle input[type=checkbox]{width:28px;height:16px;appearance:none;background:#bbbdc5;border-radius:10px;position:relative;cursor:pointer;transition:background .2s;margin:0}.all-day-toggle input[type=checkbox]:checked{background:#22973f}.all-day-toggle input[type=checkbox]:before{content:\"\";position:absolute;width:12px;height:12px;border-radius:50%;background:#fff;top:1.5px;left:2.5px;transition:transform .2s;box-shadow:0 1px 3px #0003}.all-day-toggle input[type=checkbox]:checked:before{transform:translate(12px)}.toggle-label{font-size:12px;font-weight:500;color:#111827}.all-day-toggle input[type=checkbox]:checked+.toggle-label{color:#111827}.time-inputs{display:flex;gap:14px;margin-top:12px}.time-config-list{display:flex;flex-direction:column;gap:14px;max-height:350px;overflow-y:auto;padding-right:4px}.time-config-list::-webkit-scrollbar{width:6px;height:6px}.time-config-list::-webkit-scrollbar-track{background:#f1f1f1;border-radius:3px}.time-config-list::-webkit-scrollbar-thumb{background:#b4b4b4;border-radius:3px}.time-config-list::-webkit-scrollbar-thumb:hover{background:#9b9b9b}.no-selection{padding:24px;text-align:center;color:#9ca3af;font-size:14px}.action-buttons{display:flex;justify-content:flex-end;gap:12px;padding:12px;border-top:1px solid #e5e7eb;background:#fff}.btn-clear,.btn-apply{padding:10px 20px;border:none;border-radius:6px;font-size:14px;font-weight:500;cursor:pointer;transition:all .2s;font-family:Inter,sans-serif;min-width:80px}.btn-clear{background:#fff;color:#6b7280;border:1px solid #d1d5db}.btn-clear:hover{background:#f9fafb;border-color:#9ca3af}.btn-apply{background:#111827;color:#fff}.btn-apply:hover{background:#374151}@media (max-width: 1200px){.calendar-section{flex:0 0 52%;max-width:52%}.time-config-section{flex:0 0 48%;max-width:48%}}@media (max-width: 1024px){.scheduled-content{flex-direction:column}.calendar-section{flex:1 1 auto;max-width:100%;border-right:none;border-bottom:1px solid #e5e7eb}.time-config-section{flex:1 1 auto;max-width:100%;max-height:none}.time-config-list{max-height:320px}}@media (max-width: 768px){.scheduled-date-picker-container{border-radius:0}.scheduled-header{padding:16px}.calendar-section,.time-config-section{padding:12px 16px}.tabs{overflow-x:auto}.tab-button{white-space:nowrap;font-size:12px;padding:6px 10px}.time-inputs{flex-direction:column}.time-config-item{padding:12px}.action-buttons{padding:10px}}@media (max-width: 480px){.scheduled-title{font-size:16px}.time-config-title{font-size:14px}.date-label{font-size:11px}.time-config-list{max-height:260px}.btn-clear,.btn-apply{padding:8px 14px;font-size:13px}}\n"] }]
2242
+ }], propDecorators: { timeFormat: [{
2243
+ type: Input
2244
+ }], enableSeconds: [{
2245
+ type: Input
2246
+ }], scheduled: [{
2247
+ type: Output
2248
+ }], cleared: [{
2249
+ type: Output
2250
+ }] } });
2251
+
2252
+ /**
2253
+ * Optional NgModule wrapper for projects that prefer module-based usage.
2254
+ *
2255
+ * Note:
2256
+ * - The components themselves are standalone, so you can also import them
2257
+ * directly into any standalone component without using this module.
2258
+ * - This module is mainly for:
2259
+ * - Existing apps that still use feature modules
2260
+ * - Easier "plug-and-play" integration: import CalendarModule once and use
2261
+ * the three exported components anywhere in your templates.
2262
+ */
2263
+ class CalendarModule {
2264
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CalendarModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
2265
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.16", ngImport: i0, type: CalendarModule, imports: [CommonModule,
2266
+ BkCustomCalendar,
2267
+ BkScheduledDatePicker,
2268
+ BkTimePicker], exports: [BkCustomCalendar,
2269
+ BkScheduledDatePicker,
2270
+ BkTimePicker] });
2271
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CalendarModule, imports: [CommonModule,
2272
+ BkCustomCalendar,
2273
+ BkScheduledDatePicker,
2274
+ BkTimePicker] });
2275
+ }
2276
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CalendarModule, decorators: [{
2277
+ type: NgModule,
2278
+ args: [{
2279
+ imports: [
2280
+ CommonModule,
2281
+ BkCustomCalendar,
2282
+ BkScheduledDatePicker,
2283
+ BkTimePicker
2284
+ ],
2285
+ exports: [
2286
+ BkCustomCalendar,
2287
+ BkScheduledDatePicker,
2288
+ BkTimePicker
2289
+ ]
2290
+ }]
2291
+ }] });
2292
+
2293
+ class BkToggle {
2294
+ label = '';
2295
+ disabled = false;
2296
+ toggleClass = 'toggle-md';
2297
+ change = new EventEmitter();
2298
+ isChecked = false;
2299
+ // CVA callbacks (placeholders)
2300
+ onChange = (_) => { };
2301
+ onTouched = () => { };
2302
+ toggle() {
2303
+ if (this.disabled)
2304
+ return;
2305
+ this.isChecked = !this.isChecked;
2306
+ this.onChange(this.isChecked); // Notify Forms API
2307
+ this.onTouched(); // Notify Validation API
2308
+ this.change.emit(this.isChecked); // Notify standard event listeners
2309
+ }
2310
+ // Called by Angular to write value to the view
2311
+ writeValue(value) {
2312
+ this.isChecked = value;
2313
+ }
2314
+ // Called by Angular to register the function to call when changed
2315
+ registerOnChange(fn) {
2316
+ this.onChange = fn;
2317
+ }
2318
+ // Called by Angular to register the function to call when touched
2319
+ registerOnTouched(fn) {
2320
+ this.onTouched = fn;
2321
+ }
2322
+ // Called by Angular when the disabled state changes
2323
+ setDisabledState(isDisabled) {
2324
+ this.disabled = isDisabled;
2325
+ }
2326
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkToggle, deps: [], target: i0.ɵɵFactoryTarget.Component });
2327
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkToggle, isStandalone: true, selector: "bk-toggle", inputs: { label: "label", disabled: "disabled", toggleClass: "toggleClass" }, outputs: { change: "change" }, providers: [
2328
+ {
2329
+ provide: NG_VALUE_ACCESSOR,
2330
+ useExisting: forwardRef(() => BkToggle),
2331
+ multi: true
2332
+ }
2333
+ ], ngImport: i0, template: "<div class=\"inline-flex items-center gap-2 cursor-pointer\" (click)=\"toggle()\">\r\n <button\r\n type=\"button\"\r\n role=\"switch\"\r\n [attr.aria-checked]=\"isChecked\"\r\n [disabled]=\"disabled\"\r\n class=\"toggle-base\"\r\n [ngClass]=\"toggleClass\"\r\n [class.toggle-on]=\"isChecked\"\r\n [class.toggle-off]=\"!isChecked\"\r\n [class.toggle-disabled]=\"disabled\"\r\n >\r\n <span\r\n class=\"toggle-knob\"\r\n [class.knob-on]=\"isChecked\"\r\n [class.knob-off]=\"!isChecked\"\r\n ></span>\r\n </button>\r\n @if (label){\r\n <span class=\"text-sm font-medium text-[#1B223A] select-none\" [class.opacity-70]=\"disabled\">\r\n {{ label }}\r\n </span>\r\n }\r\n</div>\r\n", styles: [".toggle-base{@apply relative inline-flex items-center rounded-full transition-colors duration-200 ease-in-out border-2 border-transparent;@apply focus:outline-none focus-visible:ring-2 focus-visible:ring-[#1336EF] focus-visible:ring-offset-2;}.toggle-off{@apply bg-[#BBBDC5] hover:bg-[#A1A3AE];}.toggle-on{@apply bg-[#22973F] hover:bg-[#1E7735];}.toggle-disabled{@apply bg-[#D6D7DC] hover:bg-[#D6D7DC] cursor-not-allowed;}.toggle-knob{@apply pointer-events-none inline-block transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out;}.toggle-sm{@apply w-7;}.toggle-sm .toggle-knob{@apply h-3 w-3;}.toggle-sm .knob-on{@apply translate-x-3;}.toggle-sm .knob-off{@apply translate-x-0;}.toggle-md{@apply w-9;}.toggle-md .toggle-knob{@apply h-4 w-4;}.toggle-md .knob-on{@apply translate-x-4;}.toggle-md .knob-off{@apply translate-x-0;}.toggle-lg{@apply w-11;}.toggle-lg .toggle-knob{@apply h-5 w-5;}.toggle-lg .knob-on{@apply translate-x-5;}.toggle-lg .knob-off{@apply translate-x-0;}.simulate-hover.toggle-off{@apply bg-[#A1A3AE];}.simulate-hover.toggle-on{@apply bg-[#1E7735];}.simulate-focus{@apply ring-2 ring-[#1336EF] ring-offset-2;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], encapsulation: i0.ViewEncapsulation.None });
2334
+ }
2335
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkToggle, decorators: [{
2336
+ type: Component,
2337
+ args: [{ selector: 'bk-toggle', standalone: true, imports: [CommonModule], encapsulation: ViewEncapsulation.None, providers: [
2338
+ {
2339
+ provide: NG_VALUE_ACCESSOR,
2340
+ useExisting: forwardRef(() => BkToggle),
2341
+ multi: true
2342
+ }
2343
+ ], template: "<div class=\"inline-flex items-center gap-2 cursor-pointer\" (click)=\"toggle()\">\r\n <button\r\n type=\"button\"\r\n role=\"switch\"\r\n [attr.aria-checked]=\"isChecked\"\r\n [disabled]=\"disabled\"\r\n class=\"toggle-base\"\r\n [ngClass]=\"toggleClass\"\r\n [class.toggle-on]=\"isChecked\"\r\n [class.toggle-off]=\"!isChecked\"\r\n [class.toggle-disabled]=\"disabled\"\r\n >\r\n <span\r\n class=\"toggle-knob\"\r\n [class.knob-on]=\"isChecked\"\r\n [class.knob-off]=\"!isChecked\"\r\n ></span>\r\n </button>\r\n @if (label){\r\n <span class=\"text-sm font-medium text-[#1B223A] select-none\" [class.opacity-70]=\"disabled\">\r\n {{ label }}\r\n </span>\r\n }\r\n</div>\r\n", styles: [".toggle-base{@apply relative inline-flex items-center rounded-full transition-colors duration-200 ease-in-out border-2 border-transparent;@apply focus:outline-none focus-visible:ring-2 focus-visible:ring-[#1336EF] focus-visible:ring-offset-2;}.toggle-off{@apply bg-[#BBBDC5] hover:bg-[#A1A3AE];}.toggle-on{@apply bg-[#22973F] hover:bg-[#1E7735];}.toggle-disabled{@apply bg-[#D6D7DC] hover:bg-[#D6D7DC] cursor-not-allowed;}.toggle-knob{@apply pointer-events-none inline-block transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out;}.toggle-sm{@apply w-7;}.toggle-sm .toggle-knob{@apply h-3 w-3;}.toggle-sm .knob-on{@apply translate-x-3;}.toggle-sm .knob-off{@apply translate-x-0;}.toggle-md{@apply w-9;}.toggle-md .toggle-knob{@apply h-4 w-4;}.toggle-md .knob-on{@apply translate-x-4;}.toggle-md .knob-off{@apply translate-x-0;}.toggle-lg{@apply w-11;}.toggle-lg .toggle-knob{@apply h-5 w-5;}.toggle-lg .knob-on{@apply translate-x-5;}.toggle-lg .knob-off{@apply translate-x-0;}.simulate-hover.toggle-off{@apply bg-[#A1A3AE];}.simulate-hover.toggle-on{@apply bg-[#1E7735];}.simulate-focus{@apply ring-2 ring-[#1336EF] ring-offset-2;}\n"] }]
2344
+ }], propDecorators: { label: [{
2345
+ type: Input
2346
+ }], disabled: [{
2347
+ type: Input
2348
+ }], toggleClass: [{
2349
+ type: Input
2350
+ }], change: [{
2351
+ type: Output
2352
+ }] } });
2353
+
2354
+ class BkCheckbox {
2355
+ checkboxClass = '';
2356
+ label = '';
2357
+ labelClass = '';
2358
+ disabled = false;
2359
+ change = new EventEmitter();
2360
+ // This is the value bound via ngModel
2361
+ isChecked = false;
2362
+ // ControlValueAccessor callbacks
2363
+ onChange = (_) => { };
2364
+ onTouched = () => { };
2365
+ // Toggle function for click / keyboard
2366
+ toggle() {
2367
+ if (this.disabled)
2368
+ return;
2369
+ this.isChecked = !this.isChecked;
2370
+ // Update ngModel value
2371
+ this.onChange(this.isChecked);
2372
+ this.onTouched();
2373
+ // Emit the change event
2374
+ this.change.emit(this.isChecked);
2375
+ }
2376
+ /** ------------------ ControlValueAccessor methods ------------------ */
2377
+ writeValue(value) {
2378
+ this.isChecked = value ?? false; // handle null/undefined safely
2379
+ }
2380
+ registerOnChange(fn) {
2381
+ this.onChange = fn;
2382
+ }
2383
+ registerOnTouched(fn) {
2384
+ this.onTouched = fn;
2385
+ }
2386
+ setDisabledState(isDisabled) {
2387
+ this.disabled = isDisabled;
2388
+ }
2389
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkCheckbox, deps: [], target: i0.ɵɵFactoryTarget.Component });
2390
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkCheckbox, isStandalone: true, selector: "bk-checkbox", inputs: { checkboxClass: "checkboxClass", label: "label", labelClass: "labelClass", disabled: "disabled" }, outputs: { change: "change" }, providers: [
2391
+ {
2392
+ provide: NG_VALUE_ACCESSOR,
2393
+ useExisting: forwardRef(() => BkCheckbox),
2394
+ multi: true
2395
+ }
2396
+ ], ngImport: i0, template: "<div\r\n class=\"inline-flex items-center gap-2 cursor-pointer group outline-none\"\r\n (click)=\"toggle()\"\r\n (keydown.enter)=\"toggle()\"\r\n (keydown.space)=\"$event.preventDefault(); toggle()\"\r\n tabindex=\"0\"\r\n [attr.aria-disabled]=\"disabled\">\r\n <div\r\n class=\"relative flex items-center justify-center border-2 transition-all duration-200 ease-in-out rounded group-focus-visible:ring-2 group-focus-visible:ring-blue-600 group-focus-visible:ring-offset-2 checkbox\"\r\n [ngClass]=\"[\r\n checkboxClass,\r\n isChecked && !disabled ? 'bg-black border-black' : '',\r\n !isChecked && !disabled ? 'bg-white border-gray-300 group-hover:border-gray-400' : '',\r\n disabled && isChecked ? 'bg-gray-300 border-gray-300' : '',\r\n disabled && !isChecked ? 'bg-gray-100 border-gray-200' : '',\r\n disabled ? 'cursor-not-allowed' : ''\r\n ]\"\r\n >\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"3.5\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n class=\"text-white pointer-events-none transition-opacity duration-200\"\r\n [class.opacity-0]=\"!isChecked\"\r\n [class.opacity-100]=\"isChecked\"\r\n >\r\n <polyline points=\"20 6 9 17 4 12\"></polyline>\r\n </svg>\r\n </div>\r\n@if(label){\r\n <span\r\n [ngClass]=\"disabled ? 'text-gray-400' : ''\"\r\n class=\"font-medium text-xs text-[#1B223A] select-none {{labelClass}}\"\r\n >\r\n {{ label }}\r\n </span>\r\n}\r\n</div>\r\n", styles: [".checkbox.xsm{@apply size-[14px];}.checkbox.sm{@apply size-[16px];}.checkbox.md{@apply size-[18px];}.checkbox.lg{@apply size-[20px];}.checkbox.xsm svg{@apply size-[10.5px];}.checkbox.sm svg{@apply size-[12px];}.checkbox.md svg{@apply size-[13.5px];}.checkbox.lg svg{@apply size-[14px];}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], encapsulation: i0.ViewEncapsulation.None });
2397
+ }
2398
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkCheckbox, decorators: [{
2399
+ type: Component,
2400
+ args: [{ selector: 'bk-checkbox', standalone: true, imports: [CommonModule], encapsulation: ViewEncapsulation.None, providers: [
2401
+ {
2402
+ provide: NG_VALUE_ACCESSOR,
2403
+ useExisting: forwardRef(() => BkCheckbox),
2404
+ multi: true
2405
+ }
2406
+ ], template: "<div\r\n class=\"inline-flex items-center gap-2 cursor-pointer group outline-none\"\r\n (click)=\"toggle()\"\r\n (keydown.enter)=\"toggle()\"\r\n (keydown.space)=\"$event.preventDefault(); toggle()\"\r\n tabindex=\"0\"\r\n [attr.aria-disabled]=\"disabled\">\r\n <div\r\n class=\"relative flex items-center justify-center border-2 transition-all duration-200 ease-in-out rounded group-focus-visible:ring-2 group-focus-visible:ring-blue-600 group-focus-visible:ring-offset-2 checkbox\"\r\n [ngClass]=\"[\r\n checkboxClass,\r\n isChecked && !disabled ? 'bg-black border-black' : '',\r\n !isChecked && !disabled ? 'bg-white border-gray-300 group-hover:border-gray-400' : '',\r\n disabled && isChecked ? 'bg-gray-300 border-gray-300' : '',\r\n disabled && !isChecked ? 'bg-gray-100 border-gray-200' : '',\r\n disabled ? 'cursor-not-allowed' : ''\r\n ]\"\r\n >\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"3.5\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n class=\"text-white pointer-events-none transition-opacity duration-200\"\r\n [class.opacity-0]=\"!isChecked\"\r\n [class.opacity-100]=\"isChecked\"\r\n >\r\n <polyline points=\"20 6 9 17 4 12\"></polyline>\r\n </svg>\r\n </div>\r\n@if(label){\r\n <span\r\n [ngClass]=\"disabled ? 'text-gray-400' : ''\"\r\n class=\"font-medium text-xs text-[#1B223A] select-none {{labelClass}}\"\r\n >\r\n {{ label }}\r\n </span>\r\n}\r\n</div>\r\n", styles: [".checkbox.xsm{@apply size-[14px];}.checkbox.sm{@apply size-[16px];}.checkbox.md{@apply size-[18px];}.checkbox.lg{@apply size-[20px];}.checkbox.xsm svg{@apply size-[10.5px];}.checkbox.sm svg{@apply size-[12px];}.checkbox.md svg{@apply size-[13.5px];}.checkbox.lg svg{@apply size-[14px];}\n"] }]
2407
+ }], propDecorators: { checkboxClass: [{
2408
+ type: Input
2409
+ }], label: [{
2410
+ type: Input
2411
+ }], labelClass: [{
2412
+ type: Input
2413
+ }], disabled: [{
2414
+ type: Input
2415
+ }], change: [{
2416
+ type: Output
2417
+ }] } });
2418
+
2419
+ class BkRadioButton {
2420
+ radioClass = '';
2421
+ label = '';
2422
+ labelClass = '';
2423
+ value;
2424
+ disabled = false;
2425
+ variant = 'dot';
2426
+ change = new EventEmitter();
2427
+ modelValue;
2428
+ onChange = (_) => { };
2429
+ onTouched = () => { };
2430
+ select() {
2431
+ if (this.disabled)
2432
+ return;
2433
+ if (this.modelValue !== this.value) {
2434
+ this.modelValue = this.value;
2435
+ this.onChange(this.value);
2436
+ this.onTouched();
2437
+ this.change.emit(this.value);
2438
+ }
2439
+ }
2440
+ get isChecked() {
2441
+ return this.modelValue === this.value;
2442
+ }
2443
+ writeValue(value) {
2444
+ this.modelValue = value;
2445
+ }
2446
+ registerOnChange(fn) {
2447
+ this.onChange = fn;
2448
+ }
2449
+ registerOnTouched(fn) {
2450
+ this.onTouched = fn;
2451
+ }
2452
+ setDisabledState(isDisabled) {
2453
+ this.disabled = isDisabled;
2454
+ }
2455
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkRadioButton, deps: [], target: i0.ɵɵFactoryTarget.Component });
2456
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkRadioButton, isStandalone: true, selector: "bk-radio-button", inputs: { radioClass: "radioClass", label: "label", labelClass: "labelClass", value: "value", disabled: "disabled", variant: "variant" }, outputs: { change: "change" }, providers: [
2457
+ {
2458
+ provide: NG_VALUE_ACCESSOR,
2459
+ useExisting: forwardRef(() => BkRadioButton),
2460
+ multi: true,
2461
+ },
2462
+ ], ngImport: i0, template: "<div\r\n class=\"inline-flex items-center gap-2 cursor-pointer group outline-none\"\r\n (click)=\"select()\"\r\n (keydown.enter)=\"select()\"\r\n (keydown.space)=\"$event.preventDefault(); select()\"\r\n tabindex=\"0\"\r\n [attr.aria-disabled]=\"disabled\">\r\n\r\n <div\r\n class=\"relative flex items-center justify-center rounded-full border-2 transition-all duration-200 flex-shrink-0 group-focus-visible:ring-2 group-focus-visible:ring-blue-600 group-focus-visible:ring-offset-2 radio\"\r\n [ngClass]=\"[\r\n radioClass,\r\n !isChecked && !disabled ? 'bg-white border-gray-300 group-hover:border-gray-400' : '',\r\n\r\n variant === 'dot' && isChecked && !disabled ? 'border-black bg-white' : '',\r\n\r\n variant === 'tick' && isChecked && !disabled ? 'bg-black border-black' : '',\r\n\r\n disabled && isChecked && variant === 'tick' ? 'bg-gray-300 border-gray-300' : '',\r\n disabled && isChecked && variant === 'dot' ? 'border-gray-300 bg-gray-50' : '',\r\n disabled && !isChecked ? 'bg-gray-100 border-gray-200' : '',\r\n disabled ? 'cursor-not-allowed' : ''\r\n ]\"\r\n >\r\n@if(variant === 'dot'){\r\n <span\r\n class=\"rounded-full bg-black transition-transform duration-200 transform dot\"\r\n [class.scale-0]=\"!isChecked\"\r\n [class.scale-100]=\"isChecked\"\r\n [class.bg-gray-400]=\"disabled\"\r\n ></span>\r\n}\r\n @if (variant === 'tick'){\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"3.5\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n class=\"text-white pointer-events-none transition-opacity duration-200 tick\"\r\n [class.opacity-0]=\"!isChecked\"\r\n [class.opacity-100]=\"isChecked\"\r\n\r\n >\r\n <polyline points=\"20 6 9 17 4 12\"></polyline>\r\n </svg>\r\n }\r\n </div>\r\n\r\n @if(label) {\r\n <span class=\"font-medium text-xs text-[#1B223A] select-none {{labelClass}}\"\r\n [ngClass]=\"disabled ? 'text-gray-400' : ''\">\r\n {{ label }}\r\n </span>\r\n }\r\n</div>\r\n", styles: [".radio.xsm{@apply size-[14px];}.radio.sm{@apply size-[16px];}.radio.md{@apply size-[18px];}.radio.lg{@apply size-[19px];}.radio.xsm .dot{@apply size-[6px];}.radio.sm .dot{@apply size-[8px];}.radio.md .dot{@apply size-[10px];}.radio.lg .dot{@apply size-[11px];}.radio.xsm .tick{@apply size-[9px];}.radio.sm .tick{@apply size-[10px];}.radio.md .tick{@apply size-[12px];}.radio.lg .tick{@apply size-[14px];}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }], encapsulation: i0.ViewEncapsulation.None });
2463
+ }
2464
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkRadioButton, decorators: [{
2465
+ type: Component,
2466
+ args: [{ selector: 'bk-radio-button', standalone: true, imports: [CommonModule, FormsModule], encapsulation: ViewEncapsulation.None, providers: [
2467
+ {
2468
+ provide: NG_VALUE_ACCESSOR,
2469
+ useExisting: forwardRef(() => BkRadioButton),
2470
+ multi: true,
2471
+ },
2472
+ ], template: "<div\r\n class=\"inline-flex items-center gap-2 cursor-pointer group outline-none\"\r\n (click)=\"select()\"\r\n (keydown.enter)=\"select()\"\r\n (keydown.space)=\"$event.preventDefault(); select()\"\r\n tabindex=\"0\"\r\n [attr.aria-disabled]=\"disabled\">\r\n\r\n <div\r\n class=\"relative flex items-center justify-center rounded-full border-2 transition-all duration-200 flex-shrink-0 group-focus-visible:ring-2 group-focus-visible:ring-blue-600 group-focus-visible:ring-offset-2 radio\"\r\n [ngClass]=\"[\r\n radioClass,\r\n !isChecked && !disabled ? 'bg-white border-gray-300 group-hover:border-gray-400' : '',\r\n\r\n variant === 'dot' && isChecked && !disabled ? 'border-black bg-white' : '',\r\n\r\n variant === 'tick' && isChecked && !disabled ? 'bg-black border-black' : '',\r\n\r\n disabled && isChecked && variant === 'tick' ? 'bg-gray-300 border-gray-300' : '',\r\n disabled && isChecked && variant === 'dot' ? 'border-gray-300 bg-gray-50' : '',\r\n disabled && !isChecked ? 'bg-gray-100 border-gray-200' : '',\r\n disabled ? 'cursor-not-allowed' : ''\r\n ]\"\r\n >\r\n@if(variant === 'dot'){\r\n <span\r\n class=\"rounded-full bg-black transition-transform duration-200 transform dot\"\r\n [class.scale-0]=\"!isChecked\"\r\n [class.scale-100]=\"isChecked\"\r\n [class.bg-gray-400]=\"disabled\"\r\n ></span>\r\n}\r\n @if (variant === 'tick'){\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"3.5\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n class=\"text-white pointer-events-none transition-opacity duration-200 tick\"\r\n [class.opacity-0]=\"!isChecked\"\r\n [class.opacity-100]=\"isChecked\"\r\n\r\n >\r\n <polyline points=\"20 6 9 17 4 12\"></polyline>\r\n </svg>\r\n }\r\n </div>\r\n\r\n @if(label) {\r\n <span class=\"font-medium text-xs text-[#1B223A] select-none {{labelClass}}\"\r\n [ngClass]=\"disabled ? 'text-gray-400' : ''\">\r\n {{ label }}\r\n </span>\r\n }\r\n</div>\r\n", styles: [".radio.xsm{@apply size-[14px];}.radio.sm{@apply size-[16px];}.radio.md{@apply size-[18px];}.radio.lg{@apply size-[19px];}.radio.xsm .dot{@apply size-[6px];}.radio.sm .dot{@apply size-[8px];}.radio.md .dot{@apply size-[10px];}.radio.lg .dot{@apply size-[11px];}.radio.xsm .tick{@apply size-[9px];}.radio.sm .tick{@apply size-[10px];}.radio.md .tick{@apply size-[12px];}.radio.lg .tick{@apply size-[14px];}\n"] }]
2473
+ }], propDecorators: { radioClass: [{
2474
+ type: Input
2475
+ }], label: [{
2476
+ type: Input
2477
+ }], labelClass: [{
2478
+ type: Input
2479
+ }], value: [{
2480
+ type: Input
2481
+ }], disabled: [{
2482
+ type: Input
2483
+ }], variant: [{
2484
+ type: Input
2485
+ }], change: [{
2486
+ type: Output
2487
+ }] } });
2488
+
2489
+ class BkPill {
2490
+ label = '';
2491
+ variant = 'Light';
2492
+ color = 'Gray';
2493
+ size = 'md';
2494
+ dot = 'none';
2495
+ removable = false;
2496
+ customClass = '';
2497
+ clicked = new EventEmitter();
2498
+ get containerClasses() {
2499
+ // 1. Size Class
2500
+ const sizeClass = `pill-${this.size}`;
2501
+ // 2. Color/Variant Class (Dynamic Generation)
2502
+ const styleClass = `${this.color}-${this.variant}`;
2503
+ // 3. customClasses
2504
+ const customClass = `${this.customClass}`;
2505
+ return `pill ${sizeClass} ${styleClass} ${customClass}`;
2506
+ }
2507
+ onRemove(e) {
2508
+ e.stopPropagation();
2509
+ this.clicked.emit(this.label);
2510
+ }
2511
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkPill, deps: [], target: i0.ɵɵFactoryTarget.Component });
2512
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkPill, isStandalone: true, selector: "bk-pill", inputs: { label: "label", variant: "variant", color: "color", size: "size", dot: "dot", removable: "removable", customClass: "customClass" }, outputs: { clicked: "clicked" }, ngImport: i0, template: "<span [className]=\"containerClasses\">\r\n\r\n @if (dot === 'left') {\r\n <span class=\"dot\"></span>\r\n }\r\n\r\n <span>{{ label }}</span>\r\n\r\n @if (dot === 'right') {\r\n <span class=\"dot\"></span>\r\n }\r\n\r\n @if (removable) {\r\n <button\r\n (click)=\"onRemove($event)\"\r\n class=\"pill-close \"> <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\r\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\r\n </svg>\r\n</button>\r\n }\r\n</span>\r\n", styles: [".pill{@apply inline-flex items-center justify-center font-medium border transition-colors duration-200 cursor-default gap-1.5 rounded-full;}.pill-xsm{@apply px-2 py-0.5 text-[10px] leading-[14px];}.pill-sm{@apply px-2 py-0.5 text-xs leading-[18px];}.pill-md{@apply px-2 py-0.5 text-sm;}.pill-lg{@apply px-3 py-1 text-sm;}.dot{@apply rounded-full size-1.5 flex-shrink-0 flex-grow-0 bg-current;}.pill-close{@apply flex items-center justify-center rounded-full text-inherit transition-colors;}.pill-xsm .pill-close,.pill-sm .pill-close{@apply w-3 h-3;}.pill-md .pill-close,.pill-lg .pill-close{@apply w-3.5 h-3.5;}.Gray-Solid{@apply bg-[#6B7080] border-[#6B7080] text-white;}.Primary-Solid{@apply bg-[#294FFF] border-[#294FFF] text-white;}.Error-Solid{@apply bg-[#FA727A] border-[#FA727A] text-[#4C0513];}.Warning-Solid{@apply bg-[#FA9E3A] border-[#FA9E3A] text-[#461C04];}.Success-Solid{@apply bg-[#57D175] border-[#57D175] text-[#461C04];}.Success-Solid .dot{@apply bg-[#082B13];}.Purple-Solid{@apply bg-[#CE8EF2] border-[#CE8EF2] text-[#461C04];}.Cyan-Solid{@apply bg-[#3FC2F1] border-[#3FC2F1] text-[#461C04];}.Gray-Light{@apply bg-[#F4F4F6] border-transparent text-[#363C51];}.Primary-Light{@apply bg-[#E5F3FF] border-transparent text-[#1434CB];}.Error-Light{@apply bg-[#FFF1F1] border-transparent text-[#CB1432];}.Warning-Light{@apply bg-[#FFEED7] border-transparent text-[#A04C02];}.Success-Light{@apply bg-[#F1FCF3] border-transparent text-[#1E7735];}.Purple-Light{@apply bg-[#F6EAFD] border-transparent text-[#9130C0];}.Cyan-Light{@apply bg-[#F1FAFE] border-transparent text-[#096E9B];}.Gray-Outline{@apply bg-[#F4F4F6] border-[#BBBDC5] text-[#363C51];}.Primary-Outline{@apply bg-[#E5F3FF] border-[#3F71FF] text-[#1434CB];}.Error-Outline{@apply bg-[#FFF1F1] border-[#FA727A] text-[#CB1432];}.Warning-Outline{@apply bg-[#FFEED7] border-[#FBAE58] text-[#A04C02];}.Success-Outline{@apply bg-[#F1FCF3] border-[#57D175] text-[#1E7735];}.Purple-Outline{@apply bg-[#F6EAFD] border-[#CE8EF2] text-[#9130C0];}.Cyan-Outline{@apply bg-[#F1FAFE] border-[#3FC2F1] text-[#096E9B];}.Gray-Transparent{@apply bg-transparent border-[#BBBDC5] text-[#363C51];}.Primary-Transparent{@apply bg-transparent border-[#3F71FF] text-[#1434CB];}.Error-Transparent{@apply bg-transparent border-[#FA727A] text-[#CB1432];}.Warning-Transparent{@apply bg-transparent border-[#FBAE58] text-[#A04C02];}.Success-Transparent{@apply bg-transparent border-[#57D175] text-[#1E7735];}.Purple-Transparent{@apply bg-transparent border-[#CE8EF2] text-[#9130C0];}.Cyan-Transparent{@apply bg-transparent border-[#3FC2F1] text-[#096E9B];}\n"] });
2513
+ }
2514
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkPill, decorators: [{
2515
+ type: Component,
2516
+ args: [{ selector: 'bk-pill', standalone: true, template: "<span [className]=\"containerClasses\">\r\n\r\n @if (dot === 'left') {\r\n <span class=\"dot\"></span>\r\n }\r\n\r\n <span>{{ label }}</span>\r\n\r\n @if (dot === 'right') {\r\n <span class=\"dot\"></span>\r\n }\r\n\r\n @if (removable) {\r\n <button\r\n (click)=\"onRemove($event)\"\r\n class=\"pill-close \"> <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\r\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\r\n </svg>\r\n</button>\r\n }\r\n</span>\r\n", styles: [".pill{@apply inline-flex items-center justify-center font-medium border transition-colors duration-200 cursor-default gap-1.5 rounded-full;}.pill-xsm{@apply px-2 py-0.5 text-[10px] leading-[14px];}.pill-sm{@apply px-2 py-0.5 text-xs leading-[18px];}.pill-md{@apply px-2 py-0.5 text-sm;}.pill-lg{@apply px-3 py-1 text-sm;}.dot{@apply rounded-full size-1.5 flex-shrink-0 flex-grow-0 bg-current;}.pill-close{@apply flex items-center justify-center rounded-full text-inherit transition-colors;}.pill-xsm .pill-close,.pill-sm .pill-close{@apply w-3 h-3;}.pill-md .pill-close,.pill-lg .pill-close{@apply w-3.5 h-3.5;}.Gray-Solid{@apply bg-[#6B7080] border-[#6B7080] text-white;}.Primary-Solid{@apply bg-[#294FFF] border-[#294FFF] text-white;}.Error-Solid{@apply bg-[#FA727A] border-[#FA727A] text-[#4C0513];}.Warning-Solid{@apply bg-[#FA9E3A] border-[#FA9E3A] text-[#461C04];}.Success-Solid{@apply bg-[#57D175] border-[#57D175] text-[#461C04];}.Success-Solid .dot{@apply bg-[#082B13];}.Purple-Solid{@apply bg-[#CE8EF2] border-[#CE8EF2] text-[#461C04];}.Cyan-Solid{@apply bg-[#3FC2F1] border-[#3FC2F1] text-[#461C04];}.Gray-Light{@apply bg-[#F4F4F6] border-transparent text-[#363C51];}.Primary-Light{@apply bg-[#E5F3FF] border-transparent text-[#1434CB];}.Error-Light{@apply bg-[#FFF1F1] border-transparent text-[#CB1432];}.Warning-Light{@apply bg-[#FFEED7] border-transparent text-[#A04C02];}.Success-Light{@apply bg-[#F1FCF3] border-transparent text-[#1E7735];}.Purple-Light{@apply bg-[#F6EAFD] border-transparent text-[#9130C0];}.Cyan-Light{@apply bg-[#F1FAFE] border-transparent text-[#096E9B];}.Gray-Outline{@apply bg-[#F4F4F6] border-[#BBBDC5] text-[#363C51];}.Primary-Outline{@apply bg-[#E5F3FF] border-[#3F71FF] text-[#1434CB];}.Error-Outline{@apply bg-[#FFF1F1] border-[#FA727A] text-[#CB1432];}.Warning-Outline{@apply bg-[#FFEED7] border-[#FBAE58] text-[#A04C02];}.Success-Outline{@apply bg-[#F1FCF3] border-[#57D175] text-[#1E7735];}.Purple-Outline{@apply bg-[#F6EAFD] border-[#CE8EF2] text-[#9130C0];}.Cyan-Outline{@apply bg-[#F1FAFE] border-[#3FC2F1] text-[#096E9B];}.Gray-Transparent{@apply bg-transparent border-[#BBBDC5] text-[#363C51];}.Primary-Transparent{@apply bg-transparent border-[#3F71FF] text-[#1434CB];}.Error-Transparent{@apply bg-transparent border-[#FA727A] text-[#CB1432];}.Warning-Transparent{@apply bg-transparent border-[#FBAE58] text-[#A04C02];}.Success-Transparent{@apply bg-transparent border-[#57D175] text-[#1E7735];}.Purple-Transparent{@apply bg-transparent border-[#CE8EF2] text-[#9130C0];}.Cyan-Transparent{@apply bg-transparent border-[#3FC2F1] text-[#096E9B];}\n"] }]
2517
+ }], propDecorators: { label: [{
2518
+ type: Input
2519
+ }], variant: [{
2520
+ type: Input
2521
+ }], color: [{
2522
+ type: Input
2523
+ }], size: [{
2524
+ type: Input
2525
+ }], dot: [{
2526
+ type: Input
2527
+ }], removable: [{
2528
+ type: Input
2529
+ }], customClass: [{
2530
+ type: Input
2531
+ }], clicked: [{
2532
+ type: Output
2533
+ }] } });
2534
+
2535
+ class BkBadge {
2536
+ label = '';
2537
+ variant = 'Light';
2538
+ color = 'Gray';
2539
+ size = 'md';
2540
+ dot = 'none';
2541
+ removable = false;
2542
+ customClass = '';
2543
+ clicked = new EventEmitter();
2544
+ get containerClasses() {
2545
+ // 1. Size Class
2546
+ const sizeClass = `badge-${this.size}`;
2547
+ // 2. Color/Variant Class (Dynamic Generation)
2548
+ const styleClass = `${this.color}-${this.variant}`;
2549
+ // 3. customClasses
2550
+ const customClass = `${this.customClass}`;
2551
+ return `badge ${sizeClass} ${styleClass} ${customClass}`;
2552
+ }
2553
+ onRemove(e) {
2554
+ e.stopPropagation();
2555
+ this.clicked.emit(this.label);
2556
+ }
2557
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkBadge, deps: [], target: i0.ɵɵFactoryTarget.Component });
2558
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkBadge, isStandalone: true, selector: "bk-badge", inputs: { label: "label", variant: "variant", color: "color", size: "size", dot: "dot", removable: "removable", customClass: "customClass" }, outputs: { clicked: "clicked" }, ngImport: i0, template: "<span [className]=\"containerClasses\">\r\n\r\n @if (dot === 'left') {\r\n <span class=\"dot\"></span>\r\n }\r\n\r\n <span>{{ label }}</span>\r\n\r\n @if (dot === 'right') {\r\n <span class=\"dot\"></span>\r\n }\r\n\r\n @if (removable) {\r\n <button\r\n (click)=\"onRemove($event)\"\r\n class=\"badge-close\"> <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\r\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\r\n </svg>\r\n</button>\r\n }\r\n</span>\r\n", styles: [".badge{@apply inline-flex items-center justify-center font-medium border transition-colors duration-200 cursor-default gap-1.5 rounded-[4px];}.badge-xsm{@apply px-2 py-0.5 text-[10px] leading-[14px];}.badge-sm{@apply px-2 py-0.5 text-xs leading-[18px];}.badge-md{@apply px-2 py-0.5 text-sm;}.badge-lg{@apply px-3 py-1 text-sm;}.dot{@apply rounded-full size-1.5 flex-shrink-0 flex-grow-0 bg-current;}.badge-close{@apply flex items-center justify-center rounded-full text-inherit transition-colors;}.badge-xsm .badge-close,.badge-sm .badge-close{@apply w-3 h-3;}.badge-md .badge-close,.badge-lg .badge-close{@apply w-3.5 h-3.5;}.Gray-Solid{@apply bg-[#6B7080] border-[#6B7080] text-white;}.Primary-Solid{@apply bg-[#294FFF] border-[#294FFF] text-white;}.Error-Solid{@apply bg-[#FA727A] border-[#FA727A] text-[#4C0513];}.Warning-Solid{@apply bg-[#FA9E3A] border-[#FA9E3A] text-[#461C04];}.Success-Solid{@apply bg-[#57D175] border-[#57D175] text-[#461C04];}.Success-Solid .dot{@apply bg-[#082B13];}.Purple-Solid{@apply bg-[#CE8EF2] border-[#CE8EF2] text-[#461C04];}.Cyan-Solid{@apply bg-[#3FC2F1] border-[#3FC2F1] text-[#461C04];}.Gray-Light{@apply bg-[#F4F4F6] border-transparent text-[#363C51];}.Primary-Light{@apply bg-[#E5F3FF] border-transparent text-[#1434CB];}.Error-Light{@apply bg-[#FFF1F1] border-transparent text-[#CB1432];}.Warning-Light{@apply bg-[#FFEED7] border-transparent text-[#A04C02];}.Success-Light{@apply bg-[#F1FCF3] border-transparent text-[#1E7735];}.Purple-Light{@apply bg-[#F6EAFD] border-transparent text-[#9130C0];}.Cyan-Light{@apply bg-[#F1FAFE] border-transparent text-[#096E9B];}.Gray-Outline{@apply bg-[#F4F4F6] border-[#BBBDC5] text-[#363C51];}.Primary-Outline{@apply bg-[#E5F3FF] border-[#3F71FF] text-[#1434CB];}.Error-Outline{@apply bg-[#FFF1F1] border-[#FA727A] text-[#CB1432];}.Warning-Outline{@apply bg-[#FFEED7] border-[#FBAE58] text-[#A04C02];}.Success-Outline{@apply bg-[#F1FCF3] border-[#57D175] text-[#1E7735];}.Purple-Outline{@apply bg-[#F6EAFD] border-[#CE8EF2] text-[#9130C0];}.Cyan-Outline{@apply bg-[#F1FAFE] border-[#3FC2F1] text-[#096E9B];}.Gray-Transparent{@apply bg-transparent border-[#BBBDC5] text-[#363C51];}.Primary-Transparent{@apply bg-transparent border-[#3F71FF] text-[#1434CB];}.Error-Transparent{@apply bg-transparent border-[#FA727A] text-[#CB1432];}.Warning-Transparent{@apply bg-transparent border-[#FBAE58] text-[#A04C02];}.Success-Transparent{@apply bg-transparent border-[#57D175] text-[#1E7735];}.Purple-Transparent{@apply bg-transparent border-[#CE8EF2] text-[#9130C0];}.Cyan-Transparent{@apply bg-transparent border-[#3FC2F1] text-[#096E9B];}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
2559
+ }
2560
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkBadge, decorators: [{
2561
+ type: Component,
2562
+ args: [{ selector: 'bk-badge', standalone: true, imports: [CommonModule], template: "<span [className]=\"containerClasses\">\r\n\r\n @if (dot === 'left') {\r\n <span class=\"dot\"></span>\r\n }\r\n\r\n <span>{{ label }}</span>\r\n\r\n @if (dot === 'right') {\r\n <span class=\"dot\"></span>\r\n }\r\n\r\n @if (removable) {\r\n <button\r\n (click)=\"onRemove($event)\"\r\n class=\"badge-close\"> <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\r\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\r\n </svg>\r\n</button>\r\n }\r\n</span>\r\n", styles: [".badge{@apply inline-flex items-center justify-center font-medium border transition-colors duration-200 cursor-default gap-1.5 rounded-[4px];}.badge-xsm{@apply px-2 py-0.5 text-[10px] leading-[14px];}.badge-sm{@apply px-2 py-0.5 text-xs leading-[18px];}.badge-md{@apply px-2 py-0.5 text-sm;}.badge-lg{@apply px-3 py-1 text-sm;}.dot{@apply rounded-full size-1.5 flex-shrink-0 flex-grow-0 bg-current;}.badge-close{@apply flex items-center justify-center rounded-full text-inherit transition-colors;}.badge-xsm .badge-close,.badge-sm .badge-close{@apply w-3 h-3;}.badge-md .badge-close,.badge-lg .badge-close{@apply w-3.5 h-3.5;}.Gray-Solid{@apply bg-[#6B7080] border-[#6B7080] text-white;}.Primary-Solid{@apply bg-[#294FFF] border-[#294FFF] text-white;}.Error-Solid{@apply bg-[#FA727A] border-[#FA727A] text-[#4C0513];}.Warning-Solid{@apply bg-[#FA9E3A] border-[#FA9E3A] text-[#461C04];}.Success-Solid{@apply bg-[#57D175] border-[#57D175] text-[#461C04];}.Success-Solid .dot{@apply bg-[#082B13];}.Purple-Solid{@apply bg-[#CE8EF2] border-[#CE8EF2] text-[#461C04];}.Cyan-Solid{@apply bg-[#3FC2F1] border-[#3FC2F1] text-[#461C04];}.Gray-Light{@apply bg-[#F4F4F6] border-transparent text-[#363C51];}.Primary-Light{@apply bg-[#E5F3FF] border-transparent text-[#1434CB];}.Error-Light{@apply bg-[#FFF1F1] border-transparent text-[#CB1432];}.Warning-Light{@apply bg-[#FFEED7] border-transparent text-[#A04C02];}.Success-Light{@apply bg-[#F1FCF3] border-transparent text-[#1E7735];}.Purple-Light{@apply bg-[#F6EAFD] border-transparent text-[#9130C0];}.Cyan-Light{@apply bg-[#F1FAFE] border-transparent text-[#096E9B];}.Gray-Outline{@apply bg-[#F4F4F6] border-[#BBBDC5] text-[#363C51];}.Primary-Outline{@apply bg-[#E5F3FF] border-[#3F71FF] text-[#1434CB];}.Error-Outline{@apply bg-[#FFF1F1] border-[#FA727A] text-[#CB1432];}.Warning-Outline{@apply bg-[#FFEED7] border-[#FBAE58] text-[#A04C02];}.Success-Outline{@apply bg-[#F1FCF3] border-[#57D175] text-[#1E7735];}.Purple-Outline{@apply bg-[#F6EAFD] border-[#CE8EF2] text-[#9130C0];}.Cyan-Outline{@apply bg-[#F1FAFE] border-[#3FC2F1] text-[#096E9B];}.Gray-Transparent{@apply bg-transparent border-[#BBBDC5] text-[#363C51];}.Primary-Transparent{@apply bg-transparent border-[#3F71FF] text-[#1434CB];}.Error-Transparent{@apply bg-transparent border-[#FA727A] text-[#CB1432];}.Warning-Transparent{@apply bg-transparent border-[#FBAE58] text-[#A04C02];}.Success-Transparent{@apply bg-transparent border-[#57D175] text-[#1E7735];}.Purple-Transparent{@apply bg-transparent border-[#CE8EF2] text-[#9130C0];}.Cyan-Transparent{@apply bg-transparent border-[#3FC2F1] text-[#096E9B];}\n"] }]
2563
+ }], propDecorators: { label: [{
2564
+ type: Input
2565
+ }], variant: [{
2566
+ type: Input
2567
+ }], color: [{
2568
+ type: Input
2569
+ }], size: [{
2570
+ type: Input
2571
+ }], dot: [{
2572
+ type: Input
2573
+ }], removable: [{
2574
+ type: Input
2575
+ }], customClass: [{
2576
+ type: Input
2577
+ }], clicked: [{
2578
+ type: Output
2579
+ }] } });
2580
+
2581
+ class BkSpinner {
2582
+ size = 'md';
2583
+ show = true;
2584
+ color = 'text-blue-600'; // default
2585
+ get classes() {
2586
+ return `spinner ${this.size} ${this.color}`;
2587
+ }
2588
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkSpinner, deps: [], target: i0.ɵɵFactoryTarget.Component });
2589
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkSpinner, isStandalone: true, selector: "bk-spinner", inputs: { size: "size", show: "show", color: "color" }, ngImport: i0, template: "@if (show) {\r\n<span [class]=\"classes\" role=\"status\" aria-label=\"loading\">\r\n <span class=\"sr-only\">Loading...</span>\r\n</span>\r\n}\r\n", styles: [".spinner{@apply inline-block rounded-full animate-spin border-current border-t-transparent;border-style:solid}.spinner.xsm{@apply w-[15px] h-[15px] border-[1.5px];}.spinner.sm{@apply w-[25px] h-[25px] border-[2.34px];}.spinner.md{@apply w-[35px] h-[35px] border-[3.28px];}.spinner.lg{@apply w-[50px] h-[50px] border-[4.7px];}.spinner.xl{@apply w-[64px] h-[64px] border-[6px];}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
2590
+ }
2591
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkSpinner, decorators: [{
2592
+ type: Component,
2593
+ args: [{ selector: 'bk-spinner', standalone: true, imports: [CommonModule], template: "@if (show) {\r\n<span [class]=\"classes\" role=\"status\" aria-label=\"loading\">\r\n <span class=\"sr-only\">Loading...</span>\r\n</span>\r\n}\r\n", styles: [".spinner{@apply inline-block rounded-full animate-spin border-current border-t-transparent;border-style:solid}.spinner.xsm{@apply w-[15px] h-[15px] border-[1.5px];}.spinner.sm{@apply w-[25px] h-[25px] border-[2.34px];}.spinner.md{@apply w-[35px] h-[35px] border-[3.28px];}.spinner.lg{@apply w-[50px] h-[50px] border-[4.7px];}.spinner.xl{@apply w-[64px] h-[64px] border-[6px];}\n"] }]
2594
+ }], propDecorators: { size: [{
2595
+ type: Input
2596
+ }], show: [{
2597
+ type: Input
2598
+ }], color: [{
2599
+ type: Input
2600
+ }] } });
2601
+
2602
+ class BkButton {
2603
+ // --- Inputs ---
2604
+ // 1. Style & Size Inputs
2605
+ variant = 'primary';
2606
+ size = 'md';
2607
+ // 2. Content Inputs
2608
+ label = ''; // Pass text directly
2609
+ leftIcon;
2610
+ rightIcon;
2611
+ iconAlt = 'icon';
2612
+ // 3. State & Config
2613
+ type = 'button';
2614
+ loading = false;
2615
+ disabled = false;
2616
+ // 4. Customization (Optional overrides)
2617
+ buttonClass = ''; // Append extra classes if needed
2618
+ textClass = '';
2619
+ spinnerClass = '';
2620
+ // --- Outputs ---
2621
+ clicked = new EventEmitter();
2622
+ // --- Logic ---
2623
+ onClick(event) {
2624
+ if (!this.disabled && !this.loading) {
2625
+ this.clicked.emit(true);
2626
+ }
2627
+ }
2628
+ // Generate the class string based on Inputs
2629
+ get buttonClasses() {
2630
+ const variantClass = this.variant === 'primary' ? 'btn-primary' : 'btn-secondary';
2631
+ // Combine: Variant + Size + Custom Classes
2632
+ // Note: The size name (e.g., 'sm') matches your CSS class name exactly
2633
+ return `btn ${variantClass} ${this.size} ${this.buttonClass}`;
2634
+ }
2635
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkButton, deps: [], target: i0.ɵɵFactoryTarget.Component });
2636
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkButton, isStandalone: true, selector: "bk-button", inputs: { variant: "variant", size: "size", label: "label", leftIcon: "leftIcon", rightIcon: "rightIcon", iconAlt: "iconAlt", type: "type", loading: "loading", disabled: "disabled", buttonClass: "buttonClass", textClass: "textClass", spinnerClass: "spinnerClass" }, outputs: { clicked: "clicked" }, ngImport: i0, template: "<button\r\n [attr.type]=\"type\"\r\n [class]=\"buttonClasses\"\r\n [disabled]=\"disabled || loading\"\r\n (click)=\"onClick($event)\"\r\n>\r\n @if (leftIcon) {\r\n <img [src]=\"leftIcon\" [alt]=\"iconAlt\" class=\"icon shrink-0\" />\r\n }\r\n\r\n @if (label) {\r\n <span [class]=\"textClass\">\r\n {{ label }}\r\n </span>\r\n }\r\n @if (loading) {\r\n <span [class]=\"spinnerClass\" class=\"spinner\"></span>\r\n }\r\n\r\n\r\n @if (rightIcon) {\r\n <img [src]=\"rightIcon\" [alt]=\"iconAlt\" class=\"icon shrink-0\" />\r\n }\r\n\r\n</button>\r\n", styles: [".btn{@apply border rounded transition-colors duration-200 cursor-pointer;}.btn-primary{@apply font-medium flex justify-center gap-2 items-center bg-black text-white focus-visible:outline-2 focus-visible:outline-offset-[2.5px] focus-visible:outline-black active:bg-[#242424] disabled:opacity-90 disabled:cursor-not-allowed disabled:bg-[#242424];}.btn-primary.xxl{@apply gap-3;}.btn-secondary{@apply font-medium flex justify-center gap-2 items-center bg-white text-[#6B7080] focus-visible:outline-2 focus-visible:outline-offset-[3px] focus-visible:outline-[#F5F5FA] active:bg-[#F4F4F6] disabled:opacity-90 disabled:cursor-not-allowed disabled:bg-[#F4F4F6];}.btn.xxsm{@apply px-2 py-1 text-xs leading-[18px];}.btn.xsm{@apply px-3 py-2 text-xs leading-[18px];}.btn.sm{@apply px-[14px] py-2 text-sm;}.btn.md{@apply px-4 py-2.5 text-sm;}.btn.lg{@apply px-[18px] py-2.5 text-base;}.btn.xl{@apply px-5 py-3 text-base;}.btn.xxl{@apply px-7 py-4 text-lg leading-[26px];}.btn.xxsm .icon{@apply size-[11px];}.btn.xsm .icon{@apply size-[15px];}.btn.sm .icon,.btn.md .icon,.btn.lg .icon,.btn.xl .icon{@apply size-4;}.btn.xxl .icon{@apply size-5;}.btn.spinner{@apply shrink-0 border-t-transparent rounded-full animate-spin border-current;}.btn.xxsm .spinner{@apply size-[14px] border-[1.5px];}.btn.xsm .spinner,.btn.sm .spinner,.btn.md .spinner,.btn.lg .spinner,.btn.xl .spinner{@apply size-[15px] border-[1.5px];}.btn.xxl .spinner{@apply size-[24px] border-[2.34px];}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
2637
+ }
2638
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkButton, decorators: [{
2639
+ type: Component,
2640
+ args: [{ selector: 'bk-button', standalone: true, imports: [CommonModule], template: "<button\r\n [attr.type]=\"type\"\r\n [class]=\"buttonClasses\"\r\n [disabled]=\"disabled || loading\"\r\n (click)=\"onClick($event)\"\r\n>\r\n @if (leftIcon) {\r\n <img [src]=\"leftIcon\" [alt]=\"iconAlt\" class=\"icon shrink-0\" />\r\n }\r\n\r\n @if (label) {\r\n <span [class]=\"textClass\">\r\n {{ label }}\r\n </span>\r\n }\r\n @if (loading) {\r\n <span [class]=\"spinnerClass\" class=\"spinner\"></span>\r\n }\r\n\r\n\r\n @if (rightIcon) {\r\n <img [src]=\"rightIcon\" [alt]=\"iconAlt\" class=\"icon shrink-0\" />\r\n }\r\n\r\n</button>\r\n", styles: [".btn{@apply border rounded transition-colors duration-200 cursor-pointer;}.btn-primary{@apply font-medium flex justify-center gap-2 items-center bg-black text-white focus-visible:outline-2 focus-visible:outline-offset-[2.5px] focus-visible:outline-black active:bg-[#242424] disabled:opacity-90 disabled:cursor-not-allowed disabled:bg-[#242424];}.btn-primary.xxl{@apply gap-3;}.btn-secondary{@apply font-medium flex justify-center gap-2 items-center bg-white text-[#6B7080] focus-visible:outline-2 focus-visible:outline-offset-[3px] focus-visible:outline-[#F5F5FA] active:bg-[#F4F4F6] disabled:opacity-90 disabled:cursor-not-allowed disabled:bg-[#F4F4F6];}.btn.xxsm{@apply px-2 py-1 text-xs leading-[18px];}.btn.xsm{@apply px-3 py-2 text-xs leading-[18px];}.btn.sm{@apply px-[14px] py-2 text-sm;}.btn.md{@apply px-4 py-2.5 text-sm;}.btn.lg{@apply px-[18px] py-2.5 text-base;}.btn.xl{@apply px-5 py-3 text-base;}.btn.xxl{@apply px-7 py-4 text-lg leading-[26px];}.btn.xxsm .icon{@apply size-[11px];}.btn.xsm .icon{@apply size-[15px];}.btn.sm .icon,.btn.md .icon,.btn.lg .icon,.btn.xl .icon{@apply size-4;}.btn.xxl .icon{@apply size-5;}.btn.spinner{@apply shrink-0 border-t-transparent rounded-full animate-spin border-current;}.btn.xxsm .spinner{@apply size-[14px] border-[1.5px];}.btn.xsm .spinner,.btn.sm .spinner,.btn.md .spinner,.btn.lg .spinner,.btn.xl .spinner{@apply size-[15px] border-[1.5px];}.btn.xxl .spinner{@apply size-[24px] border-[2.34px];}\n"] }]
2641
+ }], propDecorators: { variant: [{
2642
+ type: Input
2643
+ }], size: [{
2644
+ type: Input
2645
+ }], label: [{
2646
+ type: Input
2647
+ }], leftIcon: [{
2648
+ type: Input
2649
+ }], rightIcon: [{
2650
+ type: Input
2651
+ }], iconAlt: [{
2652
+ type: Input
2653
+ }], type: [{
2654
+ type: Input
2655
+ }], loading: [{
2656
+ type: Input
2657
+ }], disabled: [{
2658
+ type: Input
2659
+ }], buttonClass: [{
2660
+ type: Input
2661
+ }], textClass: [{
2662
+ type: Input
2663
+ }], spinnerClass: [{
2664
+ type: Input
2665
+ }], clicked: [{
2666
+ type: Output
2667
+ }] } });
2668
+
2669
+ class BkIconButton {
2670
+ // --- Inputs ---
2671
+ icon; // Required icon path
2672
+ alt = 'icon';
2673
+ variant = 'primary';
2674
+ size = 'md';
2675
+ disabled = false;
2676
+ // Custom classes
2677
+ buttonClass = '';
2678
+ clicked = new EventEmitter();
2679
+ onClick(event) {
2680
+ if (!this.disabled) {
2681
+ this.clicked.emit(true);
2682
+ }
2683
+ }
2684
+ get buttonClasses() {
2685
+ // Maps inputs to CSS classes: .btn-icon .primary .md
2686
+ return `btn-icon ${this.variant} ${this.size} ${this.buttonClass}`;
2687
+ }
2688
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkIconButton, deps: [], target: i0.ɵɵFactoryTarget.Component });
2689
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: BkIconButton, isStandalone: true, selector: "bk-icon-button", inputs: { icon: "icon", alt: "alt", variant: "variant", size: "size", disabled: "disabled", buttonClass: "buttonClass" }, outputs: { clicked: "clicked" }, ngImport: i0, template: "<button\r\n [class]=\"buttonClasses\"\r\n [disabled]=\"disabled\"\r\n (click)=\"onClick($event)\"\r\n>\r\n <img [src]=\"icon\" [alt]=\"alt\" class=\"icon\" />\r\n</button>\r\n", styles: [".btn-icon{@apply rounded border flex items-center justify-center transition-all duration-200 cursor-pointer shrink-0 shadow;}.btn-icon.primary{@apply bg-black text-white focus-visible:outline-2 focus-visible:outline-offset-[2.5px] focus-visible:outline-black active:bg-[#242424] disabled:opacity-80 disabled:cursor-not-allowed;}.btn-icon.secondary{@apply bg-white border-[#E3E3E7] text-[#6B7080] focus-visible:outline-2 focus-visible:outline-offset-[3px] focus-visible:outline-[#F5F5FA] active:bg-[#F4F4F6] disabled:opacity-50 disabled:cursor-not-allowed disabled:bg-[#F4F4F6];}.btn-icon.xxsm,.btn-icon.xsm{@apply p-1.5;}.btn-icon.sm{@apply p-2;}.btn-icon.md{@apply p-2.5;}.btn-icon.lg{@apply p-3;}.btn-icon.xl{@apply p-[14px];}.btn-icon.xxl{@apply p-4;}.btn-icon.xxsm .icon{@apply size-[14px];}.btn-icon.xsm .icon{@apply size-[18px];}.btn-icon.sm .icon,.btn-icon.md .icon,.btn-icon.lg .icon,.btn-icon.xl .icon{@apply size-[20px];}.btn-icon.xxl .icon{@apply size-[26px];}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
2690
+ }
2691
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkIconButton, decorators: [{
2692
+ type: Component,
2693
+ args: [{ selector: 'bk-icon-button', standalone: true, imports: [CommonModule], template: "<button\r\n [class]=\"buttonClasses\"\r\n [disabled]=\"disabled\"\r\n (click)=\"onClick($event)\"\r\n>\r\n <img [src]=\"icon\" [alt]=\"alt\" class=\"icon\" />\r\n</button>\r\n", styles: [".btn-icon{@apply rounded border flex items-center justify-center transition-all duration-200 cursor-pointer shrink-0 shadow;}.btn-icon.primary{@apply bg-black text-white focus-visible:outline-2 focus-visible:outline-offset-[2.5px] focus-visible:outline-black active:bg-[#242424] disabled:opacity-80 disabled:cursor-not-allowed;}.btn-icon.secondary{@apply bg-white border-[#E3E3E7] text-[#6B7080] focus-visible:outline-2 focus-visible:outline-offset-[3px] focus-visible:outline-[#F5F5FA] active:bg-[#F4F4F6] disabled:opacity-50 disabled:cursor-not-allowed disabled:bg-[#F4F4F6];}.btn-icon.xxsm,.btn-icon.xsm{@apply p-1.5;}.btn-icon.sm{@apply p-2;}.btn-icon.md{@apply p-2.5;}.btn-icon.lg{@apply p-3;}.btn-icon.xl{@apply p-[14px];}.btn-icon.xxl{@apply p-4;}.btn-icon.xxsm .icon{@apply size-[14px];}.btn-icon.xsm .icon{@apply size-[18px];}.btn-icon.sm .icon,.btn-icon.md .icon,.btn-icon.lg .icon,.btn-icon.xl .icon{@apply size-[20px];}.btn-icon.xxl .icon{@apply size-[26px];}\n"] }]
2694
+ }], propDecorators: { icon: [{
2695
+ type: Input
2696
+ }], alt: [{
2697
+ type: Input
2698
+ }], variant: [{
2699
+ type: Input
2700
+ }], size: [{
2701
+ type: Input
2702
+ }], disabled: [{
2703
+ type: Input
2704
+ }], buttonClass: [{
2705
+ type: Input
2706
+ }], clicked: [{
2707
+ type: Output
2708
+ }] } });
2709
+
2710
+ class BkButtonGroup {
2711
+ // --- Inputs ---
2712
+ items = [];
2713
+ mode = 'single';
2714
+ disabled = false;
2715
+ // Holds the current selection.
2716
+ // For 'single', it's a single value. For 'multiple', it's an array.
2717
+ value = null;
2718
+ // --- Outputs ---
2719
+ valueChange = new EventEmitter();
2720
+ // --- Logic ---
2721
+ onItemClick(itemValue) {
2722
+ if (this.disabled)
2723
+ return;
2724
+ if (this.mode === 'single') {
2725
+ // 1. Single Mode: Just set the value
2726
+ if (this.value !== itemValue) {
2727
+ this.value = itemValue;
2728
+ this.valueChange.emit(this.value);
2729
+ }
2730
+ }
2731
+ else {
2732
+ // 2. Multiple Mode: Toggle value in array
2733
+ let currentValues = Array.isArray(this.value) ? [...this.value] : [];
2734
+ if (currentValues.includes(itemValue)) {
2735
+ // Remove if exists
2736
+ currentValues = currentValues.filter(v => v !== itemValue);
2737
+ }
2738
+ else {
2739
+ // Add if not exists
2740
+ currentValues.push(itemValue);
2741
+ }
2742
+ this.value = currentValues;
2743
+ this.valueChange.emit(this.value);
2744
+ }
2745
+ }
2746
+ // Helper to check active state for UI
2747
+ isActive(itemValue) {
2748
+ if (this.mode === 'single') {
2749
+ return this.value === itemValue;
2750
+ }
2751
+ else {
2752
+ return Array.isArray(this.value) && this.value.includes(itemValue);
2753
+ }
2754
+ }
2755
+ // --- Styles ---
2756
+ get containerClass() {
2757
+ return `group-container ${this.disabled ? 'disabled' : ''}`;
2758
+ }
2759
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkButtonGroup, deps: [], target: i0.ɵɵFactoryTarget.Component });
2760
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkButtonGroup, isStandalone: true, selector: "bk-button-group", inputs: { items: "items", mode: "mode", disabled: "disabled", value: "value" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: "<div [class]=\"containerClass\">\r\n @for (item of items; track item.value) {\r\n <div\r\n class=\"group-item\"\r\n [class.active]=\"isActive(item.value)\"\r\n [class.inactive]=\"!isActive(item.value)\"\r\n (click)=\"onItemClick(item.value)\"\r\n >\r\n {{ item.label }}\r\n </div>\r\n }\r\n</div>\r\n", styles: [".group-container{@apply inline-flex items-center border border-[#E1E3EA] bg-white rounded-md p-1 gap-2.5 select-none transition-all;}.group-item{@apply flex items-center justify-center font-medium rounded-md transition-all duration-200 cursor-pointer text-center relative;}.group-item.active{@apply bg-black text-white shadow-sm;}.group-item.inactive{@apply text-[#6B7080] hover:bg-gray-50;}.group-container .group-item{@apply px-4 py-[3px] text-[13px] leading-5;}.group-container.disabled .group-item{@apply opacity-50 cursor-not-allowed;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
2761
+ }
2762
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkButtonGroup, decorators: [{
2763
+ type: Component,
2764
+ args: [{ selector: 'bk-button-group', standalone: true, imports: [CommonModule], template: "<div [class]=\"containerClass\">\r\n @for (item of items; track item.value) {\r\n <div\r\n class=\"group-item\"\r\n [class.active]=\"isActive(item.value)\"\r\n [class.inactive]=\"!isActive(item.value)\"\r\n (click)=\"onItemClick(item.value)\"\r\n >\r\n {{ item.label }}\r\n </div>\r\n }\r\n</div>\r\n", styles: [".group-container{@apply inline-flex items-center border border-[#E1E3EA] bg-white rounded-md p-1 gap-2.5 select-none transition-all;}.group-item{@apply flex items-center justify-center font-medium rounded-md transition-all duration-200 cursor-pointer text-center relative;}.group-item.active{@apply bg-black text-white shadow-sm;}.group-item.inactive{@apply text-[#6B7080] hover:bg-gray-50;}.group-container .group-item{@apply px-4 py-[3px] text-[13px] leading-5;}.group-container.disabled .group-item{@apply opacity-50 cursor-not-allowed;}\n"] }]
2765
+ }], propDecorators: { items: [{
2766
+ type: Input
2767
+ }], mode: [{
2768
+ type: Input
2769
+ }], disabled: [{
2770
+ type: Input
2771
+ }], value: [{
2772
+ type: Input
2773
+ }], valueChange: [{
2774
+ type: Output
2775
+ }] } });
2776
+
2777
+ class BkTextarea {
2778
+ ngControl;
2779
+ autoComplete = 'off';
2780
+ name;
2781
+ id;
2782
+ label = '';
2783
+ placeholder = '';
2784
+ rows = 4;
2785
+ hint = '';
2786
+ required = false;
2787
+ maxlength = null;
2788
+ minlength = null;
2789
+ hasError = false;
2790
+ disabled = false;
2791
+ errorMessage = '';
2792
+ tabIndex = null;
2793
+ readOnly = false;
2794
+ autoCapitalize = null;
2795
+ inputMode = null;
2796
+ input = new EventEmitter();
2797
+ change = new EventEmitter();
2798
+ blur = new EventEmitter();
2799
+ focus = new EventEmitter();
2800
+ value = '';
2801
+ // --- ControlValueAccessor ---
2802
+ onChange = (_) => { };
2803
+ onTouched = () => { };
2804
+ constructor(ngControl) {
2805
+ this.ngControl = ngControl;
2806
+ if (this.ngControl) {
2807
+ this.ngControl.valueAccessor = this;
2808
+ }
2809
+ }
2810
+ // --- Expose FormControl state ---
2811
+ get control() {
2812
+ return this.ngControl?.control;
2813
+ }
2814
+ get touched() {
2815
+ return this.control?.touched;
2816
+ }
2817
+ get dirty() {
2818
+ return this.control?.dirty;
2819
+ }
2820
+ get errors() {
2821
+ return this.control?.errors;
2822
+ }
2823
+ handleFocus(event) {
2824
+ this.focus.emit(event);
2825
+ }
2826
+ handleBlur(event) {
2827
+ this.onTouched();
2828
+ this.blur.emit(event);
2829
+ }
2830
+ handleInput(event) {
2831
+ const val = event.target.value;
2832
+ this.value = val; // update CVA value
2833
+ this.onChange(val); // propagate to parent form
2834
+ this.input.emit(event); // emit raw event
2835
+ }
2836
+ handleChange(event) {
2837
+ this.change.emit(event); // emit raw change event
2838
+ }
2839
+ writeValue(value) {
2840
+ this.value = value ?? '';
2841
+ }
2842
+ registerOnChange(fn) {
2843
+ this.onChange = fn;
2844
+ }
2845
+ registerOnTouched(fn) {
2846
+ this.onTouched = fn;
2847
+ }
2848
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTextarea, deps: [{ token: i1$1.NgControl, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Component });
2849
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkTextarea, isStandalone: true, selector: "bk-textarea", inputs: { autoComplete: "autoComplete", name: "name", id: "id", label: "label", placeholder: "placeholder", rows: "rows", hint: "hint", required: "required", maxlength: "maxlength", minlength: "minlength", hasError: "hasError", disabled: "disabled", errorMessage: "errorMessage", tabIndex: "tabIndex", readOnly: "readOnly", autoCapitalize: "autoCapitalize", inputMode: "inputMode" }, outputs: { input: "input", change: "change", blur: "blur", focus: "focus" }, ngImport: i0, template: "<div class=\"flex flex-col gap-1.5 w-full\">\r\n\r\n @if (label) {\r\n <label\r\n class=\"text-sm font-medium text-[#141414] block\" [for]=\"id\">\r\n {{ label }}\r\n @if (required) {\r\n <span class=\"text-[#E7000B] ml-0.5\">*</span>\r\n }\r\n </label>\r\n }\r\n\r\n <div class=\"relative\">\r\n <textarea\r\n [id]=\"id\"\r\n [name]=\"name\"\r\n [disabled]=\"disabled\"\r\n [tabindex]=\"tabIndex\"\r\n [readOnly]=\"readOnly\"\r\n [attr.maxlength]=\"maxlength\"\r\n [attr.minlength]=\"minlength\"\r\n [autocomplete]=\"autoComplete\"\r\n [autocapitalize]=\"autoCapitalize\"\r\n [inputMode]=\"inputMode\"\r\n [value]=\"value\"\r\n (input)=\"handleInput($event)\"\r\n (change)=\"handleChange($event)\"\r\n (blur)=\"handleBlur($event)\"\r\n (focus)=\"handleFocus($event)\"\r\n [placeholder]=\"placeholder\"\r\n\r\n [autocomplete]=\"autoComplete\"\r\n\r\n rows=\"{{rows}}\"\r\n class=\"\r\n w-full\r\n px-3 py-2.5\r\n text-sm\r\n border border-[#E3E3E7] rounded-[4px]\r\n outline-none\r\n transition-colors duration-200\r\n bg-white resize-y\r\n placeholder:text-[#6B7080]\r\n \"\r\n [ngClass]=\"{\r\n 'border-[#FA727A] text-[#141414]': hasError && !disabled,\r\n\r\n 'focus:border-[#6B7080] text-[#141414]': !hasError && !disabled,\r\n\r\n 'bg-[#F4F4F6] text-[#A1A3AE] border-[#E3E3E7] cursor-not-allowed': disabled\r\n }\"\r\n ></textarea>\r\n </div>\r\n\r\n <div class=\"flex justify-between items-start font-normal text-sm\">\r\n\r\n <div class=\"flex-1\">\r\n @if (hasError) {\r\n <span class=\"text-[#F34050]\">\r\n {{ errorMessage }}\r\n </span>\r\n } @else if (hint) {\r\n <span class=\"text-[#868997]\">\r\n {{ hint }}\r\n </span>\r\n }\r\n </div>\r\n\r\n @if (maxlength) {\r\n <div\r\n class=\"text-[#868997] tabular-nums flex-shrink-0\"\r\n >\r\n {{ value.length }}/{{ maxlength }}\r\n </div>\r\n }\r\n\r\n\r\n </div>\r\n\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }] });
2850
+ }
2851
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTextarea, decorators: [{
2852
+ type: Component,
2853
+ args: [{ selector: 'bk-textarea', standalone: true, imports: [CommonModule, FormsModule], template: "<div class=\"flex flex-col gap-1.5 w-full\">\r\n\r\n @if (label) {\r\n <label\r\n class=\"text-sm font-medium text-[#141414] block\" [for]=\"id\">\r\n {{ label }}\r\n @if (required) {\r\n <span class=\"text-[#E7000B] ml-0.5\">*</span>\r\n }\r\n </label>\r\n }\r\n\r\n <div class=\"relative\">\r\n <textarea\r\n [id]=\"id\"\r\n [name]=\"name\"\r\n [disabled]=\"disabled\"\r\n [tabindex]=\"tabIndex\"\r\n [readOnly]=\"readOnly\"\r\n [attr.maxlength]=\"maxlength\"\r\n [attr.minlength]=\"minlength\"\r\n [autocomplete]=\"autoComplete\"\r\n [autocapitalize]=\"autoCapitalize\"\r\n [inputMode]=\"inputMode\"\r\n [value]=\"value\"\r\n (input)=\"handleInput($event)\"\r\n (change)=\"handleChange($event)\"\r\n (blur)=\"handleBlur($event)\"\r\n (focus)=\"handleFocus($event)\"\r\n [placeholder]=\"placeholder\"\r\n\r\n [autocomplete]=\"autoComplete\"\r\n\r\n rows=\"{{rows}}\"\r\n class=\"\r\n w-full\r\n px-3 py-2.5\r\n text-sm\r\n border border-[#E3E3E7] rounded-[4px]\r\n outline-none\r\n transition-colors duration-200\r\n bg-white resize-y\r\n placeholder:text-[#6B7080]\r\n \"\r\n [ngClass]=\"{\r\n 'border-[#FA727A] text-[#141414]': hasError && !disabled,\r\n\r\n 'focus:border-[#6B7080] text-[#141414]': !hasError && !disabled,\r\n\r\n 'bg-[#F4F4F6] text-[#A1A3AE] border-[#E3E3E7] cursor-not-allowed': disabled\r\n }\"\r\n ></textarea>\r\n </div>\r\n\r\n <div class=\"flex justify-between items-start font-normal text-sm\">\r\n\r\n <div class=\"flex-1\">\r\n @if (hasError) {\r\n <span class=\"text-[#F34050]\">\r\n {{ errorMessage }}\r\n </span>\r\n } @else if (hint) {\r\n <span class=\"text-[#868997]\">\r\n {{ hint }}\r\n </span>\r\n }\r\n </div>\r\n\r\n @if (maxlength) {\r\n <div\r\n class=\"text-[#868997] tabular-nums flex-shrink-0\"\r\n >\r\n {{ value.length }}/{{ maxlength }}\r\n </div>\r\n }\r\n\r\n\r\n </div>\r\n\r\n</div>\r\n" }]
2854
+ }], ctorParameters: () => [{ type: i1$1.NgControl, decorators: [{
2855
+ type: Optional
2856
+ }, {
2857
+ type: Self
2858
+ }] }], propDecorators: { autoComplete: [{
2859
+ type: Input
2860
+ }], name: [{
2861
+ type: Input
2862
+ }], id: [{
2863
+ type: Input
2864
+ }], label: [{
2865
+ type: Input
2866
+ }], placeholder: [{
2867
+ type: Input
2868
+ }], rows: [{
2869
+ type: Input
2870
+ }], hint: [{
2871
+ type: Input
2872
+ }], required: [{
2873
+ type: Input
2874
+ }], maxlength: [{
2875
+ type: Input
2876
+ }], minlength: [{
2877
+ type: Input
2878
+ }], hasError: [{
2879
+ type: Input
2880
+ }], disabled: [{
2881
+ type: Input
2882
+ }], errorMessage: [{
2883
+ type: Input
2884
+ }], tabIndex: [{
2885
+ type: Input
2886
+ }], readOnly: [{
2887
+ type: Input
2888
+ }], autoCapitalize: [{
2889
+ type: Input
2890
+ }], inputMode: [{
2891
+ type: Input
2892
+ }], input: [{
2893
+ type: Output
2894
+ }], change: [{
2895
+ type: Output
2896
+ }], blur: [{
2897
+ type: Output
2898
+ }], focus: [{
2899
+ type: Output
2900
+ }] } });
2901
+
2902
+ class BkGrid {
2903
+ draggable = false;
2904
+ columns = [];
2905
+ result;
2906
+ actions = [];
2907
+ actionClick = new EventEmitter();
2908
+ sortChange = new EventEmitter();
2909
+ dragDropChange = new EventEmitter();
2910
+ sortColumn;
2911
+ sortDirection = 'asc';
2912
+ tableScrollContainer;
2913
+ get firstVisibleColumnIndex() {
2914
+ const index = this.columns.findIndex(col => col.visible !== false);
2915
+ return index >= 0 ? index : 0;
2916
+ }
2917
+ /* ---------- Sorting ---------- */
2918
+ sort(column, index) {
2919
+ if (!column.sortable || !column.field)
2920
+ return;
2921
+ // Toggle sort direction
2922
+ this.sortDirection =
2923
+ this.sortColumn === column.field ? (this.sortDirection === 'asc' ? 'desc' : 'asc') : 'asc';
2924
+ this.sortColumn = column.field;
2925
+ // Emit sort change separately
2926
+ this.sortChange.emit({
2927
+ columnIndex: index,
2928
+ column,
2929
+ direction: this.sortDirection,
2930
+ });
2931
+ }
2932
+ /* ---------- Visibility ---------- */
2933
+ isColumnVisible(column) {
2934
+ return column.visible !== false;
2935
+ }
2936
+ /* ---------- Cell Value ---------- */
2937
+ getCellValue(row, column) {
2938
+ if (column.formatter) {
2939
+ return column.formatter(row);
2940
+ }
2941
+ if (column.field) {
2942
+ return String(row[column.field] ?? '');
2943
+ }
2944
+ return '';
2945
+ }
2946
+ /* ---------- Actions ---------- */
2947
+ emitAction(action, row) {
2948
+ this.actionClick.emit({
2949
+ action: action.name,
2950
+ row,
2951
+ });
2952
+ }
2953
+ dropList(event) {
2954
+ if (!this.draggable || !this.result)
2955
+ return;
2956
+ moveItemInArray(this.result, event.previousIndex, event.currentIndex);
2957
+ // Update existing sortOrder on T
2958
+ this.result.forEach((item, index) => {
2959
+ item.sortOrder = index + 1;
2960
+ });
2961
+ // Emit reordered list
2962
+ this.dragDropChange.emit(this.result);
2963
+ }
2964
+ onDragMoved(event) {
2965
+ if (!this.tableScrollContainer)
2966
+ return;
2967
+ const container = this.tableScrollContainer.nativeElement;
2968
+ const rect = container.getBoundingClientRect();
2969
+ const pointerY = event.pointerPosition.y - rect.top;
2970
+ const threshold = 80;
2971
+ const maxSpeed = 25;
2972
+ if (pointerY < threshold) {
2973
+ const intensity = 1 - pointerY / threshold;
2974
+ container.scrollTop -= Math.min(maxSpeed, intensity * maxSpeed);
2975
+ }
2976
+ else if (pointerY > rect.height - threshold) {
2977
+ const intensity = 1 - (rect.height - pointerY) / threshold;
2978
+ container.scrollTop += Math.min(maxSpeed, intensity * maxSpeed);
2979
+ }
2980
+ }
2981
+ onDragStart(event) {
2982
+ const row = event.source.element.nativeElement;
2983
+ const cells = Array.from(row.querySelectorAll('td'));
2984
+ setTimeout(() => {
2985
+ const preview = document.querySelector('.cdk-drag-preview');
2986
+ if (!preview)
2987
+ return;
2988
+ const previewCells = preview.querySelectorAll('td');
2989
+ cells.forEach((cell, index) => {
2990
+ const width = cell.getBoundingClientRect().width + 'px';
2991
+ const previewCell = previewCells[index];
2992
+ if (previewCell) {
2993
+ previewCell.style.width = width;
2994
+ previewCell.style.minWidth = width;
2995
+ previewCell.style.maxWidth = width;
2996
+ }
2997
+ });
2998
+ });
2999
+ }
3000
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkGrid, deps: [], target: i0.ɵɵFactoryTarget.Component });
3001
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkGrid, isStandalone: true, selector: "bk-grid", inputs: { draggable: "draggable", columns: "columns", result: "result", actions: "actions" }, outputs: { actionClick: "actionClick", sortChange: "sortChange", dragDropChange: "dragDropChange" }, viewQueries: [{ propertyName: "tableScrollContainer", first: true, predicate: ["tableScrollContainer"], descendants: true }], ngImport: i0, template: "<div\r\n #tableScrollContainer\r\n cdkScrollable\r\n class=\"h-[calc(100vh-260px)] overflow-y-auto\">\r\n\r\n <table class=\"min-w-full text-sm text-left text-gray-800 table-auto border-collapse\">\r\n\r\n <!-- ================= HEADER ================= -->\r\n <thead>\r\n <tr>\r\n @for (col of columns; track col.header;let i=$index;) {\r\n @if (isColumnVisible(col)) {\r\n <th\r\n class=\"grid-header sticky top-0 cursor-pointer\"\r\n [class.action-sticky]=\"col.sticky\"\r\n [class.z-10]=\"col.sticky\"\r\n [ngClass]=\"col.headerClass\"\r\n [ngClass]=\"col.cellClass\"\r\n (click)=\"sort(col,i)\"\r\n >\r\n <span class=\"flex items-center gap-1\"\r\n [ngClass]=\"sortColumn === col.field\r\n ? (sortDirection === 'asc' ? 'grid-asc' : 'grid-desc')\r\n : ''\">\r\n {{ col.header }}\r\n @if (col.sortable) {\r\n <span class=\"grid-sort-icon\"></span>\r\n }\r\n </span>\r\n </th>\r\n }\r\n }\r\n\r\n @if (actions.length) {\r\n <th class=\"grid-header sticky top-0 action-sticky z-10 !bg-[#FBFBFC] w-20\">\r\n Action\r\n </th>\r\n }\r\n </tr>\r\n </thead>\r\n\r\n <!-- ================= BODY ================= -->\r\n <tbody\r\n cdkDropList\r\n [cdkDropListDisabled]=\"!draggable\"\r\n [cdkDropListData]=\"result || []\"\r\n (cdkDropListDropped)=\"dropList($event)\">\r\n\r\n @for (row of result; track row; let rowIndex = $index) {\r\n <tr\r\n cdkDrag\r\n cdkDragLockAxis=\"y\"\r\n [cdkDragDisabled]=\"!draggable\"\r\n (cdkDragStarted)=\"onDragStart($event)\"\r\n (cdkDragMoved)=\"onDragMoved($event)\"\r\n class=\"\" [ngClass]=\"{ 'cursor-move ': draggable }\">\r\n\r\n @for (col of columns; track col.header; let colIndex = $index) {\r\n @if (isColumnVisible(col)) {\r\n <td class=\"grid-cell text-nowrap\" [ngClass]=\"col.cellClass\">\r\n @if (draggable && colIndex === firstVisibleColumnIndex) {\r\n <span cdkDragHandle class=\"mr-2 text-gray-400\" [ngClass]=\"{ 'cursor-move': draggable }\">\u2630</span>\r\n }\r\n {{ getCellValue(row, col) }}\r\n </td>\r\n }\r\n }\r\n\r\n @if (actions.length) {\r\n <td class=\"grid-cell action-sticky text-center\">\r\n <div class=\"flex items-center justify-center gap-1.5\">\r\n @for (action of actions; track action.name) {\r\n @if (action.hasPermission) {\r\n <!-- appTooltip=\"{{ action.tooltip }}\"\r\n appTooltipPosition=\"top\" -->\r\n <button\r\n class=\"size-6 flex items-center justify-center rounded hover:bg-[#F8F8FA]\"\r\n (click)=\"emitAction(action, row)\"\r\n\r\n >\r\n <img\r\n [src]=\"action.icon\"\r\n width=\"14\"\r\n height=\"14\"\r\n alt=\"action-icon\"\r\n />\r\n </button>\r\n }\r\n }\r\n </div>\r\n </td>\r\n }\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n</div>\r\n", styles: [".grid-header{@apply bg-[#FBFBFC] text-xs text-[#60646C] leading-5 font-semibold capitalize px-4 py-2 whitespace-nowrap;}.grid-cell{@apply text-[#15191E] text-[13px] font-medium leading-4 px-4 py-2 border border-[#EBEDF3] border-b-0;}.grid-cell:last-child{@apply border-e-0;}.grid-cell:first-child,.grid-first-cell{@apply border-s-0;}.grid-last-cell{@apply border-e-0;}.grid-action-sticky{@apply sticky bg-white right-[.1px] z-[1px];}.grid-action-sticky:before{@apply absolute top-0 bottom-0 left-[-8px] w-2;content:\"\";background-image:linear-gradient(to left,rgba(0,0,0,.05),transparent)}.grid-required{@apply font-medium text-sm leading-normal after:content-[\"*\"] after:text-[#C10007] after:ms-0.5;}.grid-sort{display:inline-flex;align-items:center;gap:.35rem;cursor:pointer;line-height:1}.grid-sort-icon{display:inline-flex;flex-direction:column;justify-content:center;align-items:center;height:.875rem;width:.875rem;gap:.125rem;line-height:1}.grid-sort-icon:before{display:inline-block;content:\"\";height:.3rem;width:.54rem;background-repeat:no-repeat;background-position:center;background-size:cover;background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M1.08333 4.83333C0.908333 4.83333 0.791667 4.775 0.675 4.65833C0.441667 4.425 0.441667 4.075 0.675 3.84167L3.59167 0.925C3.825 0.691667 4.175 0.691667 4.40833 0.925L7.325 3.84167C7.55833 4.075 7.55833 4.425 7.325 4.65833C7.09167 4.89167 6.74167 4.89167 6.50833 4.65833L4 2.15L1.49167 4.65833C1.375 4.775 1.25833 4.83333 1.08333 4.83333Z' fill='%2378829D'/%3e%3c/svg%3e\")}.grid-sort-icon:after{display:inline-block;content:\"\";height:.3rem;width:.54rem;background-repeat:no-repeat;background-position:center;background-size:cover;background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M4 4.24984C3.825 4.24984 3.70833 4.1915 3.59167 4.07484L0.675 1.15817C0.441667 0.924838 0.441667 0.574837 0.675 0.341504C0.908333 0.108171 1.25833 0.108171 1.49167 0.341504L4 2.84984L6.50833 0.341504C6.74167 0.108171 7.09167 0.108171 7.325 0.341504C7.55833 0.574837 7.55833 0.924838 7.325 1.15817L4.40833 4.07484C4.29167 4.1915 4.175 4.24984 4 4.24984Z' fill='%2378829D'/%3e%3c/svg%3e\")}.grid-asc>.grid-sort-icon:before{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M1.08333 4.83333C0.908333 4.83333 0.791667 4.775 0.675 4.65833C0.441667 4.425 0.441667 4.075 0.675 3.84167L3.59167 0.925C3.825 0.691667 4.175 0.691667 4.40833 0.925L7.325 3.84167C7.55833 4.075 7.55833 4.425 7.325 4.65833C7.09167 4.89167 6.74167 4.89167 6.50833 4.65833L4 2.15L1.49167 4.65833C1.375 4.775 1.25833 4.83333 1.08333 4.83333Z' fill='%234B5675'/%3e%3c/svg%3e\")}.grid-asc>.grid-sort-icon:after{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M4 4.24984C3.825 4.24984 3.70833 4.1915 3.59167 4.07484L0.675 1.15817C0.441667 0.924838 0.441667 0.574837 0.675 0.341504C0.908333 0.108171 1.25833 0.108171 1.49167 0.341504L4 2.84984L6.50833 0.341504C6.74167 0.108171 7.09167 0.108171 7.325 0.341504C7.55833 0.574837 7.55833 0.924838 7.325 1.15817L4.40833 4.07484C4.29167 4.1915 4.175 4.24984 4 4.24984Z' fill='%23C4CADA'/%3e%3c/svg%3e\")}.grid-desc>.grid-sort-icon:before{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M1.08333 4.83333C0.908333 4.83333 0.791667 4.775 0.675 4.65833C0.441667 4.425 0.441667 4.075 0.675 3.84167L3.59167 0.925C3.825 0.691667 4.175 0.691667 4.40833 0.925L7.325 3.84167C7.55833 4.075 7.55833 4.425 7.325 4.65833C7.09167 4.89167 6.74167 4.89167 6.50833 4.65833L4 2.15L1.49167 4.65833C1.375 4.775 1.25833 4.83333 1.08333 4.83333Z' fill='%23C4CADA'/%3e%3c/svg%3e\")}.grid-desc>.grid-sort-icon:after{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M4 4.24984C3.825 4.24984 3.70833 4.1915 3.59167 4.07484L0.675 1.15817C0.441667 0.924838 0.441667 0.574837 0.675 0.341504C0.908333 0.108171 1.25833 0.108171 1.49167 0.341504L4 2.84984L6.50833 0.341504C6.74167 0.108171 7.09167 0.108171 7.325 0.341504C7.55833 0.574837 7.55833 0.924838 7.325 1.15817L4.40833 4.07484C4.29167 4.1915 4.175 4.24984 4 4.24984Z' fill='%234B5675'/%3e%3c/svg%3e\")}.cdk-drag-preview{display:table;width:100%;background:#fff;box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f}.cdk-drag-placeholder{opacity:.4;background-color:#f3f4f6}.cdk-drag-animating,.cdk-drop-list-dragging .cdk-drag{transition:transform .25s cubic-bezier(0,0,.2,1)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i2.ɵɵCdkScrollable, selector: "[cdk-scrollable], [cdkScrollable]" }, { kind: "directive", type: i2.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: "directive", type: i2.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: i2.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "ngmodule", type: ScrollingModule }] });
3002
+ }
3003
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkGrid, decorators: [{
3004
+ type: Component,
3005
+ args: [{ selector: 'bk-grid', standalone: true, imports: [CommonModule, DragDropModule, ScrollingModule], template: "<div\r\n #tableScrollContainer\r\n cdkScrollable\r\n class=\"h-[calc(100vh-260px)] overflow-y-auto\">\r\n\r\n <table class=\"min-w-full text-sm text-left text-gray-800 table-auto border-collapse\">\r\n\r\n <!-- ================= HEADER ================= -->\r\n <thead>\r\n <tr>\r\n @for (col of columns; track col.header;let i=$index;) {\r\n @if (isColumnVisible(col)) {\r\n <th\r\n class=\"grid-header sticky top-0 cursor-pointer\"\r\n [class.action-sticky]=\"col.sticky\"\r\n [class.z-10]=\"col.sticky\"\r\n [ngClass]=\"col.headerClass\"\r\n [ngClass]=\"col.cellClass\"\r\n (click)=\"sort(col,i)\"\r\n >\r\n <span class=\"flex items-center gap-1\"\r\n [ngClass]=\"sortColumn === col.field\r\n ? (sortDirection === 'asc' ? 'grid-asc' : 'grid-desc')\r\n : ''\">\r\n {{ col.header }}\r\n @if (col.sortable) {\r\n <span class=\"grid-sort-icon\"></span>\r\n }\r\n </span>\r\n </th>\r\n }\r\n }\r\n\r\n @if (actions.length) {\r\n <th class=\"grid-header sticky top-0 action-sticky z-10 !bg-[#FBFBFC] w-20\">\r\n Action\r\n </th>\r\n }\r\n </tr>\r\n </thead>\r\n\r\n <!-- ================= BODY ================= -->\r\n <tbody\r\n cdkDropList\r\n [cdkDropListDisabled]=\"!draggable\"\r\n [cdkDropListData]=\"result || []\"\r\n (cdkDropListDropped)=\"dropList($event)\">\r\n\r\n @for (row of result; track row; let rowIndex = $index) {\r\n <tr\r\n cdkDrag\r\n cdkDragLockAxis=\"y\"\r\n [cdkDragDisabled]=\"!draggable\"\r\n (cdkDragStarted)=\"onDragStart($event)\"\r\n (cdkDragMoved)=\"onDragMoved($event)\"\r\n class=\"\" [ngClass]=\"{ 'cursor-move ': draggable }\">\r\n\r\n @for (col of columns; track col.header; let colIndex = $index) {\r\n @if (isColumnVisible(col)) {\r\n <td class=\"grid-cell text-nowrap\" [ngClass]=\"col.cellClass\">\r\n @if (draggable && colIndex === firstVisibleColumnIndex) {\r\n <span cdkDragHandle class=\"mr-2 text-gray-400\" [ngClass]=\"{ 'cursor-move': draggable }\">\u2630</span>\r\n }\r\n {{ getCellValue(row, col) }}\r\n </td>\r\n }\r\n }\r\n\r\n @if (actions.length) {\r\n <td class=\"grid-cell action-sticky text-center\">\r\n <div class=\"flex items-center justify-center gap-1.5\">\r\n @for (action of actions; track action.name) {\r\n @if (action.hasPermission) {\r\n <!-- appTooltip=\"{{ action.tooltip }}\"\r\n appTooltipPosition=\"top\" -->\r\n <button\r\n class=\"size-6 flex items-center justify-center rounded hover:bg-[#F8F8FA]\"\r\n (click)=\"emitAction(action, row)\"\r\n\r\n >\r\n <img\r\n [src]=\"action.icon\"\r\n width=\"14\"\r\n height=\"14\"\r\n alt=\"action-icon\"\r\n />\r\n </button>\r\n }\r\n }\r\n </div>\r\n </td>\r\n }\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n</div>\r\n", styles: [".grid-header{@apply bg-[#FBFBFC] text-xs text-[#60646C] leading-5 font-semibold capitalize px-4 py-2 whitespace-nowrap;}.grid-cell{@apply text-[#15191E] text-[13px] font-medium leading-4 px-4 py-2 border border-[#EBEDF3] border-b-0;}.grid-cell:last-child{@apply border-e-0;}.grid-cell:first-child,.grid-first-cell{@apply border-s-0;}.grid-last-cell{@apply border-e-0;}.grid-action-sticky{@apply sticky bg-white right-[.1px] z-[1px];}.grid-action-sticky:before{@apply absolute top-0 bottom-0 left-[-8px] w-2;content:\"\";background-image:linear-gradient(to left,rgba(0,0,0,.05),transparent)}.grid-required{@apply font-medium text-sm leading-normal after:content-[\"*\"] after:text-[#C10007] after:ms-0.5;}.grid-sort{display:inline-flex;align-items:center;gap:.35rem;cursor:pointer;line-height:1}.grid-sort-icon{display:inline-flex;flex-direction:column;justify-content:center;align-items:center;height:.875rem;width:.875rem;gap:.125rem;line-height:1}.grid-sort-icon:before{display:inline-block;content:\"\";height:.3rem;width:.54rem;background-repeat:no-repeat;background-position:center;background-size:cover;background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M1.08333 4.83333C0.908333 4.83333 0.791667 4.775 0.675 4.65833C0.441667 4.425 0.441667 4.075 0.675 3.84167L3.59167 0.925C3.825 0.691667 4.175 0.691667 4.40833 0.925L7.325 3.84167C7.55833 4.075 7.55833 4.425 7.325 4.65833C7.09167 4.89167 6.74167 4.89167 6.50833 4.65833L4 2.15L1.49167 4.65833C1.375 4.775 1.25833 4.83333 1.08333 4.83333Z' fill='%2378829D'/%3e%3c/svg%3e\")}.grid-sort-icon:after{display:inline-block;content:\"\";height:.3rem;width:.54rem;background-repeat:no-repeat;background-position:center;background-size:cover;background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M4 4.24984C3.825 4.24984 3.70833 4.1915 3.59167 4.07484L0.675 1.15817C0.441667 0.924838 0.441667 0.574837 0.675 0.341504C0.908333 0.108171 1.25833 0.108171 1.49167 0.341504L4 2.84984L6.50833 0.341504C6.74167 0.108171 7.09167 0.108171 7.325 0.341504C7.55833 0.574837 7.55833 0.924838 7.325 1.15817L4.40833 4.07484C4.29167 4.1915 4.175 4.24984 4 4.24984Z' fill='%2378829D'/%3e%3c/svg%3e\")}.grid-asc>.grid-sort-icon:before{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M1.08333 4.83333C0.908333 4.83333 0.791667 4.775 0.675 4.65833C0.441667 4.425 0.441667 4.075 0.675 3.84167L3.59167 0.925C3.825 0.691667 4.175 0.691667 4.40833 0.925L7.325 3.84167C7.55833 4.075 7.55833 4.425 7.325 4.65833C7.09167 4.89167 6.74167 4.89167 6.50833 4.65833L4 2.15L1.49167 4.65833C1.375 4.775 1.25833 4.83333 1.08333 4.83333Z' fill='%234B5675'/%3e%3c/svg%3e\")}.grid-asc>.grid-sort-icon:after{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M4 4.24984C3.825 4.24984 3.70833 4.1915 3.59167 4.07484L0.675 1.15817C0.441667 0.924838 0.441667 0.574837 0.675 0.341504C0.908333 0.108171 1.25833 0.108171 1.49167 0.341504L4 2.84984L6.50833 0.341504C6.74167 0.108171 7.09167 0.108171 7.325 0.341504C7.55833 0.574837 7.55833 0.924838 7.325 1.15817L4.40833 4.07484C4.29167 4.1915 4.175 4.24984 4 4.24984Z' fill='%23C4CADA'/%3e%3c/svg%3e\")}.grid-desc>.grid-sort-icon:before{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M1.08333 4.83333C0.908333 4.83333 0.791667 4.775 0.675 4.65833C0.441667 4.425 0.441667 4.075 0.675 3.84167L3.59167 0.925C3.825 0.691667 4.175 0.691667 4.40833 0.925L7.325 3.84167C7.55833 4.075 7.55833 4.425 7.325 4.65833C7.09167 4.89167 6.74167 4.89167 6.50833 4.65833L4 2.15L1.49167 4.65833C1.375 4.775 1.25833 4.83333 1.08333 4.83333Z' fill='%23C4CADA'/%3e%3c/svg%3e\")}.grid-desc>.grid-sort-icon:after{background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5' fill='none'%3e%3cpath d='M4 4.24984C3.825 4.24984 3.70833 4.1915 3.59167 4.07484L0.675 1.15817C0.441667 0.924838 0.441667 0.574837 0.675 0.341504C0.908333 0.108171 1.25833 0.108171 1.49167 0.341504L4 2.84984L6.50833 0.341504C6.74167 0.108171 7.09167 0.108171 7.325 0.341504C7.55833 0.574837 7.55833 0.924838 7.325 1.15817L4.40833 4.07484C4.29167 4.1915 4.175 4.24984 4 4.24984Z' fill='%234B5675'/%3e%3c/svg%3e\")}.cdk-drag-preview{display:table;width:100%;background:#fff;box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f}.cdk-drag-placeholder{opacity:.4;background-color:#f3f4f6}.cdk-drag-animating,.cdk-drop-list-dragging .cdk-drag{transition:transform .25s cubic-bezier(0,0,.2,1)}\n"] }]
3006
+ }], propDecorators: { draggable: [{
3007
+ type: Input
3008
+ }], columns: [{
3009
+ type: Input
3010
+ }], result: [{
3011
+ type: Input
3012
+ }], actions: [{
3013
+ type: Input
3014
+ }], actionClick: [{
3015
+ type: Output
3016
+ }], sortChange: [{
3017
+ type: Output
3018
+ }], dragDropChange: [{
3019
+ type: Output
3020
+ }], tableScrollContainer: [{
3021
+ type: ViewChild,
3022
+ args: ['tableScrollContainer', { static: false }]
3023
+ }] } });
3024
+
3025
+ class BkSelect {
3026
+ // --- Inputs ---
3027
+ items = input([], ...(ngDevMode ? [{ debugName: "items" }] : []));
3028
+ bindLabel = input('label', ...(ngDevMode ? [{ debugName: "bindLabel" }] : []));
3029
+ bindValue = input('', ...(ngDevMode ? [{ debugName: "bindValue" }] : []));
3030
+ placeholder = input('', ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
3031
+ notFoundText = input('No items found', ...(ngDevMode ? [{ debugName: "notFoundText" }] : []));
3032
+ loadingText = input('Loading...', ...(ngDevMode ? [{ debugName: "loadingText" }] : []));
3033
+ clearAllText = input('Clear all', ...(ngDevMode ? [{ debugName: "clearAllText" }] : []));
3034
+ // iconSrc = input<string>('Clear all');
3035
+ iconAlt = 'icon';
3036
+ label = 'Label';
3037
+ required = false;
3038
+ iconSrc; // optional icon
3039
+ // Config
3040
+ multiple = input(false, ...(ngDevMode ? [{ debugName: "multiple" }] : []));
3041
+ maxLabels = input(2, ...(ngDevMode ? [{ debugName: "maxLabels" }] : []));
3042
+ searchable = input(true, ...(ngDevMode ? [{ debugName: "searchable" }] : []));
3043
+ clearable = input(true, ...(ngDevMode ? [{ debugName: "clearable" }] : []));
3044
+ readonly = input(false, ...(ngDevMode ? [{ debugName: "readonly" }] : []));
3045
+ disabled = model(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
3046
+ loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
3047
+ closeOnSelect = input(true, ...(ngDevMode ? [{ debugName: "closeOnSelect" }] : []));
3048
+ dropdownPosition = input('bottom', ...(ngDevMode ? [{ debugName: "dropdownPosition" }] : []));
3049
+ // 1. NEW INPUT: Toggle append-to-body behavior
3050
+ appendToBody = input(false, ...(ngDevMode ? [{ debugName: "appendToBody" }] : []));
3051
+ // --- Outputs ---
3052
+ open = output();
3053
+ close = output();
3054
+ focus = output();
3055
+ blur = output();
3056
+ search = output();
3057
+ clear = output();
3058
+ change = output();
3059
+ scrollToEnd = output();
3060
+ // --- Refs ---
3061
+ searchInput;
3062
+ optionsListContainer;
3063
+ optionsRef;
3064
+ controlWrapper;
3065
+ // --- State ---
3066
+ _value = null;
3067
+ isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
3068
+ selectedOptions = signal([], ...(ngDevMode ? [{ debugName: "selectedOptions" }] : []));
3069
+ searchTerm = signal('', ...(ngDevMode ? [{ debugName: "searchTerm" }] : []));
3070
+ markedIndex = signal(-1, ...(ngDevMode ? [{ debugName: "markedIndex" }] : []));
3071
+ dropdownStyle = signal({
3072
+ left: '0px',
3073
+ width: 'auto'
3074
+ }, ...(ngDevMode ? [{ debugName: "dropdownStyle" }] : []));
3075
+ filteredItems = computed(() => {
3076
+ const term = this.searchTerm().toLowerCase();
3077
+ const list = this.items();
3078
+ if (!term || !this.searchable())
3079
+ return list;
3080
+ return list.filter(item => {
3081
+ const label = this.resolveLabel(item).toLowerCase();
3082
+ return label.includes(term);
3083
+ });
3084
+ }, ...(ngDevMode ? [{ debugName: "filteredItems" }] : []));
3085
+ isAllSelected = computed(() => {
3086
+ const filtered = this.filteredItems();
3087
+ const current = this.selectedOptions();
3088
+ if (!filtered.length)
3089
+ return false;
3090
+ return filtered.every(item => this.isItemSelected(item));
3091
+ }, ...(ngDevMode ? [{ debugName: "isAllSelected" }] : []));
3092
+ constructor() {
3093
+ effect(() => {
3094
+ const currentItems = this.items();
3095
+ if (currentItems.length > 0 && this._value !== null) {
3096
+ this.resolveSelectedOptions(this._value);
3097
+ }
3098
+ });
3099
+ }
3100
+ // --- Helpers ---
3101
+ resolveLabel(item) {
3102
+ if (!item)
3103
+ return '';
3104
+ const labelProp = this.bindLabel();
3105
+ return labelProp && typeof item === 'object' ? item[labelProp] : String(item);
3106
+ }
3107
+ resolveValue(item) {
3108
+ const valueProp = this.bindValue();
3109
+ return valueProp && typeof item === 'object' ? item[valueProp] : item;
3110
+ }
3111
+ isItemSelected(item) {
3112
+ const current = this.selectedOptions();
3113
+ const compareFn = this.compareWith();
3114
+ const itemVal = this.resolveValue(item);
3115
+ return current.some(selected => compareFn(itemVal, this.resolveValue(selected)));
3116
+ }
3117
+ compareWith = input((a, b) => a === b, ...(ngDevMode ? [{ debugName: "compareWith" }] : []));
3118
+ // --- Actions ---
3119
+ toggleDropdown(event) {
3120
+ if (event) {
3121
+ event.preventDefault();
3122
+ event.stopPropagation();
3123
+ }
3124
+ if (this.disabled() || this.readonly())
3125
+ return;
3126
+ this.isOpen() ? this.closeDropdown() : this.openDropdown();
3127
+ }
3128
+ openDropdown() {
3129
+ if (this.isOpen())
3130
+ return;
3131
+ // Only calculate position if we are appending to body
3132
+ if (this.appendToBody()) {
3133
+ this.updatePosition();
3134
+ }
3135
+ this.isOpen.set(true);
3136
+ // this.markedIndex.set(0);
3137
+ this.open.emit();
3138
+ this.focus.emit();
3139
+ setTimeout(() => this.searchInput?.nativeElement.focus());
3140
+ }
3141
+ closeDropdown() {
3142
+ if (!this.isOpen())
3143
+ return;
3144
+ this.isOpen.set(false);
3145
+ this.searchTerm.set('');
3146
+ this.onTouched();
3147
+ this.close.emit();
3148
+ this.blur.emit();
3149
+ }
3150
+ getTop() {
3151
+ if (this.appendToBody()) {
3152
+ return this.dropdownStyle().top ?? null;
3153
+ }
3154
+ // NOT appendToBody
3155
+ return this.dropdownPosition() === 'bottom' ? '105%' : null;
3156
+ }
3157
+ getBottom() {
3158
+ if (this.appendToBody()) {
3159
+ return this.dropdownStyle().bottom ?? null;
3160
+ }
3161
+ // NOT appendToBody
3162
+ return this.dropdownPosition() === 'top' ? '105%' : null;
3163
+ }
3164
+ updatePosition() {
3165
+ const rect = this.controlWrapper.nativeElement.getBoundingClientRect();
3166
+ if (this.dropdownPosition() === 'bottom') {
3167
+ this.dropdownStyle.set({
3168
+ top: `${rect.bottom + 4}px`,
3169
+ bottom: undefined,
3170
+ left: `${rect.left}px`,
3171
+ width: `${rect.width}px`
3172
+ });
3173
+ }
3174
+ else {
3175
+ this.dropdownStyle.set({
3176
+ top: undefined,
3177
+ bottom: `${window.innerHeight - rect.top + 4}px`,
3178
+ left: `${rect.left}px`,
3179
+ width: `${rect.width}px`
3180
+ });
3181
+ }
3182
+ }
3183
+ // 2. FIXED: Removed ['$event'] argument
3184
+ onWindowEvents() {
3185
+ // Only close on scroll if we are in "fixed" mode (append to body)
3186
+ if (this.isOpen() && this.appendToBody()) {
3187
+ this.closeDropdown();
3188
+ }
3189
+ }
3190
+ // ... (toggleSelectAll, handleSelection, removeOption, handleClear logic same as before) ...
3191
+ toggleSelectAll(event) {
3192
+ event.stopPropagation();
3193
+ event.preventDefault();
3194
+ const allSelected = this.isAllSelected();
3195
+ const filtered = this.filteredItems();
3196
+ let newSelection = [...this.selectedOptions()];
3197
+ const compareFn = this.compareWith();
3198
+ if (allSelected) {
3199
+ newSelection = newSelection.filter(sel => {
3200
+ const selVal = this.resolveValue(sel);
3201
+ return !filtered.some(fItem => compareFn(this.resolveValue(fItem), selVal));
3202
+ });
3203
+ }
3204
+ else {
3205
+ filtered.forEach(item => {
3206
+ if (!this.isItemSelected(item))
3207
+ newSelection.push(item);
3208
+ });
3209
+ }
3210
+ this.updateModel(newSelection);
3211
+ }
3212
+ handleSelection(item, event) {
3213
+ if (event)
3214
+ event.stopPropagation();
3215
+ if (this.multiple()) {
3216
+ const isSelected = this.isItemSelected(item);
3217
+ let newSelection = [...this.selectedOptions()];
3218
+ const compareFn = this.compareWith();
3219
+ if (isSelected) {
3220
+ const itemVal = this.resolveValue(item);
3221
+ newSelection = newSelection.filter(sel => !compareFn(this.resolveValue(sel), itemVal));
3222
+ }
3223
+ else {
3224
+ newSelection.push(item);
3225
+ }
3226
+ this.updateModel(newSelection);
3227
+ if (this.closeOnSelect())
3228
+ this.closeDropdown();
3229
+ }
3230
+ else {
3231
+ this.updateModel([item]);
3232
+ if (this.closeOnSelect())
3233
+ this.closeDropdown();
3234
+ }
3235
+ }
3236
+ removeOption(item, event) {
3237
+ event.stopPropagation();
3238
+ const newSelection = this.selectedOptions().filter(i => i !== item);
3239
+ this.updateModel(newSelection);
3240
+ }
3241
+ handleClear(event) {
3242
+ event.stopPropagation();
3243
+ this.updateModel([]);
3244
+ this.clear.emit();
3245
+ }
3246
+ updateModel(items) {
3247
+ this.selectedOptions.set(items);
3248
+ if (this.multiple()) {
3249
+ const values = items.map(i => this.resolveValue(i));
3250
+ this._value = values;
3251
+ this.onChange(values);
3252
+ this.change.emit(values);
3253
+ }
3254
+ else {
3255
+ const item = items[0] || null;
3256
+ const value = item ? this.resolveValue(item) : null;
3257
+ this._value = value;
3258
+ this.onChange(value);
3259
+ this.change.emit(value);
3260
+ }
3261
+ }
3262
+ onSearchInput(event) {
3263
+ const val = event.target.value;
3264
+ this.searchTerm.set(val);
3265
+ this.markedIndex.set(0);
3266
+ this.search.emit({ term: val, items: this.filteredItems() });
3267
+ }
3268
+ onKeyDown(event) {
3269
+ if (!this.isOpen())
3270
+ return;
3271
+ const list = this.filteredItems();
3272
+ const current = this.markedIndex();
3273
+ switch (event.key) {
3274
+ case 'ArrowDown':
3275
+ event.preventDefault();
3276
+ if (current < list.length - 1) {
3277
+ this.markedIndex.set(current + 1);
3278
+ this.scrollToMarked();
3279
+ }
3280
+ break;
3281
+ case 'ArrowUp':
3282
+ event.preventDefault();
3283
+ if (current > 0) {
3284
+ this.markedIndex.set(current - 1);
3285
+ this.scrollToMarked();
3286
+ }
3287
+ break;
3288
+ case 'Enter':
3289
+ event.preventDefault();
3290
+ if (current >= 0 && list[current])
3291
+ this.handleSelection(list[current]);
3292
+ break;
3293
+ case 'Escape':
3294
+ event.preventDefault();
3295
+ this.closeDropdown();
3296
+ break;
3297
+ }
3298
+ }
3299
+ onScroll(event) {
3300
+ const target = event.target;
3301
+ if (target.scrollHeight - target.scrollTop <= target.clientHeight + 10) {
3302
+ this.scrollToEnd.emit();
3303
+ }
3304
+ }
3305
+ scrollToMarked() {
3306
+ setTimeout(() => {
3307
+ const container = this.optionsListContainer?.nativeElement;
3308
+ const options = this.optionsRef?.toArray();
3309
+ const index = this.markedIndex();
3310
+ if (container && options && options[index]) {
3311
+ const el = options[index].nativeElement;
3312
+ if (el.offsetTop < container.scrollTop) {
3313
+ container.scrollTop = el.offsetTop;
3314
+ }
3315
+ else if ((el.offsetTop + el.clientHeight) > (container.scrollTop + container.clientHeight)) {
3316
+ container.scrollTop = (el.offsetTop + el.clientHeight) - container.clientHeight;
3317
+ }
3318
+ }
3319
+ });
3320
+ }
3321
+ onChange = () => { };
3322
+ onTouched = () => { };
3323
+ writeValue(value) { this._value = value; this.resolveSelectedOptions(value); }
3324
+ registerOnChange(fn) { this.onChange = fn; }
3325
+ registerOnTouched(fn) { this.onTouched = fn; }
3326
+ setDisabledState(d) { this.disabled.set(d); }
3327
+ resolveSelectedOptions(val) {
3328
+ const list = this.items();
3329
+ if (!list.length)
3330
+ return;
3331
+ if (val === null || val === undefined) {
3332
+ this.selectedOptions.set([]);
3333
+ return;
3334
+ }
3335
+ const valArray = Array.isArray(val) ? val : [val];
3336
+ const bindVal = this.bindValue();
3337
+ const compare = this.compareWith();
3338
+ const matchedItems = list.filter(item => {
3339
+ const itemVal = bindVal ? item[bindVal] : item;
3340
+ return valArray.some(v => compare(v, itemVal));
3341
+ });
3342
+ this.selectedOptions.set(matchedItems);
3343
+ }
3344
+ el = inject(ElementRef);
3345
+ onClickOutside(e) {
3346
+ if (!this.el.nativeElement.contains(e.target))
3347
+ this.closeDropdown();
3348
+ }
3349
+ openFromLabel(event) {
3350
+ event.preventDefault();
3351
+ event.stopPropagation();
3352
+ if (this.disabled() || this.readonly())
3353
+ return;
3354
+ this.controlWrapper.nativeElement.focus();
3355
+ this.openDropdown();
3356
+ }
3357
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkSelect, deps: [], target: i0.ɵɵFactoryTarget.Component });
3358
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkSelect, isStandalone: true, selector: "bk-select", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, bindLabel: { classPropertyName: "bindLabel", publicName: "bindLabel", isSignal: true, isRequired: false, transformFunction: null }, bindValue: { classPropertyName: "bindValue", publicName: "bindValue", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, notFoundText: { classPropertyName: "notFoundText", publicName: "notFoundText", isSignal: true, isRequired: false, transformFunction: null }, loadingText: { classPropertyName: "loadingText", publicName: "loadingText", isSignal: true, isRequired: false, transformFunction: null }, clearAllText: { classPropertyName: "clearAllText", publicName: "clearAllText", isSignal: true, isRequired: false, transformFunction: null }, iconAlt: { classPropertyName: "iconAlt", publicName: "iconAlt", isSignal: false, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: false, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: false, isRequired: false, transformFunction: null }, iconSrc: { classPropertyName: "iconSrc", publicName: "iconSrc", isSignal: false, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, maxLabels: { classPropertyName: "maxLabels", publicName: "maxLabels", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, closeOnSelect: { classPropertyName: "closeOnSelect", publicName: "closeOnSelect", isSignal: true, isRequired: false, transformFunction: null }, dropdownPosition: { classPropertyName: "dropdownPosition", publicName: "dropdownPosition", isSignal: true, isRequired: false, transformFunction: null }, appendToBody: { classPropertyName: "appendToBody", publicName: "appendToBody", isSignal: true, isRequired: false, transformFunction: null }, compareWith: { classPropertyName: "compareWith", publicName: "compareWith", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { disabled: "disabledChange", open: "open", close: "close", focus: "focus", blur: "blur", search: "search", clear: "clear", change: "change", scrollToEnd: "scrollToEnd" }, host: { listeners: { "window:scroll": "onWindowEvents()", "window:resize": "onWindowEvents()", "document:click": "onClickOutside($event)" } }, providers: [
3359
+ {
3360
+ provide: NG_VALUE_ACCESSOR,
3361
+ useExisting: forwardRef(() => BkSelect),
3362
+ multi: true
3363
+ }
3364
+ ], viewQueries: [{ propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true }, { propertyName: "optionsListContainer", first: true, predicate: ["optionsListContainer"], descendants: true }, { propertyName: "controlWrapper", first: true, predicate: ["controlWrapper"], descendants: true }, { propertyName: "optionsRef", predicate: ["optionsRef"], descendants: true }], ngImport: i0, template: "<div class=\"ng-select-container\">\r\n\r\n <label\r\n class=\"input-label\"\r\n (click)=\"openFromLabel($event)\">\r\n {{ label }}\r\n @if(required){\r\n <span class=\"input-label-required\">*</span>\r\n }\r\n </label>\r\n\r\n <div\r\n #controlWrapper\r\n class=\"ng-select-control\"\r\n [class.focused]=\"isOpen()\"\r\n [class.disabled]=\"disabled()\"\r\n (mousedown)=\"toggleDropdown($event)\"\r\n >\r\n <!-- Icon (Always visible if set) -->\r\n @if(iconSrc){\r\n <img [src]=\"iconSrc\" [alt]=\"iconAlt\" class=\"shrink-0\" />\r\n }\r\n <div class=\"ng-value-container\">\r\n @if (selectedOptions().length === 0)\r\n {\r\n <div class=\"ng-placeholder\">{{ placeholder() }}</div>\r\n }\r\n @if\r\n (multiple() && selectedOptions().length > 0) {\r\n <div class=\"ng-value-chips\">\r\n @for (opt of selectedOptions().slice(0, maxLabels()); track $index) {\r\n <div class=\"ng-value-chip\">\r\n <span class=\"ng-value-label\">{{ resolveLabel(opt) }}</span>\r\n <span class=\"ng-value-icon\" (mousedown)=\"removeOption(opt, $event)\">\u00D7</span>\r\n </div>\r\n }\r\n @if (selectedOptions().length > maxLabels()) {\r\n <div class=\"ng-value-chip remaining-count\"><span class=\"ng-value-label\">+{{ selectedOptions().length - maxLabels() }} more</span></div>\r\n }\r\n </div>\r\n }\r\n @if (!multiple() && selectedOptions().length > 0) {\r\n <div class=\"ng-value-label-single\">{{ resolveLabel(selectedOptions()[0]) }}</div>\r\n }\r\n </div>\r\n <div class=\"ng-actions\">\r\n @if (clearable() && selectedOptions().length > 0 && !disabled()) {\r\n <span class=\"ng-clear-wrapper\" (mousedown)=\"handleClear($event)\" title=\"Clear\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line></svg>\r\n </span>\r\n }\r\n <span class=\"ng-arrow-wrapper\" [class.open]=\"isOpen()\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"m6 9 6 6 6-6\"/></svg>\r\n </span>\r\n </div>\r\n </div>\r\n\r\n @if (isOpen()) {\r\n <div\r\n #dropdownPanel\r\n class=\"custom-ng-dropdown-panel\"\r\n [attr.data-position]=\"dropdownPosition()\"\r\n (scroll)=\"onScroll($event)\"\r\n\r\n [style.position]=\"appendToBody() ? 'fixed' : 'absolute'\"\r\n [style.top]=\"getTop()\"\r\n [style.bottom]=\"getBottom()\"\r\n [style.left]=\"appendToBody() ? dropdownStyle().left : null\"\r\n [style.width]=\"appendToBody() ? dropdownStyle().width : '100%'\"\r\n >\r\n\r\n\r\n @if (searchable()) {\r\n <div class=\"ng-dropdown-search\">\r\n <div class=\"ng-search-wrapper\">\r\n <svg class=\"text-[#BBBDC5] mr-2\" xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"11\" cy=\"11\" r=\"8\"></circle><line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"></line></svg>\r\n <input #searchInput type=\"text\" class=\"ng-search-input\" [value]=\"searchTerm()\" [placeholder]=\"'Search...'\" (input)=\"onSearchInput($event)\" (keydown)=\"onKeyDown($event)\" (click)=\"$event.stopPropagation()\">\r\n </div>\r\n </div>\r\n }\r\n @if (multiple() && filteredItems().length > 0) {\r\n <div class=\"ng-option select-all-option\" (mousedown)=\"toggleSelectAll($event)\">\r\n <div class=\"mr-2 flex items-center justify-center w-4 h-4 border border-gray-300 rounded bg-white\" [class.bg-blue-600]=\"isAllSelected()\" [class.border-blue-600]=\"isAllSelected()\">\r\n @if(isAllSelected()){ <svg class=\"text-white w-3 h-3\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"4\"><polyline points=\"20 6 9 17 4 12\"/></svg> }\r\n </div>\r\n <span class=\"font-semibold\">Select All</span>\r\n </div>\r\n }\r\n <div #optionsListContainer class=\"ng-options-list\">\r\n @if (loading()) { <div class=\"ng-option-disabled\">{{ loadingText() }}</div> }\r\n @else {\r\n @for (item of filteredItems(); track $index) {\r\n <div #optionsRef class=\"ng-option\" [class.selected]=\"isItemSelected(item)\" [class.marked]=\"$index === markedIndex()\" (click)=\"handleSelection(item, $event)\" (click)=\"markedIndex.set($index)\">\r\n @if (multiple()) {\r\n <div class=\"mr-2 flex items-center justify-center w-4 h-4 border border-gray-300 rounded bg-white\" [class.bg-blue-600]=\"isItemSelected(item)\" [class.border-blue-600]=\"isItemSelected(item)\">\r\n @if(isItemSelected(item)){ <svg class=\"text-white w-3 h-3\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"4\"><polyline points=\"20 6 9 17 4 12\"/></svg> }\r\n </div>\r\n }\r\n <span class=\"flex-1\">{{ resolveLabel(item) }}</span>\r\n @if (!multiple() && isItemSelected(item)) {\r\n <svg class=\"text-[#141414]\" width=\"17\" height=\"17\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><polyline points=\"20 6 9 17 4 12\"/></svg>\r\n }\r\n </div>\r\n }\r\n @if (filteredItems().length === 0) { <div class=\"ng-option-disabled\">{{ notFoundText() }}</div> }\r\n }\r\n </div>\r\n\r\n </div>\r\n }\r\n</div>\r\n", styles: [".ng-select-container{@apply relative w-full box-border;}.ng-select-control{@apply flex items-center justify-between gap-2 w-full bg-white border border-[#E3E3E7] rounded transition-all duration-200 px-3 py-[9.2px] cursor-pointer;}.ng-select-control.focused{@apply border-[#6B7080] shadow-none z-10;}.ng-select-control.disabled{@apply bg-[#F4F4F6] cursor-not-allowed opacity-60;}.ng-value-container{@apply flex flex-1 items-center flex-wrap gap-1 relative overflow-hidden h-full;}.ng-placeholder{@apply text-[#6B7080] font-normal text-sm truncate w-full pointer-events-none;}.ng-value-label-single{@apply font-normal text-sm text-[#141414] truncate w-full;}.ng-value-chips{@apply flex flex-wrap gap-1 w-full;}.ng-value-chip{@apply flex items-center bg-gray-100 border border-gray-200 rounded px-2 py-0.5 max-w-full;}.ng-value-chip .ng-value-label{@apply text-[#15191E] truncate max-w-[150px];}.ng-value-chip .ng-value-icon{@apply ml-1 text-gray-500 hover:text-red-500 cursor-pointer text-base font-bold leading-none px-1;}.ng-actions{@apply flex items-center gap-0.5 flex-shrink-0;}.ng-clear-wrapper{@apply text-gray-400 hover:text-red-500 cursor-pointer;}.ng-arrow-wrapper{@apply text-gray-400 transition-transform duration-200;}.ng-arrow-wrapper.open{@apply rotate-180;}.custom-ng-dropdown-panel{@apply absolute left-0 w-full bg-white border border-[#E3E3E7] rounded-xl shadow-lg z-[99] overflow-hidden cursor-default;}.ng-dropdown-search{@apply px-2 pt-2;}.ng-search-wrapper{@apply flex items-center border border-[#E3E3E7] rounded-md px-3 py-[7px] bg-white transition-colors focus-within:border-[#E3E3E7];}.ng-search-input{@apply w-full outline-none font-normal text-sm text-[#141414] placeholder-[#A1A3AE] bg-transparent;}.ng-options-list{@apply max-h-60 overflow-auto relative p-2.5 mb-3.5 flex flex-col gap-0.5;}.ng-option{@apply flex items-center p-2.5 cursor-pointer transition-colors font-normal text-sm text-[#141414];}.ng-option:hover,.ng-option.marked,.ng-option.selected{@apply bg-[#F8F8F8] rounded-md;}.ng-option-disabled{@apply px-3 py-2 text-gray-400 cursor-default;}.ng-value-chip.remaining-count{@apply bg-gray-200 text-gray-600 font-semibold cursor-default;}.select-all-option{@apply sticky top-0 z-20 flex items-center px-3 py-2 cursor-pointer border-b border-[#E3E6EE] bg-gray-50 text-[#15191E];}.select-all-option:hover{@apply bg-gray-100;}.custom-ng-dropdown-panel[data-position=top]{margin-top:0;margin-bottom:4px}.input-label{@apply text-sm font-medium text-[#141414] tracking-[-.28px] mb-1.5 inline-block;}.input-label-required{@apply text-[#E7000B];}::-webkit-scrollbar{width:10px}::-webkit-scrollbar-track{background:transparent;border-radius:8px;width:8px}::-webkit-scrollbar-thumb{background:#d6d7dc;border-radius:8px;transition:.3s ease-in-out}::-webkit-scrollbar-thumb:hover{background:#909090}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }] });
3365
+ }
3366
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkSelect, decorators: [{
3367
+ type: Component,
3368
+ args: [{ selector: 'bk-select', standalone: true, imports: [CommonModule, FormsModule], providers: [
3369
+ {
3370
+ provide: NG_VALUE_ACCESSOR,
3371
+ useExisting: forwardRef(() => BkSelect),
3372
+ multi: true
3373
+ }
3374
+ ], template: "<div class=\"ng-select-container\">\r\n\r\n <label\r\n class=\"input-label\"\r\n (click)=\"openFromLabel($event)\">\r\n {{ label }}\r\n @if(required){\r\n <span class=\"input-label-required\">*</span>\r\n }\r\n </label>\r\n\r\n <div\r\n #controlWrapper\r\n class=\"ng-select-control\"\r\n [class.focused]=\"isOpen()\"\r\n [class.disabled]=\"disabled()\"\r\n (mousedown)=\"toggleDropdown($event)\"\r\n >\r\n <!-- Icon (Always visible if set) -->\r\n @if(iconSrc){\r\n <img [src]=\"iconSrc\" [alt]=\"iconAlt\" class=\"shrink-0\" />\r\n }\r\n <div class=\"ng-value-container\">\r\n @if (selectedOptions().length === 0)\r\n {\r\n <div class=\"ng-placeholder\">{{ placeholder() }}</div>\r\n }\r\n @if\r\n (multiple() && selectedOptions().length > 0) {\r\n <div class=\"ng-value-chips\">\r\n @for (opt of selectedOptions().slice(0, maxLabels()); track $index) {\r\n <div class=\"ng-value-chip\">\r\n <span class=\"ng-value-label\">{{ resolveLabel(opt) }}</span>\r\n <span class=\"ng-value-icon\" (mousedown)=\"removeOption(opt, $event)\">\u00D7</span>\r\n </div>\r\n }\r\n @if (selectedOptions().length > maxLabels()) {\r\n <div class=\"ng-value-chip remaining-count\"><span class=\"ng-value-label\">+{{ selectedOptions().length - maxLabels() }} more</span></div>\r\n }\r\n </div>\r\n }\r\n @if (!multiple() && selectedOptions().length > 0) {\r\n <div class=\"ng-value-label-single\">{{ resolveLabel(selectedOptions()[0]) }}</div>\r\n }\r\n </div>\r\n <div class=\"ng-actions\">\r\n @if (clearable() && selectedOptions().length > 0 && !disabled()) {\r\n <span class=\"ng-clear-wrapper\" (mousedown)=\"handleClear($event)\" title=\"Clear\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line></svg>\r\n </span>\r\n }\r\n <span class=\"ng-arrow-wrapper\" [class.open]=\"isOpen()\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"m6 9 6 6 6-6\"/></svg>\r\n </span>\r\n </div>\r\n </div>\r\n\r\n @if (isOpen()) {\r\n <div\r\n #dropdownPanel\r\n class=\"custom-ng-dropdown-panel\"\r\n [attr.data-position]=\"dropdownPosition()\"\r\n (scroll)=\"onScroll($event)\"\r\n\r\n [style.position]=\"appendToBody() ? 'fixed' : 'absolute'\"\r\n [style.top]=\"getTop()\"\r\n [style.bottom]=\"getBottom()\"\r\n [style.left]=\"appendToBody() ? dropdownStyle().left : null\"\r\n [style.width]=\"appendToBody() ? dropdownStyle().width : '100%'\"\r\n >\r\n\r\n\r\n @if (searchable()) {\r\n <div class=\"ng-dropdown-search\">\r\n <div class=\"ng-search-wrapper\">\r\n <svg class=\"text-[#BBBDC5] mr-2\" xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"11\" cy=\"11\" r=\"8\"></circle><line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"></line></svg>\r\n <input #searchInput type=\"text\" class=\"ng-search-input\" [value]=\"searchTerm()\" [placeholder]=\"'Search...'\" (input)=\"onSearchInput($event)\" (keydown)=\"onKeyDown($event)\" (click)=\"$event.stopPropagation()\">\r\n </div>\r\n </div>\r\n }\r\n @if (multiple() && filteredItems().length > 0) {\r\n <div class=\"ng-option select-all-option\" (mousedown)=\"toggleSelectAll($event)\">\r\n <div class=\"mr-2 flex items-center justify-center w-4 h-4 border border-gray-300 rounded bg-white\" [class.bg-blue-600]=\"isAllSelected()\" [class.border-blue-600]=\"isAllSelected()\">\r\n @if(isAllSelected()){ <svg class=\"text-white w-3 h-3\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"4\"><polyline points=\"20 6 9 17 4 12\"/></svg> }\r\n </div>\r\n <span class=\"font-semibold\">Select All</span>\r\n </div>\r\n }\r\n <div #optionsListContainer class=\"ng-options-list\">\r\n @if (loading()) { <div class=\"ng-option-disabled\">{{ loadingText() }}</div> }\r\n @else {\r\n @for (item of filteredItems(); track $index) {\r\n <div #optionsRef class=\"ng-option\" [class.selected]=\"isItemSelected(item)\" [class.marked]=\"$index === markedIndex()\" (click)=\"handleSelection(item, $event)\" (click)=\"markedIndex.set($index)\">\r\n @if (multiple()) {\r\n <div class=\"mr-2 flex items-center justify-center w-4 h-4 border border-gray-300 rounded bg-white\" [class.bg-blue-600]=\"isItemSelected(item)\" [class.border-blue-600]=\"isItemSelected(item)\">\r\n @if(isItemSelected(item)){ <svg class=\"text-white w-3 h-3\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"4\"><polyline points=\"20 6 9 17 4 12\"/></svg> }\r\n </div>\r\n }\r\n <span class=\"flex-1\">{{ resolveLabel(item) }}</span>\r\n @if (!multiple() && isItemSelected(item)) {\r\n <svg class=\"text-[#141414]\" width=\"17\" height=\"17\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><polyline points=\"20 6 9 17 4 12\"/></svg>\r\n }\r\n </div>\r\n }\r\n @if (filteredItems().length === 0) { <div class=\"ng-option-disabled\">{{ notFoundText() }}</div> }\r\n }\r\n </div>\r\n\r\n </div>\r\n }\r\n</div>\r\n", styles: [".ng-select-container{@apply relative w-full box-border;}.ng-select-control{@apply flex items-center justify-between gap-2 w-full bg-white border border-[#E3E3E7] rounded transition-all duration-200 px-3 py-[9.2px] cursor-pointer;}.ng-select-control.focused{@apply border-[#6B7080] shadow-none z-10;}.ng-select-control.disabled{@apply bg-[#F4F4F6] cursor-not-allowed opacity-60;}.ng-value-container{@apply flex flex-1 items-center flex-wrap gap-1 relative overflow-hidden h-full;}.ng-placeholder{@apply text-[#6B7080] font-normal text-sm truncate w-full pointer-events-none;}.ng-value-label-single{@apply font-normal text-sm text-[#141414] truncate w-full;}.ng-value-chips{@apply flex flex-wrap gap-1 w-full;}.ng-value-chip{@apply flex items-center bg-gray-100 border border-gray-200 rounded px-2 py-0.5 max-w-full;}.ng-value-chip .ng-value-label{@apply text-[#15191E] truncate max-w-[150px];}.ng-value-chip .ng-value-icon{@apply ml-1 text-gray-500 hover:text-red-500 cursor-pointer text-base font-bold leading-none px-1;}.ng-actions{@apply flex items-center gap-0.5 flex-shrink-0;}.ng-clear-wrapper{@apply text-gray-400 hover:text-red-500 cursor-pointer;}.ng-arrow-wrapper{@apply text-gray-400 transition-transform duration-200;}.ng-arrow-wrapper.open{@apply rotate-180;}.custom-ng-dropdown-panel{@apply absolute left-0 w-full bg-white border border-[#E3E3E7] rounded-xl shadow-lg z-[99] overflow-hidden cursor-default;}.ng-dropdown-search{@apply px-2 pt-2;}.ng-search-wrapper{@apply flex items-center border border-[#E3E3E7] rounded-md px-3 py-[7px] bg-white transition-colors focus-within:border-[#E3E3E7];}.ng-search-input{@apply w-full outline-none font-normal text-sm text-[#141414] placeholder-[#A1A3AE] bg-transparent;}.ng-options-list{@apply max-h-60 overflow-auto relative p-2.5 mb-3.5 flex flex-col gap-0.5;}.ng-option{@apply flex items-center p-2.5 cursor-pointer transition-colors font-normal text-sm text-[#141414];}.ng-option:hover,.ng-option.marked,.ng-option.selected{@apply bg-[#F8F8F8] rounded-md;}.ng-option-disabled{@apply px-3 py-2 text-gray-400 cursor-default;}.ng-value-chip.remaining-count{@apply bg-gray-200 text-gray-600 font-semibold cursor-default;}.select-all-option{@apply sticky top-0 z-20 flex items-center px-3 py-2 cursor-pointer border-b border-[#E3E6EE] bg-gray-50 text-[#15191E];}.select-all-option:hover{@apply bg-gray-100;}.custom-ng-dropdown-panel[data-position=top]{margin-top:0;margin-bottom:4px}.input-label{@apply text-sm font-medium text-[#141414] tracking-[-.28px] mb-1.5 inline-block;}.input-label-required{@apply text-[#E7000B];}::-webkit-scrollbar{width:10px}::-webkit-scrollbar-track{background:transparent;border-radius:8px;width:8px}::-webkit-scrollbar-thumb{background:#d6d7dc;border-radius:8px;transition:.3s ease-in-out}::-webkit-scrollbar-thumb:hover{background:#909090}\n"] }]
3375
+ }], ctorParameters: () => [], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], bindLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "bindLabel", required: false }] }], bindValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "bindValue", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], notFoundText: [{ type: i0.Input, args: [{ isSignal: true, alias: "notFoundText", required: false }] }], loadingText: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingText", required: false }] }], clearAllText: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearAllText", required: false }] }], iconAlt: [{
3376
+ type: Input
3377
+ }], label: [{
3378
+ type: Input
3379
+ }], required: [{
3380
+ type: Input
3381
+ }], iconSrc: [{
3382
+ type: Input
3383
+ }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], maxLabels: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxLabels", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], closeOnSelect: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnSelect", required: false }] }], dropdownPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "dropdownPosition", required: false }] }], appendToBody: [{ type: i0.Input, args: [{ isSignal: true, alias: "appendToBody", required: false }] }], open: [{ type: i0.Output, args: ["open"] }], close: [{ type: i0.Output, args: ["close"] }], focus: [{ type: i0.Output, args: ["focus"] }], blur: [{ type: i0.Output, args: ["blur"] }], search: [{ type: i0.Output, args: ["search"] }], clear: [{ type: i0.Output, args: ["clear"] }], change: [{ type: i0.Output, args: ["change"] }], scrollToEnd: [{ type: i0.Output, args: ["scrollToEnd"] }], searchInput: [{
3384
+ type: ViewChild,
3385
+ args: ['searchInput']
3386
+ }], optionsListContainer: [{
3387
+ type: ViewChild,
3388
+ args: ['optionsListContainer']
3389
+ }], optionsRef: [{
3390
+ type: ViewChildren,
3391
+ args: ['optionsRef']
3392
+ }], controlWrapper: [{
3393
+ type: ViewChild,
3394
+ args: ['controlWrapper']
3395
+ }], compareWith: [{ type: i0.Input, args: [{ isSignal: true, alias: "compareWith", required: false }] }], onWindowEvents: [{
3396
+ type: HostListener,
3397
+ args: ['window:scroll']
3398
+ }, {
3399
+ type: HostListener,
3400
+ args: ['window:resize']
3401
+ }], onClickOutside: [{
3402
+ type: HostListener,
3403
+ args: ['document:click', ['$event']]
3404
+ }] } });
3405
+
3406
+ class BkInput {
3407
+ // =================== Inputs (all your original ones) ===================
3408
+ id;
3409
+ name;
3410
+ mask = null;
3411
+ autoComplete = 'off';
3412
+ label = 'Label';
3413
+ placeholder = 'stephend@i2cinc.com';
3414
+ hint = '';
3415
+ required = false;
3416
+ type = 'text';
3417
+ value = '';
3418
+ hasError = false;
3419
+ showErrorIcon = false;
3420
+ errorMessage = '';
3421
+ disabled = false;
3422
+ tabIndex = null;
3423
+ readOnly = false;
3424
+ autoCapitalize = null;
3425
+ inputMode = null;
3426
+ iconSrc;
3427
+ iconAlt = 'icon';
3428
+ showIcon = true;
3429
+ phone = false;
3430
+ countryCode = 'US';
3431
+ countryOptions = [
3432
+ { code: 'US', name: 'US', mask: '(000) 000-0000', prefix: '+1 ', placeholder: '(000) 000-0000' },
3433
+ { code: 'MT', name: 'MT', mask: '(000) 000-0000', prefix: '+356 ', placeholder: '(000) 000-0000' },
3434
+ { code: 'PL', name: 'PL', mask: '(000) 000-0000', prefix: '+48 ', placeholder: '(000) 000-0000' },
3435
+ { code: 'CH', name: 'CH', mask: '(000) 000-0000', prefix: '+41 ', placeholder: '(000) 000-0000' },
3436
+ { code: 'TR', name: 'TR', mask: '(000) 000-0000', prefix: '+90 ', placeholder: '(000) 000-0000' },
3437
+ { code: 'UG', name: 'UG', mask: '(000) 000-0000', prefix: '+256 ', placeholder: '(000) 000-0000' },
3438
+ { code: 'ZM', name: 'ZM', mask: '(000) 000-0000', prefix: '+260 ', placeholder: '(000) 000-0000' }
3439
+ ];
3440
+ selectedCountry = this.countryOptions[0];
3441
+ iconOrientation = 'left';
3442
+ password = false;
3443
+ showPassword = false;
3444
+ pattern;
3445
+ max = null;
3446
+ min = null;
3447
+ step = null;
3448
+ maxlength = null;
3449
+ minlength = null;
3450
+ // =================== ViewChild ===================
3451
+ dropdownRef;
3452
+ selectRef;
3453
+ inputField;
3454
+ // =================== Internal State ===================
3455
+ isFocused = false;
3456
+ inputValue = '';
3457
+ isDropdownOpen = false;
3458
+ // =================== Output Emitter ===================
3459
+ input = new EventEmitter();
3460
+ change = new EventEmitter();
3461
+ focus = new EventEmitter();
3462
+ blur = new EventEmitter();
3463
+ clicked = new EventEmitter();
3464
+ get placeHolderText() {
3465
+ if (this.phone) {
3466
+ const country = this.countryOptions.find(c => c.code === this.countryCode);
3467
+ return country?.placeholder || '';
3468
+ }
3469
+ return this.placeholder;
3470
+ }
3471
+ get maskValue() {
3472
+ if (this.mask)
3473
+ return this.mask;
3474
+ if (this.phone) {
3475
+ const country = this.countryOptions.find(c => c.code === this.countryCode);
3476
+ return country?.mask || '';
3477
+ }
3478
+ return '';
3479
+ }
3480
+ get maskPrefixValue() {
3481
+ if (this.phone) {
3482
+ const country = this.countryOptions.find(c => c.code === this.countryCode);
3483
+ return country?.prefix || '';
3484
+ }
3485
+ return '';
3486
+ }
3487
+ // =================== CVA Callbacks ===================
3488
+ onChange = (value) => { };
3489
+ onTouched = () => { };
3490
+ writeValue(value) {
3491
+ this.value = value || '';
3492
+ this.inputValue = this.value;
3493
+ }
3494
+ registerOnChange(fn) {
3495
+ this.onChange = fn;
3496
+ }
3497
+ registerOnTouched(fn) {
3498
+ this.onTouched = fn;
3499
+ }
3500
+ setDisabledState(isDisabled) {
3501
+ this.disabled = isDisabled;
3502
+ }
3503
+ // =================== Lifecycle ===================
3504
+ closeAllDropdownsHandler = () => {
3505
+ if (this.phone && this.isDropdownOpen)
3506
+ this.isDropdownOpen = false;
3507
+ };
3508
+ ngOnInit() {
3509
+ if (this.value)
3510
+ this.inputValue = this.value;
3511
+ if (this.password && this.type !== 'password')
3512
+ this.type = 'password';
3513
+ if (this.phone) {
3514
+ const country = this.countryOptions.find(c => c.code === this.countryCode);
3515
+ if (country)
3516
+ this.selectedCountry = country;
3517
+ document.addEventListener('closeAllPhoneDropdowns', this.closeAllDropdownsHandler);
3518
+ }
3519
+ }
3520
+ ngOnDestroy() {
3521
+ if (this.phone) {
3522
+ document.removeEventListener('closeAllPhoneDropdowns', this.closeAllDropdownsHandler);
3523
+ }
3524
+ }
3525
+ // =================== Host Listener ===================
3526
+ onDocumentClick(event) {
3527
+ if (this.phone && this.isDropdownOpen) {
3528
+ const target = event.target;
3529
+ if (this.selectRef?.nativeElement && this.dropdownRef?.nativeElement) {
3530
+ const clickedInside = this.selectRef.nativeElement.contains(target) ||
3531
+ this.dropdownRef.nativeElement.contains(target);
3532
+ if (!clickedInside)
3533
+ this.isDropdownOpen = false;
3534
+ }
3535
+ }
3536
+ }
3537
+ // =================== Event Handlers ===================
3538
+ handleFocus(event) {
3539
+ this.focus.emit(event);
3540
+ if (!this.disabled)
3541
+ this.isFocused = true;
3542
+ }
3543
+ handleBlur(event) {
3544
+ this.isFocused = false;
3545
+ this.onTouched();
3546
+ this.blur.emit(event);
3547
+ }
3548
+ handleInput(event) {
3549
+ const val = event.target.value;
3550
+ this.inputValue = val;
3551
+ this.value = val; // update CVA value
3552
+ this.onChange(val); // propagate to parent form
3553
+ this.input.emit(event); // emit raw event
3554
+ }
3555
+ handleClicked() {
3556
+ this.clicked.emit(true);
3557
+ }
3558
+ handleChange(event) {
3559
+ this.change.emit(event); // emit raw change event
3560
+ }
3561
+ toggleDropdown(event) {
3562
+ if (!this.disabled && this.phone) {
3563
+ if (!this.isDropdownOpen) {
3564
+ document.dispatchEvent(new CustomEvent('closeAllPhoneDropdowns'));
3565
+ setTimeout(() => (this.isDropdownOpen = true), 0);
3566
+ }
3567
+ else {
3568
+ this.isDropdownOpen = false;
3569
+ }
3570
+ event?.stopPropagation();
3571
+ }
3572
+ }
3573
+ selectCountry(country) {
3574
+ const oldCountry = this.selectedCountry;
3575
+ this.selectedCountry = country;
3576
+ this.countryCode = country.code;
3577
+ this.isDropdownOpen = false;
3578
+ const currentRaw = this.inputField?.nativeElement?.value || this.inputValue;
3579
+ let newPhone = '';
3580
+ if (currentRaw && currentRaw.trim() !== '') {
3581
+ // Input has some value → replace old prefix
3582
+ if (oldCountry?.prefix && oldCountry.code !== country.code) {
3583
+ const oldPrefixEscaped = oldCountry.prefix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
3584
+ const regex = new RegExp(`^${oldPrefixEscaped}\\s?`);
3585
+ const oldMaskedValue = currentRaw.replace(regex, '');
3586
+ newPhone = country.prefix + oldMaskedValue;
3587
+ }
3588
+ else {
3589
+ newPhone = country.prefix + currentRaw;
3590
+ }
3591
+ }
3592
+ else {
3593
+ // Input is empty → show only the new prefix OR empty
3594
+ newPhone = ''; // optionally: newPhone = country.prefix;
3595
+ }
3596
+ this.inputValue = newPhone;
3597
+ this.value = newPhone;
3598
+ this.onChange(newPhone);
3599
+ setTimeout(() => {
3600
+ if (this.inputField?.nativeElement) {
3601
+ this.inputField.nativeElement.value = newPhone;
3602
+ this.inputField.nativeElement.dispatchEvent(new Event('input', { bubbles: true }));
3603
+ }
3604
+ }, 0);
3605
+ }
3606
+ togglePasswordVisibility(event) {
3607
+ if (!this.disabled && this.password) {
3608
+ event.preventDefault();
3609
+ event.stopPropagation();
3610
+ this.showPassword = !this.showPassword;
3611
+ this.type = this.showPassword ? 'text' : 'password';
3612
+ }
3613
+ }
3614
+ handleIconClick(event) {
3615
+ if (this.disabled || this.readOnly) {
3616
+ event.preventDefault();
3617
+ event.stopPropagation();
3618
+ return;
3619
+ }
3620
+ this.clicked.emit(true);
3621
+ }
3622
+ // =================== Getters ===================
3623
+ get isFilled() {
3624
+ return this.inputValue.length > 0;
3625
+ }
3626
+ get inputState() {
3627
+ if (this.disabled)
3628
+ return 'disabled';
3629
+ if (this.hasError)
3630
+ return 'error';
3631
+ if (this.isFocused || this.isDropdownOpen)
3632
+ return 'focused';
3633
+ if (this.isFilled)
3634
+ return 'filled';
3635
+ return 'default';
3636
+ }
3637
+ get currentInputType() {
3638
+ if (this.password)
3639
+ return this.showPassword ? 'text' : 'password';
3640
+ return this.type;
3641
+ }
3642
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkInput, deps: [], target: i0.ɵɵFactoryTarget.Component });
3643
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkInput, isStandalone: true, selector: "bk-input", inputs: { id: "id", name: "name", mask: "mask", autoComplete: "autoComplete", label: "label", placeholder: "placeholder", hint: "hint", required: "required", type: "type", value: "value", hasError: "hasError", showErrorIcon: "showErrorIcon", errorMessage: "errorMessage", disabled: "disabled", tabIndex: "tabIndex", readOnly: "readOnly", autoCapitalize: "autoCapitalize", inputMode: "inputMode", iconSrc: "iconSrc", iconAlt: "iconAlt", showIcon: "showIcon", phone: "phone", countryCode: "countryCode", countryOptions: "countryOptions", iconOrientation: "iconOrientation", password: "password", showPassword: "showPassword", pattern: "pattern", max: "max", min: "min", step: "step", maxlength: "maxlength", minlength: "minlength" }, outputs: { input: "input", change: "change", focus: "focus", blur: "blur", clicked: "clicked" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, providers: [
3644
+ provideNgxMask(),
3645
+ {
3646
+ provide: NG_VALUE_ACCESSOR,
3647
+ useExisting: forwardRef(() => BkInput),
3648
+ multi: true
3649
+ }
3650
+ ], viewQueries: [{ propertyName: "dropdownRef", first: true, predicate: ["dropdownRef"], descendants: true }, { propertyName: "selectRef", first: true, predicate: ["selectRef"], descendants: true }, { propertyName: "inputField", first: true, predicate: ["inputField"], descendants: true }], ngImport: i0, template: "<div class=\"input-container\">\r\n <label [for]=\"id\" class=\"input-label\">\r\n {{ label }}\r\n @if(required){\r\n <span class=\"input-label-required\">*</span>\r\n }\r\n </label>\r\n\r\n <div class=\"input-wrapper\" [ngClass]=\"{\r\n 'input-wrapper--url': type === 'url',\r\n 'input-wrapper--phone': phone,\r\n 'input-wrapper--password': password,\r\n 'input-wrapper--icon': iconSrc && showIcon\r\n }\">\r\n\r\n <input\r\n #inputField\r\n [type]=\"currentInputType\"\r\n [id]=\"id\"\r\n [name]=\"name\"\r\n [disabled]=\"disabled\"\r\n [tabindex]=\"tabIndex\"\r\n [readOnly]=\"readOnly\"\r\n [attr.maxlength]=\"maxlength\"\r\n [attr.minlength]=\"minlength\"\r\n [autocomplete]=\"autoComplete\"\r\n [autocapitalize]=\"autoCapitalize\"\r\n\r\n [attr.max]=\"max\"\r\n [attr.min]=\"min\"\r\n [attr.step]=\"step\"\r\n\r\n [placeholder]=\"placeHolderText\"\r\n [pattern]=\"pattern\"\r\n [autocomplete]=\"autoComplete\"\r\n [value]=\"inputValue\"\r\n\r\n\r\n\r\n [mask]=\"maskValue\"\r\n [prefix]=\"maskPrefixValue\"\r\n [showMaskTyped]=\"false\"\r\n [dropSpecialCharacters]=\"false\"\r\n (change)=\"handleChange($event)\"\r\n (input)=\"handleInput($event)\"\r\n (focus)=\"handleFocus($event)\"\r\n (blur)=\"handleBlur($event)\"\r\n class=\"input-field\"\r\n\r\n [ngClass]=\"{\r\n 'input-field--url': type === 'url',\r\n 'input-field--phone': phone,\r\n 'input-field--icon-left': iconSrc && showIcon && iconOrientation === 'left',\r\n 'input-field--icon-right': iconSrc && showIcon && iconOrientation === 'right',\r\n 'input-field--password': password,\r\n 'input-field--default': inputState === 'default',\r\n 'input-field--focused': inputState === 'focused',\r\n 'input-field--filled': inputState === 'filled',\r\n 'input-field--error': inputState === 'error',\r\n 'input-field--disabled': inputState === 'disabled'\r\n }\">\r\n\r\n @if(iconSrc && showIcon){\r\n <img (click)=\"handleIconClick($event)\" [src]=\"iconSrc\" [alt]=\"iconAlt\" [ngClass]=\"{\r\n 'input-search-icon--left': iconOrientation === 'left',\r\n 'input-search-icon--right': iconOrientation === 'right',\r\n 'cursor-pointer': !disabled && !readOnly\r\n }\" class=\"input-search-icon\">\r\n }\r\n\r\n @if(showErrorIcon){\r\n <img src=\"../../assets/images/icons/global/info-circle.svg\" class=\"input-search-icon input-search-icon--right\">\r\n }\r\n\r\n @if(password){\r\n <button type=\"button\" (click)=\"togglePasswordVisibility($event)\" class=\"input-password-toggle\" [disabled]=\"disabled\" tabindex=\"-1\">\r\n <img [src]=\"showPassword ? '../../assets/images/icons/global/eye-slash-icon.svg' : '../../assets/images/icons/global/eye-icon.svg'\" [alt]=\"showPassword ? 'Hide password' : 'Show password'\" class=\"input-password-icon\">\r\n </button>\r\n }\r\n\r\n @if(phone){\r\n <div #selectRef class=\"input-phone-selector\" [ngClass]=\"{\r\n 'input-phone-selector--default': inputState === 'default',\r\n 'input-phone-selector--focused': inputState === 'focused',\r\n 'input-phone-selector--filled': inputState === 'filled',\r\n 'input-phone-selector--error': inputState === 'error',\r\n 'input-phone-selector--disabled': inputState === 'disabled'\r\n }\" (click)=\"toggleDropdown($event)\">\r\n <span class=\"input-phone-selector-text\">{{ selectedCountry.name }}</span>\r\n <img src=\"../../assets/images/icons/global/input-arrow-down.svg\" alt=\"Dropdown\" class=\"input-phone-selector-arrow\" [ngClass]=\"{'input-phone-selector-arrow--open': isDropdownOpen}\">\r\n </div>\r\n }\r\n\r\n @if(phone && isDropdownOpen){\r\n <div #dropdownRef class=\"input-phone-dropdown\" (click)=\"$event.stopPropagation()\">\r\n <button *ngFor=\"let country of countryOptions\" type=\"button\" class=\"input-phone-dropdown-item\" [ngClass]=\"{'input-phone-dropdown-item--active': selectedCountry.code === country.code}\" (click)=\"selectCountry(country); $event.stopPropagation()\">\r\n {{ country.name }}\r\n </button>\r\n </div>\r\n }\r\n\r\n\r\n\r\n @if(type === 'url'){\r\n <span class=\"input-url-prefix\" [ngClass]=\"{\r\n 'input-url-prefix--default': inputState === 'default',\r\n 'input-url-prefix--focused': inputState === 'focused',\r\n 'input-url-prefix--filled': inputState === 'filled',\r\n 'input-url-prefix--error': inputState === 'error',\r\n 'input-url-prefix--disabled': inputState === 'disabled'\r\n }\">https</span>\r\n }\r\n </div>\r\n\r\n @if(hasError){\r\n @if (errorMessage) {\r\n <p class=\"input-error\">{{ errorMessage }}</p>\r\n }\r\n }\r\n @if(!hasError){\r\n @if(hint){\r\n <p class=\"input-hint\">{{ hint }}</p>\r\n }\r\n }\r\n</div>\r\n", styles: [".input-container{@apply flex flex-col gap-1.5;}.input-label{@apply text-sm font-medium text-[#141414];}.input-label-required{@apply text-[#E7000B] ml-0.5;}.input-wrapper{@apply relative;}.input-field{@apply w-full py-2.5 px-3 text-sm border rounded-[4px] outline-none transition-all duration-200 bg-white;height:40px;box-sizing:border-box}.input-field--default{@apply border-[#E3E3E7] text-[#141414] placeholder:text-[#6B7080];}.input-field--focused{@apply border-[#6B7080] text-[#141414];}.input-field--filled{@apply border-[#E3E3E7] text-[#141414] bg-white;}.input-field--error{@apply border-[#E7000B] text-[#141414];}.input-field--disabled{@apply border-[#E3E3E7] bg-[#F4F4F6] text-[#A1A3AE] cursor-not-allowed;}.input-field--icon{@apply pl-[48px];}.input-field--phone{@apply pl-[80px];}.input-field--url{@apply pl-[72px];}.input-field--icon-left{@apply pl-[48px];}.input-field--icon-right,.input-field--password{@apply pr-[48px];}.input-field--icon.input-field--url{@apply pl-[120px];}.input-field--phone.input-field--icon{@apply pl-[128px];}.input-phone-selector{@apply absolute left-0 top-0 bottom-0 px-3 flex items-center gap-2 cursor-pointer border transition-colors duration-200;border-top-left-radius:4px;border-bottom-left-radius:4px}.input-phone-selector-text{@apply text-xs leading-[18px] text-[#A1A3AE] font-normal;}.input-phone-selector-arrow{@apply w-4 h-4 transition-transform duration-200;}.input-phone-selector-arrow--open{@apply rotate-180;}.input-phone-selector--default{@apply bg-white border-[#E3E3E7];}.input-phone-selector--focused{@apply bg-white border-[#6B7080];}.input-phone-selector--filled{@apply bg-white border-[#E3E3E7];}.input-phone-selector--error{@apply bg-white border-[#E7000B];}.input-phone-selector--disabled{@apply bg-[#F4F4F6] border-[#E3E3E7] cursor-not-allowed;}.input-phone-selector--disabled .input-phone-selector-text{@apply text-[#A1A3AE];}.input-phone-dropdown{@apply absolute left-0 top-full mt-1 w-[80px] bg-white border border-[#E3E3E7] rounded-[4px] shadow-lg z-50 max-h-48 overflow-y-auto;}.input-phone-dropdown-item{@apply w-full px-5 py-2.5 text-center text-xs leading-[18px] text-[#6B7080] hover:bg-[#F9FAFA] transition-colors duration-200 border-none bg-transparent;}.input-phone-dropdown-item--active{@apply bg-[#F9FAFA] text-[#141414];}.input-icon{@apply absolute left-3 top-1/2 -translate-y-1/2 w-6 h-6 pointer-events-none size-6;}.input-wrapper--phone .input-icon{@apply left-[80px];}.input-search-icon{@apply absolute top-1/2 -translate-y-1/2 w-5 h-5;}.input-search-icon--left{@apply left-3;}.input-search-icon--right{@apply right-3;}.input-password-toggle{@apply absolute right-3 top-1/2 -translate-y-1/2 w-5 h-5 p-0 border-0 bg-transparent cursor-pointer outline-none flex items-center justify-center;}.input-password-toggle:disabled{@apply cursor-not-allowed opacity-50;}.input-password-toggle:hover:not(:disabled){@apply opacity-70;}.input-password-icon{@apply w-5 h-5 pointer-events-none;}.input-url-prefix{@apply absolute left-0 top-0 bottom-0 py-2.5 px-3 text-sm text-[#6B7080] bg-white border flex items-center transition-colors duration-200 pointer-events-none;border-top-left-radius:4px;border-bottom-left-radius:4px}.input-wrapper--icon .input-url-prefix{@apply left-[48px];}.input-url-prefix--default{@apply border-[#E3E3E7];}.input-url-prefix--focused{@apply border-[#6B7080];}.input-url-prefix--filled{@apply border-[#E3E3E7];}.input-url-prefix--error{@apply border-[#E7000B];}.input-url-prefix--disabled{@apply bg-[#F4F4F6] text-[#A1A3AE] border-r-[#E3E3E7];}.input-hint{@apply text-xs text-[#868997] font-normal;}.input-error{@apply text-xs text-[#E7000B] font-normal;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: NgxMaskDirective, selector: "input[mask], textarea[mask]", inputs: ["mask", "specialCharacters", "patterns", "prefix", "suffix", "thousandSeparator", "decimalMarker", "dropSpecialCharacters", "hiddenInput", "showMaskTyped", "placeHolderCharacter", "shownMaskExpression", "clearIfNotMatch", "validation", "separatorLimit", "allowNegativeNumbers", "leadZeroDateTime", "leadZero", "triggerOnMaskChange", "apm", "inputTransformFn", "outputTransformFn", "keepCharacterPositions", "instantPrefix"], outputs: ["maskFilled"], exportAs: ["mask", "ngxMask"] }, { kind: "ngmodule", type: FormsModule }] });
3651
+ }
3652
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkInput, decorators: [{
3653
+ type: Component,
3654
+ args: [{ selector: 'bk-input', imports: [CommonModule, NgxMaskDirective, FormsModule], standalone: true, providers: [
3655
+ provideNgxMask(),
3656
+ {
3657
+ provide: NG_VALUE_ACCESSOR,
3658
+ useExisting: forwardRef(() => BkInput),
3659
+ multi: true
3660
+ }
3661
+ ], template: "<div class=\"input-container\">\r\n <label [for]=\"id\" class=\"input-label\">\r\n {{ label }}\r\n @if(required){\r\n <span class=\"input-label-required\">*</span>\r\n }\r\n </label>\r\n\r\n <div class=\"input-wrapper\" [ngClass]=\"{\r\n 'input-wrapper--url': type === 'url',\r\n 'input-wrapper--phone': phone,\r\n 'input-wrapper--password': password,\r\n 'input-wrapper--icon': iconSrc && showIcon\r\n }\">\r\n\r\n <input\r\n #inputField\r\n [type]=\"currentInputType\"\r\n [id]=\"id\"\r\n [name]=\"name\"\r\n [disabled]=\"disabled\"\r\n [tabindex]=\"tabIndex\"\r\n [readOnly]=\"readOnly\"\r\n [attr.maxlength]=\"maxlength\"\r\n [attr.minlength]=\"minlength\"\r\n [autocomplete]=\"autoComplete\"\r\n [autocapitalize]=\"autoCapitalize\"\r\n\r\n [attr.max]=\"max\"\r\n [attr.min]=\"min\"\r\n [attr.step]=\"step\"\r\n\r\n [placeholder]=\"placeHolderText\"\r\n [pattern]=\"pattern\"\r\n [autocomplete]=\"autoComplete\"\r\n [value]=\"inputValue\"\r\n\r\n\r\n\r\n [mask]=\"maskValue\"\r\n [prefix]=\"maskPrefixValue\"\r\n [showMaskTyped]=\"false\"\r\n [dropSpecialCharacters]=\"false\"\r\n (change)=\"handleChange($event)\"\r\n (input)=\"handleInput($event)\"\r\n (focus)=\"handleFocus($event)\"\r\n (blur)=\"handleBlur($event)\"\r\n class=\"input-field\"\r\n\r\n [ngClass]=\"{\r\n 'input-field--url': type === 'url',\r\n 'input-field--phone': phone,\r\n 'input-field--icon-left': iconSrc && showIcon && iconOrientation === 'left',\r\n 'input-field--icon-right': iconSrc && showIcon && iconOrientation === 'right',\r\n 'input-field--password': password,\r\n 'input-field--default': inputState === 'default',\r\n 'input-field--focused': inputState === 'focused',\r\n 'input-field--filled': inputState === 'filled',\r\n 'input-field--error': inputState === 'error',\r\n 'input-field--disabled': inputState === 'disabled'\r\n }\">\r\n\r\n @if(iconSrc && showIcon){\r\n <img (click)=\"handleIconClick($event)\" [src]=\"iconSrc\" [alt]=\"iconAlt\" [ngClass]=\"{\r\n 'input-search-icon--left': iconOrientation === 'left',\r\n 'input-search-icon--right': iconOrientation === 'right',\r\n 'cursor-pointer': !disabled && !readOnly\r\n }\" class=\"input-search-icon\">\r\n }\r\n\r\n @if(showErrorIcon){\r\n <img src=\"../../assets/images/icons/global/info-circle.svg\" class=\"input-search-icon input-search-icon--right\">\r\n }\r\n\r\n @if(password){\r\n <button type=\"button\" (click)=\"togglePasswordVisibility($event)\" class=\"input-password-toggle\" [disabled]=\"disabled\" tabindex=\"-1\">\r\n <img [src]=\"showPassword ? '../../assets/images/icons/global/eye-slash-icon.svg' : '../../assets/images/icons/global/eye-icon.svg'\" [alt]=\"showPassword ? 'Hide password' : 'Show password'\" class=\"input-password-icon\">\r\n </button>\r\n }\r\n\r\n @if(phone){\r\n <div #selectRef class=\"input-phone-selector\" [ngClass]=\"{\r\n 'input-phone-selector--default': inputState === 'default',\r\n 'input-phone-selector--focused': inputState === 'focused',\r\n 'input-phone-selector--filled': inputState === 'filled',\r\n 'input-phone-selector--error': inputState === 'error',\r\n 'input-phone-selector--disabled': inputState === 'disabled'\r\n }\" (click)=\"toggleDropdown($event)\">\r\n <span class=\"input-phone-selector-text\">{{ selectedCountry.name }}</span>\r\n <img src=\"../../assets/images/icons/global/input-arrow-down.svg\" alt=\"Dropdown\" class=\"input-phone-selector-arrow\" [ngClass]=\"{'input-phone-selector-arrow--open': isDropdownOpen}\">\r\n </div>\r\n }\r\n\r\n @if(phone && isDropdownOpen){\r\n <div #dropdownRef class=\"input-phone-dropdown\" (click)=\"$event.stopPropagation()\">\r\n <button *ngFor=\"let country of countryOptions\" type=\"button\" class=\"input-phone-dropdown-item\" [ngClass]=\"{'input-phone-dropdown-item--active': selectedCountry.code === country.code}\" (click)=\"selectCountry(country); $event.stopPropagation()\">\r\n {{ country.name }}\r\n </button>\r\n </div>\r\n }\r\n\r\n\r\n\r\n @if(type === 'url'){\r\n <span class=\"input-url-prefix\" [ngClass]=\"{\r\n 'input-url-prefix--default': inputState === 'default',\r\n 'input-url-prefix--focused': inputState === 'focused',\r\n 'input-url-prefix--filled': inputState === 'filled',\r\n 'input-url-prefix--error': inputState === 'error',\r\n 'input-url-prefix--disabled': inputState === 'disabled'\r\n }\">https</span>\r\n }\r\n </div>\r\n\r\n @if(hasError){\r\n @if (errorMessage) {\r\n <p class=\"input-error\">{{ errorMessage }}</p>\r\n }\r\n }\r\n @if(!hasError){\r\n @if(hint){\r\n <p class=\"input-hint\">{{ hint }}</p>\r\n }\r\n }\r\n</div>\r\n", styles: [".input-container{@apply flex flex-col gap-1.5;}.input-label{@apply text-sm font-medium text-[#141414];}.input-label-required{@apply text-[#E7000B] ml-0.5;}.input-wrapper{@apply relative;}.input-field{@apply w-full py-2.5 px-3 text-sm border rounded-[4px] outline-none transition-all duration-200 bg-white;height:40px;box-sizing:border-box}.input-field--default{@apply border-[#E3E3E7] text-[#141414] placeholder:text-[#6B7080];}.input-field--focused{@apply border-[#6B7080] text-[#141414];}.input-field--filled{@apply border-[#E3E3E7] text-[#141414] bg-white;}.input-field--error{@apply border-[#E7000B] text-[#141414];}.input-field--disabled{@apply border-[#E3E3E7] bg-[#F4F4F6] text-[#A1A3AE] cursor-not-allowed;}.input-field--icon{@apply pl-[48px];}.input-field--phone{@apply pl-[80px];}.input-field--url{@apply pl-[72px];}.input-field--icon-left{@apply pl-[48px];}.input-field--icon-right,.input-field--password{@apply pr-[48px];}.input-field--icon.input-field--url{@apply pl-[120px];}.input-field--phone.input-field--icon{@apply pl-[128px];}.input-phone-selector{@apply absolute left-0 top-0 bottom-0 px-3 flex items-center gap-2 cursor-pointer border transition-colors duration-200;border-top-left-radius:4px;border-bottom-left-radius:4px}.input-phone-selector-text{@apply text-xs leading-[18px] text-[#A1A3AE] font-normal;}.input-phone-selector-arrow{@apply w-4 h-4 transition-transform duration-200;}.input-phone-selector-arrow--open{@apply rotate-180;}.input-phone-selector--default{@apply bg-white border-[#E3E3E7];}.input-phone-selector--focused{@apply bg-white border-[#6B7080];}.input-phone-selector--filled{@apply bg-white border-[#E3E3E7];}.input-phone-selector--error{@apply bg-white border-[#E7000B];}.input-phone-selector--disabled{@apply bg-[#F4F4F6] border-[#E3E3E7] cursor-not-allowed;}.input-phone-selector--disabled .input-phone-selector-text{@apply text-[#A1A3AE];}.input-phone-dropdown{@apply absolute left-0 top-full mt-1 w-[80px] bg-white border border-[#E3E3E7] rounded-[4px] shadow-lg z-50 max-h-48 overflow-y-auto;}.input-phone-dropdown-item{@apply w-full px-5 py-2.5 text-center text-xs leading-[18px] text-[#6B7080] hover:bg-[#F9FAFA] transition-colors duration-200 border-none bg-transparent;}.input-phone-dropdown-item--active{@apply bg-[#F9FAFA] text-[#141414];}.input-icon{@apply absolute left-3 top-1/2 -translate-y-1/2 w-6 h-6 pointer-events-none size-6;}.input-wrapper--phone .input-icon{@apply left-[80px];}.input-search-icon{@apply absolute top-1/2 -translate-y-1/2 w-5 h-5;}.input-search-icon--left{@apply left-3;}.input-search-icon--right{@apply right-3;}.input-password-toggle{@apply absolute right-3 top-1/2 -translate-y-1/2 w-5 h-5 p-0 border-0 bg-transparent cursor-pointer outline-none flex items-center justify-center;}.input-password-toggle:disabled{@apply cursor-not-allowed opacity-50;}.input-password-toggle:hover:not(:disabled){@apply opacity-70;}.input-password-icon{@apply w-5 h-5 pointer-events-none;}.input-url-prefix{@apply absolute left-0 top-0 bottom-0 py-2.5 px-3 text-sm text-[#6B7080] bg-white border flex items-center transition-colors duration-200 pointer-events-none;border-top-left-radius:4px;border-bottom-left-radius:4px}.input-wrapper--icon .input-url-prefix{@apply left-[48px];}.input-url-prefix--default{@apply border-[#E3E3E7];}.input-url-prefix--focused{@apply border-[#6B7080];}.input-url-prefix--filled{@apply border-[#E3E3E7];}.input-url-prefix--error{@apply border-[#E7000B];}.input-url-prefix--disabled{@apply bg-[#F4F4F6] text-[#A1A3AE] border-r-[#E3E3E7];}.input-hint{@apply text-xs text-[#868997] font-normal;}.input-error{@apply text-xs text-[#E7000B] font-normal;}\n"] }]
3662
+ }], propDecorators: { id: [{
3663
+ type: Input
3664
+ }], name: [{
3665
+ type: Input
3666
+ }], mask: [{
3667
+ type: Input
3668
+ }], autoComplete: [{
3669
+ type: Input
3670
+ }], label: [{
3671
+ type: Input
3672
+ }], placeholder: [{
3673
+ type: Input
3674
+ }], hint: [{
3675
+ type: Input
3676
+ }], required: [{
3677
+ type: Input
3678
+ }], type: [{
3679
+ type: Input
3680
+ }], value: [{
3681
+ type: Input
3682
+ }], hasError: [{
3683
+ type: Input
3684
+ }], showErrorIcon: [{
3685
+ type: Input
3686
+ }], errorMessage: [{
3687
+ type: Input
3688
+ }], disabled: [{
3689
+ type: Input
3690
+ }], tabIndex: [{
3691
+ type: Input
3692
+ }], readOnly: [{
3693
+ type: Input
3694
+ }], autoCapitalize: [{
3695
+ type: Input
3696
+ }], inputMode: [{
3697
+ type: Input
3698
+ }], iconSrc: [{
3699
+ type: Input
3700
+ }], iconAlt: [{
3701
+ type: Input
3702
+ }], showIcon: [{
3703
+ type: Input
3704
+ }], phone: [{
3705
+ type: Input
3706
+ }], countryCode: [{
3707
+ type: Input
3708
+ }], countryOptions: [{
3709
+ type: Input
3710
+ }], iconOrientation: [{
3711
+ type: Input
3712
+ }], password: [{
3713
+ type: Input
3714
+ }], showPassword: [{
3715
+ type: Input
3716
+ }], pattern: [{
3717
+ type: Input
3718
+ }], max: [{
3719
+ type: Input
3720
+ }], min: [{
3721
+ type: Input
3722
+ }], step: [{
3723
+ type: Input
3724
+ }], maxlength: [{
3725
+ type: Input
3726
+ }], minlength: [{
3727
+ type: Input
3728
+ }], dropdownRef: [{
3729
+ type: ViewChild,
3730
+ args: ['dropdownRef']
3731
+ }], selectRef: [{
3732
+ type: ViewChild,
3733
+ args: ['selectRef']
3734
+ }], inputField: [{
3735
+ type: ViewChild,
3736
+ args: ['inputField']
3737
+ }], input: [{
3738
+ type: Output
3739
+ }], change: [{
3740
+ type: Output
3741
+ }], focus: [{
3742
+ type: Output
3743
+ }], blur: [{
3744
+ type: Output
3745
+ }], clicked: [{
3746
+ type: Output
3747
+ }], onDocumentClick: [{
3748
+ type: HostListener,
3749
+ args: ['document:click', ['$event']]
3750
+ }] } });
3751
+
3752
+ class BkChips {
3753
+ badgeInput;
3754
+ fieldWrapper;
3755
+ // --- Configuration Inputs ---
3756
+ id;
3757
+ name;
3758
+ label = '';
3759
+ placeholder = '';
3760
+ hint = '';
3761
+ required = false;
3762
+ disabled = false;
3763
+ readOnly = false;
3764
+ /**
3765
+ * If true, displays the component in an error state (red border).
3766
+ * It also replaces the hint text with the error message.
3767
+ */
3768
+ hasError = false;
3769
+ errorMessage = 'This is a error message';
3770
+ // =================== Output Emitter ===================
3771
+ input = new EventEmitter();
3772
+ change = new EventEmitter();
3773
+ focus = new EventEmitter();
3774
+ blur = new EventEmitter();
3775
+ // --- State Properties ---
3776
+ badges = [];
3777
+ inputValue = '';
3778
+ isFocused = false;
3779
+ needsScroll = false;
3780
+ // --- ControlValueAccessor Methods ---
3781
+ onChange = () => { };
3782
+ onTouched = () => { };
3783
+ // Get input state for styling variants
3784
+ get inputState() {
3785
+ if (this.disabled)
3786
+ return 'disabled';
3787
+ if (this.hasError)
3788
+ return 'error';
3789
+ if (this.isFocused)
3790
+ return 'focused';
3791
+ if (this.badges.length > 0 || this.inputValue.length > 0)
3792
+ return 'filled';
3793
+ return 'default';
3794
+ }
3795
+ // Handle keydown events (Enter to add badge, Backspace to remove)
3796
+ onKeyDown(event) {
3797
+ if (this.disabled)
3798
+ return;
3799
+ // Add badge on Enter or comma
3800
+ if (event.key === 'Enter' || event.key === ',') {
3801
+ event.preventDefault();
3802
+ this.addBadge();
3803
+ }
3804
+ // Remove last badge on Backspace when input is empty
3805
+ else if (event.key === 'Backspace' && this.inputValue === '' && this.badges.length > 0) {
3806
+ this.removeBadge(this.badges.length - 1);
3807
+ }
3808
+ }
3809
+ // Add a badge from the current input value
3810
+ addBadge() {
3811
+ const trimmedValue = this.inputValue.trim();
3812
+ if (trimmedValue && !this.badges.includes(trimmedValue)) {
3813
+ this.badges.push(trimmedValue);
3814
+ this.inputValue = '';
3815
+ this.updateValue();
3816
+ // Check if scroll is needed after adding badge (with delay for DOM update)
3817
+ setTimeout(() => this.checkScrollNeeded(), 10);
3818
+ }
3819
+ else if (trimmedValue && this.badges.includes(trimmedValue)) {
3820
+ // Optionally show a message that badge already exists
3821
+ this.inputValue = '';
3822
+ }
3823
+ }
3824
+ // Remove a badge at the given index
3825
+ removeBadge(index) {
3826
+ if (this.disabled)
3827
+ return;
3828
+ this.badges.splice(index, 1);
3829
+ this.updateValue();
3830
+ // Check if scroll is needed after removing badge (with delay for DOM update)
3831
+ setTimeout(() => {
3832
+ this.checkScrollNeeded();
3833
+ if (this.badgeInput) {
3834
+ this.badgeInput.nativeElement.focus();
3835
+ }
3836
+ }, 10);
3837
+ }
3838
+ // Check if scrolling is needed (when content wraps)
3839
+ checkScrollNeeded() {
3840
+ if (this.fieldWrapper && this.fieldWrapper.nativeElement) {
3841
+ const wrapper = this.fieldWrapper.nativeElement;
3842
+ // Get all badge items
3843
+ const badgeItems = wrapper.querySelectorAll('.input-badge-item');
3844
+ if (badgeItems.length === 0) {
3845
+ // No badges, no scroll needed
3846
+ this.needsScroll = false;
3847
+ return;
3848
+ }
3849
+ // Get the first badge's top position
3850
+ const firstBadge = badgeItems[0];
3851
+ const firstBadgeTop = firstBadge.offsetTop;
3852
+ // Check if any badge is on a different line (different top position)
3853
+ let hasWrapped = false;
3854
+ for (let i = 1; i < badgeItems.length; i++) {
3855
+ const badge = badgeItems[i];
3856
+ // If a badge's top position is different, it means it wrapped to a new line
3857
+ if (Math.abs(badge.offsetTop - firstBadgeTop) > 5) {
3858
+ hasWrapped = true;
3859
+ break;
3860
+ }
3861
+ }
3862
+ // Also check if the input field is on a different line
3863
+ if (!hasWrapped && this.badgeInput && this.badgeInput.nativeElement) {
3864
+ const inputTop = this.badgeInput.nativeElement.offsetTop;
3865
+ if (Math.abs(inputTop - firstBadgeTop) > 5) {
3866
+ hasWrapped = true;
3867
+ }
3868
+ }
3869
+ // Only enable scroll if content actually wrapped
3870
+ this.needsScroll = hasWrapped;
3871
+ }
3872
+ }
3873
+ // Update the value and notify Angular Forms
3874
+ updateValue() {
3875
+ this.onChange([...this.badges]);
3876
+ this.change.emit([...this.badges]);
3877
+ }
3878
+ // Focus the input field
3879
+ focusInput() {
3880
+ if (!this.disabled && this.badgeInput) {
3881
+ this.badgeInput.nativeElement.focus();
3882
+ }
3883
+ }
3884
+ ngAfterViewInit() {
3885
+ // Check scroll after view initializes
3886
+ setTimeout(() => this.checkScrollNeeded(), 10);
3887
+ }
3888
+ // Called when Angular writes a value TO the component (e.g. initial value)
3889
+ writeValue(value) {
3890
+ if (Array.isArray(value)) {
3891
+ this.badges = [...value];
3892
+ }
3893
+ else {
3894
+ this.badges = [];
3895
+ }
3896
+ this.inputValue = '';
3897
+ // Check scroll after value is written (with delay for DOM update)
3898
+ setTimeout(() => this.checkScrollNeeded(), 10);
3899
+ }
3900
+ // Register function to call when value changes
3901
+ registerOnChange(fn) {
3902
+ this.onChange = fn;
3903
+ }
3904
+ // Register function to call when component is touched/blurred
3905
+ registerOnTouched(fn) {
3906
+ this.onTouched = fn;
3907
+ }
3908
+ // Called when the component is disabled via the form control
3909
+ setDisabledState(disabled) {
3910
+ this.disabled = disabled;
3911
+ }
3912
+ // =================== Event Handlers ===================
3913
+ // Called when the value in the UI changes (user types)
3914
+ handleInput(event) {
3915
+ const input = event.target;
3916
+ this.inputValue = input.value;
3917
+ }
3918
+ handleFocus(event) {
3919
+ if (!this.disabled) {
3920
+ this.isFocused = true;
3921
+ }
3922
+ this.onChange([...this.badges]);
3923
+ this.focus.emit(event);
3924
+ }
3925
+ handleBlur(event) {
3926
+ this.isFocused = false;
3927
+ this.onTouched();
3928
+ this.onChange([...this.badges]);
3929
+ this.blur.emit(event);
3930
+ }
3931
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkChips, deps: [], target: i0.ɵɵFactoryTarget.Component });
3932
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkChips, isStandalone: true, selector: "bk-chips", inputs: { id: "id", name: "name", label: "label", placeholder: "placeholder", hint: "hint", required: "required", disabled: "disabled", readOnly: "readOnly", hasError: "hasError", errorMessage: "errorMessage" }, outputs: { input: "input", change: "change", focus: "focus", blur: "blur" }, providers: [
3933
+ {
3934
+ provide: NG_VALUE_ACCESSOR,
3935
+ useExisting: forwardRef(() => BkChips),
3936
+ multi: true
3937
+ }
3938
+ ], viewQueries: [{ propertyName: "badgeInput", first: true, predicate: ["badgeInput"], descendants: true }, { propertyName: "fieldWrapper", first: true, predicate: ["fieldWrapper"], descendants: true }], ngImport: i0, template: "<div class=\"input-badge-container\">\r\n @if (label) {\r\n <label\r\n [for]=\"id\"\r\n class=\"input-badge-label\">\r\n {{ label }}\r\n @if (required) {\r\n <span class=\"input-badge-label-required\">*</span>\r\n }\r\n </label>\r\n }\r\n\r\n <div class=\"input-badge-wrapper\">\r\n <div\r\n #fieldWrapper\r\n class=\"input-badge-field-wrapper\"\r\n [ngClass]=\"{\r\n 'input-badge-field-wrapper--default': inputState === 'default',\r\n 'input-badge-field-wrapper--focused': inputState === 'focused',\r\n 'input-badge-field-wrapper--filled': inputState === 'filled',\r\n 'input-badge-field-wrapper--error': inputState === 'error',\r\n 'input-badge-field-wrapper--disabled': inputState === 'disabled',\r\n 'input-badge-field-wrapper--scrollable': needsScroll\r\n }\"\r\n (click)=\"focusInput()\"\r\n >\r\n <!-- Badges -->\r\n @for (badge of badges; track badge; let i = $index) {\r\n <div class=\"input-badge-item\">\r\n <span class=\"input-badge-item-text\">{{ badge }}</span>\r\n @if (!disabled) {\r\n <button type=\"button\" (click)=\"removeBadge(i); $event.stopPropagation()\"class=\"input-badge-item-close\" >\r\n <img src=\"../../../../assets/images/icons/global/badge-close.svg\" alt=\"Remove\" class=\"input-badge-item-close-icon\"/>\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Input Field -->\r\n <input\r\n #badgeInput\r\n type=\"text\"\r\n [id]=\"id\"\r\n [name]=\"name\"\r\n [value]=\"inputValue\"\r\n (keydown)=\"onKeyDown($event)\"\r\n (input)=\"handleInput($event)\"\r\n (focus)=\"handleFocus($event)\"\r\n (blur)=\"handleBlur($event)\"\r\n [placeholder]=\"badges.length === 0 ? placeholder : ''\"\r\n [disabled]=\"disabled\"\r\n [readOnly]=\"readOnly\"\r\n class=\"input-badge-input\"\r\n [ngClass]=\"{\r\n 'input-badge-input--default': inputState === 'default',\r\n 'input-badge-input--focused': inputState === 'focused',\r\n 'input-badge-input--filled': inputState === 'filled',\r\n 'input-badge-input--error': inputState === 'error',\r\n 'input-badge-input--disabled': inputState === 'disabled'\r\n }\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <div class=\"input-badge-footer\">\r\n <div class=\"input-badge-footer-content\">\r\n @if (hasError) {\r\n <span class=\"input-badge-error\"> {{ errorMessage }}</span>\r\n } @else if (hint) {\r\n <span class=\"input-badge-hint\"> {{ hint }}</span>\r\n }\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [".input-badge-container{@apply flex flex-col gap-1.5 w-full;}.input-badge-label{@apply text-sm font-medium text-[#141414] block;}.input-badge-label-required{@apply text-[#E7000B] ml-0.5;}.input-badge-wrapper{@apply relative;}.input-badge-field-wrapper{@apply w-full px-3 py-2 text-sm border rounded-[4px] outline-none transition-colors duration-200 bg-white flex flex-wrap gap-2 items-start;height:40px;box-sizing:border-box;overflow-y:hidden;overflow-x:hidden}.input-badge-field-wrapper--scrollable{overflow-y:auto}.input-badge-field-wrapper--default{@apply border-[#E3E3E7] text-[#141414];}.input-badge-field-wrapper--default:focus-within{@apply border-[#6B7080];}.input-badge-field-wrapper--focused{@apply border-[#6B7080] text-[#141414];}.input-badge-field-wrapper--filled{@apply border-[#E3E3E7] text-[#141414] bg-white;}.input-badge-field-wrapper--filled:focus-within{@apply border-[#6B7080];}.input-badge-field-wrapper--error{@apply border-[#FA727A] text-[#141414];}.input-badge-field-wrapper--disabled{@apply bg-[#F4F4F6] text-[#A1A3AE] border-[#E3E3E7] cursor-not-allowed;}.input-badge-item{@apply inline-flex items-center gap-1 px-2 py-[2.5px] bg-white border border-[#E3E3E7] rounded-[4px];}.input-badge-item-text{@apply text-sm leading-[18px] font-normal text-[#6B7080];}.input-badge-item-close{@apply cursor-pointer outline-none w-3 h-3;}.input-badge-input{@apply flex-1 min-w-[120px] outline-none bg-transparent text-[#141414] placeholder:text-[#6B7080] h-auto;flex-basis:120px}.input-badge-input--default,.input-badge-input--focused,.input-badge-input--filled,.input-badge-input--error{@apply text-[#141414];}.input-badge-input--disabled{@apply text-[#A1A3AE] cursor-not-allowed;}.input-badge-footer{@apply flex justify-between items-start font-normal text-sm;}.input-badge-footer-content{@apply flex-1;}.input-badge-hint{@apply text-xs text-[#868997] font-normal;}.input-badge-error{@apply text-xs text-[#F34050] font-normal;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }] });
3939
+ }
3940
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkChips, decorators: [{
3941
+ type: Component,
3942
+ args: [{ selector: 'bk-chips', standalone: true, imports: [CommonModule, FormsModule], providers: [
3943
+ {
3944
+ provide: NG_VALUE_ACCESSOR,
3945
+ useExisting: forwardRef(() => BkChips),
3946
+ multi: true
3947
+ }
3948
+ ], template: "<div class=\"input-badge-container\">\r\n @if (label) {\r\n <label\r\n [for]=\"id\"\r\n class=\"input-badge-label\">\r\n {{ label }}\r\n @if (required) {\r\n <span class=\"input-badge-label-required\">*</span>\r\n }\r\n </label>\r\n }\r\n\r\n <div class=\"input-badge-wrapper\">\r\n <div\r\n #fieldWrapper\r\n class=\"input-badge-field-wrapper\"\r\n [ngClass]=\"{\r\n 'input-badge-field-wrapper--default': inputState === 'default',\r\n 'input-badge-field-wrapper--focused': inputState === 'focused',\r\n 'input-badge-field-wrapper--filled': inputState === 'filled',\r\n 'input-badge-field-wrapper--error': inputState === 'error',\r\n 'input-badge-field-wrapper--disabled': inputState === 'disabled',\r\n 'input-badge-field-wrapper--scrollable': needsScroll\r\n }\"\r\n (click)=\"focusInput()\"\r\n >\r\n <!-- Badges -->\r\n @for (badge of badges; track badge; let i = $index) {\r\n <div class=\"input-badge-item\">\r\n <span class=\"input-badge-item-text\">{{ badge }}</span>\r\n @if (!disabled) {\r\n <button type=\"button\" (click)=\"removeBadge(i); $event.stopPropagation()\"class=\"input-badge-item-close\" >\r\n <img src=\"../../../../assets/images/icons/global/badge-close.svg\" alt=\"Remove\" class=\"input-badge-item-close-icon\"/>\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Input Field -->\r\n <input\r\n #badgeInput\r\n type=\"text\"\r\n [id]=\"id\"\r\n [name]=\"name\"\r\n [value]=\"inputValue\"\r\n (keydown)=\"onKeyDown($event)\"\r\n (input)=\"handleInput($event)\"\r\n (focus)=\"handleFocus($event)\"\r\n (blur)=\"handleBlur($event)\"\r\n [placeholder]=\"badges.length === 0 ? placeholder : ''\"\r\n [disabled]=\"disabled\"\r\n [readOnly]=\"readOnly\"\r\n class=\"input-badge-input\"\r\n [ngClass]=\"{\r\n 'input-badge-input--default': inputState === 'default',\r\n 'input-badge-input--focused': inputState === 'focused',\r\n 'input-badge-input--filled': inputState === 'filled',\r\n 'input-badge-input--error': inputState === 'error',\r\n 'input-badge-input--disabled': inputState === 'disabled'\r\n }\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <div class=\"input-badge-footer\">\r\n <div class=\"input-badge-footer-content\">\r\n @if (hasError) {\r\n <span class=\"input-badge-error\"> {{ errorMessage }}</span>\r\n } @else if (hint) {\r\n <span class=\"input-badge-hint\"> {{ hint }}</span>\r\n }\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [".input-badge-container{@apply flex flex-col gap-1.5 w-full;}.input-badge-label{@apply text-sm font-medium text-[#141414] block;}.input-badge-label-required{@apply text-[#E7000B] ml-0.5;}.input-badge-wrapper{@apply relative;}.input-badge-field-wrapper{@apply w-full px-3 py-2 text-sm border rounded-[4px] outline-none transition-colors duration-200 bg-white flex flex-wrap gap-2 items-start;height:40px;box-sizing:border-box;overflow-y:hidden;overflow-x:hidden}.input-badge-field-wrapper--scrollable{overflow-y:auto}.input-badge-field-wrapper--default{@apply border-[#E3E3E7] text-[#141414];}.input-badge-field-wrapper--default:focus-within{@apply border-[#6B7080];}.input-badge-field-wrapper--focused{@apply border-[#6B7080] text-[#141414];}.input-badge-field-wrapper--filled{@apply border-[#E3E3E7] text-[#141414] bg-white;}.input-badge-field-wrapper--filled:focus-within{@apply border-[#6B7080];}.input-badge-field-wrapper--error{@apply border-[#FA727A] text-[#141414];}.input-badge-field-wrapper--disabled{@apply bg-[#F4F4F6] text-[#A1A3AE] border-[#E3E3E7] cursor-not-allowed;}.input-badge-item{@apply inline-flex items-center gap-1 px-2 py-[2.5px] bg-white border border-[#E3E3E7] rounded-[4px];}.input-badge-item-text{@apply text-sm leading-[18px] font-normal text-[#6B7080];}.input-badge-item-close{@apply cursor-pointer outline-none w-3 h-3;}.input-badge-input{@apply flex-1 min-w-[120px] outline-none bg-transparent text-[#141414] placeholder:text-[#6B7080] h-auto;flex-basis:120px}.input-badge-input--default,.input-badge-input--focused,.input-badge-input--filled,.input-badge-input--error{@apply text-[#141414];}.input-badge-input--disabled{@apply text-[#A1A3AE] cursor-not-allowed;}.input-badge-footer{@apply flex justify-between items-start font-normal text-sm;}.input-badge-footer-content{@apply flex-1;}.input-badge-hint{@apply text-xs text-[#868997] font-normal;}.input-badge-error{@apply text-xs text-[#F34050] font-normal;}\n"] }]
3949
+ }], propDecorators: { badgeInput: [{
3950
+ type: ViewChild,
3951
+ args: ['badgeInput']
3952
+ }], fieldWrapper: [{
3953
+ type: ViewChild,
3954
+ args: ['fieldWrapper']
3955
+ }], id: [{
3956
+ type: Input
3957
+ }], name: [{
3958
+ type: Input
3959
+ }], label: [{
3960
+ type: Input
3961
+ }], placeholder: [{
3962
+ type: Input
3963
+ }], hint: [{
3964
+ type: Input
3965
+ }], required: [{
3966
+ type: Input
3967
+ }], disabled: [{
3968
+ type: Input
3969
+ }], readOnly: [{
3970
+ type: Input
3971
+ }], hasError: [{
3972
+ type: Input
3973
+ }], errorMessage: [{
3974
+ type: Input
3975
+ }], input: [{
3976
+ type: Output
3977
+ }], change: [{
3978
+ type: Output
3979
+ }], focus: [{
3980
+ type: Output
3981
+ }], blur: [{
3982
+ type: Output
3983
+ }] } });
3984
+
3985
+ class BkTabs {
3986
+ list = [];
3987
+ activeTabId = '';
3988
+ disabled = false;
3989
+ change = new EventEmitter();
3990
+ // Set active tab and emit change event
3991
+ setActiveTab(tab) {
3992
+ debugger;
3993
+ if (tab?.disabled || this.disabled)
3994
+ return;
3995
+ this.activeTabId = tab.id;
3996
+ this.change.emit(tab);
3997
+ }
3998
+ // Check if a tab is active
3999
+ isActive(tabId) {
4000
+ return this.activeTabId === tabId;
4001
+ }
4002
+ // Get the appropriate icon for a tab based on its active state
4003
+ getTabIcon(tab) {
4004
+ if (this.isActive(tab.id) && tab.iconActive) {
4005
+ return tab.iconActive;
4006
+ }
4007
+ return tab.icon;
4008
+ }
4009
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTabs, deps: [], target: i0.ɵɵFactoryTarget.Component });
4010
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkTabs, isStandalone: true, selector: "bk-tabs", inputs: { list: "list", activeTabId: "activeTabId", disabled: "disabled" }, outputs: { change: "change" }, ngImport: i0, template: "<div class=\"tabs-container\">\r\n <ul class=\"tabs-list\" role=\"tablist\">\r\n @for (tab of list; track tab.id; let i = $index) {\r\n <li class=\"tabs-item\" role=\"presentation\">\r\n <button\r\n type=\"button\"\r\n [id]=\"'tab-' + tab.id\"\r\n [attr.aria-selected]=\"isActive(tab.id)\"\r\n [attr.aria-controls]=\"'panel-' + tab.id\"\r\n [disabled]=\"tab.disabled\"\r\n [class.tabs-button--active]=\"isActive(tab.id)\"\r\n [class.tabs-button--disabled]=\"disabled || tab.disabled\"\r\n [class.tabs-button--no-icon]=\"!getTabIcon(tab)\"\r\n class=\"tabs-button\"\r\n (click)=\"setActiveTab(tab)\"\r\n role=\"tab\">\r\n @if (getTabIcon(tab)) {\r\n <img\r\n [src]=\"getTabIcon(tab)\"\r\n [alt]=\"tab.iconAlt || tab.label\"\r\n class=\"tabs-icon\">\r\n }\r\n <span class=\"tabs-label\">{{ tab.label }}</span>\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n</div>\r\n", styles: [".tabs-container{@apply w-full;}.tabs-list{@apply flex gap-2 list-none m-0 p-0;}.tabs-item{@apply flex-shrink-0;}.tabs-button{@apply flex items-center gap-[6px] px-3 py-2 rounded-md border-0 bg-transparent cursor-pointer transition-all duration-200 outline-none;@apply text-sm leading-[11px] font-medium text-[#141414] tracking-[-.28];}.tabs-button--no-icon{@apply gap-0 px-3 py-[10.5px];}.tabs-button--active{@apply bg-[#141414] text-white;}.tabs-button--disabled{@apply opacity-50 cursor-not-allowed;}.tabs-icon{@apply size-4 flex-shrink-0;transition:opacity .2s ease}.tabs-label{@apply whitespace-nowrap;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
4011
+ }
4012
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTabs, decorators: [{
4013
+ type: Component,
4014
+ args: [{ selector: 'bk-tabs', standalone: true, imports: [CommonModule], template: "<div class=\"tabs-container\">\r\n <ul class=\"tabs-list\" role=\"tablist\">\r\n @for (tab of list; track tab.id; let i = $index) {\r\n <li class=\"tabs-item\" role=\"presentation\">\r\n <button\r\n type=\"button\"\r\n [id]=\"'tab-' + tab.id\"\r\n [attr.aria-selected]=\"isActive(tab.id)\"\r\n [attr.aria-controls]=\"'panel-' + tab.id\"\r\n [disabled]=\"tab.disabled\"\r\n [class.tabs-button--active]=\"isActive(tab.id)\"\r\n [class.tabs-button--disabled]=\"disabled || tab.disabled\"\r\n [class.tabs-button--no-icon]=\"!getTabIcon(tab)\"\r\n class=\"tabs-button\"\r\n (click)=\"setActiveTab(tab)\"\r\n role=\"tab\">\r\n @if (getTabIcon(tab)) {\r\n <img\r\n [src]=\"getTabIcon(tab)\"\r\n [alt]=\"tab.iconAlt || tab.label\"\r\n class=\"tabs-icon\">\r\n }\r\n <span class=\"tabs-label\">{{ tab.label }}</span>\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n</div>\r\n", styles: [".tabs-container{@apply w-full;}.tabs-list{@apply flex gap-2 list-none m-0 p-0;}.tabs-item{@apply flex-shrink-0;}.tabs-button{@apply flex items-center gap-[6px] px-3 py-2 rounded-md border-0 bg-transparent cursor-pointer transition-all duration-200 outline-none;@apply text-sm leading-[11px] font-medium text-[#141414] tracking-[-.28];}.tabs-button--no-icon{@apply gap-0 px-3 py-[10.5px];}.tabs-button--active{@apply bg-[#141414] text-white;}.tabs-button--disabled{@apply opacity-50 cursor-not-allowed;}.tabs-icon{@apply size-4 flex-shrink-0;transition:opacity .2s ease}.tabs-label{@apply whitespace-nowrap;}\n"] }]
4015
+ }], propDecorators: { list: [{
4016
+ type: Input
4017
+ }], activeTabId: [{
4018
+ type: Input
4019
+ }], disabled: [{
4020
+ type: Input
4021
+ }], change: [{
4022
+ type: Output
4023
+ }] } });
4024
+
4025
+ /*
4026
+ * Public API Surface of brickclay-lib
4027
+ */
4028
+ //Icons
4029
+
4030
+ /**
4031
+ * Generated bundle index. Do not edit.
4032
+ */
4033
+
4034
+ export { BkBadge, BkButton, BkButtonGroup, BkCheckbox, BkChips, BkCustomCalendar, BkGrid, BkIconButton, BkInput, BkPill, BkRadioButton, BkScheduledDatePicker, BkSelect, BkSpinner, BkTabs, BkTextarea, BkTimePicker, BkToggle, BrickclayIcons, BrickclayLib, CalendarManagerService, CalendarModule };
4035
+ //# sourceMappingURL=brickclay-org-ui.mjs.map