@brickclay-org/ui 0.1.87 → 0.1.88

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,17 +1,17 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Component, EventEmitter, Output, Input, forwardRef, HostListener, ViewChild, Injectable, NgModule, ViewEncapsulation, Optional, Self, Directive, ChangeDetectionStrategy, input, model, output, signal, computed, effect, inject, ElementRef, ViewChildren, InjectionToken, NgZone, ContentChild } from '@angular/core';
2
+ import { Component, EventEmitter, Output, Input, Injectable, forwardRef, ViewChild, NgModule, ViewEncapsulation, Optional, Self, HostListener, Directive, ChangeDetectionStrategy, input, model, output, signal, computed, effect, inject, ElementRef, ViewChildren, InjectionToken, NgZone, ContentChild } from '@angular/core';
3
3
  import * as i1 from '@angular/common';
4
4
  import { CommonModule, NgClass, NgTemplateOutlet } from '@angular/common';
5
- import * as i2 from '@angular/forms';
5
+ import * as i2$1 from '@angular/forms';
6
6
  import { FormsModule, NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms';
7
- import moment from 'moment';
7
+ import * as i2 from '@angular/cdk/overlay';
8
+ import { OverlayModule, Overlay } from '@angular/cdk/overlay';
8
9
  import { Subject, filter } from 'rxjs';
9
- import * as i2$1 from '@angular/cdk/drag-drop';
10
+ import moment from 'moment';
11
+ import * as i3 from '@angular/cdk/drag-drop';
10
12
  import { moveItemInArray, DragDropModule, CdkDragHandle } from '@angular/cdk/drag-drop';
11
- import * as i2$2 from '@angular/cdk/scrolling';
13
+ import * as i1$1 from '@angular/cdk/scrolling';
12
14
  import { ScrollingModule, CdkScrollable, CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
13
- import * as i3 from '@angular/cdk/overlay';
14
- import { OverlayModule, Overlay } from '@angular/cdk/overlay';
15
15
  import { NgxMaskDirective, provideNgxMask } from 'ngx-mask';
16
16
  import { DIALOG_DATA, CdkDialogContainer, Dialog, DialogModule } from '@angular/cdk/dialog';
17
17
  import { CdkPortalOutlet, PortalModule, ComponentPortal } from '@angular/cdk/portal';
@@ -80,8 +80,150 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
80
80
  type: Output
81
81
  }] } });
82
82
 
83
+ class BkCalendarManagerService {
84
+ calendarInstances = new Set();
85
+ /**
86
+ * Separate from {@link calendarInstances} on purpose: a bk-time-picker embedded inside an open
87
+ * bk-custom-calendar (enableTimepicker) must NOT close its own parent calendar when it opens.
88
+ * If time-pickers shared the calendar registry, opening the embedded picker would call
89
+ * closeAllExcept(thatPicker'sCloseFn) — which closes the parent calendar too, since its
90
+ * close-fn is in the same set and isn't the "except" one. Keeping the registries independent
91
+ * means time-pickers only ever coordinate with other time-pickers, calendars only with other
92
+ * calendars — each family closes its own siblings, never the other family.
93
+ */
94
+ timePickerInstances = new Set();
95
+ closeAllSubject = new Subject();
96
+ closeAll$ = this.closeAllSubject.asObservable();
97
+ customRanges = {};
98
+ rangeOrder = [];
99
+ constructor() {
100
+ this.initializeDefaultRanges();
101
+ }
102
+ /**
103
+ * Returns service-defined custom ranges and their display order.
104
+ * Used when the calendar does not pass customRanges via @Input().
105
+ */
106
+ getCustomRanges() {
107
+ this.initializeDefaultRanges();
108
+ return {
109
+ customRanges: { ...this.customRanges },
110
+ rangeOrder: [...this.rangeOrder],
111
+ };
112
+ }
113
+ initializeDefaultRanges() {
114
+ const today = new Date();
115
+ this.customRanges = {
116
+ Today: {
117
+ start: new Date(today.getFullYear(), today.getMonth(), today.getDate()),
118
+ end: new Date(today.getFullYear(), today.getMonth(), today.getDate()),
119
+ },
120
+ Yesterday: {
121
+ start: this.addDays(today, -1),
122
+ end: this.addDays(today, -1),
123
+ },
124
+ 'Last 7 Days': {
125
+ start: this.addDays(today, -6),
126
+ end: today,
127
+ },
128
+ 'Last 30 Days': {
129
+ start: this.addDays(today, -29),
130
+ end: today,
131
+ },
132
+ 'This Month': {
133
+ start: new Date(today.getFullYear(), today.getMonth(), 1),
134
+ end: new Date(today.getFullYear(), today.getMonth() + 1, 0),
135
+ },
136
+ 'Last Month': {
137
+ start: new Date(today.getFullYear(), today.getMonth() - 1, 1),
138
+ end: new Date(today.getFullYear(), today.getMonth(), 0),
139
+ },
140
+ 'Custom Range': {
141
+ start: new Date(),
142
+ end: new Date(),
143
+ },
144
+ };
145
+ this.rangeOrder = [
146
+ 'Today',
147
+ 'Yesterday',
148
+ 'Last 7 Days',
149
+ 'Last 30 Days',
150
+ 'This Month',
151
+ 'Last Month',
152
+ 'Custom Range',
153
+ ];
154
+ }
155
+ addDays(date, days) {
156
+ const d = new Date(date);
157
+ d.setDate(d.getDate() + days);
158
+ return d;
159
+ }
160
+ /**
161
+ * Register a calendar instance with its close function
162
+ */
163
+ register(closeFn) {
164
+ this.calendarInstances.add(closeFn);
165
+ // Return unregister function
166
+ return () => {
167
+ this.calendarInstances.delete(closeFn);
168
+ };
169
+ }
170
+ /**
171
+ * Close all calendars except the one being opened
172
+ */
173
+ closeAllExcept(exceptCloseFn) {
174
+ this.calendarInstances.forEach(closeFn => {
175
+ if (closeFn !== exceptCloseFn) {
176
+ closeFn();
177
+ }
178
+ });
179
+ }
180
+ /**
181
+ * Register a time-picker instance with its close function — separate registry from calendars,
182
+ * see {@link timePickerInstances}.
183
+ */
184
+ registerTimePicker(closeFn) {
185
+ this.timePickerInstances.add(closeFn);
186
+ return () => {
187
+ this.timePickerInstances.delete(closeFn);
188
+ };
189
+ }
190
+ /**
191
+ * Close all time-pickers except the one being opened. Never touches calendarInstances — see
192
+ * {@link timePickerInstances}.
193
+ */
194
+ closeAllTimePickersExcept(exceptCloseFn) {
195
+ this.timePickerInstances.forEach(closeFn => {
196
+ if (closeFn !== exceptCloseFn) {
197
+ closeFn();
198
+ }
199
+ });
200
+ }
201
+ /**
202
+ * Close all calendars
203
+ */
204
+ closeAll() {
205
+ this.closeAllSubject.next();
206
+ this.calendarInstances.forEach(closeFn => closeFn());
207
+ }
208
+ getOnlyDate(input) {
209
+ const date = new Date(input);
210
+ const year = date.getFullYear();
211
+ const month = (date.getMonth() + 1).toString().padStart(2, '0');
212
+ const day = date.getDate().toString().padStart(2, '0');
213
+ return `${year}-${month}-${day}`;
214
+ }
215
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkCalendarManagerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
216
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkCalendarManagerService, providedIn: 'root' });
217
+ }
218
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkCalendarManagerService, decorators: [{
219
+ type: Injectable,
220
+ args: [{
221
+ providedIn: 'root'
222
+ }]
223
+ }], ctorParameters: () => [] });
224
+
83
225
  class BkTimePicker {
84
- renderer;
226
+ calendarManager;
85
227
  required = false;
86
228
  /** @deprecated Prefer [(ngModel)] */
87
229
  value = null;
@@ -94,11 +236,30 @@ class BkTimePicker {
94
236
  closePicker = 0;
95
237
  timeFormat = 12;
96
238
  showSeconds = false;
97
- /** When true, auto-flip the dropdown above/below and left/right based on available viewport space. */
239
+ /**
240
+ * When true, offers a flipped-above fallback if there isn't room below the trigger (CDK only
241
+ * uses it when the preferred side genuinely doesn't fit). When false, the dropdown always opens
242
+ * below, never flipping — matches this input's original (pre-CDK) semantics.
243
+ */
98
244
  autoPosition = false;
99
- /** When true, position the dropdown with `fixed` so it escapes ancestor overflow (dialogs, scroll containers),
100
- * follows the trigger on scroll, and closes when the trigger is scrolled out of view. */
245
+ /**
246
+ * @deprecated No-op, kept only so existing `[appendToBody]="true"` bindings don't break. The
247
+ * dropdown now always positions via Angular CDK Overlay, which portals into the shared
248
+ * `cdk-overlay-container` unconditionally — the exact clipping/stacking escape this input used
249
+ * to opt into by hand is now the only behaviour there is. Safe to remove from call sites.
250
+ */
101
251
  appendToBody = false;
252
+ /**
253
+ * Extra px CDK keeps clear of the viewport edges when flipping/pushing the dropdown. Same fix,
254
+ * same reasoning, as `bk-popover.viewportMargin` / `bk-custom-calendar.viewportMargin`.
255
+ */
256
+ viewportMargin = 0;
257
+ /**
258
+ * Classes applied to the CDK overlay pane (`cdkConnectedOverlayPanelClass`). z-index overrides
259
+ * MUST go here — the pane already establishes its own stacking context once portalled. Same
260
+ * convention as `bk-popover.panelClass` / `bk-custom-calendar.panelClass`.
261
+ */
262
+ panelClass = '';
102
263
  change = new EventEmitter();
103
264
  timeChange = new EventEmitter();
104
265
  pickerOpened = new EventEmitter();
@@ -109,14 +270,38 @@ class BkTimePicker {
109
270
  hourScrollEl;
110
271
  minuteScrollEl;
111
272
  secondScrollEl;
112
- /** The positioned trigger (its rect anchors the dropdown). */
273
+ /** The trigger — also the CDK connected-overlay origin (see #tpOrigin in the template). */
113
274
  tpWrapper;
114
- /** The dropdown panel element (measured for flip decisions). */
115
- tpDropdown;
116
- /** Resolved placement state, driven by updatePosition(). */
275
+ tpOverlay;
276
+ /** Resolved from CDK's (positionChange); drives the CSS flip-direction class. */
117
277
  placeAbove = false;
118
- resolvedPosition = 'left';
119
- dropdownStyle = {};
278
+ /**
279
+ * CDK connected-overlay positions for the current open. Rebuilt each time the dropdown opens
280
+ * (see {@link togglePicker}) from `position` (horizontal side, fixed — never flips; CDK's push,
281
+ * always on, handles keeping it on-screen instead, same approach `bk-popover`/
282
+ * `bk-custom-calendar` use for their own horizontal axis) and `autoPosition` (whether a flipped
283
+ * vertical fallback is offered at all — matches this input's original semantics exactly).
284
+ */
285
+ pickerPositions = [];
286
+ /** Tags each entry in {@link pickerPositions} with whether it places the dropdown above the
287
+ * trigger, so `onPositionChange` can read back which one CDK actually used. Matched by field
288
+ * value, not object identity — CDK reconstructs its own ConnectedPosition objects internally. */
289
+ positionMeta = [];
290
+ buildVerticalPosition(above, gap) {
291
+ const side = this.position === 'right' ? 'end' : 'start';
292
+ return above
293
+ ? { pos: { originX: side, originY: 'top', overlayX: side, overlayY: 'bottom', offsetY: -gap }, above: true }
294
+ : { pos: { originX: side, originY: 'bottom', overlayX: side, overlayY: 'top', offsetY: gap }, above: false };
295
+ }
296
+ /** (Re)computes {@link pickerPositions}: always tries `position`'s side below the trigger first;
297
+ * `autoPosition` additionally offers the same side flipped above as a fallback CDK only falls
298
+ * back to when below genuinely doesn't fit. */
299
+ computePickerPositions() {
300
+ const gap = 4;
301
+ const primary = this.buildVerticalPosition(false, gap);
302
+ this.positionMeta = this.autoPosition ? [primary, this.buildVerticalPosition(true, gap)] : [primary];
303
+ this.pickerPositions = this.positionMeta.map(e => e.pos);
304
+ }
120
305
  /** Row height in px. MUST match the .time-item height in CSS for the active variation. */
121
306
  get ITEM_HEIGHT() {
122
307
  return this.variation === 'lg' ? 32 : 28;
@@ -139,40 +324,6 @@ class BkTimePicker {
139
324
  activeSecond = 0;
140
325
  _modelValue = null;
141
326
  brickclayIcons = BrickclayIcons;
142
- constructor(renderer) {
143
- this.renderer = renderer;
144
- }
145
- /* ---------------- appendToBody dropdown relocation ---------------- */
146
- /**
147
- * `appendToBody` anchors the dropdown with `position: fixed`, which only tracks the viewport when
148
- * NO ancestor establishes a containing block (transform / filter / perspective / will-change /
149
- * contain / backdrop-filter). Inside such an ancestor the fixed coordinates resolve against that
150
- * ancestor instead and the dropdown drifts off-position. To be robust we physically move the panel
151
- * to <body> while open (Angular keeps managing it by reference) and move it back before *ngIf
152
- * tears it down. The panel carries a `tp-compact` self-class so its `default`-variation sizing —
153
- * otherwise scoped under the `.time-input-group.default` ancestor it just left — still applies.
154
- */
155
- dropdownMovedToBody = false;
156
- dropdownOriginalParent = null;
157
- moveDropdownToBody() {
158
- const el = this.tpDropdown?.nativeElement;
159
- if (!el || this.dropdownMovedToBody)
160
- return;
161
- this.dropdownOriginalParent = el.parentElement;
162
- this.renderer.appendChild(document.body, el);
163
- this.dropdownMovedToBody = true;
164
- }
165
- /** Return the dropdown to its original slot so *ngIf can destroy it cleanly (safe to call twice). */
166
- restoreDropdownFromBody() {
167
- if (!this.dropdownMovedToBody)
168
- return;
169
- const el = this.tpDropdown?.nativeElement;
170
- if (el && this.dropdownOriginalParent) {
171
- this.renderer.appendChild(this.dropdownOriginalParent, el);
172
- }
173
- this.dropdownMovedToBody = false;
174
- this.dropdownOriginalParent = null;
175
- }
176
327
  /* ---------------- CVA ---------------- */
177
328
  writeValue(value) {
178
329
  if (!value) {
@@ -228,13 +379,28 @@ class BkTimePicker {
228
379
  markAsTouched() {
229
380
  this.onTouched();
230
381
  }
382
+ constructor(calendarManager) {
383
+ this.calendarManager = calendarManager;
384
+ }
385
+ closeFn;
386
+ unregisterFn;
231
387
  /* ---------------- Lifecycle ---------------- */
232
388
  ngOnInit() {
233
389
  this.parseTimeValue(this._modelValue ?? this.value);
390
+ // Registers this picker so opening any other bk-time-picker on the page (standalone in a
391
+ // form, or another one embedded in a different calendar) closes this one first — the gap
392
+ // that let two independent time-pickers stay open simultaneously. Deliberately a separate
393
+ // registry from calendars (see BkCalendarManagerService.timePickerInstances) so this never
394
+ // closes a parent bk-custom-calendar this picker happens to be embedded inside.
395
+ this.closeFn = () => {
396
+ if (this.showPicker)
397
+ this.dismiss();
398
+ };
399
+ this.unregisterFn = this.calendarManager.registerTimePicker(this.closeFn);
234
400
  }
235
401
  ngAfterViewInit() {
236
402
  if (this.showPicker) {
237
- setTimeout(() => this.scrollToSelectedTimes(), 100);
403
+ this.scheduleScrollToSelectedTimes();
238
404
  }
239
405
  }
240
406
  ngOnChanges(changes) {
@@ -319,40 +485,120 @@ class BkTimePicker {
319
485
  : `${hour}:${mStr} ${ampm}`;
320
486
  }
321
487
  /* ---------------- Picker ---------------- */
488
+ /** True while the trigger input itself has DOM focus — see onTriggerMouseDown for why this is
489
+ * tracked (same reasoning as bk-custom-calendar's triggerHasFocus). */
490
+ triggerHasFocus = false;
491
+ /** Opens the dropdown as soon as the trigger input receives focus — including via Tab, not
492
+ * just a click. Guarded on `!this.showPicker` so it's a no-op if already open. */
493
+ onTriggerFocus() {
494
+ this.triggerHasFocus = true;
495
+ if (this.disabled)
496
+ return;
497
+ if (!this.showPicker)
498
+ this.togglePicker();
499
+ }
500
+ /** Pairs with (blur) — keeps triggerHasFocus in sync alongside the pre-existing
501
+ * markAsTouched() call this replaces inline. */
502
+ onTriggerBlur() {
503
+ this.triggerHasFocus = false;
504
+ this.markAsTouched();
505
+ }
506
+ /**
507
+ * `mousedown` (not `click`) so this cooperates with {@link onTriggerFocus} instead of racing
508
+ * it — same pattern and reasoning as bk-custom-calendar's onTriggerMouseDown: not-yet-focused
509
+ * clicks are left to the default focus shift (which opens via onTriggerFocus); an
510
+ * already-focused click means close (or, if somehow already focused but closed, open — `focus`
511
+ * won't re-fire without an actual focus change).
512
+ */
513
+ onTriggerMouseDown(event) {
514
+ if (this.disabled)
515
+ return;
516
+ if (this.showPicker) {
517
+ event.preventDefault();
518
+ this.togglePicker();
519
+ }
520
+ else if (this.triggerHasFocus) {
521
+ event.preventDefault();
522
+ this.togglePicker();
523
+ }
524
+ }
525
+ /**
526
+ * Opens the dropdown from the keyboard once the trigger input has focus — Enter, Space, or
527
+ * ArrowDown, the standard combobox/datepicker open keys. Focus alone already opens it (see
528
+ * onTriggerFocus); this mainly matters if focus is regained without opening for some other
529
+ * reason.
530
+ */
531
+ onTriggerKeydownOpen(event) {
532
+ event.preventDefault();
533
+ if (this.disabled)
534
+ return;
535
+ if (!this.showPicker)
536
+ this.togglePicker();
537
+ }
322
538
  togglePicker() {
323
539
  if (!this.showPicker) {
540
+ // Close any other open time-picker first — the shared registry (see registerTimePicker
541
+ // in ngOnInit) is scoped to time-pickers only, so this never closes a parent calendar this
542
+ // one might be embedded inside.
543
+ if (this.closeFn)
544
+ this.calendarManager.closeAllTimePickersExcept(this.closeFn);
324
545
  this.showPicker = true;
325
546
  this.parseTimeValue(this._modelValue);
547
+ this.computePickerPositions();
548
+ this.attachViewportListeners();
326
549
  this.pickerOpened.emit(this.pickerId);
327
- if (this.autoPosition || this.appendToBody) {
328
- this.attachViewportListeners();
329
- // Measure once the dropdown is in the DOM, before it becomes visible to the user.
330
- setTimeout(() => {
331
- // Relocate to <body> first so no transformed/overflow ancestor can re-anchor the fixed
332
- // dropdown, then compute viewport coordinates.
333
- if (this.appendToBody)
334
- this.moveDropdownToBody();
335
- this.updatePosition();
336
- }, 0);
337
- }
338
- setTimeout(() => this.scrollToSelectedTimes(), 100);
550
+ this.scheduleScrollToSelectedTimes();
339
551
  }
340
552
  else {
341
553
  this.dismiss();
342
554
  }
343
555
  }
344
- /** Central close path so listeners are always detached and events emitted once. */
556
+ /** Central close path so listeners are always detached and events emitted once. Not private:
557
+ * the template's own (detach) binding on cdkConnectedOverlay calls it directly. */
345
558
  dismiss() {
346
559
  if (!this.showPicker)
347
560
  return;
348
- // Put the dropdown back before showPicker=false so *ngIf removes it from the right parent on the
349
- // next change-detection pass (avoids leaving an orphan node in <body>).
350
- this.restoreDropdownFromBody();
351
- this.showPicker = false;
352
561
  this.detachViewportListeners();
562
+ this.clearScrollTimers();
563
+ // CDK's cdkConnectedOverlayOpen="showPicker" binding (see template) detaches the overlay once
564
+ // this flips false — no manual DOM teardown needed.
565
+ this.showPicker = false;
353
566
  this.markAsTouched();
354
567
  this.pickerClosed.emit(this.pickerId);
355
568
  }
569
+ /** Cancels every pending scroll-related timer/rAF (deferred open-scroll, snap-settle debounce,
570
+ * active-highlight rAF throttle) so none of them fire against a picker that has since closed
571
+ * or been destroyed. */
572
+ clearScrollTimers() {
573
+ if (this.scrollToSelectedTimeoutId != null) {
574
+ clearTimeout(this.scrollToSelectedTimeoutId);
575
+ this.scrollToSelectedTimeoutId = null;
576
+ }
577
+ if (this.hourSnapTimeoutId != null) {
578
+ clearTimeout(this.hourSnapTimeoutId);
579
+ this.hourSnapTimeoutId = null;
580
+ }
581
+ if (this.minuteSnapTimeoutId != null) {
582
+ clearTimeout(this.minuteSnapTimeoutId);
583
+ this.minuteSnapTimeoutId = null;
584
+ }
585
+ if (this.secondSnapTimeoutId != null) {
586
+ clearTimeout(this.secondSnapTimeoutId);
587
+ this.secondSnapTimeoutId = null;
588
+ }
589
+ if (this.hourScrollRafId != null) {
590
+ cancelAnimationFrame(this.hourScrollRafId);
591
+ this.hourScrollRafId = null;
592
+ }
593
+ if (this.minuteScrollRafId != null) {
594
+ cancelAnimationFrame(this.minuteScrollRafId);
595
+ this.minuteScrollRafId = null;
596
+ }
597
+ if (this.secondScrollRafId != null) {
598
+ cancelAnimationFrame(this.secondScrollRafId);
599
+ this.secondScrollRafId = null;
600
+ }
601
+ }
356
602
  /* ---------------- Change handlers ---------------- */
357
603
  onHourChange(hour) {
358
604
  this.currentHour = hour;
@@ -382,6 +628,18 @@ class BkTimePicker {
382
628
  this.timeChange.emit(newTime);
383
629
  }
384
630
  /* ---------------- Scroll ---------------- */
631
+ /** Defers scrollToSelectedTimes() until the just-opened overlay's columns have rendered.
632
+ * Clears any previously pending call first, so opening/closing/reopening in quick succession
633
+ * can never stack more than one pending scroll (each would otherwise reset the columns to the
634
+ * committed value, undoing any scrolling the user did in between). */
635
+ scheduleScrollToSelectedTimes() {
636
+ if (this.scrollToSelectedTimeoutId != null)
637
+ clearTimeout(this.scrollToSelectedTimeoutId);
638
+ this.scrollToSelectedTimeoutId = setTimeout(() => {
639
+ this.scrollToSelectedTimeoutId = null;
640
+ this.scrollToSelectedTimes();
641
+ }, 100);
642
+ }
385
643
  /** Position each column so the committed value sits at the top of its viewport. */
386
644
  scrollToSelectedTimes() {
387
645
  this.scrollColumnTo(this.hourScrollEl, this.getHours().indexOf(this.currentHour));
@@ -407,19 +665,31 @@ class BkTimePicker {
407
665
  return Math.min(Math.max(index, 0), count - 1);
408
666
  }
409
667
  /* ---------------- Outside click ---------------- */
410
- onDocumentClick(event) {
411
- if (!this.showPicker)
412
- return;
413
- const target = event.target;
414
- // When appendToBody has relocated the dropdown to <body>, it is no longer inside
415
- // .time-picker-wrapper, so also treat clicks within the dropdown itself as "inside".
416
- const dropdownEl = this.tpDropdown?.nativeElement;
417
- const insideDropdown = !!dropdownEl && (dropdownEl === target || dropdownEl.contains(target));
418
- if (!target.closest('.time-picker-wrapper') && !insideDropdown) {
419
- this.dismiss();
420
- }
668
+ /** CDK's overlay origin already excludes clicks on the trigger from outside-click dispatch by
669
+ * design (same note in bk-popover/bk-custom-calendar's onOverlayOutsideClick), so the input's
670
+ * own (click)="togglePicker()" stays the sole opener/closer via the trigger. */
671
+ onOverlayOutsideClick() {
672
+ this.dismiss();
421
673
  }
422
674
  previousCloseCounter = 0;
675
+ /** Handle for the deferred scrollToSelectedTimes() (see togglePicker/ngAfterViewInit). Stored
676
+ * so a stale timer never fires after the picker has already closed, and so opening/closing in
677
+ * quick succession never stacks more than one pending call. */
678
+ scrollToSelectedTimeoutId = null;
679
+ /** rAF handles throttling the active-highlight update to at most once per frame during fast
680
+ * wheel/trackpad scrolling — same pattern as {@link onViewportChange}. Without this, a scroll
681
+ * event firing many times per frame drove Angular change detection just as often, which is
682
+ * what made the wheel feel like it was "sticking" during a fast scroll. */
683
+ hourScrollRafId = null;
684
+ minuteScrollRafId = null;
685
+ secondScrollRafId = null;
686
+ /** Debounce handles for {@link settleColumn} — row-boundary snapping now happens in JS, only
687
+ * once scrolling has actually stopped, instead of via CSS scroll-snap-type. CSS snapping on a
688
+ * list this short fights real-time mouse-wheel input in Chrome/Windows (the browser re-snaps
689
+ * after every wheel tick), which is what actually caused the "gets stuck" symptom. */
690
+ hourSnapTimeoutId = null;
691
+ minuteSnapTimeoutId = null;
692
+ secondSnapTimeoutId = null;
423
693
  getHours() {
424
694
  if (this.timeFormat === 24) {
425
695
  return Array.from({ length: 24 }, (_, i) => i);
@@ -429,86 +699,85 @@ class BkTimePicker {
429
699
  getAMPMOptions() {
430
700
  return ['PM', 'AM'];
431
701
  }
432
- // Scrolling any column only moves its highlight; the value is committed on click.
702
+ // Scrolling any column only moves its highlight; the value is committed on click. Each handler
703
+ // does two things, both throttled/debounced so a fast wheel/trackpad scroll can't fire Angular
704
+ // change detection or a snap-back on every single scroll event:
705
+ // 1. Update the active highlight, at most once per animation frame (rAF-gated).
706
+ // 2. Schedule a row-boundary "settle" once scrolling has actually stopped (debounced) — the
707
+ // JS replacement for CSS scroll-snap-type; see settleColumn() and the .time-scroll CSS
708
+ // comment for why CSS snapping was removed.
433
709
  onHourScroll() {
434
- const idx = this.scrollIndex(this.hourScrollEl, this.getHours().length);
435
- if (idx < 0)
436
- return;
437
- this.activeHour = this.getHours()[idx];
710
+ if (this.hourScrollRafId == null) {
711
+ this.hourScrollRafId = requestAnimationFrame(() => {
712
+ this.hourScrollRafId = null;
713
+ const idx = this.scrollIndex(this.hourScrollEl, this.getHours().length);
714
+ if (idx < 0)
715
+ return;
716
+ this.activeHour = this.getHours()[idx];
717
+ });
718
+ }
719
+ this.scheduleSnapSettle('hour');
438
720
  }
439
721
  onMinuteScroll() {
440
- const idx = this.scrollIndex(this.minuteScrollEl, this.minutes.length);
441
- if (idx < 0)
442
- return;
443
- this.activeMinute = idx;
722
+ if (this.minuteScrollRafId == null) {
723
+ this.minuteScrollRafId = requestAnimationFrame(() => {
724
+ this.minuteScrollRafId = null;
725
+ const idx = this.scrollIndex(this.minuteScrollEl, this.minutes.length);
726
+ if (idx < 0)
727
+ return;
728
+ this.activeMinute = idx;
729
+ });
730
+ }
731
+ this.scheduleSnapSettle('minute');
444
732
  }
445
733
  onSecondScroll() {
446
- const idx = this.scrollIndex(this.secondScrollEl, this.seconds.length);
734
+ if (this.secondScrollRafId == null) {
735
+ this.secondScrollRafId = requestAnimationFrame(() => {
736
+ this.secondScrollRafId = null;
737
+ const idx = this.scrollIndex(this.secondScrollEl, this.seconds.length);
738
+ if (idx < 0)
739
+ return;
740
+ this.activeSecond = idx;
741
+ });
742
+ }
743
+ this.scheduleSnapSettle('second');
744
+ }
745
+ /** Debounces settleColumn() to 120ms after the last scroll event on that column — i.e. it only
746
+ * runs once the user has actually stopped scrolling, never mid-gesture. */
747
+ scheduleSnapSettle(column) {
748
+ const idField = column === 'hour' ? 'hourSnapTimeoutId'
749
+ : column === 'minute' ? 'minuteSnapTimeoutId'
750
+ : 'secondSnapTimeoutId';
751
+ const existing = this[idField];
752
+ if (existing != null)
753
+ clearTimeout(existing);
754
+ this[idField] = setTimeout(() => {
755
+ this[idField] = null;
756
+ this.settleColumn(column);
757
+ }, 120);
758
+ }
759
+ /** Snaps a column to the row boundary nearest its current scroll position — the JS equivalent
760
+ * of what `scroll-snap-align: center` used to do, minus the mouse-wheel "stuck" bug that came
761
+ * with doing it via CSS on a list this short (see .time-scroll's CSS comment). */
762
+ settleColumn(column) {
763
+ const ref = column === 'hour' ? this.hourScrollEl
764
+ : column === 'minute' ? this.minuteScrollEl
765
+ : this.secondScrollEl;
766
+ const count = column === 'hour' ? this.getHours().length
767
+ : column === 'minute' ? this.minutes.length
768
+ : this.seconds.length;
769
+ const idx = this.scrollIndex(ref, count);
447
770
  if (idx < 0)
448
771
  return;
449
- this.activeSecond = idx;
772
+ this.scrollColumnTo(ref, idx);
450
773
  }
451
- /* ---------------- Overlay positioning (auto-flip / appendToBody) ---------------- */
452
- /**
453
- * Resolve the dropdown placement against the current viewport.
454
- * - autoPosition: flip above when there isn't room below, and flip the horizontal
455
- * side when the preferred side would overflow.
456
- * - appendToBody: additionally anchor with `position: fixed` (inline style) so the
457
- * dropdown escapes ancestor overflow and follows the trigger on scroll.
458
- */
459
- updatePosition() {
460
- if (!this.showPicker)
461
- return;
462
- const trigger = this.tpWrapper?.nativeElement;
463
- const dropdown = this.tpDropdown?.nativeElement;
464
- if (!trigger || !dropdown)
465
- return;
466
- const rect = trigger.getBoundingClientRect();
467
- const height = dropdown.offsetHeight || 140;
468
- const width = dropdown.offsetWidth || 182;
469
- const margin = 8;
470
- const gap = 4;
471
- // Vertical: flip above only when there isn't enough room below and there's more room above.
472
- const spaceBelow = window.innerHeight - rect.bottom;
473
- const spaceAbove = rect.top;
474
- this.placeAbove =
475
- this.autoPosition && spaceBelow < height + margin && spaceAbove > spaceBelow;
476
- // Horizontal: start from the requested side, flip if it would overflow that edge.
477
- const viewportW = window.innerWidth;
478
- let side = this.position;
479
- if (this.autoPosition) {
480
- if (side === 'left' && rect.left + width > viewportW - margin)
481
- side = 'right';
482
- else if (side === 'right' && rect.right - width < margin)
483
- side = 'left';
484
- }
485
- this.resolvedPosition = side;
486
- if (this.appendToBody) {
487
- let left = side === 'right' ? rect.right - width : rect.left;
488
- // Clamp so it never leaves the viewport, regardless of the flip decision above.
489
- left = Math.min(left, viewportW - width - margin);
490
- left = Math.max(left, margin);
491
- this.dropdownStyle = this.placeAbove
492
- ? {
493
- position: 'fixed',
494
- top: 'auto',
495
- bottom: `${window.innerHeight - rect.top + gap}px`,
496
- left: `${left}px`,
497
- right: 'auto',
498
- 'z-index': '100000',
499
- }
500
- : {
501
- position: 'fixed',
502
- top: `${rect.bottom + gap}px`,
503
- left: `${left}px`,
504
- right: 'auto',
505
- 'z-index': '100000',
506
- };
507
- }
508
- else {
509
- // Non-appendToBody stays absolute; placement is driven by CSS classes only.
510
- this.dropdownStyle = {};
511
- }
774
+ /* ---------------- Overlay positioning ---------------- */
775
+ /** Fires whenever CDK (re)applies a position, including the first one after open. Reads back
776
+ * which of `positionMeta`'s tagged entries CDK actually used, to drive the CSS flip-direction
777
+ * class the same value the old manual updatePosition() used to. */
778
+ onPositionChange(event) {
779
+ const match = this.positionMeta.find(e => positionsEqual$2(e.pos, event.connectionPair));
780
+ this.placeAbove = match?.above ?? false;
512
781
  }
513
782
  viewportListenersAttached = false;
514
783
  viewportRafId = null;
@@ -520,19 +789,23 @@ class BkTimePicker {
520
789
  this.handleViewportChange();
521
790
  });
522
791
  };
792
+ /**
793
+ * CDK's own scroll strategy only reacts to real `document`/`window` scroll — it has no way to
794
+ * know an app shell might scroll a nested container instead. A capture-phase listener on
795
+ * `document` still sees scroll events fired on any descendant scrollable element (scroll
796
+ * doesn't bubble, but capture does) — the same trick `bk-custom-calendar` uses. Throttled
797
+ * through requestAnimationFrame to avoid layout thrash during fast scrolling.
798
+ */
523
799
  handleViewportChange() {
524
800
  if (!this.showPicker)
525
801
  return;
526
- if (this.appendToBody) {
527
- const rect = this.tpWrapper?.nativeElement?.getBoundingClientRect();
528
- if (!rect)
529
- return;
530
- if (this.isTriggerOutOfView(rect)) {
531
- this.dismiss();
532
- return;
533
- }
802
+ const rect = this.tpWrapper?.nativeElement?.getBoundingClientRect();
803
+ if (rect && this.isTriggerOutOfView(rect)) {
804
+ this.dismiss();
805
+ return;
534
806
  }
535
- this.updatePosition();
807
+ // Re-run CDK's own flip/push so the dropdown follows the trigger.
808
+ this.tpOverlay?.overlayRef?.updatePosition();
536
809
  }
537
810
  /** True when the trigger has scrolled out of the viewport or out of any clipping ancestor. */
538
811
  isTriggerOutOfView(rect) {
@@ -576,30 +849,32 @@ class BkTimePicker {
576
849
  }
577
850
  }
578
851
  ngOnDestroy() {
852
+ // Ensure global scroll/resize listeners never outlive the component
579
853
  this.detachViewportListeners();
580
- // If destroyed while open with the dropdown relocated to <body>, put it back so Angular's
581
- // teardown removes it from the expected parent instead of leaving an orphan node in <body>.
582
- this.restoreDropdownFromBody();
854
+ // Ensure no deferred scroll timer/rAF outlives the component either
855
+ this.clearScrollTimers();
856
+ // Unregister this picker so a stale closure isn't kept alive in the shared registry
857
+ this.unregisterFn?.();
583
858
  }
584
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTimePicker, deps: [{ token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component });
585
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkTimePicker, isStandalone: true, selector: "bk-time-picker", inputs: { required: "required", value: "value", label: "label", placeholder: "placeholder", clearable: "clearable", position: "position", variation: "variation", pickerId: "pickerId", closePicker: "closePicker", timeFormat: "timeFormat", showSeconds: "showSeconds", autoPosition: "autoPosition", appendToBody: "appendToBody", disabled: "disabled" }, outputs: { change: "change", timeChange: "timeChange", pickerOpened: "pickerOpened", pickerClosed: "pickerClosed" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, providers: [
859
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTimePicker, deps: [{ token: BkCalendarManagerService }], target: i0.ɵɵFactoryTarget.Component });
860
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkTimePicker, isStandalone: true, selector: "bk-time-picker", inputs: { required: "required", value: "value", label: "label", placeholder: "placeholder", clearable: "clearable", position: "position", variation: "variation", pickerId: "pickerId", closePicker: "closePicker", timeFormat: "timeFormat", showSeconds: "showSeconds", autoPosition: "autoPosition", appendToBody: "appendToBody", viewportMargin: "viewportMargin", panelClass: "panelClass", disabled: "disabled" }, outputs: { change: "change", timeChange: "timeChange", pickerOpened: "pickerOpened", pickerClosed: "pickerClosed" }, providers: [
586
861
  {
587
862
  provide: NG_VALUE_ACCESSOR,
588
863
  useExisting: forwardRef(() => BkTimePicker),
589
864
  multi: true,
590
865
  },
591
- ], viewQueries: [{ propertyName: "hourScrollEl", first: true, predicate: ["hourScroll"], descendants: true }, { propertyName: "minuteScrollEl", first: true, predicate: ["minuteScroll"], descendants: true }, { propertyName: "secondScrollEl", first: true, predicate: ["secondScroll"], descendants: true }, { propertyName: "tpWrapper", first: true, predicate: ["tpWrapper"], descendants: true }, { propertyName: "tpDropdown", first: true, predicate: ["tpDropdown"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"time-picker-wrapper\">\r\n <div class=\"time-input-group\" [ngClass]=\"variation\">\r\n @if (label) {\r\n <label>{{ label }}</label>\r\n }\r\n <div class=\"time-input-wrapper\" [class.has-value]=\"hasValue\" #tpWrapper>\r\n <input\r\n type=\"text\"\r\n class=\"time-input\"\r\n [value]=\"getDisplayValue()\"\r\n [placeholder]=\"placeholder\"\r\n [disabled]=\"disabled ? true : null\"\r\n readonly\r\n (click)=\"!disabled && togglePicker()\"\r\n (blur)=\"markAsTouched()\"\r\n />\r\n <span class=\"time-icon\">\r\n <img alt=\"timer\" class=\"timer-icon\" [src]=\"brickclayIcons.timerIcon\" />\r\n </span>\r\n <button\r\n type=\"button\"\r\n class=\"time-clear-btn\"\r\n *ngIf=\"clearable && hasValue && !disabled\"\r\n (click)=\"clear(); $event.stopPropagation()\"\r\n title=\"Clear time\"\r\n aria-label=\"Clear time\"\r\n >\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"14\"\r\n height=\"14\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n >\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 <div class=\"custom-time-picker-dropdown\" *ngIf=\"showPicker\">\r\n <div\r\n #tpDropdown\r\n class=\"custom-time-picker\"\r\n [ngStyle]=\"dropdownStyle\"\r\n [class.tp-above]=\"placeAbove\"\r\n [class.append-to-body]=\"appendToBody\"\r\n [ngClass]=\"{\r\n 'left-position': resolvedPosition === 'left',\r\n 'right-position': resolvedPosition === 'right',\r\n 'format-24': timeFormat === 24,\r\n 'tp-compact': variation === 'default',\r\n }\"\r\n >\r\n <!-- Hours Column (finite list, no loop) -->\r\n <div class=\"time-column\">\r\n <div class=\"time-scroll\" #hourScroll (scroll)=\"onHourScroll()\">\r\n <div\r\n *ngFor=\"let h of getHours()\"\r\n class=\"time-item\"\r\n [class.selected]=\"currentHour === h\"\r\n [class.active]=\"activeHour === h\"\r\n (click)=\"onHourChange(h)\"\r\n >\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 (finite list, no loop) -->\r\n <div class=\"time-column\">\r\n <div class=\"time-scroll\" #minuteScroll (scroll)=\"onMinuteScroll()\">\r\n <div\r\n *ngFor=\"let m of minutes\"\r\n class=\"time-item\"\r\n [class.selected]=\"currentMinute === m\"\r\n [class.active]=\"activeMinute === m\"\r\n (click)=\"onMinuteChange(m)\"\r\n >\r\n {{ m.toString().padStart(2, '0') }}\r\n </div>\r\n </div>\r\n </div>\r\n @if (showSeconds) {\r\n <span class=\"time-separator\">:</span>\r\n <!-- Seconds Column (finite list, no loop) -->\r\n <div class=\"time-column\">\r\n <div class=\"time-scroll\" #secondScroll (scroll)=\"onSecondScroll()\">\r\n <div\r\n *ngFor=\"let s of seconds\"\r\n class=\"time-item\"\r\n [class.selected]=\"currentSecond === s\"\r\n [class.active]=\"activeSecond === s\"\r\n (click)=\"onSecondChange(s)\"\r\n >\r\n {{ s.toString().padStart(2, '0') }}\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n <!-- AM/PM Column (only in 12-hour format) -->\r\n @if (timeFormat === 12) {\r\n <span class=\"time-separator\">:</span>\r\n <div class=\"time-column ampm-column\">\r\n <div class=\"time-scroll\">\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 >\r\n {{ ap }}\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\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-wrapper.has-value .time-input{padding-right:56px}.time-input{border:1px solid #d1d5db;border-radius:4px;font-family:Inter,sans-serif;color:#707280;background:#fff;transition:all .2s;width:100%;box-sizing:border-box;cursor:pointer}.time-input::placeholder{color:#6b7080}.time-input-group.default .time-input{font-size:12px;padding:6px 40px 5px 12px}.time-input-group.lg .time-input{font-size:14px;line-height:18px;padding:10px 40px 10px 12px}.time-input:focus{outline:none;border-color:#111827}.time-input:hover{border-color:#9ca3af}.time-clear-btn{position:absolute;right:26px;background:none;border:none;font-size:18px;color:#9ca3af;cursor:pointer;padding:0;width:20px;height:20px;display:flex;align-items:center;justify-content:center;line-height:1}.time-clear-btn:hover{color:#374151}.time-input-group.default .time-clear-btn{top:5px}.time-input-group.lg .time-clear-btn{top:10px}.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;align-items:flex-start;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.format-24{width:124px}.custom-time-picker.left-position{left:0}.custom-time-picker.right-position{right:0}.custom-time-picker.tp-above:not(.append-to-body){top:auto;bottom:calc(100% + 4px)}.time-column{display:flex;flex-direction:column;position:relative}.time-scroll{display:flex;flex-direction:column;max-height:96px;overflow-y:auto;overflow-x:hidden;scroll-snap-type:y proximity;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;scroll-snap-align:center;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}.time-item.active:not(.selected){background:#eef2ff;color:#111827;font-weight:500}.ampm-column .time-item{min-width:40px;width:40px}.time-separator{font-size:16px;font-weight:600;color:#6b7280;margin:5px 0 0}.time-input:disabled{cursor:not-allowed;border-color:#e3e3e7;background-color:#f4f4f6;color:#a1a3ae}.time-input-group.default .custom-time-picker{width:fit-content;gap:6px;padding:8px}.time-input-group.default .custom-time-picker.format-24{width:fit-content}.time-input-group.default .time-scroll{max-height:84px}.time-input-group.default .time-item{min-width:26px;width:26px;height:28px;min-height:28px;font-size:12px}.time-input-group.default .ampm-column .time-item{min-width:26px;width:26px}.time-input-group.default .time-separator{font-size:14px}.custom-time-picker.append-to-body{font-family:Inter,sans-serif}.custom-time-picker.tp-compact{width:fit-content;gap:6px;padding:8px}.custom-time-picker.tp-compact.format-24{width:fit-content}.custom-time-picker.tp-compact .time-scroll{max-height:84px}.custom-time-picker.tp-compact .time-item{min-width:26px;width:26px;height:28px;min-height:28px;font-size:12px}.custom-time-picker.tp-compact .ampm-column .time-item{min-width:26px;width:26px}.custom-time-picker.tp-compact .time-separator{font-size:14px}\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: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }] });
866
+ ], viewQueries: [{ propertyName: "hourScrollEl", first: true, predicate: ["hourScroll"], descendants: true }, { propertyName: "minuteScrollEl", first: true, predicate: ["minuteScroll"], descendants: true }, { propertyName: "secondScrollEl", first: true, predicate: ["secondScroll"], descendants: true }, { propertyName: "tpWrapper", first: true, predicate: ["tpWrapper"], descendants: true }, { propertyName: "tpOverlay", first: true, predicate: ["tpOverlay"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"time-picker-wrapper\">\r\n <div class=\"time-input-group\" [ngClass]=\"variation\">\r\n @if (label) {\r\n <label>{{ label }}</label>\r\n }\r\n <div class=\"time-input-wrapper\" [class.has-value]=\"hasValue\" #tpWrapper cdkOverlayOrigin #tpOrigin=\"cdkOverlayOrigin\">\r\n <input\r\n type=\"text\"\r\n class=\"time-input\"\r\n [value]=\"getDisplayValue()\"\r\n [placeholder]=\"placeholder\"\r\n [disabled]=\"disabled ? true : null\"\r\n readonly\r\n (mousedown)=\"onTriggerMouseDown($event)\"\r\n (focus)=\"onTriggerFocus()\"\r\n (keydown.enter)=\"onTriggerKeydownOpen($event)\"\r\n (keydown.space)=\"onTriggerKeydownOpen($event)\"\r\n (keydown.arrowDown)=\"onTriggerKeydownOpen($event)\"\r\n (blur)=\"onTriggerBlur()\"\r\n />\r\n <span class=\"time-icon\">\r\n <img alt=\"timer\" class=\"timer-icon\" [src]=\"brickclayIcons.timerIcon\" />\r\n </span>\r\n <button\r\n type=\"button\"\r\n class=\"time-clear-btn\"\r\n *ngIf=\"clearable && hasValue && !disabled\"\r\n (click)=\"clear(); $event.stopPropagation()\"\r\n title=\"Clear time\"\r\n aria-label=\"Clear time\"\r\n >\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"14\"\r\n height=\"14\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n >\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 </div>\r\n\r\n <!-- Positioned via Angular CDK Overlay, portalled into the shared cdk-overlay-container so it\r\n escapes clipping/stacking inside dialogs and scroll containers regardless of the old\r\n appendToBody flag (see its @deprecated note in the component). Works the same whether this\r\n picker is standalone (time-only) or embedded inside bk-custom-calendar's own (also CDK)\r\n popup \u2014 CDK overlays nest via the shared global container regardless of where the trigger\r\n sits in the DOM. -->\r\n <ng-template\r\n cdkConnectedOverlay\r\n #tpOverlay=\"cdkConnectedOverlay\"\r\n [cdkConnectedOverlayOrigin]=\"tpOrigin\"\r\n [cdkConnectedOverlayOpen]=\"showPicker\"\r\n [cdkConnectedOverlayPositions]=\"pickerPositions\"\r\n [cdkConnectedOverlayPush]=\"true\"\r\n [cdkConnectedOverlayViewportMargin]=\"viewportMargin\"\r\n [cdkConnectedOverlayPanelClass]=\"panelClass\"\r\n [cdkConnectedOverlayFlexibleDimensions]=\"false\"\r\n (positionChange)=\"onPositionChange($event)\"\r\n (overlayOutsideClick)=\"onOverlayOutsideClick()\"\r\n (detach)=\"dismiss()\"\r\n >\r\n <div\r\n class=\"custom-time-picker\"\r\n [class.tp-above]=\"placeAbove\"\r\n [ngClass]=\"{\r\n 'left-position': position === 'left',\r\n 'right-position': position === 'right',\r\n 'format-24': timeFormat === 24,\r\n 'tp-compact': variation === 'default',\r\n }\"\r\n >\r\n <!-- Hours Column (finite list, no loop) -->\r\n <div class=\"time-column\">\r\n <div class=\"time-scroll\" #hourScroll (scroll)=\"onHourScroll()\">\r\n <div\r\n *ngFor=\"let h of getHours()\"\r\n class=\"time-item\"\r\n [class.selected]=\"currentHour === h\"\r\n [class.active]=\"activeHour === h\"\r\n (click)=\"onHourChange(h)\"\r\n >\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 (finite list, no loop) -->\r\n <div class=\"time-column\">\r\n <div class=\"time-scroll\" #minuteScroll (scroll)=\"onMinuteScroll()\">\r\n <div\r\n *ngFor=\"let m of minutes\"\r\n class=\"time-item\"\r\n [class.selected]=\"currentMinute === m\"\r\n [class.active]=\"activeMinute === m\"\r\n (click)=\"onMinuteChange(m)\"\r\n >\r\n {{ m.toString().padStart(2, '0') }}\r\n </div>\r\n </div>\r\n </div>\r\n @if (showSeconds) {\r\n <span class=\"time-separator\">:</span>\r\n <!-- Seconds Column (finite list, no loop) -->\r\n <div class=\"time-column\">\r\n <div class=\"time-scroll\" #secondScroll (scroll)=\"onSecondScroll()\">\r\n <div\r\n *ngFor=\"let s of seconds\"\r\n class=\"time-item\"\r\n [class.selected]=\"currentSecond === s\"\r\n [class.active]=\"activeSecond === s\"\r\n (click)=\"onSecondChange(s)\"\r\n >\r\n {{ s.toString().padStart(2, '0') }}\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n <!-- AM/PM Column (only in 12-hour format) -->\r\n @if (timeFormat === 12) {\r\n <span class=\"time-separator\">:</span>\r\n <div class=\"time-column ampm-column\">\r\n <div class=\"time-scroll\">\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 >\r\n {{ ap }}\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </ng-template>\r\n </div>\r\n</div>\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-wrapper.has-value .time-input{padding-right:56px}.time-input{border:1px solid #d1d5db;border-radius:4px;font-family:Inter,sans-serif;color:#707280;background:#fff;transition:all .2s;width:100%;box-sizing:border-box;cursor:pointer}.time-input::placeholder{color:#6b7080}.time-input-group.default .time-input{font-size:12px;padding:6px 40px 5px 12px}.time-input-group.lg .time-input{font-size:14px;line-height:18px;padding:10px 40px 10px 12px}.time-input:focus{outline:none;border-color:#111827}.time-input:hover{border-color:#9ca3af}.time-clear-btn{position:absolute;right:26px;background:none;border:none;font-size:18px;color:#9ca3af;cursor:pointer;padding:0;width:20px;height:20px;display:flex;align-items:center;justify-content:center;line-height:1}.time-clear-btn:hover{color:#374151}.time-input-group.default .time-clear-btn{top:5px}.time-input-group.lg .time-clear-btn{top:10px}.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;align-items:flex-start;gap:8px;background:#fff;border:1px solid #e5e7eb;border-radius:8px;padding:10px;box-shadow:0 4px 12px #00000026;width:182px;font-family:Inter,sans-serif}.custom-time-picker.format-24{width:124px}.time-column{display:flex;flex-direction:column;position:relative}.time-scroll{display:flex;flex-direction:column;max-height:96px;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}.time-item.active:not(.selected){background:#eef2ff;color:#111827;font-weight:500}.ampm-column .time-item{min-width:40px;width:40px}.time-separator{font-size:16px;font-weight:600;color:#6b7280;margin:5px 0 0}.time-input:disabled{cursor:not-allowed;border-color:#e3e3e7;background-color:#f4f4f6;color:#a1a3ae}.time-input-group.default .custom-time-picker{width:fit-content;gap:6px;padding:8px}.time-input-group.default .custom-time-picker.format-24{width:fit-content}.time-input-group.default .time-scroll{max-height:84px}.time-input-group.default .time-item{min-width:26px;width:26px;height:28px;min-height:28px;font-size:12px}.time-input-group.default .ampm-column .time-item{min-width:26px;width:26px}.time-input-group.default .time-separator{font-size:14px}.custom-time-picker.tp-compact{width:fit-content;gap:6px;padding:8px}.custom-time-picker.tp-compact.format-24{width:fit-content}.custom-time-picker.tp-compact .time-scroll{max-height:84px}.custom-time-picker.tp-compact .time-item{min-width:26px;width:26px;height:28px;min-height:28px;font-size:12px}.custom-time-picker.tp-compact .ampm-column .time-item{min-width:26px;width:26px}.custom-time-picker.tp-compact .time-separator{font-size:14px}\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: "ngmodule", type: OverlayModule }, { kind: "directive", type: i2.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i2.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }] });
592
867
  }
593
868
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTimePicker, decorators: [{
594
869
  type: Component,
595
- args: [{ selector: 'bk-time-picker', standalone: true, imports: [CommonModule, FormsModule], providers: [
870
+ args: [{ selector: 'bk-time-picker', standalone: true, imports: [CommonModule, FormsModule, OverlayModule], providers: [
596
871
  {
597
872
  provide: NG_VALUE_ACCESSOR,
598
873
  useExisting: forwardRef(() => BkTimePicker),
599
874
  multi: true,
600
875
  },
601
- ], template: "<div class=\"time-picker-wrapper\">\r\n <div class=\"time-input-group\" [ngClass]=\"variation\">\r\n @if (label) {\r\n <label>{{ label }}</label>\r\n }\r\n <div class=\"time-input-wrapper\" [class.has-value]=\"hasValue\" #tpWrapper>\r\n <input\r\n type=\"text\"\r\n class=\"time-input\"\r\n [value]=\"getDisplayValue()\"\r\n [placeholder]=\"placeholder\"\r\n [disabled]=\"disabled ? true : null\"\r\n readonly\r\n (click)=\"!disabled && togglePicker()\"\r\n (blur)=\"markAsTouched()\"\r\n />\r\n <span class=\"time-icon\">\r\n <img alt=\"timer\" class=\"timer-icon\" [src]=\"brickclayIcons.timerIcon\" />\r\n </span>\r\n <button\r\n type=\"button\"\r\n class=\"time-clear-btn\"\r\n *ngIf=\"clearable && hasValue && !disabled\"\r\n (click)=\"clear(); $event.stopPropagation()\"\r\n title=\"Clear time\"\r\n aria-label=\"Clear time\"\r\n >\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"14\"\r\n height=\"14\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n >\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 <div class=\"custom-time-picker-dropdown\" *ngIf=\"showPicker\">\r\n <div\r\n #tpDropdown\r\n class=\"custom-time-picker\"\r\n [ngStyle]=\"dropdownStyle\"\r\n [class.tp-above]=\"placeAbove\"\r\n [class.append-to-body]=\"appendToBody\"\r\n [ngClass]=\"{\r\n 'left-position': resolvedPosition === 'left',\r\n 'right-position': resolvedPosition === 'right',\r\n 'format-24': timeFormat === 24,\r\n 'tp-compact': variation === 'default',\r\n }\"\r\n >\r\n <!-- Hours Column (finite list, no loop) -->\r\n <div class=\"time-column\">\r\n <div class=\"time-scroll\" #hourScroll (scroll)=\"onHourScroll()\">\r\n <div\r\n *ngFor=\"let h of getHours()\"\r\n class=\"time-item\"\r\n [class.selected]=\"currentHour === h\"\r\n [class.active]=\"activeHour === h\"\r\n (click)=\"onHourChange(h)\"\r\n >\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 (finite list, no loop) -->\r\n <div class=\"time-column\">\r\n <div class=\"time-scroll\" #minuteScroll (scroll)=\"onMinuteScroll()\">\r\n <div\r\n *ngFor=\"let m of minutes\"\r\n class=\"time-item\"\r\n [class.selected]=\"currentMinute === m\"\r\n [class.active]=\"activeMinute === m\"\r\n (click)=\"onMinuteChange(m)\"\r\n >\r\n {{ m.toString().padStart(2, '0') }}\r\n </div>\r\n </div>\r\n </div>\r\n @if (showSeconds) {\r\n <span class=\"time-separator\">:</span>\r\n <!-- Seconds Column (finite list, no loop) -->\r\n <div class=\"time-column\">\r\n <div class=\"time-scroll\" #secondScroll (scroll)=\"onSecondScroll()\">\r\n <div\r\n *ngFor=\"let s of seconds\"\r\n class=\"time-item\"\r\n [class.selected]=\"currentSecond === s\"\r\n [class.active]=\"activeSecond === s\"\r\n (click)=\"onSecondChange(s)\"\r\n >\r\n {{ s.toString().padStart(2, '0') }}\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n <!-- AM/PM Column (only in 12-hour format) -->\r\n @if (timeFormat === 12) {\r\n <span class=\"time-separator\">:</span>\r\n <div class=\"time-column ampm-column\">\r\n <div class=\"time-scroll\">\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 >\r\n {{ ap }}\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\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-wrapper.has-value .time-input{padding-right:56px}.time-input{border:1px solid #d1d5db;border-radius:4px;font-family:Inter,sans-serif;color:#707280;background:#fff;transition:all .2s;width:100%;box-sizing:border-box;cursor:pointer}.time-input::placeholder{color:#6b7080}.time-input-group.default .time-input{font-size:12px;padding:6px 40px 5px 12px}.time-input-group.lg .time-input{font-size:14px;line-height:18px;padding:10px 40px 10px 12px}.time-input:focus{outline:none;border-color:#111827}.time-input:hover{border-color:#9ca3af}.time-clear-btn{position:absolute;right:26px;background:none;border:none;font-size:18px;color:#9ca3af;cursor:pointer;padding:0;width:20px;height:20px;display:flex;align-items:center;justify-content:center;line-height:1}.time-clear-btn:hover{color:#374151}.time-input-group.default .time-clear-btn{top:5px}.time-input-group.lg .time-clear-btn{top:10px}.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;align-items:flex-start;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.format-24{width:124px}.custom-time-picker.left-position{left:0}.custom-time-picker.right-position{right:0}.custom-time-picker.tp-above:not(.append-to-body){top:auto;bottom:calc(100% + 4px)}.time-column{display:flex;flex-direction:column;position:relative}.time-scroll{display:flex;flex-direction:column;max-height:96px;overflow-y:auto;overflow-x:hidden;scroll-snap-type:y proximity;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;scroll-snap-align:center;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}.time-item.active:not(.selected){background:#eef2ff;color:#111827;font-weight:500}.ampm-column .time-item{min-width:40px;width:40px}.time-separator{font-size:16px;font-weight:600;color:#6b7280;margin:5px 0 0}.time-input:disabled{cursor:not-allowed;border-color:#e3e3e7;background-color:#f4f4f6;color:#a1a3ae}.time-input-group.default .custom-time-picker{width:fit-content;gap:6px;padding:8px}.time-input-group.default .custom-time-picker.format-24{width:fit-content}.time-input-group.default .time-scroll{max-height:84px}.time-input-group.default .time-item{min-width:26px;width:26px;height:28px;min-height:28px;font-size:12px}.time-input-group.default .ampm-column .time-item{min-width:26px;width:26px}.time-input-group.default .time-separator{font-size:14px}.custom-time-picker.append-to-body{font-family:Inter,sans-serif}.custom-time-picker.tp-compact{width:fit-content;gap:6px;padding:8px}.custom-time-picker.tp-compact.format-24{width:fit-content}.custom-time-picker.tp-compact .time-scroll{max-height:84px}.custom-time-picker.tp-compact .time-item{min-width:26px;width:26px;height:28px;min-height:28px;font-size:12px}.custom-time-picker.tp-compact .ampm-column .time-item{min-width:26px;width:26px}.custom-time-picker.tp-compact .time-separator{font-size:14px}\n"] }]
602
- }], ctorParameters: () => [{ type: i0.Renderer2 }], propDecorators: { required: [{
876
+ ], template: "<div class=\"time-picker-wrapper\">\r\n <div class=\"time-input-group\" [ngClass]=\"variation\">\r\n @if (label) {\r\n <label>{{ label }}</label>\r\n }\r\n <div class=\"time-input-wrapper\" [class.has-value]=\"hasValue\" #tpWrapper cdkOverlayOrigin #tpOrigin=\"cdkOverlayOrigin\">\r\n <input\r\n type=\"text\"\r\n class=\"time-input\"\r\n [value]=\"getDisplayValue()\"\r\n [placeholder]=\"placeholder\"\r\n [disabled]=\"disabled ? true : null\"\r\n readonly\r\n (mousedown)=\"onTriggerMouseDown($event)\"\r\n (focus)=\"onTriggerFocus()\"\r\n (keydown.enter)=\"onTriggerKeydownOpen($event)\"\r\n (keydown.space)=\"onTriggerKeydownOpen($event)\"\r\n (keydown.arrowDown)=\"onTriggerKeydownOpen($event)\"\r\n (blur)=\"onTriggerBlur()\"\r\n />\r\n <span class=\"time-icon\">\r\n <img alt=\"timer\" class=\"timer-icon\" [src]=\"brickclayIcons.timerIcon\" />\r\n </span>\r\n <button\r\n type=\"button\"\r\n class=\"time-clear-btn\"\r\n *ngIf=\"clearable && hasValue && !disabled\"\r\n (click)=\"clear(); $event.stopPropagation()\"\r\n title=\"Clear time\"\r\n aria-label=\"Clear time\"\r\n >\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"14\"\r\n height=\"14\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n >\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 </div>\r\n\r\n <!-- Positioned via Angular CDK Overlay, portalled into the shared cdk-overlay-container so it\r\n escapes clipping/stacking inside dialogs and scroll containers regardless of the old\r\n appendToBody flag (see its @deprecated note in the component). Works the same whether this\r\n picker is standalone (time-only) or embedded inside bk-custom-calendar's own (also CDK)\r\n popup \u2014 CDK overlays nest via the shared global container regardless of where the trigger\r\n sits in the DOM. -->\r\n <ng-template\r\n cdkConnectedOverlay\r\n #tpOverlay=\"cdkConnectedOverlay\"\r\n [cdkConnectedOverlayOrigin]=\"tpOrigin\"\r\n [cdkConnectedOverlayOpen]=\"showPicker\"\r\n [cdkConnectedOverlayPositions]=\"pickerPositions\"\r\n [cdkConnectedOverlayPush]=\"true\"\r\n [cdkConnectedOverlayViewportMargin]=\"viewportMargin\"\r\n [cdkConnectedOverlayPanelClass]=\"panelClass\"\r\n [cdkConnectedOverlayFlexibleDimensions]=\"false\"\r\n (positionChange)=\"onPositionChange($event)\"\r\n (overlayOutsideClick)=\"onOverlayOutsideClick()\"\r\n (detach)=\"dismiss()\"\r\n >\r\n <div\r\n class=\"custom-time-picker\"\r\n [class.tp-above]=\"placeAbove\"\r\n [ngClass]=\"{\r\n 'left-position': position === 'left',\r\n 'right-position': position === 'right',\r\n 'format-24': timeFormat === 24,\r\n 'tp-compact': variation === 'default',\r\n }\"\r\n >\r\n <!-- Hours Column (finite list, no loop) -->\r\n <div class=\"time-column\">\r\n <div class=\"time-scroll\" #hourScroll (scroll)=\"onHourScroll()\">\r\n <div\r\n *ngFor=\"let h of getHours()\"\r\n class=\"time-item\"\r\n [class.selected]=\"currentHour === h\"\r\n [class.active]=\"activeHour === h\"\r\n (click)=\"onHourChange(h)\"\r\n >\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 (finite list, no loop) -->\r\n <div class=\"time-column\">\r\n <div class=\"time-scroll\" #minuteScroll (scroll)=\"onMinuteScroll()\">\r\n <div\r\n *ngFor=\"let m of minutes\"\r\n class=\"time-item\"\r\n [class.selected]=\"currentMinute === m\"\r\n [class.active]=\"activeMinute === m\"\r\n (click)=\"onMinuteChange(m)\"\r\n >\r\n {{ m.toString().padStart(2, '0') }}\r\n </div>\r\n </div>\r\n </div>\r\n @if (showSeconds) {\r\n <span class=\"time-separator\">:</span>\r\n <!-- Seconds Column (finite list, no loop) -->\r\n <div class=\"time-column\">\r\n <div class=\"time-scroll\" #secondScroll (scroll)=\"onSecondScroll()\">\r\n <div\r\n *ngFor=\"let s of seconds\"\r\n class=\"time-item\"\r\n [class.selected]=\"currentSecond === s\"\r\n [class.active]=\"activeSecond === s\"\r\n (click)=\"onSecondChange(s)\"\r\n >\r\n {{ s.toString().padStart(2, '0') }}\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n <!-- AM/PM Column (only in 12-hour format) -->\r\n @if (timeFormat === 12) {\r\n <span class=\"time-separator\">:</span>\r\n <div class=\"time-column ampm-column\">\r\n <div class=\"time-scroll\">\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 >\r\n {{ ap }}\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </ng-template>\r\n </div>\r\n</div>\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-wrapper.has-value .time-input{padding-right:56px}.time-input{border:1px solid #d1d5db;border-radius:4px;font-family:Inter,sans-serif;color:#707280;background:#fff;transition:all .2s;width:100%;box-sizing:border-box;cursor:pointer}.time-input::placeholder{color:#6b7080}.time-input-group.default .time-input{font-size:12px;padding:6px 40px 5px 12px}.time-input-group.lg .time-input{font-size:14px;line-height:18px;padding:10px 40px 10px 12px}.time-input:focus{outline:none;border-color:#111827}.time-input:hover{border-color:#9ca3af}.time-clear-btn{position:absolute;right:26px;background:none;border:none;font-size:18px;color:#9ca3af;cursor:pointer;padding:0;width:20px;height:20px;display:flex;align-items:center;justify-content:center;line-height:1}.time-clear-btn:hover{color:#374151}.time-input-group.default .time-clear-btn{top:5px}.time-input-group.lg .time-clear-btn{top:10px}.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;align-items:flex-start;gap:8px;background:#fff;border:1px solid #e5e7eb;border-radius:8px;padding:10px;box-shadow:0 4px 12px #00000026;width:182px;font-family:Inter,sans-serif}.custom-time-picker.format-24{width:124px}.time-column{display:flex;flex-direction:column;position:relative}.time-scroll{display:flex;flex-direction:column;max-height:96px;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}.time-item.active:not(.selected){background:#eef2ff;color:#111827;font-weight:500}.ampm-column .time-item{min-width:40px;width:40px}.time-separator{font-size:16px;font-weight:600;color:#6b7280;margin:5px 0 0}.time-input:disabled{cursor:not-allowed;border-color:#e3e3e7;background-color:#f4f4f6;color:#a1a3ae}.time-input-group.default .custom-time-picker{width:fit-content;gap:6px;padding:8px}.time-input-group.default .custom-time-picker.format-24{width:fit-content}.time-input-group.default .time-scroll{max-height:84px}.time-input-group.default .time-item{min-width:26px;width:26px;height:28px;min-height:28px;font-size:12px}.time-input-group.default .ampm-column .time-item{min-width:26px;width:26px}.time-input-group.default .time-separator{font-size:14px}.custom-time-picker.tp-compact{width:fit-content;gap:6px;padding:8px}.custom-time-picker.tp-compact.format-24{width:fit-content}.custom-time-picker.tp-compact .time-scroll{max-height:84px}.custom-time-picker.tp-compact .time-item{min-width:26px;width:26px;height:28px;min-height:28px;font-size:12px}.custom-time-picker.tp-compact .ampm-column .time-item{min-width:26px;width:26px}.custom-time-picker.tp-compact .time-separator{font-size:14px}\n"] }]
877
+ }], ctorParameters: () => [{ type: BkCalendarManagerService }], propDecorators: { required: [{
603
878
  type: Input
604
879
  }], value: [{
605
880
  type: Input
@@ -625,6 +900,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
625
900
  type: Input
626
901
  }], appendToBody: [{
627
902
  type: Input
903
+ }], viewportMargin: [{
904
+ type: Input
905
+ }], panelClass: [{
906
+ type: Input
628
907
  }], change: [{
629
908
  type: Output
630
909
  }], timeChange: [{
@@ -647,125 +926,59 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
647
926
  }], tpWrapper: [{
648
927
  type: ViewChild,
649
928
  args: ['tpWrapper']
650
- }], tpDropdown: [{
929
+ }], tpOverlay: [{
651
930
  type: ViewChild,
652
- args: ['tpDropdown']
653
- }], onDocumentClick: [{
654
- type: HostListener,
655
- args: ['document:click', ['$event']]
931
+ args: ['tpOverlay']
656
932
  }] } });
657
-
658
- class BkCalendarManagerService {
659
- calendarInstances = new Set();
660
- closeAllSubject = new Subject();
661
- closeAll$ = this.closeAllSubject.asObservable();
662
- customRanges = {};
663
- rangeOrder = [];
664
- constructor() {
665
- this.initializeDefaultRanges();
666
- }
667
- /**
668
- * Returns service-defined custom ranges and their display order.
669
- * Used when the calendar does not pass customRanges via @Input().
670
- */
671
- getCustomRanges() {
672
- this.initializeDefaultRanges();
673
- return {
674
- customRanges: { ...this.customRanges },
675
- rangeOrder: [...this.rangeOrder],
676
- };
677
- }
678
- initializeDefaultRanges() {
679
- const today = new Date();
680
- this.customRanges = {
681
- Today: {
682
- start: new Date(today.getFullYear(), today.getMonth(), today.getDate()),
683
- end: new Date(today.getFullYear(), today.getMonth(), today.getDate()),
684
- },
685
- Yesterday: {
686
- start: this.addDays(today, -1),
687
- end: this.addDays(today, -1),
688
- },
689
- 'Last 7 Days': {
690
- start: this.addDays(today, -6),
691
- end: today,
692
- },
693
- 'Last 30 Days': {
694
- start: this.addDays(today, -29),
695
- end: today,
696
- },
697
- 'This Month': {
698
- start: new Date(today.getFullYear(), today.getMonth(), 1),
699
- end: new Date(today.getFullYear(), today.getMonth() + 1, 0),
700
- },
701
- 'Last Month': {
702
- start: new Date(today.getFullYear(), today.getMonth() - 1, 1),
703
- end: new Date(today.getFullYear(), today.getMonth(), 0),
704
- },
705
- 'Custom Range': {
706
- start: new Date(),
707
- end: new Date(),
708
- },
709
- };
710
- this.rangeOrder = [
711
- 'Today',
712
- 'Yesterday',
713
- 'Last 7 Days',
714
- 'Last 30 Days',
715
- 'This Month',
716
- 'Last Month',
717
- 'Custom Range',
718
- ];
719
- }
720
- addDays(date, days) {
721
- const d = new Date(date);
722
- d.setDate(d.getDate() + days);
723
- return d;
724
- }
725
- /**
726
- * Register a calendar instance with its close function
727
- */
728
- register(closeFn) {
729
- this.calendarInstances.add(closeFn);
730
- // Return unregister function
731
- return () => {
732
- this.calendarInstances.delete(closeFn);
733
- };
734
- }
735
- /**
736
- * Close all calendars except the one being opened
737
- */
738
- closeAllExcept(exceptCloseFn) {
739
- this.calendarInstances.forEach(closeFn => {
740
- if (closeFn !== exceptCloseFn) {
741
- closeFn();
742
- }
743
- });
744
- }
745
- /**
746
- * Close all calendars
747
- */
748
- closeAll() {
749
- this.closeAllSubject.next();
750
- this.calendarInstances.forEach(closeFn => closeFn());
751
- }
752
- getOnlyDate(input) {
753
- const date = new Date(input);
754
- const year = date.getFullYear();
755
- const month = (date.getMonth() + 1).toString().padStart(2, '0');
756
- const day = date.getDate().toString().padStart(2, '0');
757
- return `${year}-${month}-${day}`;
758
- }
759
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkCalendarManagerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
760
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkCalendarManagerService, providedIn: 'root' });
933
+ /** Field-by-field equality for ConnectedPosition — CDK does not preserve object identity for
934
+ * positions passed via cdkConnectedOverlayPositions, so `event.connectionPair` must be matched
935
+ * by value against the entries handed to it, never by `===`. Same approach as
936
+ * bk-custom-calendar's positionsEqual. */
937
+ function positionsEqual$2(a, b) {
938
+ return a.originX === b.originX && a.originY === b.originY &&
939
+ a.overlayX === b.overlayX && a.overlayY === b.overlayY &&
940
+ (a.offsetX ?? 0) === (b.offsetX ?? 0) && (a.offsetY ?? 0) === (b.offsetY ?? 0);
761
941
  }
762
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkCalendarManagerService, decorators: [{
763
- type: Injectable,
764
- args: [{
765
- providedIn: 'root'
766
- }]
767
- }], ctorParameters: () => [] });
768
942
 
943
+ /**
944
+ * 1-based month numbers (January = 1 … December = 12) — deliberately NOT JS `Date`'s 0-based
945
+ * `getMonth()` convention, so callers reading `allowedMonths` see the calendar month number they'd
946
+ * expect. Backs {@link BkCustomCalendar.allowedMonths} so callers can write `CalendarMonth.March`
947
+ * instead of a bare `3`. {@link BkCustomCalendar.allowedMonthsZeroBased} converts back to 0-based
948
+ * for every internal comparison against `Date.getMonth()`/the month grid's loop index.
949
+ */
950
+ var CalendarMonth;
951
+ (function (CalendarMonth) {
952
+ CalendarMonth[CalendarMonth["January"] = 1] = "January";
953
+ CalendarMonth[CalendarMonth["February"] = 2] = "February";
954
+ CalendarMonth[CalendarMonth["March"] = 3] = "March";
955
+ CalendarMonth[CalendarMonth["April"] = 4] = "April";
956
+ CalendarMonth[CalendarMonth["May"] = 5] = "May";
957
+ CalendarMonth[CalendarMonth["June"] = 6] = "June";
958
+ CalendarMonth[CalendarMonth["July"] = 7] = "July";
959
+ CalendarMonth[CalendarMonth["August"] = 8] = "August";
960
+ CalendarMonth[CalendarMonth["September"] = 9] = "September";
961
+ CalendarMonth[CalendarMonth["October"] = 10] = "October";
962
+ CalendarMonth[CalendarMonth["November"] = 11] = "November";
963
+ CalendarMonth[CalendarMonth["December"] = 12] = "December";
964
+ })(CalendarMonth || (CalendarMonth = {}));
965
+ /**
966
+ * 1-based day-of-week numbers (Sunday = 1 … Saturday = 7) — same reasoning as {@link
967
+ * CalendarMonth}: deliberately NOT JS `Date`'s 0-based `getDay()` convention, so a bare `0` in
968
+ * `allowedDaysOfWeek` can't be mistaken for "unset" or silently match the wrong day. Backs
969
+ * {@link BkCustomCalendar.allowedDaysOfWeek}. {@link BkCustomCalendar.allowedDaysOfWeekZeroBased}
970
+ * converts back to 0-based for every internal comparison against `Date.getDay()`.
971
+ */
972
+ var CalendarWeekday;
973
+ (function (CalendarWeekday) {
974
+ CalendarWeekday[CalendarWeekday["Sunday"] = 1] = "Sunday";
975
+ CalendarWeekday[CalendarWeekday["Monday"] = 2] = "Monday";
976
+ CalendarWeekday[CalendarWeekday["Tuesday"] = 3] = "Tuesday";
977
+ CalendarWeekday[CalendarWeekday["Wednesday"] = 4] = "Wednesday";
978
+ CalendarWeekday[CalendarWeekday["Thursday"] = 5] = "Thursday";
979
+ CalendarWeekday[CalendarWeekday["Friday"] = 6] = "Friday";
980
+ CalendarWeekday[CalendarWeekday["Saturday"] = 7] = "Saturday";
981
+ })(CalendarWeekday || (CalendarWeekday = {}));
769
982
  class CalendarSelection {
770
983
  startDate = null;
771
984
  endDate = null;
@@ -774,10 +987,16 @@ class CalendarSelection {
774
987
  /** End time in 12-hour format with AM/PM (e.g. "2:00 AM"). */
775
988
  endTime = null;
776
989
  selectedDates = []; // For multi-date selection
990
+ /**
991
+ * Set only when `pickerView` is 'month' (paired with {@link selectedYear}) — the selected
992
+ * month, 0-11. `startDate`/`endDate` stay null in this mode; there is no day-level value.
993
+ */
994
+ selectedMonth = null;
995
+ /** Set when `pickerView` is 'year' (alone) or 'month' (paired with {@link selectedMonth}). */
996
+ selectedYear = null;
777
997
  }
778
998
  class BkCustomCalendar {
779
999
  calendarManager;
780
- renderer;
781
1000
  // Basic Options
782
1001
  enableTimepicker = false;
783
1002
  autoApply = false;
@@ -785,13 +1004,37 @@ class BkCustomCalendar {
785
1004
  showCancel = true;
786
1005
  linkedCalendars = false;
787
1006
  singleDatePicker = false;
1007
+ /**
1008
+ * Restricts selection to just a month or just a year, skipping the day grid entirely. Only
1009
+ * takes effect with `singleDatePicker` and `!dualCalendar` — ignored (falls back to normal
1010
+ * day-grid behaviour) for range/dual selection, which isn't supported yet. Picking a
1011
+ * month/year is the final action: it commits immediately (like `autoApply`) and populates only
1012
+ * `selectedMonth`/`selectedYear` on the emitted {@link CalendarSelection} — `startDate` stays
1013
+ * null, there is no day-level value to give it.
1014
+ */
1015
+ pickerView = 'day';
788
1016
  showWeekNumbers = false;
789
1017
  showISOWeekNumbers = false;
790
1018
  customRangeDirection = false;
791
1019
  lockStartDate = false;
792
- position = 'left';
793
- /** Vertical placement relative to the input. When explicitly set, overrides viewport-space detection entirely. */
794
- popupPosition;
1020
+ /**
1021
+ * @deprecated Use {@link opens} instead same 'left' | 'right' | 'center' values, same meaning.
1022
+ * Kept, and still honoured, only so existing `[position]="..."` bindings keep working; when set,
1023
+ * it takes priority over `opens` (see {@link horizontalAlign}). No known consumers currently set
1024
+ * this — safe to remove once none do.
1025
+ */
1026
+ position;
1027
+ /**
1028
+ * Preferred vertical side of the popup relative to the input. The opposite side is always
1029
+ * offered as a CDK flip fallback (see {@link computeCalendarPositions}) — there is no way to
1030
+ * lock the popup to one side regardless of available space.
1031
+ */
1032
+ popupPosition = 'bottom';
1033
+ /**
1034
+ * @deprecated No-op. Use {@link popupPosition} ('bottom' | 'top') instead — 'down'/'up' were
1035
+ * renamed to 'bottom'/'top' to match it. Auto-flip is always on now, so this no longer has a
1036
+ * "never flips" mode to opt out of either. Safe to remove from call sites.
1037
+ */
795
1038
  drop = 'down';
796
1039
  dualCalendar = false;
797
1040
  showRanges = true;
@@ -804,21 +1047,80 @@ class BkCustomCalendar {
804
1047
  multiDateSelection = false; // NEW: Enable multi-date selection
805
1048
  maxDate; // NEW: Maximum selectable date
806
1049
  minDate; // NEW: Minimum selectable date
1050
+ /**
1051
+ * Allow-list of selectable months, for the month grid — e.g.
1052
+ * `[CalendarMonth.January, CalendarMonth.March]` for Jan/Mar only. 1-based (January = 1 …
1053
+ * December = 12) — a bare `0` won't match January here, unlike JS `Date.getMonth()`. Unset
1054
+ * (default) means no restriction beyond `minDate`/`maxDate`. Combines with them: a month must
1055
+ * satisfy both to be selectable. Backs every month grid ({@link isMonthDisabled}) — `pickerView`
1056
+ * 'month' and the day grid's own month quick-pick alike.
1057
+ */
1058
+ allowedMonths;
1059
+ /**
1060
+ * Allow-list of selectable years, for the year grid — e.g. `[2025, 2027]`. Unset (default) means
1061
+ * no restriction beyond `minDate`/`maxDate`. Combines with them the same way as
1062
+ * {@link allowedMonths}. Backs every year grid ({@link isYearDisabled}).
1063
+ */
1064
+ allowedYears;
1065
+ /**
1066
+ * Allow-list of selectable weekdays, for the day grid — e.g.
1067
+ * `[CalendarWeekday.Monday, ..., CalendarWeekday.Friday]` for business days only. 1-based
1068
+ * (Sunday = 1 … Saturday = 7) — a bare `0` won't match Sunday here, unlike JS `Date.getDay()`.
1069
+ * Unset (default) means no restriction. Unlike `allowedMonths`/`allowedYears`, this is
1070
+ * day-granularity only — it does NOT disable a whole month/year grid cell just because some of
1071
+ * its days fall on a disallowed weekday, since a month/year still has other selectable days.
1072
+ * Combines (AND) with every other constraint. Backs {@link isDateDisabled}.
1073
+ */
1074
+ allowedDaysOfWeek;
1075
+ /**
1076
+ * Blackout list — specific dates that are never selectable regardless of every other
1077
+ * constraint (minDate/maxDate/allowedMonths/allowedYears/allowedDaysOfWeek all still apply on
1078
+ * top; this only ever narrows further, e.g. for holidays or dates already booked elsewhere).
1079
+ * Compared by calendar day (year/month/date), time-of-day is ignored. Backs {@link
1080
+ * isDateDisabled}.
1081
+ */
1082
+ disabledDates;
1083
+ /**
1084
+ * Allow-list of specific selectable dates — same AND semantics as `allowedMonths`/
1085
+ * `allowedYears`/`allowedDaysOfWeek` (a date must satisfy this AND every other constraint that's
1086
+ * set, not "these dates are selectable regardless of the rest"). Compared by calendar day
1087
+ * (year/month/date), time-of-day is ignored. Backs {@link isDateDisabled}.
1088
+ */
1089
+ allowedDates;
807
1090
  placeholder = 'Select date range'; // NEW: Custom placeholder
808
1091
  opens = 'left'; // NEW: Popup position
809
1092
  inline = false; // NEW: Always show calendar inline (no popup)
810
1093
  compact = false; // NEW: Compact (smaller) layout variant. Default false keeps the original sizing.
811
- autoPosition = false; // NEW: When true, auto-flip popup above/below based on available viewport space. Default false.
812
- appendToBody = false; // When true, positions popup with fixed so it isn't clipped inside dialogs/overflow
1094
+ /**
1095
+ * @deprecated No-op, kept only so existing `[appendToBody]="true"` bindings don't break.
1096
+ * The popup now always positions via Angular CDK Overlay, which portals into the shared
1097
+ * `cdk-overlay-container` unconditionally — the exact clipping/stacking escape this input used
1098
+ * to opt into by hand is now the only behaviour there is. Safe to remove from call sites.
1099
+ */
1100
+ appendToBody = false;
1101
+ /**
1102
+ * Extra px CDK keeps clear of the viewport edges when flipping/pushing the popup. CDK's
1103
+ * flip/push only avoids the window edges — it has no idea a sticky app header or a sticky
1104
+ * table `<thead>` occupies part of that space, and will happily flip/push the popup underneath
1105
+ * one. Set this to the height of any such sticky/fixed chrome the popup must never land under.
1106
+ * Same fix, same reasoning, as `bk-popover.viewportMargin`.
1107
+ */
1108
+ viewportMargin = 0;
1109
+ /**
1110
+ * Classes applied to the CDK overlay pane (`cdkConnectedOverlayPanelClass`). z-index overrides
1111
+ * MUST go here (e.g. `panelClass="!z-[1100]"`) — the pane already establishes its own stacking
1112
+ * context once portalled, so setting z-index anywhere else (the calendar's host element, a
1113
+ * consumer's own wrapper) is a no-op. Same convention as `bk-popover.panelClass`.
1114
+ */
1115
+ panelClass = '';
813
1116
  isDisplayCrossIcon = true; // NEW: Show/Hide clear (X) icon
814
1117
  hasError = false; // NEW: Show/Hide clear (X) icon
815
1118
  errorMessage = '';
816
1119
  selected = new EventEmitter();
817
1120
  inputWrapper;
818
1121
  calendarPopupRef;
819
- /** Used when appendToBody is true to position the popup in viewport coordinates */
820
- dropdownStyle = {};
821
- /** Resolved after layout; used for CSS `drop-up` and appendToBody positioning with viewport flip */
1122
+ calendarOverlay;
1123
+ /** Resolved from CDK's (positionChange); drives the CSS `drop-up` class + slide direction. */
822
1124
  popupPlacementAbove = false;
823
1125
  opened = new EventEmitter();
824
1126
  closed = new EventEmitter();
@@ -849,9 +1151,21 @@ class BkCustomCalendar {
849
1151
  rightYear;
850
1152
  leftCalendar = [];
851
1153
  rightCalendar = [];
1154
+ /** Drill-down state for the header's month/year quick-pick. Independent per side in dual mode. */
1155
+ view = 'days';
1156
+ leftView = 'days';
1157
+ rightView = 'days';
1158
+ /** First year shown in the currently open year-grid (a 12-year page). */
1159
+ yearRangeStart = 0;
1160
+ leftYearRangeStart = 0;
1161
+ rightYearRangeStart = 0;
1162
+ monthNamesShort = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
852
1163
  startDate = null;
853
1164
  endDate = null;
854
1165
  selectedDates = []; // NEW: For multi-date selection
1166
+ /** Committed selection for `pickerView` 'month' (paired with {@link selectedYearValue}) / 'year'. */
1167
+ selectedMonthValue = null;
1168
+ selectedYearValue = null;
855
1169
  disableHighlight = false;
856
1170
  hoveredDate = null; // For hover preview
857
1171
  // Track raw input values for minutes to allow free typing
@@ -890,52 +1204,51 @@ class BkCustomCalendar {
890
1204
  unregisterFn;
891
1205
  closeAllSubscription;
892
1206
  closeFn;
893
- constructor(calendarManager, renderer) {
1207
+ constructor(calendarManager) {
894
1208
  this.calendarManager = calendarManager;
895
- this.renderer = renderer;
896
1209
  }
897
1210
  /**
898
- * appendToBody popup relocation.
899
- *
900
- * `appendToBody` uses `position: fixed`, which only anchors to the viewport when NO ancestor
901
- * establishes a containing block (transform / filter / perspective / will-change / contain /
902
- * backdrop-filter). Consumers frequently place the calendar inside such an ancestor (an animated
903
- * panel, a CSS-transformed modal, etc.), which silently re-anchors the fixed popup and pushes it
904
- * off-position. To be robust everywhere we physically move the popup node to <body> while it is
905
- * open, then move it back before Angular's *ngIf tears it down. Angular keeps managing the node by
906
- * reference after the move, so its event bindings, change detection, and emulated-encapsulation
907
- * styles all continue to work.
908
- */
909
- popupMovedToBody = false;
910
- popupOriginalParent = null;
911
- popupOriginalNextSibling = null;
912
- movePopupToBody() {
913
- const el = this.calendarPopupRef?.nativeElement;
914
- if (!el || this.popupMovedToBody)
915
- return;
916
- this.popupOriginalParent = el.parentElement;
917
- this.popupOriginalNextSibling = el.nextSibling;
918
- this.renderer.appendChild(document.body, el);
919
- this.popupMovedToBody = true;
920
- }
921
- /** Return the popup to its original DOM slot so *ngIf can destroy it cleanly (safe to call twice). */
922
- restorePopupFromBody() {
923
- if (!this.popupMovedToBody)
924
- return;
925
- const el = this.calendarPopupRef?.nativeElement;
926
- const parent = this.popupOriginalParent;
927
- if (el && parent) {
928
- const ref = this.popupOriginalNextSibling;
929
- if (ref && ref.parentNode === parent) {
930
- this.renderer.insertBefore(parent, el, ref);
931
- }
932
- else {
933
- this.renderer.appendChild(parent, el);
934
- }
935
- }
936
- this.popupMovedToBody = false;
937
- this.popupOriginalParent = null;
938
- this.popupOriginalNextSibling = null;
1211
+ * CDK connected-overlay positions for the current open. Rebuilt each time the popup opens (see
1212
+ * {@link toggle}) from `opens` (horizontal alignment) and `popupPosition` (which vertical side is
1213
+ * primary). Auto-flip is always on the opposite vertical side is always offered as a fallback,
1214
+ * the same as `opens`'s horizontal push; there is no opt-out flag, matching `bk-select`/
1215
+ * `bk-popover`. `cdkConnectedOverlayPush` (see the template) stays on regardless, so CDK slides
1216
+ * the popup back on-screen horizontally instead of the old hand-rolled flip-then-clamp in
1217
+ * computePopupLeft() the same push-based approach bk-popover uses.
1218
+ */
1219
+ calendarPositions = [];
1220
+ /** Tags each entry in {@link calendarPositions} with whether it places the popup above the
1221
+ * trigger, so `onPositionChange` can read back which one CDK actually used. Matched by field
1222
+ * value, not object identity — CDK reconstructs its own ConnectedPosition objects internally. */
1223
+ positionMeta = [];
1224
+ /** Horizontal alignment from `opens` (deprecated `position` wins when explicitly set — see its
1225
+ * JSDoc): 'left' aligns left edges (opens rightwards, the default), 'right' aligns right edges
1226
+ * (opens leftwards), 'center' centers on the trigger. */
1227
+ horizontalAlign() {
1228
+ const side = this.position ?? this.opens;
1229
+ if (side === 'right')
1230
+ return { originX: 'end', overlayX: 'end' };
1231
+ if (side === 'center')
1232
+ return { originX: 'center', overlayX: 'center' };
1233
+ return { originX: 'start', overlayX: 'start' };
1234
+ }
1235
+ buildVerticalPosition(above, gap) {
1236
+ const { originX, overlayX } = this.horizontalAlign();
1237
+ return above
1238
+ ? { pos: { originX, originY: 'top', overlayX, overlayY: 'bottom', offsetY: -gap }, above: true }
1239
+ : { pos: { originX, originY: 'bottom', overlayX, overlayY: 'top', offsetY: gap }, above: false };
1240
+ }
1241
+ /**
1242
+ * (Re)computes {@link calendarPositions}: `popupPosition` picks the preferred/primary side, and
1243
+ * the opposite side always follows as CDK's flip fallback — used only when the preferred side
1244
+ * genuinely doesn't fit the viewport (`viewportMargin` included).
1245
+ */
1246
+ computeCalendarPositions() {
1247
+ const gap = 4;
1248
+ const preferAbove = this.popupPosition === 'top';
1249
+ const primary = this.buildVerticalPosition(preferAbove, gap);
1250
+ this.positionMeta = [primary, this.buildVerticalPosition(!preferAbove, gap)];
1251
+ this.calendarPositions = this.positionMeta.map(e => e.pos);
939
1252
  }
940
1253
  /** Weekday headers; falls back to Mon–Sun if the input is not length 7. */
941
1254
  get resolvedWeekDayLabels() {
@@ -973,17 +1286,14 @@ class BkCustomCalendar {
973
1286
  return;
974
1287
  this.detachViewportListeners();
975
1288
  this.revertSingleDateDraftIfNeeded();
976
- // Put the popup back in its original slot BEFORE show=false so *ngIf removes it from the right
977
- // parent on the next change-detection pass (avoids leaving an orphan node in <body>).
978
- this.restorePopupFromBody();
1289
+ // Always reopen on the day grid, not whatever month/year drill-down the user left open.
1290
+ this.resetDrillDownViews();
1291
+ // CDK's cdkConnectedOverlayOpen="show" binding (see template) detaches the overlay once this
1292
+ // flips false — no manual DOM teardown needed.
979
1293
  this.show = false;
980
1294
  this.onTouched();
981
1295
  this.closed.emit();
982
1296
  }
983
- /** User preference before viewport adjustment (only used when popupPosition is not explicitly set). */
984
- preferPopupAbove() {
985
- return this.drop === 'up';
986
- }
987
1297
  resolveCustomRangesFromInputsOrService() {
988
1298
  const svc = this.calendarManager.getCustomRanges();
989
1299
  if (!this.customRanges) {
@@ -1043,6 +1353,12 @@ class BkCustomCalendar {
1043
1353
  if (!value.selectedDates || value.selectedDates.length === 0)
1044
1354
  return { required: true };
1045
1355
  }
1356
+ else if (this.isPickerViewActive()) {
1357
+ if (value.selectedYear == null)
1358
+ return { required: true };
1359
+ if (this.pickerView === 'month' && value.selectedMonth == null)
1360
+ return { required: true };
1361
+ }
1046
1362
  else {
1047
1363
  if (!value.startDate)
1048
1364
  return { required: true };
@@ -1084,8 +1400,11 @@ class BkCustomCalendar {
1084
1400
  this.startTime = null;
1085
1401
  this.endTime = null;
1086
1402
  this.selectedDates = [];
1403
+ this.selectedMonthValue = null;
1404
+ this.selectedYearValue = null;
1087
1405
  this.activeRange = null;
1088
1406
  this.resetEmbeddedTimePickerUiState();
1407
+ this.resetDrillDownViews();
1089
1408
  this.month = this.today.getMonth();
1090
1409
  this.year = this.today.getFullYear();
1091
1410
  this.generateCalendar();
@@ -1100,9 +1419,15 @@ class BkCustomCalendar {
1100
1419
  this.selectedDates = (s.selectedDates || []).map((d) => typeof d === 'string' ? this.parseDateString(d) : new Date(d));
1101
1420
  this.startTime = s.startTime ?? null;
1102
1421
  this.endTime = s.endTime ?? null;
1103
- const focusDate = this.startDate ?? this.endDate ?? new Date();
1422
+ this.selectedMonthValue = s.selectedMonth ?? null;
1423
+ this.selectedYearValue = s.selectedYear ?? null;
1424
+ const focusDate = this.startDate ?? this.endDate ??
1425
+ (this.selectedYearValue != null ? new Date(this.selectedYearValue, this.selectedMonthValue ?? 0, 1) : new Date());
1104
1426
  this.month = focusDate.getMonth();
1105
1427
  this.year = focusDate.getFullYear();
1428
+ // Runs after `this.year` above so a hydrated pickerView 'year' value re-centers the year grid
1429
+ // on that year (see resetDrillDownViews' own JSDoc), not whatever year was showing before.
1430
+ this.resetDrillDownViews();
1106
1431
  if (this.dualCalendar) {
1107
1432
  this.initializeDual();
1108
1433
  if (this.startDate) {
@@ -1204,30 +1529,32 @@ class BkCustomCalendar {
1204
1529
  const m = minute.toString().padStart(2, '0');
1205
1530
  return `${hour12}:${m} ${ampm}`;
1206
1531
  }
1207
- onClickOutside(event) {
1208
- // Don't handle click outside if inline mode is enabled
1209
- if (this.inline) {
1210
- return;
1211
- }
1212
- if (!this.show)
1213
- return;
1214
- const target = event.target;
1215
- // When appendToBody has relocated the popup to <body>, it is no longer a descendant of
1216
- // .calendar-container, so also treat clicks within the popup element itself as "inside".
1217
- const popupEl = this.calendarPopupRef?.nativeElement;
1218
- const insidePopup = !!popupEl && (popupEl === target || popupEl.contains(target));
1219
- if (!target.closest('.calendar-container') && !insidePopup) {
1220
- this.close();
1221
- }
1532
+ /**
1533
+ * CDK's overlay origin already excludes clicks on the trigger from outside-click dispatch by
1534
+ * design (same note in bk-popover's onOverlayOutsideClick), so the input's own (click)="toggle()"
1535
+ * stays the sole opener/closer via the trigger.
1536
+ */
1537
+ onOverlayOutsideClick() {
1538
+ this.close();
1539
+ }
1540
+ /** Fires whenever CDK (re)applies a position, including the first one after open. Reads back
1541
+ * which of `positionMeta`'s tagged entries CDK actually used, to drive the `drop-up` CSS class
1542
+ * (and its slide-up/slide-down animation) — the same value computePlacementAbove() used to. */
1543
+ onPositionChange(event) {
1544
+ const match = this.positionMeta.find(e => positionsEqual$1(e.pos, event.connectionPair));
1545
+ this.popupPlacementAbove = match?.above ?? false;
1222
1546
  }
1223
- /** True while capture-phase scroll + resize listeners are attached (only while the popup is open). */
1547
+ /** True while the capture-phase scroll/resize listener is attached (only while the popup is open). */
1224
1548
  viewportListenersAttached = false;
1225
1549
  /** Pending rAF id so bursts of scroll events collapse into one layout pass. */
1226
1550
  viewportRafId = null;
1227
1551
  /**
1228
- * Recipe steps 2 & 4: while the popup is open, keep it glued to the trigger as the page
1229
- * (or any nested scroll container) scrolls, and dismiss it once the trigger leaves the viewport.
1230
- * Throttled through requestAnimationFrame to avoid layout thrash during fast scrolling.
1552
+ * CDK's own scroll strategy only reacts to real `document`/`window` scroll it has no way to
1553
+ * know an app shell might scroll a nested container instead (a dashboard layout with a fixed
1554
+ * header/sidebar and a scrollable content pane, a dialog body, etc). A capture-phase listener on
1555
+ * `document` still sees scroll events fired on any descendant scrollable element (scroll doesn't
1556
+ * bubble, but capture does) — the same trick bk-popover uses. Throttled through
1557
+ * requestAnimationFrame to avoid layout thrash during fast scrolling.
1231
1558
  */
1232
1559
  onViewportChange = () => {
1233
1560
  if (this.viewportRafId != null)
@@ -1240,23 +1567,17 @@ class BkCustomCalendar {
1240
1567
  handleViewportChange() {
1241
1568
  if (!this.show || this.inline)
1242
1569
  return;
1243
- if (this.appendToBody) {
1244
- const trigger = this.inputWrapper?.nativeElement;
1245
- if (!trigger)
1246
- return;
1247
- const rect = trigger.getBoundingClientRect();
1248
- // Step 4: trigger scrolled fully out of view → close instead of leaving a floating panel behind.
1249
- if (this.isTriggerOutOfView(rect)) {
1250
- this.close();
1251
- return;
1252
- }
1253
- // Step 2: re-anchor (and re-flip) so the panel follows the trigger.
1254
- this.updatePosition();
1255
- }
1256
- else {
1257
- // Absolute-positioned popups track the trigger natively; just re-evaluate the flip.
1258
- this.refreshPopupPlacement();
1570
+ const trigger = this.inputWrapper?.nativeElement;
1571
+ if (!trigger)
1572
+ return;
1573
+ const rect = trigger.getBoundingClientRect();
1574
+ // Trigger scrolled fully out of view → close instead of leaving a floating panel behind.
1575
+ if (this.isTriggerOutOfView(rect)) {
1576
+ this.close();
1577
+ return;
1259
1578
  }
1579
+ // Re-run CDK's own flip/push so the panel follows the trigger.
1580
+ this.calendarOverlay?.overlayRef?.updatePosition();
1260
1581
  }
1261
1582
  /**
1262
1583
  * Trigger is no longer visible and the fixed popup should be dismissed. True when the trigger is
@@ -1311,6 +1632,9 @@ class BkCustomCalendar {
1311
1632
  }
1312
1633
  }
1313
1634
  ngOnInit() {
1635
+ // Covers the case where no ngModel/formControl is bound at all, so CVA's writeValue (which
1636
+ // also does this) never fires.
1637
+ this.resetDrillDownViews();
1314
1638
  this.resolveCustomRangesFromInputsOrService();
1315
1639
  if (this.dualCalendar)
1316
1640
  this.initializeDual();
@@ -1358,9 +1682,22 @@ class BkCustomCalendar {
1358
1682
  if (changes['customRanges'] || changes['rangeOrder']) {
1359
1683
  this.resolveCustomRangesFromInputsOrService();
1360
1684
  }
1685
+ // Only auto-revalidate when the constraint inputs change on their own — if the parent is also
1686
+ // pushing a fresh selectedValue in the same change (handled just above), trust that explicit
1687
+ // value instead of immediately clearing it against the new constraints.
1688
+ if ((changes['minDate'] || changes['maxDate'] || changes['allowedMonths'] || changes['allowedYears'] ||
1689
+ changes['allowedDaysOfWeek'] || changes['disabledDates'] || changes['allowedDates']) &&
1690
+ !changes['selectedValue']) {
1691
+ this.revalidateSelectionAgainstConstraints();
1692
+ }
1361
1693
  if (changes['weekDayLabels'] && !changes['weekDayLabels'].firstChange) {
1362
1694
  this.regenerateCalendarsForWeekStart();
1363
1695
  }
1696
+ // pickerView pins which grid the (closed) popup opens back into — re-resolve it if it changes
1697
+ // while the calendar isn't currently showing a drilled-in month/year grid of its own.
1698
+ if ((changes['pickerView'] || changes['dualCalendar'] || changes['singleDatePicker']) && !this.show) {
1699
+ this.resetDrillDownViews();
1700
+ }
1364
1701
  }
1365
1702
  regenerateCalendarsForWeekStart() {
1366
1703
  if (this.dualCalendar) {
@@ -1373,9 +1710,6 @@ class BkCustomCalendar {
1373
1710
  ngOnDestroy() {
1374
1711
  // Ensure global scroll/resize listeners never outlive the component
1375
1712
  this.detachViewportListeners();
1376
- // If destroyed while open with the popup relocated to <body>, put it back so Angular's teardown
1377
- // removes it from the expected parent instead of leaving an orphan node in <body>.
1378
- this.restorePopupFromBody();
1379
1713
  // Unregister this calendar instance
1380
1714
  if (this.unregisterFn) {
1381
1715
  this.unregisterFn();
@@ -1443,6 +1777,81 @@ class BkCustomCalendar {
1443
1777
  }
1444
1778
  }
1445
1779
  }
1780
+ /** True while the trigger input itself has DOM focus — tracked because a click on an already-
1781
+ * focused-but-closed input doesn't re-fire `focus` (no actual focus change happens), so
1782
+ * onTriggerMouseDown needs another way to know it should still open. Set/cleared by
1783
+ * onTriggerFocus/onTriggerBlur. */
1784
+ triggerHasFocus = false;
1785
+ /** Set immediately before {@link returnFocusToTrigger} programmatically refocuses the input, so
1786
+ * the resulting onTriggerFocus() doesn't treat "focus we just gave back after closing" as a
1787
+ * request to reopen the very popup it was asked to close. Consumed (cleared) by the next
1788
+ * onTriggerFocus() call — see its own comment. */
1789
+ suppressNextTriggerAutoOpen = false;
1790
+ /**
1791
+ * Opens the popup as soon as the trigger input receives focus — including via Tab, not just a
1792
+ * click. Guarded on `!this.show` so it's a no-op if something else already opened it. Also
1793
+ * consumes {@link suppressNextTriggerAutoOpen}: when {@link returnFocusToTrigger} refocuses the
1794
+ * input after Cancel/Apply closed the popup, this fires too (a genuine focus transition, same
1795
+ * as any other) — without the guard it would immediately reopen the popup right after closing
1796
+ * it.
1797
+ */
1798
+ onTriggerFocus() {
1799
+ this.triggerHasFocus = true;
1800
+ if (this.suppressNextTriggerAutoOpen) {
1801
+ this.suppressNextTriggerAutoOpen = false;
1802
+ return;
1803
+ }
1804
+ if (this.disabled)
1805
+ return;
1806
+ if (!this.show)
1807
+ this.toggle();
1808
+ }
1809
+ /** Pairs with (blur)="onTriggerBlur()" on the trigger input — keeps {@link triggerHasFocus} in
1810
+ * sync, on top of the pre-existing markAsTouched() call this replaces inline. */
1811
+ onTriggerBlur() {
1812
+ this.triggerHasFocus = false;
1813
+ this.markAsTouched();
1814
+ }
1815
+ /**
1816
+ * `mousedown` (not `click`) so this cooperates with {@link onTriggerFocus} instead of racing
1817
+ * it: `mousedown` fires *before* the browser's default focus shift, `focus` fires *after* it —
1818
+ * same click sequence, different moments.
1819
+ * - Not yet focused, closed: do nothing here — let the mousedown's own default focus shift
1820
+ * fire `onTriggerFocus` right after, which opens it. Exactly one open, no double-handling.
1821
+ * - Already focused (so `focus` won't fire again — no actual focus change) but somehow closed
1822
+ * (e.g. Cancel/Apply just closed it while focus was returned here): open it explicitly, since
1823
+ * nothing else will.
1824
+ * - Already open (and therefore already focused, since focus always opens): this click means
1825
+ * close — toggle closed, and preventDefault so the browser doesn't do anything odd with a
1826
+ * mousedown on an already-focused field it's about to lose visually.
1827
+ */
1828
+ onTriggerMouseDown(event) {
1829
+ if (this.disabled)
1830
+ return;
1831
+ if (this.show) {
1832
+ event.preventDefault();
1833
+ this.toggle();
1834
+ }
1835
+ else if (this.triggerHasFocus) {
1836
+ event.preventDefault();
1837
+ this.toggle();
1838
+ }
1839
+ }
1840
+ /**
1841
+ * Opens the popup from the keyboard once the trigger input has focus — Enter, Space, or
1842
+ * ArrowDown, the standard combobox/datepicker open keys. Focus alone already opens it (see
1843
+ * onTriggerFocus), so in practice this only matters if focus is regained without opening for
1844
+ * some other reason. Guarded on `!this.show` so it never re-closes an already-open popup.
1845
+ */
1846
+ onTriggerKeydownOpen(event) {
1847
+ // Always preventDefault — same as the old (keydown.enter) binding this replaces, so Enter
1848
+ // never submits an enclosing form, disabled or not.
1849
+ event.preventDefault();
1850
+ if (this.disabled)
1851
+ return;
1852
+ if (!this.show)
1853
+ this.toggle();
1854
+ }
1446
1855
  toggle() {
1447
1856
  if (this.disabled)
1448
1857
  return;
@@ -1458,19 +1867,11 @@ class BkCustomCalendar {
1458
1867
  this.calendarManager.closeAllExcept(this.closeFn);
1459
1868
  }
1460
1869
  this.disableHighlight = false;
1870
+ this.computeCalendarPositions();
1461
1871
  this.attachViewportListeners();
1462
1872
  setTimeout(() => {
1463
1873
  this.initKeyboardFocus();
1464
1874
  this.calendarPopupRef?.nativeElement?.focus({ preventScroll: true });
1465
- if (this.appendToBody && this.inputWrapper?.nativeElement) {
1466
- // Move the popup out to <body> first so any transformed/overflow ancestor can no longer
1467
- // re-anchor or clip its fixed positioning, then compute viewport coordinates.
1468
- this.movePopupToBody();
1469
- this.updatePosition();
1470
- }
1471
- else if (!this.inline) {
1472
- this.refreshPopupPlacement();
1473
- }
1474
1875
  }, 0);
1475
1876
  this.opened.emit();
1476
1877
  }
@@ -1478,132 +1879,92 @@ class BkCustomCalendar {
1478
1879
  this.finishPopupDismissal();
1479
1880
  }
1480
1881
  }
1481
- /** Update popup position when appendToBody is true (fixed positioning relative to viewport). */
1482
- updatePosition() {
1483
- if (!this.inputWrapper?.nativeElement)
1484
- return;
1485
- const rect = this.inputWrapper.nativeElement.getBoundingClientRect();
1486
- const popupEl = this.calendarPopupRef?.nativeElement;
1487
- const popupH = popupEl?.offsetHeight ?? 360;
1488
- const popupW = popupEl?.offsetWidth ?? 320;
1489
- const placeAbove = this.computePlacementAbove(rect, popupH);
1490
- this.popupPlacementAbove = placeAbove;
1491
- const left = this.computePopupLeft(rect, popupW);
1492
- const gap = 4;
1493
- if (placeAbove) {
1494
- this.dropdownStyle = {
1495
- bottom: `${window.innerHeight - rect.top + gap}px`,
1496
- left: `${left}px`,
1497
- };
1498
- }
1499
- else {
1500
- this.dropdownStyle = {
1501
- top: `${rect.bottom + gap}px`,
1502
- left: `${left}px`,
1503
- };
1504
- }
1505
- }
1506
- /**
1507
- * Horizontal placement for the fixed (appendToBody) popup.
1508
- *
1509
- * The base edge follows the author's {@link opens} preference:
1510
- * • 'left' → align left edges, panel opens rightwards (default)
1511
- * • 'right' → align right edges, panel opens leftwards
1512
- * • 'center' → centred on the trigger
1513
- * When {@link autoPosition} is on, the panel auto-flips to the opposite edge if the preferred
1514
- * side would overflow the viewport, then clamps to an 8px margin so it can never leave the screen.
1515
- * When autoPosition is off, the explicit `opens` value is honoured as-is.
1516
- */
1517
- computePopupLeft(rect, popupWidth) {
1518
- const margin = 8;
1519
- const viewportW = window.innerWidth;
1520
- // 1. Base alignment from the user-provided `opens`.
1521
- let left;
1522
- if (this.opens === 'right') {
1523
- left = rect.right - popupWidth; // align right edges → opens leftwards
1524
- }
1525
- else if (this.opens === 'center') {
1526
- left = rect.left + rect.width / 2 - popupWidth / 2;
1527
- }
1528
- else {
1529
- left = rect.left; // align left edges → opens rightwards
1530
- }
1531
- if (!this.autoPosition)
1532
- return left;
1533
- // 2. Auto-flip to the opposite edge when the preferred side overflows the viewport.
1534
- if (left + popupWidth > viewportW - margin) {
1535
- left = rect.right - popupWidth; // flip: open leftwards
1536
- }
1537
- if (left < margin) {
1538
- left = rect.left; // flip back: open rightwards
1539
- }
1540
- // 3. Final clamp so the panel always stays fully on screen on both edges.
1541
- left = Math.min(left, viewportW - popupWidth - margin);
1542
- left = Math.max(left, margin);
1543
- return left;
1544
- }
1545
- /** Non–append-to-body: set `popupPlacementAbove` for CSS `drop-up` with viewport flip. */
1546
- refreshPopupPlacement() {
1547
- if (!this.inputWrapper?.nativeElement)
1548
- return;
1549
- const rect = this.inputWrapper.nativeElement.getBoundingClientRect();
1550
- const popupH = this.calendarPopupRef?.nativeElement?.offsetHeight ?? 360;
1551
- this.popupPlacementAbove = this.computePlacementAbove(rect, popupH);
1552
- }
1553
- computePlacementAbove(rect, popupHeight) {
1554
- // If the consumer explicitly set popupPosition, honour it — no space-check override.
1555
- if (this.popupPosition === 'top')
1556
- return true;
1557
- if (this.popupPosition === 'bottom')
1558
- return false;
1559
- // Space-based auto-flip is opt-in. When disabled, just honour the `drop` preference.
1560
- if (!this.autoPosition) {
1561
- return this.preferPopupAbove();
1562
- }
1563
- // autoPosition enabled → auto-detect based on available viewport space.
1564
- const gap = 12;
1565
- const spaceBelow = window.innerHeight - rect.bottom - gap;
1566
- const spaceAbove = rect.top - gap;
1567
- const preferAbove = this.preferPopupAbove();
1568
- if (preferAbove) {
1569
- return spaceAbove >= popupHeight || spaceAbove >= spaceBelow;
1570
- }
1571
- if (spaceBelow >= popupHeight || spaceBelow >= spaceAbove)
1572
- return false;
1573
- return true;
1574
- }
1575
- /** Normalize to local midnight and clamp to min/max selectable day. */
1576
- clampCalendarDayToSelectableRange(d) {
1577
- let x = new Date(d.getFullYear(), d.getMonth(), d.getDate());
1882
+ /** minDate/maxDate day clamp, factored out so {@link clampCalendarDayToSelectableRange} can
1883
+ * apply it a second time after jumping to a different month (see there for why). */
1884
+ clampToMinMax(date) {
1885
+ let x = date;
1578
1886
  if (this.minDate) {
1579
1887
  const min = new Date(this.minDate.getFullYear(), this.minDate.getMonth(), this.minDate.getDate());
1580
1888
  if (x < min)
1581
- x = new Date(min.getFullYear(), min.getMonth(), min.getDate());
1889
+ x = min;
1582
1890
  }
1583
1891
  if (this.maxDate) {
1584
1892
  const max = new Date(this.maxDate.getFullYear(), this.maxDate.getMonth(), this.maxDate.getDate());
1585
1893
  if (x > max)
1586
- x = new Date(max.getFullYear(), max.getMonth(), max.getDate());
1894
+ x = max;
1895
+ }
1896
+ return x;
1897
+ }
1898
+ /** Nearest month (year+month pair) to `month`/`year` that isn't disabled — i.e. that has at
1899
+ * least one selectable day once minDate/maxDate AND allowedMonths AND allowedYears are all
1900
+ * applied (see isMonthDisabled). Searches outward a month at a time, forward and back in
1901
+ * lockstep, so it finds the true nearest regardless of which side the given month missed on.
1902
+ * Bounded to 50 years either way as a safety net against a contradictory config (e.g.
1903
+ * allowedYears entirely outside minDate/maxDate) that has no answer at all — returns the
1904
+ * original month/year unchanged in that case. */
1905
+ nearestSelectableMonth(month, year) {
1906
+ if (!this.isMonthDisabled(month, year))
1907
+ return { month, year };
1908
+ for (let offset = 1; offset <= 600; offset++) {
1909
+ for (const dir of [1, -1]) {
1910
+ const total = year * 12 + month + dir * offset;
1911
+ const y = Math.floor(total / 12);
1912
+ const m = ((total % 12) + 12) % 12;
1913
+ if (!this.isMonthDisabled(m, y))
1914
+ return { month: m, year: y };
1915
+ }
1916
+ }
1917
+ return { month, year };
1918
+ }
1919
+ /**
1920
+ * Normalize to local midnight, clamp into [minDate, maxDate], then — if that alone still lands
1921
+ * on a month allowedMonths/allowedYears excludes — jump to the nearest month that actually has
1922
+ * a selectable day. Without this, opening the calendar (or narrowing allowedMonths/allowedYears
1923
+ * while a stale view was showing) could land squarely on a dead month: minDate/maxDate-valid but
1924
+ * allowedMonths-disabled, e.g. minDate falls in August with allowedMonths excluding it — since
1925
+ * month/year nav stays deliberately unguarded (see nextMonth/prevMonth), the user would have to
1926
+ * page there by hand with no indication which direction to go. Re-clamps to minDate/maxDate
1927
+ * after the jump too, in case the nearest allowed month is the very month minDate or maxDate
1928
+ * falls in (the 1st of that month alone could still sit outside the day-level bound). If
1929
+ * nearestSelectableMonth can't find anything better at all (a self-contradictory config, e.g.
1930
+ * allowedYears entirely outside minDate/maxDate — it then returns the same month/year back
1931
+ * unchanged), this leaves the original clamped day exactly as-is instead of needlessly
1932
+ * resetting it to the 1st for no actual improvement.
1933
+ */
1934
+ clampCalendarDayToSelectableRange(d) {
1935
+ let x = this.clampToMinMax(new Date(d.getFullYear(), d.getMonth(), d.getDate()));
1936
+ if (this.isMonthDisabled(x.getMonth(), x.getFullYear())) {
1937
+ const nearest = this.nearestSelectableMonth(x.getMonth(), x.getFullYear());
1938
+ if (nearest.month !== x.getMonth() || nearest.year !== x.getFullYear()) {
1939
+ x = this.clampToMinMax(new Date(nearest.year, nearest.month, 1));
1940
+ }
1587
1941
  }
1588
1942
  return x;
1589
1943
  }
1590
1944
  initKeyboardFocus() {
1591
1945
  if (!this.inline && !this.show)
1592
1946
  return;
1947
+ // pickerView 'month'/'year' selections never populate startDate/endDate (only
1948
+ // selectedMonthValue/selectedYearValue — see commitMonthYearSelection), so without this
1949
+ // fallback this always fell through to today, and ensureKeyboardFocusVisible() below would
1950
+ // then silently reset this.month/this.year to today on every reopen — wiping the "active"
1951
+ // highlight off a previously committed month/year selection.
1593
1952
  const base = this.startDate ??
1594
1953
  this.endDate ??
1954
+ (this.selectedYearValue != null ? new Date(this.selectedYearValue, this.selectedMonthValue ?? 0, 1) : null) ??
1595
1955
  new Date(this.today.getFullYear(), this.today.getMonth(), this.today.getDate());
1596
1956
  const d = this.clampCalendarDayToSelectableRange(new Date(base.getFullYear(), base.getMonth(), base.getDate()));
1597
1957
  this.keyboardFocusDate = d;
1598
1958
  this.ensureKeyboardFocusVisible();
1599
1959
  }
1600
1960
  /**
1601
- * After clearing values, drop stale keyboard highlight (was last start/end) and reset the
1602
- * visible month(s) to today (clamped). Move DOM focus to the popup when open, else the input.
1961
+ * Re-centers the visible month(s) and keyboard focus on `date` (clamped into the selectable
1962
+ * range). Shared by {@link resetCalendarFocusAfterClear} and
1963
+ * {@link revalidateSelectionAgainstConstraints} — callers differ only in whether they also
1964
+ * steal DOM focus afterwards.
1603
1965
  */
1604
- resetCalendarFocusAfterClear() {
1605
- const todayLocal = new Date(this.today.getFullYear(), this.today.getMonth(), this.today.getDate());
1606
- this.keyboardFocusDate = this.clampCalendarDayToSelectableRange(todayLocal);
1966
+ recenterCalendarOn(date) {
1967
+ this.keyboardFocusDate = this.clampCalendarDayToSelectableRange(date);
1607
1968
  if (this.dualCalendar) {
1608
1969
  this.leftMonth = this.keyboardFocusDate.getMonth();
1609
1970
  this.leftYear = this.keyboardFocusDate.getFullYear();
@@ -1620,8 +1981,66 @@ class BkCustomCalendar {
1620
1981
  this.year = this.keyboardFocusDate.getFullYear();
1621
1982
  this.generateCalendar();
1622
1983
  }
1984
+ }
1985
+ /**
1986
+ * After clearing values, drop stale keyboard highlight (was last start/end) and reset the
1987
+ * visible month(s) to today (clamped). Move DOM focus to the popup when open, else the input.
1988
+ */
1989
+ resetCalendarFocusAfterClear() {
1990
+ const todayLocal = new Date(this.today.getFullYear(), this.today.getMonth(), this.today.getDate());
1991
+ this.recenterCalendarOn(todayLocal);
1623
1992
  this.scheduleDomFocusAfterClear();
1624
1993
  }
1994
+ /**
1995
+ * Called from {@link ngOnChanges} when any of `minDate`/`maxDate`/`allowedMonths`/
1996
+ * `allowedYears`/`allowedDaysOfWeek`/`disabledDates`/`allowedDates` change: clears any existing
1997
+ * selection that no longer satisfies all of them — e.g. a date picked before the range was
1998
+ * tightened, or before allowedMonths excluded its month — instead of leaving it displayed as
1999
+ * "selected" while every cell that could represent it is now disabled. Delegates to {@link
2000
+ * isDateDisabled} so this can never drift from what the day grid itself considers selectable.
2001
+ * Re-emits so the bound model stays in sync with what's actually shown, and re-centers the
2002
+ * visible month(s) on the closest still-valid day so the user isn't left staring at a month
2003
+ * that no longer contains their selection.
2004
+ */
2005
+ revalidateSelectionAgainstConstraints() {
2006
+ if (!this.minDate && !this.maxDate &&
2007
+ !this.allowedMonths?.length && !this.allowedYears?.length &&
2008
+ !this.allowedDaysOfWeek?.length && !this.disabledDates?.length && !this.allowedDates?.length)
2009
+ return;
2010
+ const isOutOfRange = (d) => !!d && this.isDateDisabled(d.getFullYear(), d.getMonth(), d.getDate());
2011
+ let changed = false;
2012
+ if (this.multiDateSelection) {
2013
+ const filtered = this.selectedDates.filter(d => !isOutOfRange(d));
2014
+ if (filtered.length !== this.selectedDates.length) {
2015
+ this.selectedDates = filtered;
2016
+ this.startDate = filtered.length ? new Date(filtered[0]) : null;
2017
+ this.endDate = filtered.length ? new Date(filtered[filtered.length - 1]) : null;
2018
+ changed = true;
2019
+ }
2020
+ }
2021
+ else {
2022
+ if (isOutOfRange(this.startDate)) {
2023
+ this.startDate = null;
2024
+ this.startTime = null;
2025
+ changed = true;
2026
+ }
2027
+ if (isOutOfRange(this.endDate)) {
2028
+ this.endDate = null;
2029
+ this.endTime = null;
2030
+ changed = true;
2031
+ }
2032
+ }
2033
+ if (changed) {
2034
+ this.activeRange = (this.startDate || this.endDate || this.selectedDates.length) ? 'Custom Range' : null;
2035
+ if (this.startDate && this.endDate)
2036
+ this.checkAndSetActiveRange();
2037
+ this.emitSelection();
2038
+ }
2039
+ // Re-center on the closest still-valid day (today, clamped into range) so the visible month
2040
+ // always shows at least the one day that's actually selectable after the range tightens.
2041
+ const todayLocal = new Date(this.today.getFullYear(), this.today.getMonth(), this.today.getDate());
2042
+ this.recenterCalendarOn(this.startDate ?? this.endDate ?? todayLocal);
2043
+ }
1625
2044
  scheduleDomFocusAfterClear() {
1626
2045
  setTimeout(() => {
1627
2046
  if (this.show || this.inline) {
@@ -1629,7 +2048,13 @@ class BkCustomCalendar {
1629
2048
  return;
1630
2049
  }
1631
2050
  const inputEl = this.inputWrapper?.nativeElement?.querySelector('.calendar-input');
1632
- inputEl?.focus({ preventScroll: true });
2051
+ if (!inputEl)
2052
+ return;
2053
+ // Same guard returnFocusToTrigger() uses: onTriggerFocus() opens the popup on any real
2054
+ // focus transition (for Tab/keyboard access), so this programmatic refocus-after-clear
2055
+ // would otherwise immediately reopen the very popup Clear is meant to leave closed.
2056
+ this.suppressNextTriggerAutoOpen = true;
2057
+ inputEl.focus({ preventScroll: true });
1633
2058
  }, 0);
1634
2059
  }
1635
2060
  ensureKeyboardFocusVisible() {
@@ -1713,6 +2138,49 @@ class BkCustomCalendar {
1713
2138
  else if (k === 'Enter' || k === ' ')
1714
2139
  this.applyKeyboardSelection();
1715
2140
  }
2141
+ /**
2142
+ * CDK portals the popup into `.cdk-overlay-container` (position: fixed, full-viewport). Some
2143
+ * browsers don't chain a wheel scroll from inside that fixed container back out to the page
2144
+ * underneath, so hovering the (non-inline) popup and scrolling silently does nothing instead of
2145
+ * scrolling the page — breaking the "popup follows the trigger as the page scrolls" behaviour
2146
+ * the viewport-tracking above exists for. Forward the wheel delta to the page manually, but only
2147
+ * once nothing inside the popup can still consume it: walk up from the actual wheel target
2148
+ * looking for a genuinely scrollable ancestor with room left in that direction — e.g. the time
2149
+ * picker's minute/second `.time-scroll` wheel, or the whole popup once `@media
2150
+ * (max-width:1024px)` makes it scroll — and let that handle it natively instead.
2151
+ */
2152
+ onCalendarPopupWheel(event) {
2153
+ if (this.inline)
2154
+ return;
2155
+ const popup = event.currentTarget;
2156
+ let el = event.target;
2157
+ while (el) {
2158
+ if (this.canElementConsumeWheel(el, event.deltaY))
2159
+ return;
2160
+ if (el === popup)
2161
+ break;
2162
+ el = el.parentElement;
2163
+ }
2164
+ // Angular/zone.js may register (wheel) as a passive listener, in which case preventDefault()
2165
+ // is a silent no-op (and a console warning if called unconditionally) — guard it. Nothing here
2166
+ // depends on it succeeding: there was no native scroll happening to prevent in the first
2167
+ // place (that's the bug), window.scrollBy() below is the actual fix.
2168
+ if (event.cancelable)
2169
+ event.preventDefault();
2170
+ window.scrollBy({ left: event.deltaX, top: event.deltaY });
2171
+ }
2172
+ /** True when `el` is a scroll container with room left to move further in `deltaY`'s direction. */
2173
+ canElementConsumeWheel(el, deltaY) {
2174
+ const style = getComputedStyle(el);
2175
+ const scrollable = /(auto|scroll)/.test(style.overflowY) && el.scrollHeight > el.clientHeight;
2176
+ if (!scrollable)
2177
+ return false;
2178
+ if (deltaY < 0)
2179
+ return el.scrollTop > 0;
2180
+ if (deltaY > 0)
2181
+ return el.scrollTop + el.clientHeight < el.scrollHeight;
2182
+ return false;
2183
+ }
1716
2184
  applyKeyboardSelection() {
1717
2185
  if (!this.keyboardFocusDate)
1718
2186
  return;
@@ -1790,10 +2258,12 @@ class BkCustomCalendar {
1790
2258
  }
1791
2259
  // Clear hover on selection
1792
2260
  this.hoveredDate = null;
1793
- // Check min/max date constraints
1794
- if (this.minDate && selected < this.minDate)
1795
- return;
1796
- if (this.maxDate && selected > this.maxDate)
2261
+ // Reject anything the day grid itself marks unselectable — minDate/maxDate AND
2262
+ // allowedMonths/allowedYears (see isDateDisabled). This used to re-check minDate/maxDate
2263
+ // inline and nothing else, which let a keyboard-committed selection (Enter on a
2264
+ // keyboard-focused cell, via applyKeyboardSelection — the template's own click guard doesn't
2265
+ // run for that path) bypass allowedMonths/allowedYears entirely.
2266
+ if (this.isDateDisabled(selected.getFullYear(), selected.getMonth(), selected.getDate()))
1797
2267
  return;
1798
2268
  this.keyboardFocusDate = new Date(selected.getFullYear(), selected.getMonth(), selected.getDate());
1799
2269
  // Multi-date selection mode
@@ -2000,6 +2470,7 @@ class BkCustomCalendar {
2000
2470
  this.disableHighlight = true;
2001
2471
  this.onTouched();
2002
2472
  this.close();
2473
+ this.returnFocusToTrigger();
2003
2474
  }
2004
2475
  cancel() {
2005
2476
  if (this.disabled)
@@ -2013,6 +2484,30 @@ class BkCustomCalendar {
2013
2484
  // this.selectedDates = [];
2014
2485
  // this.resetCalendarFocusAfterClear();
2015
2486
  this.close();
2487
+ this.returnFocusToTrigger();
2488
+ }
2489
+ /**
2490
+ * Returns keyboard focus to the trigger input after an explicit in-popup dismissal (Cancel /
2491
+ * Apply). Without this, focus is left on the Cancel/Apply button as the (portalled) popup tears
2492
+ * down out from under it — the browser then drops focus to <body>, so a keyboard user loses
2493
+ * their place entirely and Tab restarts from the top of the page instead of continuing from the
2494
+ * calendar. Not called from the generic outside-click/scroll-out dismissal path (finishPopupDismissal) —
2495
+ * there the user's own click already established where focus should go; forcing it back to the
2496
+ * trigger would fight that. setTimeout(0) mirrors scheduleDomFocusAfterClear: it defers past the
2497
+ * click's own default focus handling (which would otherwise re-focus the Cancel/Apply button
2498
+ * right after and win the race against a synchronous call here).
2499
+ */
2500
+ returnFocusToTrigger() {
2501
+ setTimeout(() => {
2502
+ const inputEl = this.inputWrapper?.nativeElement?.querySelector('.calendar-input');
2503
+ if (!inputEl)
2504
+ return;
2505
+ // Only set right before a focus() call actually happens — onTriggerFocus() is the only
2506
+ // place that clears it, so setting it with no matching focus() call would leave it stuck,
2507
+ // silently swallowing the next legitimate focus-to-open.
2508
+ this.suppressNextTriggerAutoOpen = true;
2509
+ inputEl.focus({ preventScroll: true });
2510
+ }, 0);
2016
2511
  }
2017
2512
  clear() {
2018
2513
  if (this.disabled)
@@ -2022,11 +2517,22 @@ class BkCustomCalendar {
2022
2517
  this.startTime = null;
2023
2518
  this.endTime = null;
2024
2519
  this.selectedDates = [];
2520
+ this.selectedMonthValue = null;
2521
+ this.selectedYearValue = null;
2025
2522
  this.activeRange = null;
2026
2523
  this.resetEmbeddedTimePickerUiState();
2524
+ this.resetDrillDownViews();
2027
2525
  this.resetCalendarFocusAfterClear();
2028
2526
  this.emitSelection();
2029
2527
  }
2528
+ /**
2529
+ * Applies a preset range (Today/Yesterday/Last 7 days/etc.) or activates "Custom Range".
2530
+ * Deliberately does NOT check minDate/maxDate/allowedMonths/allowedYears/allowedDaysOfWeek/
2531
+ * disabledDates/allowedDates — those constraints are scoped to manual day-grid picking only
2532
+ * (selectDate() routes through isDateDisabled before ever setting startDate/endDate; this does
2533
+ * not). A preset always applies exactly as configured, even if part of it falls outside those
2534
+ * constraints — isDateSelected() has a matching note on why it doesn't re-check them either.
2535
+ */
2030
2536
  chooseRange(key) {
2031
2537
  if (this.disabled || !this.customRanges)
2032
2538
  return;
@@ -2127,6 +2633,7 @@ class BkCustomCalendar {
2127
2633
  emitSelection() {
2128
2634
  const hasValue = this.startDate != null ||
2129
2635
  this.endDate != null ||
2636
+ this.selectedYearValue != null ||
2130
2637
  (this.multiDateSelection && this.selectedDates.length > 0);
2131
2638
  if (!hasValue) {
2132
2639
  this.selectedValue = null;
@@ -2137,6 +2644,8 @@ class BkCustomCalendar {
2137
2644
  startTime: null,
2138
2645
  endTime: null,
2139
2646
  selectedDates: [],
2647
+ selectedMonth: null,
2648
+ selectedYear: null,
2140
2649
  });
2141
2650
  return;
2142
2651
  }
@@ -2145,6 +2654,8 @@ class BkCustomCalendar {
2145
2654
  endDate: this.endDate ? this.formatDateToString(this.endDate) : null,
2146
2655
  startTime: this.startTime ?? null,
2147
2656
  endTime: this.endTime ?? null,
2657
+ selectedMonth: this.selectedMonthValue,
2658
+ selectedYear: this.selectedYearValue,
2148
2659
  };
2149
2660
  if (this.multiDateSelection && this.selectedDates.length > 0) {
2150
2661
  selection.selectedDates = this.selectedDates.map((d) => this.formatDateToString(d));
@@ -2221,6 +2732,377 @@ class BkCustomCalendar {
2221
2732
  }
2222
2733
  this.rightCalendar = this.buildCalendar(this.rightYear, this.rightMonth);
2223
2734
  }
2735
+ // --------------------------------------------------------------------
2736
+ // Header year jump (the "<<" / ">>" chevrons) — steps a whole year at a
2737
+ // time while staying on the day grid. Independent per side in dual mode,
2738
+ // mirroring the existing prevMonth/prevLeftMonth/prevRightMonth split.
2739
+ // --------------------------------------------------------------------
2740
+ nextYear() {
2741
+ if (this.isNextYearDisabled(this.year))
2742
+ return;
2743
+ this.year++;
2744
+ this.generateCalendar();
2745
+ }
2746
+ prevYear() {
2747
+ if (this.isPrevYearDisabled(this.year))
2748
+ return;
2749
+ this.year--;
2750
+ this.generateCalendar();
2751
+ }
2752
+ nextLeftYear() {
2753
+ if (this.isNextYearDisabled(this.leftYear))
2754
+ return;
2755
+ this.leftYear++;
2756
+ this.leftCalendar = this.buildCalendar(this.leftYear, this.leftMonth);
2757
+ }
2758
+ prevLeftYear() {
2759
+ if (this.isPrevYearDisabled(this.leftYear))
2760
+ return;
2761
+ this.leftYear--;
2762
+ this.leftCalendar = this.buildCalendar(this.leftYear, this.leftMonth);
2763
+ }
2764
+ nextRightYear() {
2765
+ if (this.isNextYearDisabled(this.rightYear))
2766
+ return;
2767
+ this.rightYear++;
2768
+ this.rightCalendar = this.buildCalendar(this.rightYear, this.rightMonth);
2769
+ }
2770
+ prevRightYear() {
2771
+ if (this.isPrevYearDisabled(this.rightYear))
2772
+ return;
2773
+ this.rightYear--;
2774
+ this.rightCalendar = this.buildCalendar(this.rightYear, this.rightMonth);
2775
+ }
2776
+ /** Drives both the click guard and the `<<`/`>>` chevrons' disabled state. */
2777
+ isNextYearDisabled(currentYear) {
2778
+ return !!this.disabled || (!!this.maxDate && currentYear + 1 > this.maxDate.getFullYear());
2779
+ }
2780
+ isPrevYearDisabled(currentYear) {
2781
+ return !!this.disabled || (!!this.minDate && currentYear - 1 < this.minDate.getFullYear());
2782
+ }
2783
+ // --------------------------------------------------------------------
2784
+ // Month / year quick-pick (click "August" or "2026" in the header).
2785
+ // Picking a month or a year drops straight back to the day grid — there
2786
+ // is no intermediate step chaining the two views together.
2787
+ // --------------------------------------------------------------------
2788
+ computeYearRangeStart(year) {
2789
+ return Math.floor(year / 12) * 12;
2790
+ }
2791
+ /** The 12 years shown in an open year-grid, given its page anchor. */
2792
+ getYearGridYears(rangeStart) {
2793
+ return Array.from({ length: 12 }, (_, i) => rangeStart + i);
2794
+ }
2795
+ /** {@link allowedMonths} (1-based) converted to the 0-based month indices used everywhere
2796
+ * internally — JS `Date.getMonth()`, `this.month`, the month grid's own loop index. */
2797
+ get allowedMonthsZeroBased() {
2798
+ return this.allowedMonths?.map(m => m - 1);
2799
+ }
2800
+ /** {@link allowedDaysOfWeek} (1-based) converted to the 0-based weekday indices JS
2801
+ * `Date.getDay()` uses. */
2802
+ get allowedDaysOfWeekZeroBased() {
2803
+ return this.allowedDaysOfWeek?.map(d => d - 1);
2804
+ }
2805
+ /** True if `list` contains a Date matching `year`/`month`/`day` — compared by calendar day
2806
+ * only, same normalize-to-midnight reasoning as every other date comparison in this file (see
2807
+ * isDateDisabled). Backs {@link disabledDates}/{@link allowedDates}. */
2808
+ dateListIncludes(list, year, month, day) {
2809
+ if (!list?.length)
2810
+ return false;
2811
+ return list.some(d => d.getFullYear() === year && d.getMonth() === month && d.getDate() === day);
2812
+ }
2813
+ /** minDate/maxDate checked first, then allowedMonths — same precedence as isDateDisabled/
2814
+ * isYearDisabled (AND overall, so check order doesn't change the result, only readability). */
2815
+ isMonthDisabled(month, year) {
2816
+ const monthStart = new Date(year, month, 1);
2817
+ const monthEnd = new Date(year, month + 1, 0);
2818
+ if (this.minDate) {
2819
+ const min = new Date(this.minDate.getFullYear(), this.minDate.getMonth(), this.minDate.getDate());
2820
+ if (monthEnd < min)
2821
+ return true;
2822
+ }
2823
+ if (this.maxDate) {
2824
+ const max = new Date(this.maxDate.getFullYear(), this.maxDate.getMonth(), this.maxDate.getDate());
2825
+ if (monthStart > max)
2826
+ return true;
2827
+ }
2828
+ if (this.allowedMonthsZeroBased?.length && !this.allowedMonthsZeroBased.includes(month))
2829
+ return true;
2830
+ // A month's own year must also be allowed — otherwise paging the month grid to a year outside
2831
+ // allowedYears (nav stays unguarded, same as the day grid's month nav) left every month in it
2832
+ // showing as selectable, since nothing here previously consulted allowedYears at all.
2833
+ if (this.allowedYears?.length && !this.allowedYears.includes(year))
2834
+ return true;
2835
+ return false;
2836
+ }
2837
+ /** minDate/maxDate checked first, then allowedYears — see isMonthDisabled's note on ordering. */
2838
+ isYearDisabled(year) {
2839
+ const yearStart = new Date(year, 0, 1);
2840
+ const yearEnd = new Date(year, 11, 31);
2841
+ if (this.minDate) {
2842
+ const min = new Date(this.minDate.getFullYear(), this.minDate.getMonth(), this.minDate.getDate());
2843
+ if (yearEnd < min)
2844
+ return true;
2845
+ }
2846
+ if (this.maxDate) {
2847
+ const max = new Date(this.maxDate.getFullYear(), this.maxDate.getMonth(), this.maxDate.getDate());
2848
+ if (yearStart > max)
2849
+ return true;
2850
+ }
2851
+ if (this.allowedYears?.length && !this.allowedYears.includes(year))
2852
+ return true;
2853
+ return false;
2854
+ }
2855
+ /** 0-based entry in {@link allowedMonthsZeroBased} nearest to `month`, ties broken toward the
2856
+ * earlier one. */
2857
+ nearestAllowedMonth(month) {
2858
+ return this.allowedMonthsZeroBased.reduce((best, m) => Math.abs(m - month) < Math.abs(best - month) ? m : best);
2859
+ }
2860
+ /** If switching to `year` would leave the current month disabled, snap it back inside range. */
2861
+ clampMonthForYear(month, year) {
2862
+ if (!this.isMonthDisabled(month, year))
2863
+ return month;
2864
+ if (this.minDate && year === this.minDate.getFullYear())
2865
+ return this.minDate.getMonth();
2866
+ if (this.maxDate && year === this.maxDate.getFullYear())
2867
+ return this.maxDate.getMonth();
2868
+ if (this.allowedMonths?.length)
2869
+ return this.nearestAllowedMonth(month);
2870
+ return month;
2871
+ }
2872
+ /** True when `pickerView` actually restricts this calendar to a month/year grid — single-date
2873
+ * only, per its JSDoc; dual/range calendars always use the day grid regardless of the input. */
2874
+ isPickerViewActive() {
2875
+ return this.pickerView !== 'day' && this.singleDatePicker && !this.dualCalendar;
2876
+ }
2877
+ /** The view a single calendar starts on / collapses back to: the day grid, unless `pickerView`
2878
+ * pins it to the month or year grid instead — there is no day grid to fall back to there. */
2879
+ baseView() {
2880
+ if (!this.isPickerViewActive())
2881
+ return 'days';
2882
+ return this.pickerView === 'month' ? 'months' : 'years';
2883
+ }
2884
+ /** Collapse any open month/year grid back to {@link baseView} (called whenever the popup resets).
2885
+ * When that lands on the year grid, also re-centers {@link yearRangeStart} on `this.year` — the
2886
+ * grid is otherwise never reached via {@link openYearView} (the only other place that sets it),
2887
+ * so it would stay at its `0` default and show the wrong 12-year page. */
2888
+ resetDrillDownViews() {
2889
+ this.view = this.baseView();
2890
+ if (this.view === 'years')
2891
+ this.yearRangeStart = this.computeYearRangeStart(this.year);
2892
+ this.leftView = 'days';
2893
+ this.rightView = 'days';
2894
+ }
2895
+ // Single calendar ------------------------------------------------------
2896
+ openMonthView() {
2897
+ if (this.disabled)
2898
+ return;
2899
+ this.view = 'months';
2900
+ }
2901
+ /** Year-changing chevrons shown alongside the month grid — shift its year without leaving the view. */
2902
+ prevMonthGridYear() {
2903
+ if (this.isPrevYearDisabled(this.year))
2904
+ return;
2905
+ this.year--;
2906
+ }
2907
+ nextMonthGridYear() {
2908
+ if (this.isNextYearDisabled(this.year))
2909
+ return;
2910
+ this.year++;
2911
+ }
2912
+ openYearView() {
2913
+ if (this.disabled)
2914
+ return;
2915
+ this.yearRangeStart = this.computeYearRangeStart(this.year);
2916
+ this.view = 'years';
2917
+ }
2918
+ prevYearRange() {
2919
+ this.yearRangeStart -= 12;
2920
+ }
2921
+ nextYearRange() {
2922
+ this.yearRangeStart += 12;
2923
+ }
2924
+ selectMonthFromGrid(month) {
2925
+ if (this.isMonthDisabled(month, this.year))
2926
+ return;
2927
+ this.month = month;
2928
+ // pickerView 'month': picking a month IS the final selection — commit and close, same as
2929
+ // autoApply. There is no day grid to drill into here.
2930
+ if (this.pickerView === 'month' && this.isPickerViewActive()) {
2931
+ this.commitMonthYearSelection(this.year, month);
2932
+ return;
2933
+ }
2934
+ this.generateCalendar();
2935
+ this.view = 'days';
2936
+ }
2937
+ selectYearFromGrid(year) {
2938
+ if (this.isYearDisabled(year))
2939
+ return;
2940
+ this.year = year;
2941
+ this.month = this.clampMonthForYear(this.month, year);
2942
+ // pickerView 'year': picking a year IS the final selection — commit and close.
2943
+ if (this.pickerView === 'year' && this.isPickerViewActive()) {
2944
+ this.commitMonthYearSelection(year, null);
2945
+ return;
2946
+ }
2947
+ // pickerView 'month': the year grid here is only reached via the month grid's own "change
2948
+ // year" header button — return to the month grid on the newly chosen year rather than
2949
+ // finalizing (the month is the thing being picked, not the year on its own).
2950
+ if (this.pickerView === 'month' && this.isPickerViewActive()) {
2951
+ this.view = 'months';
2952
+ return;
2953
+ }
2954
+ this.generateCalendar();
2955
+ this.view = 'days';
2956
+ }
2957
+ /** Commits a `pickerView` 'month'/'year' selection: populates {@link selectedMonthValue}/
2958
+ * {@link selectedYearValue}, emits, and closes the popup (unless inline) — the same "pick →
2959
+ * done" flow `autoApply` gives the day grid. */
2960
+ commitMonthYearSelection(year, month) {
2961
+ this.selectedYearValue = year;
2962
+ this.selectedMonthValue = month;
2963
+ this.activeRange = null;
2964
+ this.emitSelection();
2965
+ this.disableHighlight = true;
2966
+ this.onTouched();
2967
+ if (!this.inline) {
2968
+ this.close();
2969
+ this.returnFocusToTrigger();
2970
+ }
2971
+ }
2972
+ /** "Today" quick-jump shown at the bottom of the month/year grids — jumps to today's month/year.
2973
+ * In `pickerView` 'month'/'year' mode this finalizes the selection there; otherwise it jumps
2974
+ * back to the day grid and selects today's date. */
2975
+ goToToday() {
2976
+ if (this.disabled)
2977
+ return;
2978
+ const t = this.today;
2979
+ if (this.isDateDisabled(t.getFullYear(), t.getMonth(), t.getDate()))
2980
+ return;
2981
+ this.month = t.getMonth();
2982
+ this.year = t.getFullYear();
2983
+ if (this.isPickerViewActive()) {
2984
+ if (this.pickerView === 'month')
2985
+ this.selectMonthFromGrid(this.month);
2986
+ else
2987
+ this.selectYearFromGrid(this.year);
2988
+ return;
2989
+ }
2990
+ this.generateCalendar();
2991
+ this.view = 'days';
2992
+ this.selectDate(t.getDate());
2993
+ }
2994
+ // Dual calendar — left --------------------------------------------------
2995
+ openLeftMonthView() {
2996
+ if (this.disabled)
2997
+ return;
2998
+ this.leftView = 'months';
2999
+ }
3000
+ prevLeftMonthGridYear() {
3001
+ if (this.isPrevYearDisabled(this.leftYear))
3002
+ return;
3003
+ this.leftYear--;
3004
+ }
3005
+ nextLeftMonthGridYear() {
3006
+ if (this.isNextYearDisabled(this.leftYear))
3007
+ return;
3008
+ this.leftYear++;
3009
+ }
3010
+ openLeftYearView() {
3011
+ if (this.disabled)
3012
+ return;
3013
+ this.leftYearRangeStart = this.computeYearRangeStart(this.leftYear);
3014
+ this.leftView = 'years';
3015
+ }
3016
+ prevLeftYearRange() {
3017
+ this.leftYearRangeStart -= 12;
3018
+ }
3019
+ nextLeftYearRange() {
3020
+ this.leftYearRangeStart += 12;
3021
+ }
3022
+ selectLeftMonthFromGrid(month) {
3023
+ if (this.isMonthDisabled(month, this.leftYear))
3024
+ return;
3025
+ this.leftMonth = month;
3026
+ this.leftCalendar = this.buildCalendar(this.leftYear, this.leftMonth);
3027
+ this.leftView = 'days';
3028
+ }
3029
+ selectLeftYearFromGrid(year) {
3030
+ if (this.isYearDisabled(year))
3031
+ return;
3032
+ this.leftYear = year;
3033
+ this.leftMonth = this.clampMonthForYear(this.leftMonth, year);
3034
+ this.leftCalendar = this.buildCalendar(this.leftYear, this.leftMonth);
3035
+ this.leftView = 'days';
3036
+ }
3037
+ /** "Today" quick-jump for the left calendar's month/year grids. */
3038
+ goToLeftToday() {
3039
+ if (this.disabled)
3040
+ return;
3041
+ const t = this.today;
3042
+ if (this.isDateDisabled(t.getFullYear(), t.getMonth(), t.getDate()))
3043
+ return;
3044
+ this.leftMonth = t.getMonth();
3045
+ this.leftYear = t.getFullYear();
3046
+ this.leftCalendar = this.buildCalendar(this.leftYear, this.leftMonth);
3047
+ this.leftView = 'days';
3048
+ this.selectDate(t.getDate(), false);
3049
+ }
3050
+ // Dual calendar — right --------------------------------------------------
3051
+ openRightMonthView() {
3052
+ if (this.disabled)
3053
+ return;
3054
+ this.rightView = 'months';
3055
+ }
3056
+ prevRightMonthGridYear() {
3057
+ if (this.isPrevYearDisabled(this.rightYear))
3058
+ return;
3059
+ this.rightYear--;
3060
+ }
3061
+ nextRightMonthGridYear() {
3062
+ if (this.isNextYearDisabled(this.rightYear))
3063
+ return;
3064
+ this.rightYear++;
3065
+ }
3066
+ openRightYearView() {
3067
+ if (this.disabled)
3068
+ return;
3069
+ this.rightYearRangeStart = this.computeYearRangeStart(this.rightYear);
3070
+ this.rightView = 'years';
3071
+ }
3072
+ prevRightYearRange() {
3073
+ this.rightYearRangeStart -= 12;
3074
+ }
3075
+ nextRightYearRange() {
3076
+ this.rightYearRangeStart += 12;
3077
+ }
3078
+ selectRightMonthFromGrid(month) {
3079
+ if (this.isMonthDisabled(month, this.rightYear))
3080
+ return;
3081
+ this.rightMonth = month;
3082
+ this.rightCalendar = this.buildCalendar(this.rightYear, this.rightMonth);
3083
+ this.rightView = 'days';
3084
+ }
3085
+ selectRightYearFromGrid(year) {
3086
+ if (this.isYearDisabled(year))
3087
+ return;
3088
+ this.rightYear = year;
3089
+ this.rightMonth = this.clampMonthForYear(this.rightMonth, year);
3090
+ this.rightCalendar = this.buildCalendar(this.rightYear, this.rightMonth);
3091
+ this.rightView = 'days';
3092
+ }
3093
+ /** "Today" quick-jump for the right calendar's month/year grids. */
3094
+ goToRightToday() {
3095
+ if (this.disabled)
3096
+ return;
3097
+ const t = this.today;
3098
+ if (this.isDateDisabled(t.getFullYear(), t.getMonth(), t.getDate()))
3099
+ return;
3100
+ this.rightMonth = t.getMonth();
3101
+ this.rightYear = t.getFullYear();
3102
+ this.rightCalendar = this.buildCalendar(this.rightYear, this.rightMonth);
3103
+ this.rightView = 'days';
3104
+ this.selectDate(t.getDate(), true);
3105
+ }
2224
3106
  initializeDual() {
2225
3107
  this.leftMonth = this.today.getMonth();
2226
3108
  this.leftYear = this.today.getFullYear();
@@ -2292,11 +3174,13 @@ class BkCustomCalendar {
2292
3174
  }
2293
3175
  if (!this.startDate)
2294
3176
  return false;
2295
- // Check if date is disabled
2296
- if (this.minDate && cellDate < this.minDate)
2297
- return false;
2298
- if (this.maxDate && cellDate > this.maxDate)
2299
- return false;
3177
+ // Deliberately NOT re-checking minDate/maxDate/allowedMonths/etc. here (this used to have its
3178
+ // own minDate/maxDate check, which meant a range chosen via chooseRange() — Today/Yesterday/
3179
+ // Last 7 days/etc. — could silently fail to render its .selected highlight if it fell outside
3180
+ // the range, even though the value itself was set correctly). Those constraints are meant to
3181
+ // gate manual day-grid picking only (see selectDate(), which routes through isDateDisabled
3182
+ // before ever setting startDate/endDate) — presets are intentionally exempt (see chooseRange).
3183
+ // Whatever startDate/endDate actually holds is what should render as selected, full stop.
2300
3184
  const sameDay = cellDate.getFullYear() === this.startDate.getFullYear() &&
2301
3185
  cellDate.getMonth() === this.startDate.getMonth() &&
2302
3186
  cellDate.getDate() === this.startDate.getDate();
@@ -2342,13 +3226,45 @@ class BkCustomCalendar {
2342
3226
  }
2343
3227
  return false;
2344
3228
  }
3229
+ /**
3230
+ * A cell is disabled unless it satisfies EVERY constraint that's set — minDate AND maxDate AND
3231
+ * allowedMonths AND allowedYears AND allowedDaysOfWeek AND NOT-in-disabledDates AND (if set)
3232
+ * in-allowedDates. Checked in that order, matching isMonthDisabled/isYearDisabled's own
3233
+ * minDate/maxDate-first ordering below — purely for readability, since AND makes the overall
3234
+ * result order-independent. This is the single source of truth for day-level selectability:
3235
+ * selectDate() routes through it too (rather than re-checking constraints on its own), so a
3236
+ * value can never be committed — including via keyboard Enter, which bypasses the template's
3237
+ * click guard — that this marks disabled.
3238
+ */
2345
3239
  isDateDisabled(year, month, day) {
2346
3240
  if (!day)
2347
3241
  return false;
2348
3242
  const cellDate = new Date(year, month, day);
2349
- if (this.minDate && cellDate < this.minDate)
3243
+ // Normalize minDate/maxDate to midnight before comparing — cellDate is always midnight, so an
3244
+ // un-normalized minDate/maxDate carrying today's current time-of-day (e.g. `new Date()`) would
3245
+ // otherwise disable today itself (00:00 < 14:32 is true even though it's the same calendar day).
3246
+ if (this.minDate) {
3247
+ const min = new Date(this.minDate.getFullYear(), this.minDate.getMonth(), this.minDate.getDate());
3248
+ if (cellDate < min)
3249
+ return true;
3250
+ }
3251
+ if (this.maxDate) {
3252
+ const max = new Date(this.maxDate.getFullYear(), this.maxDate.getMonth(), this.maxDate.getDate());
3253
+ if (cellDate > max)
3254
+ return true;
3255
+ }
3256
+ if (this.allowedMonthsZeroBased?.length && !this.allowedMonthsZeroBased.includes(month))
3257
+ return true;
3258
+ if (this.allowedYears?.length && !this.allowedYears.includes(year))
3259
+ return true;
3260
+ if (this.allowedDaysOfWeekZeroBased?.length && !this.allowedDaysOfWeekZeroBased.includes(cellDate.getDay()))
3261
+ return true;
3262
+ // Blackout list — a hard AND-in-disable, same weight as every check above regardless of
3263
+ // order (if a date is ever in both disabledDates and allowedDates — a contradictory config —
3264
+ // it stays disabled, since either check alone is enough to return true here).
3265
+ if (this.dateListIncludes(this.disabledDates, year, month, day))
2350
3266
  return true;
2351
- if (this.maxDate && cellDate > this.maxDate)
3267
+ if (this.allowedDates?.length && !this.dateListIncludes(this.allowedDates, year, month, day))
2352
3268
  return true;
2353
3269
  return false;
2354
3270
  }
@@ -2361,6 +3277,16 @@ class BkCustomCalendar {
2361
3277
  cellDate.getMonth() === today.getMonth() &&
2362
3278
  cellDate.getDate() === today.getDate();
2363
3279
  }
3280
+ /** Today's month cell in the month grid — same "current" marker as {@link isToday} gives the
3281
+ * day grid, independent of `active` (the picked/displayed month). */
3282
+ isCurrentMonth(month, year) {
3283
+ const today = new Date();
3284
+ return year === today.getFullYear() && month === today.getMonth();
3285
+ }
3286
+ /** Today's year cell in the year grid — same idea as {@link isCurrentMonth}. */
3287
+ isCurrentYear(year) {
3288
+ return year === new Date().getFullYear();
3289
+ }
2364
3290
  getDisplayValue() {
2365
3291
  if (this.multiDateSelection && this.selectedDates.length > 0) {
2366
3292
  if (this.selectedDates.length === 1) {
@@ -2368,6 +3294,14 @@ class BkCustomCalendar {
2368
3294
  }
2369
3295
  return `${this.selectedDates.length} dates selected`;
2370
3296
  }
3297
+ if (this.isPickerViewActive()) {
3298
+ if (this.selectedYearValue == null)
3299
+ return '';
3300
+ if (this.pickerView === 'month' && this.selectedMonthValue != null) {
3301
+ return moment().year(this.selectedYearValue).month(this.selectedMonthValue).format('MMMM YYYY');
3302
+ }
3303
+ return String(this.selectedYearValue);
3304
+ }
2371
3305
  if (!this.startDate)
2372
3306
  return '';
2373
3307
  // Prefer moment formatting for consistent display
@@ -3082,8 +4016,8 @@ class BkCustomCalendar {
3082
4016
  const dd = date.getDate().toString().padStart(2, '0');
3083
4017
  return `${yyyy}-${mm}-${dd}`;
3084
4018
  }
3085
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkCustomCalendar, deps: [{ token: BkCalendarManagerService }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component });
3086
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.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", popupPosition: "popupPosition", drop: "drop", dualCalendar: "dualCalendar", showRanges: "showRanges", timeFormat: "timeFormat", clearableTime: "clearableTime", enableSeconds: "enableSeconds", customRanges: "customRanges", weekDayLabels: "weekDayLabels", multiDateSelection: "multiDateSelection", maxDate: "maxDate", minDate: "minDate", placeholder: "placeholder", opens: "opens", inline: "inline", compact: "compact", autoPosition: "autoPosition", appendToBody: "appendToBody", isDisplayCrossIcon: "isDisplayCrossIcon", hasError: "hasError", errorMessage: "errorMessage", showCancelApply: "showCancelApply", selectedValue: "selectedValue", displayFormat: "displayFormat", required: "required", rangeOrder: "rangeOrder" }, outputs: { selected: "selected", opened: "opened", closed: "closed" }, host: { listeners: { "document:click": "onClickOutside($event)" } }, providers: [
4019
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkCustomCalendar, deps: [{ token: BkCalendarManagerService }], target: i0.ɵɵFactoryTarget.Component });
4020
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.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", pickerView: "pickerView", showWeekNumbers: "showWeekNumbers", showISOWeekNumbers: "showISOWeekNumbers", customRangeDirection: "customRangeDirection", lockStartDate: "lockStartDate", position: "position", popupPosition: "popupPosition", drop: "drop", dualCalendar: "dualCalendar", showRanges: "showRanges", timeFormat: "timeFormat", clearableTime: "clearableTime", enableSeconds: "enableSeconds", customRanges: "customRanges", weekDayLabels: "weekDayLabels", multiDateSelection: "multiDateSelection", maxDate: "maxDate", minDate: "minDate", allowedMonths: "allowedMonths", allowedYears: "allowedYears", allowedDaysOfWeek: "allowedDaysOfWeek", disabledDates: "disabledDates", allowedDates: "allowedDates", placeholder: "placeholder", opens: "opens", inline: "inline", compact: "compact", appendToBody: "appendToBody", viewportMargin: "viewportMargin", panelClass: "panelClass", isDisplayCrossIcon: "isDisplayCrossIcon", hasError: "hasError", errorMessage: "errorMessage", showCancelApply: "showCancelApply", selectedValue: "selectedValue", displayFormat: "displayFormat", required: "required", rangeOrder: "rangeOrder" }, outputs: { selected: "selected", opened: "opened", closed: "closed" }, providers: [
3087
4021
  {
3088
4022
  provide: NG_VALUE_ACCESSOR,
3089
4023
  useExisting: forwardRef(() => BkCustomCalendar),
@@ -3094,11 +4028,11 @@ class BkCustomCalendar {
3094
4028
  useExisting: forwardRef(() => BkCustomCalendar),
3095
4029
  multi: true,
3096
4030
  },
3097
- ], viewQueries: [{ propertyName: "inputWrapper", first: true, predicate: ["inputWrapper"], descendants: true }, { propertyName: "calendarPopupRef", first: true, predicate: ["calendarPopup"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"calendar-container relative\" [class.open]=\"show\" [class.inline-mode]=\"inline\" [class.disabled]=\"disabled\">\r\n <!-- Input field -->\r\n <div #inputWrapper class=\"input-wrapper\" *ngIf=\"!inline\">\r\n <input\r\n type=\"text\"\r\n (click)=\"!disabled && toggle()\"\r\n (keydown.enter)=\"$event.preventDefault()\"\r\n (blur)=\"markAsTouched()\"\r\n readonly\r\n [value]=\"getDisplayValue()\"\r\n [placeholder]=\"placeholder\"\r\n [attr.disabled]=\"disabled ? true : null\"\r\n [class.hasError]=\"hasError\"\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 type=\"button\" class=\"clear-btn\" *ngIf=\"getDisplayValue() && isDisplayCrossIcon && !disabled\" (click)=\"clear(); $event.stopPropagation()\" title=\"Clear\">\u00D7</button>\r\n </div>\r\n\r\n <!-- Calendar Popup / Inline -->\r\n <div #calendarPopup\r\n class=\"calendar-popup\"\r\n [class.inline-calendar]=\"inline\"\r\n [class.append-to-body]=\"appendToBody && !inline\"\r\n [style.position]=\"appendToBody && !inline ? 'fixed' : null\"\r\n [style.top]=\"appendToBody && !inline && !popupPlacementAbove ? dropdownStyle.top : null\"\r\n [style.bottom]=\"appendToBody && !inline && popupPlacementAbove ? dropdownStyle.bottom : null\"\r\n [style.left]=\"appendToBody && !inline ? dropdownStyle.left : null\"\r\n tabindex=\"0\"\r\n (keydown)=\"onCalendarPopupKeydown($event)\"\r\n [ngClass]=\"{\r\n 'position-right': !inline && !appendToBody && opens === 'right',\r\n 'position-center': !inline && !appendToBody && opens === 'center',\r\n 'drop-up': !inline && popupPlacementAbove,\r\n 'has-ranges': showRanges && customRanges,\r\n 'dual-calendar-mode': dualCalendar,\r\n 'compact': compact\r\n }\"\r\n *ngIf=\"inline || show\">\r\n\r\n <!-- RANGES -->\r\n <div class=\"ranges\" *ngIf=\"showRanges && customRanges\" role=\"listbox\" aria-label=\"Date ranges\">\r\n <button\r\n type=\"button\"\r\n *ngFor=\"let rangeKey of rangeOrder\"\r\n (click)=\"chooseRange(rangeKey)\"\r\n (keydown)=\"onRangeButtonKeydown($event, rangeKey)\"\r\n [class.active]=\"activeRange === rangeKey\"\r\n [class.custom-range]=\"rangeKey === 'Custom Range'\"\r\n class=\"range-btn\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"activeRange === rangeKey\">\r\n {{ rangeKey }}\r\n </button>\r\n </div>\r\n<div class=\"\" [ngClass]=\"showRanges ? 'w-100 flex-grow-1 border-l border-[#eee]' : ''\">\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\" role=\"grid\" [attr.aria-label]=\"getMonthName(month) + ' ' + year\">\r\n <thead>\r\n <tr role=\"row\">\r\n <th *ngFor=\"let d of resolvedWeekDayLabels\" class=\"weekday-header\" scope=\"col\" role=\"columnheader\">{{ d }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let week of calendar\" role=\"row\">\r\n <td\r\n *ngFor=\"let dayObj of week\"\r\n role=\"gridcell\"\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-keyboard-focus]=\"dayObj.currentMonth && isKeyboardFocusedCell(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 [variation]=\"compact ? 'default' : 'lg'\"\r\n [timeFormat]=\"timeFormat\"\r\n [clearable]=\"clearableTime\"\r\n [label]=\"''\"\r\n [ngModel]=\"singleTimeModel\"\r\n (ngModelChange)=\"onSingleTimePickerChange($event); singleTimeModel=$event\"\r\n [closePicker]=\"shouldClosePicker('single-time')\"\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\" role=\"grid\" [attr.aria-label]=\"getMonthName(leftMonth) + ' ' + leftYear\">\r\n <thead>\r\n <tr role=\"row\">\r\n <th *ngFor=\"let d of resolvedWeekDayLabels\" class=\"weekday-header\" scope=\"col\" role=\"columnheader\">{{ d }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let week of leftCalendar\" role=\"row\">\r\n <td\r\n *ngFor=\"let dayObj of week\"\r\n role=\"gridcell\"\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-keyboard-focus]=\"dayObj.currentMonth && isKeyboardFocusedCell(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 [variation]=\"compact ? 'default' : 'lg'\"\r\n [timeFormat]=\"timeFormat\"\r\n [clearable]=\"clearableTime\"\r\n [label]=\"''\"\r\n [ngModel]=\"startTimeModel\"\r\n (ngModelChange)=\"onDualTimePickerChange($event, true); startTimeModel=$event\"\r\n [closePicker]=\"shouldClosePicker('dual-start')\"\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\" role=\"grid\" [attr.aria-label]=\"getMonthName(rightMonth) + ' ' + rightYear\">\r\n <thead>\r\n <tr role=\"row\">\r\n <th *ngFor=\"let d of resolvedWeekDayLabels\" class=\"weekday-header\" scope=\"col\" role=\"columnheader\">{{ d }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let week of rightCalendar\" role=\"row\">\r\n <td\r\n *ngFor=\"let dayObj of week\"\r\n role=\"gridcell\"\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-keyboard-focus]=\"dayObj.currentMonth && isKeyboardFocusedCell(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 [variation]=\"compact ? 'default' : 'lg'\"\r\n [timeFormat]=\"timeFormat\"\r\n [clearable]=\"clearableTime\"\r\n [label]=\"''\"\r\n [ngModel]=\"endTimeModel\"\r\n (ngModelChange)=\"onDualTimePickerChange($event, false); endTimeModel=$event\"\r\n [closePicker]=\"shouldClosePicker('dual-end')\"\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 && showCancelApply\">\r\n <button *ngIf=\"showCancel\" (click)=\"cancel()\" class=\"btn-cancel\" type=\"button\">Cancel</button>\r\n <button (click)=\"apply()\" class=\"btn-apply\" type=\"button\" [disabled]=\"disabled || isDualRangeApplyBlocked\">Apply</button>\r\n </div>\r\n\r\n </div>\r\n\r\n </div>\r\n</div>\r\n\r\n@if (hasError){\r\n<p class=\"calender-error\">{{errorMessage}}</p>\r\n}\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}.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:focus-visible{outline:0!important}.calendar-popup.append-to-body{font-family:Inter,sans-serif;z-index:100000}.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.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}.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%}.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-apply{background:#000;color:#fff}.btn-apply:active{transform:translateY(0)}@media (max-width: 768px){.calendar-popup{width:100%;max-width:320px;max-height:300px;overflow:auto}.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}.calendar-input.calendar-input-has-error{@apply border-[#d11e14];}.calendar-input:disabled{cursor:not-allowed;border-color:#e3e3e7;background-color:#f4f4f6;color:#a1a3ae}.btn-apply:disabled{cursor:not-allowed!important;opacity:.7}.calendar-day.calendar-day-keyboard-focus:not(.disabled):not(.other-month){outline:0px solid #000}.calendar-popup.compact{width:240px}.calendar-popup.compact.has-ranges{width:380px}.calendar-popup.compact.dual-calendar-mode{width:480px}.calendar-popup.compact.dual-calendar-mode.has-ranges{width:600px}.calendar-popup.compact .header{padding:8px 0}.calendar-popup.compact .month-year{font-size:13px}.calendar-popup.compact .nav-btn{height:24px;width:24px;padding:6px 8px}.calendar-popup.compact .calendar-wrapper,.calendar-popup.compact .calendar-left,.calendar-popup.compact .calendar-right{padding:0 8px 8px}.calendar-popup.compact .weekday-header{font-size:11px;padding:4px 2px}.calendar-popup.compact .calendar-day{font-size:12px;padding:5px 2px;line-height:1.3}.calendar-popup.compact .ranges{min-width:120px;gap:2px;margin-bottom:8px;padding-bottom:8px}.calendar-popup.compact.has-ranges .ranges{padding:6px}.calendar-popup.compact .range-btn{font-size:12px;padding:5px 8px}.calendar-popup.compact .timepicker-section{margin-top:8px;padding-top:8px}.calendar-popup.compact .timepicker-label{font-size:11px}.calendar-popup.compact .footer{padding:8px;gap:6px}.calendar-popup.compact .btn-cancel,.calendar-popup.compact .btn-apply{font-size:11px;padding:6px 12px;min-width:64px}\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: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: BkTimePicker, selector: "bk-time-picker", inputs: ["required", "value", "label", "placeholder", "clearable", "position", "variation", "pickerId", "closePicker", "timeFormat", "showSeconds", "autoPosition", "appendToBody", "disabled"], outputs: ["change", "timeChange", "pickerOpened", "pickerClosed"] }] });
4031
+ ], viewQueries: [{ propertyName: "inputWrapper", first: true, predicate: ["inputWrapper"], descendants: true }, { propertyName: "calendarPopupRef", first: true, predicate: ["calendarPopup"], descendants: true }, { propertyName: "calendarOverlay", first: true, predicate: ["calendarOverlay"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"calendar-container relative\" [class.open]=\"show\" [class.inline-mode]=\"inline\" [class.disabled]=\"disabled\">\r\n <!-- Input field + its CDK overlay share one *ngIf=\"!inline\" scope so the origin's template ref\r\n (#calendarOrigin) is visible to the overlay template below \u2014 a ref declared inside one *ngIf\r\n embedded view isn't visible from a different (even identically-conditioned) *ngIf. -->\r\n <ng-container *ngIf=\"!inline\">\r\n <div #inputWrapper cdkOverlayOrigin #calendarOrigin=\"cdkOverlayOrigin\" class=\"input-wrapper\">\r\n <input\r\n type=\"text\"\r\n (mousedown)=\"onTriggerMouseDown($event)\"\r\n (focus)=\"onTriggerFocus()\"\r\n (keydown.enter)=\"onTriggerKeydownOpen($event)\"\r\n (keydown.space)=\"onTriggerKeydownOpen($event)\"\r\n (keydown.arrowDown)=\"onTriggerKeydownOpen($event)\"\r\n (blur)=\"onTriggerBlur()\"\r\n readonly\r\n [value]=\"getDisplayValue()\"\r\n [placeholder]=\"placeholder\"\r\n [attr.disabled]=\"disabled ? true : null\"\r\n [class.hasError]=\"hasError\"\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 type=\"button\" class=\"clear-btn\" *ngIf=\"getDisplayValue() && isDisplayCrossIcon && !disabled\" (click)=\"clear(); $event.stopPropagation()\" title=\"Clear\">\u00D7</button>\r\n </div>\r\n\r\n <!-- Positioned via Angular CDK Overlay, portalled into the shared cdk-overlay-container so it\r\n escapes clipping/stacking inside dialogs and scroll containers regardless of the old\r\n appendToBody flag (see its @deprecated note in the component). -->\r\n <ng-template\r\n cdkConnectedOverlay\r\n #calendarOverlay=\"cdkConnectedOverlay\"\r\n [cdkConnectedOverlayOrigin]=\"calendarOrigin\"\r\n [cdkConnectedOverlayOpen]=\"show\"\r\n [cdkConnectedOverlayPositions]=\"calendarPositions\"\r\n [cdkConnectedOverlayPush]=\"true\"\r\n [cdkConnectedOverlayViewportMargin]=\"viewportMargin\"\r\n [cdkConnectedOverlayPanelClass]=\"panelClass\"\r\n [cdkConnectedOverlayFlexibleDimensions]=\"false\"\r\n (positionChange)=\"onPositionChange($event)\"\r\n (overlayOutsideClick)=\"onOverlayOutsideClick()\"\r\n (detach)=\"close()\">\r\n <div #calendarPopup\r\n class=\"calendar-popup\"\r\n tabindex=\"0\"\r\n (keydown)=\"onCalendarPopupKeydown($event)\"\r\n (wheel)=\"onCalendarPopupWheel($event)\"\r\n [ngClass]=\"{\r\n 'drop-up': popupPlacementAbove,\r\n 'has-ranges': showRanges && customRanges,\r\n 'dual-calendar-mode': dualCalendar,\r\n 'compact': compact\r\n }\">\r\n <ng-container *ngTemplateOutlet=\"popupContent\"></ng-container>\r\n </div>\r\n </ng-template>\r\n </ng-container>\r\n\r\n <!-- Popup content \u2014 written once, projected into whichever render path below is active -->\r\n <ng-template #popupContent>\r\n <!-- RANGES: date-range shortcuts don't apply once selection is restricted to a month/year. -->\r\n <div class=\"ranges\" *ngIf=\"showRanges && customRanges && pickerView === 'day'\" role=\"listbox\" aria-label=\"Date ranges\">\r\n <button\r\n type=\"button\"\r\n *ngFor=\"let rangeKey of rangeOrder\"\r\n (click)=\"chooseRange(rangeKey)\"\r\n (keydown)=\"onRangeButtonKeydown($event, rangeKey)\"\r\n [class.active]=\"activeRange === rangeKey\"\r\n [class.custom-range]=\"rangeKey === 'Custom Range'\"\r\n class=\"range-btn\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"activeRange === rangeKey\">\r\n {{ rangeKey }}\r\n </button>\r\n </div>\r\n<div class=\"\" [ngClass]=\"showRanges && pickerView === 'day' ? 'w-100 flex-grow-1 border-l border-[#eee]' : ''\">\r\n\r\n\r\n <!-- SINGLE CALENDAR -->\r\n <div *ngIf=\"!dualCalendar\" class=\"calendar-wrapper\">\r\n\r\n <!-- DAY GRID HEADER -->\r\n <div class=\"header\" *ngIf=\"view === 'days'\">\r\n <button class=\"nav-btn bk-nav-btn-year\" type=\"button\" (click)=\"prevYear()\" [disabled]=\"isPrevYearDisabled(year)\" title=\"Prev year\">\r\n <img alt=\"prev year\" [src]=\"brickclayIcons.arrowLeftDouble\"/>\r\n </button>\r\n <button class=\"nav-btn\" type=\"button\" (click)=\"prevMonth()\" title=\"Prev month\">\r\n <img alt=\"prev\" [src]=\"brickclayIcons.arrowleft\"/>\r\n </button>\r\n <span class=\"month-year\">\r\n <button type=\"button\" class=\"bk-month-year-btn\" (click)=\"openMonthView()\" [disabled]=\"disabled\">{{ getMonthName(month) }}</button>\r\n <button type=\"button\" class=\"bk-month-year-btn\" (click)=\"openYearView()\" [disabled]=\"disabled\">{{ year }}</button>\r\n </span>\r\n <button class=\"nav-btn\" type=\"button\" (click)=\"nextMonth()\" title=\"Next month\">\r\n <img alt=\"next\" [src]='brickclayIcons.arrowRight'/>\r\n </button>\r\n <button class=\"nav-btn bk-nav-btn-year\" type=\"button\" (click)=\"nextYear()\" [disabled]=\"isNextYearDisabled(year)\" title=\"Next year\">\r\n <img alt=\"next year\" [src]=\"brickclayIcons.arrowRightDouble\"/>\r\n </button>\r\n </div>\r\n\r\n <!-- MONTH GRID HEADER -->\r\n <div class=\"header\" *ngIf=\"view === 'months'\">\r\n <button class=\"nav-btn bk-nav-btn-year\" type=\"button\" (click)=\"prevMonthGridYear()\" [disabled]=\"isPrevYearDisabled(year)\" title=\"Prev year\">\r\n <img alt=\"prev year\" [src]=\"brickclayIcons.arrowLeftDouble\"/>\r\n </button>\r\n <span class=\"month-year\">\r\n <button type=\"button\" class=\"bk-month-year-btn\" (click)=\"openYearView()\" [disabled]=\"disabled\">{{ year }}</button>\r\n </span>\r\n <button class=\"nav-btn bk-nav-btn-year\" type=\"button\" (click)=\"nextMonthGridYear()\" [disabled]=\"isNextYearDisabled(year)\" title=\"Next year\">\r\n <img alt=\"next year\" [src]=\"brickclayIcons.arrowRightDouble\"/>\r\n </button>\r\n </div>\r\n\r\n <!-- YEAR GRID HEADER -->\r\n <div class=\"header\" *ngIf=\"view === 'years'\">\r\n <button class=\"nav-btn bk-nav-btn-year\" type=\"button\" (click)=\"prevYearRange()\" title=\"Prev years\">\r\n <img alt=\"prev\" [src]=\"brickclayIcons.arrowLeftDouble\"/>\r\n </button>\r\n <span class=\"month-year\">{{ yearRangeStart }} - {{ yearRangeStart + 11 }}</span>\r\n <button class=\"nav-btn bk-nav-btn-year\" type=\"button\" (click)=\"nextYearRange()\" title=\"Next years\">\r\n <img alt=\"next\" [src]=\"brickclayIcons.arrowRightDouble\"/>\r\n </button>\r\n </div>\r\n\r\n <table class=\"calendar-table\" *ngIf=\"view === 'days'\" role=\"grid\" [attr.aria-label]=\"getMonthName(month) + ' ' + year\">\r\n <thead>\r\n <tr role=\"row\">\r\n <th *ngFor=\"let d of resolvedWeekDayLabels\" class=\"weekday-header\" scope=\"col\" role=\"columnheader\">{{ d }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let week of calendar\" role=\"row\">\r\n <td\r\n *ngFor=\"let dayObj of week\"\r\n role=\"gridcell\"\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-keyboard-focus]=\"dayObj.currentMonth && isKeyboardFocusedCell(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 <!-- MONTH GRID -->\r\n <div class=\"bk-grid-picker\" *ngIf=\"view === 'months'\">\r\n <div class=\"bk-month-grid\" role=\"listbox\" [attr.aria-label]=\"'Select month for ' + year\">\r\n <button\r\n *ngFor=\"let m of monthNamesShort; let i = index\"\r\n type=\"button\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"i === month\"\r\n [class.active]=\"i === month\"\r\n [class.current]=\"isCurrentMonth(i, year)\"\r\n [disabled]=\"isMonthDisabled(i, year)\"\r\n (click)=\"selectMonthFromGrid(i)\"\r\n class=\"bk-month-cell\">\r\n {{ m }}\r\n </button>\r\n </div>\r\n <button type=\"button\" class=\"bk-today-btn\" (click)=\"goToToday()\" [disabled]=\"disabled || isDateDisabled(today.getFullYear(), today.getMonth(), today.getDate())\">Today</button>\r\n </div>\r\n\r\n <!-- YEAR GRID -->\r\n <div class=\"bk-grid-picker\" *ngIf=\"view === 'years'\">\r\n <div class=\"bk-year-grid\" role=\"listbox\" aria-label=\"Select year\">\r\n <button\r\n *ngFor=\"let y of getYearGridYears(yearRangeStart)\"\r\n type=\"button\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"y === year\"\r\n [class.active]=\"y === year\"\r\n [class.current]=\"isCurrentYear(y)\"\r\n [disabled]=\"isYearDisabled(y)\"\r\n (click)=\"selectYearFromGrid(y)\"\r\n class=\"bk-year-cell\">\r\n {{ y }}\r\n </button>\r\n </div>\r\n <button type=\"button\" class=\"bk-today-btn\" (click)=\"goToToday()\" [disabled]=\"disabled || isDateDisabled(today.getFullYear(), today.getMonth(), today.getDate())\">Today</button>\r\n </div>\r\n\r\n <!-- Single Calendar Time Picker -->\r\n <div *ngIf=\"enableTimepicker && view === 'days'\" 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 [variation]=\"compact ? 'default' : 'lg'\"\r\n [timeFormat]=\"timeFormat\"\r\n [clearable]=\"clearableTime\"\r\n [label]=\"''\"\r\n [ngModel]=\"singleTimeModel\"\r\n (ngModelChange)=\"onSingleTimePickerChange($event); singleTimeModel=$event\"\r\n [closePicker]=\"shouldClosePicker('single-time')\"\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\" *ngIf=\"leftView === 'days'\">\r\n <button (click)=\"prevLeftYear()\" class=\"nav-btn bk-nav-btn-year\" type=\"button\" [disabled]=\"isPrevYearDisabled(leftYear)\" title=\"Prev year\">\r\n <img alt=\"prev year\" class=\"arrow-left\" [src]=\"brickclayIcons.arrowLeftDouble\"/>\r\n </button>\r\n <button (click)=\"prevLeftMonth()\" class=\"nav-btn\" type=\"button\" title=\"Prev month\">\r\n <img alt=\"arrow-left\" class=\"arrow-left\" [src]=\"brickclayIcons.arrowleft\"/>\r\n </button>\r\n <span class=\"month-year\">\r\n <button type=\"button\" class=\"bk-month-year-btn\" (click)=\"openLeftMonthView()\" [disabled]=\"disabled\">{{ getMonthName(leftMonth) }}</button>\r\n <button type=\"button\" class=\"bk-month-year-btn\" (click)=\"openLeftYearView()\" [disabled]=\"disabled\">{{ leftYear }}</button>\r\n </span>\r\n <button (click)=\"nextLeftMonth()\" class=\"nav-btn\" type=\"button\" title=\"Next month\">\r\n <img alt=\"arrow-right\" class=\"arrow-right\" [src]='brickclayIcons.arrowRight'/>\r\n </button>\r\n <button (click)=\"nextLeftYear()\" class=\"nav-btn bk-nav-btn-year\" type=\"button\" [disabled]=\"isNextYearDisabled(leftYear)\" title=\"Next year\">\r\n <img alt=\"next year\" class=\"arrow-right\" [src]=\"brickclayIcons.arrowRightDouble\"/>\r\n </button>\r\n </div>\r\n\r\n <!-- MONTH GRID HEADER -->\r\n <div class=\"header\" *ngIf=\"leftView === 'months'\">\r\n <button class=\"nav-btn bk-nav-btn-year\" type=\"button\" (click)=\"prevLeftMonthGridYear()\" [disabled]=\"isPrevYearDisabled(leftYear)\" title=\"Prev year\">\r\n <img alt=\"prev year\" [src]=\"brickclayIcons.arrowLeftDouble\"/>\r\n </button>\r\n <span class=\"month-year\">\r\n <button type=\"button\" class=\"bk-month-year-btn\" (click)=\"openLeftYearView()\" [disabled]=\"disabled\">{{ leftYear }}</button>\r\n </span>\r\n <button class=\"nav-btn bk-nav-btn-year\" type=\"button\" (click)=\"nextLeftMonthGridYear()\" [disabled]=\"isNextYearDisabled(leftYear)\" title=\"Next year\">\r\n <img alt=\"next year\" [src]=\"brickclayIcons.arrowRightDouble\"/>\r\n </button>\r\n </div>\r\n\r\n <!-- YEAR GRID HEADER -->\r\n <div class=\"header\" *ngIf=\"leftView === 'years'\">\r\n <button class=\"nav-btn bk-nav-btn-year\" type=\"button\" (click)=\"prevLeftYearRange()\" title=\"Prev years\">\r\n <img alt=\"prev\" [src]=\"brickclayIcons.arrowLeftDouble\"/>\r\n </button>\r\n <span class=\"month-year\">{{ leftYearRangeStart }} - {{ leftYearRangeStart + 11 }}</span>\r\n <button class=\"nav-btn bk-nav-btn-year\" type=\"button\" (click)=\"nextLeftYearRange()\" title=\"Next years\">\r\n <img alt=\"next\" [src]=\"brickclayIcons.arrowRightDouble\"/>\r\n </button>\r\n </div>\r\n\r\n <table class=\"calendar-table\" *ngIf=\"leftView === 'days'\" role=\"grid\" [attr.aria-label]=\"getMonthName(leftMonth) + ' ' + leftYear\">\r\n <thead>\r\n <tr role=\"row\">\r\n <th *ngFor=\"let d of resolvedWeekDayLabels\" class=\"weekday-header\" scope=\"col\" role=\"columnheader\">{{ d }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let week of leftCalendar\" role=\"row\">\r\n <td\r\n *ngFor=\"let dayObj of week\"\r\n role=\"gridcell\"\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-keyboard-focus]=\"dayObj.currentMonth && isKeyboardFocusedCell(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 <!-- MONTH GRID -->\r\n <div class=\"bk-grid-picker\" *ngIf=\"leftView === 'months'\">\r\n <div class=\"bk-month-grid\" role=\"listbox\" [attr.aria-label]=\"'Select month for ' + leftYear\">\r\n <button\r\n *ngFor=\"let m of monthNamesShort; let i = index\"\r\n type=\"button\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"i === leftMonth\"\r\n [class.active]=\"i === leftMonth\"\r\n [class.current]=\"isCurrentMonth(i, leftYear)\"\r\n [disabled]=\"isMonthDisabled(i, leftYear)\"\r\n (click)=\"selectLeftMonthFromGrid(i)\"\r\n class=\"bk-month-cell\">\r\n {{ m }}\r\n </button>\r\n </div>\r\n <button type=\"button\" class=\"bk-today-btn\" (click)=\"goToLeftToday()\" [disabled]=\"disabled || isDateDisabled(today.getFullYear(), today.getMonth(), today.getDate())\">Today</button>\r\n </div>\r\n\r\n <!-- YEAR GRID -->\r\n <div class=\"bk-grid-picker\" *ngIf=\"leftView === 'years'\">\r\n <div class=\"bk-year-grid\" role=\"listbox\" aria-label=\"Select year\">\r\n <button\r\n *ngFor=\"let y of getYearGridYears(leftYearRangeStart)\"\r\n type=\"button\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"y === leftYear\"\r\n [class.active]=\"y === leftYear\"\r\n [class.current]=\"isCurrentYear(y)\"\r\n [disabled]=\"isYearDisabled(y)\"\r\n (click)=\"selectLeftYearFromGrid(y)\"\r\n class=\"bk-year-cell\">\r\n {{ y }}\r\n </button>\r\n </div>\r\n <button type=\"button\" class=\"bk-today-btn\" (click)=\"goToLeftToday()\" [disabled]=\"disabled || isDateDisabled(today.getFullYear(), today.getMonth(), today.getDate())\">Today</button>\r\n </div>\r\n\r\n <!-- Start Time Picker for Dual Calendar -->\r\n <div *ngIf=\"enableTimepicker && leftView === 'days'\" 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 [variation]=\"compact ? 'default' : 'lg'\"\r\n [timeFormat]=\"timeFormat\"\r\n [clearable]=\"clearableTime\"\r\n [label]=\"''\"\r\n [ngModel]=\"startTimeModel\"\r\n (ngModelChange)=\"onDualTimePickerChange($event, true); startTimeModel=$event\"\r\n [closePicker]=\"shouldClosePicker('dual-start')\"\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\" *ngIf=\"rightView === 'days'\">\r\n <button (click)=\"prevRightYear()\" class=\"nav-btn bk-nav-btn-year\" type=\"button\" [disabled]=\"isPrevYearDisabled(rightYear)\" title=\"Prev year\">\r\n <img alt=\"prev year\" class=\"arrow-left\" [src]=\"brickclayIcons.arrowLeftDouble\"/>\r\n </button>\r\n <button (click)=\"prevRightMonth()\" class=\"nav-btn\" type=\"button\" title=\"Prev month\">\r\n <img alt=\"arrow-left\" class=\"arrow-left\" [src]=\"brickclayIcons.arrowleft\"/>\r\n </button>\r\n <span class=\"month-year\">\r\n <button type=\"button\" class=\"bk-month-year-btn\" (click)=\"openRightMonthView()\" [disabled]=\"disabled\">{{ getMonthName(rightMonth) }}</button>\r\n <button type=\"button\" class=\"bk-month-year-btn\" (click)=\"openRightYearView()\" [disabled]=\"disabled\">{{ rightYear }}</button>\r\n </span>\r\n <button (click)=\"nextRightMonth()\" class=\"nav-btn\" type=\"button\" title=\"Next month\">\r\n <img alt=\"arrow-right\" class=\"arrow-right\" [src]='brickclayIcons.arrowRight'/>\r\n </button>\r\n <button (click)=\"nextRightYear()\" class=\"nav-btn bk-nav-btn-year\" type=\"button\" [disabled]=\"isNextYearDisabled(rightYear)\" title=\"Next year\">\r\n <img alt=\"next year\" class=\"arrow-right\" [src]=\"brickclayIcons.arrowRightDouble\"/>\r\n </button>\r\n </div>\r\n\r\n <!-- MONTH GRID HEADER -->\r\n <div class=\"header\" *ngIf=\"rightView === 'months'\">\r\n <button class=\"nav-btn bk-nav-btn-year\" type=\"button\" (click)=\"prevRightMonthGridYear()\" [disabled]=\"isPrevYearDisabled(rightYear)\" title=\"Prev year\">\r\n <img alt=\"prev year\" [src]=\"brickclayIcons.arrowLeftDouble\"/>\r\n </button>\r\n <span class=\"month-year\">\r\n <button type=\"button\" class=\"bk-month-year-btn\" (click)=\"openRightYearView()\" [disabled]=\"disabled\">{{ rightYear }}</button>\r\n </span>\r\n <button class=\"nav-btn bk-nav-btn-year\" type=\"button\" (click)=\"nextRightMonthGridYear()\" [disabled]=\"isNextYearDisabled(rightYear)\" title=\"Next year\">\r\n <img alt=\"next year\" [src]=\"brickclayIcons.arrowRightDouble\"/>\r\n </button>\r\n </div>\r\n\r\n <!-- YEAR GRID HEADER -->\r\n <div class=\"header\" *ngIf=\"rightView === 'years'\">\r\n <button class=\"nav-btn bk-nav-btn-year\" type=\"button\" (click)=\"prevRightYearRange()\" title=\"Prev years\">\r\n <img alt=\"prev\" [src]=\"brickclayIcons.arrowLeftDouble\"/>\r\n </button>\r\n <span class=\"month-year\">{{ rightYearRangeStart }} - {{ rightYearRangeStart + 11 }}</span>\r\n <button class=\"nav-btn bk-nav-btn-year\" type=\"button\" (click)=\"nextRightYearRange()\" title=\"Next years\">\r\n <img alt=\"next\" [src]=\"brickclayIcons.arrowRightDouble\"/>\r\n </button>\r\n </div>\r\n\r\n <table class=\"calendar-table\" *ngIf=\"rightView === 'days'\" role=\"grid\" [attr.aria-label]=\"getMonthName(rightMonth) + ' ' + rightYear\">\r\n <thead>\r\n <tr role=\"row\">\r\n <th *ngFor=\"let d of resolvedWeekDayLabels\" class=\"weekday-header\" scope=\"col\" role=\"columnheader\">{{ d }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let week of rightCalendar\" role=\"row\">\r\n <td\r\n *ngFor=\"let dayObj of week\"\r\n role=\"gridcell\"\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-keyboard-focus]=\"dayObj.currentMonth && isKeyboardFocusedCell(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 <!-- MONTH GRID -->\r\n <div class=\"bk-grid-picker\" *ngIf=\"rightView === 'months'\">\r\n <div class=\"bk-month-grid\" role=\"listbox\" [attr.aria-label]=\"'Select month for ' + rightYear\">\r\n <button\r\n *ngFor=\"let m of monthNamesShort; let i = index\"\r\n type=\"button\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"i === rightMonth\"\r\n [class.active]=\"i === rightMonth\"\r\n [class.current]=\"isCurrentMonth(i, rightYear)\"\r\n [disabled]=\"isMonthDisabled(i, rightYear)\"\r\n (click)=\"selectRightMonthFromGrid(i)\"\r\n class=\"bk-month-cell\">\r\n {{ m }}\r\n </button>\r\n </div>\r\n <button type=\"button\" class=\"bk-today-btn\" (click)=\"goToRightToday()\" [disabled]=\"disabled || isDateDisabled(today.getFullYear(), today.getMonth(), today.getDate())\">Today</button>\r\n </div>\r\n\r\n <!-- YEAR GRID -->\r\n <div class=\"bk-grid-picker\" *ngIf=\"rightView === 'years'\">\r\n <div class=\"bk-year-grid\" role=\"listbox\" aria-label=\"Select year\">\r\n <button\r\n *ngFor=\"let y of getYearGridYears(rightYearRangeStart)\"\r\n type=\"button\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"y === rightYear\"\r\n [class.active]=\"y === rightYear\"\r\n [class.current]=\"isCurrentYear(y)\"\r\n [disabled]=\"isYearDisabled(y)\"\r\n (click)=\"selectRightYearFromGrid(y)\"\r\n class=\"bk-year-cell\">\r\n {{ y }}\r\n </button>\r\n </div>\r\n <button type=\"button\" class=\"bk-today-btn\" (click)=\"goToRightToday()\" [disabled]=\"disabled || isDateDisabled(today.getFullYear(), today.getMonth(), today.getDate())\">Today</button>\r\n </div>\r\n\r\n <!-- End Time Picker for Dual Calendar -->\r\n <div *ngIf=\"enableTimepicker && rightView === 'days'\" 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 [variation]=\"compact ? 'default' : 'lg'\"\r\n [timeFormat]=\"timeFormat\"\r\n [clearable]=\"clearableTime\"\r\n [label]=\"''\"\r\n [ngModel]=\"endTimeModel\"\r\n (ngModelChange)=\"onDualTimePickerChange($event, false); endTimeModel=$event\"\r\n [closePicker]=\"shouldClosePicker('dual-end')\"\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: month/year-only selection commits on click (like autoApply) \u2014 no Apply/Cancel to show. -->\r\n <div class=\"footer\" *ngIf=\"!inline && showCancelApply && pickerView === 'day'\">\r\n <button *ngIf=\"showCancel\" (click)=\"cancel()\" class=\"btn-cancel\" type=\"button\">Cancel</button>\r\n <button (click)=\"apply()\" class=\"btn-apply\" type=\"button\" [disabled]=\"disabled || isDualRangeApplyBlocked\">Apply</button>\r\n </div>\r\n\r\n </div>\r\n\r\n </ng-template>\r\n\r\n <!-- INLINE: rendered directly in normal flow, no overlay -->\r\n <div #calendarPopup\r\n *ngIf=\"inline\"\r\n class=\"calendar-popup inline-calendar\"\r\n tabindex=\"0\"\r\n (keydown)=\"onCalendarPopupKeydown($event)\"\r\n [ngClass]=\"{\r\n 'has-ranges': showRanges && customRanges,\r\n 'dual-calendar-mode': dualCalendar,\r\n 'compact': compact\r\n }\">\r\n <ng-container *ngTemplateOutlet=\"popupContent\"></ng-container>\r\n </div>\r\n</div>\r\n\r\n@if (hasError){\r\n<p class=\"calender-error\">{{errorMessage}}</p>\r\n}\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}.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{width:320px;background:#fff;border-radius:12px;box-shadow:0 10px 40px #00000026;z-index:1000;animation:slideDown .2s ease-out;font-family:Inter,sans-serif;scrollbar-width:thin;scrollbar-color:#c1c1c1 transparent}.calendar-popup::-webkit-scrollbar{width:6px}.calendar-popup::-webkit-scrollbar-track{background:transparent}.calendar-popup::-webkit-scrollbar-thumb{background:#c1c1c1;border-radius:3px}.calendar-popup::-webkit-scrollbar-thumb:hover{background:#a8a8a8}.calendar-popup:focus-visible{outline:0!important}.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.drop-up{animation:slideUp .2s ease-out}@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;scrollbar-width:thin;scrollbar-color:#888 #f1f1f1}.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}.header{display:flex;justify-content:space-between;align-items:center;padding:12px 0;min-height:54px;box-sizing:border-box}.month-year{font-size:15px;font-weight:500;color:#333;flex:1;display:flex;align-items:center;justify-content:center;text-align:center;text-transform:capitalize}.bk-month-year-btn{@apply bg-transparent border-0 rounded py-1 px-1 cursor-pointer transition-all duration-200;font:inherit;color:inherit;text-transform:inherit}.bk-month-year-btn:hover:not(:disabled){@apply text-black;}.bk-month-year-btn:disabled{@apply cursor-not-allowed text-[#ccc] opacity-50;}.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{max-width:none!important}.nav-btn:disabled{cursor:not-allowed;opacity:.35;pointer-events:none}.bk-grid-picker{@apply flex flex-col box-border h-[256px];}.bk-month-grid,.bk-year-grid{@apply grid grid-cols-3 auto-rows-min shrink-0 gap-[18px];}.bk-today-btn{@apply shrink-0 w-full p-2 mt-2 border border-[#eee] rounded-md bg-transparent text-[#333] text-[13px] font-medium cursor-pointer transition-all duration-200;}.bk-today-btn:hover:not(:disabled){@apply bg-[#efefef] text-black;}.bk-today-btn:disabled{@apply text-[#ddd] cursor-not-allowed opacity-50;}.bk-month-cell,.bk-year-cell{@apply flex items-center justify-center py-2.5 px-1 text-[13px] font-medium text-[#333] bg-transparent border-0 rounded-md cursor-pointer text-center transition-all duration-200;}.bk-month-cell:hover:not(:disabled):not(.active):not(.current),.bk-year-cell:hover:not(:disabled):not(.active):not(.current){@apply bg-[#efefef] text-black;}.bk-month-cell.active,.bk-year-cell.active{@apply bg-black text-white font-semibold;}.bk-month-cell.current:not(.active),.bk-year-cell.current:not(.active){@apply bg-[#e5e4e4] font-semibold;}.bk-month-cell:disabled,.bk-year-cell:disabled{@apply text-[#ddd] cursor-not-allowed opacity-50;}.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.today.disabled,.bk-month-cell.current:disabled,.bk-year-cell.current:disabled{color:#a9a9a9}.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%}.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-apply{background:#000;color:#fff}.btn-apply:active{transform:translateY(0)}@media (max-width: 576px){.calendar-popup.dual-calendar-mode{max-width:300px}}@media (max-width: 768px){.dual-calendar{flex-direction:column}}@media (min-width: 577px) and (max-width: 1024px){.calendar-popup.dual-calendar-mode{max-width:500px}}@media (max-width: 1024px){.calendar-popup{width:100%;max-width:320px;max-height:300px;overflow:auto}.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}.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}.calendar-input.calendar-input-has-error{@apply border-[#d11e14];}.calendar-input:disabled{cursor:not-allowed;border-color:#e3e3e7;background-color:#f4f4f6;color:#a1a3ae}.btn-apply:disabled{cursor:not-allowed!important;opacity:.7}.calendar-day.calendar-day-keyboard-focus:not(.disabled):not(.other-month){outline:0px solid #000}.calendar-popup.compact{width:240px}.calendar-popup.compact.has-ranges{width:380px}.calendar-popup.compact.dual-calendar-mode{width:480px}.calendar-popup.compact.dual-calendar-mode.has-ranges{width:600px}.calendar-popup.compact .header{padding:8px 0;min-height:40px}.calendar-popup.compact .month-year{font-size:13px}.calendar-popup.compact .nav-btn{height:24px;width:24px;padding:6px 8px}.calendar-popup.compact .calendar-wrapper,.calendar-popup.compact .calendar-left,.calendar-popup.compact .calendar-right{padding:0 8px 8px}.calendar-popup.compact .weekday-header{font-size:11px;padding:4px 2px}.calendar-popup.compact .calendar-day{font-size:12px;padding:5px 2px;line-height:1.3}.calendar-popup.compact .ranges{min-width:120px;gap:2px;margin-bottom:8px;padding-bottom:8px}.calendar-popup.compact.has-ranges .ranges{padding:6px}.calendar-popup.compact .range-btn{font-size:12px;padding:5px 8px}.calendar-popup.compact .timepicker-section{margin-top:8px;padding-top:8px}.calendar-popup.compact .timepicker-label{font-size:11px}.calendar-popup.compact .footer{padding:8px;gap:6px}.calendar-popup.compact .btn-cancel,.calendar-popup.compact .btn-apply{font-size:11px;padding:6px 12px;min-width:64px}.calendar-popup.compact .bk-month-year-btn{@apply text-[13px] py-px px-1;}.calendar-popup.compact .nav-btn img{width:12px;height:8px}.calendar-popup.compact .bk-nav-btn-year img{width:12px;height:12px}.calendar-popup.compact .bk-grid-picker{@apply h-[178px];@apply justify-center;}.calendar-popup.compact .bk-month-grid,.calendar-popup.compact .bk-year-grid{@apply gap-1;}.calendar-popup.compact .bk-month-cell,.calendar-popup.compact .bk-year-cell{@apply text-[11px] py-1.5 px-0.5;}.calendar-popup.compact .bk-today-btn{@apply text-[11px] p-[5px];}\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: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: BkTimePicker, selector: "bk-time-picker", inputs: ["required", "value", "label", "placeholder", "clearable", "position", "variation", "pickerId", "closePicker", "timeFormat", "showSeconds", "autoPosition", "appendToBody", "viewportMargin", "panelClass", "disabled"], outputs: ["change", "timeChange", "pickerOpened", "pickerClosed"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i2.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i2.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }] });
3098
4032
  }
3099
4033
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkCustomCalendar, decorators: [{
3100
4034
  type: Component,
3101
- args: [{ selector: 'bk-custom-calendar', standalone: true, imports: [CommonModule, FormsModule, BkTimePicker], providers: [
4035
+ args: [{ selector: 'bk-custom-calendar', standalone: true, imports: [CommonModule, FormsModule, BkTimePicker, OverlayModule], providers: [
3102
4036
  {
3103
4037
  provide: NG_VALUE_ACCESSOR,
3104
4038
  useExisting: forwardRef(() => BkCustomCalendar),
@@ -3109,8 +4043,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
3109
4043
  useExisting: forwardRef(() => BkCustomCalendar),
3110
4044
  multi: true,
3111
4045
  },
3112
- ], template: "<div class=\"calendar-container relative\" [class.open]=\"show\" [class.inline-mode]=\"inline\" [class.disabled]=\"disabled\">\r\n <!-- Input field -->\r\n <div #inputWrapper class=\"input-wrapper\" *ngIf=\"!inline\">\r\n <input\r\n type=\"text\"\r\n (click)=\"!disabled && toggle()\"\r\n (keydown.enter)=\"$event.preventDefault()\"\r\n (blur)=\"markAsTouched()\"\r\n readonly\r\n [value]=\"getDisplayValue()\"\r\n [placeholder]=\"placeholder\"\r\n [attr.disabled]=\"disabled ? true : null\"\r\n [class.hasError]=\"hasError\"\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 type=\"button\" class=\"clear-btn\" *ngIf=\"getDisplayValue() && isDisplayCrossIcon && !disabled\" (click)=\"clear(); $event.stopPropagation()\" title=\"Clear\">\u00D7</button>\r\n </div>\r\n\r\n <!-- Calendar Popup / Inline -->\r\n <div #calendarPopup\r\n class=\"calendar-popup\"\r\n [class.inline-calendar]=\"inline\"\r\n [class.append-to-body]=\"appendToBody && !inline\"\r\n [style.position]=\"appendToBody && !inline ? 'fixed' : null\"\r\n [style.top]=\"appendToBody && !inline && !popupPlacementAbove ? dropdownStyle.top : null\"\r\n [style.bottom]=\"appendToBody && !inline && popupPlacementAbove ? dropdownStyle.bottom : null\"\r\n [style.left]=\"appendToBody && !inline ? dropdownStyle.left : null\"\r\n tabindex=\"0\"\r\n (keydown)=\"onCalendarPopupKeydown($event)\"\r\n [ngClass]=\"{\r\n 'position-right': !inline && !appendToBody && opens === 'right',\r\n 'position-center': !inline && !appendToBody && opens === 'center',\r\n 'drop-up': !inline && popupPlacementAbove,\r\n 'has-ranges': showRanges && customRanges,\r\n 'dual-calendar-mode': dualCalendar,\r\n 'compact': compact\r\n }\"\r\n *ngIf=\"inline || show\">\r\n\r\n <!-- RANGES -->\r\n <div class=\"ranges\" *ngIf=\"showRanges && customRanges\" role=\"listbox\" aria-label=\"Date ranges\">\r\n <button\r\n type=\"button\"\r\n *ngFor=\"let rangeKey of rangeOrder\"\r\n (click)=\"chooseRange(rangeKey)\"\r\n (keydown)=\"onRangeButtonKeydown($event, rangeKey)\"\r\n [class.active]=\"activeRange === rangeKey\"\r\n [class.custom-range]=\"rangeKey === 'Custom Range'\"\r\n class=\"range-btn\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"activeRange === rangeKey\">\r\n {{ rangeKey }}\r\n </button>\r\n </div>\r\n<div class=\"\" [ngClass]=\"showRanges ? 'w-100 flex-grow-1 border-l border-[#eee]' : ''\">\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\" role=\"grid\" [attr.aria-label]=\"getMonthName(month) + ' ' + year\">\r\n <thead>\r\n <tr role=\"row\">\r\n <th *ngFor=\"let d of resolvedWeekDayLabels\" class=\"weekday-header\" scope=\"col\" role=\"columnheader\">{{ d }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let week of calendar\" role=\"row\">\r\n <td\r\n *ngFor=\"let dayObj of week\"\r\n role=\"gridcell\"\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-keyboard-focus]=\"dayObj.currentMonth && isKeyboardFocusedCell(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 [variation]=\"compact ? 'default' : 'lg'\"\r\n [timeFormat]=\"timeFormat\"\r\n [clearable]=\"clearableTime\"\r\n [label]=\"''\"\r\n [ngModel]=\"singleTimeModel\"\r\n (ngModelChange)=\"onSingleTimePickerChange($event); singleTimeModel=$event\"\r\n [closePicker]=\"shouldClosePicker('single-time')\"\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\" role=\"grid\" [attr.aria-label]=\"getMonthName(leftMonth) + ' ' + leftYear\">\r\n <thead>\r\n <tr role=\"row\">\r\n <th *ngFor=\"let d of resolvedWeekDayLabels\" class=\"weekday-header\" scope=\"col\" role=\"columnheader\">{{ d }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let week of leftCalendar\" role=\"row\">\r\n <td\r\n *ngFor=\"let dayObj of week\"\r\n role=\"gridcell\"\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-keyboard-focus]=\"dayObj.currentMonth && isKeyboardFocusedCell(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 [variation]=\"compact ? 'default' : 'lg'\"\r\n [timeFormat]=\"timeFormat\"\r\n [clearable]=\"clearableTime\"\r\n [label]=\"''\"\r\n [ngModel]=\"startTimeModel\"\r\n (ngModelChange)=\"onDualTimePickerChange($event, true); startTimeModel=$event\"\r\n [closePicker]=\"shouldClosePicker('dual-start')\"\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\" role=\"grid\" [attr.aria-label]=\"getMonthName(rightMonth) + ' ' + rightYear\">\r\n <thead>\r\n <tr role=\"row\">\r\n <th *ngFor=\"let d of resolvedWeekDayLabels\" class=\"weekday-header\" scope=\"col\" role=\"columnheader\">{{ d }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let week of rightCalendar\" role=\"row\">\r\n <td\r\n *ngFor=\"let dayObj of week\"\r\n role=\"gridcell\"\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-keyboard-focus]=\"dayObj.currentMonth && isKeyboardFocusedCell(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 [variation]=\"compact ? 'default' : 'lg'\"\r\n [timeFormat]=\"timeFormat\"\r\n [clearable]=\"clearableTime\"\r\n [label]=\"''\"\r\n [ngModel]=\"endTimeModel\"\r\n (ngModelChange)=\"onDualTimePickerChange($event, false); endTimeModel=$event\"\r\n [closePicker]=\"shouldClosePicker('dual-end')\"\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 && showCancelApply\">\r\n <button *ngIf=\"showCancel\" (click)=\"cancel()\" class=\"btn-cancel\" type=\"button\">Cancel</button>\r\n <button (click)=\"apply()\" class=\"btn-apply\" type=\"button\" [disabled]=\"disabled || isDualRangeApplyBlocked\">Apply</button>\r\n </div>\r\n\r\n </div>\r\n\r\n </div>\r\n</div>\r\n\r\n@if (hasError){\r\n<p class=\"calender-error\">{{errorMessage}}</p>\r\n}\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}.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:focus-visible{outline:0!important}.calendar-popup.append-to-body{font-family:Inter,sans-serif;z-index:100000}.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.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}.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%}.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-apply{background:#000;color:#fff}.btn-apply:active{transform:translateY(0)}@media (max-width: 768px){.calendar-popup{width:100%;max-width:320px;max-height:300px;overflow:auto}.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}.calendar-input.calendar-input-has-error{@apply border-[#d11e14];}.calendar-input:disabled{cursor:not-allowed;border-color:#e3e3e7;background-color:#f4f4f6;color:#a1a3ae}.btn-apply:disabled{cursor:not-allowed!important;opacity:.7}.calendar-day.calendar-day-keyboard-focus:not(.disabled):not(.other-month){outline:0px solid #000}.calendar-popup.compact{width:240px}.calendar-popup.compact.has-ranges{width:380px}.calendar-popup.compact.dual-calendar-mode{width:480px}.calendar-popup.compact.dual-calendar-mode.has-ranges{width:600px}.calendar-popup.compact .header{padding:8px 0}.calendar-popup.compact .month-year{font-size:13px}.calendar-popup.compact .nav-btn{height:24px;width:24px;padding:6px 8px}.calendar-popup.compact .calendar-wrapper,.calendar-popup.compact .calendar-left,.calendar-popup.compact .calendar-right{padding:0 8px 8px}.calendar-popup.compact .weekday-header{font-size:11px;padding:4px 2px}.calendar-popup.compact .calendar-day{font-size:12px;padding:5px 2px;line-height:1.3}.calendar-popup.compact .ranges{min-width:120px;gap:2px;margin-bottom:8px;padding-bottom:8px}.calendar-popup.compact.has-ranges .ranges{padding:6px}.calendar-popup.compact .range-btn{font-size:12px;padding:5px 8px}.calendar-popup.compact .timepicker-section{margin-top:8px;padding-top:8px}.calendar-popup.compact .timepicker-label{font-size:11px}.calendar-popup.compact .footer{padding:8px;gap:6px}.calendar-popup.compact .btn-cancel,.calendar-popup.compact .btn-apply{font-size:11px;padding:6px 12px;min-width:64px}\n"] }]
3113
- }], ctorParameters: () => [{ type: BkCalendarManagerService }, { type: i0.Renderer2 }], propDecorators: { enableTimepicker: [{
4046
+ ], template: "<div class=\"calendar-container relative\" [class.open]=\"show\" [class.inline-mode]=\"inline\" [class.disabled]=\"disabled\">\r\n <!-- Input field + its CDK overlay share one *ngIf=\"!inline\" scope so the origin's template ref\r\n (#calendarOrigin) is visible to the overlay template below \u2014 a ref declared inside one *ngIf\r\n embedded view isn't visible from a different (even identically-conditioned) *ngIf. -->\r\n <ng-container *ngIf=\"!inline\">\r\n <div #inputWrapper cdkOverlayOrigin #calendarOrigin=\"cdkOverlayOrigin\" class=\"input-wrapper\">\r\n <input\r\n type=\"text\"\r\n (mousedown)=\"onTriggerMouseDown($event)\"\r\n (focus)=\"onTriggerFocus()\"\r\n (keydown.enter)=\"onTriggerKeydownOpen($event)\"\r\n (keydown.space)=\"onTriggerKeydownOpen($event)\"\r\n (keydown.arrowDown)=\"onTriggerKeydownOpen($event)\"\r\n (blur)=\"onTriggerBlur()\"\r\n readonly\r\n [value]=\"getDisplayValue()\"\r\n [placeholder]=\"placeholder\"\r\n [attr.disabled]=\"disabled ? true : null\"\r\n [class.hasError]=\"hasError\"\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 type=\"button\" class=\"clear-btn\" *ngIf=\"getDisplayValue() && isDisplayCrossIcon && !disabled\" (click)=\"clear(); $event.stopPropagation()\" title=\"Clear\">\u00D7</button>\r\n </div>\r\n\r\n <!-- Positioned via Angular CDK Overlay, portalled into the shared cdk-overlay-container so it\r\n escapes clipping/stacking inside dialogs and scroll containers regardless of the old\r\n appendToBody flag (see its @deprecated note in the component). -->\r\n <ng-template\r\n cdkConnectedOverlay\r\n #calendarOverlay=\"cdkConnectedOverlay\"\r\n [cdkConnectedOverlayOrigin]=\"calendarOrigin\"\r\n [cdkConnectedOverlayOpen]=\"show\"\r\n [cdkConnectedOverlayPositions]=\"calendarPositions\"\r\n [cdkConnectedOverlayPush]=\"true\"\r\n [cdkConnectedOverlayViewportMargin]=\"viewportMargin\"\r\n [cdkConnectedOverlayPanelClass]=\"panelClass\"\r\n [cdkConnectedOverlayFlexibleDimensions]=\"false\"\r\n (positionChange)=\"onPositionChange($event)\"\r\n (overlayOutsideClick)=\"onOverlayOutsideClick()\"\r\n (detach)=\"close()\">\r\n <div #calendarPopup\r\n class=\"calendar-popup\"\r\n tabindex=\"0\"\r\n (keydown)=\"onCalendarPopupKeydown($event)\"\r\n (wheel)=\"onCalendarPopupWheel($event)\"\r\n [ngClass]=\"{\r\n 'drop-up': popupPlacementAbove,\r\n 'has-ranges': showRanges && customRanges,\r\n 'dual-calendar-mode': dualCalendar,\r\n 'compact': compact\r\n }\">\r\n <ng-container *ngTemplateOutlet=\"popupContent\"></ng-container>\r\n </div>\r\n </ng-template>\r\n </ng-container>\r\n\r\n <!-- Popup content \u2014 written once, projected into whichever render path below is active -->\r\n <ng-template #popupContent>\r\n <!-- RANGES: date-range shortcuts don't apply once selection is restricted to a month/year. -->\r\n <div class=\"ranges\" *ngIf=\"showRanges && customRanges && pickerView === 'day'\" role=\"listbox\" aria-label=\"Date ranges\">\r\n <button\r\n type=\"button\"\r\n *ngFor=\"let rangeKey of rangeOrder\"\r\n (click)=\"chooseRange(rangeKey)\"\r\n (keydown)=\"onRangeButtonKeydown($event, rangeKey)\"\r\n [class.active]=\"activeRange === rangeKey\"\r\n [class.custom-range]=\"rangeKey === 'Custom Range'\"\r\n class=\"range-btn\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"activeRange === rangeKey\">\r\n {{ rangeKey }}\r\n </button>\r\n </div>\r\n<div class=\"\" [ngClass]=\"showRanges && pickerView === 'day' ? 'w-100 flex-grow-1 border-l border-[#eee]' : ''\">\r\n\r\n\r\n <!-- SINGLE CALENDAR -->\r\n <div *ngIf=\"!dualCalendar\" class=\"calendar-wrapper\">\r\n\r\n <!-- DAY GRID HEADER -->\r\n <div class=\"header\" *ngIf=\"view === 'days'\">\r\n <button class=\"nav-btn bk-nav-btn-year\" type=\"button\" (click)=\"prevYear()\" [disabled]=\"isPrevYearDisabled(year)\" title=\"Prev year\">\r\n <img alt=\"prev year\" [src]=\"brickclayIcons.arrowLeftDouble\"/>\r\n </button>\r\n <button class=\"nav-btn\" type=\"button\" (click)=\"prevMonth()\" title=\"Prev month\">\r\n <img alt=\"prev\" [src]=\"brickclayIcons.arrowleft\"/>\r\n </button>\r\n <span class=\"month-year\">\r\n <button type=\"button\" class=\"bk-month-year-btn\" (click)=\"openMonthView()\" [disabled]=\"disabled\">{{ getMonthName(month) }}</button>\r\n <button type=\"button\" class=\"bk-month-year-btn\" (click)=\"openYearView()\" [disabled]=\"disabled\">{{ year }}</button>\r\n </span>\r\n <button class=\"nav-btn\" type=\"button\" (click)=\"nextMonth()\" title=\"Next month\">\r\n <img alt=\"next\" [src]='brickclayIcons.arrowRight'/>\r\n </button>\r\n <button class=\"nav-btn bk-nav-btn-year\" type=\"button\" (click)=\"nextYear()\" [disabled]=\"isNextYearDisabled(year)\" title=\"Next year\">\r\n <img alt=\"next year\" [src]=\"brickclayIcons.arrowRightDouble\"/>\r\n </button>\r\n </div>\r\n\r\n <!-- MONTH GRID HEADER -->\r\n <div class=\"header\" *ngIf=\"view === 'months'\">\r\n <button class=\"nav-btn bk-nav-btn-year\" type=\"button\" (click)=\"prevMonthGridYear()\" [disabled]=\"isPrevYearDisabled(year)\" title=\"Prev year\">\r\n <img alt=\"prev year\" [src]=\"brickclayIcons.arrowLeftDouble\"/>\r\n </button>\r\n <span class=\"month-year\">\r\n <button type=\"button\" class=\"bk-month-year-btn\" (click)=\"openYearView()\" [disabled]=\"disabled\">{{ year }}</button>\r\n </span>\r\n <button class=\"nav-btn bk-nav-btn-year\" type=\"button\" (click)=\"nextMonthGridYear()\" [disabled]=\"isNextYearDisabled(year)\" title=\"Next year\">\r\n <img alt=\"next year\" [src]=\"brickclayIcons.arrowRightDouble\"/>\r\n </button>\r\n </div>\r\n\r\n <!-- YEAR GRID HEADER -->\r\n <div class=\"header\" *ngIf=\"view === 'years'\">\r\n <button class=\"nav-btn bk-nav-btn-year\" type=\"button\" (click)=\"prevYearRange()\" title=\"Prev years\">\r\n <img alt=\"prev\" [src]=\"brickclayIcons.arrowLeftDouble\"/>\r\n </button>\r\n <span class=\"month-year\">{{ yearRangeStart }} - {{ yearRangeStart + 11 }}</span>\r\n <button class=\"nav-btn bk-nav-btn-year\" type=\"button\" (click)=\"nextYearRange()\" title=\"Next years\">\r\n <img alt=\"next\" [src]=\"brickclayIcons.arrowRightDouble\"/>\r\n </button>\r\n </div>\r\n\r\n <table class=\"calendar-table\" *ngIf=\"view === 'days'\" role=\"grid\" [attr.aria-label]=\"getMonthName(month) + ' ' + year\">\r\n <thead>\r\n <tr role=\"row\">\r\n <th *ngFor=\"let d of resolvedWeekDayLabels\" class=\"weekday-header\" scope=\"col\" role=\"columnheader\">{{ d }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let week of calendar\" role=\"row\">\r\n <td\r\n *ngFor=\"let dayObj of week\"\r\n role=\"gridcell\"\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-keyboard-focus]=\"dayObj.currentMonth && isKeyboardFocusedCell(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 <!-- MONTH GRID -->\r\n <div class=\"bk-grid-picker\" *ngIf=\"view === 'months'\">\r\n <div class=\"bk-month-grid\" role=\"listbox\" [attr.aria-label]=\"'Select month for ' + year\">\r\n <button\r\n *ngFor=\"let m of monthNamesShort; let i = index\"\r\n type=\"button\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"i === month\"\r\n [class.active]=\"i === month\"\r\n [class.current]=\"isCurrentMonth(i, year)\"\r\n [disabled]=\"isMonthDisabled(i, year)\"\r\n (click)=\"selectMonthFromGrid(i)\"\r\n class=\"bk-month-cell\">\r\n {{ m }}\r\n </button>\r\n </div>\r\n <button type=\"button\" class=\"bk-today-btn\" (click)=\"goToToday()\" [disabled]=\"disabled || isDateDisabled(today.getFullYear(), today.getMonth(), today.getDate())\">Today</button>\r\n </div>\r\n\r\n <!-- YEAR GRID -->\r\n <div class=\"bk-grid-picker\" *ngIf=\"view === 'years'\">\r\n <div class=\"bk-year-grid\" role=\"listbox\" aria-label=\"Select year\">\r\n <button\r\n *ngFor=\"let y of getYearGridYears(yearRangeStart)\"\r\n type=\"button\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"y === year\"\r\n [class.active]=\"y === year\"\r\n [class.current]=\"isCurrentYear(y)\"\r\n [disabled]=\"isYearDisabled(y)\"\r\n (click)=\"selectYearFromGrid(y)\"\r\n class=\"bk-year-cell\">\r\n {{ y }}\r\n </button>\r\n </div>\r\n <button type=\"button\" class=\"bk-today-btn\" (click)=\"goToToday()\" [disabled]=\"disabled || isDateDisabled(today.getFullYear(), today.getMonth(), today.getDate())\">Today</button>\r\n </div>\r\n\r\n <!-- Single Calendar Time Picker -->\r\n <div *ngIf=\"enableTimepicker && view === 'days'\" 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 [variation]=\"compact ? 'default' : 'lg'\"\r\n [timeFormat]=\"timeFormat\"\r\n [clearable]=\"clearableTime\"\r\n [label]=\"''\"\r\n [ngModel]=\"singleTimeModel\"\r\n (ngModelChange)=\"onSingleTimePickerChange($event); singleTimeModel=$event\"\r\n [closePicker]=\"shouldClosePicker('single-time')\"\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\" *ngIf=\"leftView === 'days'\">\r\n <button (click)=\"prevLeftYear()\" class=\"nav-btn bk-nav-btn-year\" type=\"button\" [disabled]=\"isPrevYearDisabled(leftYear)\" title=\"Prev year\">\r\n <img alt=\"prev year\" class=\"arrow-left\" [src]=\"brickclayIcons.arrowLeftDouble\"/>\r\n </button>\r\n <button (click)=\"prevLeftMonth()\" class=\"nav-btn\" type=\"button\" title=\"Prev month\">\r\n <img alt=\"arrow-left\" class=\"arrow-left\" [src]=\"brickclayIcons.arrowleft\"/>\r\n </button>\r\n <span class=\"month-year\">\r\n <button type=\"button\" class=\"bk-month-year-btn\" (click)=\"openLeftMonthView()\" [disabled]=\"disabled\">{{ getMonthName(leftMonth) }}</button>\r\n <button type=\"button\" class=\"bk-month-year-btn\" (click)=\"openLeftYearView()\" [disabled]=\"disabled\">{{ leftYear }}</button>\r\n </span>\r\n <button (click)=\"nextLeftMonth()\" class=\"nav-btn\" type=\"button\" title=\"Next month\">\r\n <img alt=\"arrow-right\" class=\"arrow-right\" [src]='brickclayIcons.arrowRight'/>\r\n </button>\r\n <button (click)=\"nextLeftYear()\" class=\"nav-btn bk-nav-btn-year\" type=\"button\" [disabled]=\"isNextYearDisabled(leftYear)\" title=\"Next year\">\r\n <img alt=\"next year\" class=\"arrow-right\" [src]=\"brickclayIcons.arrowRightDouble\"/>\r\n </button>\r\n </div>\r\n\r\n <!-- MONTH GRID HEADER -->\r\n <div class=\"header\" *ngIf=\"leftView === 'months'\">\r\n <button class=\"nav-btn bk-nav-btn-year\" type=\"button\" (click)=\"prevLeftMonthGridYear()\" [disabled]=\"isPrevYearDisabled(leftYear)\" title=\"Prev year\">\r\n <img alt=\"prev year\" [src]=\"brickclayIcons.arrowLeftDouble\"/>\r\n </button>\r\n <span class=\"month-year\">\r\n <button type=\"button\" class=\"bk-month-year-btn\" (click)=\"openLeftYearView()\" [disabled]=\"disabled\">{{ leftYear }}</button>\r\n </span>\r\n <button class=\"nav-btn bk-nav-btn-year\" type=\"button\" (click)=\"nextLeftMonthGridYear()\" [disabled]=\"isNextYearDisabled(leftYear)\" title=\"Next year\">\r\n <img alt=\"next year\" [src]=\"brickclayIcons.arrowRightDouble\"/>\r\n </button>\r\n </div>\r\n\r\n <!-- YEAR GRID HEADER -->\r\n <div class=\"header\" *ngIf=\"leftView === 'years'\">\r\n <button class=\"nav-btn bk-nav-btn-year\" type=\"button\" (click)=\"prevLeftYearRange()\" title=\"Prev years\">\r\n <img alt=\"prev\" [src]=\"brickclayIcons.arrowLeftDouble\"/>\r\n </button>\r\n <span class=\"month-year\">{{ leftYearRangeStart }} - {{ leftYearRangeStart + 11 }}</span>\r\n <button class=\"nav-btn bk-nav-btn-year\" type=\"button\" (click)=\"nextLeftYearRange()\" title=\"Next years\">\r\n <img alt=\"next\" [src]=\"brickclayIcons.arrowRightDouble\"/>\r\n </button>\r\n </div>\r\n\r\n <table class=\"calendar-table\" *ngIf=\"leftView === 'days'\" role=\"grid\" [attr.aria-label]=\"getMonthName(leftMonth) + ' ' + leftYear\">\r\n <thead>\r\n <tr role=\"row\">\r\n <th *ngFor=\"let d of resolvedWeekDayLabels\" class=\"weekday-header\" scope=\"col\" role=\"columnheader\">{{ d }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let week of leftCalendar\" role=\"row\">\r\n <td\r\n *ngFor=\"let dayObj of week\"\r\n role=\"gridcell\"\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-keyboard-focus]=\"dayObj.currentMonth && isKeyboardFocusedCell(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 <!-- MONTH GRID -->\r\n <div class=\"bk-grid-picker\" *ngIf=\"leftView === 'months'\">\r\n <div class=\"bk-month-grid\" role=\"listbox\" [attr.aria-label]=\"'Select month for ' + leftYear\">\r\n <button\r\n *ngFor=\"let m of monthNamesShort; let i = index\"\r\n type=\"button\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"i === leftMonth\"\r\n [class.active]=\"i === leftMonth\"\r\n [class.current]=\"isCurrentMonth(i, leftYear)\"\r\n [disabled]=\"isMonthDisabled(i, leftYear)\"\r\n (click)=\"selectLeftMonthFromGrid(i)\"\r\n class=\"bk-month-cell\">\r\n {{ m }}\r\n </button>\r\n </div>\r\n <button type=\"button\" class=\"bk-today-btn\" (click)=\"goToLeftToday()\" [disabled]=\"disabled || isDateDisabled(today.getFullYear(), today.getMonth(), today.getDate())\">Today</button>\r\n </div>\r\n\r\n <!-- YEAR GRID -->\r\n <div class=\"bk-grid-picker\" *ngIf=\"leftView === 'years'\">\r\n <div class=\"bk-year-grid\" role=\"listbox\" aria-label=\"Select year\">\r\n <button\r\n *ngFor=\"let y of getYearGridYears(leftYearRangeStart)\"\r\n type=\"button\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"y === leftYear\"\r\n [class.active]=\"y === leftYear\"\r\n [class.current]=\"isCurrentYear(y)\"\r\n [disabled]=\"isYearDisabled(y)\"\r\n (click)=\"selectLeftYearFromGrid(y)\"\r\n class=\"bk-year-cell\">\r\n {{ y }}\r\n </button>\r\n </div>\r\n <button type=\"button\" class=\"bk-today-btn\" (click)=\"goToLeftToday()\" [disabled]=\"disabled || isDateDisabled(today.getFullYear(), today.getMonth(), today.getDate())\">Today</button>\r\n </div>\r\n\r\n <!-- Start Time Picker for Dual Calendar -->\r\n <div *ngIf=\"enableTimepicker && leftView === 'days'\" 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 [variation]=\"compact ? 'default' : 'lg'\"\r\n [timeFormat]=\"timeFormat\"\r\n [clearable]=\"clearableTime\"\r\n [label]=\"''\"\r\n [ngModel]=\"startTimeModel\"\r\n (ngModelChange)=\"onDualTimePickerChange($event, true); startTimeModel=$event\"\r\n [closePicker]=\"shouldClosePicker('dual-start')\"\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\" *ngIf=\"rightView === 'days'\">\r\n <button (click)=\"prevRightYear()\" class=\"nav-btn bk-nav-btn-year\" type=\"button\" [disabled]=\"isPrevYearDisabled(rightYear)\" title=\"Prev year\">\r\n <img alt=\"prev year\" class=\"arrow-left\" [src]=\"brickclayIcons.arrowLeftDouble\"/>\r\n </button>\r\n <button (click)=\"prevRightMonth()\" class=\"nav-btn\" type=\"button\" title=\"Prev month\">\r\n <img alt=\"arrow-left\" class=\"arrow-left\" [src]=\"brickclayIcons.arrowleft\"/>\r\n </button>\r\n <span class=\"month-year\">\r\n <button type=\"button\" class=\"bk-month-year-btn\" (click)=\"openRightMonthView()\" [disabled]=\"disabled\">{{ getMonthName(rightMonth) }}</button>\r\n <button type=\"button\" class=\"bk-month-year-btn\" (click)=\"openRightYearView()\" [disabled]=\"disabled\">{{ rightYear }}</button>\r\n </span>\r\n <button (click)=\"nextRightMonth()\" class=\"nav-btn\" type=\"button\" title=\"Next month\">\r\n <img alt=\"arrow-right\" class=\"arrow-right\" [src]='brickclayIcons.arrowRight'/>\r\n </button>\r\n <button (click)=\"nextRightYear()\" class=\"nav-btn bk-nav-btn-year\" type=\"button\" [disabled]=\"isNextYearDisabled(rightYear)\" title=\"Next year\">\r\n <img alt=\"next year\" class=\"arrow-right\" [src]=\"brickclayIcons.arrowRightDouble\"/>\r\n </button>\r\n </div>\r\n\r\n <!-- MONTH GRID HEADER -->\r\n <div class=\"header\" *ngIf=\"rightView === 'months'\">\r\n <button class=\"nav-btn bk-nav-btn-year\" type=\"button\" (click)=\"prevRightMonthGridYear()\" [disabled]=\"isPrevYearDisabled(rightYear)\" title=\"Prev year\">\r\n <img alt=\"prev year\" [src]=\"brickclayIcons.arrowLeftDouble\"/>\r\n </button>\r\n <span class=\"month-year\">\r\n <button type=\"button\" class=\"bk-month-year-btn\" (click)=\"openRightYearView()\" [disabled]=\"disabled\">{{ rightYear }}</button>\r\n </span>\r\n <button class=\"nav-btn bk-nav-btn-year\" type=\"button\" (click)=\"nextRightMonthGridYear()\" [disabled]=\"isNextYearDisabled(rightYear)\" title=\"Next year\">\r\n <img alt=\"next year\" [src]=\"brickclayIcons.arrowRightDouble\"/>\r\n </button>\r\n </div>\r\n\r\n <!-- YEAR GRID HEADER -->\r\n <div class=\"header\" *ngIf=\"rightView === 'years'\">\r\n <button class=\"nav-btn bk-nav-btn-year\" type=\"button\" (click)=\"prevRightYearRange()\" title=\"Prev years\">\r\n <img alt=\"prev\" [src]=\"brickclayIcons.arrowLeftDouble\"/>\r\n </button>\r\n <span class=\"month-year\">{{ rightYearRangeStart }} - {{ rightYearRangeStart + 11 }}</span>\r\n <button class=\"nav-btn bk-nav-btn-year\" type=\"button\" (click)=\"nextRightYearRange()\" title=\"Next years\">\r\n <img alt=\"next\" [src]=\"brickclayIcons.arrowRightDouble\"/>\r\n </button>\r\n </div>\r\n\r\n <table class=\"calendar-table\" *ngIf=\"rightView === 'days'\" role=\"grid\" [attr.aria-label]=\"getMonthName(rightMonth) + ' ' + rightYear\">\r\n <thead>\r\n <tr role=\"row\">\r\n <th *ngFor=\"let d of resolvedWeekDayLabels\" class=\"weekday-header\" scope=\"col\" role=\"columnheader\">{{ d }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let week of rightCalendar\" role=\"row\">\r\n <td\r\n *ngFor=\"let dayObj of week\"\r\n role=\"gridcell\"\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-keyboard-focus]=\"dayObj.currentMonth && isKeyboardFocusedCell(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 <!-- MONTH GRID -->\r\n <div class=\"bk-grid-picker\" *ngIf=\"rightView === 'months'\">\r\n <div class=\"bk-month-grid\" role=\"listbox\" [attr.aria-label]=\"'Select month for ' + rightYear\">\r\n <button\r\n *ngFor=\"let m of monthNamesShort; let i = index\"\r\n type=\"button\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"i === rightMonth\"\r\n [class.active]=\"i === rightMonth\"\r\n [class.current]=\"isCurrentMonth(i, rightYear)\"\r\n [disabled]=\"isMonthDisabled(i, rightYear)\"\r\n (click)=\"selectRightMonthFromGrid(i)\"\r\n class=\"bk-month-cell\">\r\n {{ m }}\r\n </button>\r\n </div>\r\n <button type=\"button\" class=\"bk-today-btn\" (click)=\"goToRightToday()\" [disabled]=\"disabled || isDateDisabled(today.getFullYear(), today.getMonth(), today.getDate())\">Today</button>\r\n </div>\r\n\r\n <!-- YEAR GRID -->\r\n <div class=\"bk-grid-picker\" *ngIf=\"rightView === 'years'\">\r\n <div class=\"bk-year-grid\" role=\"listbox\" aria-label=\"Select year\">\r\n <button\r\n *ngFor=\"let y of getYearGridYears(rightYearRangeStart)\"\r\n type=\"button\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"y === rightYear\"\r\n [class.active]=\"y === rightYear\"\r\n [class.current]=\"isCurrentYear(y)\"\r\n [disabled]=\"isYearDisabled(y)\"\r\n (click)=\"selectRightYearFromGrid(y)\"\r\n class=\"bk-year-cell\">\r\n {{ y }}\r\n </button>\r\n </div>\r\n <button type=\"button\" class=\"bk-today-btn\" (click)=\"goToRightToday()\" [disabled]=\"disabled || isDateDisabled(today.getFullYear(), today.getMonth(), today.getDate())\">Today</button>\r\n </div>\r\n\r\n <!-- End Time Picker for Dual Calendar -->\r\n <div *ngIf=\"enableTimepicker && rightView === 'days'\" 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 [variation]=\"compact ? 'default' : 'lg'\"\r\n [timeFormat]=\"timeFormat\"\r\n [clearable]=\"clearableTime\"\r\n [label]=\"''\"\r\n [ngModel]=\"endTimeModel\"\r\n (ngModelChange)=\"onDualTimePickerChange($event, false); endTimeModel=$event\"\r\n [closePicker]=\"shouldClosePicker('dual-end')\"\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: month/year-only selection commits on click (like autoApply) \u2014 no Apply/Cancel to show. -->\r\n <div class=\"footer\" *ngIf=\"!inline && showCancelApply && pickerView === 'day'\">\r\n <button *ngIf=\"showCancel\" (click)=\"cancel()\" class=\"btn-cancel\" type=\"button\">Cancel</button>\r\n <button (click)=\"apply()\" class=\"btn-apply\" type=\"button\" [disabled]=\"disabled || isDualRangeApplyBlocked\">Apply</button>\r\n </div>\r\n\r\n </div>\r\n\r\n </ng-template>\r\n\r\n <!-- INLINE: rendered directly in normal flow, no overlay -->\r\n <div #calendarPopup\r\n *ngIf=\"inline\"\r\n class=\"calendar-popup inline-calendar\"\r\n tabindex=\"0\"\r\n (keydown)=\"onCalendarPopupKeydown($event)\"\r\n [ngClass]=\"{\r\n 'has-ranges': showRanges && customRanges,\r\n 'dual-calendar-mode': dualCalendar,\r\n 'compact': compact\r\n }\">\r\n <ng-container *ngTemplateOutlet=\"popupContent\"></ng-container>\r\n </div>\r\n</div>\r\n\r\n@if (hasError){\r\n<p class=\"calender-error\">{{errorMessage}}</p>\r\n}\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}.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{width:320px;background:#fff;border-radius:12px;box-shadow:0 10px 40px #00000026;z-index:1000;animation:slideDown .2s ease-out;font-family:Inter,sans-serif;scrollbar-width:thin;scrollbar-color:#c1c1c1 transparent}.calendar-popup::-webkit-scrollbar{width:6px}.calendar-popup::-webkit-scrollbar-track{background:transparent}.calendar-popup::-webkit-scrollbar-thumb{background:#c1c1c1;border-radius:3px}.calendar-popup::-webkit-scrollbar-thumb:hover{background:#a8a8a8}.calendar-popup:focus-visible{outline:0!important}.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.drop-up{animation:slideUp .2s ease-out}@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;scrollbar-width:thin;scrollbar-color:#888 #f1f1f1}.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}.header{display:flex;justify-content:space-between;align-items:center;padding:12px 0;min-height:54px;box-sizing:border-box}.month-year{font-size:15px;font-weight:500;color:#333;flex:1;display:flex;align-items:center;justify-content:center;text-align:center;text-transform:capitalize}.bk-month-year-btn{@apply bg-transparent border-0 rounded py-1 px-1 cursor-pointer transition-all duration-200;font:inherit;color:inherit;text-transform:inherit}.bk-month-year-btn:hover:not(:disabled){@apply text-black;}.bk-month-year-btn:disabled{@apply cursor-not-allowed text-[#ccc] opacity-50;}.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{max-width:none!important}.nav-btn:disabled{cursor:not-allowed;opacity:.35;pointer-events:none}.bk-grid-picker{@apply flex flex-col box-border h-[256px];}.bk-month-grid,.bk-year-grid{@apply grid grid-cols-3 auto-rows-min shrink-0 gap-[18px];}.bk-today-btn{@apply shrink-0 w-full p-2 mt-2 border border-[#eee] rounded-md bg-transparent text-[#333] text-[13px] font-medium cursor-pointer transition-all duration-200;}.bk-today-btn:hover:not(:disabled){@apply bg-[#efefef] text-black;}.bk-today-btn:disabled{@apply text-[#ddd] cursor-not-allowed opacity-50;}.bk-month-cell,.bk-year-cell{@apply flex items-center justify-center py-2.5 px-1 text-[13px] font-medium text-[#333] bg-transparent border-0 rounded-md cursor-pointer text-center transition-all duration-200;}.bk-month-cell:hover:not(:disabled):not(.active):not(.current),.bk-year-cell:hover:not(:disabled):not(.active):not(.current){@apply bg-[#efefef] text-black;}.bk-month-cell.active,.bk-year-cell.active{@apply bg-black text-white font-semibold;}.bk-month-cell.current:not(.active),.bk-year-cell.current:not(.active){@apply bg-[#e5e4e4] font-semibold;}.bk-month-cell:disabled,.bk-year-cell:disabled{@apply text-[#ddd] cursor-not-allowed opacity-50;}.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.today.disabled,.bk-month-cell.current:disabled,.bk-year-cell.current:disabled{color:#a9a9a9}.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%}.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-apply{background:#000;color:#fff}.btn-apply:active{transform:translateY(0)}@media (max-width: 576px){.calendar-popup.dual-calendar-mode{max-width:300px}}@media (max-width: 768px){.dual-calendar{flex-direction:column}}@media (min-width: 577px) and (max-width: 1024px){.calendar-popup.dual-calendar-mode{max-width:500px}}@media (max-width: 1024px){.calendar-popup{width:100%;max-width:320px;max-height:300px;overflow:auto}.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}.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}.calendar-input.calendar-input-has-error{@apply border-[#d11e14];}.calendar-input:disabled{cursor:not-allowed;border-color:#e3e3e7;background-color:#f4f4f6;color:#a1a3ae}.btn-apply:disabled{cursor:not-allowed!important;opacity:.7}.calendar-day.calendar-day-keyboard-focus:not(.disabled):not(.other-month){outline:0px solid #000}.calendar-popup.compact{width:240px}.calendar-popup.compact.has-ranges{width:380px}.calendar-popup.compact.dual-calendar-mode{width:480px}.calendar-popup.compact.dual-calendar-mode.has-ranges{width:600px}.calendar-popup.compact .header{padding:8px 0;min-height:40px}.calendar-popup.compact .month-year{font-size:13px}.calendar-popup.compact .nav-btn{height:24px;width:24px;padding:6px 8px}.calendar-popup.compact .calendar-wrapper,.calendar-popup.compact .calendar-left,.calendar-popup.compact .calendar-right{padding:0 8px 8px}.calendar-popup.compact .weekday-header{font-size:11px;padding:4px 2px}.calendar-popup.compact .calendar-day{font-size:12px;padding:5px 2px;line-height:1.3}.calendar-popup.compact .ranges{min-width:120px;gap:2px;margin-bottom:8px;padding-bottom:8px}.calendar-popup.compact.has-ranges .ranges{padding:6px}.calendar-popup.compact .range-btn{font-size:12px;padding:5px 8px}.calendar-popup.compact .timepicker-section{margin-top:8px;padding-top:8px}.calendar-popup.compact .timepicker-label{font-size:11px}.calendar-popup.compact .footer{padding:8px;gap:6px}.calendar-popup.compact .btn-cancel,.calendar-popup.compact .btn-apply{font-size:11px;padding:6px 12px;min-width:64px}.calendar-popup.compact .bk-month-year-btn{@apply text-[13px] py-px px-1;}.calendar-popup.compact .nav-btn img{width:12px;height:8px}.calendar-popup.compact .bk-nav-btn-year img{width:12px;height:12px}.calendar-popup.compact .bk-grid-picker{@apply h-[178px];@apply justify-center;}.calendar-popup.compact .bk-month-grid,.calendar-popup.compact .bk-year-grid{@apply gap-1;}.calendar-popup.compact .bk-month-cell,.calendar-popup.compact .bk-year-cell{@apply text-[11px] py-1.5 px-0.5;}.calendar-popup.compact .bk-today-btn{@apply text-[11px] p-[5px];}\n"] }]
4047
+ }], ctorParameters: () => [{ type: BkCalendarManagerService }], propDecorators: { enableTimepicker: [{
3114
4048
  type: Input
3115
4049
  }], autoApply: [{
3116
4050
  type: Input
@@ -3122,6 +4056,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
3122
4056
  type: Input
3123
4057
  }], singleDatePicker: [{
3124
4058
  type: Input
4059
+ }], pickerView: [{
4060
+ type: Input
3125
4061
  }], showWeekNumbers: [{
3126
4062
  type: Input
3127
4063
  }], showISOWeekNumbers: [{
@@ -3156,6 +4092,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
3156
4092
  type: Input
3157
4093
  }], minDate: [{
3158
4094
  type: Input
4095
+ }], allowedMonths: [{
4096
+ type: Input
4097
+ }], allowedYears: [{
4098
+ type: Input
4099
+ }], allowedDaysOfWeek: [{
4100
+ type: Input
4101
+ }], disabledDates: [{
4102
+ type: Input
4103
+ }], allowedDates: [{
4104
+ type: Input
3159
4105
  }], placeholder: [{
3160
4106
  type: Input
3161
4107
  }], opens: [{
@@ -3164,10 +4110,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
3164
4110
  type: Input
3165
4111
  }], compact: [{
3166
4112
  type: Input
3167
- }], autoPosition: [{
3168
- type: Input
3169
4113
  }], appendToBody: [{
3170
4114
  type: Input
4115
+ }], viewportMargin: [{
4116
+ type: Input
4117
+ }], panelClass: [{
4118
+ type: Input
3171
4119
  }], isDisplayCrossIcon: [{
3172
4120
  type: Input
3173
4121
  }], hasError: [{
@@ -3182,6 +4130,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
3182
4130
  }], calendarPopupRef: [{
3183
4131
  type: ViewChild,
3184
4132
  args: ['calendarPopup']
4133
+ }], calendarOverlay: [{
4134
+ type: ViewChild,
4135
+ args: ['calendarOverlay']
3185
4136
  }], opened: [{
3186
4137
  type: Output
3187
4138
  }], closed: [{
@@ -3196,10 +4147,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
3196
4147
  type: Input
3197
4148
  }], rangeOrder: [{
3198
4149
  type: Input
3199
- }], onClickOutside: [{
3200
- type: HostListener,
3201
- args: ['document:click', ['$event']]
3202
4150
  }] } });
4151
+ /** Field-by-field equality for ConnectedPosition — CDK does not preserve object identity for
4152
+ * positions passed via cdkConnectedOverlayPositions, so `event.connectionPair` must be matched
4153
+ * by value against the entries handed to it, never by `===`. Same approach as bk-popover's
4154
+ * positionsEqual in popover-position.ts. */
4155
+ function positionsEqual$1(a, b) {
4156
+ return a.originX === b.originX && a.originY === b.originY &&
4157
+ a.overlayX === b.overlayX && a.overlayY === b.overlayY &&
4158
+ (a.offsetX ?? 0) === (b.offsetX ?? 0) && (a.offsetY ?? 0) === (b.offsetY ?? 0);
4159
+ }
3203
4160
 
3204
4161
  class BkScheduledDatePicker {
3205
4162
  timeFormat = 12;
@@ -3504,7 +4461,7 @@ class BkScheduledDatePicker {
3504
4461
  this.emitScheduled();
3505
4462
  }
3506
4463
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkScheduledDatePicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
3507
- 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 (change)=\"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 (change)=\"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 (change)=\"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 (change)=\"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 (change)=\"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 (change)=\"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", "popupPosition", "drop", "dualCalendar", "showRanges", "timeFormat", "clearableTime", "enableSeconds", "customRanges", "weekDayLabels", "multiDateSelection", "maxDate", "minDate", "placeholder", "opens", "inline", "compact", "autoPosition", "appendToBody", "isDisplayCrossIcon", "hasError", "errorMessage", "showCancelApply", "selectedValue", "displayFormat", "required", "rangeOrder"], outputs: ["selected", "opened", "closed"] }, { kind: "component", type: BkTimePicker, selector: "bk-time-picker", inputs: ["required", "value", "label", "placeholder", "clearable", "position", "variation", "pickerId", "closePicker", "timeFormat", "showSeconds", "autoPosition", "appendToBody", "disabled"], outputs: ["change", "timeChange", "pickerOpened", "pickerClosed"] }] });
4464
+ 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 (change)=\"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 (change)=\"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 (change)=\"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 (change)=\"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 (change)=\"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 (change)=\"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", "pickerView", "showWeekNumbers", "showISOWeekNumbers", "customRangeDirection", "lockStartDate", "position", "popupPosition", "drop", "dualCalendar", "showRanges", "timeFormat", "clearableTime", "enableSeconds", "customRanges", "weekDayLabels", "multiDateSelection", "maxDate", "minDate", "allowedMonths", "allowedYears", "allowedDaysOfWeek", "disabledDates", "allowedDates", "placeholder", "opens", "inline", "compact", "appendToBody", "viewportMargin", "panelClass", "isDisplayCrossIcon", "hasError", "errorMessage", "showCancelApply", "selectedValue", "displayFormat", "required", "rangeOrder"], outputs: ["selected", "opened", "closed"] }, { kind: "component", type: BkTimePicker, selector: "bk-time-picker", inputs: ["required", "value", "label", "placeholder", "clearable", "position", "variation", "pickerId", "closePicker", "timeFormat", "showSeconds", "autoPosition", "appendToBody", "viewportMargin", "panelClass", "disabled"], outputs: ["change", "timeChange", "pickerOpened", "pickerClosed"] }] });
3508
4465
  }
3509
4466
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkScheduledDatePicker, decorators: [{
3510
4467
  type: Component,
@@ -4180,13 +5137,13 @@ class BkTextarea {
4180
5137
  registerOnTouched(fn) {
4181
5138
  this.onTouched = fn;
4182
5139
  }
4183
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTextarea, deps: [{ token: i2.NgControl, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Component });
5140
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTextarea, deps: [{ token: i2$1.NgControl, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Component });
4184
5141
  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 @if (label) {\r\n <label 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 [autocomplete]=\"autoComplete\"\r\n rows=\"{{ rows }}\"\r\n class=\"w-full px-3 py-2.5 text-sm border border-[#E3E3E7] outline-none transition-colors duration-200 bg-white resize-y placeholder:text-[#6B7080] rounded bk-textarea-shadow \"\r\n [ngClass]=\"{\r\n 'border-[#FA727A]': hasError && !disabled,\r\n 'focus:border-[#6B7080]': !hasError && !disabled,\r\n '!bg-[#F4F4F6] !text-[#A1A3AE] cursor-not-allowed !border-[#E3E3E7]': 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 <div class=\"flex-1\">\r\n @if (hasError) {\r\n <span class=\"font-medium text-xs leading-normal text-[#C10007] text-left\">\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 class=\"text-[#868997] tabular-nums flex-shrink-0\">\r\n {{ value.length }}/{{ maxlength }}\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }] });
4185
5142
  }
4186
5143
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTextarea, decorators: [{
4187
5144
  type: Component,
4188
5145
  args: [{ selector: 'bk-textarea', standalone: true, imports: [CommonModule, FormsModule], template: "<div class=\"flex flex-col gap-1.5 w-full\">\r\n @if (label) {\r\n <label 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 [autocomplete]=\"autoComplete\"\r\n rows=\"{{ rows }}\"\r\n class=\"w-full px-3 py-2.5 text-sm border border-[#E3E3E7] outline-none transition-colors duration-200 bg-white resize-y placeholder:text-[#6B7080] rounded bk-textarea-shadow \"\r\n [ngClass]=\"{\r\n 'border-[#FA727A]': hasError && !disabled,\r\n 'focus:border-[#6B7080]': !hasError && !disabled,\r\n '!bg-[#F4F4F6] !text-[#A1A3AE] cursor-not-allowed !border-[#E3E3E7]': 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 <div class=\"flex-1\">\r\n @if (hasError) {\r\n <span class=\"font-medium text-xs leading-normal text-[#C10007] text-left\">\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 class=\"text-[#868997] tabular-nums flex-shrink-0\">\r\n {{ value.length }}/{{ maxlength }}\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n" }]
4189
- }], ctorParameters: () => [{ type: i2.NgControl, decorators: [{
5146
+ }], ctorParameters: () => [{ type: i2$1.NgControl, decorators: [{
4190
5147
  type: Optional
4191
5148
  }, {
4192
5149
  type: Self
@@ -4998,7 +5955,7 @@ class BkGrid {
4998
5955
  return this.noRecordImgUrl || './assets/icons/no-data-found.jpg';
4999
5956
  }
5000
5957
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkGrid, deps: [], target: i0.ɵɵFactoryTarget.Component });
5001
- 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", customClass: "customClass", actionIconClass: "actionIconClass", actionClass: "actionClass", showNoRecords: "showNoRecords", noRecordFoundHeight: "noRecordFoundHeight", noRecordImgUrl: "noRecordImgUrl", showNoRecordImg: "showNoRecordImg", noRecordMessage: "noRecordMessage", rows: "rows" }, outputs: { change: "change", actionClick: "actionClick", sortChange: "sortChange", dragDropChange: "dragDropChange" }, viewQueries: [{ propertyName: "tableScrollContainer", first: true, predicate: ["tableScrollContainer"], descendants: true }], ngImport: i0, template: "<div #tableScrollContainer cdkScrollable class=\"overflow-y-auto\" [ngClass]=\"customClass\">\r\n <table class=\"min-w-full text-sm text-left text-gray-800 table-auto border-collapse\">\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-[-1px]\"\r\n [class.cursor-pointer]=\"col.sortable\"\r\n [class.cursor-default]=\"!col.sortable\"\r\n [class.action-sticky]=\"col.sticky\"\r\n [class.z-10]=\"col.sticky\"\r\n class=\"{{ col.headerClass }} {{ col.cellClass }}\"\r\n (click)=\"sort(col, i)\"\r\n >\r\n <!-- [ngClass]=\"col.headerClass\"\r\n [ngClass]=\"col.cellClass\" -->\r\n <span\r\n class=\"flex items-center gap-1\"\r\n [ngClass]=\"\r\n sortColumn === col.field\r\n ? sortDirection === 'asc'\r\n ? 'grid-asc'\r\n : 'grid-desc'\r\n : ''\r\n \"\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 {{actionClass}}\">Action</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=\"\"\r\n [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\r\n cdkDragHandle\r\n class=\"mr-2 text-gray-400\"\r\n [ngClass]=\"{ 'cursor-move': draggable }\"\r\n >\u2630</span\r\n >\r\n }\r\n @if (col.checkbox) {\r\n <bk-checkbox\r\n checkboxClass=\"sm\"\r\n [ngModel]=\"getCheckboxValue(row, col)\"\r\n (ngModelChange)=\"setCheckboxValue(row, col, $event)\"\r\n [disabled]=\"typeof col.checkboxDisabled === 'function' ? col.checkboxDisabled(row) : col.checkboxDisabled || false\"\r\n [bkTooltip]=\"typeof col.checkboxTooltip === 'function' ? col.checkboxTooltip(row) : col.checkboxTooltip || ''\"\r\n [bkTooltipPosition]=\"col.checkboxTooltipPosition || 'top'\"\r\n ></bk-checkbox>\r\n } @else if (col.badges) {\r\n @let badge = getBadge(row, col);\r\n @if (badge) {\r\n <bk-badge\r\n [label]=\"badge.label\"\r\n [variant]=\"badge.variant\"\r\n [size]=\"badge.size\"\r\n [color]=\"badge.color\"\r\n [dot]=\"badge.dot\"\r\n [customClass]=\"badge.customClass\"\r\n [bkTooltip]=\"badge.toolTipLabel || ''\"\r\n [bkTooltipPosition]=\"badge.tooltipPosition || 'top'\"\r\n ></bk-badge>\r\n }\r\n } @else if (col.icons) {\r\n @let iconsList = getIcons(row, col);\r\n <div class=\"flex justify-center items-center gap-2\">\r\n @for (icon of iconsList; track $index) {\r\n @if(icon.url){\r\n <img\r\n [src]=\"icon.url\"\r\n class=\"size-4\"\r\n [ngClass]=\"{ 'cursor-pointer': icon.url }\"\r\n [bkTooltip]=\"icon.toolTipLabel || []\"\r\n [bkTooltipPosition]=\"icon.tooltipPosition || 'top'\"\r\n />\r\n }\r\n }\r\n </div>\r\n } @else if (col.toolTipField) {\r\n <span\r\n [bkTooltip]=\"getTooltipValue(row, col)\"\r\n [bkTooltipPosition]=\"col.toolTipPosition || 'top'\"\r\n >\r\n {{ getCellValue(row, col) }}\r\n </span>\r\n } @else {\r\n {{ getCellValue(row, col) }}\r\n }\r\n </td>\r\n }\r\n }\r\n\r\n @if (getRowActions(row).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 getRowActions(row); track action.name) {\r\n @if (isActionVisible(action, row)) {\r\n <!-- <bk-icon-button\r\n [bkTooltip]=\"action.tooltip\"\r\n [size]=\"\"\r\n [bkTooltipPosition]=\"action?.tooltipPosition || 'top'\"\r\n class=\"size-6 flex items-center justify-center rounded hover:bg-[#F8F8FA]\"\r\n (clicked)=\"emitAction(action, row)\"\r\n [disabled]=\"isActionDisabled(action, row)\">\r\n </bk-icon-button> -->\r\n <button\r\n [bkTooltip]=\"action.tooltip\"\r\n [bkTooltipPosition]=\"action?.tooltipPosition || 'top'\"\r\n class=\"size-6 flex items-center justify-center rounded hover:bg-[#F8F8FA] {{actionIconClass}}\"\r\n (click)=\"emitAction(action, row)\"\r\n [disabled]=\"isActionDisabled(action, row)\"\r\n >\r\n <img [src]=\"action.icon\" width=\"14\" height=\"14\" alt=\"action-icon\" />\r\n </button>\r\n }\r\n }\r\n </div>\r\n </td>\r\n }\r\n </tr>\r\n }\r\n @if (showNoRecords) {\r\n <tr>\r\n <td\r\n [attr.colspan]=\"columns.length + (actions.length ? 1 : 0)\"\r\n class=\"text-center py-10 {{ noRecordFoundHeight }}\"\r\n >\r\n <div class=\"flex flex-col justify-center items-center w-full h-auto\">\r\n @if (showNoRecordImg) {\r\n <img\r\n [src]=\"noRecordImagePath\"\r\n class=\"mb-3 w-96\"\r\n alt=\"No data found\"\r\n />\r\n }\r\n\r\n <span class=\"block text-sm leading-3 text-center font-semibold text-[#60646C] mt-2\"\r\n >{{ noRecordMessage }}</span\r\n >\r\n </div>\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n</div>\r\n", styles: [".grid-header{@apply bg-[#F9FAFA] text-xs text-[#60646C] font-semibold capitalize px-[17px] py-2.5 whitespace-nowrap;box-shadow:0 1px #ebedf3;-webkit-transform:translateZ(0);transform:translateZ(0);backface-visibility:hidden;-webkit-backface-visibility:hidden}thead tr th:first-child{border-top-left-radius:.75rem}thead tr th:last-child{border-top-right-radius:.75rem}.grid-cell{@apply text-[#15191E] text-[13px] font-medium leading-4 px-4 py-2 border-x border-b border-[#EBEDF3];}.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$1.ɵɵCdkScrollable, selector: "[cdk-scrollable], [cdkScrollable]" }, { kind: "directive", type: i2$1.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$1.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$1.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "component", type: BkBadge, selector: "bk-badge", inputs: ["label", "variant", "color", "size", "dot", "removable", "customClass", "customBg", "customBorder", "customText"], outputs: ["clicked"] }, { kind: "directive", type: BKTooltipDirective, selector: "[bkTooltip]", inputs: ["bkTooltip", "bkTooltipPosition", "bkTooltipScrollable", "bkTooltipMaxHeight", "bkTooltipSize", "bkTooltipAutoHeight"] }, { kind: "component", type: BkCheckbox, selector: "bk-checkbox", inputs: ["checkboxClass", "label", "labelClass", "disabled"], outputs: ["change"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
5958
+ 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", customClass: "customClass", actionIconClass: "actionIconClass", actionClass: "actionClass", showNoRecords: "showNoRecords", noRecordFoundHeight: "noRecordFoundHeight", noRecordImgUrl: "noRecordImgUrl", showNoRecordImg: "showNoRecordImg", noRecordMessage: "noRecordMessage", rows: "rows" }, outputs: { change: "change", actionClick: "actionClick", sortChange: "sortChange", dragDropChange: "dragDropChange" }, viewQueries: [{ propertyName: "tableScrollContainer", first: true, predicate: ["tableScrollContainer"], descendants: true }], ngImport: i0, template: "<div #tableScrollContainer cdkScrollable class=\"overflow-y-auto\" [ngClass]=\"customClass\">\r\n <table class=\"min-w-full text-sm text-left text-gray-800 table-auto border-collapse\">\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-[-1px]\"\r\n [class.cursor-pointer]=\"col.sortable\"\r\n [class.cursor-default]=\"!col.sortable\"\r\n [class.action-sticky]=\"col.sticky\"\r\n [class.z-10]=\"col.sticky\"\r\n class=\"{{ col.headerClass }} {{ col.cellClass }}\"\r\n (click)=\"sort(col, i)\"\r\n >\r\n <!-- [ngClass]=\"col.headerClass\"\r\n [ngClass]=\"col.cellClass\" -->\r\n <span\r\n class=\"flex items-center gap-1\"\r\n [ngClass]=\"\r\n sortColumn === col.field\r\n ? sortDirection === 'asc'\r\n ? 'grid-asc'\r\n : 'grid-desc'\r\n : ''\r\n \"\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 {{actionClass}}\">Action</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=\"\"\r\n [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\r\n cdkDragHandle\r\n class=\"mr-2 text-gray-400\"\r\n [ngClass]=\"{ 'cursor-move': draggable }\"\r\n >\u2630</span\r\n >\r\n }\r\n @if (col.checkbox) {\r\n <bk-checkbox\r\n checkboxClass=\"sm\"\r\n [ngModel]=\"getCheckboxValue(row, col)\"\r\n (ngModelChange)=\"setCheckboxValue(row, col, $event)\"\r\n [disabled]=\"typeof col.checkboxDisabled === 'function' ? col.checkboxDisabled(row) : col.checkboxDisabled || false\"\r\n [bkTooltip]=\"typeof col.checkboxTooltip === 'function' ? col.checkboxTooltip(row) : col.checkboxTooltip || ''\"\r\n [bkTooltipPosition]=\"col.checkboxTooltipPosition || 'top'\"\r\n ></bk-checkbox>\r\n } @else if (col.badges) {\r\n @let badge = getBadge(row, col);\r\n @if (badge) {\r\n <bk-badge\r\n [label]=\"badge.label\"\r\n [variant]=\"badge.variant\"\r\n [size]=\"badge.size\"\r\n [color]=\"badge.color\"\r\n [dot]=\"badge.dot\"\r\n [customClass]=\"badge.customClass\"\r\n [bkTooltip]=\"badge.toolTipLabel || ''\"\r\n [bkTooltipPosition]=\"badge.tooltipPosition || 'top'\"\r\n ></bk-badge>\r\n }\r\n } @else if (col.icons) {\r\n @let iconsList = getIcons(row, col);\r\n <div class=\"flex justify-center items-center gap-2\">\r\n @for (icon of iconsList; track $index) {\r\n @if(icon.url){\r\n <img\r\n [src]=\"icon.url\"\r\n class=\"size-4\"\r\n [ngClass]=\"{ 'cursor-pointer': icon.url }\"\r\n [bkTooltip]=\"icon.toolTipLabel || []\"\r\n [bkTooltipPosition]=\"icon.tooltipPosition || 'top'\"\r\n />\r\n }\r\n }\r\n </div>\r\n } @else if (col.toolTipField) {\r\n <span\r\n [bkTooltip]=\"getTooltipValue(row, col)\"\r\n [bkTooltipPosition]=\"col.toolTipPosition || 'top'\"\r\n >\r\n {{ getCellValue(row, col) }}\r\n </span>\r\n } @else {\r\n {{ getCellValue(row, col) }}\r\n }\r\n </td>\r\n }\r\n }\r\n\r\n @if (getRowActions(row).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 getRowActions(row); track action.name) {\r\n @if (isActionVisible(action, row)) {\r\n <!-- <bk-icon-button\r\n [bkTooltip]=\"action.tooltip\"\r\n [size]=\"\"\r\n [bkTooltipPosition]=\"action?.tooltipPosition || 'top'\"\r\n class=\"size-6 flex items-center justify-center rounded hover:bg-[#F8F8FA]\"\r\n (clicked)=\"emitAction(action, row)\"\r\n [disabled]=\"isActionDisabled(action, row)\">\r\n </bk-icon-button> -->\r\n <button\r\n [bkTooltip]=\"action.tooltip\"\r\n [bkTooltipPosition]=\"action?.tooltipPosition || 'top'\"\r\n class=\"size-6 flex items-center justify-center rounded hover:bg-[#F8F8FA] {{actionIconClass}}\"\r\n (click)=\"emitAction(action, row)\"\r\n [disabled]=\"isActionDisabled(action, row)\"\r\n >\r\n <img [src]=\"action.icon\" width=\"14\" height=\"14\" alt=\"action-icon\" />\r\n </button>\r\n }\r\n }\r\n </div>\r\n </td>\r\n }\r\n </tr>\r\n }\r\n @if (showNoRecords) {\r\n <tr>\r\n <td\r\n [attr.colspan]=\"columns.length + (actions.length ? 1 : 0)\"\r\n class=\"text-center py-10 {{ noRecordFoundHeight }}\"\r\n >\r\n <div class=\"flex flex-col justify-center items-center w-full h-auto\">\r\n @if (showNoRecordImg) {\r\n <img\r\n [src]=\"noRecordImagePath\"\r\n class=\"mb-3 w-96\"\r\n alt=\"No data found\"\r\n />\r\n }\r\n\r\n <span class=\"block text-sm leading-3 text-center font-semibold text-[#60646C] mt-2\"\r\n >{{ noRecordMessage }}</span\r\n >\r\n </div>\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n</div>\r\n", styles: [".grid-header{@apply bg-[#F9FAFA] text-xs text-[#60646C] font-semibold capitalize px-[17px] py-2.5 whitespace-nowrap;box-shadow:0 1px #ebedf3;-webkit-transform:translateZ(0);transform:translateZ(0);backface-visibility:hidden;-webkit-backface-visibility:hidden}thead tr th:first-child{border-top-left-radius:.75rem}thead tr th:last-child{border-top-right-radius:.75rem}.grid-cell{@apply text-[#15191E] text-[13px] font-medium leading-4 px-4 py-2 border-x border-b border-[#EBEDF3];}.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: i3.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: i3.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: i3.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "component", type: BkBadge, selector: "bk-badge", inputs: ["label", "variant", "color", "size", "dot", "removable", "customClass", "customBg", "customBorder", "customText"], outputs: ["clicked"] }, { kind: "directive", type: BKTooltipDirective, selector: "[bkTooltip]", inputs: ["bkTooltip", "bkTooltipPosition", "bkTooltipScrollable", "bkTooltipMaxHeight", "bkTooltipSize", "bkTooltipAutoHeight"] }, { kind: "component", type: BkCheckbox, selector: "bk-checkbox", inputs: ["checkboxClass", "label", "labelClass", "disabled"], outputs: ["change"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
5002
5959
  }
5003
5960
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkGrid, decorators: [{
5004
5961
  type: Component,
@@ -6298,7 +7255,7 @@ class BkSelect {
6298
7255
  useExisting: forwardRef(() => BkSelect),
6299
7256
  multi: true
6300
7257
  }
6301
- ], 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: "dropdownPanel", first: true, predicate: ["dropdownPanel"], descendants: true }, { propertyName: "selectOverlay", first: true, predicate: ["selectOverlay"], descendants: true }, { propertyName: "chipsViewport", first: true, predicate: ["chipsViewport"], descendants: true }, { propertyName: "measurePlus", first: true, predicate: ["measurePlus"], descendants: true }, { propertyName: "optionsRef", predicate: ["optionsRef"], descendants: true }, { propertyName: "measureChips", predicate: ["measureChip"], descendants: true }], ngImport: i0, template: "<div class=\"bk-select-container\" [ngClass]=\"variation\" [class.bk-grid-view]=\"dropdownView() === 'grid'\">\r\n @if (label) {\r\n <label class=\"bk-select-label\" (click)=\"openFromLabel($event)\">\r\n {{ label }}\r\n @if (required) {\r\n <span class=\"bk-select-label-required\">*</span>\r\n }\r\n </label>\r\n }\r\n\r\n <div class=\"relative\">\r\n <!-- controlStyle() resolves the tint: the selected option's accent normally,\r\n a soft red one while hasError. It's a method rather than a computed\r\n because hasError is a plain @Input, not a signal. -->\r\n <div\r\n #controlWrapper\r\n cdkOverlayOrigin\r\n #selectOrigin=\"cdkOverlayOrigin\"\r\n class=\"bk-select-control\"\r\n [ngClass]=\"{ 'bk-has-error': hasError }\"\r\n tabindex=\"0\"\r\n (keydown)=\"onKeyDown($event)\"\r\n [class.bk-focused]=\"isOpen()\"\r\n [class.bk-disabled]=\"disabled()\"\r\n [class.bk-filled]=\"!!controlStyle().backgroundColor\"\r\n [style.backgroundColor]=\"controlStyle().backgroundColor\"\r\n [style.color]=\"controlStyle().color\"\r\n [style.borderColor]=\"controlStyle().borderColor\"\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=\"bk-value-container\">\r\n @if (selectedOptions().length === 0) {\r\n <div class=\"bk-placeholder\">{{ placeholder() }}</div>\r\n }\r\n @if (multiple() && selectedOptions().length > 0) {\r\n <div\r\n #chipsViewport\r\n class=\"bk-value-chips bk-chips-viewport flex gap-0.5 flex-nowrap overflow-hidden h-[18px]\"\r\n >\r\n @for (opt of selectedOptions().slice(0, visibleCount()); track $index) {\r\n <div class=\"bk-multi-badge-item me-0.5\" [class.bk-chip-has-avatar]=\"showAvatar()\">\r\n <!-- One leading visual only: avatar > icon > dot. -->\r\n @if (showAvatar()) {\r\n <bk-avatar\r\n class=\"shrink-0 flex\"\r\n size=\"xxsm\"\r\n [src]=\"resolveAvatarSrc(opt)\"\r\n [name]=\"resolveLabel(opt)\"\r\n [alt]=\"iconAlt\"\r\n [bgColor]=\"avatarBgFor(opt)\"\r\n [textColor]=\"avatarTextFor(opt)\"\r\n ></bk-avatar>\r\n } @else if (resolveIcon(opt)) {\r\n <img [src]=\"resolveIcon(opt)!\" alt=\"icon\" class=\"bk-chip-icon shrink-0\" />\r\n } @else if (showDots() && accentFor(opt)) {\r\n <span class=\"bk-chip-dot\" [style.backgroundColor]=\"accentFor(opt)\"></span>\r\n }\r\n <span #badgeTextEl class=\"bk-multi-badge-item-text\" [style.color]=\"optionTextColor(opt)\"\r\n [bkTooltip]=\"getTooltipIfEllipsed(badgeTextEl, resolveLabel(opt))\"\r\n bkTooltipPosition=\"top\">{{\r\n resolveLabel(opt)\r\n }}</span>\r\n\r\n <!-- A locked control must not offer a way to drop a value. -->\r\n @if (isEditable()) {\r\n <button type=\"button\" (mousedown)=\"removeOption(opt, $event)\">\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"8\"\r\n height=\"8\"\r\n viewBox=\"0 0 8 8\"\r\n fill=\"none\"\r\n >\r\n <path\r\n d=\"M6.625 0.625L0.625 6.625M0.625 0.625L6.625 6.625\"\r\n stroke=\"#BBBDC5\"\r\n stroke-width=\"1.25\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n </svg>\r\n </button>\r\n }\r\n </div>\r\n }\r\n @if (visibleCount() < selectedOptions().length) {\r\n <div class=\"bk-multi-badge-item\">\r\n <span\r\n class=\"bk-multi-badge-item-text\"\r\n bkTooltipPosition=\"top\"\r\n [bkTooltip]=\"getRemainingItems()\"\r\n [bkTooltipScrollable]=\"true\"\r\n bkTooltipMaxHeight=\"240px\"\r\n >+{{ selectedOptions().length - visibleCount() }}</span\r\n >\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Hidden off-screen row used only to measure each chip's natural\r\n width so we can decide how many fit on a single line. -->\r\n <div class=\"bk-value-chips bk-chips-measure flex gap-0.5 flex-nowrap\" aria-hidden=\"true\">\r\n @for (opt of selectedOptions(); track $index) {\r\n <div #measureChip class=\"bk-multi-badge-item me-0.5\" [class.bk-chip-has-avatar]=\"showAvatar()\">\r\n <!-- Must mirror the visible chip exactly \u2014 same leading visual\r\n and same precedence \u2014 or the measured width is wrong and\r\n \"+N\" collapses at the wrong point. -->\r\n @if (showAvatar()) {\r\n <bk-avatar\r\n class=\"shrink-0 flex\"\r\n size=\"xxsm\"\r\n [src]=\"resolveAvatarSrc(opt)\"\r\n [name]=\"resolveLabel(opt)\"\r\n [alt]=\"iconAlt\"\r\n ></bk-avatar>\r\n } @else if (resolveIcon(opt)) {\r\n <img [src]=\"resolveIcon(opt)!\" alt=\"icon\" class=\"bk-chip-icon shrink-0\" />\r\n } @else if (showDots() && accentFor(opt)) {\r\n <span class=\"bk-chip-dot\"></span>\r\n }\r\n <span class=\"bk-multi-badge-item-text\">{{ resolveLabel(opt) }}</span>\r\n @if (isEditable()) {\r\n <button type=\"button\" tabindex=\"-1\">\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"8\"\r\n height=\"8\"\r\n viewBox=\"0 0 8 8\"\r\n fill=\"none\"\r\n >\r\n <path\r\n d=\"M6.625 0.625L0.625 6.625M0.625 0.625L6.625 6.625\"\r\n stroke=\"#BBBDC5\"\r\n stroke-width=\"1.25\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n </svg>\r\n </button>\r\n }\r\n </div>\r\n }\r\n <div #measurePlus class=\"bk-multi-badge-item\">\r\n <span class=\"bk-multi-badge-item-text\">+{{ selectedOptions().length }}</span>\r\n </div>\r\n </div>\r\n }\r\n @if (!multiple() && selectedOptions().length > 0) {\r\n <div class=\"flex items-center gap-1.5 min-w-0 w-full\">\r\n <!-- One leading visual only: avatar > icon > dot.\r\n `flex` on the host: bk-avatar's host is display:inline by\r\n default, so its inline-flex body sits on a baseline and the\r\n host gains descender space \u2014 which knocks the avatar out of\r\n vertical centre against the label. -->\r\n @if (showAvatar()) {\r\n <bk-avatar\r\n class=\"shrink-0 flex\"\r\n size=\"xxsm\"\r\n [src]=\"resolveAvatarSrc(selectedOptions()[0])\"\r\n [name]=\"resolveLabel(selectedOptions()[0])\"\r\n [alt]=\"iconAlt\"\r\n [bgColor]=\"avatarBgFor(selectedOptions()[0])\"\r\n [textColor]=\"avatarTextFor(selectedOptions()[0])\"\r\n ></bk-avatar>\r\n } @else if (resolveIcon(selectedOptions()[0])) {\r\n <img [src]=\"resolveIcon(selectedOptions()[0])!\" alt=\"icon\" class=\"bk-option-icon shrink-0\" />\r\n } @else if (showDots() && accentFor(selectedOptions()[0])) {\r\n <span class=\"bk-value-dot\" [style.backgroundColor]=\"accentFor(selectedOptions()[0])\"></span>\r\n }\r\n <div #singleValueEl class=\"bk-value-label-single\" [style.color]=\"controlStyle().color ?? resolveColor(selectedOptions()[0])\"\r\n [bkTooltip]=\"getTooltipIfEllipsed(singleValueEl, resolveLabel(selectedOptions()[0]))\"\r\n bkTooltipPosition=\"top\">\r\n {{ resolveLabel(selectedOptions()[0]) }}\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n <div class=\"bk-actions\">\r\n @if (clearable() && selectedOptions().length > 0 && isEditable()) {\r\n <span class=\"bk-clear-wrapper\" (mousedown)=\"handleClear($event)\" title=\"Clear\">\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"14\"\r\n height=\"14\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n >\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 </span>\r\n }\r\n <span class=\"bk-arrow-wrapper\" [class.bk-open]=\"isOpen()\">\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"18\"\r\n height=\"18\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n >\r\n <path d=\"m6 9 6 6 6-6\" />\r\n </svg>\r\n </span>\r\n </div>\r\n </div>\r\n\r\n <!--\r\n CDK connected overlay: portals the panel into the shared cdk-overlay-container instead of\r\n an inline `position:absolute`/`fixed` div, so it escapes clipping inside dialogs/scroll\r\n containers and stacks correctly above other CDK-overlay content, regardless of the old\r\n appendToBody flag (see its @deprecated note). No backdrop \u2014 see onOverlayOutsideClick.\r\n -->\r\n <ng-template\r\n cdkConnectedOverlay\r\n #selectOverlay=\"cdkConnectedOverlay\"\r\n [cdkConnectedOverlayOrigin]=\"selectOrigin\"\r\n [cdkConnectedOverlayOpen]=\"isOpen()\"\r\n [cdkConnectedOverlayPositions]=\"selectDropdownPositions\"\r\n [cdkConnectedOverlayWidth]=\"dropdownWidth() ?? ''\"\r\n [cdkConnectedOverlayFlexibleDimensions]=\"false\"\r\n (positionChange)=\"onPositionChange($event)\"\r\n (overlayOutsideClick)=\"onOverlayOutsideClick()\"\r\n (detach)=\"closeDropdown()\"\r\n >\r\n <div\r\n #dropdownPanel\r\n tabindex=\"-1\"\r\n (keydown)=\"onTabPress($event)\"\r\n class=\"bk-dropdown-panel\"\r\n [style.visibility]=\"panelReady() ? 'visible' : 'hidden'\"\r\n [attr.data-position]=\"placement()\"\r\n [class.bk-grouped]=\"groupBy()\"\r\n [class.bk-grid-panel]=\"dropdownView() === 'grid'\"\r\n [class.bk-grid-compact]=\"dropdownView() === 'grid' && isGridCompact()\"\r\n >\r\n @if (searchable()) {\r\n <div class=\"bk-dropdown-search mb-1\">\r\n <div class=\"bk-search-wrapper\">\r\n <svg\r\n class=\"text-[#BBBDC5] mr-2\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"20\"\r\n height=\"20\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n >\r\n <circle cx=\"11\" cy=\"11\" r=\"8\"></circle>\r\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"></line>\r\n </svg>\r\n <input\r\n #searchInput\r\n tabindex=\"0\"\r\n type=\"text\"\r\n class=\"bk-search-input\"\r\n [value]=\"searchTerm()\"\r\n [placeholder]=\"'Search...'\"\r\n (input)=\"onSearchInput($event)\"\r\n (keydown)=\"onKeyDown($event)\"\r\n (click)=\"$event.stopPropagation()\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n @if (dropdownView() === 'grid') {\r\n <div\r\n #optionsListContainer\r\n class=\"bk-grid-scroll\"\r\n [class.bk-no-responsive]=\"!isResponsive()\"\r\n [style.maxHeight]=\"gridMaxHeight()\"\r\n (scroll)=\"onScroll($event)\"\r\n >\r\n <table class=\"bk-select-grid\" [style.minWidth]=\"gridMinWidth()\">\r\n <thead>\r\n <tr>\r\n @if (multiple()) {\r\n <th class=\"bk-grid-checkbox-column\" aria-label=\"Selection\"></th>\r\n }\r\n @for (column of gridColumns(); track column.key) {\r\n <th [ngStyle]=\"gridColumnStyle(column)\">{{ column.label }}</th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @if (loading()) {\r\n <tr><td [attr.colspan]=\"gridColumns().length + (multiple() ? 1 : 0)\" class=\"bk-grid-message\">{{ loadingText() }}</td></tr>\r\n } @else {\r\n @for (item of filteredItems(); track resolveValue(item); let rowIndex = $index) {\r\n <tr\r\n #optionsRef\r\n tabindex=\"-1\"\r\n [class.bk-selected]=\"isGridItemSelected(item)\"\r\n [class.bk-marked]=\"rowIndex === markedIndex()\"\r\n [class.bk-option-disabled]=\"isItemDisabled(item)\"\r\n (click)=\"handleGridSelection(item, $event)\"\r\n (mouseenter)=\"onOptionHover(rowIndex)\"\r\n >\r\n @if (multiple()) {\r\n <td class=\"bk-grid-checkbox-column\">\r\n <bk-checkbox\r\n class=\"pointer-events-none flex\"\r\n checkboxClass=\"sm\"\r\n [disabled]=\"isItemDisabled(item)\"\r\n [ngModel]=\"isGridItemSelected(item)\"\r\n [ngModelOptions]=\"{ standalone: true }\"\r\n ></bk-checkbox>\r\n </td>\r\n }\r\n @for (column of gridColumns(); track column.key) {\r\n <td [ngStyle]=\"gridColumnStyle(column)\">\r\n @if (column.type === 'badge') {\r\n <bk-badge\r\n [label]=\"resolveGridCell(item, column)\"\r\n [color]=\"gridBadgeColor(item, column)\"\r\n [variant]=\"column.badgeVariant ?? 'Light'\"\r\n [size]=\"isGridCompact() ? 'xsm' : 'sm'\"\r\n ></bk-badge>\r\n } @else {\r\n <span class=\"bk-grid-cell-text\">{{ resolveGridCell(item, column) }}</span>\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n @if (filteredItems().length === 0) {\r\n <tr><td [attr.colspan]=\"gridColumns().length + (multiple() ? 1 : 0)\" class=\"bk-grid-message\">{{ notFoundText() }}</td></tr>\r\n }\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n @if (multiple()) {\r\n <div class=\"bk-grid-footer\">\r\n <span>{{ gridSelectedCount() }} selected</span>\r\n @if (gridSelectionActions()) {\r\n <div class=\"bk-grid-footer-actions\">\r\n <bk-button variant=\"secondary\" [size]=\"isGridCompact() ? 'xxsm' : 'xsm'\" [label]=\"gridClearText()\" (clicked)=\"clearGridDraft()\"></bk-button>\r\n <bk-button variant=\"primary\" [size]=\"isGridCompact() ? 'xxsm' : 'xsm'\" [label]=\"gridApplyText()\" (clicked)=\"applyGridDraft()\"></bk-button>\r\n </div>\r\n }\r\n </div>\r\n }\r\n } @else {\r\n <div\r\n #optionsListContainer\r\n tabindex=\"-1\"\r\n class=\"bk-options-list\"\r\n [class.bk-no-responsive]=\"!isResponsive()\"\r\n (scroll)=\"onScroll($event)\"\r\n >\r\n @if (loading()) {\r\n <div class=\"bk-option-disabled\">{{ loadingText() }}</div>\r\n } @else {\r\n @if (allSelect()) {\r\n @if (multiple() && filteredItems().length > 0) {\r\n <div\r\n class=\"bk-option\"\r\n (mousedown)=\"toggleSelectAll($event)\"\r\n [class.bk-selected]=\"isAllSelected()\"\r\n >\r\n <div class=\"flex-1 flex items-center gap-2 min-w-0\">\r\n <!-- Reflects state only: pointer-events-none lets the row's\r\n mousedown own the toggle, so the box can't fire twice.\r\n standalone keeps this ngModel out of any parent <form>\r\n bk-select is rendered inside. -->\r\n <bk-checkbox\r\n class=\"pointer-events-none shrink-0 flex\"\r\n checkboxClass=\"sm\"\r\n [ngModel]=\"isAllSelected()\"\r\n [ngModelOptions]=\"{ standalone: true }\"\r\n ></bk-checkbox>\r\n <span class=\"line-clamp-1\">Select All</span>\r\n </div>\r\n </div>\r\n }\r\n }\r\n @for (group of groupedItems(); track $index) {\r\n @if (group.group) {\r\n <div class=\"bk-option-group\">\r\n {{ group.group }}\r\n </div>\r\n }\r\n\r\n @for (item of group.items; track $index) {\r\n <div\r\n #optionsRef\r\n tabindex=\"-1\"\r\n class=\"bk-option\"\r\n [class.bk-selected]=\"isItemSelected(item)\"\r\n [class.bk-marked]=\"isMarked(item)\"\r\n [class.bk-option-disabled]=\"isItemDisabled(item)\"\r\n [class.cursor-not-allowed]=\"isItemDisabled(item)\"\r\n (click)=\"handleSelection(item, $event)\"\r\n (mouseenter)=\"markOption(item)\"\r\n >\r\n <div class=\"flex-1 flex justify-between gap-2 min-w-0\">\r\n <div class=\"flex items-center gap-2 min-w-0 flex-1\">\r\n <!-- One leading visual only: avatar > icon > dot. -->\r\n @if (showAvatar()) {\r\n <bk-avatar\r\n class=\"shrink-0 flex\"\r\n size=\"xxsm\"\r\n [src]=\"resolveAvatarSrc(item)\"\r\n [name]=\"resolveLabel(item)\"\r\n [alt]=\"iconAlt\"\r\n [bgColor]=\"avatarBgFor(item)\"\r\n [textColor]=\"avatarTextFor(item)\"\r\n ></bk-avatar>\r\n } @else if (resolveIcon(item)) {\r\n <img [src]=\"resolveIcon(item)!\" alt=\"icon\" class=\"bk-option-icon shrink-0\" />\r\n } @else if (showDots() && accentFor(item)) {\r\n <span class=\"bk-value-dot\" [style.backgroundColor]=\"accentFor(item)\"></span>\r\n }\r\n <span #optionLabelEl class=\"bk-option-label min-w-0\" [style.color]=\"optionTextColor(item)\"\r\n [bkTooltip]=\"getTooltipIfEllipsed(optionLabelEl, resolveLabel(item))\"\r\n bkTooltipPosition=\"top\">{{\r\n resolveLabel(item)\r\n }}</span>\r\n </div>\r\n\r\n @if (isItemSelected(item)) {\r\n <svg\r\n class=\"text-[#141414] shrink-0\"\r\n width=\"17\"\r\n height=\"17\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2.5\"\r\n >\r\n <polyline points=\"20 6 9 17 4 12\" />\r\n </svg>\r\n }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n @if (filteredItems().length === 0) {\r\n <div class=\"bk-option-disabled\">{{ notFoundText() }}</div>\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n </ng-template>\r\n </div>\r\n @if (hasError) {\r\n @if (errorMessage) {\r\n <p class=\"bk-select-error\">{{ errorMessage }}</p>\r\n }\r\n }\r\n</div>\r\n", styles: [".bk-select-container{@apply relative w-full box-border flex flex-col gap-1.5;}.bk-select-control{@apply flex items-center justify-between gap-2 w-full bg-white border border-[#E3E3E7] rounded cursor-pointer focus:border-[#E3E3E7] focus-visible:!outline-[.1px] focus-visible:!outline-[#6B7080];transition:border-color .2s,box-shadow .2s;box-shadow:0 1px 2px #1018280d}.bk-select-control:focus-visible{outline-style:solid!important}.bk-select-control.bk-focused{@apply shadow-none z-10;outline:none!important}.bk-select-control.bk-focused:not(.bk-filled){@apply border-[#6B7080];}.bk-select-control.bk-filled{box-shadow:none}.bk-select-control.bk-disabled{@apply cursor-not-allowed;border-color:#e3e3e7!important;background-color:#f4f4f6!important;color:#a1a3ae!important}.bk-select-control.bk-disabled .bk-placeholder{color:#a1a3ae}.bk-select-container.default .bk-select-control{@apply px-3 py-2.5;}.bk-select-container.sm .bk-select-control{@apply px-3 py-[5px];}.bk-select-control.bk-has-error{border-color:#d11e14!important}.bk-value-container{@apply flex flex-1 items-center flex-wrap gap-1 relative overflow-hidden h-full;}.bk-placeholder{@apply text-[#6B7080] font-normal text-[14px] truncate w-full pointer-events-none !leading-[18px];}.bk-value-label-single{@apply font-normal text-[#141414] truncate w-full;}.bk-select-container.default .bk-select-control .bk-value-label-single{@apply text-[14px] !leading-[18px];}.bk-select-container.sm .bk-select-control .bk-value-label-single{@apply text-xs !leading-[18px];}.bk-chips-viewport{flex:1 1 0%;min-width:0;max-width:100%}.bk-chips-measure{position:absolute;top:0;left:0;visibility:hidden;pointer-events:none;white-space:nowrap;z-index:-1}.bk-multi-badge-item{@apply inline-flex items-center gap-1.5 px-1.5 py-0.5 bg-white border border-[#E3E3E7] rounded-[4px];max-width:120px;min-width:0}.bk-multi-badge-item.bk-chip-has-avatar{@apply py-0 ps-0.5;max-width:140px}.bk-select-container.bk-grid-view .bk-multi-badge-item{max-width:175px}.bk-multi-badge-item-text{@apply text-[10px] leading-[12px] font-normal text-[#6B7080];white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.bk-multi-badge-close{@apply cursor-pointer outline-none w-3 h-3;}.bk-actions{@apply flex items-center gap-0.5 flex-shrink-0;}.bk-clear-wrapper{@apply text-gray-400 hover:text-red-500 cursor-pointer;}.bk-arrow-wrapper{@apply text-gray-400 transition-transform duration-200;}.bk-arrow-wrapper.bk-open{@apply rotate-180;}.bk-dropdown-panel{@apply static left-auto w-full bg-white border border-[#E3E3E7] rounded-xl shadow-lg overflow-hidden cursor-default p-2.5;}.bk-grid-scroll{@apply overflow-auto -mx-2.5;scrollbar-width:thin;scrollbar-color:#D6D7DC transparent}.bk-grid-scroll::-webkit-scrollbar{width:6px;height:6px}.bk-grid-scroll::-webkit-scrollbar-track{background:transparent}.bk-grid-scroll::-webkit-scrollbar-thumb{background:#d6d7dc;border-radius:999px}.bk-grid-scroll::-webkit-scrollbar-thumb:hover{background:#909090}.bk-grid-scroll::-webkit-scrollbar-button{display:none}.bk-dropdown-panel.bk-grid-panel{padding-top:0;padding-bottom:0}.bk-select-grid{@apply w-full border-collapse text-sm text-[#141414];table-layout:fixed}.bk-select-grid th{@apply sticky top-0 z-10 bg-[#F1F1F3] px-4 py-2.5 font-semibold whitespace-nowrap border-b border-[#E3E3E7];}.bk-select-grid td{@apply px-4 py-2.5 border-b border-[#E3E3E7] align-middle;}.bk-select-grid tbody tr{@apply cursor-pointer transition-colors;}.bk-select-grid tbody tr:hover,.bk-select-grid tbody tr.bk-marked{@apply bg-[#F8F8F8];}.bk-select-grid tbody tr.bk-selected{background-color:#f8f8f8}.bk-select-grid tbody tr.bk-option-disabled{@apply opacity-50 cursor-not-allowed;}.bk-grid-checkbox-column{width:48px;min-width:48px;@apply !px-4;}.bk-grid-cell-text{@apply block truncate;}.bk-grid-message{@apply !px-4 !py-4 text-center text-gray-400;}.bk-grid-footer{@apply flex items-center justify-between gap-4 px-1 py-2.5 text-xs text-[#6B7080];}.bk-grid-footer-actions{@apply flex items-center gap-2;}.bk-dropdown-panel.bk-grid-compact{padding:0 .5rem}.bk-dropdown-panel.bk-grid-compact .bk-dropdown-search{@apply px-1 pt-1;}.bk-dropdown-panel.bk-grid-compact .bk-search-wrapper{@apply px-2 py-1;}.bk-dropdown-panel.bk-grid-compact .bk-search-input{@apply text-xs;}.bk-dropdown-panel.bk-grid-compact .bk-grid-scroll{@apply -mx-2;}.bk-dropdown-panel.bk-grid-compact .bk-select-grid{@apply text-xs;}.bk-dropdown-panel.bk-grid-compact .bk-select-grid th,.bk-dropdown-panel.bk-grid-compact .bk-select-grid td{@apply px-3 py-1.5;}.bk-dropdown-panel.bk-grid-compact .bk-grid-checkbox-column{width:40px;min-width:40px;@apply !px-3;}.bk-dropdown-panel.bk-grid-compact .bk-grid-footer{@apply gap-3 px-0 py-1.5 text-[11px];}.bk-dropdown-panel.bk-grid-compact .bk-grid-footer-actions{@apply gap-1.5;}@media (max-width: 640px){.bk-grid-scroll{max-width:calc(100vw - 32px)}}.bk-dropdown-search{@apply px-2 pt-2;}.bk-search-wrapper{@apply flex items-center border border-[#E3E3E7] rounded-md px-3 py-[7px] bg-white transition-colors focus-within:border-[#E3E3E7];}.bk-search-input{@apply w-full outline-none font-normal text-sm text-[#141414] placeholder-[#A1A3AE] bg-transparent;}.bk-options-list{@apply overflow-y-auto overflow-x-hidden relative flex flex-col gap-0.5;}@media (max-height: 700px){.bk-options-list{max-height:125px}}@media (min-height: 701px) and (max-height: 900px){.bk-options-list{max-height:166px}}@media (min-height: 901px){.bk-options-list{max-height:210px}}.bk-options-list.bk-no-responsive{max-height:166px!important}.bk-option{@apply flex items-center p-2.5 cursor-pointer transition-colors font-normal text-sm text-[#141414] min-w-0;}.bk-option:hover,.bk-option.bk-marked{@apply bg-[#F1F1F3] rounded-md;}.bk-option.bk-selected{@apply bg-[#F8F8F8] rounded-md;}.bk-option.bk-selected:hover,.bk-option.bk-selected.bk-marked{@apply bg-[#F1F1F3];}.bk-option.bk-option-disabled{@apply opacity-50 cursor-not-allowed;}.bk-option.bk-option-disabled:hover{@apply bg-transparent;}.bk-option .bk-option-label{@apply line-clamp-1 break-all;}.bk-grouped .bk-option{@apply ps-5;}.bk-option-disabled{@apply px-3 py-2 text-gray-400 cursor-default text-sm;}.bk-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];}.bk-select-all-option:hover{@apply bg-gray-100;}.bk-dropdown-panel[data-position=top]{margin-top:0;margin-bottom:4px}.bk-select-label{@apply text-sm font-medium text-[#141414] tracking-[-.28px] inline-block;}.bk-select-label-required{@apply text-[#E7000B];}.bk-options-list ::-webkit-scrollbar{width:10px}.bk-options-list ::-webkit-scrollbar-track{background:transparent;border-radius:8px;width:8px}.bk-options-list ::-webkit-scrollbar-thumb{background:#d6d7dc;border-radius:8px;transition:.3s ease-in-out}.bk-options-list ::-webkit-scrollbar-thumb:hover{background:#909090}.bk-option-group{@apply px-2.5 py-1 font-bold text-[13px] leading-5 text-[#141414];}.bk-option-group:not(:first-child){@apply mt-4;}.bk-select-error{@apply text-xs text-[#E7000B] font-normal;}.bk-select-hint{@apply text-xs text-[#868997] font-normal;}.bk-search-input:focus-visible{outline:2px solid transparent}.bk-option-icon{@apply w-4 h-4 object-contain rounded-sm;}.bk-chip-icon{@apply w-3 h-3 object-contain rounded-sm;}.bk-value-dot{@apply inline-block w-2 h-2 rounded-full shrink-0;}.bk-chip-dot{@apply inline-block w-1.5 h-1.5 rounded-full shrink-0;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: BKTooltipDirective, selector: "[bkTooltip]", inputs: ["bkTooltip", "bkTooltipPosition", "bkTooltipScrollable", "bkTooltipMaxHeight", "bkTooltipSize", "bkTooltipAutoHeight"] }, { kind: "component", type: BkCheckbox, selector: "bk-checkbox", inputs: ["checkboxClass", "label", "labelClass", "disabled"], outputs: ["change"] }, { kind: "component", type: BkAvatar, selector: "bk-avatar", inputs: ["src", "alt", "name", "initialsOverride", "tooltipContent", "bgColor", "textColor", "size", "variant", "fallback", "dot", "dotPosition"], outputs: ["imageLoadError"] }, { kind: "component", type: BkButton, selector: "bk-button", inputs: ["variant", "size", "shadow", "label", "leftIcon", "rightIcon", "iconAlt", "type", "loading", "disabled", "buttonClass", "textClass", "spinnerClass"], outputs: ["clicked"] }, { kind: "component", type: BkBadge, selector: "bk-badge", inputs: ["label", "variant", "color", "size", "dot", "removable", "customClass", "customBg", "customBorder", "customText"], outputs: ["clicked"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i3.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i3.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }] });
7258
+ ], 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: "dropdownPanel", first: true, predicate: ["dropdownPanel"], descendants: true }, { propertyName: "selectOverlay", first: true, predicate: ["selectOverlay"], descendants: true }, { propertyName: "chipsViewport", first: true, predicate: ["chipsViewport"], descendants: true }, { propertyName: "measurePlus", first: true, predicate: ["measurePlus"], descendants: true }, { propertyName: "optionsRef", predicate: ["optionsRef"], descendants: true }, { propertyName: "measureChips", predicate: ["measureChip"], descendants: true }], ngImport: i0, template: "<div class=\"bk-select-container\" [ngClass]=\"variation\" [class.bk-grid-view]=\"dropdownView() === 'grid'\">\r\n @if (label) {\r\n <label class=\"bk-select-label\" (click)=\"openFromLabel($event)\">\r\n {{ label }}\r\n @if (required) {\r\n <span class=\"bk-select-label-required\">*</span>\r\n }\r\n </label>\r\n }\r\n\r\n <div class=\"relative\">\r\n <!-- controlStyle() resolves the tint: the selected option's accent normally,\r\n a soft red one while hasError. It's a method rather than a computed\r\n because hasError is a plain @Input, not a signal. -->\r\n <div\r\n #controlWrapper\r\n cdkOverlayOrigin\r\n #selectOrigin=\"cdkOverlayOrigin\"\r\n class=\"bk-select-control\"\r\n [ngClass]=\"{ 'bk-has-error': hasError }\"\r\n tabindex=\"0\"\r\n (keydown)=\"onKeyDown($event)\"\r\n [class.bk-focused]=\"isOpen()\"\r\n [class.bk-disabled]=\"disabled()\"\r\n [class.bk-filled]=\"!!controlStyle().backgroundColor\"\r\n [style.backgroundColor]=\"controlStyle().backgroundColor\"\r\n [style.color]=\"controlStyle().color\"\r\n [style.borderColor]=\"controlStyle().borderColor\"\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=\"bk-value-container\">\r\n @if (selectedOptions().length === 0) {\r\n <div class=\"bk-placeholder\">{{ placeholder() }}</div>\r\n }\r\n @if (multiple() && selectedOptions().length > 0) {\r\n <div\r\n #chipsViewport\r\n class=\"bk-value-chips bk-chips-viewport flex gap-0.5 flex-nowrap overflow-hidden h-[18px]\"\r\n >\r\n @for (opt of selectedOptions().slice(0, visibleCount()); track $index) {\r\n <div class=\"bk-multi-badge-item me-0.5\" [class.bk-chip-has-avatar]=\"showAvatar()\">\r\n <!-- One leading visual only: avatar > icon > dot. -->\r\n @if (showAvatar()) {\r\n <bk-avatar\r\n class=\"shrink-0 flex\"\r\n size=\"xxsm\"\r\n [src]=\"resolveAvatarSrc(opt)\"\r\n [name]=\"resolveLabel(opt)\"\r\n [alt]=\"iconAlt\"\r\n [bgColor]=\"avatarBgFor(opt)\"\r\n [textColor]=\"avatarTextFor(opt)\"\r\n ></bk-avatar>\r\n } @else if (resolveIcon(opt)) {\r\n <img [src]=\"resolveIcon(opt)!\" alt=\"icon\" class=\"bk-chip-icon shrink-0\" />\r\n } @else if (showDots() && accentFor(opt)) {\r\n <span class=\"bk-chip-dot\" [style.backgroundColor]=\"accentFor(opt)\"></span>\r\n }\r\n <span #badgeTextEl class=\"bk-multi-badge-item-text\" [style.color]=\"optionTextColor(opt)\"\r\n [bkTooltip]=\"getTooltipIfEllipsed(badgeTextEl, resolveLabel(opt))\"\r\n bkTooltipPosition=\"top\">{{\r\n resolveLabel(opt)\r\n }}</span>\r\n\r\n <!-- A locked control must not offer a way to drop a value. -->\r\n @if (isEditable()) {\r\n <button type=\"button\" (mousedown)=\"removeOption(opt, $event)\">\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"8\"\r\n height=\"8\"\r\n viewBox=\"0 0 8 8\"\r\n fill=\"none\"\r\n >\r\n <path\r\n d=\"M6.625 0.625L0.625 6.625M0.625 0.625L6.625 6.625\"\r\n stroke=\"#BBBDC5\"\r\n stroke-width=\"1.25\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n </svg>\r\n </button>\r\n }\r\n </div>\r\n }\r\n @if (visibleCount() < selectedOptions().length) {\r\n <div class=\"bk-multi-badge-item\">\r\n <span\r\n class=\"bk-multi-badge-item-text\"\r\n bkTooltipPosition=\"top\"\r\n [bkTooltip]=\"getRemainingItems()\"\r\n [bkTooltipScrollable]=\"true\"\r\n bkTooltipMaxHeight=\"240px\"\r\n >+{{ selectedOptions().length - visibleCount() }}</span\r\n >\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Hidden off-screen row used only to measure each chip's natural\r\n width so we can decide how many fit on a single line. -->\r\n <div class=\"bk-value-chips bk-chips-measure flex gap-0.5 flex-nowrap\" aria-hidden=\"true\">\r\n @for (opt of selectedOptions(); track $index) {\r\n <div #measureChip class=\"bk-multi-badge-item me-0.5\" [class.bk-chip-has-avatar]=\"showAvatar()\">\r\n <!-- Must mirror the visible chip exactly \u2014 same leading visual\r\n and same precedence \u2014 or the measured width is wrong and\r\n \"+N\" collapses at the wrong point. -->\r\n @if (showAvatar()) {\r\n <bk-avatar\r\n class=\"shrink-0 flex\"\r\n size=\"xxsm\"\r\n [src]=\"resolveAvatarSrc(opt)\"\r\n [name]=\"resolveLabel(opt)\"\r\n [alt]=\"iconAlt\"\r\n ></bk-avatar>\r\n } @else if (resolveIcon(opt)) {\r\n <img [src]=\"resolveIcon(opt)!\" alt=\"icon\" class=\"bk-chip-icon shrink-0\" />\r\n } @else if (showDots() && accentFor(opt)) {\r\n <span class=\"bk-chip-dot\"></span>\r\n }\r\n <span class=\"bk-multi-badge-item-text\">{{ resolveLabel(opt) }}</span>\r\n @if (isEditable()) {\r\n <button type=\"button\" tabindex=\"-1\">\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"8\"\r\n height=\"8\"\r\n viewBox=\"0 0 8 8\"\r\n fill=\"none\"\r\n >\r\n <path\r\n d=\"M6.625 0.625L0.625 6.625M0.625 0.625L6.625 6.625\"\r\n stroke=\"#BBBDC5\"\r\n stroke-width=\"1.25\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n </svg>\r\n </button>\r\n }\r\n </div>\r\n }\r\n <div #measurePlus class=\"bk-multi-badge-item\">\r\n <span class=\"bk-multi-badge-item-text\">+{{ selectedOptions().length }}</span>\r\n </div>\r\n </div>\r\n }\r\n @if (!multiple() && selectedOptions().length > 0) {\r\n <div class=\"flex items-center gap-1.5 min-w-0 w-full\">\r\n <!-- One leading visual only: avatar > icon > dot.\r\n `flex` on the host: bk-avatar's host is display:inline by\r\n default, so its inline-flex body sits on a baseline and the\r\n host gains descender space \u2014 which knocks the avatar out of\r\n vertical centre against the label. -->\r\n @if (showAvatar()) {\r\n <bk-avatar\r\n class=\"shrink-0 flex\"\r\n size=\"xxsm\"\r\n [src]=\"resolveAvatarSrc(selectedOptions()[0])\"\r\n [name]=\"resolveLabel(selectedOptions()[0])\"\r\n [alt]=\"iconAlt\"\r\n [bgColor]=\"avatarBgFor(selectedOptions()[0])\"\r\n [textColor]=\"avatarTextFor(selectedOptions()[0])\"\r\n ></bk-avatar>\r\n } @else if (resolveIcon(selectedOptions()[0])) {\r\n <img [src]=\"resolveIcon(selectedOptions()[0])!\" alt=\"icon\" class=\"bk-option-icon shrink-0\" />\r\n } @else if (showDots() && accentFor(selectedOptions()[0])) {\r\n <span class=\"bk-value-dot\" [style.backgroundColor]=\"accentFor(selectedOptions()[0])\"></span>\r\n }\r\n <div #singleValueEl class=\"bk-value-label-single\" [style.color]=\"controlStyle().color ?? resolveColor(selectedOptions()[0])\"\r\n [bkTooltip]=\"getTooltipIfEllipsed(singleValueEl, resolveLabel(selectedOptions()[0]))\"\r\n bkTooltipPosition=\"top\">\r\n {{ resolveLabel(selectedOptions()[0]) }}\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n <div class=\"bk-actions\">\r\n @if (clearable() && selectedOptions().length > 0 && isEditable()) {\r\n <span class=\"bk-clear-wrapper\" (mousedown)=\"handleClear($event)\" title=\"Clear\">\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"14\"\r\n height=\"14\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n >\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 </span>\r\n }\r\n <span class=\"bk-arrow-wrapper\" [class.bk-open]=\"isOpen()\">\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"18\"\r\n height=\"18\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n >\r\n <path d=\"m6 9 6 6 6-6\" />\r\n </svg>\r\n </span>\r\n </div>\r\n </div>\r\n\r\n <!--\r\n CDK connected overlay: portals the panel into the shared cdk-overlay-container instead of\r\n an inline `position:absolute`/`fixed` div, so it escapes clipping inside dialogs/scroll\r\n containers and stacks correctly above other CDK-overlay content, regardless of the old\r\n appendToBody flag (see its @deprecated note). No backdrop \u2014 see onOverlayOutsideClick.\r\n -->\r\n <ng-template\r\n cdkConnectedOverlay\r\n #selectOverlay=\"cdkConnectedOverlay\"\r\n [cdkConnectedOverlayOrigin]=\"selectOrigin\"\r\n [cdkConnectedOverlayOpen]=\"isOpen()\"\r\n [cdkConnectedOverlayPositions]=\"selectDropdownPositions\"\r\n [cdkConnectedOverlayWidth]=\"dropdownWidth() ?? ''\"\r\n [cdkConnectedOverlayFlexibleDimensions]=\"false\"\r\n (positionChange)=\"onPositionChange($event)\"\r\n (overlayOutsideClick)=\"onOverlayOutsideClick()\"\r\n (detach)=\"closeDropdown()\"\r\n >\r\n <div\r\n #dropdownPanel\r\n tabindex=\"-1\"\r\n (keydown)=\"onTabPress($event)\"\r\n class=\"bk-dropdown-panel\"\r\n [style.visibility]=\"panelReady() ? 'visible' : 'hidden'\"\r\n [attr.data-position]=\"placement()\"\r\n [class.bk-grouped]=\"groupBy()\"\r\n [class.bk-grid-panel]=\"dropdownView() === 'grid'\"\r\n [class.bk-grid-compact]=\"dropdownView() === 'grid' && isGridCompact()\"\r\n >\r\n @if (searchable()) {\r\n <div class=\"bk-dropdown-search mb-1\">\r\n <div class=\"bk-search-wrapper\">\r\n <svg\r\n class=\"text-[#BBBDC5] mr-2\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"20\"\r\n height=\"20\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n >\r\n <circle cx=\"11\" cy=\"11\" r=\"8\"></circle>\r\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"></line>\r\n </svg>\r\n <input\r\n #searchInput\r\n tabindex=\"0\"\r\n type=\"text\"\r\n class=\"bk-search-input\"\r\n [value]=\"searchTerm()\"\r\n [placeholder]=\"'Search...'\"\r\n (input)=\"onSearchInput($event)\"\r\n (keydown)=\"onKeyDown($event)\"\r\n (click)=\"$event.stopPropagation()\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n @if (dropdownView() === 'grid') {\r\n <div\r\n #optionsListContainer\r\n class=\"bk-grid-scroll\"\r\n [class.bk-no-responsive]=\"!isResponsive()\"\r\n [style.maxHeight]=\"gridMaxHeight()\"\r\n (scroll)=\"onScroll($event)\"\r\n >\r\n <table class=\"bk-select-grid\" [style.minWidth]=\"gridMinWidth()\">\r\n <thead>\r\n <tr>\r\n @if (multiple()) {\r\n <th class=\"bk-grid-checkbox-column\" aria-label=\"Selection\"></th>\r\n }\r\n @for (column of gridColumns(); track column.key) {\r\n <th [ngStyle]=\"gridColumnStyle(column)\">{{ column.label }}</th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @if (loading()) {\r\n <tr><td [attr.colspan]=\"gridColumns().length + (multiple() ? 1 : 0)\" class=\"bk-grid-message\">{{ loadingText() }}</td></tr>\r\n } @else {\r\n @for (item of filteredItems(); track resolveValue(item); let rowIndex = $index) {\r\n <tr\r\n #optionsRef\r\n tabindex=\"-1\"\r\n [class.bk-selected]=\"isGridItemSelected(item)\"\r\n [class.bk-marked]=\"rowIndex === markedIndex()\"\r\n [class.bk-option-disabled]=\"isItemDisabled(item)\"\r\n (click)=\"handleGridSelection(item, $event)\"\r\n (mouseenter)=\"onOptionHover(rowIndex)\"\r\n >\r\n @if (multiple()) {\r\n <td class=\"bk-grid-checkbox-column\">\r\n <bk-checkbox\r\n class=\"pointer-events-none flex\"\r\n checkboxClass=\"sm\"\r\n [disabled]=\"isItemDisabled(item)\"\r\n [ngModel]=\"isGridItemSelected(item)\"\r\n [ngModelOptions]=\"{ standalone: true }\"\r\n ></bk-checkbox>\r\n </td>\r\n }\r\n @for (column of gridColumns(); track column.key) {\r\n <td [ngStyle]=\"gridColumnStyle(column)\">\r\n @if (column.type === 'badge') {\r\n <bk-badge\r\n [label]=\"resolveGridCell(item, column)\"\r\n [color]=\"gridBadgeColor(item, column)\"\r\n [variant]=\"column.badgeVariant ?? 'Light'\"\r\n [size]=\"isGridCompact() ? 'xsm' : 'sm'\"\r\n ></bk-badge>\r\n } @else {\r\n <span class=\"bk-grid-cell-text\">{{ resolveGridCell(item, column) }}</span>\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n @if (filteredItems().length === 0) {\r\n <tr><td [attr.colspan]=\"gridColumns().length + (multiple() ? 1 : 0)\" class=\"bk-grid-message\">{{ notFoundText() }}</td></tr>\r\n }\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n @if (multiple()) {\r\n <div class=\"bk-grid-footer\">\r\n <span>{{ gridSelectedCount() }} selected</span>\r\n @if (gridSelectionActions()) {\r\n <div class=\"bk-grid-footer-actions\">\r\n <bk-button variant=\"secondary\" [size]=\"isGridCompact() ? 'xxsm' : 'xsm'\" [label]=\"gridClearText()\" (clicked)=\"clearGridDraft()\"></bk-button>\r\n <bk-button variant=\"primary\" [size]=\"isGridCompact() ? 'xxsm' : 'xsm'\" [label]=\"gridApplyText()\" (clicked)=\"applyGridDraft()\"></bk-button>\r\n </div>\r\n }\r\n </div>\r\n }\r\n } @else {\r\n <div\r\n #optionsListContainer\r\n tabindex=\"-1\"\r\n class=\"bk-options-list\"\r\n [class.bk-no-responsive]=\"!isResponsive()\"\r\n (scroll)=\"onScroll($event)\"\r\n >\r\n @if (loading()) {\r\n <div class=\"bk-option-disabled\">{{ loadingText() }}</div>\r\n } @else {\r\n @if (allSelect()) {\r\n @if (multiple() && filteredItems().length > 0) {\r\n <div\r\n class=\"bk-option\"\r\n (mousedown)=\"toggleSelectAll($event)\"\r\n [class.bk-selected]=\"isAllSelected()\"\r\n >\r\n <div class=\"flex-1 flex items-center gap-2 min-w-0\">\r\n <!-- Reflects state only: pointer-events-none lets the row's\r\n mousedown own the toggle, so the box can't fire twice.\r\n standalone keeps this ngModel out of any parent <form>\r\n bk-select is rendered inside. -->\r\n <bk-checkbox\r\n class=\"pointer-events-none shrink-0 flex\"\r\n checkboxClass=\"sm\"\r\n [ngModel]=\"isAllSelected()\"\r\n [ngModelOptions]=\"{ standalone: true }\"\r\n ></bk-checkbox>\r\n <span class=\"line-clamp-1\">Select All</span>\r\n </div>\r\n </div>\r\n }\r\n }\r\n @for (group of groupedItems(); track $index) {\r\n @if (group.group) {\r\n <div class=\"bk-option-group\">\r\n {{ group.group }}\r\n </div>\r\n }\r\n\r\n @for (item of group.items; track $index) {\r\n <div\r\n #optionsRef\r\n tabindex=\"-1\"\r\n class=\"bk-option\"\r\n [class.bk-selected]=\"isItemSelected(item)\"\r\n [class.bk-marked]=\"isMarked(item)\"\r\n [class.bk-option-disabled]=\"isItemDisabled(item)\"\r\n [class.cursor-not-allowed]=\"isItemDisabled(item)\"\r\n (click)=\"handleSelection(item, $event)\"\r\n (mouseenter)=\"markOption(item)\"\r\n >\r\n <div class=\"flex-1 flex justify-between gap-2 min-w-0\">\r\n <div class=\"flex items-center gap-2 min-w-0 flex-1\">\r\n <!-- One leading visual only: avatar > icon > dot. -->\r\n @if (showAvatar()) {\r\n <bk-avatar\r\n class=\"shrink-0 flex\"\r\n size=\"xxsm\"\r\n [src]=\"resolveAvatarSrc(item)\"\r\n [name]=\"resolveLabel(item)\"\r\n [alt]=\"iconAlt\"\r\n [bgColor]=\"avatarBgFor(item)\"\r\n [textColor]=\"avatarTextFor(item)\"\r\n ></bk-avatar>\r\n } @else if (resolveIcon(item)) {\r\n <img [src]=\"resolveIcon(item)!\" alt=\"icon\" class=\"bk-option-icon shrink-0\" />\r\n } @else if (showDots() && accentFor(item)) {\r\n <span class=\"bk-value-dot\" [style.backgroundColor]=\"accentFor(item)\"></span>\r\n }\r\n <span #optionLabelEl class=\"bk-option-label min-w-0\" [style.color]=\"optionTextColor(item)\"\r\n [bkTooltip]=\"getTooltipIfEllipsed(optionLabelEl, resolveLabel(item))\"\r\n bkTooltipPosition=\"top\">{{\r\n resolveLabel(item)\r\n }}</span>\r\n </div>\r\n\r\n @if (isItemSelected(item)) {\r\n <svg\r\n class=\"text-[#141414] shrink-0\"\r\n width=\"17\"\r\n height=\"17\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2.5\"\r\n >\r\n <polyline points=\"20 6 9 17 4 12\" />\r\n </svg>\r\n }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n @if (filteredItems().length === 0) {\r\n <div class=\"bk-option-disabled\">{{ notFoundText() }}</div>\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n </ng-template>\r\n </div>\r\n @if (hasError) {\r\n @if (errorMessage) {\r\n <p class=\"bk-select-error\">{{ errorMessage }}</p>\r\n }\r\n }\r\n</div>\r\n", styles: [".bk-select-container{@apply relative w-full box-border flex flex-col gap-1.5;}.bk-select-control{@apply flex items-center justify-between gap-2 w-full bg-white border border-[#E3E3E7] rounded cursor-pointer focus:border-[#E3E3E7] focus-visible:!outline-[.1px] focus-visible:!outline-[#6B7080];transition:border-color .2s,box-shadow .2s;box-shadow:0 1px 2px #1018280d}.bk-select-control:focus-visible{outline-style:solid!important}.bk-select-control.bk-focused{@apply shadow-none z-10;outline:none!important}.bk-select-control.bk-focused:not(.bk-filled){@apply border-[#6B7080];}.bk-select-control.bk-filled{box-shadow:none}.bk-select-control.bk-disabled{@apply cursor-not-allowed;border-color:#e3e3e7!important;background-color:#f4f4f6!important;color:#a1a3ae!important}.bk-select-control.bk-disabled .bk-placeholder{color:#a1a3ae}.bk-select-container.default .bk-select-control{@apply px-3 py-2.5;}.bk-select-container.sm .bk-select-control{@apply px-3 py-[5px];}.bk-select-control.bk-has-error{border-color:#d11e14!important}.bk-value-container{@apply flex flex-1 items-center flex-wrap gap-1 relative overflow-hidden h-full;}.bk-placeholder{@apply text-[#6B7080] font-normal text-[14px] truncate w-full pointer-events-none !leading-[18px];}.bk-value-label-single{@apply font-normal text-[#141414] truncate w-full;}.bk-select-container.default .bk-select-control .bk-value-label-single{@apply text-[14px] !leading-[18px];}.bk-select-container.sm .bk-select-control .bk-value-label-single{@apply text-xs !leading-[18px];}.bk-chips-viewport{flex:1 1 0%;min-width:0;max-width:100%}.bk-chips-measure{position:absolute;top:0;left:0;visibility:hidden;pointer-events:none;white-space:nowrap;z-index:-1}.bk-multi-badge-item{@apply inline-flex items-center gap-1.5 px-1.5 py-0.5 bg-white border border-[#E3E3E7] rounded-[4px];max-width:120px;min-width:0}.bk-multi-badge-item.bk-chip-has-avatar{@apply py-0 ps-0.5;max-width:140px}.bk-select-container.bk-grid-view .bk-multi-badge-item{max-width:175px}.bk-multi-badge-item-text{@apply text-[10px] leading-[12px] font-normal text-[#6B7080];white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.bk-multi-badge-close{@apply cursor-pointer outline-none w-3 h-3;}.bk-actions{@apply flex items-center gap-0.5 flex-shrink-0;}.bk-clear-wrapper{@apply text-gray-400 hover:text-red-500 cursor-pointer;}.bk-arrow-wrapper{@apply text-gray-400 transition-transform duration-200;}.bk-arrow-wrapper.bk-open{@apply rotate-180;}.bk-dropdown-panel{@apply static left-auto w-full bg-white border border-[#E3E3E7] rounded-xl shadow-lg overflow-hidden cursor-default p-2.5;}.bk-grid-scroll{@apply overflow-auto -mx-2.5;scrollbar-width:thin;scrollbar-color:#D6D7DC transparent}.bk-grid-scroll::-webkit-scrollbar{width:6px;height:6px}.bk-grid-scroll::-webkit-scrollbar-track{background:transparent}.bk-grid-scroll::-webkit-scrollbar-thumb{background:#d6d7dc;border-radius:999px}.bk-grid-scroll::-webkit-scrollbar-thumb:hover{background:#909090}.bk-grid-scroll::-webkit-scrollbar-button{display:none}.bk-dropdown-panel.bk-grid-panel{padding-top:0;padding-bottom:0}.bk-select-grid{@apply w-full border-collapse text-sm text-[#141414];table-layout:fixed}.bk-select-grid th{@apply sticky top-0 z-10 bg-[#F1F1F3] px-4 py-2.5 font-semibold whitespace-nowrap border-b border-[#E3E3E7];}.bk-select-grid td{@apply px-4 py-2.5 border-b border-[#E3E3E7] align-middle;}.bk-select-grid tbody tr{@apply cursor-pointer transition-colors;}.bk-select-grid tbody tr:hover,.bk-select-grid tbody tr.bk-marked{@apply bg-[#F8F8F8];}.bk-select-grid tbody tr.bk-selected{background-color:#f8f8f8}.bk-select-grid tbody tr.bk-option-disabled{@apply opacity-50 cursor-not-allowed;}.bk-grid-checkbox-column{width:48px;min-width:48px;@apply !px-4;}.bk-grid-cell-text{@apply block truncate;}.bk-grid-message{@apply !px-4 !py-4 text-center text-gray-400;}.bk-grid-footer{@apply flex items-center justify-between gap-4 px-1 py-2.5 text-xs text-[#6B7080];}.bk-grid-footer-actions{@apply flex items-center gap-2;}.bk-dropdown-panel.bk-grid-compact{padding:0 .5rem}.bk-dropdown-panel.bk-grid-compact .bk-dropdown-search{@apply px-1 pt-1;}.bk-dropdown-panel.bk-grid-compact .bk-search-wrapper{@apply px-2 py-1;}.bk-dropdown-panel.bk-grid-compact .bk-search-input{@apply text-xs;}.bk-dropdown-panel.bk-grid-compact .bk-grid-scroll{@apply -mx-2;}.bk-dropdown-panel.bk-grid-compact .bk-select-grid{@apply text-xs;}.bk-dropdown-panel.bk-grid-compact .bk-select-grid th,.bk-dropdown-panel.bk-grid-compact .bk-select-grid td{@apply px-3 py-1.5;}.bk-dropdown-panel.bk-grid-compact .bk-grid-checkbox-column{width:40px;min-width:40px;@apply !px-3;}.bk-dropdown-panel.bk-grid-compact .bk-grid-footer{@apply gap-3 px-0 py-1.5 text-[11px];}.bk-dropdown-panel.bk-grid-compact .bk-grid-footer-actions{@apply gap-1.5;}@media (max-width: 640px){.bk-grid-scroll{max-width:calc(100vw - 32px)}}.bk-dropdown-search{@apply px-2 pt-2;}.bk-search-wrapper{@apply flex items-center border border-[#E3E3E7] rounded-md px-3 py-[7px] bg-white transition-colors focus-within:border-[#E3E3E7];}.bk-search-input{@apply w-full outline-none font-normal text-sm text-[#141414] placeholder-[#A1A3AE] bg-transparent;}.bk-options-list{@apply overflow-y-auto overflow-x-hidden relative flex flex-col gap-0.5;}@media (max-height: 700px){.bk-options-list{max-height:125px}}@media (min-height: 701px) and (max-height: 900px){.bk-options-list{max-height:166px}}@media (min-height: 901px){.bk-options-list{max-height:210px}}.bk-options-list.bk-no-responsive{max-height:166px!important}.bk-option{@apply flex items-center p-2.5 cursor-pointer transition-colors font-normal text-sm text-[#141414] min-w-0;}.bk-option:hover,.bk-option.bk-marked{@apply bg-[#F1F1F3] rounded-md;}.bk-option.bk-selected{@apply bg-[#F8F8F8] rounded-md;}.bk-option.bk-selected:hover,.bk-option.bk-selected.bk-marked{@apply bg-[#F1F1F3];}.bk-option.bk-option-disabled{@apply opacity-50 cursor-not-allowed;}.bk-option.bk-option-disabled:hover{@apply bg-transparent;}.bk-option .bk-option-label{@apply line-clamp-1 break-all;}.bk-grouped .bk-option{@apply ps-5;}.bk-option-disabled{@apply px-3 py-2 text-gray-400 cursor-default text-sm;}.bk-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];}.bk-select-all-option:hover{@apply bg-gray-100;}.bk-dropdown-panel[data-position=top]{margin-top:0;margin-bottom:4px}.bk-select-label{@apply text-sm font-medium text-[#141414] tracking-[-.28px] inline-block;}.bk-select-label-required{@apply text-[#E7000B];}.bk-options-list ::-webkit-scrollbar{width:10px}.bk-options-list ::-webkit-scrollbar-track{background:transparent;border-radius:8px;width:8px}.bk-options-list ::-webkit-scrollbar-thumb{background:#d6d7dc;border-radius:8px;transition:.3s ease-in-out}.bk-options-list ::-webkit-scrollbar-thumb:hover{background:#909090}.bk-option-group{@apply px-2.5 py-1 font-bold text-[13px] leading-5 text-[#141414];}.bk-option-group:not(:first-child){@apply mt-4;}.bk-select-error{@apply text-xs text-[#E7000B] font-normal;}.bk-select-hint{@apply text-xs text-[#868997] font-normal;}.bk-search-input:focus-visible{outline:2px solid transparent}.bk-option-icon{@apply w-4 h-4 object-contain rounded-sm;}.bk-chip-icon{@apply w-3 h-3 object-contain rounded-sm;}.bk-value-dot{@apply inline-block w-2 h-2 rounded-full shrink-0;}.bk-chip-dot{@apply inline-block w-1.5 h-1.5 rounded-full shrink-0;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: BKTooltipDirective, selector: "[bkTooltip]", inputs: ["bkTooltip", "bkTooltipPosition", "bkTooltipScrollable", "bkTooltipMaxHeight", "bkTooltipSize", "bkTooltipAutoHeight"] }, { kind: "component", type: BkCheckbox, selector: "bk-checkbox", inputs: ["checkboxClass", "label", "labelClass", "disabled"], outputs: ["change"] }, { kind: "component", type: BkAvatar, selector: "bk-avatar", inputs: ["src", "alt", "name", "initialsOverride", "tooltipContent", "bgColor", "textColor", "size", "variant", "fallback", "dot", "dotPosition"], outputs: ["imageLoadError"] }, { kind: "component", type: BkButton, selector: "bk-button", inputs: ["variant", "size", "shadow", "label", "leftIcon", "rightIcon", "iconAlt", "type", "loading", "disabled", "buttonClass", "textClass", "spinnerClass"], outputs: ["clicked"] }, { kind: "component", type: BkBadge, selector: "bk-badge", inputs: ["label", "variant", "color", "size", "dot", "removable", "customClass", "customBg", "customBorder", "customText"], outputs: ["clicked"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i2.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i2.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }] });
6302
7259
  }
6303
7260
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkSelect, decorators: [{
6304
7261
  type: Component,
@@ -6757,7 +7714,7 @@ class BkInput {
6757
7714
  useExisting: forwardRef(() => BkInput),
6758
7715
  multi: true
6759
7716
  }
6760
- ], viewQueries: [{ propertyName: "inputField", first: true, predicate: ["inputField"], descendants: true }, { propertyName: "maskDirective", first: true, predicate: NgxMaskDirective, descendants: true }, { propertyName: "phoneOverlay", first: true, predicate: ["phoneOverlay"], descendants: true }], ngImport: i0, template: "<div class=\"input-container\" [class.input-container--sm]=\"size === 'sm'\">\r\n @if(label){\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\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 @if (maskValue) {\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 [attr.pattern]=\"pattern\"\r\n [autocomplete]=\"autoComplete\"\r\n [value]=\"inputValue\"\r\n\r\n [mask]=\"maskValue\"\r\n [prefix]=\"maskPrefixValue\"\r\n [showMaskTyped]=\"false\"\r\n [dropSpecialCharacters]=\"dropSpecialCharacters\"\r\n [thousandSeparator]=\"maskThousandSeparator\"\r\n [decimalMarker]=\"maskDecimalMarker\"\r\n [allowNegativeNumbers]=\"maskAllowNegativeNumbers\"\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--currency': currency,\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 } @else {\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 [attr.pattern]=\"pattern\"\r\n [autocomplete]=\"autoComplete\"\r\n [value]=\"inputValue\"\r\n\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--currency': currency,\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\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\r\n cdkOverlayOrigin\r\n #phoneOrigin=\"cdkOverlayOrigin\"\r\n class=\"input-phone-selector\"\r\n [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 CDK connected overlay: portals the panel into the shared cdk-overlay-container instead of\r\n an inline `position:absolute` div, so it escapes clipping inside dialogs/scroll containers\r\n and stacks correctly above other CDK-overlay content. Deliberately no backdrop: a backdrop\r\n is a full-viewport, click-catching layer appended to <body> \u2014 right for a true modal, wrong\r\n for a plain dropdown. In a shell that scrolls a nested container (not the window/body), a\r\n backdrop's wheel events have no scrollable ancestor to chain to and swallow ALL page scroll\r\n while open. `overlayOutsideClick` gives \"click outside to close\" without that cost \u2014 it\r\n already excludes clicks on the trigger itself, so toggleDropdown() stays the sole opener.\r\n -->\r\n <ng-template\r\n cdkConnectedOverlay\r\n #phoneOverlay=\"cdkConnectedOverlay\"\r\n [cdkConnectedOverlayOrigin]=\"phoneOrigin\"\r\n [cdkConnectedOverlayOpen]=\"isDropdownOpen\"\r\n [cdkConnectedOverlayPositions]=\"phoneDropdownPositions\"\r\n [cdkConnectedOverlayFlexibleDimensions]=\"false\"\r\n (overlayOutsideClick)=\"closeDropdown()\"\r\n (detach)=\"closeDropdown()\">\r\n <div class=\"input-phone-dropdown\">\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)\">\r\n {{ country.name }}\r\n </button>\r\n </div>\r\n </ng-template>\r\n }\r\n\r\n\r\n\r\n @if(currency){\r\n <span class=\"input-currency-icon\" [ngClass]=\"{\r\n 'input-currency-icon--default': inputState === 'default',\r\n 'input-currency-icon--focused': inputState === 'focused',\r\n 'input-currency-icon--filled': inputState === 'filled',\r\n 'input-currency-icon--error': inputState === 'error',\r\n 'input-currency-icon--disabled': inputState === 'disabled'\r\n }\">\r\n <img src=\"../../assets/icons/dollar-icon.svg\" alt=\"Currency\">\r\n </span>\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\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;box-shadow:0 1px 2px #1018280d}.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--currency{@apply pl-[3.5rem];}.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 static left-auto top-auto mt-0 w-[80px] bg-white border border-[#E3E3E7] rounded-[4px] shadow-lg 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 truncate;}.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-currency-icon{@apply absolute left-0 top-0 bottom-0 w-11 flex items-center justify-center bg-white border transition-colors duration-200 pointer-events-none;border-top-left-radius:4px;border-bottom-left-radius:4px}.input-currency-icon img{@apply w-5 h-5;}.input-currency-icon--default{@apply border-[#E3E3E7];}.input-currency-icon--focused{@apply border-[#6B7080];}.input-currency-icon--filled{@apply border-[#E3E3E7];}.input-currency-icon--error{@apply border-[#E7000B];}.input-currency-icon--disabled{@apply bg-[#F4F4F6] border-[#E3E3E7];}.input-hint{@apply text-xs text-[#868997] font-normal;}.input-error{@apply text-xs text-[#E7000B] font-normal;}.input-container ::-webkit-scrollbar{width:4px}.input-container ::-webkit-scrollbar-track{background:transparent;border-radius:8px;width:8px}.input-container ::-webkit-scrollbar-thumb{background:#d6d7dc;border-radius:8px;transition:.3s ease-in-out}.input-container ::-webkit-scrollbar-thumb:hover{background:#909090}.input-container--sm .input-label{@apply text-xs;}.input-container--sm .input-hint,.input-container--sm .input-error{@apply text-[11px];}.input-container--sm .input-field{@apply py-1.5 px-2.5 text-xs;height:32px}.input-container--sm .input-field--icon,.input-container--sm .input-field--icon-left{@apply pl-8;}.input-container--sm .input-field--icon-right,.input-container--sm .input-field--password{@apply pr-8;}.input-container--sm .input-field--phone,.input-container--sm .input-field--url{@apply pl-16;}.input-container--sm .input-field--currency{@apply pl-9;}.input-container--sm .input-currency-icon{@apply w-8;}.input-container--sm .input-currency-icon img{@apply w-4 h-4;}.input-container--sm .input-field--icon.input-field--url,.input-container--sm .input-field--phone.input-field--icon{@apply pl-24;}.input-container--sm .input-search-icon{@apply w-4 h-4;}.input-container--sm .input-search-icon--left{@apply left-2;}.input-container--sm .input-search-icon--right{@apply right-2;}.input-container--sm .input-password-toggle{@apply right-2 w-4 h-4;}.input-container--sm .input-password-icon{@apply w-4 h-4;}.input-container--sm .input-phone-selector{@apply px-2;}.input-container--sm .input-phone-selector-text{@apply text-[11px];}.input-container--sm .input-url-prefix{@apply py-1.5 px-2.5 text-xs;}.input-container--sm .input-phone-dropdown{@apply w-[68px] mt-0.5;}.input-container--sm .input-phone-dropdown-item{@apply px-3 py-1.5 text-[11px];}.input-container--sm .input-phone-selector-arrow{@apply w-3 h-3;}\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 }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i3.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i3.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }] });
7717
+ ], viewQueries: [{ propertyName: "inputField", first: true, predicate: ["inputField"], descendants: true }, { propertyName: "maskDirective", first: true, predicate: NgxMaskDirective, descendants: true }, { propertyName: "phoneOverlay", first: true, predicate: ["phoneOverlay"], descendants: true }], ngImport: i0, template: "<div class=\"bk-input-container\" [class.bk-input-container--sm]=\"size === 'sm'\">\r\n @if(label){\r\n <label [for]=\"id\" class=\"bk-input-label\">\r\n {{ label }}\r\n @if(required){\r\n <span class=\"bk-input-label-required\">*</span>\r\n }\r\n </label>\r\n }\r\n\r\n <div class=\"bk-input-wrapper\" [ngClass]=\"{\r\n 'bk-input-wrapper--url': type === 'url',\r\n 'bk-input-wrapper--phone': phone,\r\n 'bk-input-wrapper--password': password,\r\n 'bk-input-wrapper--icon': iconSrc && showIcon\r\n }\">\r\n\r\n @if (maskValue) {\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 [attr.pattern]=\"pattern\"\r\n [autocomplete]=\"autoComplete\"\r\n [value]=\"inputValue\"\r\n\r\n [mask]=\"maskValue\"\r\n [prefix]=\"maskPrefixValue\"\r\n [showMaskTyped]=\"false\"\r\n [dropSpecialCharacters]=\"dropSpecialCharacters\"\r\n [thousandSeparator]=\"maskThousandSeparator\"\r\n [decimalMarker]=\"maskDecimalMarker\"\r\n [allowNegativeNumbers]=\"maskAllowNegativeNumbers\"\r\n (change)=\"handleChange($event)\"\r\n (input)=\"handleInput($event)\"\r\n (focus)=\"handleFocus($event)\"\r\n (blur)=\"handleBlur($event)\"\r\n class=\"bk-input-field\"\r\n\r\n [ngClass]=\"{\r\n 'bk-input-field--url': type === 'url',\r\n 'bk-input-field--phone': phone,\r\n 'bk-input-field--currency': currency,\r\n 'bk-input-field--icon-left': iconSrc && showIcon && iconOrientation === 'left',\r\n 'bk-input-field--icon-right': iconSrc && showIcon && iconOrientation === 'right',\r\n 'bk-input-field--password': password,\r\n 'bk-input-field--default': inputState === 'default',\r\n 'bk-input-field--focused': inputState === 'focused',\r\n 'bk-input-field--filled': inputState === 'filled',\r\n 'bk-input-field--error': inputState === 'error',\r\n 'bk-input-field--disabled': inputState === 'disabled'\r\n }\">\r\n } @else {\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 [attr.pattern]=\"pattern\"\r\n [autocomplete]=\"autoComplete\"\r\n [value]=\"inputValue\"\r\n\r\n (change)=\"handleChange($event)\"\r\n (input)=\"handleInput($event)\"\r\n (focus)=\"handleFocus($event)\"\r\n (blur)=\"handleBlur($event)\"\r\n class=\"bk-input-field\"\r\n\r\n [ngClass]=\"{\r\n 'bk-input-field--url': type === 'url',\r\n 'bk-input-field--phone': phone,\r\n 'bk-input-field--currency': currency,\r\n 'bk-input-field--icon-left': iconSrc && showIcon && iconOrientation === 'left',\r\n 'bk-input-field--icon-right': iconSrc && showIcon && iconOrientation === 'right',\r\n 'bk-input-field--password': password,\r\n 'bk-input-field--default': inputState === 'default',\r\n 'bk-input-field--focused': inputState === 'focused',\r\n 'bk-input-field--filled': inputState === 'filled',\r\n 'bk-input-field--error': inputState === 'error',\r\n 'bk-input-field--disabled': inputState === 'disabled'\r\n }\">\r\n }\r\n\r\n @if(iconSrc && showIcon){\r\n <img (click)=\"handleIconClick($event)\" [src]=\"iconSrc\" [alt]=\"iconAlt\" [ngClass]=\"{\r\n 'bk-input-search-icon--left': iconOrientation === 'left',\r\n 'bk-input-search-icon--right': iconOrientation === 'right',\r\n 'cursor-pointer': !disabled && !readOnly\r\n }\" class=\"bk-input-search-icon\">\r\n }\r\n\r\n @if(showErrorIcon){\r\n <img src=\"../../assets/images/icons/global/info-circle.svg\" class=\"bk-input-search-icon bk-input-search-icon--right\">\r\n }\r\n\r\n @if(password){\r\n <button type=\"button\" (click)=\"togglePasswordVisibility($event)\" class=\"bk-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=\"bk-input-password-icon\">\r\n </button>\r\n }\r\n\r\n @if(phone){\r\n <div\r\n cdkOverlayOrigin\r\n #phoneOrigin=\"cdkOverlayOrigin\"\r\n class=\"bk-input-phone-selector\"\r\n [ngClass]=\"{\r\n 'bk-input-phone-selector--default': inputState === 'default',\r\n 'bk-input-phone-selector--focused': inputState === 'focused',\r\n 'bk-input-phone-selector--filled': inputState === 'filled',\r\n 'bk-input-phone-selector--error': inputState === 'error',\r\n 'bk-input-phone-selector--disabled': inputState === 'disabled'\r\n }\" (click)=\"toggleDropdown($event)\">\r\n <span class=\"bk-input-phone-selector-text\">{{ selectedCountry.name }}</span>\r\n <img src=\"../../assets/images/icons/global/input-arrow-down.svg\" alt=\"Dropdown\" class=\"bk-input-phone-selector-arrow\" [ngClass]=\"{'bk-input-phone-selector-arrow--open': isDropdownOpen}\">\r\n </div>\r\n\r\n <!--\r\n CDK connected overlay: portals the panel into the shared cdk-overlay-container instead of\r\n an inline `position:absolute` div, so it escapes clipping inside dialogs/scroll containers\r\n and stacks correctly above other CDK-overlay content. Deliberately no backdrop: a backdrop\r\n is a full-viewport, click-catching layer appended to <body> \u2014 right for a true modal, wrong\r\n for a plain dropdown. In a shell that scrolls a nested container (not the window/body), a\r\n backdrop's wheel events have no scrollable ancestor to chain to and swallow ALL page scroll\r\n while open. `overlayOutsideClick` gives \"click outside to close\" without that cost \u2014 it\r\n already excludes clicks on the trigger itself, so toggleDropdown() stays the sole opener.\r\n -->\r\n <ng-template\r\n cdkConnectedOverlay\r\n #phoneOverlay=\"cdkConnectedOverlay\"\r\n [cdkConnectedOverlayOrigin]=\"phoneOrigin\"\r\n [cdkConnectedOverlayOpen]=\"isDropdownOpen\"\r\n [cdkConnectedOverlayPositions]=\"phoneDropdownPositions\"\r\n [cdkConnectedOverlayFlexibleDimensions]=\"false\"\r\n (overlayOutsideClick)=\"closeDropdown()\"\r\n (detach)=\"closeDropdown()\">\r\n <div class=\"bk-input-phone-dropdown\">\r\n <button *ngFor=\"let country of countryOptions\" type=\"button\" class=\"bk-input-phone-dropdown-item\" [ngClass]=\"{'bk-input-phone-dropdown-item--active': selectedCountry.code === country.code}\" (click)=\"selectCountry(country)\">\r\n {{ country.name }}\r\n </button>\r\n </div>\r\n </ng-template>\r\n }\r\n\r\n\r\n\r\n @if(currency){\r\n <span class=\"bk-input-currency-icon\" [ngClass]=\"{\r\n 'bk-input-currency-icon--default': inputState === 'default',\r\n 'bk-input-currency-icon--focused': inputState === 'focused',\r\n 'bk-input-currency-icon--filled': inputState === 'filled',\r\n 'bk-input-currency-icon--error': inputState === 'error',\r\n 'bk-input-currency-icon--disabled': inputState === 'disabled'\r\n }\">\r\n <img src=\"../../assets/icons/dollar-icon.svg\" alt=\"Currency\">\r\n </span>\r\n }\r\n\r\n @if(type === 'url'){\r\n <span class=\"bk-input-url-prefix\" [ngClass]=\"{\r\n 'bk-input-url-prefix--default': inputState === 'default',\r\n 'bk-input-url-prefix--focused': inputState === 'focused',\r\n 'bk-input-url-prefix--filled': inputState === 'filled',\r\n 'bk-input-url-prefix--error': inputState === 'error',\r\n 'bk-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=\"bk-input-error\">{{ errorMessage }}</p>\r\n }\r\n }\r\n @if(!hasError){\r\n @if(hint){\r\n <p class=\"bk-input-hint\">{{ hint }}</p>\r\n }\r\n }\r\n</div>\r\n\r\n", styles: [".bk-input-container{@apply flex flex-col gap-1.5;}.bk-input-label{@apply text-sm font-medium text-[#141414];}.bk-input-label-required{@apply text-[#E7000B] ml-0.5;}.bk-input-wrapper{@apply relative;}.bk-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;box-shadow:0 1px 2px #1018280d}.bk-input-field--default{@apply border-[#E3E3E7] text-[#141414] placeholder:text-[#6B7080];}.bk-input-field--focused{@apply border-[#6B7080] text-[#141414];}.bk-input-field--filled{@apply border-[#E3E3E7] text-[#141414] bg-white;}.bk-input-field--error{@apply border-[#E7000B] text-[#141414];}.bk-input-field--disabled{@apply border-[#E3E3E7] bg-[#F4F4F6] text-[#A1A3AE] cursor-not-allowed;}.bk-input-field--icon{@apply !pl-[48px];}.bk-input-field--phone{@apply !pl-[80px];}.bk-input-field--url{@apply !pl-[72px];}.bk-input-field--currency{@apply !pl-[3.5rem];}.bk-input-field--icon-left{@apply !pl-[48px];}.bk-input-field--icon-right,.bk-input-field--password{@apply !pr-[48px];}.bk-input-field--icon.bk-input-field--url{@apply !pl-[120px];}.bk-input-field--phone.bk-input-field--icon{@apply !pl-[128px];}.bk-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}.bk-input-phone-selector-text{@apply text-xs leading-[18px] text-[#A1A3AE] font-normal;}.bk-input-phone-selector-arrow{@apply w-4 h-4 transition-transform duration-200;}.bk-input-phone-selector-arrow--open{@apply rotate-180;}.bk-input-phone-selector--default{@apply bg-white border-[#E3E3E7];}.bk-input-phone-selector--focused{@apply bg-white border-[#6B7080];}.bk-input-phone-selector--filled{@apply bg-white border-[#E3E3E7];}.bk-input-phone-selector--error{@apply bg-white border-[#E7000B];}.bk-input-phone-selector--disabled{@apply bg-[#F4F4F6] border-[#E3E3E7] cursor-not-allowed;}.bk-input-phone-selector--disabled .bk-input-phone-selector-text{@apply text-[#A1A3AE];}.bk-input-phone-dropdown{@apply static left-auto top-auto mt-0 w-[80px] bg-white border border-[#E3E3E7] rounded-[4px] shadow-lg max-h-48 overflow-y-auto;}.bk-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 truncate;}.bk-input-phone-dropdown-item--active{@apply bg-[#F9FAFA] text-[#141414];}.bk-input-icon{@apply absolute left-3 top-1/2 -translate-y-1/2 w-6 h-6 pointer-events-none size-6;}.bk-input-wrapper--phone .bk-input-icon{@apply left-[80px];}.bk-input-search-icon{@apply absolute top-1/2 -translate-y-1/2 w-5 h-5;}.bk-input-search-icon--left{@apply left-3;}.bk-input-search-icon--right{@apply right-3;}.bk-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;}.bk-input-password-toggle:disabled{@apply cursor-not-allowed opacity-50;}.bk-input-password-toggle:hover:not(:disabled){@apply opacity-70;}.bk-input-password-icon{@apply w-5 h-5 pointer-events-none;}.bk-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}.bk-input-wrapper--icon .bk-input-url-prefix{@apply left-[48px];}.bk-input-url-prefix--default{@apply border-[#E3E3E7];}.bk-input-url-prefix--focused{@apply border-[#6B7080];}.bk-input-url-prefix--filled{@apply border-[#E3E3E7];}.bk-input-url-prefix--error{@apply border-[#E7000B];}.bk-input-url-prefix--disabled{@apply bg-[#F4F4F6] text-[#A1A3AE] border-r-[#E3E3E7];}.bk-input-currency-icon{@apply absolute left-0 top-0 bottom-0 w-11 flex items-center justify-center bg-white border transition-colors duration-200 pointer-events-none;border-top-left-radius:4px;border-bottom-left-radius:4px}.bk-input-currency-icon img{@apply w-5 h-5;}.bk-input-currency-icon--default{@apply border-[#E3E3E7];}.bk-input-currency-icon--focused{@apply border-[#6B7080];}.bk-input-currency-icon--filled{@apply border-[#E3E3E7];}.bk-input-currency-icon--error{@apply border-[#E7000B];}.bk-input-currency-icon--disabled{@apply bg-[#F4F4F6] border-[#E3E3E7];}.bk-input-hint{@apply text-xs text-[#868997] font-normal;}.bk-input-error{@apply text-xs text-[#E7000B] font-normal;}.bk-input-container ::-webkit-scrollbar{width:4px}.bk-input-container ::-webkit-scrollbar-track{background:transparent;border-radius:8px;width:8px}.bk-input-container ::-webkit-scrollbar-thumb{background:#d6d7dc;border-radius:8px;transition:.3s ease-in-out}.bk-input-container ::-webkit-scrollbar-thumb:hover{background:#909090}.bk-input-container--sm .bk-input-label{@apply text-xs;}.bk-input-container--sm .bk-input-hint,.bk-input-container--sm .bk-input-error{@apply text-[11px];}.bk-input-container--sm .bk-input-field{@apply py-1.5 px-2.5 text-xs;height:32px}.bk-input-container--sm .bk-input-field--icon,.bk-input-container--sm .bk-input-field--icon-left{@apply !pl-8;}.bk-input-container--sm .bk-input-field--icon-right,.bk-input-container--sm .bk-input-field--password{@apply !pr-8;}.bk-input-container--sm .bk-input-field--phone,.bk-input-container--sm .bk-input-field--url{@apply !pl-16;}.bk-input-container--sm .bk-input-field--currency{@apply !pl-9;}.bk-input-container--sm .bk-input-currency-icon{@apply w-8;}.bk-input-container--sm .bk-input-currency-icon img{@apply w-4 h-4;}.bk-input-container--sm .bk-input-field--icon.bk-input-field--url,.bk-input-container--sm .bk-input-field--phone.bk-input-field--icon{@apply !pl-24;}.bk-input-container--sm .bk-input-search-icon{@apply w-4 h-4;}.bk-input-container--sm .bk-input-search-icon--left{@apply left-2;}.bk-input-container--sm .bk-input-search-icon--right{@apply right-2;}.bk-input-container--sm .bk-input-password-toggle{@apply right-2 w-4 h-4;}.bk-input-container--sm .bk-input-password-icon{@apply w-4 h-4;}.bk-input-container--sm .bk-input-phone-selector{@apply px-2;}.bk-input-container--sm .bk-input-phone-selector-text{@apply text-[11px];}.bk-input-container--sm .bk-input-url-prefix{@apply py-1.5 px-2.5 text-xs;}.bk-input-container--sm .bk-input-phone-dropdown{@apply w-[68px] mt-0.5;}.bk-input-container--sm .bk-input-phone-dropdown-item{@apply px-3 py-1.5 text-[11px];}.bk-input-container--sm .bk-input-phone-selector-arrow{@apply w-3 h-3;}\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 }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i2.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i2.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }] });
6761
7718
  }
6762
7719
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkInput, decorators: [{
6763
7720
  type: Component,
@@ -6768,7 +7725,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
6768
7725
  useExisting: forwardRef(() => BkInput),
6769
7726
  multi: true
6770
7727
  }
6771
- ], template: "<div class=\"input-container\" [class.input-container--sm]=\"size === 'sm'\">\r\n @if(label){\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\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 @if (maskValue) {\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 [attr.pattern]=\"pattern\"\r\n [autocomplete]=\"autoComplete\"\r\n [value]=\"inputValue\"\r\n\r\n [mask]=\"maskValue\"\r\n [prefix]=\"maskPrefixValue\"\r\n [showMaskTyped]=\"false\"\r\n [dropSpecialCharacters]=\"dropSpecialCharacters\"\r\n [thousandSeparator]=\"maskThousandSeparator\"\r\n [decimalMarker]=\"maskDecimalMarker\"\r\n [allowNegativeNumbers]=\"maskAllowNegativeNumbers\"\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--currency': currency,\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 } @else {\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 [attr.pattern]=\"pattern\"\r\n [autocomplete]=\"autoComplete\"\r\n [value]=\"inputValue\"\r\n\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--currency': currency,\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\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\r\n cdkOverlayOrigin\r\n #phoneOrigin=\"cdkOverlayOrigin\"\r\n class=\"input-phone-selector\"\r\n [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 CDK connected overlay: portals the panel into the shared cdk-overlay-container instead of\r\n an inline `position:absolute` div, so it escapes clipping inside dialogs/scroll containers\r\n and stacks correctly above other CDK-overlay content. Deliberately no backdrop: a backdrop\r\n is a full-viewport, click-catching layer appended to <body> \u2014 right for a true modal, wrong\r\n for a plain dropdown. In a shell that scrolls a nested container (not the window/body), a\r\n backdrop's wheel events have no scrollable ancestor to chain to and swallow ALL page scroll\r\n while open. `overlayOutsideClick` gives \"click outside to close\" without that cost \u2014 it\r\n already excludes clicks on the trigger itself, so toggleDropdown() stays the sole opener.\r\n -->\r\n <ng-template\r\n cdkConnectedOverlay\r\n #phoneOverlay=\"cdkConnectedOverlay\"\r\n [cdkConnectedOverlayOrigin]=\"phoneOrigin\"\r\n [cdkConnectedOverlayOpen]=\"isDropdownOpen\"\r\n [cdkConnectedOverlayPositions]=\"phoneDropdownPositions\"\r\n [cdkConnectedOverlayFlexibleDimensions]=\"false\"\r\n (overlayOutsideClick)=\"closeDropdown()\"\r\n (detach)=\"closeDropdown()\">\r\n <div class=\"input-phone-dropdown\">\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)\">\r\n {{ country.name }}\r\n </button>\r\n </div>\r\n </ng-template>\r\n }\r\n\r\n\r\n\r\n @if(currency){\r\n <span class=\"input-currency-icon\" [ngClass]=\"{\r\n 'input-currency-icon--default': inputState === 'default',\r\n 'input-currency-icon--focused': inputState === 'focused',\r\n 'input-currency-icon--filled': inputState === 'filled',\r\n 'input-currency-icon--error': inputState === 'error',\r\n 'input-currency-icon--disabled': inputState === 'disabled'\r\n }\">\r\n <img src=\"../../assets/icons/dollar-icon.svg\" alt=\"Currency\">\r\n </span>\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\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;box-shadow:0 1px 2px #1018280d}.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--currency{@apply pl-[3.5rem];}.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 static left-auto top-auto mt-0 w-[80px] bg-white border border-[#E3E3E7] rounded-[4px] shadow-lg 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 truncate;}.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-currency-icon{@apply absolute left-0 top-0 bottom-0 w-11 flex items-center justify-center bg-white border transition-colors duration-200 pointer-events-none;border-top-left-radius:4px;border-bottom-left-radius:4px}.input-currency-icon img{@apply w-5 h-5;}.input-currency-icon--default{@apply border-[#E3E3E7];}.input-currency-icon--focused{@apply border-[#6B7080];}.input-currency-icon--filled{@apply border-[#E3E3E7];}.input-currency-icon--error{@apply border-[#E7000B];}.input-currency-icon--disabled{@apply bg-[#F4F4F6] border-[#E3E3E7];}.input-hint{@apply text-xs text-[#868997] font-normal;}.input-error{@apply text-xs text-[#E7000B] font-normal;}.input-container ::-webkit-scrollbar{width:4px}.input-container ::-webkit-scrollbar-track{background:transparent;border-radius:8px;width:8px}.input-container ::-webkit-scrollbar-thumb{background:#d6d7dc;border-radius:8px;transition:.3s ease-in-out}.input-container ::-webkit-scrollbar-thumb:hover{background:#909090}.input-container--sm .input-label{@apply text-xs;}.input-container--sm .input-hint,.input-container--sm .input-error{@apply text-[11px];}.input-container--sm .input-field{@apply py-1.5 px-2.5 text-xs;height:32px}.input-container--sm .input-field--icon,.input-container--sm .input-field--icon-left{@apply pl-8;}.input-container--sm .input-field--icon-right,.input-container--sm .input-field--password{@apply pr-8;}.input-container--sm .input-field--phone,.input-container--sm .input-field--url{@apply pl-16;}.input-container--sm .input-field--currency{@apply pl-9;}.input-container--sm .input-currency-icon{@apply w-8;}.input-container--sm .input-currency-icon img{@apply w-4 h-4;}.input-container--sm .input-field--icon.input-field--url,.input-container--sm .input-field--phone.input-field--icon{@apply pl-24;}.input-container--sm .input-search-icon{@apply w-4 h-4;}.input-container--sm .input-search-icon--left{@apply left-2;}.input-container--sm .input-search-icon--right{@apply right-2;}.input-container--sm .input-password-toggle{@apply right-2 w-4 h-4;}.input-container--sm .input-password-icon{@apply w-4 h-4;}.input-container--sm .input-phone-selector{@apply px-2;}.input-container--sm .input-phone-selector-text{@apply text-[11px];}.input-container--sm .input-url-prefix{@apply py-1.5 px-2.5 text-xs;}.input-container--sm .input-phone-dropdown{@apply w-[68px] mt-0.5;}.input-container--sm .input-phone-dropdown-item{@apply px-3 py-1.5 text-[11px];}.input-container--sm .input-phone-selector-arrow{@apply w-3 h-3;}\n"] }]
7728
+ ], template: "<div class=\"bk-input-container\" [class.bk-input-container--sm]=\"size === 'sm'\">\r\n @if(label){\r\n <label [for]=\"id\" class=\"bk-input-label\">\r\n {{ label }}\r\n @if(required){\r\n <span class=\"bk-input-label-required\">*</span>\r\n }\r\n </label>\r\n }\r\n\r\n <div class=\"bk-input-wrapper\" [ngClass]=\"{\r\n 'bk-input-wrapper--url': type === 'url',\r\n 'bk-input-wrapper--phone': phone,\r\n 'bk-input-wrapper--password': password,\r\n 'bk-input-wrapper--icon': iconSrc && showIcon\r\n }\">\r\n\r\n @if (maskValue) {\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 [attr.pattern]=\"pattern\"\r\n [autocomplete]=\"autoComplete\"\r\n [value]=\"inputValue\"\r\n\r\n [mask]=\"maskValue\"\r\n [prefix]=\"maskPrefixValue\"\r\n [showMaskTyped]=\"false\"\r\n [dropSpecialCharacters]=\"dropSpecialCharacters\"\r\n [thousandSeparator]=\"maskThousandSeparator\"\r\n [decimalMarker]=\"maskDecimalMarker\"\r\n [allowNegativeNumbers]=\"maskAllowNegativeNumbers\"\r\n (change)=\"handleChange($event)\"\r\n (input)=\"handleInput($event)\"\r\n (focus)=\"handleFocus($event)\"\r\n (blur)=\"handleBlur($event)\"\r\n class=\"bk-input-field\"\r\n\r\n [ngClass]=\"{\r\n 'bk-input-field--url': type === 'url',\r\n 'bk-input-field--phone': phone,\r\n 'bk-input-field--currency': currency,\r\n 'bk-input-field--icon-left': iconSrc && showIcon && iconOrientation === 'left',\r\n 'bk-input-field--icon-right': iconSrc && showIcon && iconOrientation === 'right',\r\n 'bk-input-field--password': password,\r\n 'bk-input-field--default': inputState === 'default',\r\n 'bk-input-field--focused': inputState === 'focused',\r\n 'bk-input-field--filled': inputState === 'filled',\r\n 'bk-input-field--error': inputState === 'error',\r\n 'bk-input-field--disabled': inputState === 'disabled'\r\n }\">\r\n } @else {\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 [attr.pattern]=\"pattern\"\r\n [autocomplete]=\"autoComplete\"\r\n [value]=\"inputValue\"\r\n\r\n (change)=\"handleChange($event)\"\r\n (input)=\"handleInput($event)\"\r\n (focus)=\"handleFocus($event)\"\r\n (blur)=\"handleBlur($event)\"\r\n class=\"bk-input-field\"\r\n\r\n [ngClass]=\"{\r\n 'bk-input-field--url': type === 'url',\r\n 'bk-input-field--phone': phone,\r\n 'bk-input-field--currency': currency,\r\n 'bk-input-field--icon-left': iconSrc && showIcon && iconOrientation === 'left',\r\n 'bk-input-field--icon-right': iconSrc && showIcon && iconOrientation === 'right',\r\n 'bk-input-field--password': password,\r\n 'bk-input-field--default': inputState === 'default',\r\n 'bk-input-field--focused': inputState === 'focused',\r\n 'bk-input-field--filled': inputState === 'filled',\r\n 'bk-input-field--error': inputState === 'error',\r\n 'bk-input-field--disabled': inputState === 'disabled'\r\n }\">\r\n }\r\n\r\n @if(iconSrc && showIcon){\r\n <img (click)=\"handleIconClick($event)\" [src]=\"iconSrc\" [alt]=\"iconAlt\" [ngClass]=\"{\r\n 'bk-input-search-icon--left': iconOrientation === 'left',\r\n 'bk-input-search-icon--right': iconOrientation === 'right',\r\n 'cursor-pointer': !disabled && !readOnly\r\n }\" class=\"bk-input-search-icon\">\r\n }\r\n\r\n @if(showErrorIcon){\r\n <img src=\"../../assets/images/icons/global/info-circle.svg\" class=\"bk-input-search-icon bk-input-search-icon--right\">\r\n }\r\n\r\n @if(password){\r\n <button type=\"button\" (click)=\"togglePasswordVisibility($event)\" class=\"bk-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=\"bk-input-password-icon\">\r\n </button>\r\n }\r\n\r\n @if(phone){\r\n <div\r\n cdkOverlayOrigin\r\n #phoneOrigin=\"cdkOverlayOrigin\"\r\n class=\"bk-input-phone-selector\"\r\n [ngClass]=\"{\r\n 'bk-input-phone-selector--default': inputState === 'default',\r\n 'bk-input-phone-selector--focused': inputState === 'focused',\r\n 'bk-input-phone-selector--filled': inputState === 'filled',\r\n 'bk-input-phone-selector--error': inputState === 'error',\r\n 'bk-input-phone-selector--disabled': inputState === 'disabled'\r\n }\" (click)=\"toggleDropdown($event)\">\r\n <span class=\"bk-input-phone-selector-text\">{{ selectedCountry.name }}</span>\r\n <img src=\"../../assets/images/icons/global/input-arrow-down.svg\" alt=\"Dropdown\" class=\"bk-input-phone-selector-arrow\" [ngClass]=\"{'bk-input-phone-selector-arrow--open': isDropdownOpen}\">\r\n </div>\r\n\r\n <!--\r\n CDK connected overlay: portals the panel into the shared cdk-overlay-container instead of\r\n an inline `position:absolute` div, so it escapes clipping inside dialogs/scroll containers\r\n and stacks correctly above other CDK-overlay content. Deliberately no backdrop: a backdrop\r\n is a full-viewport, click-catching layer appended to <body> \u2014 right for a true modal, wrong\r\n for a plain dropdown. In a shell that scrolls a nested container (not the window/body), a\r\n backdrop's wheel events have no scrollable ancestor to chain to and swallow ALL page scroll\r\n while open. `overlayOutsideClick` gives \"click outside to close\" without that cost \u2014 it\r\n already excludes clicks on the trigger itself, so toggleDropdown() stays the sole opener.\r\n -->\r\n <ng-template\r\n cdkConnectedOverlay\r\n #phoneOverlay=\"cdkConnectedOverlay\"\r\n [cdkConnectedOverlayOrigin]=\"phoneOrigin\"\r\n [cdkConnectedOverlayOpen]=\"isDropdownOpen\"\r\n [cdkConnectedOverlayPositions]=\"phoneDropdownPositions\"\r\n [cdkConnectedOverlayFlexibleDimensions]=\"false\"\r\n (overlayOutsideClick)=\"closeDropdown()\"\r\n (detach)=\"closeDropdown()\">\r\n <div class=\"bk-input-phone-dropdown\">\r\n <button *ngFor=\"let country of countryOptions\" type=\"button\" class=\"bk-input-phone-dropdown-item\" [ngClass]=\"{'bk-input-phone-dropdown-item--active': selectedCountry.code === country.code}\" (click)=\"selectCountry(country)\">\r\n {{ country.name }}\r\n </button>\r\n </div>\r\n </ng-template>\r\n }\r\n\r\n\r\n\r\n @if(currency){\r\n <span class=\"bk-input-currency-icon\" [ngClass]=\"{\r\n 'bk-input-currency-icon--default': inputState === 'default',\r\n 'bk-input-currency-icon--focused': inputState === 'focused',\r\n 'bk-input-currency-icon--filled': inputState === 'filled',\r\n 'bk-input-currency-icon--error': inputState === 'error',\r\n 'bk-input-currency-icon--disabled': inputState === 'disabled'\r\n }\">\r\n <img src=\"../../assets/icons/dollar-icon.svg\" alt=\"Currency\">\r\n </span>\r\n }\r\n\r\n @if(type === 'url'){\r\n <span class=\"bk-input-url-prefix\" [ngClass]=\"{\r\n 'bk-input-url-prefix--default': inputState === 'default',\r\n 'bk-input-url-prefix--focused': inputState === 'focused',\r\n 'bk-input-url-prefix--filled': inputState === 'filled',\r\n 'bk-input-url-prefix--error': inputState === 'error',\r\n 'bk-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=\"bk-input-error\">{{ errorMessage }}</p>\r\n }\r\n }\r\n @if(!hasError){\r\n @if(hint){\r\n <p class=\"bk-input-hint\">{{ hint }}</p>\r\n }\r\n }\r\n</div>\r\n\r\n", styles: [".bk-input-container{@apply flex flex-col gap-1.5;}.bk-input-label{@apply text-sm font-medium text-[#141414];}.bk-input-label-required{@apply text-[#E7000B] ml-0.5;}.bk-input-wrapper{@apply relative;}.bk-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;box-shadow:0 1px 2px #1018280d}.bk-input-field--default{@apply border-[#E3E3E7] text-[#141414] placeholder:text-[#6B7080];}.bk-input-field--focused{@apply border-[#6B7080] text-[#141414];}.bk-input-field--filled{@apply border-[#E3E3E7] text-[#141414] bg-white;}.bk-input-field--error{@apply border-[#E7000B] text-[#141414];}.bk-input-field--disabled{@apply border-[#E3E3E7] bg-[#F4F4F6] text-[#A1A3AE] cursor-not-allowed;}.bk-input-field--icon{@apply !pl-[48px];}.bk-input-field--phone{@apply !pl-[80px];}.bk-input-field--url{@apply !pl-[72px];}.bk-input-field--currency{@apply !pl-[3.5rem];}.bk-input-field--icon-left{@apply !pl-[48px];}.bk-input-field--icon-right,.bk-input-field--password{@apply !pr-[48px];}.bk-input-field--icon.bk-input-field--url{@apply !pl-[120px];}.bk-input-field--phone.bk-input-field--icon{@apply !pl-[128px];}.bk-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}.bk-input-phone-selector-text{@apply text-xs leading-[18px] text-[#A1A3AE] font-normal;}.bk-input-phone-selector-arrow{@apply w-4 h-4 transition-transform duration-200;}.bk-input-phone-selector-arrow--open{@apply rotate-180;}.bk-input-phone-selector--default{@apply bg-white border-[#E3E3E7];}.bk-input-phone-selector--focused{@apply bg-white border-[#6B7080];}.bk-input-phone-selector--filled{@apply bg-white border-[#E3E3E7];}.bk-input-phone-selector--error{@apply bg-white border-[#E7000B];}.bk-input-phone-selector--disabled{@apply bg-[#F4F4F6] border-[#E3E3E7] cursor-not-allowed;}.bk-input-phone-selector--disabled .bk-input-phone-selector-text{@apply text-[#A1A3AE];}.bk-input-phone-dropdown{@apply static left-auto top-auto mt-0 w-[80px] bg-white border border-[#E3E3E7] rounded-[4px] shadow-lg max-h-48 overflow-y-auto;}.bk-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 truncate;}.bk-input-phone-dropdown-item--active{@apply bg-[#F9FAFA] text-[#141414];}.bk-input-icon{@apply absolute left-3 top-1/2 -translate-y-1/2 w-6 h-6 pointer-events-none size-6;}.bk-input-wrapper--phone .bk-input-icon{@apply left-[80px];}.bk-input-search-icon{@apply absolute top-1/2 -translate-y-1/2 w-5 h-5;}.bk-input-search-icon--left{@apply left-3;}.bk-input-search-icon--right{@apply right-3;}.bk-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;}.bk-input-password-toggle:disabled{@apply cursor-not-allowed opacity-50;}.bk-input-password-toggle:hover:not(:disabled){@apply opacity-70;}.bk-input-password-icon{@apply w-5 h-5 pointer-events-none;}.bk-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}.bk-input-wrapper--icon .bk-input-url-prefix{@apply left-[48px];}.bk-input-url-prefix--default{@apply border-[#E3E3E7];}.bk-input-url-prefix--focused{@apply border-[#6B7080];}.bk-input-url-prefix--filled{@apply border-[#E3E3E7];}.bk-input-url-prefix--error{@apply border-[#E7000B];}.bk-input-url-prefix--disabled{@apply bg-[#F4F4F6] text-[#A1A3AE] border-r-[#E3E3E7];}.bk-input-currency-icon{@apply absolute left-0 top-0 bottom-0 w-11 flex items-center justify-center bg-white border transition-colors duration-200 pointer-events-none;border-top-left-radius:4px;border-bottom-left-radius:4px}.bk-input-currency-icon img{@apply w-5 h-5;}.bk-input-currency-icon--default{@apply border-[#E3E3E7];}.bk-input-currency-icon--focused{@apply border-[#6B7080];}.bk-input-currency-icon--filled{@apply border-[#E3E3E7];}.bk-input-currency-icon--error{@apply border-[#E7000B];}.bk-input-currency-icon--disabled{@apply bg-[#F4F4F6] border-[#E3E3E7];}.bk-input-hint{@apply text-xs text-[#868997] font-normal;}.bk-input-error{@apply text-xs text-[#E7000B] font-normal;}.bk-input-container ::-webkit-scrollbar{width:4px}.bk-input-container ::-webkit-scrollbar-track{background:transparent;border-radius:8px;width:8px}.bk-input-container ::-webkit-scrollbar-thumb{background:#d6d7dc;border-radius:8px;transition:.3s ease-in-out}.bk-input-container ::-webkit-scrollbar-thumb:hover{background:#909090}.bk-input-container--sm .bk-input-label{@apply text-xs;}.bk-input-container--sm .bk-input-hint,.bk-input-container--sm .bk-input-error{@apply text-[11px];}.bk-input-container--sm .bk-input-field{@apply py-1.5 px-2.5 text-xs;height:32px}.bk-input-container--sm .bk-input-field--icon,.bk-input-container--sm .bk-input-field--icon-left{@apply !pl-8;}.bk-input-container--sm .bk-input-field--icon-right,.bk-input-container--sm .bk-input-field--password{@apply !pr-8;}.bk-input-container--sm .bk-input-field--phone,.bk-input-container--sm .bk-input-field--url{@apply !pl-16;}.bk-input-container--sm .bk-input-field--currency{@apply !pl-9;}.bk-input-container--sm .bk-input-currency-icon{@apply w-8;}.bk-input-container--sm .bk-input-currency-icon img{@apply w-4 h-4;}.bk-input-container--sm .bk-input-field--icon.bk-input-field--url,.bk-input-container--sm .bk-input-field--phone.bk-input-field--icon{@apply !pl-24;}.bk-input-container--sm .bk-input-search-icon{@apply w-4 h-4;}.bk-input-container--sm .bk-input-search-icon--left{@apply left-2;}.bk-input-container--sm .bk-input-search-icon--right{@apply right-2;}.bk-input-container--sm .bk-input-password-toggle{@apply right-2 w-4 h-4;}.bk-input-container--sm .bk-input-password-icon{@apply w-4 h-4;}.bk-input-container--sm .bk-input-phone-selector{@apply px-2;}.bk-input-container--sm .bk-input-phone-selector-text{@apply text-[11px];}.bk-input-container--sm .bk-input-url-prefix{@apply py-1.5 px-2.5 text-xs;}.bk-input-container--sm .bk-input-phone-dropdown{@apply w-[68px] mt-0.5;}.bk-input-container--sm .bk-input-phone-dropdown-item{@apply px-3 py-1.5 text-[11px];}.bk-input-container--sm .bk-input-phone-selector-arrow{@apply w-3 h-3;}\n"] }]
6772
7729
  }], propDecorators: { id: [{
6773
7730
  type: Input
6774
7731
  }], name: [{
@@ -8209,7 +9166,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
8209
9166
  */
8210
9167
  class BkDialogContent {
8211
9168
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkDialogContent, deps: [], target: i0.ɵɵFactoryTarget.Directive });
8212
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.16", type: BkDialogContent, isStandalone: true, selector: "[bk-dialog-content], bk-dialog-content, [bkDialogContent]", host: { classAttribute: "bk-dialog-content" }, exportAs: ["bkDialogContent"], hostDirectives: [{ directive: i2$2.CdkScrollable }], ngImport: i0 });
9169
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.16", type: BkDialogContent, isStandalone: true, selector: "[bk-dialog-content], bk-dialog-content, [bkDialogContent]", host: { classAttribute: "bk-dialog-content" }, exportAs: ["bkDialogContent"], hostDirectives: [{ directive: i1$1.CdkScrollable }], ngImport: i0 });
8213
9170
  }
8214
9171
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkDialogContent, decorators: [{
8215
9172
  type: Directive,
@@ -9424,7 +10381,7 @@ class BkHierarchicalSelect {
9424
10381
  useExisting: forwardRef(() => BkHierarchicalSelect),
9425
10382
  multi: true,
9426
10383
  },
9427
- ], viewQueries: [{ propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true }, { propertyName: "controlWrapper", first: true, predicate: ["controlWrapper"], descendants: true }, { propertyName: "dropdownPanel", first: true, predicate: ["dropdownPanel"], descendants: true }, { propertyName: "optionsListContainer", first: true, predicate: ["optionsListContainer"], descendants: true }, { propertyName: "hierarchicalOverlay", first: true, predicate: ["hierarchicalOverlay"], descendants: true }, { propertyName: "optionEls", predicate: ["optionRef"], descendants: true }], ngImport: i0, template: "<div class=\"hierarchical-select-container\">\r\n @if (label()) {\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\r\n <div class=\"hierarchical-select-field\">\r\n <!-- With showDots on, the control is tinted by the selected node's accent.\r\n An errored control drops the tint entirely and goes neutral, so the red\r\n border reads as an error rather than competing with the accent. -->\r\n <div\r\n #controlWrapper\r\n cdkOverlayOrigin\r\n #hierarchicalOrigin=\"cdkOverlayOrigin\"\r\n class=\"hierarchical-select-control\"\r\n [ngClass]=\"{ 'hierarchical-select-control-has-error': hasError() }\"\r\n tabindex=\"0\"\r\n [class.focused]=\"isOpen()\"\r\n [class.disabled]=\"isDisabled()\"\r\n [class.filled]=\"!hasError() && !!controlAppearance().backgroundColor\"\r\n [style.backgroundColor]=\"hasError() ? null : controlAppearance().backgroundColor\"\r\n [style.color]=\"hasError() ? null : controlAppearance().color\"\r\n [style.borderColor]=\"hasError() ? null : controlAppearance().borderColor\"\r\n (keydown)=\"onKeyDown($event)\"\r\n (mousedown)=\"toggleDropdown($event)\">\r\n @if (iconSrc()) {\r\n <img [src]=\"iconSrc()\" [alt]=\"iconAlt()\" class=\"shrink-0\" />\r\n }\r\n <div class=\"hierarchical-value-container\">\r\n @if (!selected()) {\r\n <div class=\"hierarchical-placeholder\">{{ placeholder() }}</div>\r\n } @else {\r\n <!-- Single row: the container is flex-wrap and the label is w-full, so\r\n a bare sibling dot would push the label onto a second line. -->\r\n <div class=\"hierarchical-value-row\">\r\n @if (showDots() && accentFor(selected()!)) {\r\n <span class=\"hierarchical-dot\" [style.backgroundColor]=\"accentFor(selected()!)\"></span>\r\n }\r\n <div class=\"hierarchical-value-label\" [style.color]=\"controlAppearance().color ?? resolveColor(selected())\">\r\n @for (node of displayPath(); track getValue(node); let last = $last) {\r\n <span\r\n #breadNode\r\n class=\"hierarchical-breadcrumb-node\"\r\n [bkTooltip]=\"breadNode.scrollWidth > breadNode.clientWidth ? getLabel(node) : ''\"\r\n bkTooltipPosition=\"top\">{{ getLabel(node) }}</span>\r\n\r\n @if (!last) {\r\n <svg\r\n class=\"breadcrumb-separator\"\r\n width=\"5\"\r\n height=\"8\"\r\n viewBox=\"0 0 5 8\"\r\n fill=\"none\"\r\n xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n d=\"M4.57142 4.00286C4.57185 3.92766 4.55744 3.85312 4.52901 3.78351C4.50057 3.71389 4.45868 3.65058 4.40572 3.59719L0.977497 0.169008C0.924381 0.115455 0.861186 0.0729493 0.79156 0.0439419C0.721933 0.0149346 0.647251 0 0.571824 0C0.496396 0 0.421714 0.0149346 0.352088 0.0439419C0.282461 0.0729493 0.219267 0.115455 0.16615 0.169008C0.059732 0.27606 0 0.420874 0 0.57182C0 0.722766 0.059732 0.867579 0.16615 0.974631L3.19442 4.00286L0.16615 7.02537C0.059732 7.13242 0 7.27723 0 7.42818C0 7.57913 0.059732 7.72394 0.16615 7.83099C0.219267 7.88454 0.282461 7.92705 0.352088 7.95606C0.421714 7.98507 0.496396 8 0.571824 8C0.647251 8 0.721933 7.98507 0.79156 7.95606C0.861186 7.92705 0.924381 7.88454 0.977497 7.83099L4.40572 4.40281C4.51128 4.29639 4.57079 4.15275 4.57142 4.00286Z\"\r\n fill=\"#BBBDC5\"/>\r\n </svg>\r\n }\r\n }\r\n </div>\r\n </div>\r\n\r\n }\r\n </div>\r\n <div class=\"hierarchical-actions\">\r\n @if (clearable() && selected() && !isDisabled()) {\r\n <span class=\"hierarchical-clear-wrapper\" (mousedown)=\"handleClear($event)\" title=\"Clear\" [bkTooltip]=\"clearTooltip()\" bkTooltipPosition=\"top\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\"\r\n stroke=\"currentColor\" stroke-width=\"2\" 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 </span>\r\n }\r\n <span class=\"hierarchical-arrow\" [class.open]=\"isOpen()\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\"\r\n stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"m6 9 6 6 6-6\"/>\r\n </svg>\r\n </span>\r\n </div>\r\n </div>\r\n\r\n <!--\r\n CDK connected overlay: portals the panel into the shared cdk-overlay-container instead of\r\n an inline `position:absolute`/`fixed` div, so it escapes clipping inside dialogs/scroll\r\n containers and stacks correctly above other CDK-overlay content, regardless of the old\r\n appendToBody flag (see its @deprecated note). No backdrop \u2014 see onOverlayOutsideClick.\r\n -->\r\n <ng-template\r\n cdkConnectedOverlay\r\n #hierarchicalOverlay=\"cdkConnectedOverlay\"\r\n [cdkConnectedOverlayOrigin]=\"hierarchicalOrigin\"\r\n [cdkConnectedOverlayOpen]=\"isOpen()\"\r\n [cdkConnectedOverlayPositions]=\"hierarchicalDropdownPositions\"\r\n [cdkConnectedOverlayWidth]=\"dropdownWidth() ?? ''\"\r\n [cdkConnectedOverlayFlexibleDimensions]=\"false\"\r\n (positionChange)=\"onPositionChange($event)\"\r\n (overlayOutsideClick)=\"onOverlayOutsideClick()\"\r\n (detach)=\"closeDropdown()\"\r\n >\r\n <div\r\n #dropdownPanel\r\n class=\"hierarchical-dropdown-panel\"\r\n [style.visibility]=\"panelReady() ? 'visible' : 'hidden'\"\r\n [attr.data-position]=\"placement()\">\r\n @if (searchable()) {\r\n <div class=\"hierarchical-search\">\r\n <div class=\"hierarchical-search-wrapper\">\r\n <svg class=\"text-[#BBBDC5] mr-2\" xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\"\r\n viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\">\r\n <circle cx=\"11\" cy=\"11\" r=\"8\"></circle>\r\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"></line>\r\n </svg>\r\n <input\r\n #searchInput\r\n type=\"text\"\r\n class=\"hierarchical-search-input\"\r\n [value]=\"searchTerm()\"\r\n [placeholder]=\"searchPlaceholder()\"\r\n (input)=\"onSearchInput($event)\"\r\n (keydown)=\"onKeyDown($event)\"\r\n (click)=\"$event.stopPropagation()\" />\r\n </div>\r\n </div>\r\n }\r\n\r\n @if (showBack()) {\r\n <button\r\n type=\"button\"\r\n class=\"hierarchical-back\"\r\n (mousedown)=\"goBack(); $event.preventDefault(); $event.stopPropagation()\">\r\n <span>\r\n <svg width=\"6\" height=\"10\" viewBox=\"0 0 6 10\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n<path d=\"M4.59961 0.599976L0.599609 4.59998L4.59961 8.59998\" stroke=\"#141414\" stroke-width=\"1.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\r\n</svg>\r\n\r\n </span>\r\n {{ backToMainText() }}\r\n </button>\r\n }\r\n\r\n <div #optionsListContainer class=\"hierarchical-options-list\">\r\n @for (item of filteredItems(); track getValue(item)) {\r\n <div\r\n #optionRef\r\n class=\"hierarchical-option\"\r\n [class.selected]=\"isSelected(item)\"\r\n [class.marked]=\"$index === markedIndex()\"\r\n [class.disabled-item]=\"item.disabled\"\r\n [class.cursor-not-allowed]=\"item.disabled\"\r\n (mouseenter)=\"markOption($index)\"\r\n (mousedown)=\"selectItem(item, $event)\">\r\n <!-- Grouped so the row's justify-between still has exactly two\r\n children (body + trailing chevron/tick). -->\r\n <div class=\"hierarchical-option-body\">\r\n @if (allowParentSelection()) {\r\n @if (hasChildren(item)) {\r\n <!-- Only nodes with children get a box \u2014 a leaf is already\r\n selected by clicking its row. It owns its own mousedown so\r\n the row still navigates; the box itself is inert\r\n (pointer-events-none) so it can't toggle twice. standalone\r\n keeps this ngModel out of any parent <form> the select is\r\n rendered inside. -->\r\n <span\r\n class=\"hierarchical-option-checkbox\"\r\n role=\"button\"\r\n [attr.aria-label]=\"'Select ' + getLabel(item)\"\r\n (mousedown)=\"toggleParentSelection(item, $event)\">\r\n <bk-checkbox\r\n class=\"pointer-events-none shrink-0 flex\"\r\n checkboxClass=\"sm\"\r\n [disabled]=\"!!item.disabled\"\r\n [ngModel]=\"isSelected(item)\"\r\n [ngModelOptions]=\"{ standalone: true }\"\r\n ></bk-checkbox>\r\n </span>\r\n } @else {\r\n <!-- Holds the checkbox column open so leaf labels line up with\r\n the parents' above them. -->\r\n <span class=\"hierarchical-option-checkbox-spacer\" aria-hidden=\"true\"></span>\r\n }\r\n }\r\n @if (showDots() && accentFor(item)) {\r\n <span class=\"hierarchical-dot\" [style.backgroundColor]=\"accentFor(item)\"></span>\r\n }\r\n <span\r\n #optLabel\r\n class=\"hierarchical-option-label\"\r\n [style.color]=\"optionTextColor(item)\"\r\n [bkTooltip]=\"optLabel.scrollWidth > optLabel.clientWidth ? getLabel(item) : ''\"\r\n bkTooltipPosition=\"top\">{{ getLabel(item) }}</span>\r\n </div>\r\n @if (hasChildren(item)) {\r\n <svg width=\"5\" height=\"8\" viewBox=\"0 0 5 8\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path d=\"M4.57142 4.00286C4.57185 3.92766 4.55744 3.85312 4.52901 3.78351C4.50057 3.71389 4.45868 3.65058 4.40572 3.59719L0.977497 0.169008C0.924381 0.115455 0.861186 0.0729493 0.79156 0.0439419C0.721933 0.0149346 0.647251 0 0.571824 0C0.496396 0 0.421714 0.0149346 0.352088 0.0439419C0.282461 0.0729493 0.219267 0.115455 0.16615 0.169008C0.059732 0.27606 0 0.420874 0 0.57182C0 0.722766 0.059732 0.867579 0.16615 0.974631L3.19442 4.00286L0.16615 7.02537C0.059732 7.13242 0 7.27723 0 7.42818C0 7.57913 0.059732 7.72394 0.16615 7.83099C0.219267 7.88454 0.282461 7.92705 0.352088 7.95606C0.421714 7.98507 0.496396 8 0.571824 8C0.647251 8 0.721933 7.98507 0.79156 7.95606C0.861186 7.92705 0.924381 7.88454 0.977497 7.83099L4.40572 4.40281C4.51128 4.29639 4.57079 4.15275 4.57142 4.00286Z\" fill=\"#BBBDC5\"/>\r\n </svg>\r\n } @else if (isSelected(item)) {\r\n <svg width=\"10\" height=\"7\" viewBox=\"0 0 10 7\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path d=\"M3.72939 6.28273C3.64166 6.28324 3.55468 6.26642 3.47346 6.23324C3.39223 6.20007 3.31835 6.15118 3.25606 6.08939L0.196061 3.00273C0.0705253 2.87719 -1.32274e-09 2.70693 0 2.52939C1.32273e-09 2.35186 0.0705253 2.1816 0.196061 2.05606C0.321597 1.93053 0.49186 1.86 0.669394 1.86C0.846929 1.86 1.01719 1.93053 1.14273 2.05606L3.72939 4.64939L8.17606 0.196061C8.3016 0.0705253 8.47186 -3.49963e-09 8.64939 0C8.82693 3.49963e-09 8.99719 0.0705253 9.12273 0.196061C9.24826 0.321597 9.31879 0.49186 9.31879 0.669395C9.31879 0.846929 9.24826 1.01719 9.12273 1.14273L4.20273 6.06273C4.07921 6.19434 3.90963 6.27316 3.72939 6.28273V6.28273Z\" fill=\"#141414\"/>\r\n </svg>\r\n }\r\n </div>\r\n }\r\n @if (filteredItems().length === 0) {\r\n <div class=\"hierarchical-option-empty\">No records found</div>\r\n }\r\n </div>\r\n </div>\r\n </ng-template>\r\n </div>\r\n</div>\r\n", styles: [".hierarchical-select-container{@apply relative w-full box-border;}.hierarchical-select-field{@apply relative w-full;}.hierarchical-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-2.5 cursor-pointer;}.hierarchical-select-control.focused{@apply border-[#6B7080] shadow-none z-10;}.hierarchical-select-control.disabled{@apply cursor-not-allowed;background-color:#f4f4f6!important;border-color:#e3e3e7!important;color:#a1a3ae!important}.hierarchical-select-control.disabled .hierarchical-placeholder{@apply text-gray-400;}.hierarchical-value-container{@apply flex flex-1 items-center flex-wrap gap-1 relative overflow-hidden h-full min-w-0;}.hierarchical-placeholder{@apply text-[#6B7080] font-normal text-sm truncate w-full pointer-events-none;}.hierarchical-value-row{@apply flex items-center gap-1.5 w-full min-w-0;}.hierarchical-value-label{@apply font-normal text-sm leading-[18px] text-[#141414] truncate w-full flex items-center;}.hierarchical-dot{@apply inline-block w-2 h-2 rounded-full shrink-0;}.hierarchical-option-body{@apply flex items-center gap-2 min-w-0 flex-1;}.hierarchical-actions{@apply flex items-center gap-2 flex-shrink-0;}.hierarchical-clear-wrapper{@apply text-gray-400 hover:text-red-500 cursor-pointer;}.hierarchical-arrow{@apply flex-shrink-0 text-gray-400 transition-transform duration-200;}.hierarchical-arrow.open{@apply rotate-180;}.hierarchical-dropdown-panel{@apply static left-auto w-full min-w-[250px] max-w-full bg-white border border-[#E3E3E7] rounded-xl shadow-lg overflow-hidden cursor-default p-2.5;}.hierarchical-search{@apply px-2 pt-2;}.hierarchical-search-wrapper{@apply flex items-center border border-[#E3E3E7] rounded-md px-3 py-[7px] bg-white transition-colors focus-within:border-[#E3E3E7];}.hierarchical-search-input{@apply w-full outline-none font-normal text-sm text-[#141414] placeholder-[#A1A3AE] bg-transparent;}.hierarchical-back{@apply w-full text-left px-2.5 py-2 text-sm text-[#141414] bg-[#F8F8F8] rounded-md transition-colors mt-1 flex items-center gap-1.5;}.hierarchical-options-list{@apply overflow-auto relative flex flex-col gap-0.5 mt-1;}@media (max-height: 700px){.hierarchical-options-list{max-height:124px}}@media (min-height: 701px) and (max-height: 900px){.hierarchical-options-list{max-height:164px}}@media (min-height: 901px){.hierarchical-options-list{max-height:204px}}.hierarchical-option{@apply flex items-center justify-between gap-2 p-2.5 cursor-pointer transition-colors font-normal text-sm text-[#141414] rounded-md;}.hierarchical-option.disabled-item{@apply opacity-50 cursor-not-allowed;}.hierarchical-option.disabled-item:hover{@apply bg-transparent;}.hierarchical-option:hover,.hierarchical-option.marked{@apply bg-[#F1F1F3];}.hierarchical-option.marked.disabled-item{@apply bg-transparent;}.hierarchical-option.selected{@apply bg-[#F8F8F8];}.hierarchical-option.selected:hover,.hierarchical-option.selected.marked{@apply bg-[#F1F1F3];}.hierarchical-option.selected.disabled-item{@apply bg-transparent;}.hierarchical-option-label{@apply flex-1 truncate;}.hierarchical-option-chevron{@apply flex-shrink-0 text-[#6B7080];}.hierarchical-option-check{@apply flex-shrink-0 text-[#141414];}.hierarchical-option-checkbox{@apply flex-shrink-0 flex items-center cursor-pointer;}.hierarchical-option-checkbox-spacer{@apply flex-shrink-0 w-4;}.hierarchical-option-empty{@apply px-3 py-2 text-gray-400 cursor-default text-sm;}.input-label{@apply text-sm font-medium text-[#141414] tracking-[-.28px] mb-1.5 inline-block;}.input-label-required{@apply text-[#E7000B];}.hierarchical-options-list::-webkit-scrollbar{width:6px}.hierarchical-options-list::-webkit-scrollbar-track{background:transparent;border-radius:8px;width:8px}.hierarchical-options-list::-webkit-scrollbar-thumb{background:#d6d7dc;border-radius:8px;transition:.3s ease-in-out}.hierarchical-options-list::-webkit-scrollbar-thumb:hover{background:#909090}.hierarchical-breadcrumb-node{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.breadcrumb-separator{margin:0 6px;flex-shrink:0}.hierarchical-select-control.hierarchical-select-control-has-error{border-color:#d11e14!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: BKTooltipDirective, selector: "[bkTooltip]", inputs: ["bkTooltip", "bkTooltipPosition", "bkTooltipScrollable", "bkTooltipMaxHeight", "bkTooltipSize", "bkTooltipAutoHeight"] }, { kind: "component", type: BkCheckbox, selector: "bk-checkbox", inputs: ["checkboxClass", "label", "labelClass", "disabled"], outputs: ["change"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i3.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i3.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }] });
10384
+ ], viewQueries: [{ propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true }, { propertyName: "controlWrapper", first: true, predicate: ["controlWrapper"], descendants: true }, { propertyName: "dropdownPanel", first: true, predicate: ["dropdownPanel"], descendants: true }, { propertyName: "optionsListContainer", first: true, predicate: ["optionsListContainer"], descendants: true }, { propertyName: "hierarchicalOverlay", first: true, predicate: ["hierarchicalOverlay"], descendants: true }, { propertyName: "optionEls", predicate: ["optionRef"], descendants: true }], ngImport: i0, template: "<div class=\"hierarchical-select-container\">\r\n @if (label()) {\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\r\n <div class=\"hierarchical-select-field\">\r\n <!-- With showDots on, the control is tinted by the selected node's accent.\r\n An errored control drops the tint entirely and goes neutral, so the red\r\n border reads as an error rather than competing with the accent. -->\r\n <div\r\n #controlWrapper\r\n cdkOverlayOrigin\r\n #hierarchicalOrigin=\"cdkOverlayOrigin\"\r\n class=\"hierarchical-select-control\"\r\n [ngClass]=\"{ 'hierarchical-select-control-has-error': hasError() }\"\r\n tabindex=\"0\"\r\n [class.focused]=\"isOpen()\"\r\n [class.disabled]=\"isDisabled()\"\r\n [class.filled]=\"!hasError() && !!controlAppearance().backgroundColor\"\r\n [style.backgroundColor]=\"hasError() ? null : controlAppearance().backgroundColor\"\r\n [style.color]=\"hasError() ? null : controlAppearance().color\"\r\n [style.borderColor]=\"hasError() ? null : controlAppearance().borderColor\"\r\n (keydown)=\"onKeyDown($event)\"\r\n (mousedown)=\"toggleDropdown($event)\">\r\n @if (iconSrc()) {\r\n <img [src]=\"iconSrc()\" [alt]=\"iconAlt()\" class=\"shrink-0\" />\r\n }\r\n <div class=\"hierarchical-value-container\">\r\n @if (!selected()) {\r\n <div class=\"hierarchical-placeholder\">{{ placeholder() }}</div>\r\n } @else {\r\n <!-- Single row: the container is flex-wrap and the label is w-full, so\r\n a bare sibling dot would push the label onto a second line. -->\r\n <div class=\"hierarchical-value-row\">\r\n @if (showDots() && accentFor(selected()!)) {\r\n <span class=\"hierarchical-dot\" [style.backgroundColor]=\"accentFor(selected()!)\"></span>\r\n }\r\n <div class=\"hierarchical-value-label\" [style.color]=\"controlAppearance().color ?? resolveColor(selected())\">\r\n @for (node of displayPath(); track getValue(node); let last = $last) {\r\n <span\r\n #breadNode\r\n class=\"hierarchical-breadcrumb-node\"\r\n [bkTooltip]=\"breadNode.scrollWidth > breadNode.clientWidth ? getLabel(node) : ''\"\r\n bkTooltipPosition=\"top\">{{ getLabel(node) }}</span>\r\n\r\n @if (!last) {\r\n <svg\r\n class=\"breadcrumb-separator\"\r\n width=\"5\"\r\n height=\"8\"\r\n viewBox=\"0 0 5 8\"\r\n fill=\"none\"\r\n xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n d=\"M4.57142 4.00286C4.57185 3.92766 4.55744 3.85312 4.52901 3.78351C4.50057 3.71389 4.45868 3.65058 4.40572 3.59719L0.977497 0.169008C0.924381 0.115455 0.861186 0.0729493 0.79156 0.0439419C0.721933 0.0149346 0.647251 0 0.571824 0C0.496396 0 0.421714 0.0149346 0.352088 0.0439419C0.282461 0.0729493 0.219267 0.115455 0.16615 0.169008C0.059732 0.27606 0 0.420874 0 0.57182C0 0.722766 0.059732 0.867579 0.16615 0.974631L3.19442 4.00286L0.16615 7.02537C0.059732 7.13242 0 7.27723 0 7.42818C0 7.57913 0.059732 7.72394 0.16615 7.83099C0.219267 7.88454 0.282461 7.92705 0.352088 7.95606C0.421714 7.98507 0.496396 8 0.571824 8C0.647251 8 0.721933 7.98507 0.79156 7.95606C0.861186 7.92705 0.924381 7.88454 0.977497 7.83099L4.40572 4.40281C4.51128 4.29639 4.57079 4.15275 4.57142 4.00286Z\"\r\n fill=\"#BBBDC5\"/>\r\n </svg>\r\n }\r\n }\r\n </div>\r\n </div>\r\n\r\n }\r\n </div>\r\n <div class=\"hierarchical-actions\">\r\n @if (clearable() && selected() && !isDisabled()) {\r\n <span class=\"hierarchical-clear-wrapper\" (mousedown)=\"handleClear($event)\" title=\"Clear\" [bkTooltip]=\"clearTooltip()\" bkTooltipPosition=\"top\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\"\r\n stroke=\"currentColor\" stroke-width=\"2\" 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 </span>\r\n }\r\n <span class=\"hierarchical-arrow\" [class.open]=\"isOpen()\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\"\r\n stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"m6 9 6 6 6-6\"/>\r\n </svg>\r\n </span>\r\n </div>\r\n </div>\r\n\r\n <!--\r\n CDK connected overlay: portals the panel into the shared cdk-overlay-container instead of\r\n an inline `position:absolute`/`fixed` div, so it escapes clipping inside dialogs/scroll\r\n containers and stacks correctly above other CDK-overlay content, regardless of the old\r\n appendToBody flag (see its @deprecated note). No backdrop \u2014 see onOverlayOutsideClick.\r\n -->\r\n <ng-template\r\n cdkConnectedOverlay\r\n #hierarchicalOverlay=\"cdkConnectedOverlay\"\r\n [cdkConnectedOverlayOrigin]=\"hierarchicalOrigin\"\r\n [cdkConnectedOverlayOpen]=\"isOpen()\"\r\n [cdkConnectedOverlayPositions]=\"hierarchicalDropdownPositions\"\r\n [cdkConnectedOverlayWidth]=\"dropdownWidth() ?? ''\"\r\n [cdkConnectedOverlayFlexibleDimensions]=\"false\"\r\n (positionChange)=\"onPositionChange($event)\"\r\n (overlayOutsideClick)=\"onOverlayOutsideClick()\"\r\n (detach)=\"closeDropdown()\"\r\n >\r\n <div\r\n #dropdownPanel\r\n class=\"hierarchical-dropdown-panel\"\r\n [style.visibility]=\"panelReady() ? 'visible' : 'hidden'\"\r\n [attr.data-position]=\"placement()\">\r\n @if (searchable()) {\r\n <div class=\"hierarchical-search\">\r\n <div class=\"hierarchical-search-wrapper\">\r\n <svg class=\"text-[#BBBDC5] mr-2\" xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\"\r\n viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\">\r\n <circle cx=\"11\" cy=\"11\" r=\"8\"></circle>\r\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"></line>\r\n </svg>\r\n <input\r\n #searchInput\r\n type=\"text\"\r\n class=\"hierarchical-search-input\"\r\n [value]=\"searchTerm()\"\r\n [placeholder]=\"searchPlaceholder()\"\r\n (input)=\"onSearchInput($event)\"\r\n (keydown)=\"onKeyDown($event)\"\r\n (click)=\"$event.stopPropagation()\" />\r\n </div>\r\n </div>\r\n }\r\n\r\n @if (showBack()) {\r\n <button\r\n type=\"button\"\r\n class=\"hierarchical-back\"\r\n (mousedown)=\"goBack(); $event.preventDefault(); $event.stopPropagation()\">\r\n <span>\r\n <svg width=\"6\" height=\"10\" viewBox=\"0 0 6 10\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n<path d=\"M4.59961 0.599976L0.599609 4.59998L4.59961 8.59998\" stroke=\"#141414\" stroke-width=\"1.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\r\n</svg>\r\n\r\n </span>\r\n {{ backToMainText() }}\r\n </button>\r\n }\r\n\r\n <div #optionsListContainer class=\"hierarchical-options-list\">\r\n @for (item of filteredItems(); track getValue(item)) {\r\n <div\r\n #optionRef\r\n class=\"hierarchical-option\"\r\n [class.selected]=\"isSelected(item)\"\r\n [class.marked]=\"$index === markedIndex()\"\r\n [class.disabled-item]=\"item.disabled\"\r\n [class.cursor-not-allowed]=\"item.disabled\"\r\n (mouseenter)=\"markOption($index)\"\r\n (mousedown)=\"selectItem(item, $event)\">\r\n <!-- Grouped so the row's justify-between still has exactly two\r\n children (body + trailing chevron/tick). -->\r\n <div class=\"hierarchical-option-body\">\r\n @if (allowParentSelection()) {\r\n @if (hasChildren(item)) {\r\n <!-- Only nodes with children get a box \u2014 a leaf is already\r\n selected by clicking its row. It owns its own mousedown so\r\n the row still navigates; the box itself is inert\r\n (pointer-events-none) so it can't toggle twice. standalone\r\n keeps this ngModel out of any parent <form> the select is\r\n rendered inside. -->\r\n <span\r\n class=\"hierarchical-option-checkbox\"\r\n role=\"button\"\r\n [attr.aria-label]=\"'Select ' + getLabel(item)\"\r\n (mousedown)=\"toggleParentSelection(item, $event)\">\r\n <bk-checkbox\r\n class=\"pointer-events-none shrink-0 flex\"\r\n checkboxClass=\"sm\"\r\n [disabled]=\"!!item.disabled\"\r\n [ngModel]=\"isSelected(item)\"\r\n [ngModelOptions]=\"{ standalone: true }\"\r\n ></bk-checkbox>\r\n </span>\r\n } @else {\r\n <!-- Holds the checkbox column open so leaf labels line up with\r\n the parents' above them. -->\r\n <span class=\"hierarchical-option-checkbox-spacer\" aria-hidden=\"true\"></span>\r\n }\r\n }\r\n @if (showDots() && accentFor(item)) {\r\n <span class=\"hierarchical-dot\" [style.backgroundColor]=\"accentFor(item)\"></span>\r\n }\r\n <span\r\n #optLabel\r\n class=\"hierarchical-option-label\"\r\n [style.color]=\"optionTextColor(item)\"\r\n [bkTooltip]=\"optLabel.scrollWidth > optLabel.clientWidth ? getLabel(item) : ''\"\r\n bkTooltipPosition=\"top\">{{ getLabel(item) }}</span>\r\n </div>\r\n @if (hasChildren(item)) {\r\n <svg width=\"5\" height=\"8\" viewBox=\"0 0 5 8\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path d=\"M4.57142 4.00286C4.57185 3.92766 4.55744 3.85312 4.52901 3.78351C4.50057 3.71389 4.45868 3.65058 4.40572 3.59719L0.977497 0.169008C0.924381 0.115455 0.861186 0.0729493 0.79156 0.0439419C0.721933 0.0149346 0.647251 0 0.571824 0C0.496396 0 0.421714 0.0149346 0.352088 0.0439419C0.282461 0.0729493 0.219267 0.115455 0.16615 0.169008C0.059732 0.27606 0 0.420874 0 0.57182C0 0.722766 0.059732 0.867579 0.16615 0.974631L3.19442 4.00286L0.16615 7.02537C0.059732 7.13242 0 7.27723 0 7.42818C0 7.57913 0.059732 7.72394 0.16615 7.83099C0.219267 7.88454 0.282461 7.92705 0.352088 7.95606C0.421714 7.98507 0.496396 8 0.571824 8C0.647251 8 0.721933 7.98507 0.79156 7.95606C0.861186 7.92705 0.924381 7.88454 0.977497 7.83099L4.40572 4.40281C4.51128 4.29639 4.57079 4.15275 4.57142 4.00286Z\" fill=\"#BBBDC5\"/>\r\n </svg>\r\n } @else if (isSelected(item)) {\r\n <svg width=\"10\" height=\"7\" viewBox=\"0 0 10 7\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path d=\"M3.72939 6.28273C3.64166 6.28324 3.55468 6.26642 3.47346 6.23324C3.39223 6.20007 3.31835 6.15118 3.25606 6.08939L0.196061 3.00273C0.0705253 2.87719 -1.32274e-09 2.70693 0 2.52939C1.32273e-09 2.35186 0.0705253 2.1816 0.196061 2.05606C0.321597 1.93053 0.49186 1.86 0.669394 1.86C0.846929 1.86 1.01719 1.93053 1.14273 2.05606L3.72939 4.64939L8.17606 0.196061C8.3016 0.0705253 8.47186 -3.49963e-09 8.64939 0C8.82693 3.49963e-09 8.99719 0.0705253 9.12273 0.196061C9.24826 0.321597 9.31879 0.49186 9.31879 0.669395C9.31879 0.846929 9.24826 1.01719 9.12273 1.14273L4.20273 6.06273C4.07921 6.19434 3.90963 6.27316 3.72939 6.28273V6.28273Z\" fill=\"#141414\"/>\r\n </svg>\r\n }\r\n </div>\r\n }\r\n @if (filteredItems().length === 0) {\r\n <div class=\"hierarchical-option-empty\">No records found</div>\r\n }\r\n </div>\r\n </div>\r\n </ng-template>\r\n </div>\r\n</div>\r\n", styles: [".hierarchical-select-container{@apply relative w-full box-border;}.hierarchical-select-field{@apply relative w-full;}.hierarchical-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-2.5 cursor-pointer;}.hierarchical-select-control.focused{@apply border-[#6B7080] shadow-none z-10;}.hierarchical-select-control.disabled{@apply cursor-not-allowed;background-color:#f4f4f6!important;border-color:#e3e3e7!important;color:#a1a3ae!important}.hierarchical-select-control.disabled .hierarchical-placeholder{@apply text-gray-400;}.hierarchical-value-container{@apply flex flex-1 items-center flex-wrap gap-1 relative overflow-hidden h-full min-w-0;}.hierarchical-placeholder{@apply text-[#6B7080] font-normal text-sm truncate w-full pointer-events-none;}.hierarchical-value-row{@apply flex items-center gap-1.5 w-full min-w-0;}.hierarchical-value-label{@apply font-normal text-sm leading-[18px] text-[#141414] truncate w-full flex items-center;}.hierarchical-dot{@apply inline-block w-2 h-2 rounded-full shrink-0;}.hierarchical-option-body{@apply flex items-center gap-2 min-w-0 flex-1;}.hierarchical-actions{@apply flex items-center gap-2 flex-shrink-0;}.hierarchical-clear-wrapper{@apply text-gray-400 hover:text-red-500 cursor-pointer;}.hierarchical-arrow{@apply flex-shrink-0 text-gray-400 transition-transform duration-200;}.hierarchical-arrow.open{@apply rotate-180;}.hierarchical-dropdown-panel{@apply static left-auto w-full min-w-[250px] max-w-full bg-white border border-[#E3E3E7] rounded-xl shadow-lg overflow-hidden cursor-default p-2.5;}.hierarchical-search{@apply px-2 pt-2;}.hierarchical-search-wrapper{@apply flex items-center border border-[#E3E3E7] rounded-md px-3 py-[7px] bg-white transition-colors focus-within:border-[#E3E3E7];}.hierarchical-search-input{@apply w-full outline-none font-normal text-sm text-[#141414] placeholder-[#A1A3AE] bg-transparent;}.hierarchical-back{@apply w-full text-left px-2.5 py-2 text-sm text-[#141414] bg-[#F8F8F8] rounded-md transition-colors mt-1 flex items-center gap-1.5;}.hierarchical-options-list{@apply overflow-auto relative flex flex-col gap-0.5 mt-1;}@media (max-height: 700px){.hierarchical-options-list{max-height:124px}}@media (min-height: 701px) and (max-height: 900px){.hierarchical-options-list{max-height:164px}}@media (min-height: 901px){.hierarchical-options-list{max-height:204px}}.hierarchical-option{@apply flex items-center justify-between gap-2 p-2.5 cursor-pointer transition-colors font-normal text-sm text-[#141414] rounded-md;}.hierarchical-option.disabled-item{@apply opacity-50 cursor-not-allowed;}.hierarchical-option.disabled-item:hover{@apply bg-transparent;}.hierarchical-option:hover,.hierarchical-option.marked{@apply bg-[#F1F1F3];}.hierarchical-option.marked.disabled-item{@apply bg-transparent;}.hierarchical-option.selected{@apply bg-[#F8F8F8];}.hierarchical-option.selected:hover,.hierarchical-option.selected.marked{@apply bg-[#F1F1F3];}.hierarchical-option.selected.disabled-item{@apply bg-transparent;}.hierarchical-option-label{@apply flex-1 truncate;}.hierarchical-option-chevron{@apply flex-shrink-0 text-[#6B7080];}.hierarchical-option-check{@apply flex-shrink-0 text-[#141414];}.hierarchical-option-checkbox{@apply flex-shrink-0 flex items-center cursor-pointer;}.hierarchical-option-checkbox-spacer{@apply flex-shrink-0 w-4;}.hierarchical-option-empty{@apply px-3 py-2 text-gray-400 cursor-default text-sm;}.input-label{@apply text-sm font-medium text-[#141414] tracking-[-.28px] mb-1.5 inline-block;}.input-label-required{@apply text-[#E7000B];}.hierarchical-options-list::-webkit-scrollbar{width:6px}.hierarchical-options-list::-webkit-scrollbar-track{background:transparent;border-radius:8px;width:8px}.hierarchical-options-list::-webkit-scrollbar-thumb{background:#d6d7dc;border-radius:8px;transition:.3s ease-in-out}.hierarchical-options-list::-webkit-scrollbar-thumb:hover{background:#909090}.hierarchical-breadcrumb-node{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.breadcrumb-separator{margin:0 6px;flex-shrink:0}.hierarchical-select-control.hierarchical-select-control-has-error{border-color:#d11e14!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: BKTooltipDirective, selector: "[bkTooltip]", inputs: ["bkTooltip", "bkTooltipPosition", "bkTooltipScrollable", "bkTooltipMaxHeight", "bkTooltipSize", "bkTooltipAutoHeight"] }, { kind: "component", type: BkCheckbox, selector: "bk-checkbox", inputs: ["checkboxClass", "label", "labelClass", "disabled"], outputs: ["change"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i2.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i2.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }] });
9428
10385
  }
9429
10386
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkHierarchicalSelect, decorators: [{
9430
10387
  type: Component,
@@ -9823,7 +10780,7 @@ class BkColumnSelect {
9823
10780
  useExisting: forwardRef(() => BkColumnSelect),
9824
10781
  multi: true,
9825
10782
  },
9826
- ], viewQueries: [{ propertyName: "formBoxRef", first: true, predicate: ["formBox"], descendants: true }, { propertyName: "triggerRef", first: true, predicate: ["trigger"], descendants: true, read: ElementRef }], usesOnChanges: true, ngImport: i0, template: "<div class=\"relative\">\r\n\r\n <bk-button #trigger [size]=\"'xsm'\" [variant]=\"'secondary'\" [leftIcon]=\"lefticon\"\r\n (click)=\"filterButtonClicked($event)\" [label]=\"label\" [buttonClass]=\"`text-black ${buttonClass}`\"></bk-button>\r\n\r\n <!-- Dropdown Box -->\r\n @if(isOpened){\r\n\r\n <div #formBox\r\n class=\"absolute {{ panelPositionClass }} w-[178px] bg-white border border-[#EFEFF1] rounded-xl shadow-xl z-[9999]\">\r\n @if(searchable){\r\n <div class=\"px-3 py-1\">\r\n <bk-input [id]=\"'search-input-1'\" [name]=\"'search-input-1'\" [size]=\"'sm'\"\r\n [iconSrc]=\"'../../../../assets/icons/search-input.svg'\" type=\"text\" [(ngModel)]=\"search\"\r\n placeholder=\"Search\"></bk-input>\r\n </div>\r\n }\r\n <div class=\"column-select-options-list\">\r\n @for (column of list; track column.columnName; let i = $index) {\r\n <div class=\"flex items-center gap-2 px-3 py-1 hover:bg-gray-100 cursor-pointer\">\r\n <bk-checkbox [label]=\"column.columnName\" id=\"columnsFilterList-{{column.columnName}}\" checkboxClass=\"sm\" [(ngModel)]=\"column.selected\" labelClass=\"!text-left\"\r\n (change)=\"onChangeColumnFilter()\">\r\n\r\n </bk-checkbox>\r\n\r\n <!-- <label class=\"text-xs cursor-pointer text-[#141414] select-none truncate font-medium\"\r\n for=\"columnsFilterList-{{column.columnName}}\">\r\n {{column.columnName}}\r\n </label> -->\r\n\r\n </div>\r\n }\r\n @if(!list.length){\r\n <p class=\"column-select-option-empty\">No records found</p>\r\n }\r\n </div>\r\n </div>\r\n }\r\n</div>\r\n", styles: [".column-select-option-empty{@apply px-3 py-2 text-gray-400 cursor-default text-sm;}.column-select-options-list{display:flex;flex-direction:column;overflow-y:auto;max-height:225px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: BkButton, selector: "bk-button", inputs: ["variant", "size", "shadow", "label", "leftIcon", "rightIcon", "iconAlt", "type", "loading", "disabled", "buttonClass", "textClass", "spinnerClass"], outputs: ["clicked"] }, { kind: "component", type: BkCheckbox, selector: "bk-checkbox", inputs: ["checkboxClass", "label", "labelClass", "disabled"], outputs: ["change"] }, { kind: "component", type: BkInput, selector: "bk-input", inputs: ["id", "name", "mask", "dropSpecialCharacters", "autoComplete", "label", "placeholder", "hint", "required", "type", "size", "value", "hasError", "showErrorIcon", "errorMessage", "disabled", "tabIndex", "readOnly", "autoCapitalize", "inputMode", "iconSrc", "iconAlt", "showIcon", "phone", "currency", "currencyDecimals", "allowNegative", "countryCode", "countryOptions", "iconOrientation", "password", "showPassword", "pattern", "max", "min", "step", "maxlength", "minlength"], outputs: ["input", "change", "focus", "blur", "clicked"] }] });
10783
+ ], viewQueries: [{ propertyName: "formBoxRef", first: true, predicate: ["formBox"], descendants: true }, { propertyName: "triggerRef", first: true, predicate: ["trigger"], descendants: true, read: ElementRef }], usesOnChanges: true, ngImport: i0, template: "<div class=\"relative\">\r\n\r\n <bk-button #trigger [size]=\"'xsm'\" [variant]=\"'secondary'\" [leftIcon]=\"lefticon\"\r\n (click)=\"filterButtonClicked($event)\" [label]=\"label\" [buttonClass]=\"`text-black ${buttonClass}`\"></bk-button>\r\n\r\n <!-- Dropdown Box -->\r\n @if(isOpened){\r\n\r\n <div #formBox\r\n class=\"absolute {{ panelPositionClass }} w-[178px] bg-white border border-[#EFEFF1] rounded-xl shadow-xl z-[9999]\">\r\n @if(searchable){\r\n <div class=\"px-3 py-1\">\r\n <bk-input [id]=\"'search-input-1'\" [name]=\"'search-input-1'\" [size]=\"'sm'\"\r\n [iconSrc]=\"'../../../../assets/icons/search-input.svg'\" type=\"text\" [(ngModel)]=\"search\"\r\n placeholder=\"Search\"></bk-input>\r\n </div>\r\n }\r\n <div class=\"column-select-options-list\">\r\n @for (column of list; track column.columnName; let i = $index) {\r\n <div class=\"flex items-center gap-2 px-3 py-1 hover:bg-gray-100 cursor-pointer\">\r\n <bk-checkbox [label]=\"column.columnName\" id=\"columnsFilterList-{{column.columnName}}\" checkboxClass=\"sm\" [(ngModel)]=\"column.selected\" labelClass=\"!text-left\"\r\n (change)=\"onChangeColumnFilter()\">\r\n\r\n </bk-checkbox>\r\n\r\n <!-- <label class=\"text-xs cursor-pointer text-[#141414] select-none truncate font-medium\"\r\n for=\"columnsFilterList-{{column.columnName}}\">\r\n {{column.columnName}}\r\n </label> -->\r\n\r\n </div>\r\n }\r\n @if(!list.length){\r\n <p class=\"column-select-option-empty\">No records found</p>\r\n }\r\n </div>\r\n </div>\r\n }\r\n</div>\r\n", styles: [".column-select-option-empty{@apply px-3 py-2 text-gray-400 cursor-default text-sm;}.column-select-options-list{display:flex;flex-direction:column;overflow-y:auto;max-height:225px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: BkButton, selector: "bk-button", inputs: ["variant", "size", "shadow", "label", "leftIcon", "rightIcon", "iconAlt", "type", "loading", "disabled", "buttonClass", "textClass", "spinnerClass"], outputs: ["clicked"] }, { kind: "component", type: BkCheckbox, selector: "bk-checkbox", inputs: ["checkboxClass", "label", "labelClass", "disabled"], outputs: ["change"] }, { kind: "component", type: BkInput, selector: "bk-input", inputs: ["id", "name", "mask", "dropSpecialCharacters", "autoComplete", "label", "placeholder", "hint", "required", "type", "size", "value", "hasError", "showErrorIcon", "errorMessage", "disabled", "tabIndex", "readOnly", "autoCapitalize", "inputMode", "iconSrc", "iconAlt", "showIcon", "phone", "currency", "currencyDecimals", "allowNegative", "countryCode", "countryOptions", "iconOrientation", "password", "showPassword", "pattern", "max", "min", "step", "maxlength", "minlength"], outputs: ["input", "change", "focus", "blur", "clicked"] }] });
9827
10784
  }
9828
10785
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkColumnSelect, decorators: [{
9829
10786
  type: Component,
@@ -10268,7 +11225,7 @@ class BkPagination {
10268
11225
  return this.getPageCount();
10269
11226
  }
10270
11227
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkPagination, deps: [], target: i0.ɵɵFactoryTarget.Component });
10271
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkPagination, isStandalone: true, selector: "bk-pagination", inputs: { pageSize: "pageSize", total: "total", activePage: "activePage", showPageSize: "showPageSize", showRecordsText: "showRecordsText", showPageCount: "showPageCount", customClass: "customClass" }, outputs: { changePageSize: "changePageSize", pageChanged: "pageChanged", activePageChange: "activePageChange" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"md:px-4 px-2 md:py-3 py-2 border-t border-[#EBEDF3] rounded-b-xl\">\r\n <div class=\"flex flex-row items-center justify-between md:gap-3 gap-1 {{ customClass }}\">\r\n\r\n <!-- Page size dropdown -->\r\n\r\n @if (!pageSizeHidden) {\r\n <div class=\"flex gap-3 items-center pagination\">\r\n @if (showPageSizeLabel) {\r\n <p class=\"text-xs text-[#141414] font-medium md:block hidden\">Rows per page</p>\r\n }\r\n @if (showPageSizeInput) {\r\n <bk-select\r\n [items]=\"pageSizesList\"\r\n [searchable]=\"false\"\r\n bindLabel=\"key\"\r\n bindValue=\"value\"\r\n [clearable]=\"false\"\r\n [(ngModel)]=\"pageSize\"\r\n [dropdownPosition]=\"'top'\"\r\n (change)=\"changeSize($event)\"\r\n [variation]=\"'sm'\"\r\n [isResponsive]=\"false\"\r\n class=\"!min-w-[90px] lg:!min-w-[131px]\"\r\n >\r\n </bk-select>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- showing entries -->\r\n @if (showRecordsText) {\r\n <p class=\"text-xs text-[#141414] font-medium md:block hidden\">\r\n Showing <span>{{ startIndex }}</span> to\r\n <span>{{ endIndex > totalItems ? totalItems : endIndex }}</span> of\r\n <span>{{ totalItems }}</span> Records\r\n </p>\r\n }\r\n\r\n <!-- Pagination main -->\r\n <!-- With 2+ top-level blocks visible, the parent row's justify-between already\r\n pins this to the end on its own; customClass on the row (e.g. \"justify-end\")\r\n controls arrangement among those blocks.\r\n Hidden down to just this one, there's nothing left for the row to distribute\r\n against, so it grows to fill the row (flex-1) instead \u2014 letting customClass\r\n act here on its own two children (page count text vs. the page-number list)\r\n via e.g. \"justify-between\" or \"justify-around\". -->\r\n <nav\r\n class=\"flex gap-1.5 items-center {{ customClass }}\"\r\n [class.flex-1]=\"pageSizeHidden && !showRecordsText\"\r\n >\r\n\r\n @if (showPageCount) {\r\n <!-- Page count -->\r\n <p class=\"text-xs text-[#141414] font-medium md:block hidden\">\r\n <span>{{ startingPage || 0 }}</span> -\r\n <span>{{ endingPage || 0 }}</span> of\r\n <span>{{ getTotalPages() || 0 }}</span>\r\n </p>\r\n\r\n\r\n <!-- Page count mobile version -->\r\n <p class=\"text-xs text-[#141414] font-medium md:hidden block\">\r\n <span>{{ startingPage || 0 }}</span> -\r\n <span>{{ endingPage || 0 }}</span> of\r\n <span>{{ getTotalPages() || 0 }}</span>\r\n </p>\r\n }\r\n\r\n <ul class=\"flex items-center space-x-1 text-[13px] text-[#B9BBC6]\">\r\n\r\n <!-- Previous -->\r\n <li class=\"md:block hidden\">\r\n <a\r\n href=\"javascript:void(0)\"\r\n (click)=\"onClickPage(1)\"\r\n class=\"flex items-center justify-center md:size-7 size-6 text-[13px] leading-6 text-[#15191E] rounded-md hover:bg-[#F8F8FA]\"\r\n [ngClass]=\"{'cursor-not-allowed': activePage === 1}\"\r\n >\r\n @if(activePage === 1){\r\n <img\r\n src=\"../../assets/icons/arrow-left-double-gray.svg\"\r\n alt=\"Left Arrow Disabled\"\r\n />\r\n }\r\n @if(activePage !== 1){\r\n <img\r\n src=\"../../assets/icons/arrow-left-double-black.svg\"\r\n alt=\"Left Arrow\"\r\n />\r\n }\r\n </a>\r\n </li>\r\n <!-- Previous -->\r\n <li>\r\n <a\r\n href=\"javascript:void(0)\"\r\n (click)=\"onClickPage(activePage - 1)\"\r\n class=\"flex items-center justify-center md:size-7 size-6 text-[13px] leading-6 text-[#15191E] rounded-md hover:bg-[#F8F8FA]\"\r\n [ngClass]=\"{'cursor-not-allowed': activePage === 1}\"\r\n >\r\n @if(activePage === 1){\r\n <img\r\n src=\"../../assets/icons/pagination-left-gray.svg\"\r\n alt=\"Left Arrow Disabled\"\r\n />\r\n }\r\n @if(activePage !== 1){\r\n <img\r\n src=\"../../assets/icons/pagination-left-black.svg\"\r\n alt=\"Left Arrow\"\r\n />\r\n }\r\n </a>\r\n </li>\r\n\r\n <!-- Page Numbers -->\r\n <li *ngFor=\"let item of paginate()\">\r\n <a\r\n (click)=\"onClickPage(item)\"\r\n href=\"javascript:void(0)\"\r\n class=\"flex items-center justify-center md:size-7 size-6 leading-6 rounded-lg\"\r\n [ngClass]=\"item === activePage\r\n ? 'text-[#15191E] bg-[#F8F8FA] hover:bg-[#F8F8FA]'\r\n : 'hover:bg-[#F8F8FA] hover:text-[#15191E]'\">\r\n {{ item }}\r\n </a>\r\n </li>\r\n\r\n <!-- Next -->\r\n <li>\r\n <a\r\n href=\"javascript:void(0)\"\r\n (click)=\"onClickPage(activePage + 1)\"\r\n class=\"flex items-center justify-center md:size-7 size-6 text-[13px] leading-6 text-[#15191E] rounded-md hover:bg-[#F8F8FA]\"\r\n [ngClass]=\"{'cursor-not-allowed': activePage === getTotalPages()}\"\r\n >\r\n @if(activePage === getTotalPages()){\r\n <img\r\n src=\"../../assets/icons/pagination-right-gray.svg\"\r\n alt=\"Right Arrow Disabled\"\r\n />\r\n }\r\n @if(activePage !== getTotalPages()){\r\n <img\r\n src=\"../../assets/icons/pagination-right-black.svg\"\r\n alt=\"Right Arrow\"\r\n />\r\n }\r\n </a>\r\n </li>\r\n <!-- next double arrow -->\r\n <li class=\"md:block hidden\">\r\n <a\r\n href=\"javascript:void(0)\"\r\n (click)=\"onClickPage(getTotalPages())\"\r\n class=\"flex items-center justify-center md:size-7 size-6 text-[13px] leading-6 text-[#15191E] rounded-md hover:bg-[#F8F8FA]\"\r\n [ngClass]=\"{'cursor-not-allowed': activePage === getTotalPages()}\"\r\n >\r\n @if(activePage === getTotalPages()){\r\n <img\r\n src=\"../../assets/icons/arrow-right-double-gray.svg\"\r\n alt=\"Right Arrow Disabled\"\r\n />\r\n }\r\n @if(activePage !== getTotalPages()){\r\n <img\r\n src=\"../../assets/icons/arrow-right-double-black.svg\"\r\n alt=\"Right Arrow\"\r\n />\r\n }\r\n </a>\r\n </li>\r\n </ul>\r\n </nav>\r\n </div>\r\n</div>\r\n", styles: [""], 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: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: BkSelect, selector: "bk-select", inputs: ["items", "bindLabel", "bindValue", "bindIcon", "isResponsive", "placeholder", "notFoundText", "loadingText", "clearAllText", "groupBy", "colorKey", "dropdownView", "gridColumns", "gridVariation", "gridSelectionActions", "gridMinWidth", "gridMaxHeight", "gridSelectedLabelKeys", "gridSelectedLabelSeparator", "gridApplyText", "gridClearText", "showDots", "showAvatar", "avatarKey", "iconAlt", "label", "required", "variation", "iconSrc", "multiple", "maxLabels", "searchable", "allSelect", "clearable", "readonly", "disabled", "loading", "closeOnSelect", "openOnFocus", "dropdownPosition", "hasError", "errorMessage", "appendToBody", "compareWith"], outputs: ["disabledChange", "open", "close", "focus", "blur", "search", "clear", "change", "scrollToEnd"] }] });
11228
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkPagination, isStandalone: true, selector: "bk-pagination", inputs: { pageSize: "pageSize", total: "total", activePage: "activePage", showPageSize: "showPageSize", showRecordsText: "showRecordsText", showPageCount: "showPageCount", customClass: "customClass" }, outputs: { changePageSize: "changePageSize", pageChanged: "pageChanged", activePageChange: "activePageChange" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"md:px-4 px-2 md:py-3 py-2 border-t border-[#EBEDF3] rounded-b-xl\">\r\n <div class=\"flex flex-row items-center justify-between md:gap-3 gap-1 {{ customClass }}\">\r\n\r\n <!-- Page size dropdown -->\r\n\r\n @if (!pageSizeHidden) {\r\n <div class=\"flex gap-3 items-center pagination\">\r\n @if (showPageSizeLabel) {\r\n <p class=\"text-xs text-[#141414] font-medium md:block hidden\">Rows per page</p>\r\n }\r\n @if (showPageSizeInput) {\r\n <bk-select\r\n [items]=\"pageSizesList\"\r\n [searchable]=\"false\"\r\n bindLabel=\"key\"\r\n bindValue=\"value\"\r\n [clearable]=\"false\"\r\n [(ngModel)]=\"pageSize\"\r\n [dropdownPosition]=\"'top'\"\r\n (change)=\"changeSize($event)\"\r\n [variation]=\"'sm'\"\r\n [isResponsive]=\"false\"\r\n class=\"!min-w-[90px] lg:!min-w-[131px]\"\r\n >\r\n </bk-select>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- showing entries -->\r\n @if (showRecordsText) {\r\n <p class=\"text-xs text-[#141414] font-medium md:block hidden\">\r\n Showing <span>{{ startIndex }}</span> to\r\n <span>{{ endIndex > totalItems ? totalItems : endIndex }}</span> of\r\n <span>{{ totalItems }}</span> Records\r\n </p>\r\n }\r\n\r\n <!-- Pagination main -->\r\n <!-- With 2+ top-level blocks visible, the parent row's justify-between already\r\n pins this to the end on its own; customClass on the row (e.g. \"justify-end\")\r\n controls arrangement among those blocks.\r\n Hidden down to just this one, there's nothing left for the row to distribute\r\n against, so it grows to fill the row (flex-1) instead \u2014 letting customClass\r\n act here on its own two children (page count text vs. the page-number list)\r\n via e.g. \"justify-between\" or \"justify-around\". -->\r\n <nav\r\n class=\"flex gap-1.5 items-center {{ customClass }}\"\r\n [class.flex-1]=\"pageSizeHidden && !showRecordsText\"\r\n >\r\n\r\n @if (showPageCount) {\r\n <!-- Page count -->\r\n <p class=\"text-xs text-[#141414] font-medium md:block hidden\">\r\n <span>{{ startingPage || 0 }}</span> -\r\n <span>{{ endingPage || 0 }}</span> of\r\n <span>{{ getTotalPages() || 0 }}</span>\r\n </p>\r\n\r\n\r\n <!-- Page count mobile version -->\r\n <p class=\"text-xs text-[#141414] font-medium md:hidden block\">\r\n <span>{{ startingPage || 0 }}</span> -\r\n <span>{{ endingPage || 0 }}</span> of\r\n <span>{{ getTotalPages() || 0 }}</span>\r\n </p>\r\n }\r\n\r\n <ul class=\"flex items-center space-x-1 text-[13px] text-[#B9BBC6]\">\r\n\r\n <!-- Previous -->\r\n <li class=\"md:block hidden\">\r\n <a\r\n href=\"javascript:void(0)\"\r\n (click)=\"onClickPage(1)\"\r\n class=\"flex items-center justify-center md:size-7 size-6 text-[13px] leading-6 text-[#15191E] rounded-md hover:bg-[#F8F8FA]\"\r\n [ngClass]=\"{'cursor-not-allowed': activePage === 1}\"\r\n >\r\n @if(activePage === 1){\r\n <img\r\n src=\"../../assets/icons/arrow-left-double-gray.svg\"\r\n alt=\"Left Arrow Disabled\"\r\n />\r\n }\r\n @if(activePage !== 1){\r\n <img\r\n src=\"../../assets/icons/arrow-left-double-black.svg\"\r\n alt=\"Left Arrow\"\r\n />\r\n }\r\n </a>\r\n </li>\r\n <!-- Previous -->\r\n <li>\r\n <a\r\n href=\"javascript:void(0)\"\r\n (click)=\"onClickPage(activePage - 1)\"\r\n class=\"flex items-center justify-center md:size-7 size-6 text-[13px] leading-6 text-[#15191E] rounded-md hover:bg-[#F8F8FA]\"\r\n [ngClass]=\"{'cursor-not-allowed': activePage === 1}\"\r\n >\r\n @if(activePage === 1){\r\n <img\r\n src=\"../../assets/icons/pagination-left-gray.svg\"\r\n alt=\"Left Arrow Disabled\"\r\n />\r\n }\r\n @if(activePage !== 1){\r\n <img\r\n src=\"../../assets/icons/pagination-left-black.svg\"\r\n alt=\"Left Arrow\"\r\n />\r\n }\r\n </a>\r\n </li>\r\n\r\n <!-- Page Numbers -->\r\n <li *ngFor=\"let item of paginate()\">\r\n <a\r\n (click)=\"onClickPage(item)\"\r\n href=\"javascript:void(0)\"\r\n class=\"flex items-center justify-center md:size-7 size-6 leading-6 rounded-lg\"\r\n [ngClass]=\"item === activePage\r\n ? 'text-[#15191E] bg-[#F8F8FA] hover:bg-[#F8F8FA]'\r\n : 'hover:bg-[#F8F8FA] hover:text-[#15191E]'\">\r\n {{ item }}\r\n </a>\r\n </li>\r\n\r\n <!-- Next -->\r\n <li>\r\n <a\r\n href=\"javascript:void(0)\"\r\n (click)=\"onClickPage(activePage + 1)\"\r\n class=\"flex items-center justify-center md:size-7 size-6 text-[13px] leading-6 text-[#15191E] rounded-md hover:bg-[#F8F8FA]\"\r\n [ngClass]=\"{'cursor-not-allowed': activePage === getTotalPages()}\"\r\n >\r\n @if(activePage === getTotalPages()){\r\n <img\r\n src=\"../../assets/icons/pagination-right-gray.svg\"\r\n alt=\"Right Arrow Disabled\"\r\n />\r\n }\r\n @if(activePage !== getTotalPages()){\r\n <img\r\n src=\"../../assets/icons/pagination-right-black.svg\"\r\n alt=\"Right Arrow\"\r\n />\r\n }\r\n </a>\r\n </li>\r\n <!-- next double arrow -->\r\n <li class=\"md:block hidden\">\r\n <a\r\n href=\"javascript:void(0)\"\r\n (click)=\"onClickPage(getTotalPages())\"\r\n class=\"flex items-center justify-center md:size-7 size-6 text-[13px] leading-6 text-[#15191E] rounded-md hover:bg-[#F8F8FA]\"\r\n [ngClass]=\"{'cursor-not-allowed': activePage === getTotalPages()}\"\r\n >\r\n @if(activePage === getTotalPages()){\r\n <img\r\n src=\"../../assets/icons/arrow-right-double-gray.svg\"\r\n alt=\"Right Arrow Disabled\"\r\n />\r\n }\r\n @if(activePage !== getTotalPages()){\r\n <img\r\n src=\"../../assets/icons/arrow-right-double-black.svg\"\r\n alt=\"Right Arrow\"\r\n />\r\n }\r\n </a>\r\n </li>\r\n </ul>\r\n </nav>\r\n </div>\r\n</div>\r\n", styles: [""], 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: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: BkSelect, selector: "bk-select", inputs: ["items", "bindLabel", "bindValue", "bindIcon", "isResponsive", "placeholder", "notFoundText", "loadingText", "clearAllText", "groupBy", "colorKey", "dropdownView", "gridColumns", "gridVariation", "gridSelectionActions", "gridMinWidth", "gridMaxHeight", "gridSelectedLabelKeys", "gridSelectedLabelSeparator", "gridApplyText", "gridClearText", "showDots", "showAvatar", "avatarKey", "iconAlt", "label", "required", "variation", "iconSrc", "multiple", "maxLabels", "searchable", "allSelect", "clearable", "readonly", "disabled", "loading", "closeOnSelect", "openOnFocus", "dropdownPosition", "hasError", "errorMessage", "appendToBody", "compareWith"], outputs: ["disabledChange", "open", "close", "focus", "blur", "search", "clear", "change", "scrollToEnd"] }] });
10272
11229
  }
10273
11230
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkPagination, decorators: [{
10274
11231
  type: Component,
@@ -11383,7 +12340,7 @@ class BkPopover {
11383
12340
  this.cancelClose();
11384
12341
  }
11385
12342
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkPopover, deps: [], target: i0.ɵɵFactoryTarget.Component });
11386
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkPopover, isStandalone: true, selector: "bk-popover", inputs: { placement: { classPropertyName: "placement", publicName: "placement", isSignal: true, isRequired: false, transformFunction: null }, trigger: { classPropertyName: "trigger", publicName: "trigger", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, closable: { classPropertyName: "closable", publicName: "closable", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, showArrow: { classPropertyName: "showArrow", publicName: "showArrow", isSignal: true, isRequired: false, transformFunction: null }, offset: { classPropertyName: "offset", publicName: "offset", isSignal: true, isRequired: false, transformFunction: null }, flip: { classPropertyName: "flip", publicName: "flip", isSignal: true, isRequired: false, transformFunction: null }, closeOnClickOutside: { classPropertyName: "closeOnClickOutside", publicName: "closeOnClickOutside", isSignal: true, isRequired: false, transformFunction: null }, closeOnEscape: { classPropertyName: "closeOnEscape", publicName: "closeOnEscape", isSignal: true, isRequired: false, transformFunction: null }, openDelay: { classPropertyName: "openDelay", publicName: "openDelay", isSignal: true, isRequired: false, transformFunction: null }, closeDelay: { classPropertyName: "closeDelay", publicName: "closeDelay", isSignal: true, isRequired: false, transformFunction: null }, maxWidth: { classPropertyName: "maxWidth", publicName: "maxWidth", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, panelClass: { classPropertyName: "panelClass", publicName: "panelClass", isSignal: true, isRequired: false, transformFunction: null }, appendToBody: { classPropertyName: "appendToBody", publicName: "appendToBody", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { opened: "opened", closed: "closed", openChange: "openChange" }, host: { listeners: { "document:keydown.escape": "onEscape()" }, properties: { "attr.title": "null" } }, viewQueries: [{ propertyName: "anchorRef", first: true, predicate: ["anchor"], descendants: true }, { propertyName: "panelRef", first: true, predicate: ["panel"], descendants: true }, { propertyName: "popoverOverlay", first: true, predicate: ["popoverOverlay"], descendants: true }], exportAs: ["bkPopover"], ngImport: i0, template: "<!-- The anchor wraps the projected trigger so the popover has an element to\r\n measure and to listen on, whatever the consumer passes in. -->\r\n<span\r\n #anchor\r\n cdkOverlayOrigin\r\n #popoverOrigin=\"cdkOverlayOrigin\"\r\n class=\"bk-popover-anchor\"\r\n (click)=\"onAnchorClick()\"\r\n (mouseenter)=\"onAnchorEnter()\"\r\n (mouseleave)=\"onAnchorLeave()\"\r\n>\r\n <ng-content select=\"[bkPopoverTrigger]\"></ng-content>\r\n</span>\r\n\r\n<!--\r\n CDK connected overlay: portals the panel into the shared cdk-overlay-container instead of an\r\n inline `position:fixed` div, so it escapes clipping inside dialogs/scroll containers and\r\n stacks correctly above other CDK-overlay content, regardless of the old appendToBody flag (see\r\n its @deprecated note). No backdrop \u2014 see onOverlayOutsideClick.\r\n-->\r\n<ng-template\r\n cdkConnectedOverlay\r\n #popoverOverlay=\"cdkConnectedOverlay\"\r\n [cdkConnectedOverlayOrigin]=\"popoverOrigin\"\r\n [cdkConnectedOverlayOpen]=\"isOpen()\"\r\n [cdkConnectedOverlayPositions]=\"popoverPositions\"\r\n [cdkConnectedOverlayFlexibleDimensions]=\"false\"\r\n (positionChange)=\"onPositionChange($event)\"\r\n (overlayOutsideClick)=\"onOverlayOutsideClick()\"\r\n (detach)=\"close()\"\r\n>\r\n <!-- Hidden until panelReady(): the first frame exists only so CDK/we can measure it, and\r\n painting it at its initial position first flashes it in the corner. -->\r\n <div\r\n #panel\r\n class=\"bk-popover-panel\"\r\n [ngClass]=\"panelClass()\"\r\n role=\"dialog\"\r\n [attr.data-side]=\"side()\"\r\n [style.width]=\"width()\"\r\n [style.maxWidth]=\"effectiveMaxWidth()\"\r\n [class.bk-popover-ready]=\"panelReady()\"\r\n (mouseenter)=\"onPanelEnter()\"\r\n (mouseleave)=\"onPanelLeave()\"\r\n >\r\n @if (showArrow()) {\r\n <!-- A rotated square, not a border triangle: it inherits the panel's\r\n background and border, so the tip matches the panel on every side.\r\n Sits above the panel's own border, hiding the segment it crosses. -->\r\n <span\r\n class=\"bk-popover-arrow\"\r\n [style.left.px]=\"arrowLeft()\"\r\n [style.top.px]=\"arrowTop()\"\r\n ></span>\r\n }\r\n\r\n @if (title()) {\r\n <div class=\"bk-popover-header\">\r\n <span class=\"bk-popover-title\">{{ title() }}</span>\r\n @if (closable()) {\r\n <button type=\"button\" class=\"bk-popover-close\" aria-label=\"Close\" (click)=\"close()\">\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"14\"\r\n height=\"14\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n >\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 </div>\r\n }\r\n\r\n <div class=\"bk-popover-body\">\r\n <ng-content></ng-content>\r\n </div>\r\n </div>\r\n</ng-template>\r\n", styles: [":host{@apply inline-flex;}.bk-popover-anchor{@apply inline-flex;}.bk-popover-panel{@apply static z-[10000] bg-white border border-[#E3E3E7] rounded-lg p-3 cursor-default;box-shadow:0 12px 24px -6px #1018281f,0 4px 8px -4px #1018280f;visibility:hidden;opacity:0}.bk-popover-panel.bk-popover-ready{visibility:visible;opacity:1;transition:opacity .12s ease-out}.bk-popover-arrow{@apply absolute block w-2.5 h-2.5 bg-white border border-[#E3E3E7];}.bk-popover-panel[data-side=top] .bk-popover-arrow{bottom:-5px;border-top:none;border-left:none;transform:translate(-50%) rotate(45deg)}.bk-popover-panel[data-side=bottom] .bk-popover-arrow{top:-5px;border-bottom:none;border-right:none;transform:translate(-50%) rotate(45deg)}.bk-popover-panel[data-side=left] .bk-popover-arrow{right:-5px;border-bottom:none;border-left:none;transform:translateY(-50%) rotate(45deg)}.bk-popover-panel[data-side=right] .bk-popover-arrow{left:-5px;border-top:none;border-right:none;transform:translateY(-50%) rotate(45deg)}.bk-popover-header{@apply flex items-start justify-between gap-3 mb-1;}.bk-popover-title{@apply text-sm font-semibold text-[#141414];}.bk-popover-close{@apply shrink-0 text-gray-400 hover:text-[#141414] cursor-pointer -me-1 -mt-0.5;}.bk-popover-body{@apply text-sm font-normal text-[#6B7080];}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i3.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i3.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }] });
12343
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkPopover, isStandalone: true, selector: "bk-popover", inputs: { placement: { classPropertyName: "placement", publicName: "placement", isSignal: true, isRequired: false, transformFunction: null }, trigger: { classPropertyName: "trigger", publicName: "trigger", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, closable: { classPropertyName: "closable", publicName: "closable", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, showArrow: { classPropertyName: "showArrow", publicName: "showArrow", isSignal: true, isRequired: false, transformFunction: null }, offset: { classPropertyName: "offset", publicName: "offset", isSignal: true, isRequired: false, transformFunction: null }, flip: { classPropertyName: "flip", publicName: "flip", isSignal: true, isRequired: false, transformFunction: null }, closeOnClickOutside: { classPropertyName: "closeOnClickOutside", publicName: "closeOnClickOutside", isSignal: true, isRequired: false, transformFunction: null }, closeOnEscape: { classPropertyName: "closeOnEscape", publicName: "closeOnEscape", isSignal: true, isRequired: false, transformFunction: null }, openDelay: { classPropertyName: "openDelay", publicName: "openDelay", isSignal: true, isRequired: false, transformFunction: null }, closeDelay: { classPropertyName: "closeDelay", publicName: "closeDelay", isSignal: true, isRequired: false, transformFunction: null }, maxWidth: { classPropertyName: "maxWidth", publicName: "maxWidth", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, panelClass: { classPropertyName: "panelClass", publicName: "panelClass", isSignal: true, isRequired: false, transformFunction: null }, appendToBody: { classPropertyName: "appendToBody", publicName: "appendToBody", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { opened: "opened", closed: "closed", openChange: "openChange" }, host: { listeners: { "document:keydown.escape": "onEscape()" }, properties: { "attr.title": "null" } }, viewQueries: [{ propertyName: "anchorRef", first: true, predicate: ["anchor"], descendants: true }, { propertyName: "panelRef", first: true, predicate: ["panel"], descendants: true }, { propertyName: "popoverOverlay", first: true, predicate: ["popoverOverlay"], descendants: true }], exportAs: ["bkPopover"], ngImport: i0, template: "<!-- The anchor wraps the projected trigger so the popover has an element to\r\n measure and to listen on, whatever the consumer passes in. -->\r\n<span\r\n #anchor\r\n cdkOverlayOrigin\r\n #popoverOrigin=\"cdkOverlayOrigin\"\r\n class=\"bk-popover-anchor\"\r\n (click)=\"onAnchorClick()\"\r\n (mouseenter)=\"onAnchorEnter()\"\r\n (mouseleave)=\"onAnchorLeave()\"\r\n>\r\n <ng-content select=\"[bkPopoverTrigger]\"></ng-content>\r\n</span>\r\n\r\n<!--\r\n CDK connected overlay: portals the panel into the shared cdk-overlay-container instead of an\r\n inline `position:fixed` div, so it escapes clipping inside dialogs/scroll containers and\r\n stacks correctly above other CDK-overlay content, regardless of the old appendToBody flag (see\r\n its @deprecated note). No backdrop \u2014 see onOverlayOutsideClick.\r\n-->\r\n<ng-template\r\n cdkConnectedOverlay\r\n #popoverOverlay=\"cdkConnectedOverlay\"\r\n [cdkConnectedOverlayOrigin]=\"popoverOrigin\"\r\n [cdkConnectedOverlayOpen]=\"isOpen()\"\r\n [cdkConnectedOverlayPositions]=\"popoverPositions\"\r\n [cdkConnectedOverlayFlexibleDimensions]=\"false\"\r\n (positionChange)=\"onPositionChange($event)\"\r\n (overlayOutsideClick)=\"onOverlayOutsideClick()\"\r\n (detach)=\"close()\"\r\n>\r\n <!-- Hidden until panelReady(): the first frame exists only so CDK/we can measure it, and\r\n painting it at its initial position first flashes it in the corner. -->\r\n <div\r\n #panel\r\n class=\"bk-popover-panel\"\r\n [ngClass]=\"panelClass()\"\r\n role=\"dialog\"\r\n [attr.data-side]=\"side()\"\r\n [style.width]=\"width()\"\r\n [style.maxWidth]=\"effectiveMaxWidth()\"\r\n [class.bk-popover-ready]=\"panelReady()\"\r\n (mouseenter)=\"onPanelEnter()\"\r\n (mouseleave)=\"onPanelLeave()\"\r\n >\r\n @if (showArrow()) {\r\n <!-- A rotated square, not a border triangle: it inherits the panel's\r\n background and border, so the tip matches the panel on every side.\r\n Sits above the panel's own border, hiding the segment it crosses. -->\r\n <span\r\n class=\"bk-popover-arrow\"\r\n [style.left.px]=\"arrowLeft()\"\r\n [style.top.px]=\"arrowTop()\"\r\n ></span>\r\n }\r\n\r\n @if (title()) {\r\n <div class=\"bk-popover-header\">\r\n <span class=\"bk-popover-title\">{{ title() }}</span>\r\n @if (closable()) {\r\n <button type=\"button\" class=\"bk-popover-close\" aria-label=\"Close\" (click)=\"close()\">\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"14\"\r\n height=\"14\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n >\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 </div>\r\n }\r\n\r\n <div class=\"bk-popover-body\">\r\n <ng-content></ng-content>\r\n </div>\r\n </div>\r\n</ng-template>\r\n", styles: [":host{@apply inline-flex;}.bk-popover-anchor{@apply inline-flex;}.bk-popover-panel{@apply static z-[10000] bg-white border border-[#E3E3E7] rounded-lg p-3 cursor-default;box-shadow:0 12px 24px -6px #1018281f,0 4px 8px -4px #1018280f;visibility:hidden;opacity:0}.bk-popover-panel.bk-popover-ready{visibility:visible;opacity:1;transition:opacity .12s ease-out}.bk-popover-arrow{@apply absolute block w-2.5 h-2.5 bg-white border border-[#E3E3E7];}.bk-popover-panel[data-side=top] .bk-popover-arrow{bottom:-5px;border-top:none;border-left:none;transform:translate(-50%) rotate(45deg)}.bk-popover-panel[data-side=bottom] .bk-popover-arrow{top:-5px;border-bottom:none;border-right:none;transform:translate(-50%) rotate(45deg)}.bk-popover-panel[data-side=left] .bk-popover-arrow{right:-5px;border-bottom:none;border-left:none;transform:translateY(-50%) rotate(45deg)}.bk-popover-panel[data-side=right] .bk-popover-arrow{left:-5px;border-top:none;border-right:none;transform:translateY(-50%) rotate(45deg)}.bk-popover-header{@apply flex items-start justify-between gap-3 mb-1;}.bk-popover-title{@apply text-sm font-semibold text-[#141414];}.bk-popover-close{@apply shrink-0 text-gray-400 hover:text-[#141414] cursor-pointer -me-1 -mt-0.5;}.bk-popover-body{@apply text-sm font-normal text-[#6B7080];}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i2.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i2.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }] });
11387
12344
  }
11388
12345
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkPopover, decorators: [{
11389
12346
  type: Component,
@@ -12138,7 +13095,7 @@ class BkTable {
12138
13095
  });
12139
13096
  }
12140
13097
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTable, deps: [], target: i0.ɵɵFactoryTarget.Component });
12141
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkTable, isStandalone: true, selector: "bk-table", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, bordered: { classPropertyName: "bordered", publicName: "bordered", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, footer: { classPropertyName: "footer", publicName: "footer", isSignal: true, isRequired: false, transformFunction: null }, scroll: { classPropertyName: "scroll", publicName: "scroll", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, showLoadingOverlay: { classPropertyName: "showLoadingOverlay", publicName: "showLoadingOverlay", isSignal: true, isRequired: false, transformFunction: null }, noResult: { classPropertyName: "noResult", publicName: "noResult", isSignal: true, isRequired: false, transformFunction: null }, showPagination: { classPropertyName: "showPagination", publicName: "showPagination", isSignal: true, isRequired: false, transformFunction: null }, frontPagination: { classPropertyName: "frontPagination", publicName: "frontPagination", isSignal: true, isRequired: false, transformFunction: null }, pageIndex: { classPropertyName: "pageIndex", publicName: "pageIndex", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, total: { classPropertyName: "total", publicName: "total", isSignal: true, isRequired: false, transformFunction: null }, virtualItemSize: { classPropertyName: "virtualItemSize", publicName: "virtualItemSize", isSignal: true, isRequired: false, transformFunction: null }, virtualTrackBy: { classPropertyName: "virtualTrackBy", publicName: "virtualTrackBy", isSignal: true, isRequired: false, transformFunction: null }, stableColumnWidth: { classPropertyName: "stableColumnWidth", publicName: "stableColumnWidth", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { pageIndex: "pageIndexChange", pageSize: "pageSizeChange", queryParams: "queryParams", currentPageDataChange: "currentPageDataChange" }, host: { classAttribute: "bk-table-host" }, queries: [{ propertyName: "titleContent", first: true, predicate: BkTableTitle, descendants: true }, { propertyName: "footerContent", first: true, predicate: BkTableFooter, descendants: true }, { propertyName: "virtualScroll", first: true, predicate: BkVirtualScroll, descendants: true }], viewQueries: [{ propertyName: "viewport", first: true, predicate: CdkVirtualScrollViewport, descendants: true }, { propertyName: "virtualHead", first: true, predicate: ["virtualHead"], descendants: true }], exportAs: ["bkTable"], ngImport: i0, template: "<!--\r\n Projection slots live inside <ng-template> rather than directly in the\r\n branches below. A given <ng-content> can only be declared once \u00E2\u20AC\u201D repeating\r\n the same selector in both the virtual and normal branches would leave one of\r\n them permanently empty. Wrapping each slot in a template declares it once and\r\n lets an outlet place it wherever it is needed.\r\n-->\r\n<ng-template #headSlot><ng-content select=\"thead\"></ng-content></ng-template>\r\n<ng-template #bodySlot><ng-content select=\"tbody\"></ng-content></ng-template>\r\n<ng-template #footSlot><ng-content select=\"tfoot\"></ng-content></ng-template>\r\n\r\n<div\r\n class=\"bk-table-wrapper\"\r\n [class.bk-table-bordered]=\"bordered()\"\r\n [ngClass]=\"sizeClass()\"\r\n>\r\n <!--\r\n The frame is one box, and it is the only box that draws an outline or a\r\n corner. Radius on the header cells and border on the table (or on the title\r\n bar) means two boxes describing the same corner from different places, and\r\n they disagree the moment a title bar appears above the header. Everything\r\n inside here draws separators only; `overflow: hidden` clips them to the curve.\r\n -->\r\n <div class=\"bk-table-frame\">\r\n @if (hasTitle()) {\r\n <div class=\"bk-table-title-bar\">\r\n @if (title()) {\r\n {{ title() }}\r\n }\r\n <ng-content select=\"[bkTableTitle]\"></ng-content>\r\n </div>\r\n }\r\n\r\n <div class=\"bk-table-container\" [ngStyle]=\"containerStyle()\">\r\n @if (isVirtual() && virtualScroll) {\r\n <!--\r\n Header and body are two separate tables here, which they are not in any\r\n other mode. The CDK viewport scrolls by translating its content wrapper,\r\n and a transformed ancestor takes over as the containing block for\r\n sticky descendants \u00E2\u20AC\u201D so a header inside the viewport gets dragged along\r\n by the very transform it is supposed to stay still against. Lifting it\r\n out is the only way it stays put.\r\n\r\n The cost is that the two tables can no longer size each other, so a\r\n shared <colgroup> holds their columns in alignment and the body's\r\n horizontal scroll is mirrored onto the header by hand.\r\n -->\r\n <div #virtualHead class=\"bk-table-virtual-head\">\r\n <table class=\"bk-table\" [ngStyle]=\"tableStyle()\">\r\n <colgroup>\r\n @for (width of colWidths(); track $index) {\r\n <col [style.width]=\"width\" />\r\n }\r\n </colgroup>\r\n <ng-container [ngTemplateOutlet]=\"headSlot\"></ng-container>\r\n </table>\r\n </div>\r\n\r\n <cdk-virtual-scroll-viewport\r\n class=\"bk-table-viewport\"\r\n [itemSize]=\"virtualItemSize()\"\r\n [style.height]=\"scroll().y || '400px'\"\r\n (scroll)=\"onViewportScroll($event)\"\r\n >\r\n <table class=\"bk-table\" [ngStyle]=\"tableStyle()\">\r\n <colgroup>\r\n @for (width of colWidths(); track $index) {\r\n <col [style.width]=\"width\" />\r\n }\r\n </colgroup>\r\n <tbody>\r\n <ng-container\r\n *cdkVirtualFor=\"\r\n let row of renderData();\r\n let i = index;\r\n trackBy: virtualTrackBy()\r\n \"\r\n [ngTemplateOutlet]=\"virtualScroll.templateRef\"\r\n [ngTemplateOutletContext]=\"{ $implicit: row, index: i }\"\r\n ></ng-container>\r\n </tbody>\r\n <ng-container [ngTemplateOutlet]=\"footSlot\"></ng-container>\r\n </table>\r\n </cdk-virtual-scroll-viewport>\r\n } @else {\r\n <table class=\"bk-table\" [ngStyle]=\"tableStyle()\">\r\n <ng-container [ngTemplateOutlet]=\"headSlot\"></ng-container>\r\n <ng-container [ngTemplateOutlet]=\"bodySlot\"></ng-container>\r\n <ng-container [ngTemplateOutlet]=\"footSlot\"></ng-container>\r\n </table>\r\n }\r\n\r\n @if (loading() && showLoadingOverlay()) {\r\n <div class=\"bk-table-loading\">\r\n <span class=\"bk-table-spinner\"></span>\r\n </div>\r\n }\r\n\r\n @if (isEmpty()) {\r\n <div class=\"bk-table-empty\">\r\n @if (!emptyImageFailed()) {\r\n <img\r\n [src]=\"noResultImage()\"\r\n class=\"bk-table-empty-img\"\r\n alt=\"No data found\"\r\n (error)=\"onEmptyImageError()\"\r\n />\r\n }\r\n <span class=\"bk-table-empty-text\">{{ noResultText() }}</span>\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (hasFooter()) {\r\n <div class=\"bk-table-footer-bar\">\r\n @if (footer()) {\r\n {{ footer() }}\r\n }\r\n <ng-content select=\"[bkTableFooter]\"></ng-content>\r\n </div>\r\n }\r\n\r\n <!-- Inside the frame: the pager belongs to the table it drives, and the\r\n frame's bottom edge is what closes the card around both.\r\n\r\n `!isEmpty()`, not `totalCount() > 0`: in server mode `totalCount()`\r\n is just the `total` input, which can say more rows exist than are\r\n actually on screen right now (a search with no matches but a stale\r\n total, a page past the end) \u2014 the pager has nothing to page through\r\n either way, so it goes by what's actually rendered. -->\r\n @if (showPagination() && !isEmpty()) {\r\n <div class=\"bk-table-pagination\">\r\n <bk-pagination\r\n [total]=\"totalCount()\"\r\n [pageSize]=\"pageSize()\"\r\n [activePage]=\"pageIndex()\"\r\n (pageChanged)=\"onPageIndexChange($event)\"\r\n (changePageSize)=\"onPageSizeChange($event)\"\r\n ></bk-pagination>\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n", styles: [".bk-table-host{display:block}.bk-table-wrapper{@apply w-full;}.bk-table-frame{border:1px solid #ebedf3;border-radius:.75rem;overflow:hidden}.bk-table-title-bar,.bk-table-footer-bar{@apply text-[13px] font-semibold text-[#15191E] bg-[#F9FAFA] px-4 py-2.5;}.bk-table-title-bar{border-bottom:1px solid #ebedf3}.bk-table-footer-bar{border-top:1px solid #ebedf3}.bk-table-container{@apply relative overflow-auto;}.bk-table{@apply min-w-full text-left;border-collapse:separate;border-spacing:0}.bk-th{@apply bg-[#F9FAFA] text-xs text-[#60646C] font-semibold capitalize px-[17px] py-2.5 whitespace-nowrap align-middle;border-bottom:1px solid #ebedf3;position:sticky;top:0;z-index:2}.bk-table thead tr:nth-child(2) .bk-th{top:var(--bk-thead-row-1, 38px);z-index:1}.bk-th-content{@apply flex items-center justify-between gap-1;}.bk-th-align-right .bk-th-content{@apply justify-end;}.bk-th-align-center .bk-th-content{@apply justify-center;}.bk-th-label{@apply inline-flex items-center gap-1;}.bk-th-sortable .bk-th-label{@apply cursor-pointer select-none;}.bk-th-selection{@apply flex items-center gap-1;}.bk-cell-selection{@apply px-3;}.bk-th-selection-caret{@apply inline-flex items-center justify-center size-4 rounded hover:bg-[#EFF1F4];}.bk-td{@apply text-[#15191E] text-[13px] font-medium leading-4 px-4 py-2 align-middle bg-white;border-bottom:1px solid #ebedf3}.bk-td-content{@apply inline-flex items-center gap-1 align-middle;}.bk-td-content-block{@apply block w-full;}.bk-table tbody tr:hover .bk-td{@apply bg-[#FBFBFC];}.bk-table-lg .bk-th{@apply px-5 py-3.5 text-[13px];}.bk-table-lg .bk-td{@apply px-5 py-3.5 text-sm leading-5;}.bk-table-md .bk-th{@apply px-3 py-2;}.bk-table-md .bk-td{@apply px-3 py-1.5;}.bk-table-sm .bk-th{@apply px-2 py-1.5 text-[11px];}.bk-table-sm .bk-td{@apply px-2 py-1 text-xs;}.bk-table-lg .bk-cell-selection{@apply px-4;}.bk-table-md .bk-cell-selection{@apply px-2.5;}.bk-table-sm .bk-cell-selection{@apply px-2;}.bk-table-bordered .bk-th,.bk-table-bordered .bk-td{border-right:1px solid #ebedf3}.bk-table-bordered .bk-th:last-child,.bk-table-bordered .bk-td:last-child{border-right:0}.bk-table tbody tr:last-child>.bk-td{border-bottom:0}.bk-table-underfilled .bk-table tbody tr:last-child>.bk-td{border-bottom:1px solid #ebedf3}.bk-cell-sticky{position:sticky;z-index:1}.bk-th.bk-cell-sticky{z-index:3}.bk-cell-sticky-left:after,.bk-cell-sticky-right:before{content:\"\";@apply absolute top-0 bottom-0 w-2 pointer-events-none;}.bk-cell-sticky-left:after{right:-8px;background-image:linear-gradient(to right,rgba(0,0,0,.05),transparent)}.bk-cell-sticky-right:before{left:-8px;background-image:linear-gradient(to left,rgba(0,0,0,.05),transparent)}.bk-cell-ellipsis{@apply overflow-hidden text-ellipsis whitespace-nowrap;max-width:0}.bk-td-content-ellipsis{@apply flex w-full;}.bk-td-ellipsis-text{@apply overflow-hidden text-ellipsis whitespace-nowrap min-w-0 flex-1;}.bk-cell-break-word{@apply whitespace-normal;word-break:break-all}.bk-td-indent{@apply inline-block;}.bk-td-expand,.bk-td-expand-spacer{@apply inline-flex items-center justify-center size-4 shrink-0;}.bk-td-expand{@apply rounded text-[#78829D] hover:bg-[#EFF1F4] transition-transform duration-200;transform:rotate(-90deg)}.bk-td-expand-open{transform:rotate(0)}.bk-expanded-row>.bk-td,.bk-expanded-row>td{@apply bg-[#FBFBFC];}.bk-td-flush{@apply p-3;}.bk-table-flush .bk-table-frame{border:0;border-radius:0}.bk-table-summary .bk-td{@apply bg-[#F9FAFA] font-semibold;border-top:1px solid #ebedf3;border-bottom:0}.bk-table-summary-fixed .bk-td{position:sticky;bottom:0;z-index:2}.bk-sort-icon{display:inline-flex;flex-direction:column;justify-content:center;align-items:center;height:.875rem;width:.875rem;gap:.125rem;line-height:1}.bk-sort-icon:before,.bk-sort-icon:after{display:inline-block;content:\"\";height:.3rem;width:.54rem;background-repeat:no-repeat;background-position:center;background-size:cover}.bk-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='%2378829D'/%3e%3c/svg%3e\")}.bk-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='%2378829D'/%3e%3c/svg%3e\")}.bk-sort-asc: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\")}.bk-sort-asc: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\")}.bk-sort-desc: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\")}.bk-sort-desc: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\")}.bk-sort-priority{@apply inline-flex items-center justify-center min-w-4 h-4 px-1 rounded bg-[#EFF1F4] text-[10px] font-semibold text-[#4B5675];}.bk-filter-trigger{@apply inline-flex items-center justify-center size-5 rounded text-[#78829D] hover:bg-[#EFF1F4];}.bk-filter-active{@apply text-black;}.bk-filter-menu{@apply min-w-[180px];}.bk-filter-list{@apply flex flex-col gap-2 max-h-60 overflow-y-auto py-1;}.bk-filter-option{@apply text-[13px] text-[#15191E];}.bk-filter-actions{@apply flex items-center justify-between gap-2 pt-2 mt-2;border-top:1px solid #ebedf3}.bk-filter-btn{@apply text-xs font-semibold px-2.5 py-1 rounded;}.bk-filter-btn-link{@apply text-[#60646C] hover:bg-[#F1F2F4];}.bk-filter-btn-primary{@apply bg-black text-white hover:bg-[#2A2E36];}.bk-table-menu{@apply min-w-[160px] flex flex-col;}.bk-table-menu-item{@apply w-full text-left text-[13px] text-[#15191E] px-2 py-1.5 rounded hover:bg-[#F1F2F4];}.bk-table-loading{@apply absolute inset-0 flex items-center justify-center bg-white/60 z-10;}.bk-table-spinner{@apply block size-8 rounded-full border-2 border-[#EBEDF3] border-t-black;animation:bk-table-spin .8s linear infinite}@keyframes bk-table-spin{to{transform:rotate(360deg)}}.bk-table-empty{@apply absolute inset-x-0 bottom-0 flex flex-col justify-center items-center py-10;top:var(--bk-thead-row-1, 38px)}.bk-table-empty-img{@apply mb-3 w-96 max-w-full;}.bk-table-empty-text{@apply block text-sm leading-3 text-center font-semibold text-[#60646C] mt-2;}.bk-table-pagination{@apply contents;}.bk-table-viewport{@apply w-full;}.bk-table-virtual-head{@apply w-full overflow-hidden;}.bk-table-virtual-head .bk-th{position:static}.bk-checkbox-indeterminate .checkbox{@apply bg-black border-black;}.bk-checkbox-indeterminate .checkbox:after{content:\"\";@apply absolute w-2 h-0.5 bg-white rounded-sm;}.cdk-drag-preview{display:table;table-layout:fixed;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)}.bk-drag-handle{@apply cursor-move inline-flex items-center justify-center text-[#C4CADA] hover:text-[#78829D] mr-2 align-middle;}.bk-tree-drop-line{@apply absolute pointer-events-none rounded-full;height:2px;background:#15191e;z-index:5}.bk-table tbody tr.bk-tree-drop-inside .bk-td{background:#f1f2f4;box-shadow:inset 0 0 0 1px #15191e59}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i2$2.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i2$2.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i2$2.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "component", type: BkPagination, selector: "bk-pagination", inputs: ["pageSize", "total", "activePage", "showPageSize", "showRecordsText", "showPageCount", "customClass"], outputs: ["changePageSize", "pageChanged", "activePageChange"] }], encapsulation: i0.ViewEncapsulation.None });
13098
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkTable, isStandalone: true, selector: "bk-table", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, bordered: { classPropertyName: "bordered", publicName: "bordered", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, footer: { classPropertyName: "footer", publicName: "footer", isSignal: true, isRequired: false, transformFunction: null }, scroll: { classPropertyName: "scroll", publicName: "scroll", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, showLoadingOverlay: { classPropertyName: "showLoadingOverlay", publicName: "showLoadingOverlay", isSignal: true, isRequired: false, transformFunction: null }, noResult: { classPropertyName: "noResult", publicName: "noResult", isSignal: true, isRequired: false, transformFunction: null }, showPagination: { classPropertyName: "showPagination", publicName: "showPagination", isSignal: true, isRequired: false, transformFunction: null }, frontPagination: { classPropertyName: "frontPagination", publicName: "frontPagination", isSignal: true, isRequired: false, transformFunction: null }, pageIndex: { classPropertyName: "pageIndex", publicName: "pageIndex", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, total: { classPropertyName: "total", publicName: "total", isSignal: true, isRequired: false, transformFunction: null }, virtualItemSize: { classPropertyName: "virtualItemSize", publicName: "virtualItemSize", isSignal: true, isRequired: false, transformFunction: null }, virtualTrackBy: { classPropertyName: "virtualTrackBy", publicName: "virtualTrackBy", isSignal: true, isRequired: false, transformFunction: null }, stableColumnWidth: { classPropertyName: "stableColumnWidth", publicName: "stableColumnWidth", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { pageIndex: "pageIndexChange", pageSize: "pageSizeChange", queryParams: "queryParams", currentPageDataChange: "currentPageDataChange" }, host: { classAttribute: "bk-table-host" }, queries: [{ propertyName: "titleContent", first: true, predicate: BkTableTitle, descendants: true }, { propertyName: "footerContent", first: true, predicate: BkTableFooter, descendants: true }, { propertyName: "virtualScroll", first: true, predicate: BkVirtualScroll, descendants: true }], viewQueries: [{ propertyName: "viewport", first: true, predicate: CdkVirtualScrollViewport, descendants: true }, { propertyName: "virtualHead", first: true, predicate: ["virtualHead"], descendants: true }], exportAs: ["bkTable"], ngImport: i0, template: "<!--\r\n Projection slots live inside <ng-template> rather than directly in the\r\n branches below. A given <ng-content> can only be declared once \u00E2\u20AC\u201D repeating\r\n the same selector in both the virtual and normal branches would leave one of\r\n them permanently empty. Wrapping each slot in a template declares it once and\r\n lets an outlet place it wherever it is needed.\r\n-->\r\n<ng-template #headSlot><ng-content select=\"thead\"></ng-content></ng-template>\r\n<ng-template #bodySlot><ng-content select=\"tbody\"></ng-content></ng-template>\r\n<ng-template #footSlot><ng-content select=\"tfoot\"></ng-content></ng-template>\r\n\r\n<div\r\n class=\"bk-table-wrapper\"\r\n [class.bk-table-bordered]=\"bordered()\"\r\n [ngClass]=\"sizeClass()\"\r\n>\r\n <!--\r\n The frame is one box, and it is the only box that draws an outline or a\r\n corner. Radius on the header cells and border on the table (or on the title\r\n bar) means two boxes describing the same corner from different places, and\r\n they disagree the moment a title bar appears above the header. Everything\r\n inside here draws separators only; `overflow: hidden` clips them to the curve.\r\n -->\r\n <div class=\"bk-table-frame\">\r\n @if (hasTitle()) {\r\n <div class=\"bk-table-title-bar\">\r\n @if (title()) {\r\n {{ title() }}\r\n }\r\n <ng-content select=\"[bkTableTitle]\"></ng-content>\r\n </div>\r\n }\r\n\r\n <div class=\"bk-table-container\" [ngStyle]=\"containerStyle()\">\r\n @if (isVirtual() && virtualScroll) {\r\n <!--\r\n Header and body are two separate tables here, which they are not in any\r\n other mode. The CDK viewport scrolls by translating its content wrapper,\r\n and a transformed ancestor takes over as the containing block for\r\n sticky descendants \u00E2\u20AC\u201D so a header inside the viewport gets dragged along\r\n by the very transform it is supposed to stay still against. Lifting it\r\n out is the only way it stays put.\r\n\r\n The cost is that the two tables can no longer size each other, so a\r\n shared <colgroup> holds their columns in alignment and the body's\r\n horizontal scroll is mirrored onto the header by hand.\r\n -->\r\n <div #virtualHead class=\"bk-table-virtual-head\">\r\n <table class=\"bk-table\" [ngStyle]=\"tableStyle()\">\r\n <colgroup>\r\n @for (width of colWidths(); track $index) {\r\n <col [style.width]=\"width\" />\r\n }\r\n </colgroup>\r\n <ng-container [ngTemplateOutlet]=\"headSlot\"></ng-container>\r\n </table>\r\n </div>\r\n\r\n <cdk-virtual-scroll-viewport\r\n class=\"bk-table-viewport\"\r\n [itemSize]=\"virtualItemSize()\"\r\n [style.height]=\"scroll().y || '400px'\"\r\n (scroll)=\"onViewportScroll($event)\"\r\n >\r\n <table class=\"bk-table\" [ngStyle]=\"tableStyle()\">\r\n <colgroup>\r\n @for (width of colWidths(); track $index) {\r\n <col [style.width]=\"width\" />\r\n }\r\n </colgroup>\r\n <tbody>\r\n <ng-container\r\n *cdkVirtualFor=\"\r\n let row of renderData();\r\n let i = index;\r\n trackBy: virtualTrackBy()\r\n \"\r\n [ngTemplateOutlet]=\"virtualScroll.templateRef\"\r\n [ngTemplateOutletContext]=\"{ $implicit: row, index: i }\"\r\n ></ng-container>\r\n </tbody>\r\n <ng-container [ngTemplateOutlet]=\"footSlot\"></ng-container>\r\n </table>\r\n </cdk-virtual-scroll-viewport>\r\n } @else {\r\n <table class=\"bk-table\" [ngStyle]=\"tableStyle()\">\r\n <ng-container [ngTemplateOutlet]=\"headSlot\"></ng-container>\r\n <ng-container [ngTemplateOutlet]=\"bodySlot\"></ng-container>\r\n <ng-container [ngTemplateOutlet]=\"footSlot\"></ng-container>\r\n </table>\r\n }\r\n\r\n @if (loading() && showLoadingOverlay()) {\r\n <div class=\"bk-table-loading\">\r\n <span class=\"bk-table-spinner\"></span>\r\n </div>\r\n }\r\n\r\n @if (isEmpty()) {\r\n <div class=\"bk-table-empty\">\r\n @if (!emptyImageFailed()) {\r\n <img\r\n [src]=\"noResultImage()\"\r\n class=\"bk-table-empty-img\"\r\n alt=\"No data found\"\r\n (error)=\"onEmptyImageError()\"\r\n />\r\n }\r\n <span class=\"bk-table-empty-text\">{{ noResultText() }}</span>\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (hasFooter()) {\r\n <div class=\"bk-table-footer-bar\">\r\n @if (footer()) {\r\n {{ footer() }}\r\n }\r\n <ng-content select=\"[bkTableFooter]\"></ng-content>\r\n </div>\r\n }\r\n\r\n <!-- Inside the frame: the pager belongs to the table it drives, and the\r\n frame's bottom edge is what closes the card around both.\r\n\r\n `!isEmpty()`, not `totalCount() > 0`: in server mode `totalCount()`\r\n is just the `total` input, which can say more rows exist than are\r\n actually on screen right now (a search with no matches but a stale\r\n total, a page past the end) \u2014 the pager has nothing to page through\r\n either way, so it goes by what's actually rendered. -->\r\n @if (showPagination() && !isEmpty()) {\r\n <div class=\"bk-table-pagination\">\r\n <bk-pagination\r\n [total]=\"totalCount()\"\r\n [pageSize]=\"pageSize()\"\r\n [activePage]=\"pageIndex()\"\r\n (pageChanged)=\"onPageIndexChange($event)\"\r\n (changePageSize)=\"onPageSizeChange($event)\"\r\n ></bk-pagination>\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n", styles: [".bk-table-host{display:block}.bk-table-wrapper{@apply w-full;}.bk-table-frame{border:1px solid #ebedf3;border-radius:.75rem;overflow:hidden}.bk-table-title-bar,.bk-table-footer-bar{@apply text-[13px] font-semibold text-[#15191E] bg-[#F9FAFA] px-4 py-2.5;}.bk-table-title-bar{border-bottom:1px solid #ebedf3}.bk-table-footer-bar{border-top:1px solid #ebedf3}.bk-table-container{@apply relative overflow-auto;}.bk-table{@apply min-w-full text-left;border-collapse:separate;border-spacing:0}.bk-th{@apply bg-[#F9FAFA] text-xs text-[#60646C] font-semibold capitalize px-[17px] py-2.5 whitespace-nowrap align-middle;border-bottom:1px solid #ebedf3;position:sticky;top:0;z-index:2}.bk-table thead tr:nth-child(2) .bk-th{top:var(--bk-thead-row-1, 38px);z-index:1}.bk-th-content{@apply flex items-center justify-between gap-1;}.bk-th-align-right .bk-th-content{@apply justify-end;}.bk-th-align-center .bk-th-content{@apply justify-center;}.bk-th-label{@apply inline-flex items-center gap-1;}.bk-th-sortable .bk-th-label{@apply cursor-pointer select-none;}.bk-th-selection{@apply flex items-center gap-1;}.bk-cell-selection{@apply px-3;}.bk-th-selection-caret{@apply inline-flex items-center justify-center size-4 rounded hover:bg-[#EFF1F4];}.bk-td{@apply text-[#15191E] text-[13px] font-medium leading-4 px-4 py-2 align-middle bg-white;border-bottom:1px solid #ebedf3}.bk-td-content{@apply inline-flex items-center gap-1 align-middle;}.bk-td-content-block{@apply block w-full;}.bk-table tbody tr:hover .bk-td{@apply bg-[#FBFBFC];}.bk-table-lg .bk-th{@apply px-5 py-3.5 text-[13px];}.bk-table-lg .bk-td{@apply px-5 py-3.5 text-sm leading-5;}.bk-table-md .bk-th{@apply px-3 py-2;}.bk-table-md .bk-td{@apply px-3 py-1.5;}.bk-table-sm .bk-th{@apply px-2 py-1.5 text-[11px];}.bk-table-sm .bk-td{@apply px-2 py-1 text-xs;}.bk-table-lg .bk-cell-selection{@apply px-4;}.bk-table-md .bk-cell-selection{@apply px-2.5;}.bk-table-sm .bk-cell-selection{@apply px-2;}.bk-table-bordered .bk-th,.bk-table-bordered .bk-td{border-right:1px solid #ebedf3}.bk-table-bordered .bk-th:last-child,.bk-table-bordered .bk-td:last-child{border-right:0}.bk-table tbody tr:last-child>.bk-td{border-bottom:0}.bk-table-underfilled .bk-table tbody tr:last-child>.bk-td{border-bottom:1px solid #ebedf3}.bk-cell-sticky{position:sticky;z-index:1}.bk-th.bk-cell-sticky{z-index:3}.bk-cell-sticky-left:after,.bk-cell-sticky-right:before{content:\"\";@apply absolute top-0 bottom-0 w-2 pointer-events-none;}.bk-cell-sticky-left:after{right:-8px;background-image:linear-gradient(to right,rgba(0,0,0,.05),transparent)}.bk-cell-sticky-right:before{left:-8px;background-image:linear-gradient(to left,rgba(0,0,0,.05),transparent)}.bk-cell-ellipsis{@apply overflow-hidden text-ellipsis whitespace-nowrap;max-width:0}.bk-td-content-ellipsis{@apply flex w-full;}.bk-td-ellipsis-text{@apply overflow-hidden text-ellipsis whitespace-nowrap min-w-0 flex-1;}.bk-cell-break-word{@apply whitespace-normal;word-break:break-all}.bk-td-indent{@apply inline-block;}.bk-td-expand,.bk-td-expand-spacer{@apply inline-flex items-center justify-center size-4 shrink-0;}.bk-td-expand{@apply rounded text-[#78829D] hover:bg-[#EFF1F4] transition-transform duration-200;transform:rotate(-90deg)}.bk-td-expand-open{transform:rotate(0)}.bk-expanded-row>.bk-td,.bk-expanded-row>td{@apply bg-[#FBFBFC];}.bk-td-flush{@apply p-3;}.bk-table-flush .bk-table-frame{border:0;border-radius:0}.bk-table-summary .bk-td{@apply bg-[#F9FAFA] font-semibold;border-top:1px solid #ebedf3;border-bottom:0}.bk-table-summary-fixed .bk-td{position:sticky;bottom:0;z-index:2}.bk-sort-icon{display:inline-flex;flex-direction:column;justify-content:center;align-items:center;height:.875rem;width:.875rem;gap:.125rem;line-height:1}.bk-sort-icon:before,.bk-sort-icon:after{display:inline-block;content:\"\";height:.3rem;width:.54rem;background-repeat:no-repeat;background-position:center;background-size:cover}.bk-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='%2378829D'/%3e%3c/svg%3e\")}.bk-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='%2378829D'/%3e%3c/svg%3e\")}.bk-sort-asc: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\")}.bk-sort-asc: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\")}.bk-sort-desc: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\")}.bk-sort-desc: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\")}.bk-sort-priority{@apply inline-flex items-center justify-center min-w-4 h-4 px-1 rounded bg-[#EFF1F4] text-[10px] font-semibold text-[#4B5675];}.bk-filter-trigger{@apply inline-flex items-center justify-center size-5 rounded text-[#78829D] hover:bg-[#EFF1F4];}.bk-filter-active{@apply text-black;}.bk-filter-menu{@apply min-w-[180px];}.bk-filter-list{@apply flex flex-col gap-2 max-h-60 overflow-y-auto py-1;}.bk-filter-option{@apply text-[13px] text-[#15191E];}.bk-filter-actions{@apply flex items-center justify-between gap-2 pt-2 mt-2;border-top:1px solid #ebedf3}.bk-filter-btn{@apply text-xs font-semibold px-2.5 py-1 rounded;}.bk-filter-btn-link{@apply text-[#60646C] hover:bg-[#F1F2F4];}.bk-filter-btn-primary{@apply bg-black text-white hover:bg-[#2A2E36];}.bk-table-menu{@apply min-w-[160px] flex flex-col;}.bk-table-menu-item{@apply w-full text-left text-[13px] text-[#15191E] px-2 py-1.5 rounded hover:bg-[#F1F2F4];}.bk-table-loading{@apply absolute inset-0 flex items-center justify-center bg-white/60 z-10;}.bk-table-spinner{@apply block size-8 rounded-full border-2 border-[#EBEDF3] border-t-black;animation:bk-table-spin .8s linear infinite}@keyframes bk-table-spin{to{transform:rotate(360deg)}}.bk-table-empty{@apply absolute inset-x-0 bottom-0 flex flex-col justify-center items-center py-10;top:var(--bk-thead-row-1, 38px)}.bk-table-empty-img{@apply mb-3 w-96 max-w-full;}.bk-table-empty-text{@apply block text-sm leading-3 text-center font-semibold text-[#60646C] mt-2;}.bk-table-pagination{@apply contents;}.bk-table-viewport{@apply w-full;}.bk-table-virtual-head{@apply w-full overflow-hidden;}.bk-table-virtual-head .bk-th{position:static}.bk-checkbox-indeterminate .checkbox{@apply bg-black border-black;}.bk-checkbox-indeterminate .checkbox:after{content:\"\";@apply absolute w-2 h-0.5 bg-white rounded-sm;}.cdk-drag-preview{display:table;table-layout:fixed;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)}.bk-drag-handle{@apply cursor-move inline-flex items-center justify-center text-[#C4CADA] hover:text-[#78829D] mr-2 align-middle;}.bk-tree-drop-line{@apply absolute pointer-events-none rounded-full;height:2px;background:#15191e;z-index:5}.bk-table tbody tr.bk-tree-drop-inside .bk-td{background:#f1f2f4;box-shadow:inset 0 0 0 1px #15191e59}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i2.ɵɵCdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i2.ɵɵCdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i2.ɵɵCdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "component", type: BkPagination, selector: "bk-pagination", inputs: ["pageSize", "total", "activePage", "showPageSize", "showRecordsText", "showPageCount", "customClass"], outputs: ["changePageSize", "pageChanged", "activePageChange"] }], encapsulation: i0.ViewEncapsulation.None });
12142
13099
  }
12143
13100
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTable, decorators: [{
12144
13101
  type: Component,
@@ -12433,7 +13390,7 @@ class BkTh extends BkCellBase {
12433
13390
  popover?.close();
12434
13391
  }
12435
13392
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTh, deps: null, target: i0.ɵɵFactoryTarget.Component });
12436
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkTh, isStandalone: true, selector: "th[bk-th]", inputs: { columnKeyInput: { classPropertyName: "columnKeyInput", publicName: "columnKey", isSignal: true, isRequired: false, transformFunction: null }, widthInput: { classPropertyName: "widthInput", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, sortFn: { classPropertyName: "sortFn", publicName: "sortFn", isSignal: true, isRequired: false, transformFunction: null }, sortOrder: { classPropertyName: "sortOrder", publicName: "sortOrder", isSignal: true, isRequired: false, transformFunction: null }, sortDirections: { classPropertyName: "sortDirections", publicName: "sortDirections", isSignal: true, isRequired: false, transformFunction: null }, sortPriorityInput: { classPropertyName: "sortPriorityInput", publicName: "sortPriority", isSignal: true, isRequired: false, transformFunction: null }, filters: { classPropertyName: "filters", publicName: "filters", isSignal: true, isRequired: false, transformFunction: null }, filterFn: { classPropertyName: "filterFn", publicName: "filterFn", isSignal: true, isRequired: false, transformFunction: null }, filterMultiple: { classPropertyName: "filterMultiple", publicName: "filterMultiple", isSignal: true, isRequired: false, transformFunction: null }, checkbox: { classPropertyName: "checkbox", publicName: "checkbox", isSignal: true, isRequired: false, transformFunction: null }, checked: { classPropertyName: "checked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null }, indeterminate: { classPropertyName: "indeterminate", publicName: "indeterminate", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, selections: { classPropertyName: "selections", publicName: "selections", isSignal: true, isRequired: false, transformFunction: null }, showExpand: { classPropertyName: "showExpand", publicName: "showExpand", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sortOrder: "sortOrderChange", checked: "checkedChange" }, host: { properties: { "class.bk-th-sortable": "showSort()", "class.bk-cell-selection": "checkbox()", "class.bk-cell-sticky": "isSticky", "class.bk-cell-sticky-left": "left() !== false", "class.bk-cell-sticky-right": "right() !== false", "class.bk-cell-ellipsis": "ellipsis()", "class.bk-cell-break-word": "breakWord()", "class.bk-th-align-right": "align() === 'right'", "class.bk-th-align-center": "align() === 'center'", "style.left": "stickyLeft()", "style.right": "stickyRight()", "style.width": "widthInput()", "style.text-align": "align()" }, classAttribute: "bk-th" }, usesInheritance: true, ngImport: i0, template: "@if (checkbox()) {\r\n <!-- Selection column: checkbox, plus a caret when custom selections exist. -->\r\n <div class=\"bk-th-selection\">\r\n <bk-checkbox\r\n checkboxClass=\"sm\"\r\n [ngModel]=\"checked()\"\r\n (ngModelChange)=\"onCheckedChange($event)\"\r\n [disabled]=\"disabled()\"\r\n [class.bk-checkbox-indeterminate]=\"indeterminate() && !checked()\"\r\n ></bk-checkbox>\r\n\r\n @if (selections().length) {\r\n <!-- appendToBody: see the filter popover below \u2014 same containment problem. -->\r\n <bk-popover\r\n #selectionPop=\"bkPopover\"\r\n trigger=\"click\"\r\n placement=\"bottom-left\"\r\n [showArrow]=\"false\"\r\n [appendToBody]=\"true\"\r\n >\r\n <button type=\"button\" bkPopoverTrigger class=\"bk-th-selection-caret\" aria-label=\"Selection options\">\r\n <svg width=\"8\" height=\"5\" viewBox=\"0 0 8 5\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n d=\"M4 4.25c-.175 0-.292-.058-.408-.175L.675 1.158a.664.664 0 0 1 0-.817.664.664 0 0 1 .817 0L4 2.85 6.508.341a.664.664 0 0 1 .817 0 .664.664 0 0 1 0 .817L4.408 4.075C4.292 4.192 4.175 4.25 4 4.25Z\"\r\n fill=\"#78829D\"\r\n />\r\n </svg>\r\n </button>\r\n\r\n <ul class=\"bk-table-menu\">\r\n @for (selection of selections(); track selection.text) {\r\n <li>\r\n <button type=\"button\" class=\"bk-table-menu-item\" (click)=\"runSelection(selection, selectionPop)\">\r\n {{ selection.text }}\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n </bk-popover>\r\n }\r\n </div>\r\n} @else {\r\n <div class=\"bk-th-content\" [class.bk-th-clickable]=\"showSort()\">\r\n <!--\r\n Only the label triggers sorting. The filter icon sits outside this span so\r\n opening the menu doesn't also flip the sort order.\r\n -->\r\n <span class=\"bk-th-label\" (click)=\"onSortClick()\">\r\n <ng-content></ng-content>\r\n\r\n @if (showSort()) {\r\n <span\r\n class=\"bk-sort-icon\"\r\n [class.bk-sort-asc]=\"sortOrder() === 'ascend'\"\r\n [class.bk-sort-desc]=\"sortOrder() === 'descend'\"\r\n ></span>\r\n }\r\n\r\n @if (showSort() && sortPriority !== null && sortOrder() !== null) {\r\n <!-- Rank badge: without it, multi-sort gives no clue which column wins. -->\r\n <span class=\"bk-sort-priority\">{{ sortPriority }}</span>\r\n }\r\n </span>\r\n\r\n @if (showFilter()) {\r\n <!--\r\n appendToBody is not optional here. The panel is `position: fixed`, and a\r\n table puts two things in its way: the header cell is inside\r\n `.bk-table-container`, which scrolls, and any transformed ancestor would\r\n turn the panel's viewport coordinates into cell-relative ones. Relocating\r\n it to <body> is the only placement that survives both.\r\n -->\r\n <bk-popover\r\n #filterPop=\"bkPopover\"\r\n trigger=\"click\"\r\n placement=\"bottom-right\"\r\n [showArrow]=\"false\"\r\n panelClass=\"bk-filter-popover\"\r\n [appendToBody]=\"true\"\r\n (opened)=\"onFilterMenuOpen()\"\r\n >\r\n <button\r\n type=\"button\"\r\n bkPopoverTrigger\r\n class=\"bk-filter-trigger\"\r\n [class.bk-filter-active]=\"isFiltered()\"\r\n aria-label=\"Filter column\"\r\n >\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n d=\"M1.5 2.5h13L9.5 8.2v4.6l-3 1.7V8.2L1.5 2.5Z\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"1.3\"\r\n stroke-linejoin=\"round\"\r\n [attr.fill]=\"isFiltered() ? 'currentColor' : 'none'\"\r\n />\r\n </svg>\r\n </button>\r\n\r\n <div class=\"bk-filter-menu\">\r\n <ul class=\"bk-filter-list\">\r\n @for (option of filters(); track option.value) {\r\n <li class=\"bk-filter-option\">\r\n @if (filterMultiple()) {\r\n <bk-checkbox\r\n checkboxClass=\"sm\"\r\n [label]=\"option.text\"\r\n [ngModel]=\"isPending(option.value)\"\r\n (ngModelChange)=\"toggleFilterOption(option.value, $event)\"\r\n ></bk-checkbox>\r\n } @else {\r\n <bk-radio-button\r\n [label]=\"option.text\"\r\n [value]=\"option.value\"\r\n [ngModel]=\"singleFilter\"\r\n (ngModelChange)=\"singleFilter = $event\"\r\n ></bk-radio-button>\r\n }\r\n </li>\r\n }\r\n </ul>\r\n\r\n <div class=\"bk-filter-actions\">\r\n <button type=\"button\" class=\"bk-filter-btn bk-filter-btn-link\" (click)=\"resetFilter(filterPop)\">\r\n Reset\r\n </button>\r\n <button type=\"button\" class=\"bk-filter-btn bk-filter-btn-primary\" (click)=\"applyFilter(filterPop)\">\r\n OK\r\n </button>\r\n </div>\r\n </div>\r\n </bk-popover>\r\n }\r\n </div>\r\n}\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: BkCheckbox, selector: "bk-checkbox", inputs: ["checkboxClass", "label", "labelClass", "disabled"], outputs: ["change"] }, { kind: "component", type: BkRadioButton, selector: "bk-radio-button", inputs: ["radioClass", "label", "labelClass", "value", "uncheckedValue", "allowDeselect", "disabled", "variant"], outputs: ["change"] }, { kind: "component", type: BkPopover, selector: "bk-popover", inputs: ["placement", "trigger", "title", "closable", "disabled", "showArrow", "offset", "flip", "closeOnClickOutside", "closeOnEscape", "openDelay", "closeDelay", "maxWidth", "width", "panelClass", "appendToBody"], outputs: ["opened", "closed", "openChange"], exportAs: ["bkPopover"] }], encapsulation: i0.ViewEncapsulation.None });
13393
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkTh, isStandalone: true, selector: "th[bk-th]", inputs: { columnKeyInput: { classPropertyName: "columnKeyInput", publicName: "columnKey", isSignal: true, isRequired: false, transformFunction: null }, widthInput: { classPropertyName: "widthInput", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, sortFn: { classPropertyName: "sortFn", publicName: "sortFn", isSignal: true, isRequired: false, transformFunction: null }, sortOrder: { classPropertyName: "sortOrder", publicName: "sortOrder", isSignal: true, isRequired: false, transformFunction: null }, sortDirections: { classPropertyName: "sortDirections", publicName: "sortDirections", isSignal: true, isRequired: false, transformFunction: null }, sortPriorityInput: { classPropertyName: "sortPriorityInput", publicName: "sortPriority", isSignal: true, isRequired: false, transformFunction: null }, filters: { classPropertyName: "filters", publicName: "filters", isSignal: true, isRequired: false, transformFunction: null }, filterFn: { classPropertyName: "filterFn", publicName: "filterFn", isSignal: true, isRequired: false, transformFunction: null }, filterMultiple: { classPropertyName: "filterMultiple", publicName: "filterMultiple", isSignal: true, isRequired: false, transformFunction: null }, checkbox: { classPropertyName: "checkbox", publicName: "checkbox", isSignal: true, isRequired: false, transformFunction: null }, checked: { classPropertyName: "checked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null }, indeterminate: { classPropertyName: "indeterminate", publicName: "indeterminate", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, selections: { classPropertyName: "selections", publicName: "selections", isSignal: true, isRequired: false, transformFunction: null }, showExpand: { classPropertyName: "showExpand", publicName: "showExpand", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sortOrder: "sortOrderChange", checked: "checkedChange" }, host: { properties: { "class.bk-th-sortable": "showSort()", "class.bk-cell-selection": "checkbox()", "class.bk-cell-sticky": "isSticky", "class.bk-cell-sticky-left": "left() !== false", "class.bk-cell-sticky-right": "right() !== false", "class.bk-cell-ellipsis": "ellipsis()", "class.bk-cell-break-word": "breakWord()", "class.bk-th-align-right": "align() === 'right'", "class.bk-th-align-center": "align() === 'center'", "style.left": "stickyLeft()", "style.right": "stickyRight()", "style.width": "widthInput()", "style.text-align": "align()" }, classAttribute: "bk-th" }, usesInheritance: true, ngImport: i0, template: "@if (checkbox()) {\r\n <!-- Selection column: checkbox, plus a caret when custom selections exist. -->\r\n <div class=\"bk-th-selection\">\r\n <bk-checkbox\r\n checkboxClass=\"sm\"\r\n [ngModel]=\"checked()\"\r\n (ngModelChange)=\"onCheckedChange($event)\"\r\n [disabled]=\"disabled()\"\r\n [class.bk-checkbox-indeterminate]=\"indeterminate() && !checked()\"\r\n ></bk-checkbox>\r\n\r\n @if (selections().length) {\r\n <!-- appendToBody: see the filter popover below \u2014 same containment problem. -->\r\n <bk-popover\r\n #selectionPop=\"bkPopover\"\r\n trigger=\"click\"\r\n placement=\"bottom-left\"\r\n [showArrow]=\"false\"\r\n [appendToBody]=\"true\"\r\n >\r\n <button type=\"button\" bkPopoverTrigger class=\"bk-th-selection-caret\" aria-label=\"Selection options\">\r\n <svg width=\"8\" height=\"5\" viewBox=\"0 0 8 5\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n d=\"M4 4.25c-.175 0-.292-.058-.408-.175L.675 1.158a.664.664 0 0 1 0-.817.664.664 0 0 1 .817 0L4 2.85 6.508.341a.664.664 0 0 1 .817 0 .664.664 0 0 1 0 .817L4.408 4.075C4.292 4.192 4.175 4.25 4 4.25Z\"\r\n fill=\"#78829D\"\r\n />\r\n </svg>\r\n </button>\r\n\r\n <ul class=\"bk-table-menu\">\r\n @for (selection of selections(); track selection.text) {\r\n <li>\r\n <button type=\"button\" class=\"bk-table-menu-item\" (click)=\"runSelection(selection, selectionPop)\">\r\n {{ selection.text }}\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n </bk-popover>\r\n }\r\n </div>\r\n} @else {\r\n <div class=\"bk-th-content\" [class.bk-th-clickable]=\"showSort()\">\r\n <!--\r\n Only the label triggers sorting. The filter icon sits outside this span so\r\n opening the menu doesn't also flip the sort order.\r\n -->\r\n <span class=\"bk-th-label\" (click)=\"onSortClick()\">\r\n <ng-content></ng-content>\r\n\r\n @if (showSort()) {\r\n <span\r\n class=\"bk-sort-icon\"\r\n [class.bk-sort-asc]=\"sortOrder() === 'ascend'\"\r\n [class.bk-sort-desc]=\"sortOrder() === 'descend'\"\r\n ></span>\r\n }\r\n\r\n @if (showSort() && sortPriority !== null && sortOrder() !== null) {\r\n <!-- Rank badge: without it, multi-sort gives no clue which column wins. -->\r\n <span class=\"bk-sort-priority\">{{ sortPriority }}</span>\r\n }\r\n </span>\r\n\r\n @if (showFilter()) {\r\n <!--\r\n appendToBody is not optional here. The panel is `position: fixed`, and a\r\n table puts two things in its way: the header cell is inside\r\n `.bk-table-container`, which scrolls, and any transformed ancestor would\r\n turn the panel's viewport coordinates into cell-relative ones. Relocating\r\n it to <body> is the only placement that survives both.\r\n -->\r\n <bk-popover\r\n #filterPop=\"bkPopover\"\r\n trigger=\"click\"\r\n placement=\"bottom-right\"\r\n [showArrow]=\"false\"\r\n panelClass=\"bk-filter-popover\"\r\n [appendToBody]=\"true\"\r\n (opened)=\"onFilterMenuOpen()\"\r\n >\r\n <button\r\n type=\"button\"\r\n bkPopoverTrigger\r\n class=\"bk-filter-trigger\"\r\n [class.bk-filter-active]=\"isFiltered()\"\r\n aria-label=\"Filter column\"\r\n >\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n d=\"M1.5 2.5h13L9.5 8.2v4.6l-3 1.7V8.2L1.5 2.5Z\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"1.3\"\r\n stroke-linejoin=\"round\"\r\n [attr.fill]=\"isFiltered() ? 'currentColor' : 'none'\"\r\n />\r\n </svg>\r\n </button>\r\n\r\n <div class=\"bk-filter-menu\">\r\n <ul class=\"bk-filter-list\">\r\n @for (option of filters(); track option.value) {\r\n <li class=\"bk-filter-option\">\r\n @if (filterMultiple()) {\r\n <bk-checkbox\r\n checkboxClass=\"sm\"\r\n [label]=\"option.text\"\r\n [ngModel]=\"isPending(option.value)\"\r\n (ngModelChange)=\"toggleFilterOption(option.value, $event)\"\r\n ></bk-checkbox>\r\n } @else {\r\n <bk-radio-button\r\n [label]=\"option.text\"\r\n [value]=\"option.value\"\r\n [ngModel]=\"singleFilter\"\r\n (ngModelChange)=\"singleFilter = $event\"\r\n ></bk-radio-button>\r\n }\r\n </li>\r\n }\r\n </ul>\r\n\r\n <div class=\"bk-filter-actions\">\r\n <button type=\"button\" class=\"bk-filter-btn bk-filter-btn-link\" (click)=\"resetFilter(filterPop)\">\r\n Reset\r\n </button>\r\n <button type=\"button\" class=\"bk-filter-btn bk-filter-btn-primary\" (click)=\"applyFilter(filterPop)\">\r\n OK\r\n </button>\r\n </div>\r\n </div>\r\n </bk-popover>\r\n }\r\n </div>\r\n}\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: BkCheckbox, selector: "bk-checkbox", inputs: ["checkboxClass", "label", "labelClass", "disabled"], outputs: ["change"] }, { kind: "component", type: BkRadioButton, selector: "bk-radio-button", inputs: ["radioClass", "label", "labelClass", "value", "uncheckedValue", "allowDeselect", "disabled", "variant"], outputs: ["change"] }, { kind: "component", type: BkPopover, selector: "bk-popover", inputs: ["placement", "trigger", "title", "closable", "disabled", "showArrow", "offset", "flip", "closeOnClickOutside", "closeOnEscape", "openDelay", "closeDelay", "maxWidth", "width", "panelClass", "appendToBody"], outputs: ["opened", "closed", "openChange"], exportAs: ["bkPopover"] }], encapsulation: i0.ViewEncapsulation.None });
12437
13394
  }
12438
13395
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTh, decorators: [{
12439
13396
  type: Component,
@@ -12576,7 +13533,7 @@ class BkTd extends BkCellBase {
12576
13533
  });
12577
13534
  }
12578
13535
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTd, deps: null, target: i0.ɵɵFactoryTarget.Component });
12579
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkTd, isStandalone: true, selector: "td[bk-td]", inputs: { tooltipPosition: { classPropertyName: "tooltipPosition", publicName: "tooltipPosition", isSignal: true, isRequired: false, transformFunction: null }, checkbox: { classPropertyName: "checkbox", publicName: "checkbox", isSignal: true, isRequired: false, transformFunction: null }, checked: { classPropertyName: "checked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, indeterminate: { classPropertyName: "indeterminate", publicName: "indeterminate", isSignal: true, isRequired: false, transformFunction: null }, showExpand: { classPropertyName: "showExpand", publicName: "showExpand", isSignal: true, isRequired: false, transformFunction: null }, expand: { classPropertyName: "expand", publicName: "expand", isSignal: true, isRequired: false, transformFunction: null }, expandIcon: { classPropertyName: "expandIcon", publicName: "expandIcon", isSignal: true, isRequired: false, transformFunction: null }, indentLevel: { classPropertyName: "indentLevel", publicName: "indentLevel", isSignal: true, isRequired: false, transformFunction: null }, indentSize: { classPropertyName: "indentSize", publicName: "indentSize", isSignal: true, isRequired: false, transformFunction: null }, treeCell: { classPropertyName: "treeCell", publicName: "treeCell", isSignal: true, isRequired: false, transformFunction: null }, block: { classPropertyName: "block", publicName: "block", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { checked: "checkedChange", expand: "expandChange" }, host: { properties: { "class.bk-cell-selection": "checkbox()", "class.bk-cell-sticky": "isSticky", "class.bk-cell-sticky-left": "left() !== false", "class.bk-cell-sticky-right": "right() !== false", "class.bk-cell-ellipsis": "ellipsis()", "class.bk-cell-break-word": "breakWord()", "style.left": "stickyLeft()", "style.right": "stickyRight()", "style.text-align": "align()" }, classAttribute: "bk-td" }, viewQueries: [{ propertyName: "ellipsisTextRef", first: true, predicate: ["ellipsisText"], descendants: true }], usesInheritance: true, ngImport: i0, template: "@if (checkbox()) {\r\n <bk-checkbox\r\n checkboxClass=\"sm\"\r\n [ngModel]=\"checked()\"\r\n (ngModelChange)=\"onCheckedChange($event)\"\r\n [disabled]=\"disabled()\"\r\n [class.bk-checkbox-indeterminate]=\"indeterminate() && !checked()\"\r\n ></bk-checkbox>\r\n} @else {\r\n <span\r\n class=\"bk-td-content\"\r\n [class.bk-td-content-block]=\"block()\"\r\n [class.bk-td-content-ellipsis]=\"ellipsis()\"\r\n >\r\n @if (indentPx() > 0) {\r\n <!-- Depth is expressed as blank width, so the cell keeps one text flow\r\n and long labels still wrap under themselves rather than under the\r\n indent. -->\r\n <span class=\"bk-td-indent\" [style.padding-left.px]=\"indentPx()\"></span>\r\n }\r\n\r\n @if (showExpand()) {\r\n <button\r\n type=\"button\"\r\n class=\"bk-td-expand\"\r\n [class.bk-td-expand-open]=\"expand()\"\r\n [attr.aria-expanded]=\"expand()\"\r\n aria-label=\"Toggle row\"\r\n (click)=\"onExpandClick()\"\r\n >\r\n @if (expandIcon()) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"expandIcon()!\"\r\n [ngTemplateOutletContext]=\"{ $implicit: expand() }\"\r\n ></ng-container>\r\n } @else {\r\n <svg width=\"8\" height=\"8\" viewBox=\"0 0 8 5\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n d=\"M4 4.25c-.175 0-.292-.058-.408-.175L.675 1.158a.664.664 0 0 1 0-.817.664.664 0 0 1 .817 0L4 2.85 6.508.341a.664.664 0 0 1 .817 0 .664.664 0 0 1 0 .817L4.408 4.075C4.292 4.192 4.175 4.25 4 4.25Z\"\r\n fill=\"currentColor\"\r\n />\r\n </svg>\r\n }\r\n </button>\r\n } @else if (isLeafSpacer()) {\r\n <span class=\"bk-td-expand-spacer\"></span>\r\n }\r\n\r\n <span\r\n #ellipsisText\r\n [class.bk-td-ellipsis-text]=\"ellipsis()\"\r\n [bkTooltip]=\"truncatedTooltip()\"\r\n [bkTooltipPosition]=\"tooltipPosition()\"\r\n >\r\n <ng-content></ng-content>\r\n </span>\r\n </span>\r\n}\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: BkCheckbox, selector: "bk-checkbox", inputs: ["checkboxClass", "label", "labelClass", "disabled"], outputs: ["change"] }, { kind: "directive", type: BKTooltipDirective, selector: "[bkTooltip]", inputs: ["bkTooltip", "bkTooltipPosition", "bkTooltipScrollable", "bkTooltipMaxHeight", "bkTooltipSize", "bkTooltipAutoHeight"] }], encapsulation: i0.ViewEncapsulation.None });
13536
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkTd, isStandalone: true, selector: "td[bk-td]", inputs: { tooltipPosition: { classPropertyName: "tooltipPosition", publicName: "tooltipPosition", isSignal: true, isRequired: false, transformFunction: null }, checkbox: { classPropertyName: "checkbox", publicName: "checkbox", isSignal: true, isRequired: false, transformFunction: null }, checked: { classPropertyName: "checked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, indeterminate: { classPropertyName: "indeterminate", publicName: "indeterminate", isSignal: true, isRequired: false, transformFunction: null }, showExpand: { classPropertyName: "showExpand", publicName: "showExpand", isSignal: true, isRequired: false, transformFunction: null }, expand: { classPropertyName: "expand", publicName: "expand", isSignal: true, isRequired: false, transformFunction: null }, expandIcon: { classPropertyName: "expandIcon", publicName: "expandIcon", isSignal: true, isRequired: false, transformFunction: null }, indentLevel: { classPropertyName: "indentLevel", publicName: "indentLevel", isSignal: true, isRequired: false, transformFunction: null }, indentSize: { classPropertyName: "indentSize", publicName: "indentSize", isSignal: true, isRequired: false, transformFunction: null }, treeCell: { classPropertyName: "treeCell", publicName: "treeCell", isSignal: true, isRequired: false, transformFunction: null }, block: { classPropertyName: "block", publicName: "block", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { checked: "checkedChange", expand: "expandChange" }, host: { properties: { "class.bk-cell-selection": "checkbox()", "class.bk-cell-sticky": "isSticky", "class.bk-cell-sticky-left": "left() !== false", "class.bk-cell-sticky-right": "right() !== false", "class.bk-cell-ellipsis": "ellipsis()", "class.bk-cell-break-word": "breakWord()", "style.left": "stickyLeft()", "style.right": "stickyRight()", "style.text-align": "align()" }, classAttribute: "bk-td" }, viewQueries: [{ propertyName: "ellipsisTextRef", first: true, predicate: ["ellipsisText"], descendants: true }], usesInheritance: true, ngImport: i0, template: "@if (checkbox()) {\r\n <bk-checkbox\r\n checkboxClass=\"sm\"\r\n [ngModel]=\"checked()\"\r\n (ngModelChange)=\"onCheckedChange($event)\"\r\n [disabled]=\"disabled()\"\r\n [class.bk-checkbox-indeterminate]=\"indeterminate() && !checked()\"\r\n ></bk-checkbox>\r\n} @else {\r\n <span\r\n class=\"bk-td-content\"\r\n [class.bk-td-content-block]=\"block()\"\r\n [class.bk-td-content-ellipsis]=\"ellipsis()\"\r\n >\r\n @if (indentPx() > 0) {\r\n <!-- Depth is expressed as blank width, so the cell keeps one text flow\r\n and long labels still wrap under themselves rather than under the\r\n indent. -->\r\n <span class=\"bk-td-indent\" [style.padding-left.px]=\"indentPx()\"></span>\r\n }\r\n\r\n @if (showExpand()) {\r\n <button\r\n type=\"button\"\r\n class=\"bk-td-expand\"\r\n [class.bk-td-expand-open]=\"expand()\"\r\n [attr.aria-expanded]=\"expand()\"\r\n aria-label=\"Toggle row\"\r\n (click)=\"onExpandClick()\"\r\n >\r\n @if (expandIcon()) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"expandIcon()!\"\r\n [ngTemplateOutletContext]=\"{ $implicit: expand() }\"\r\n ></ng-container>\r\n } @else {\r\n <svg width=\"8\" height=\"8\" viewBox=\"0 0 8 5\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n d=\"M4 4.25c-.175 0-.292-.058-.408-.175L.675 1.158a.664.664 0 0 1 0-.817.664.664 0 0 1 .817 0L4 2.85 6.508.341a.664.664 0 0 1 .817 0 .664.664 0 0 1 0 .817L4.408 4.075C4.292 4.192 4.175 4.25 4 4.25Z\"\r\n fill=\"currentColor\"\r\n />\r\n </svg>\r\n }\r\n </button>\r\n } @else if (isLeafSpacer()) {\r\n <span class=\"bk-td-expand-spacer\"></span>\r\n }\r\n\r\n <span\r\n #ellipsisText\r\n [class.bk-td-ellipsis-text]=\"ellipsis()\"\r\n [bkTooltip]=\"truncatedTooltip()\"\r\n [bkTooltipPosition]=\"tooltipPosition()\"\r\n >\r\n <ng-content></ng-content>\r\n </span>\r\n </span>\r\n}\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: BkCheckbox, selector: "bk-checkbox", inputs: ["checkboxClass", "label", "labelClass", "disabled"], outputs: ["change"] }, { kind: "directive", type: BKTooltipDirective, selector: "[bkTooltip]", inputs: ["bkTooltip", "bkTooltipPosition", "bkTooltipScrollable", "bkTooltipMaxHeight", "bkTooltipSize", "bkTooltipAutoHeight"] }], encapsulation: i0.ViewEncapsulation.None });
12580
13537
  }
12581
13538
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTd, decorators: [{
12582
13539
  type: Component,
@@ -12776,7 +13733,7 @@ class BkDragHandle {
12776
13733
  icon = input(null, ...(ngDevMode ? [{ debugName: "icon" }] : []));
12777
13734
  ariaLabel = input('Reorder row', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : []));
12778
13735
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkDragHandle, deps: [], target: i0.ɵɵFactoryTarget.Component });
12779
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.16", type: BkDragHandle, isStandalone: true, selector: "bk-drag-handle", inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "button" }, properties: { "attr.aria-label": "ariaLabel()" }, classAttribute: "bk-drag-handle" }, exportAs: ["bkDragHandle"], hostDirectives: [{ directive: i2$1.CdkDragHandle }], ngImport: i0, template: `
13736
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.16", type: BkDragHandle, isStandalone: true, selector: "bk-drag-handle", inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "button" }, properties: { "attr.aria-label": "ariaLabel()" }, classAttribute: "bk-drag-handle" }, exportAs: ["bkDragHandle"], hostDirectives: [{ directive: i3.CdkDragHandle }], ngImport: i0, template: `
12780
13737
  <ng-container [ngTemplateOutlet]="icon() ?? defaultIcon"></ng-container>
12781
13738
  <ng-template #defaultIcon>
12782
13739
  <svg width="10" height="16" viewBox="0 0 10 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
@@ -13086,5 +14043,5 @@ const BK_TABLE = [
13086
14043
  * Generated bundle index. Do not edit.
13087
14044
  */
13088
14045
 
13089
- export { ARROW_CORNER_GAP, BKTooltipDirective, BK_DEFAULT_DIALOG_CONFIG, BK_DIALOG_DATA, BK_DIALOG_GLOBAL_CONFIG, BK_TABLE, BkAvatar, BkAvatarGroup, BkAvatarUploader, BkBadge, BkBreadcrumb, BkButton, BkButtonGroup, BkCalendarManagerService, BkCheckbox, BkColumnFilterService, BkColumnSelect, BkCustomCalendar, BkDialogActions, BkDialogClose, BkDialogContent, BkDialogModule, BkDialogRef, BkDialogService, BkDialogTitle, BkDragHandle, BkDropdown, BkFileCard, BkFilePicker, BkGrid, BkHierarchicalSelect, BkIconButton, BkInput, BkInputChips, BkLoader, BkMenu, BkPagination, BkPill, BkPopover, BkRadioButton, BkScheduledDatePicker, BkSelect, BkSpinner, BkTable, BkTableDrag, BkTableFooter, BkTableSummary, BkTableTitle, BkTabs, BkTd, BkTextarea, BkTh, BkTimePicker, BkToastr, BkToastrService, BkToggle, BkTooltipInteractionService, BkTrExpand, BkTreeDrag, BkValidator, BkVirtualScroll, BrickclayIcons, BrickclayLib, CalendarModule, CalendarSelection, ColumnFilterOption, DEFAULT_COUNTRY_OPTIONS, NEUTRAL_APPEARANCE, OPPOSITE_SIDE, POPOVER_PLACEMENTS, clamp, containsBkTreeNode, deriveAppearance, flattenBkTreeData, getDialogBackdropAnimation, getDialogPanelAnimation, joinPlacement, moveBkTreeNode, normalizeBkTableSize, parseColor, splitPlacement };
14046
+ export { ARROW_CORNER_GAP, BKTooltipDirective, BK_DEFAULT_DIALOG_CONFIG, BK_DIALOG_DATA, BK_DIALOG_GLOBAL_CONFIG, BK_TABLE, BkAvatar, BkAvatarGroup, BkAvatarUploader, BkBadge, BkBreadcrumb, BkButton, BkButtonGroup, BkCalendarManagerService, BkCheckbox, BkColumnFilterService, BkColumnSelect, BkCustomCalendar, BkDialogActions, BkDialogClose, BkDialogContent, BkDialogModule, BkDialogRef, BkDialogService, BkDialogTitle, BkDragHandle, BkDropdown, BkFileCard, BkFilePicker, BkGrid, BkHierarchicalSelect, BkIconButton, BkInput, BkInputChips, BkLoader, BkMenu, BkPagination, BkPill, BkPopover, BkRadioButton, BkScheduledDatePicker, BkSelect, BkSpinner, BkTable, BkTableDrag, BkTableFooter, BkTableSummary, BkTableTitle, BkTabs, BkTd, BkTextarea, BkTh, BkTimePicker, BkToastr, BkToastrService, BkToggle, BkTooltipInteractionService, BkTrExpand, BkTreeDrag, BkValidator, BkVirtualScroll, BrickclayIcons, BrickclayLib, CalendarModule, CalendarMonth, CalendarSelection, CalendarWeekday, ColumnFilterOption, DEFAULT_COUNTRY_OPTIONS, NEUTRAL_APPEARANCE, OPPOSITE_SIDE, POPOVER_PLACEMENTS, clamp, containsBkTreeNode, deriveAppearance, flattenBkTreeData, getDialogBackdropAnimation, getDialogPanelAnimation, joinPlacement, moveBkTreeNode, normalizeBkTableSize, parseColor, splitPlacement };
13090
14047
  //# sourceMappingURL=brickclay-org-ui.mjs.map