@brickclay-org/ui 0.1.70 → 0.1.72

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,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Component, EventEmitter, forwardRef, HostListener, ViewChildren, Input, Output, Injectable, ViewChild, NgModule, ViewEncapsulation, Optional, Self, Directive, input, model, output, signal, computed, effect, inject, ElementRef, InjectionToken, createComponent, ChangeDetectionStrategy } from '@angular/core';
2
+ import { Component, EventEmitter, forwardRef, HostListener, ViewChild, Input, Output, Injectable, NgModule, ViewEncapsulation, Optional, Self, Directive, input, model, output, signal, computed, effect, inject, ElementRef, ViewChildren, InjectionToken, createComponent, ChangeDetectionStrategy } from '@angular/core';
3
3
  import * as i1 from '@angular/common';
4
4
  import { CommonModule, NgClass } from '@angular/common';
5
5
  import * as i3 from '@angular/forms';
@@ -43,6 +43,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
43
43
  }] });
44
44
 
45
45
  class BkTimePicker {
46
+ renderer;
46
47
  required = false;
47
48
  /** @deprecated Prefer [(ngModel)] */
48
49
  value = null;
@@ -55,6 +56,11 @@ class BkTimePicker {
55
56
  closePicker = 0;
56
57
  timeFormat = 12;
57
58
  showSeconds = false;
59
+ /** When true, auto-flip the dropdown above/below and left/right based on available viewport space. */
60
+ autoPosition = false;
61
+ /** When true, position the dropdown with `fixed` so it escapes ancestor overflow (dialogs, scroll containers),
62
+ * follows the trigger on scroll, and closes when the trigger is scrolled out of view. */
63
+ appendToBody = false;
58
64
  change = new EventEmitter();
59
65
  timeChange = new EventEmitter();
60
66
  pickerOpened = new EventEmitter();
@@ -62,26 +68,73 @@ class BkTimePicker {
62
68
  onChange = () => { };
63
69
  onTouched = () => { };
64
70
  disabled = false;
65
- timeScrollElements;
66
- minuteScrollElements;
67
- secondScrollElements;
68
- WHEEL_CYCLE = 60;
71
+ hourScrollEl;
72
+ minuteScrollEl;
73
+ secondScrollEl;
74
+ /** The positioned trigger (its rect anchors the dropdown). */
75
+ tpWrapper;
76
+ /** The dropdown panel element (measured for flip decisions). */
77
+ tpDropdown;
78
+ /** Resolved placement state, driven by updatePosition(). */
79
+ placeAbove = false;
80
+ resolvedPosition = 'left';
81
+ dropdownStyle = {};
69
82
  /** Row height in px. MUST match the .time-item height in CSS for the active variation. */
70
83
  get ITEM_HEIGHT() {
71
84
  return this.variation === 'lg' ? 32 : 28;
72
85
  }
73
- get MIDDLE_OFFSET() {
74
- return this.WHEEL_CYCLE * this.ITEM_HEIGHT;
75
- }
76
- wheelMinutes = Array.from({ length: this.WHEEL_CYCLE * 3 }, (_, i) => i % this.WHEEL_CYCLE);
77
- wheelSeconds = Array.from({ length: this.WHEEL_CYCLE * 3 }, (_, i) => i % this.WHEEL_CYCLE);
86
+ /** Finite lists (no cyclic loop) — same as the hours column, so 00..59 has a hard start/end. */
87
+ minutes = Array.from({ length: 60 }, (_, i) => i);
88
+ seconds = Array.from({ length: 60 }, (_, i) => i);
78
89
  showPicker = false;
79
90
  currentHour = 12;
80
91
  currentMinute = 0;
81
92
  currentSecond = 0;
82
93
  currentAMPM = 'PM';
94
+ /**
95
+ * Highlight that follows a column while scrolling. It is purely visual: scrolling moves it
96
+ * but does NOT commit the value. The value is only selected/committed when the user clicks
97
+ * an item (see onHourChange / onMinuteChange / onSecondChange).
98
+ */
99
+ activeHour = 12;
100
+ activeMinute = 0;
101
+ activeSecond = 0;
83
102
  _modelValue = null;
84
103
  brickclayIcons = BrickclayIcons;
104
+ constructor(renderer) {
105
+ this.renderer = renderer;
106
+ }
107
+ /* ---------------- appendToBody dropdown relocation ---------------- */
108
+ /**
109
+ * `appendToBody` anchors the dropdown with `position: fixed`, which only tracks the viewport when
110
+ * NO ancestor establishes a containing block (transform / filter / perspective / will-change /
111
+ * contain / backdrop-filter). Inside such an ancestor the fixed coordinates resolve against that
112
+ * ancestor instead and the dropdown drifts off-position. To be robust we physically move the panel
113
+ * to <body> while open (Angular keeps managing it by reference) and move it back before *ngIf
114
+ * tears it down. The panel carries a `tp-compact` self-class so its `default`-variation sizing —
115
+ * otherwise scoped under the `.time-input-group.default` ancestor it just left — still applies.
116
+ */
117
+ dropdownMovedToBody = false;
118
+ dropdownOriginalParent = null;
119
+ moveDropdownToBody() {
120
+ const el = this.tpDropdown?.nativeElement;
121
+ if (!el || this.dropdownMovedToBody)
122
+ return;
123
+ this.dropdownOriginalParent = el.parentElement;
124
+ this.renderer.appendChild(document.body, el);
125
+ this.dropdownMovedToBody = true;
126
+ }
127
+ /** Return the dropdown to its original slot so *ngIf can destroy it cleanly (safe to call twice). */
128
+ restoreDropdownFromBody() {
129
+ if (!this.dropdownMovedToBody)
130
+ return;
131
+ const el = this.tpDropdown?.nativeElement;
132
+ if (el && this.dropdownOriginalParent) {
133
+ this.renderer.appendChild(this.dropdownOriginalParent, el);
134
+ }
135
+ this.dropdownMovedToBody = false;
136
+ this.dropdownOriginalParent = null;
137
+ }
85
138
  /* ---------------- CVA ---------------- */
86
139
  writeValue(value) {
87
140
  if (!value) {
@@ -121,6 +174,9 @@ class BkTimePicker {
121
174
  }
122
175
  this.currentMinute = 0;
123
176
  this.currentSecond = 0;
177
+ this.activeHour = this.currentHour;
178
+ this.activeMinute = 0;
179
+ this.activeSecond = 0;
124
180
  }
125
181
  clear() {
126
182
  this._modelValue = null;
@@ -150,9 +206,7 @@ class BkTimePicker {
150
206
  if (changes['closePicker'] && this.showPicker) {
151
207
  const newCounter = changes['closePicker'].currentValue;
152
208
  if (newCounter > this.previousCloseCounter) {
153
- this.showPicker = false;
154
- this.markAsTouched();
155
- this.pickerClosed.emit(this.pickerId);
209
+ this.dismiss();
156
210
  this.previousCloseCounter = newCounter;
157
211
  }
158
212
  }
@@ -171,6 +225,10 @@ class BkTimePicker {
171
225
  this.currentMinute = parsed.minute;
172
226
  this.currentSecond = parsed.second;
173
227
  this.currentAMPM = parsed.ampm;
228
+ // Scroll highlight starts on the committed value.
229
+ this.activeHour = parsed.hour;
230
+ this.activeMinute = parsed.minute;
231
+ this.activeSecond = parsed.second;
174
232
  }
175
233
  parseTimeStringToComponents(timeStr) {
176
234
  const parts = timeStr.trim().split(' ');
@@ -228,25 +286,49 @@ class BkTimePicker {
228
286
  this.showPicker = true;
229
287
  this.parseTimeValue(this._modelValue);
230
288
  this.pickerOpened.emit(this.pickerId);
289
+ if (this.autoPosition || this.appendToBody) {
290
+ this.attachViewportListeners();
291
+ // Measure once the dropdown is in the DOM, before it becomes visible to the user.
292
+ setTimeout(() => {
293
+ // Relocate to <body> first so no transformed/overflow ancestor can re-anchor the fixed
294
+ // dropdown, then compute viewport coordinates.
295
+ if (this.appendToBody)
296
+ this.moveDropdownToBody();
297
+ this.updatePosition();
298
+ }, 0);
299
+ }
231
300
  setTimeout(() => this.scrollToSelectedTimes(), 100);
232
301
  }
233
302
  else {
234
- this.showPicker = false;
235
- this.markAsTouched();
236
- this.pickerClosed.emit(this.pickerId);
303
+ this.dismiss();
237
304
  }
238
305
  }
306
+ /** Central close path so listeners are always detached and events emitted once. */
307
+ dismiss() {
308
+ if (!this.showPicker)
309
+ return;
310
+ // Put the dropdown back before showPicker=false so *ngIf removes it from the right parent on the
311
+ // next change-detection pass (avoids leaving an orphan node in <body>).
312
+ this.restoreDropdownFromBody();
313
+ this.showPicker = false;
314
+ this.detachViewportListeners();
315
+ this.markAsTouched();
316
+ this.pickerClosed.emit(this.pickerId);
317
+ }
239
318
  /* ---------------- Change handlers ---------------- */
240
319
  onHourChange(hour) {
241
320
  this.currentHour = hour;
321
+ this.activeHour = hour;
242
322
  this.updateTime();
243
323
  }
244
324
  onMinuteChange(minute) {
245
325
  this.currentMinute = minute;
326
+ this.activeMinute = minute;
246
327
  this.updateTime();
247
328
  }
248
329
  onSecondChange(second) {
249
330
  this.currentSecond = second;
331
+ this.activeSecond = second;
250
332
  this.updateTime();
251
333
  }
252
334
  onAMPMChange(ampm) {
@@ -262,40 +344,41 @@ class BkTimePicker {
262
344
  this.timeChange.emit(newTime);
263
345
  }
264
346
  /* ---------------- Scroll ---------------- */
347
+ /** Position each column so the committed value sits at the top of its viewport. */
265
348
  scrollToSelectedTimes() {
266
- this.timeScrollElements.forEach((elRef) => {
267
- const element = elRef.nativeElement;
268
- const selected = element.querySelector('.time-item.selected');
269
- if (selected) {
270
- element.scrollTop =
271
- selected.offsetTop -
272
- element.offsetHeight / 2 +
273
- selected.offsetHeight / 2;
274
- }
275
- });
276
- this.initMinuteWheelScroll();
349
+ this.scrollColumnTo(this.hourScrollEl, this.getHours().indexOf(this.currentHour));
350
+ this.scrollColumnTo(this.minuteScrollEl, this.currentMinute);
277
351
  if (this.showSeconds)
278
- this.initSecondWheelScroll();
352
+ this.scrollColumnTo(this.secondScrollEl, this.currentSecond);
279
353
  }
280
- initMinuteWheelScroll() {
281
- const el = this.minuteScrollElements?.first?.nativeElement;
282
- if (!el)
354
+ scrollColumnTo(ref, index) {
355
+ const el = ref?.nativeElement;
356
+ if (!el || index < 0)
283
357
  return;
284
- el.scrollTop = this.MIDDLE_OFFSET + this.currentMinute * this.ITEM_HEIGHT;
358
+ // Center the value in the viewport; the browser clamps at the top/bottom edges, which
359
+ // keeps the ~3 visible rows filled with real values instead of blank space.
360
+ el.scrollTop = index * this.ITEM_HEIGHT - el.clientHeight / 2 + this.ITEM_HEIGHT / 2;
285
361
  }
286
- initSecondWheelScroll() {
287
- const el = this.secondScrollElements?.first?.nativeElement;
362
+ /** Item nearest the viewport center for the current scroll position, clamped to [0, count - 1]. */
363
+ scrollIndex(ref, count) {
364
+ const el = ref?.nativeElement;
288
365
  if (!el)
289
- return;
290
- el.scrollTop = this.MIDDLE_OFFSET + this.currentSecond * this.ITEM_HEIGHT;
366
+ return -1;
367
+ const center = el.scrollTop + el.clientHeight / 2;
368
+ const index = Math.round((center - this.ITEM_HEIGHT / 2) / this.ITEM_HEIGHT);
369
+ return Math.min(Math.max(index, 0), count - 1);
291
370
  }
292
371
  /* ---------------- Outside click ---------------- */
293
372
  onDocumentClick(event) {
373
+ if (!this.showPicker)
374
+ return;
294
375
  const target = event.target;
295
- if (!target.closest('.time-picker-wrapper') && this.showPicker) {
296
- this.showPicker = false;
297
- this.markAsTouched();
298
- this.pickerClosed.emit(this.pickerId);
376
+ // When appendToBody has relocated the dropdown to <body>, it is no longer inside
377
+ // .time-picker-wrapper, so also treat clicks within the dropdown itself as "inside".
378
+ const dropdownEl = this.tpDropdown?.nativeElement;
379
+ const insideDropdown = !!dropdownEl && (dropdownEl === target || dropdownEl.contains(target));
380
+ if (!target.closest('.time-picker-wrapper') && !insideDropdown) {
381
+ this.dismiss();
299
382
  }
300
383
  }
301
384
  previousCloseCounter = 0;
@@ -308,56 +391,166 @@ class BkTimePicker {
308
391
  getAMPMOptions() {
309
392
  return ['PM', 'AM'];
310
393
  }
311
- onMinuteWheelScroll() {
312
- const el = this.minuteScrollElements?.first?.nativeElement;
313
- if (!el)
394
+ // Scrolling any column only moves its highlight; the value is committed on click.
395
+ onHourScroll() {
396
+ const idx = this.scrollIndex(this.hourScrollEl, this.getHours().length);
397
+ if (idx < 0)
314
398
  return;
315
- let scrollTop = el.scrollTop;
316
- const maxScroll = this.MIDDLE_OFFSET * 2 - 50;
317
- if (scrollTop < this.MIDDLE_OFFSET - 100) {
318
- scrollTop += this.MIDDLE_OFFSET;
319
- el.scrollTop = scrollTop;
320
- }
321
- else if (scrollTop > maxScroll) {
322
- scrollTop -= this.MIDDLE_OFFSET;
323
- el.scrollTop = scrollTop;
399
+ this.activeHour = this.getHours()[idx];
400
+ }
401
+ onMinuteScroll() {
402
+ const idx = this.scrollIndex(this.minuteScrollEl, this.minutes.length);
403
+ if (idx < 0)
404
+ return;
405
+ this.activeMinute = idx;
406
+ }
407
+ onSecondScroll() {
408
+ const idx = this.scrollIndex(this.secondScrollEl, this.seconds.length);
409
+ if (idx < 0)
410
+ return;
411
+ this.activeSecond = idx;
412
+ }
413
+ /* ---------------- Overlay positioning (auto-flip / appendToBody) ---------------- */
414
+ /**
415
+ * Resolve the dropdown placement against the current viewport.
416
+ * - autoPosition: flip above when there isn't room below, and flip the horizontal
417
+ * side when the preferred side would overflow.
418
+ * - appendToBody: additionally anchor with `position: fixed` (inline style) so the
419
+ * dropdown escapes ancestor overflow and follows the trigger on scroll.
420
+ */
421
+ updatePosition() {
422
+ if (!this.showPicker)
423
+ return;
424
+ const trigger = this.tpWrapper?.nativeElement;
425
+ const dropdown = this.tpDropdown?.nativeElement;
426
+ if (!trigger || !dropdown)
427
+ return;
428
+ const rect = trigger.getBoundingClientRect();
429
+ const height = dropdown.offsetHeight || 140;
430
+ const width = dropdown.offsetWidth || 182;
431
+ const margin = 8;
432
+ const gap = 4;
433
+ // Vertical: flip above only when there isn't enough room below and there's more room above.
434
+ const spaceBelow = window.innerHeight - rect.bottom;
435
+ const spaceAbove = rect.top;
436
+ this.placeAbove =
437
+ this.autoPosition && spaceBelow < height + margin && spaceAbove > spaceBelow;
438
+ // Horizontal: start from the requested side, flip if it would overflow that edge.
439
+ const viewportW = window.innerWidth;
440
+ let side = this.position;
441
+ if (this.autoPosition) {
442
+ if (side === 'left' && rect.left + width > viewportW - margin)
443
+ side = 'right';
444
+ else if (side === 'right' && rect.right - width < margin)
445
+ side = 'left';
446
+ }
447
+ this.resolvedPosition = side;
448
+ if (this.appendToBody) {
449
+ let left = side === 'right' ? rect.right - width : rect.left;
450
+ // Clamp so it never leaves the viewport, regardless of the flip decision above.
451
+ left = Math.min(left, viewportW - width - margin);
452
+ left = Math.max(left, margin);
453
+ this.dropdownStyle = this.placeAbove
454
+ ? {
455
+ position: 'fixed',
456
+ top: 'auto',
457
+ bottom: `${window.innerHeight - rect.top + gap}px`,
458
+ left: `${left}px`,
459
+ right: 'auto',
460
+ 'z-index': '100000',
461
+ }
462
+ : {
463
+ position: 'fixed',
464
+ top: `${rect.bottom + gap}px`,
465
+ left: `${left}px`,
466
+ right: 'auto',
467
+ 'z-index': '100000',
468
+ };
324
469
  }
325
- const index = Math.round(scrollTop / this.ITEM_HEIGHT);
326
- const value = ((index % this.WHEEL_CYCLE) + this.WHEEL_CYCLE) % this.WHEEL_CYCLE;
327
- if (value !== this.currentMinute) {
328
- this.currentMinute = value;
329
- this.updateTime();
470
+ else {
471
+ // Non-appendToBody stays absolute; placement is driven by CSS classes only.
472
+ this.dropdownStyle = {};
330
473
  }
331
474
  }
332
- onSecondWheelScroll() {
333
- const el = this.secondScrollElements?.first?.nativeElement;
334
- if (!el)
475
+ viewportListenersAttached = false;
476
+ viewportRafId = null;
477
+ onViewportChange = () => {
478
+ if (this.viewportRafId != null)
479
+ return;
480
+ this.viewportRafId = requestAnimationFrame(() => {
481
+ this.viewportRafId = null;
482
+ this.handleViewportChange();
483
+ });
484
+ };
485
+ handleViewportChange() {
486
+ if (!this.showPicker)
335
487
  return;
336
- let scrollTop = el.scrollTop;
337
- const maxScroll = this.MIDDLE_OFFSET * 2 - 50;
338
- if (scrollTop < this.MIDDLE_OFFSET - 100) {
339
- scrollTop += this.MIDDLE_OFFSET;
340
- el.scrollTop = scrollTop;
488
+ if (this.appendToBody) {
489
+ const rect = this.tpWrapper?.nativeElement?.getBoundingClientRect();
490
+ if (!rect)
491
+ return;
492
+ if (this.isTriggerOutOfView(rect)) {
493
+ this.dismiss();
494
+ return;
495
+ }
341
496
  }
342
- else if (scrollTop > maxScroll) {
343
- scrollTop -= this.MIDDLE_OFFSET;
344
- el.scrollTop = scrollTop;
497
+ this.updatePosition();
498
+ }
499
+ /** True when the trigger has scrolled out of the viewport or out of any clipping ancestor. */
500
+ isTriggerOutOfView(rect) {
501
+ if (rect.bottom <= 0 || rect.top >= window.innerHeight)
502
+ return true;
503
+ let el = this.tpWrapper?.nativeElement?.parentElement ?? null;
504
+ while (el && el !== document.body && el !== document.documentElement) {
505
+ if (this.isScrollClippingContainer(el)) {
506
+ const c = el.getBoundingClientRect();
507
+ if (rect.bottom <= c.top || rect.top >= c.bottom || rect.right <= c.left || rect.left >= c.right) {
508
+ return true;
509
+ }
510
+ }
511
+ el = el.parentElement;
345
512
  }
346
- const index = Math.round(scrollTop / this.ITEM_HEIGHT);
347
- const value = ((index % this.WHEEL_CYCLE) + this.WHEEL_CYCLE) % this.WHEEL_CYCLE;
348
- if (value !== this.currentSecond) {
349
- this.currentSecond = value;
350
- this.updateTime();
513
+ return false;
514
+ }
515
+ isScrollClippingContainer(el) {
516
+ const style = getComputedStyle(el);
517
+ const clipsY = /(auto|scroll|hidden)/.test(style.overflowY) && el.scrollHeight > el.clientHeight;
518
+ const clipsX = /(auto|scroll|hidden)/.test(style.overflowX) && el.scrollWidth > el.clientWidth;
519
+ return clipsY || clipsX;
520
+ }
521
+ attachViewportListeners() {
522
+ if (this.viewportListenersAttached)
523
+ return;
524
+ // Capture phase so nested scroll containers (dialog bodies, panels) are caught too.
525
+ document.addEventListener('scroll', this.onViewportChange, true);
526
+ window.addEventListener('resize', this.onViewportChange);
527
+ this.viewportListenersAttached = true;
528
+ }
529
+ detachViewportListeners() {
530
+ if (!this.viewportListenersAttached)
531
+ return;
532
+ document.removeEventListener('scroll', this.onViewportChange, true);
533
+ window.removeEventListener('resize', this.onViewportChange);
534
+ this.viewportListenersAttached = false;
535
+ if (this.viewportRafId != null) {
536
+ cancelAnimationFrame(this.viewportRafId);
537
+ this.viewportRafId = null;
351
538
  }
352
539
  }
353
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTimePicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
354
- 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", disabled: "disabled" }, outputs: { change: "change", timeChange: "timeChange", pickerOpened: "pickerOpened", pickerClosed: "pickerClosed" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, providers: [
540
+ ngOnDestroy() {
541
+ this.detachViewportListeners();
542
+ // If destroyed while open with the dropdown relocated to <body>, put it back so Angular's
543
+ // teardown removes it from the expected parent instead of leaving an orphan node in <body>.
544
+ this.restoreDropdownFromBody();
545
+ }
546
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTimePicker, deps: [{ token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component });
547
+ 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: [
355
548
  {
356
549
  provide: NG_VALUE_ACCESSOR,
357
550
  useExisting: forwardRef(() => BkTimePicker),
358
551
  multi: true,
359
552
  },
360
- ], viewQueries: [{ propertyName: "timeScrollElements", predicate: ["timeScroll"], descendants: true }, { propertyName: "minuteScrollElements", predicate: ["minuteScroll"], descendants: true }, { propertyName: "secondScrollElements", predicate: ["secondScroll"], 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\">\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 class=\"custom-time-picker\"\r\n [ngClass]=\"{\r\n 'left-position': position === 'left',\r\n 'right-position': position === 'right',\r\n 'format-24': timeFormat === 24,\r\n }\"\r\n >\r\n <!-- Hours Column -->\r\n <div class=\"time-column\">\r\n <div class=\"time-scroll\" #timeScroll>\r\n <div\r\n *ngFor=\"let h of getHours()\"\r\n class=\"time-item\"\r\n [class.selected]=\"currentHour === h\"\r\n (click)=\"onHourChange(h)\"\r\n >\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 (cyclic wheel: 59 -> 00) -->\r\n <div class=\"time-column\">\r\n <div class=\"time-scroll time-wheel\" #minuteScroll (scroll)=\"onMinuteWheelScroll()\">\r\n <div\r\n *ngFor=\"let m of wheelMinutes\"\r\n class=\"time-item\"\r\n [class.selected]=\"currentMinute === 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 (cyclic wheel: 59 -> 00) -->\r\n <div class=\"time-column\">\r\n <div class=\"time-scroll time-wheel\" #secondScroll (scroll)=\"onSecondWheelScroll()\">\r\n <div\r\n *ngFor=\"let s of wheelSeconds\"\r\n class=\"time-item\"\r\n [class.selected]=\"currentSecond === 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\" #timeScroll>\r\n <div\r\n *ngFor=\"let ap of getAMPMOptions()\"\r\n class=\"time-item\"\r\n [class.selected]=\"currentAMPM === ap\"\r\n (click)=\"onAMPMChange(ap)\"\r\n >\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}.time-column{display:flex;flex-direction:column;position:relative}.time-scroll{display:flex;flex-direction:column;max-height:95px;overflow-y:auto;overflow-x:hidden;scrollbar-width:thin;scrollbar-color:#cbd5e1 transparent;scrollbar-width:none;-ms-overflow-style:none}.time-scroll::-webkit-scrollbar{display:none}.time-scroll::-webkit-scrollbar-track{background:transparent}.time-scroll::-webkit-scrollbar-thumb{background:#cbd5e1;border-radius:2px}.time-scroll::-webkit-scrollbar-thumb:hover{background:#94a3b8}.time-item{min-width:40px;width:40px;height:32px;min-height:32px;display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:400;color:#374151;cursor:pointer;border-radius:4px;transition:all .15s ease;-webkit-user-select:none;user-select:none;font-family:Inter,sans-serif}.time-item:hover{background:#f3f4f6}.time-item.selected{background:#111827;color:#fff;font-weight:500}.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}\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 }] });
553
+ ], 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 }] });
361
554
  }
362
555
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTimePicker, decorators: [{
363
556
  type: Component,
@@ -367,8 +560,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
367
560
  useExisting: forwardRef(() => BkTimePicker),
368
561
  multi: true,
369
562
  },
370
- ], 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\">\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 class=\"custom-time-picker\"\r\n [ngClass]=\"{\r\n 'left-position': position === 'left',\r\n 'right-position': position === 'right',\r\n 'format-24': timeFormat === 24,\r\n }\"\r\n >\r\n <!-- Hours Column -->\r\n <div class=\"time-column\">\r\n <div class=\"time-scroll\" #timeScroll>\r\n <div\r\n *ngFor=\"let h of getHours()\"\r\n class=\"time-item\"\r\n [class.selected]=\"currentHour === h\"\r\n (click)=\"onHourChange(h)\"\r\n >\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 (cyclic wheel: 59 -> 00) -->\r\n <div class=\"time-column\">\r\n <div class=\"time-scroll time-wheel\" #minuteScroll (scroll)=\"onMinuteWheelScroll()\">\r\n <div\r\n *ngFor=\"let m of wheelMinutes\"\r\n class=\"time-item\"\r\n [class.selected]=\"currentMinute === 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 (cyclic wheel: 59 -> 00) -->\r\n <div class=\"time-column\">\r\n <div class=\"time-scroll time-wheel\" #secondScroll (scroll)=\"onSecondWheelScroll()\">\r\n <div\r\n *ngFor=\"let s of wheelSeconds\"\r\n class=\"time-item\"\r\n [class.selected]=\"currentSecond === 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\" #timeScroll>\r\n <div\r\n *ngFor=\"let ap of getAMPMOptions()\"\r\n class=\"time-item\"\r\n [class.selected]=\"currentAMPM === ap\"\r\n (click)=\"onAMPMChange(ap)\"\r\n >\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}.time-column{display:flex;flex-direction:column;position:relative}.time-scroll{display:flex;flex-direction:column;max-height:95px;overflow-y:auto;overflow-x:hidden;scrollbar-width:thin;scrollbar-color:#cbd5e1 transparent;scrollbar-width:none;-ms-overflow-style:none}.time-scroll::-webkit-scrollbar{display:none}.time-scroll::-webkit-scrollbar-track{background:transparent}.time-scroll::-webkit-scrollbar-thumb{background:#cbd5e1;border-radius:2px}.time-scroll::-webkit-scrollbar-thumb:hover{background:#94a3b8}.time-item{min-width:40px;width:40px;height:32px;min-height:32px;display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:400;color:#374151;cursor:pointer;border-radius:4px;transition:all .15s ease;-webkit-user-select:none;user-select:none;font-family:Inter,sans-serif}.time-item:hover{background:#f3f4f6}.time-item.selected{background:#111827;color:#fff;font-weight:500}.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}\n"] }]
371
- }], propDecorators: { required: [{
563
+ ], 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"] }]
564
+ }], ctorParameters: () => [{ type: i0.Renderer2 }], propDecorators: { required: [{
372
565
  type: Input
373
566
  }], value: [{
374
567
  type: Input
@@ -390,6 +583,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
390
583
  type: Input
391
584
  }], showSeconds: [{
392
585
  type: Input
586
+ }], autoPosition: [{
587
+ type: Input
588
+ }], appendToBody: [{
589
+ type: Input
393
590
  }], change: [{
394
591
  type: Output
395
592
  }], timeChange: [{
@@ -400,15 +597,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
400
597
  type: Output
401
598
  }], disabled: [{
402
599
  type: Input
403
- }], timeScrollElements: [{
404
- type: ViewChildren,
405
- args: ['timeScroll']
406
- }], minuteScrollElements: [{
407
- type: ViewChildren,
600
+ }], hourScrollEl: [{
601
+ type: ViewChild,
602
+ args: ['hourScroll']
603
+ }], minuteScrollEl: [{
604
+ type: ViewChild,
408
605
  args: ['minuteScroll']
409
- }], secondScrollElements: [{
410
- type: ViewChildren,
606
+ }], secondScrollEl: [{
607
+ type: ViewChild,
411
608
  args: ['secondScroll']
609
+ }], tpWrapper: [{
610
+ type: ViewChild,
611
+ args: ['tpWrapper']
612
+ }], tpDropdown: [{
613
+ type: ViewChild,
614
+ args: ['tpDropdown']
412
615
  }], onDocumentClick: [{
413
616
  type: HostListener,
414
617
  args: ['document:click', ['$event']]
@@ -536,6 +739,7 @@ class CalendarSelection {
536
739
  }
537
740
  class BkCustomCalendar {
538
741
  calendarManager;
742
+ renderer;
539
743
  // Basic Options
540
744
  enableTimepicker = false;
541
745
  autoApply = false;
@@ -648,8 +852,52 @@ class BkCustomCalendar {
648
852
  unregisterFn;
649
853
  closeAllSubscription;
650
854
  closeFn;
651
- constructor(calendarManager) {
855
+ constructor(calendarManager, renderer) {
652
856
  this.calendarManager = calendarManager;
857
+ this.renderer = renderer;
858
+ }
859
+ /**
860
+ * appendToBody popup relocation.
861
+ *
862
+ * `appendToBody` uses `position: fixed`, which only anchors to the viewport when NO ancestor
863
+ * establishes a containing block (transform / filter / perspective / will-change / contain /
864
+ * backdrop-filter). Consumers frequently place the calendar inside such an ancestor (an animated
865
+ * panel, a CSS-transformed modal, etc.), which silently re-anchors the fixed popup and pushes it
866
+ * off-position. To be robust everywhere we physically move the popup node to <body> while it is
867
+ * open, then move it back before Angular's *ngIf tears it down. Angular keeps managing the node by
868
+ * reference after the move, so its event bindings, change detection, and emulated-encapsulation
869
+ * styles all continue to work.
870
+ */
871
+ popupMovedToBody = false;
872
+ popupOriginalParent = null;
873
+ popupOriginalNextSibling = null;
874
+ movePopupToBody() {
875
+ const el = this.calendarPopupRef?.nativeElement;
876
+ if (!el || this.popupMovedToBody)
877
+ return;
878
+ this.popupOriginalParent = el.parentElement;
879
+ this.popupOriginalNextSibling = el.nextSibling;
880
+ this.renderer.appendChild(document.body, el);
881
+ this.popupMovedToBody = true;
882
+ }
883
+ /** Return the popup to its original DOM slot so *ngIf can destroy it cleanly (safe to call twice). */
884
+ restorePopupFromBody() {
885
+ if (!this.popupMovedToBody)
886
+ return;
887
+ const el = this.calendarPopupRef?.nativeElement;
888
+ const parent = this.popupOriginalParent;
889
+ if (el && parent) {
890
+ const ref = this.popupOriginalNextSibling;
891
+ if (ref && ref.parentNode === parent) {
892
+ this.renderer.insertBefore(parent, el, ref);
893
+ }
894
+ else {
895
+ this.renderer.appendChild(parent, el);
896
+ }
897
+ }
898
+ this.popupMovedToBody = false;
899
+ this.popupOriginalParent = null;
900
+ this.popupOriginalNextSibling = null;
653
901
  }
654
902
  /** Weekday headers; falls back to Mon–Sun if the input is not length 7. */
655
903
  get resolvedWeekDayLabels() {
@@ -685,7 +933,11 @@ class BkCustomCalendar {
685
933
  finishPopupDismissal() {
686
934
  if (this.inline)
687
935
  return;
936
+ this.detachViewportListeners();
688
937
  this.revertSingleDateDraftIfNeeded();
938
+ // Put the popup back in its original slot BEFORE show=false so *ngIf removes it from the right
939
+ // parent on the next change-detection pass (avoids leaving an orphan node in <body>).
940
+ this.restorePopupFromBody();
689
941
  this.show = false;
690
942
  this.onTouched();
691
943
  this.closed.emit();
@@ -919,18 +1171,105 @@ class BkCustomCalendar {
919
1171
  if (this.inline) {
920
1172
  return;
921
1173
  }
1174
+ if (!this.show)
1175
+ return;
922
1176
  const target = event.target;
923
- if (this.show && !target.closest('.calendar-container')) {
1177
+ // When appendToBody has relocated the popup to <body>, it is no longer a descendant of
1178
+ // .calendar-container, so also treat clicks within the popup element itself as "inside".
1179
+ const popupEl = this.calendarPopupRef?.nativeElement;
1180
+ const insidePopup = !!popupEl && (popupEl === target || popupEl.contains(target));
1181
+ if (!target.closest('.calendar-container') && !insidePopup) {
924
1182
  this.close();
925
1183
  }
926
1184
  }
927
- onWindowEvents() {
928
- if (this.show && this.appendToBody) {
929
- this.close();
1185
+ /** True while capture-phase scroll + resize listeners are attached (only while the popup is open). */
1186
+ viewportListenersAttached = false;
1187
+ /** Pending rAF id so bursts of scroll events collapse into one layout pass. */
1188
+ viewportRafId = null;
1189
+ /**
1190
+ * Recipe steps 2 & 4: while the popup is open, keep it glued to the trigger as the page
1191
+ * (or any nested scroll container) scrolls, and dismiss it once the trigger leaves the viewport.
1192
+ * Throttled through requestAnimationFrame to avoid layout thrash during fast scrolling.
1193
+ */
1194
+ onViewportChange = () => {
1195
+ if (this.viewportRafId != null)
930
1196
  return;
1197
+ this.viewportRafId = requestAnimationFrame(() => {
1198
+ this.viewportRafId = null;
1199
+ this.handleViewportChange();
1200
+ });
1201
+ };
1202
+ handleViewportChange() {
1203
+ if (!this.show || this.inline)
1204
+ return;
1205
+ if (this.appendToBody) {
1206
+ const trigger = this.inputWrapper?.nativeElement;
1207
+ if (!trigger)
1208
+ return;
1209
+ const rect = trigger.getBoundingClientRect();
1210
+ // Step 4: trigger scrolled fully out of view → close instead of leaving a floating panel behind.
1211
+ if (this.isTriggerOutOfView(rect)) {
1212
+ this.close();
1213
+ return;
1214
+ }
1215
+ // Step 2: re-anchor (and re-flip) so the panel follows the trigger.
1216
+ this.updatePosition();
1217
+ }
1218
+ else {
1219
+ // Absolute-positioned popups track the trigger natively; just re-evaluate the flip.
1220
+ this.refreshPopupPlacement();
931
1221
  }
932
- if (this.show && !this.inline && !this.appendToBody) {
933
- setTimeout(() => this.refreshPopupPlacement(), 0);
1222
+ }
1223
+ /**
1224
+ * Trigger is no longer visible and the fixed popup should be dismissed. True when the trigger is
1225
+ * either entirely outside the viewport, or clipped out of ANY ancestor scroll container — e.g.
1226
+ * scrolled behind the header/footer of a modal body. This makes step 4 work both on the plain
1227
+ * page and inside a dialog when `appendToBody` positions the popup with `fixed`.
1228
+ */
1229
+ isTriggerOutOfView(rect) {
1230
+ // 1. Fully above or below the viewport.
1231
+ if (rect.bottom <= 0 || rect.top >= window.innerHeight)
1232
+ return true;
1233
+ // 2. Fully clipped out of a scrollable ancestor (the modal body, a scroll pane, etc.).
1234
+ let el = this.inputWrapper?.nativeElement?.parentElement ?? null;
1235
+ while (el && el !== document.body && el !== document.documentElement) {
1236
+ if (this.isScrollClippingContainer(el)) {
1237
+ const c = el.getBoundingClientRect();
1238
+ if (rect.bottom <= c.top ||
1239
+ rect.top >= c.bottom ||
1240
+ rect.right <= c.left ||
1241
+ rect.left >= c.right) {
1242
+ return true;
1243
+ }
1244
+ }
1245
+ el = el.parentElement;
1246
+ }
1247
+ return false;
1248
+ }
1249
+ /** An ancestor that clips overflowing content on an axis where its content actually overflows. */
1250
+ isScrollClippingContainer(el) {
1251
+ const style = getComputedStyle(el);
1252
+ const clipsY = /(auto|scroll|hidden)/.test(style.overflowY) && el.scrollHeight > el.clientHeight;
1253
+ const clipsX = /(auto|scroll|hidden)/.test(style.overflowX) && el.scrollWidth > el.clientWidth;
1254
+ return clipsY || clipsX;
1255
+ }
1256
+ attachViewportListeners() {
1257
+ if (this.viewportListenersAttached)
1258
+ return;
1259
+ // capture = true so scrolling inside ANY ancestor container fires this, not only window scroll.
1260
+ document.addEventListener('scroll', this.onViewportChange, true);
1261
+ window.addEventListener('resize', this.onViewportChange);
1262
+ this.viewportListenersAttached = true;
1263
+ }
1264
+ detachViewportListeners() {
1265
+ if (!this.viewportListenersAttached)
1266
+ return;
1267
+ document.removeEventListener('scroll', this.onViewportChange, true);
1268
+ window.removeEventListener('resize', this.onViewportChange);
1269
+ this.viewportListenersAttached = false;
1270
+ if (this.viewportRafId != null) {
1271
+ cancelAnimationFrame(this.viewportRafId);
1272
+ this.viewportRafId = null;
934
1273
  }
935
1274
  }
936
1275
  ngOnInit() {
@@ -994,6 +1333,11 @@ class BkCustomCalendar {
994
1333
  }
995
1334
  }
996
1335
  ngOnDestroy() {
1336
+ // Ensure global scroll/resize listeners never outlive the component
1337
+ this.detachViewportListeners();
1338
+ // If destroyed while open with the popup relocated to <body>, put it back so Angular's teardown
1339
+ // removes it from the expected parent instead of leaving an orphan node in <body>.
1340
+ this.restorePopupFromBody();
997
1341
  // Unregister this calendar instance
998
1342
  if (this.unregisterFn) {
999
1343
  this.unregisterFn();
@@ -1076,10 +1420,14 @@ class BkCustomCalendar {
1076
1420
  this.calendarManager.closeAllExcept(this.closeFn);
1077
1421
  }
1078
1422
  this.disableHighlight = false;
1423
+ this.attachViewportListeners();
1079
1424
  setTimeout(() => {
1080
1425
  this.initKeyboardFocus();
1081
1426
  this.calendarPopupRef?.nativeElement?.focus({ preventScroll: true });
1082
1427
  if (this.appendToBody && this.inputWrapper?.nativeElement) {
1428
+ // Move the popup out to <body> first so any transformed/overflow ancestor can no longer
1429
+ // re-anchor or clip its fixed positioning, then compute viewport coordinates.
1430
+ this.movePopupToBody();
1083
1431
  this.updatePosition();
1084
1432
  }
1085
1433
  else if (!this.inline) {
@@ -1097,23 +1445,65 @@ class BkCustomCalendar {
1097
1445
  if (!this.inputWrapper?.nativeElement)
1098
1446
  return;
1099
1447
  const rect = this.inputWrapper.nativeElement.getBoundingClientRect();
1100
- const popupH = this.calendarPopupRef?.nativeElement?.offsetHeight ?? 360;
1448
+ const popupEl = this.calendarPopupRef?.nativeElement;
1449
+ const popupH = popupEl?.offsetHeight ?? 360;
1450
+ const popupW = popupEl?.offsetWidth ?? 320;
1101
1451
  const placeAbove = this.computePlacementAbove(rect, popupH);
1102
1452
  this.popupPlacementAbove = placeAbove;
1453
+ const left = this.computePopupLeft(rect, popupW);
1103
1454
  const gap = 4;
1104
1455
  if (placeAbove) {
1105
1456
  this.dropdownStyle = {
1106
1457
  bottom: `${window.innerHeight - rect.top + gap}px`,
1107
- left: `${rect.left}px`,
1458
+ left: `${left}px`,
1108
1459
  };
1109
1460
  }
1110
1461
  else {
1111
1462
  this.dropdownStyle = {
1112
1463
  top: `${rect.bottom + gap}px`,
1113
- left: `${rect.left}px`,
1464
+ left: `${left}px`,
1114
1465
  };
1115
1466
  }
1116
1467
  }
1468
+ /**
1469
+ * Horizontal placement for the fixed (appendToBody) popup.
1470
+ *
1471
+ * The base edge follows the author's {@link opens} preference:
1472
+ * • 'left' → align left edges, panel opens rightwards (default)
1473
+ * • 'right' → align right edges, panel opens leftwards
1474
+ * • 'center' → centred on the trigger
1475
+ * When {@link autoPosition} is on, the panel auto-flips to the opposite edge if the preferred
1476
+ * side would overflow the viewport, then clamps to an 8px margin so it can never leave the screen.
1477
+ * When autoPosition is off, the explicit `opens` value is honoured as-is.
1478
+ */
1479
+ computePopupLeft(rect, popupWidth) {
1480
+ const margin = 8;
1481
+ const viewportW = window.innerWidth;
1482
+ // 1. Base alignment from the user-provided `opens`.
1483
+ let left;
1484
+ if (this.opens === 'right') {
1485
+ left = rect.right - popupWidth; // align right edges → opens leftwards
1486
+ }
1487
+ else if (this.opens === 'center') {
1488
+ left = rect.left + rect.width / 2 - popupWidth / 2;
1489
+ }
1490
+ else {
1491
+ left = rect.left; // align left edges → opens rightwards
1492
+ }
1493
+ if (!this.autoPosition)
1494
+ return left;
1495
+ // 2. Auto-flip to the opposite edge when the preferred side overflows the viewport.
1496
+ if (left + popupWidth > viewportW - margin) {
1497
+ left = rect.right - popupWidth; // flip: open leftwards
1498
+ }
1499
+ if (left < margin) {
1500
+ left = rect.left; // flip back: open rightwards
1501
+ }
1502
+ // 3. Final clamp so the panel always stays fully on screen on both edges.
1503
+ left = Math.min(left, viewportW - popupWidth - margin);
1504
+ left = Math.max(left, margin);
1505
+ return left;
1506
+ }
1117
1507
  /** Non–append-to-body: set `popupPlacementAbove` for CSS `drop-up` with viewport flip. */
1118
1508
  refreshPopupPlacement() {
1119
1509
  if (!this.inputWrapper?.nativeElement)
@@ -2654,8 +3044,8 @@ class BkCustomCalendar {
2654
3044
  const dd = date.getDate().toString().padStart(2, '0');
2655
3045
  return `${yyyy}-${mm}-${dd}`;
2656
3046
  }
2657
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkCustomCalendar, deps: [{ token: BkCalendarManagerService }], target: i0.ɵɵFactoryTarget.Component });
2658
- 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)", "window:scroll": "onWindowEvents()", "window:resize": "onWindowEvents()" } }, providers: [
3047
+ 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 });
3048
+ 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: [
2659
3049
  {
2660
3050
  provide: NG_VALUE_ACCESSOR,
2661
3051
  useExisting: forwardRef(() => BkCustomCalendar),
@@ -2666,7 +3056,7 @@ class BkCustomCalendar {
2666
3056
  useExisting: forwardRef(() => BkCustomCalendar),
2667
3057
  multi: true,
2668
3058
  },
2669
- ], 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.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: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.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", "disabled"], outputs: ["change", "timeChange", "pickerOpened", "pickerClosed"] }] });
3059
+ ], 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: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.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"] }] });
2670
3060
  }
2671
3061
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkCustomCalendar, decorators: [{
2672
3062
  type: Component,
@@ -2681,8 +3071,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
2681
3071
  useExisting: forwardRef(() => BkCustomCalendar),
2682
3072
  multi: true,
2683
3073
  },
2684
- ], 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.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"] }]
2685
- }], ctorParameters: () => [{ type: BkCalendarManagerService }], propDecorators: { enableTimepicker: [{
3074
+ ], 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"] }]
3075
+ }], ctorParameters: () => [{ type: BkCalendarManagerService }, { type: i0.Renderer2 }], propDecorators: { enableTimepicker: [{
2686
3076
  type: Input
2687
3077
  }], autoApply: [{
2688
3078
  type: Input
@@ -2771,12 +3161,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
2771
3161
  }], onClickOutside: [{
2772
3162
  type: HostListener,
2773
3163
  args: ['document:click', ['$event']]
2774
- }], onWindowEvents: [{
2775
- type: HostListener,
2776
- args: ['window:scroll']
2777
- }, {
2778
- type: HostListener,
2779
- args: ['window:resize']
2780
3164
  }] } });
2781
3165
 
2782
3166
  class BkScheduledDatePicker {
@@ -3082,7 +3466,7 @@ class BkScheduledDatePicker {
3082
3466
  this.emitScheduled();
3083
3467
  }
3084
3468
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkScheduledDatePicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
3085
- 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", "disabled"], outputs: ["change", "timeChange", "pickerOpened", "pickerClosed"] }] });
3469
+ 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"] }] });
3086
3470
  }
3087
3471
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkScheduledDatePicker, decorators: [{
3088
3472
  type: Component,
@@ -4519,6 +4903,7 @@ class BkSelect {
4519
4903
  optionsListContainer;
4520
4904
  optionsRef;
4521
4905
  controlWrapper;
4906
+ dropdownPanel;
4522
4907
  chipsViewport;
4523
4908
  measureChips;
4524
4909
  measurePlus;
@@ -4529,6 +4914,18 @@ class BkSelect {
4529
4914
  selectedOptions = signal([], ...(ngDevMode ? [{ debugName: "selectedOptions" }] : []));
4530
4915
  searchTerm = signal('', ...(ngDevMode ? [{ debugName: "searchTerm" }] : []));
4531
4916
  markedIndex = signal(-1, ...(ngDevMode ? [{ debugName: "markedIndex" }] : []));
4917
+ // Side the panel is actually rendered on. Starts from the requested
4918
+ // `dropdownPosition` but is auto-flipped based on available viewport space
4919
+ // (see applyPlacement). Used by both append-to-body and inline modes.
4920
+ placement = signal('bottom', ...(ngDevMode ? [{ debugName: "placement" }] : []));
4921
+ // When appendToBody is on we physically relocate the panel to <body> so it
4922
+ // escapes any transformed/overflow ancestor (e.g. an animated dialog, whose
4923
+ // residual transform would otherwise make position:fixed resolve against the
4924
+ // dialog and get clipped). These track the panel's home so we can put it back
4925
+ // before Angular removes it on close.
4926
+ originalPanelParent = null;
4927
+ originalPanelAnchor = null;
4928
+ panelInBody = false;
4532
4929
  // Number of multi-select chips currently rendered before collapsing into "+N".
4533
4930
  // Computed dynamically from the available width (see recomputeVisibleChips()).
4534
4931
  visibleCount = signal(0, ...(ngDevMode ? [{ debugName: "visibleCount" }] : []));
@@ -4579,9 +4976,96 @@ class BkSelect {
4579
4976
  }
4580
4977
  }
4581
4978
  this.scheduleRecompute();
4979
+ // Keep the append-to-body (fixed) panel glued to the control while any
4980
+ // ancestor scrolls or the window resizes. Capture phase (`true`) is what
4981
+ // lets us catch scrolling inside nested overflow containers, not just the
4982
+ // window — @HostListener('window:scroll') would miss those.
4983
+ window.addEventListener('scroll', this.reposition, true);
4984
+ window.addEventListener('resize', this.reposition);
4582
4985
  }
4583
4986
  ngOnDestroy() {
4584
4987
  this.resizeObserver?.disconnect();
4988
+ window.removeEventListener('scroll', this.reposition, true);
4989
+ window.removeEventListener('resize', this.reposition);
4990
+ // If we're torn down while open, don't leave the relocated panel orphaned in <body>.
4991
+ if (this.panelInBody) {
4992
+ this.dropdownPanel?.nativeElement.remove();
4993
+ this.panelInBody = false;
4994
+ }
4995
+ }
4996
+ // Re-evaluate placement as the page scrolls/resizes. For append-to-body this
4997
+ // recomputes the fixed coordinates so the panel follows the control while it's
4998
+ // visible, and closes once the control is fully scrolled out of view (by the
4999
+ // viewport OR any scroll container such as a modal body). Inline just re-flips.
5000
+ // Bound as an arrow fn so it can be add/removeEventListener'd.
5001
+ reposition = () => {
5002
+ if (!this.isOpen())
5003
+ return;
5004
+ if (this.appendToBody()) {
5005
+ const rect = this.controlWrapper?.nativeElement.getBoundingClientRect();
5006
+ if (rect && this.isControlClipped(rect)) {
5007
+ this.closeDropdown();
5008
+ return;
5009
+ }
5010
+ }
5011
+ this.applyPlacement();
5012
+ };
5013
+ /**
5014
+ * True when the control is fully outside the visible area — either the
5015
+ * viewport or a scrollable/clipping ancestor (e.g. a dialog's scroll body).
5016
+ * Used to close the floating (append-to-body) panel once its anchor is no
5017
+ * longer on screen, instead of leaving it hanging.
5018
+ */
5019
+ isControlClipped(rect) {
5020
+ // Outside the viewport.
5021
+ if (rect.bottom <= 0 || rect.top >= window.innerHeight ||
5022
+ rect.right <= 0 || rect.left >= window.innerWidth) {
5023
+ return true;
5024
+ }
5025
+ // Outside any clipping ancestor.
5026
+ let el = this.controlWrapper?.nativeElement.parentElement;
5027
+ while (el && el !== document.body) {
5028
+ const style = getComputedStyle(el);
5029
+ const clips = /(auto|scroll|hidden|clip|overlay)/;
5030
+ if (clips.test(style.overflowY) || clips.test(style.overflowX)) {
5031
+ const r = el.getBoundingClientRect();
5032
+ if (rect.bottom <= r.top || rect.top >= r.bottom ||
5033
+ rect.right <= r.left || rect.left >= r.right) {
5034
+ return true;
5035
+ }
5036
+ }
5037
+ el = el.parentElement;
5038
+ }
5039
+ return false;
5040
+ }
5041
+ /**
5042
+ * Relocate the panel node to <body> so it truly escapes any transformed or
5043
+ * overflow-clipped ancestor (dialogs, drawers, cards with overflow, etc.).
5044
+ * Setting position:fixed alone is not enough when an ancestor has a transform.
5045
+ */
5046
+ movePanelToBody() {
5047
+ const panel = this.dropdownPanel?.nativeElement;
5048
+ if (!panel || this.panelInBody)
5049
+ return;
5050
+ this.originalPanelParent = panel.parentNode;
5051
+ this.originalPanelAnchor = panel.nextSibling;
5052
+ document.body.appendChild(panel);
5053
+ this.panelInBody = true;
5054
+ }
5055
+ /**
5056
+ * Return the panel to its original DOM position so Angular's @if can remove
5057
+ * it cleanly on close. Must run before isOpen is set to false.
5058
+ */
5059
+ restorePanel() {
5060
+ const panel = this.dropdownPanel?.nativeElement;
5061
+ if (!panel || !this.panelInBody)
5062
+ return;
5063
+ if (this.originalPanelParent) {
5064
+ this.originalPanelParent.insertBefore(panel, this.originalPanelAnchor);
5065
+ }
5066
+ this.panelInBody = false;
5067
+ this.originalPanelParent = null;
5068
+ this.originalPanelAnchor = null;
4585
5069
  }
4586
5070
  scheduleRecompute() {
4587
5071
  // Defer to the next frame so the hidden measurement row has been laid out.
@@ -4684,13 +5168,21 @@ class BkSelect {
4684
5168
  BkSelect.activeInstance.closeDropdown();
4685
5169
  }
4686
5170
  BkSelect.activeInstance = this;
4687
- if (this.appendToBody()) {
4688
- this.updatePosition();
4689
- }
5171
+ // Decide the initial side before the panel paints (uses an estimated
5172
+ // height; corrected after render in the setTimeout below).
5173
+ this.applyPlacement();
4690
5174
  this.isOpen.set(true);
4691
5175
  this.open.emit();
4692
5176
  this.focus.emit();
4693
5177
  setTimeout(() => {
5178
+ // Panel is in the DOM now. In appendToBody mode, relocate it to <body>
5179
+ // so it escapes any transformed/overflow ancestor, then position it.
5180
+ if (this.appendToBody())
5181
+ this.movePanelToBody();
5182
+ // Recompute with the panel's real height so the initial up/down flip is
5183
+ // accurate (openDropdown ran applyPlacement() before the panel existed,
5184
+ // using an estimated height).
5185
+ this.applyPlacement();
4694
5186
  if (this.searchable()) {
4695
5187
  this.searchInput?.nativeElement.focus();
4696
5188
  }
@@ -4702,6 +5194,8 @@ class BkSelect {
4702
5194
  closeDropdown() {
4703
5195
  if (!this.isOpen())
4704
5196
  return;
5197
+ // Put the panel back where Angular expects it before the @if removes it.
5198
+ this.restorePanel();
4705
5199
  this.isOpen.set(false);
4706
5200
  this.searchTerm.set('');
4707
5201
  this.onTouched();
@@ -4715,42 +5209,70 @@ class BkSelect {
4715
5209
  if (this.appendToBody()) {
4716
5210
  return this.dropdownStyle().top ?? null;
4717
5211
  }
4718
- // NOT appendToBody
4719
- return this.dropdownPosition() === 'bottom' ? '105%' : null;
5212
+ // NOT appendToBody — use the auto-flipped placement, not the raw input.
5213
+ return this.placement() === 'bottom' ? '105%' : null;
4720
5214
  }
4721
5215
  getBottom() {
4722
5216
  if (this.appendToBody()) {
4723
5217
  return this.dropdownStyle().bottom ?? null;
4724
5218
  }
4725
- // NOT appendToBody
4726
- return this.dropdownPosition() === 'top' ? 'calc(100% + 4px)' : null;
5219
+ // NOT appendToBody — use the auto-flipped placement, not the raw input.
5220
+ return this.placement() === 'top' ? 'calc(100% + 4px)' : null;
4727
5221
  }
4728
- updatePosition() {
4729
- const rect = this.controlWrapper.nativeElement.getBoundingClientRect();
4730
- if (this.dropdownPosition() === 'bottom') {
5222
+ /**
5223
+ * Decides which side the panel should open on (auto-flip) and, for
5224
+ * append-to-body mode, computes the fixed coordinates. Shared by both modes
5225
+ * and re-run on open and on every scroll/resize so the panel snaps to
5226
+ * whichever side has room — honouring `dropdownPosition` when it fits.
5227
+ */
5228
+ applyPlacement() {
5229
+ const control = this.controlWrapper?.nativeElement;
5230
+ if (!control)
5231
+ return;
5232
+ const rect = control.getBoundingClientRect();
5233
+ const gap = 4;
5234
+ // Actual panel height once it's rendered; fall back to a sensible estimate
5235
+ // on the very first open (panel isn't in the DOM yet at that point — a
5236
+ // follow-up call after render corrects it with the real height).
5237
+ const panelHeight = this.dropdownPanel?.nativeElement.offsetHeight || 300;
5238
+ const spaceBelow = window.innerHeight - rect.bottom - gap;
5239
+ const spaceAbove = rect.top - gap;
5240
+ // Honour the requested position when it fits; otherwise flip to wherever
5241
+ // there's more room.
5242
+ const preferred = this.dropdownPosition();
5243
+ let placeTop;
5244
+ if (preferred === 'top') {
5245
+ placeTop = spaceAbove >= panelHeight || spaceAbove > spaceBelow;
5246
+ }
5247
+ else {
5248
+ placeTop = spaceBelow < panelHeight && spaceAbove > spaceBelow;
5249
+ }
5250
+ this.placement.set(placeTop ? 'top' : 'bottom');
5251
+ // Inline (absolute) mode is positioned by CSS relative to the control, so
5252
+ // the placement signal above is all it needs. Only append-to-body needs
5253
+ // explicit fixed coordinates.
5254
+ if (!this.appendToBody())
5255
+ return;
5256
+ if (placeTop) {
4731
5257
  this.dropdownStyle.set({
4732
- top: `${rect.bottom + 4}px`,
4733
- bottom: undefined,
5258
+ top: undefined,
5259
+ bottom: `${window.innerHeight - rect.top + gap}px`,
4734
5260
  left: `${rect.left}px`,
4735
5261
  width: `${rect.width}px`
4736
5262
  });
4737
5263
  }
4738
5264
  else {
4739
5265
  this.dropdownStyle.set({
4740
- top: undefined,
4741
- bottom: `${window.innerHeight - rect.top + 4}px`,
5266
+ top: `${rect.bottom + gap}px`,
5267
+ bottom: undefined,
4742
5268
  left: `${rect.left}px`,
4743
5269
  width: `${rect.width}px`
4744
5270
  });
4745
5271
  }
4746
5272
  }
4747
- // 2. FIXED: Removed ['$event'] argument
4748
- onWindowEvents() {
4749
- // Only close on scroll if we are in "fixed" mode (append to body)
4750
- if (this.isOpen() && this.appendToBody()) {
4751
- this.closeDropdown();
4752
- }
4753
- }
5273
+ // Scroll/resize are handled by the capture-phase listeners wired up in
5274
+ // ngAfterViewInit (see `reposition`), which keep the panel attached to the
5275
+ // control and re-flip it up/down as space allows, instead of closing it.
4754
5276
  // ... (toggleSelectAll, handleSelection, removeOption, handleClear logic same as before) ...
4755
5277
  toggleSelectAll(event) {
4756
5278
  event.stopPropagation();
@@ -4922,8 +5444,15 @@ class BkSelect {
4922
5444
  }
4923
5445
  el = inject(ElementRef);
4924
5446
  onClickOutside(e) {
4925
- if (!this.el.nativeElement.contains(e.target))
4926
- this.closeDropdown();
5447
+ const target = e.target;
5448
+ // When appendToBody relocates the panel to <body>, it's no longer inside
5449
+ // the host element — treat clicks within the panel as "inside" too so
5450
+ // interacting with the search box / scrollbar doesn't close it.
5451
+ if (this.el.nativeElement.contains(target))
5452
+ return;
5453
+ if (this.dropdownPanel?.nativeElement.contains(target))
5454
+ return;
5455
+ this.closeDropdown();
4927
5456
  }
4928
5457
  openFromLabel(event) {
4929
5458
  event.preventDefault();
@@ -4977,13 +5506,13 @@ class BkSelect {
4977
5506
  this.markedIndex.set(index);
4978
5507
  }
4979
5508
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkSelect, deps: [], target: i0.ɵɵFactoryTarget.Component });
4980
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkSelect, isStandalone: true, selector: "bk-select", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, bindLabel: { classPropertyName: "bindLabel", publicName: "bindLabel", isSignal: true, isRequired: false, transformFunction: null }, bindValue: { classPropertyName: "bindValue", publicName: "bindValue", isSignal: true, isRequired: false, transformFunction: null }, bindIcon: { classPropertyName: "bindIcon", publicName: "bindIcon", isSignal: true, isRequired: false, transformFunction: null }, isResponsive: { classPropertyName: "isResponsive", publicName: "isResponsive", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, notFoundText: { classPropertyName: "notFoundText", publicName: "notFoundText", isSignal: true, isRequired: false, transformFunction: null }, loadingText: { classPropertyName: "loadingText", publicName: "loadingText", isSignal: true, isRequired: false, transformFunction: null }, clearAllText: { classPropertyName: "clearAllText", publicName: "clearAllText", isSignal: true, isRequired: false, transformFunction: null }, groupBy: { classPropertyName: "groupBy", publicName: "groupBy", isSignal: true, isRequired: false, transformFunction: null }, colorKey: { classPropertyName: "colorKey", publicName: "colorKey", isSignal: true, isRequired: false, transformFunction: null }, iconAlt: { classPropertyName: "iconAlt", publicName: "iconAlt", isSignal: false, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: false, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: false, isRequired: false, transformFunction: null }, variation: { classPropertyName: "variation", publicName: "variation", isSignal: false, isRequired: false, transformFunction: null }, iconSrc: { classPropertyName: "iconSrc", publicName: "iconSrc", isSignal: false, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, maxLabels: { classPropertyName: "maxLabels", publicName: "maxLabels", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, allSelect: { classPropertyName: "allSelect", publicName: "allSelect", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, closeOnSelect: { classPropertyName: "closeOnSelect", publicName: "closeOnSelect", isSignal: true, isRequired: false, transformFunction: null }, dropdownPosition: { classPropertyName: "dropdownPosition", publicName: "dropdownPosition", isSignal: true, isRequired: false, transformFunction: null }, hasError: { classPropertyName: "hasError", publicName: "hasError", isSignal: false, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: false, isRequired: false, transformFunction: null }, appendToBody: { classPropertyName: "appendToBody", publicName: "appendToBody", isSignal: true, isRequired: false, transformFunction: null }, compareWith: { classPropertyName: "compareWith", publicName: "compareWith", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { disabled: "disabledChange", open: "open", close: "close", focus: "focus", blur: "blur", search: "search", clear: "clear", change: "change", scrollToEnd: "scrollToEnd" }, host: { listeners: { "window:scroll": "onWindowEvents()", "window:resize": "onWindowEvents()", "document:click": "onClickOutside($event)" } }, providers: [
5509
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkSelect, isStandalone: true, selector: "bk-select", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, bindLabel: { classPropertyName: "bindLabel", publicName: "bindLabel", isSignal: true, isRequired: false, transformFunction: null }, bindValue: { classPropertyName: "bindValue", publicName: "bindValue", isSignal: true, isRequired: false, transformFunction: null }, bindIcon: { classPropertyName: "bindIcon", publicName: "bindIcon", isSignal: true, isRequired: false, transformFunction: null }, isResponsive: { classPropertyName: "isResponsive", publicName: "isResponsive", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, notFoundText: { classPropertyName: "notFoundText", publicName: "notFoundText", isSignal: true, isRequired: false, transformFunction: null }, loadingText: { classPropertyName: "loadingText", publicName: "loadingText", isSignal: true, isRequired: false, transformFunction: null }, clearAllText: { classPropertyName: "clearAllText", publicName: "clearAllText", isSignal: true, isRequired: false, transformFunction: null }, groupBy: { classPropertyName: "groupBy", publicName: "groupBy", isSignal: true, isRequired: false, transformFunction: null }, colorKey: { classPropertyName: "colorKey", publicName: "colorKey", isSignal: true, isRequired: false, transformFunction: null }, iconAlt: { classPropertyName: "iconAlt", publicName: "iconAlt", isSignal: false, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: false, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: false, isRequired: false, transformFunction: null }, variation: { classPropertyName: "variation", publicName: "variation", isSignal: false, isRequired: false, transformFunction: null }, iconSrc: { classPropertyName: "iconSrc", publicName: "iconSrc", isSignal: false, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, maxLabels: { classPropertyName: "maxLabels", publicName: "maxLabels", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, allSelect: { classPropertyName: "allSelect", publicName: "allSelect", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, closeOnSelect: { classPropertyName: "closeOnSelect", publicName: "closeOnSelect", isSignal: true, isRequired: false, transformFunction: null }, dropdownPosition: { classPropertyName: "dropdownPosition", publicName: "dropdownPosition", isSignal: true, isRequired: false, transformFunction: null }, hasError: { classPropertyName: "hasError", publicName: "hasError", isSignal: false, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: false, isRequired: false, transformFunction: null }, appendToBody: { classPropertyName: "appendToBody", publicName: "appendToBody", isSignal: true, isRequired: false, transformFunction: null }, compareWith: { classPropertyName: "compareWith", publicName: "compareWith", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { disabled: "disabledChange", open: "open", close: "close", focus: "focus", blur: "blur", search: "search", clear: "clear", change: "change", scrollToEnd: "scrollToEnd" }, host: { listeners: { "document:click": "onClickOutside($event)" } }, providers: [
4981
5510
  {
4982
5511
  provide: NG_VALUE_ACCESSOR,
4983
5512
  useExisting: forwardRef(() => BkSelect),
4984
5513
  multi: true
4985
5514
  }
4986
- ], 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: "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\">\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 <div\r\n #controlWrapper\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 (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 #chipsViewport class=\"bk-value-chips bk-chips-viewport flex gap-0.5 flex-nowrap h-[18px] overflow-hidden\">\r\n @for (opt of selectedOptions().slice(0, visibleCount()); track $index) {\r\n <div class=\"bk-multi-badge-item me-0.5\">\r\n @if (resolveIcon(opt)) {\r\n <img [src]=\"resolveIcon(opt)!\" alt=\"icon\" class=\"bk-chip-icon shrink-0\" />\r\n }\r\n <span #badgeTextEl class=\"bk-multi-badge-item-text\" [style.color]=\"resolveColor(opt)\"\r\n [bkTooltip]=\"getTooltipIfEllipsed(badgeTextEl, resolveLabel(opt))\"\r\n bkTooltipPosition=\"top\">{{\r\n resolveLabel(opt)\r\n }}</span>\r\n\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 </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 >+{{ 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\">\r\n @if (resolveIcon(opt)) {\r\n <img [src]=\"resolveIcon(opt)!\" alt=\"icon\" class=\"bk-chip-icon shrink-0\" />\r\n }\r\n <span class=\"bk-multi-badge-item-text\">{{ resolveLabel(opt) }}</span>\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 </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 @if (resolveIcon(selectedOptions()[0])) {\r\n <img [src]=\"resolveIcon(selectedOptions()[0])!\" alt=\"icon\" class=\"bk-option-icon shrink-0\" />\r\n }\r\n <div #singleValueEl class=\"bk-value-label-single\" [style.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 && !disabled()) {\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 @if (isOpen()) {\r\n <div\r\n #dropdownPanel\r\n tabindex=\"-1\"\r\n (keydown)=\"onTabPress($event)\"\r\n class=\"bk-dropdown-panel\"\r\n [attr.data-position]=\"dropdownPosition()\"\r\n [style.position]=\"appendToBody() ? 'fixed' : 'absolute'\"\r\n [style.top]=\"getTop()\"\r\n [style.bottom]=\"getBottom()\"\r\n [style.left]=\"appendToBody() ? dropdownStyle().left : null\"\r\n [style.width]=\"appendToBody() ? dropdownStyle().width : '100%'\"\r\n [class.bk-grouped]=\"groupBy()\"\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=\"-1\"\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 <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 justify-between\">\r\n <span class=\"line-clamp-1\">Select All</span>\r\n @if (isAllSelected()) {\r\n <svg\r\n class=\"text-[#141414]\"\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 @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]=\"$index === markedIndex()\"\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)=\"onOptionHover($index)\"\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 @if (resolveIcon(item)) {\r\n <img [src]=\"resolveIcon(item)!\" alt=\"icon\" class=\"bk-option-icon shrink-0\" />\r\n }\r\n <span #optionLabelEl class=\"bk-option-label min-w-0\" [style.color]=\"resolveColor(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 </div>\r\n }\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 border-[#6B7080] shadow-none z-10;outline:none!important}.bk-select-control.bk-disabled{@apply cursor-not-allowed;border-color:#e3e3e7;background-color:#f4f4f6}.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{@apply border-[#d11e14];}.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;}.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-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 absolute left-0 w-full bg-white border border-[#E3E3E7] rounded-xl shadow-lg z-[100] overflow-hidden cursor-default p-2.5;}.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,.bk-option.bk-selected{@apply bg-[#F8F8F8] rounded-md;}.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;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: BKTooltipDirective, selector: "[bkTooltip]", inputs: ["bkTooltip", "bkTooltipPosition", "bkTooltipScrollable", "bkTooltipMaxHeight", "bkTooltipSize", "bkTooltipAutoHeight"] }] });
5515
+ ], 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: "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\">\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 <div\r\n #controlWrapper\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 (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 #chipsViewport class=\"bk-value-chips bk-chips-viewport flex gap-0.5 flex-nowrap h-[18px] overflow-hidden\">\r\n @for (opt of selectedOptions().slice(0, visibleCount()); track $index) {\r\n <div class=\"bk-multi-badge-item me-0.5\">\r\n @if (resolveIcon(opt)) {\r\n <img [src]=\"resolveIcon(opt)!\" alt=\"icon\" class=\"bk-chip-icon shrink-0\" />\r\n }\r\n <span #badgeTextEl class=\"bk-multi-badge-item-text\" [style.color]=\"resolveColor(opt)\"\r\n [bkTooltip]=\"getTooltipIfEllipsed(badgeTextEl, resolveLabel(opt))\"\r\n bkTooltipPosition=\"top\">{{\r\n resolveLabel(opt)\r\n }}</span>\r\n\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 </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 >+{{ 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\">\r\n @if (resolveIcon(opt)) {\r\n <img [src]=\"resolveIcon(opt)!\" alt=\"icon\" class=\"bk-chip-icon shrink-0\" />\r\n }\r\n <span class=\"bk-multi-badge-item-text\">{{ resolveLabel(opt) }}</span>\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 </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 @if (resolveIcon(selectedOptions()[0])) {\r\n <img [src]=\"resolveIcon(selectedOptions()[0])!\" alt=\"icon\" class=\"bk-option-icon shrink-0\" />\r\n }\r\n <div #singleValueEl class=\"bk-value-label-single\" [style.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 && !disabled()) {\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 @if (isOpen()) {\r\n <div\r\n #dropdownPanel\r\n tabindex=\"-1\"\r\n (keydown)=\"onTabPress($event)\"\r\n class=\"bk-dropdown-panel\"\r\n [attr.data-position]=\"placement()\"\r\n [style.position]=\"appendToBody() ? 'fixed' : 'absolute'\"\r\n [style.top]=\"getTop()\"\r\n [style.bottom]=\"getBottom()\"\r\n [style.left]=\"appendToBody() ? dropdownStyle().left : null\"\r\n [style.width]=\"appendToBody() ? dropdownStyle().width : '100%'\"\r\n [style.zIndex]=\"appendToBody() ? 10000 : null\"\r\n [class.bk-grouped]=\"groupBy()\"\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=\"-1\"\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 <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 justify-between\">\r\n <span class=\"line-clamp-1\">Select All</span>\r\n @if (isAllSelected()) {\r\n <svg\r\n class=\"text-[#141414]\"\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 @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]=\"$index === markedIndex()\"\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)=\"onOptionHover($index)\"\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 @if (resolveIcon(item)) {\r\n <img [src]=\"resolveIcon(item)!\" alt=\"icon\" class=\"bk-option-icon shrink-0\" />\r\n }\r\n <span #optionLabelEl class=\"bk-option-label min-w-0\" [style.color]=\"resolveColor(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 </div>\r\n }\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 border-[#6B7080] shadow-none z-10;outline:none!important}.bk-select-control.bk-disabled{@apply cursor-not-allowed;border-color:#e3e3e7;background-color:#f4f4f6}.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{@apply border-[#d11e14];}.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;}.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-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 absolute left-0 w-full bg-white border border-[#E3E3E7] rounded-xl shadow-lg z-[100] overflow-hidden cursor-default p-2.5;}.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,.bk-option.bk-selected{@apply bg-[#F8F8F8] rounded-md;}.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;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: BKTooltipDirective, selector: "[bkTooltip]", inputs: ["bkTooltip", "bkTooltipPosition", "bkTooltipScrollable", "bkTooltipMaxHeight", "bkTooltipSize", "bkTooltipAutoHeight"] }] });
4987
5516
  }
4988
5517
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkSelect, decorators: [{
4989
5518
  type: Component,
@@ -4993,7 +5522,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
4993
5522
  useExisting: forwardRef(() => BkSelect),
4994
5523
  multi: true
4995
5524
  }
4996
- ], template: "<div class=\"bk-select-container\" [ngClass]=\"variation\">\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 <div\r\n #controlWrapper\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 (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 #chipsViewport class=\"bk-value-chips bk-chips-viewport flex gap-0.5 flex-nowrap h-[18px] overflow-hidden\">\r\n @for (opt of selectedOptions().slice(0, visibleCount()); track $index) {\r\n <div class=\"bk-multi-badge-item me-0.5\">\r\n @if (resolveIcon(opt)) {\r\n <img [src]=\"resolveIcon(opt)!\" alt=\"icon\" class=\"bk-chip-icon shrink-0\" />\r\n }\r\n <span #badgeTextEl class=\"bk-multi-badge-item-text\" [style.color]=\"resolveColor(opt)\"\r\n [bkTooltip]=\"getTooltipIfEllipsed(badgeTextEl, resolveLabel(opt))\"\r\n bkTooltipPosition=\"top\">{{\r\n resolveLabel(opt)\r\n }}</span>\r\n\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 </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 >+{{ 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\">\r\n @if (resolveIcon(opt)) {\r\n <img [src]=\"resolveIcon(opt)!\" alt=\"icon\" class=\"bk-chip-icon shrink-0\" />\r\n }\r\n <span class=\"bk-multi-badge-item-text\">{{ resolveLabel(opt) }}</span>\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 </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 @if (resolveIcon(selectedOptions()[0])) {\r\n <img [src]=\"resolveIcon(selectedOptions()[0])!\" alt=\"icon\" class=\"bk-option-icon shrink-0\" />\r\n }\r\n <div #singleValueEl class=\"bk-value-label-single\" [style.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 && !disabled()) {\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 @if (isOpen()) {\r\n <div\r\n #dropdownPanel\r\n tabindex=\"-1\"\r\n (keydown)=\"onTabPress($event)\"\r\n class=\"bk-dropdown-panel\"\r\n [attr.data-position]=\"dropdownPosition()\"\r\n [style.position]=\"appendToBody() ? 'fixed' : 'absolute'\"\r\n [style.top]=\"getTop()\"\r\n [style.bottom]=\"getBottom()\"\r\n [style.left]=\"appendToBody() ? dropdownStyle().left : null\"\r\n [style.width]=\"appendToBody() ? dropdownStyle().width : '100%'\"\r\n [class.bk-grouped]=\"groupBy()\"\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=\"-1\"\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 <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 justify-between\">\r\n <span class=\"line-clamp-1\">Select All</span>\r\n @if (isAllSelected()) {\r\n <svg\r\n class=\"text-[#141414]\"\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 @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]=\"$index === markedIndex()\"\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)=\"onOptionHover($index)\"\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 @if (resolveIcon(item)) {\r\n <img [src]=\"resolveIcon(item)!\" alt=\"icon\" class=\"bk-option-icon shrink-0\" />\r\n }\r\n <span #optionLabelEl class=\"bk-option-label min-w-0\" [style.color]=\"resolveColor(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 </div>\r\n }\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 border-[#6B7080] shadow-none z-10;outline:none!important}.bk-select-control.bk-disabled{@apply cursor-not-allowed;border-color:#e3e3e7;background-color:#f4f4f6}.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{@apply border-[#d11e14];}.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;}.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-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 absolute left-0 w-full bg-white border border-[#E3E3E7] rounded-xl shadow-lg z-[100] overflow-hidden cursor-default p-2.5;}.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,.bk-option.bk-selected{@apply bg-[#F8F8F8] rounded-md;}.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;}\n"] }]
5525
+ ], template: "<div class=\"bk-select-container\" [ngClass]=\"variation\">\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 <div\r\n #controlWrapper\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 (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 #chipsViewport class=\"bk-value-chips bk-chips-viewport flex gap-0.5 flex-nowrap h-[18px] overflow-hidden\">\r\n @for (opt of selectedOptions().slice(0, visibleCount()); track $index) {\r\n <div class=\"bk-multi-badge-item me-0.5\">\r\n @if (resolveIcon(opt)) {\r\n <img [src]=\"resolveIcon(opt)!\" alt=\"icon\" class=\"bk-chip-icon shrink-0\" />\r\n }\r\n <span #badgeTextEl class=\"bk-multi-badge-item-text\" [style.color]=\"resolveColor(opt)\"\r\n [bkTooltip]=\"getTooltipIfEllipsed(badgeTextEl, resolveLabel(opt))\"\r\n bkTooltipPosition=\"top\">{{\r\n resolveLabel(opt)\r\n }}</span>\r\n\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 </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 >+{{ 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\">\r\n @if (resolveIcon(opt)) {\r\n <img [src]=\"resolveIcon(opt)!\" alt=\"icon\" class=\"bk-chip-icon shrink-0\" />\r\n }\r\n <span class=\"bk-multi-badge-item-text\">{{ resolveLabel(opt) }}</span>\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 </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 @if (resolveIcon(selectedOptions()[0])) {\r\n <img [src]=\"resolveIcon(selectedOptions()[0])!\" alt=\"icon\" class=\"bk-option-icon shrink-0\" />\r\n }\r\n <div #singleValueEl class=\"bk-value-label-single\" [style.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 && !disabled()) {\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 @if (isOpen()) {\r\n <div\r\n #dropdownPanel\r\n tabindex=\"-1\"\r\n (keydown)=\"onTabPress($event)\"\r\n class=\"bk-dropdown-panel\"\r\n [attr.data-position]=\"placement()\"\r\n [style.position]=\"appendToBody() ? 'fixed' : 'absolute'\"\r\n [style.top]=\"getTop()\"\r\n [style.bottom]=\"getBottom()\"\r\n [style.left]=\"appendToBody() ? dropdownStyle().left : null\"\r\n [style.width]=\"appendToBody() ? dropdownStyle().width : '100%'\"\r\n [style.zIndex]=\"appendToBody() ? 10000 : null\"\r\n [class.bk-grouped]=\"groupBy()\"\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=\"-1\"\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 <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 justify-between\">\r\n <span class=\"line-clamp-1\">Select All</span>\r\n @if (isAllSelected()) {\r\n <svg\r\n class=\"text-[#141414]\"\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 @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]=\"$index === markedIndex()\"\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)=\"onOptionHover($index)\"\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 @if (resolveIcon(item)) {\r\n <img [src]=\"resolveIcon(item)!\" alt=\"icon\" class=\"bk-option-icon shrink-0\" />\r\n }\r\n <span #optionLabelEl class=\"bk-option-label min-w-0\" [style.color]=\"resolveColor(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 </div>\r\n }\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 border-[#6B7080] shadow-none z-10;outline:none!important}.bk-select-control.bk-disabled{@apply cursor-not-allowed;border-color:#e3e3e7;background-color:#f4f4f6}.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{@apply border-[#d11e14];}.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;}.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-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 absolute left-0 w-full bg-white border border-[#E3E3E7] rounded-xl shadow-lg z-[100] overflow-hidden cursor-default p-2.5;}.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,.bk-option.bk-selected{@apply bg-[#F8F8F8] rounded-md;}.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;}\n"] }]
4997
5526
  }], ctorParameters: () => [], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], bindLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "bindLabel", required: false }] }], bindValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "bindValue", required: false }] }], bindIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "bindIcon", required: false }] }], isResponsive: [{ type: i0.Input, args: [{ isSignal: true, alias: "isResponsive", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], notFoundText: [{ type: i0.Input, args: [{ isSignal: true, alias: "notFoundText", required: false }] }], loadingText: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingText", required: false }] }], clearAllText: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearAllText", required: false }] }], groupBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupBy", required: false }] }], colorKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "colorKey", required: false }] }], iconAlt: [{
4998
5527
  type: Input
4999
5528
  }], label: [{
@@ -5020,6 +5549,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
5020
5549
  }], controlWrapper: [{
5021
5550
  type: ViewChild,
5022
5551
  args: ['controlWrapper']
5552
+ }], dropdownPanel: [{
5553
+ type: ViewChild,
5554
+ args: ['dropdownPanel']
5023
5555
  }], chipsViewport: [{
5024
5556
  type: ViewChild,
5025
5557
  args: ['chipsViewport']
@@ -5029,13 +5561,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
5029
5561
  }], measurePlus: [{
5030
5562
  type: ViewChild,
5031
5563
  args: ['measurePlus']
5032
- }], compareWith: [{ type: i0.Input, args: [{ isSignal: true, alias: "compareWith", required: false }] }], onWindowEvents: [{
5033
- type: HostListener,
5034
- args: ['window:scroll']
5035
- }, {
5036
- type: HostListener,
5037
- args: ['window:resize']
5038
- }], onClickOutside: [{
5564
+ }], compareWith: [{ type: i0.Input, args: [{ isSignal: true, alias: "compareWith", required: false }] }], onClickOutside: [{
5039
5565
  type: HostListener,
5040
5566
  args: ['document:click', ['$event']]
5041
5567
  }] } });
@@ -5694,6 +6220,14 @@ class BkTabs {
5694
6220
  orientation = 'horizontal';
5695
6221
  variant = 'default';
5696
6222
  colors = {};
6223
+ /**
6224
+ * When true, if the currently active tab is in an error state, navigation to
6225
+ * the other tabs is blocked (they render disabled) until the error clears.
6226
+ * Optional — defaults to false, so navigation stays free unless opted in.
6227
+ */
6228
+ lockNavigationOnError = false;
6229
+ /** Fallback error icon used when a tab has `showErrorIcon` but no `errorIcon`. */
6230
+ defaultErrorIcon = '../../assets/icons/alert-circle-red.svg';
5697
6231
  // Convenience getters for template class bindings
5698
6232
  get isVertical() {
5699
6233
  return this.orientation === 'vertical';
@@ -5717,9 +6251,18 @@ class BkTabs {
5717
6251
  return this.colors.inactive ?? '';
5718
6252
  }
5719
6253
  change = new EventEmitter();
6254
+ // True when the currently active tab is flagged with an error.
6255
+ get activeTabHasError() {
6256
+ return this.list.some(t => t.id === this.activeTabId && !!t.error);
6257
+ }
6258
+ // A tab is locked when navigation-on-error is enabled, the active tab has an
6259
+ // error, and this tab is not the active one. Locked tabs render disabled.
6260
+ isLocked(tab) {
6261
+ return this.lockNavigationOnError && this.activeTabHasError && tab.id !== this.activeTabId;
6262
+ }
5720
6263
  // Set active tab and emit change event
5721
6264
  setActiveTab(tab) {
5722
- if (tab?.disabled || this.disabled)
6265
+ if (tab?.disabled || this.disabled || this.isLocked(tab))
5723
6266
  return;
5724
6267
  this.activeTabId = tab.id;
5725
6268
  this.change.emit(tab);
@@ -5728,19 +6271,25 @@ class BkTabs {
5728
6271
  isActive(tabId) {
5729
6272
  return this.activeTabId === tabId;
5730
6273
  }
5731
- // Get the appropriate icon for a tab based on its active state
6274
+ // Get the appropriate icon for a tab based on its active/error state.
6275
+ // In an error state, when the tab opts into an error icon, show the custom
6276
+ // `errorIcon` or the component default error icon — this replaces the tab's
6277
+ // own decorative `icon` so the error is always what's surfaced.
5732
6278
  getTabIcon(tab) {
6279
+ if (tab.error && tab.showErrorIcon) {
6280
+ return tab.errorIcon ?? this.defaultErrorIcon;
6281
+ }
5733
6282
  if (this.isActive(tab.id) && tab.iconActive) {
5734
6283
  return tab.iconActive;
5735
6284
  }
5736
6285
  return tab.icon;
5737
6286
  }
5738
6287
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTabs, deps: [], target: i0.ɵɵFactoryTarget.Component });
5739
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkTabs, isStandalone: true, selector: "bk-tabs", inputs: { list: "list", activeTabId: "activeTabId", disabled: "disabled", orientation: "orientation", variant: "variant", colors: "colors" }, outputs: { change: "change" }, ngImport: i0, template: "<div class=\"tabs-container\" [class.tabs-container--segmented]=\"isSegmented\"\r\n [ngClass]=\"isSegmented ? wrapperClass : (isVertical ? 'w-auto' : 'overflow-x-auto whitespace-nowrap')\">\r\n <ul class=\"tabs-list\" [class.tabs-list--segmented]=\"isSegmented\"\r\n [class.tabs-list--segmented-vertical]=\"isSegmented && isVertical\"\r\n [class.tabs-list--vertical]=\"isVertical && !isSegmented\" [attr.aria-orientation]=\"orientation\" role=\"tablist\">\r\n @for (tab of list; track tab.id; let i = $index) {\r\n <li class=\"tabs-item\" role=\"presentation\">\r\n <!--\r\n Tooltip logic:\r\n - Icon present (error or not) \u2192 tooltip on the icon, button gets no tooltip\r\n - No icon + error state \u2192 tooltip on the button\r\n - No icon + no error \u2192 no tooltip\r\n -->\r\n <button type=\"button\" [id]=\"'tab-' + tab.id\" [attr.aria-selected]=\"isActive(tab.id)\"\r\n [attr.aria-controls]=\"'panel-' + tab.id\" [disabled]=\"tab.disabled\"\r\n [class.tabs-button--active]=\"isActive(tab.id)\" [class.tabs-button--error]=\"tab.error\"\r\n [class.tabs-button--disabled]=\"disabled || tab.disabled\"\r\n [class.tabs-button--icon-right]=\"tab.direction === 'right'\" [class.tabs-button--segmented]=\"isSegmented\"\r\n [ngClass]=\"[\r\n isSegmented ? segmentedTabClass(tab) : '',\r\n (isVertical && !isSegmented) ? 'w-full justify-start' : ''\r\n ]\" [bkTooltip]=\"(!getTabIcon(tab) && tab.error) ? (tab.iconTooltip || []) : []\"\r\n [bkTooltipPosition]=\"tab.iconTooltipDirection || 'top'\" class=\"tabs-button\" (click)=\"setActiveTab(tab)\"\r\n role=\"tab\">\r\n <!-- Left icon: tooltip lives on the icon when an icon is present -->\r\n <img [bkTooltip]=\"getTabIcon(tab) ? (tab.iconTooltip || []) : []\"\r\n [bkTooltipPosition]=\"tab.iconTooltipDirection || 'top'\" [attr.src]=\"getTabIcon(tab)\"\r\n [alt]=\"tab.iconAlt || tab.label\" [class.tabs-icon--hidden]=\"!getTabIcon(tab) || tab.direction === 'right'\"\r\n class=\"tabs-icon\">\r\n <span class=\"tabs-label\">{{ tab.label }}</span>\r\n <!-- Right icon: same tooltip rule, shown when direction is 'right' -->\r\n <img [bkTooltip]=\"getTabIcon(tab) ? (tab.iconTooltip || []) : []\"\r\n [bkTooltipPosition]=\"tab.iconTooltipDirection || 'top'\" [attr.src]=\"getTabIcon(tab)\"\r\n [alt]=\"tab.iconAlt || tab.label\" [class.tabs-icon--hidden]=\"!getTabIcon(tab) || tab.direction !== 'right'\"\r\n class=\"tabs-icon\">\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n</div>", styles: [".tabs-container{@apply w-full;}.tabs-list{@apply grid grid-flow-col auto-cols-max gap-[4px] list-none m-0 px-0 py-0.5;}.tabs-item{@apply min-w-0;}.tabs-list--vertical{@apply grid-cols-1 grid-flow-row auto-rows-max;}.tabs-button{@apply flex items-center gap-[6px] px-3 py-2 rounded-md border-0 bg-transparent cursor-pointer transition-all duration-100 outline-none;@apply text-sm leading-[11px] font-medium text-[#141414] tracking-[-.28];}.tabs-button:hover:not(:disabled):not(.tabs-button--active){@apply text-[#141414] bg-[#EDEEF0];}.tabs-list--vertical .tabs-button{@apply py-[9px];}.tabs-button--active{@apply bg-[#141414] text-white;}.tabs-button--error{@apply bg-[#C10007] text-white border-0;}.tabs-button--disabled{@apply opacity-50 cursor-not-allowed;}.tabs-icon{@apply size-4 flex-shrink-0;max-width:1rem;opacity:1;overflow:hidden;transition:max-width .2s ease,opacity .2s ease}.tabs-icon--hidden{max-width:0;opacity:0}.tabs-label{@apply whitespace-nowrap;}.tabs-container--segmented{@apply p-[3px] rounded-md w-full md:w-auto overflow-x-auto;background:#54578e12}.tabs-list--segmented{@apply grid grid-flow-col items-center gap-2 rounded-md font-medium text-sm leading-4 w-full sm:w-auto py-0;grid-auto-columns:minmax(max-content,1fr);color:#6b7080}.tabs-button--segmented{@apply border border-transparent px-3 sm:min-w-[5rem] py-1.5 w-full text-center justify-center rounded;color:#6b7080}.tabs-button--segmented:hover:not(:disabled):not(.tabs-button--active){border-color:#42578a26;background:#fff;color:#15191e}.tabs-button--segmented.tabs-button--active{background:#fff;color:#15191e}.tabs-list--segmented-vertical{@apply grid-cols-1 grid-flow-row auto-rows-max gap-1;}.tabs-list--segmented-vertical .tabs-button--segmented{@apply justify-start text-left;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: BKTooltipDirective, selector: "[bkTooltip]", inputs: ["bkTooltip", "bkTooltipPosition", "bkTooltipScrollable", "bkTooltipMaxHeight", "bkTooltipSize", "bkTooltipAutoHeight"] }] });
6288
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkTabs, isStandalone: true, selector: "bk-tabs", inputs: { list: "list", activeTabId: "activeTabId", disabled: "disabled", orientation: "orientation", variant: "variant", colors: "colors", lockNavigationOnError: "lockNavigationOnError" }, outputs: { change: "change" }, ngImport: i0, template: "<div\r\n class=\"tabs-container\"\r\n [class.tabs-container--segmented]=\"isSegmented\"\r\n [ngClass]=\"isSegmented ? wrapperClass : (isVertical ? 'w-auto' : 'overflow-x-auto whitespace-nowrap')\">\r\n <ul\r\n class=\"tabs-list\"\r\n [class.tabs-list--segmented]=\"isSegmented\"\r\n [class.tabs-list--segmented-vertical]=\"isSegmented && isVertical\"\r\n [class.tabs-list--vertical]=\"isVertical && !isSegmented\"\r\n [attr.aria-orientation]=\"orientation\"\r\n role=\"tablist\">\r\n @for (tab of list; track tab.id; let i = $index) {\r\n <li class=\"tabs-item\" role=\"presentation\">\r\n <!--\r\n Tooltip logic:\r\n - Icon present (error or not) \u2192 tooltip on the icon, button gets no tooltip\r\n - No icon + error state \u2192 tooltip on the button\r\n - No icon + no error \u2192 no tooltip\r\n -->\r\n <button\r\n type=\"button\"\r\n [id]=\"'tab-' + tab.id\"\r\n [attr.aria-selected]=\"isActive(tab.id)\"\r\n [attr.aria-controls]=\"'panel-' + tab.id\"\r\n [disabled]=\"tab.disabled || isLocked(tab)\"\r\n [class.tabs-button--active]=\"isActive(tab.id)\"\r\n [class.tabs-button--error]=\"tab.error\"\r\n [class.tabs-button--disabled]=\"disabled || tab.disabled || isLocked(tab)\"\r\n [class.tabs-button--icon-right]=\"tab.direction === 'right'\"\r\n [class.tabs-button--segmented]=\"isSegmented\"\r\n [ngClass]=\"[\r\n isSegmented ? segmentedTabClass(tab) : '',\r\n (isVertical && !isSegmented) ? 'w-full justify-start' : ''\r\n ]\"\r\n [bkTooltip]=\"(!getTabIcon(tab) && tab.error) ? (tab.iconTooltip || []) : []\"\r\n [bkTooltipPosition]=\"tab.iconTooltipDirection || 'top'\"\r\n class=\"tabs-button\"\r\n (click)=\"setActiveTab(tab)\"\r\n role=\"tab\">\r\n <!-- Left icon: tooltip lives on the icon when an icon is present -->\r\n <img\r\n [bkTooltip]=\"getTabIcon(tab) ? (tab.iconTooltip || []) : []\" [bkTooltipPosition]=\"tab.iconTooltipDirection || 'top'\"\r\n [attr.src]=\"getTabIcon(tab)\"\r\n [alt]=\"tab.iconAlt || tab.label\"\r\n [class.tabs-icon--hidden]=\"!getTabIcon(tab) || tab.direction === 'right'\"\r\n class=\"tabs-icon\">\r\n <span class=\"tabs-label\">{{ tab.label }}</span>\r\n <!-- Right icon: same tooltip rule, shown when direction is 'right' -->\r\n <img\r\n [bkTooltip]=\"getTabIcon(tab) ? (tab.iconTooltip || []) : []\" [bkTooltipPosition]=\"tab.iconTooltipDirection || 'top'\"\r\n [attr.src]=\"getTabIcon(tab)\"\r\n [alt]=\"tab.iconAlt || tab.label\"\r\n [class.tabs-icon--hidden]=\"!getTabIcon(tab) || tab.direction !== 'right'\"\r\n class=\"tabs-icon\">\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n</div>\r\n\r\n", styles: [".tabs-container{@apply w-full;}.tabs-list{@apply grid grid-flow-col auto-cols-max gap-[4px] list-none m-0 px-0 py-0.5;}.tabs-item{@apply min-w-0;}.tabs-list--vertical{@apply grid-cols-1 grid-flow-row auto-rows-max;}.tabs-button{@apply flex items-center gap-[6px] px-3 py-2 rounded-md border-0 bg-transparent cursor-pointer transition-all duration-100 outline-none;@apply text-sm leading-[11px] font-medium text-[#141414] tracking-[-.28];}.tabs-button:hover:not(:disabled):not(.tabs-button--active){@apply text-[#141414] bg-[#EDEEF0];}.tabs-list--vertical .tabs-button{@apply py-[9px];}.tabs-button--active{@apply bg-[#141414] text-white;}.tabs-button--error{@apply bg-[#C10007] text-white border-0;}.tabs-button--disabled{@apply opacity-50 cursor-not-allowed;}.tabs-icon{@apply size-4 flex-shrink-0;max-width:1rem;opacity:1;overflow:hidden;transition:max-width .2s ease,opacity .2s ease}.tabs-icon--hidden{max-width:0;opacity:0}.tabs-label{@apply whitespace-nowrap;}.tabs-container--segmented{@apply p-[3px] rounded-md w-full md:w-auto overflow-x-auto;background:#54578e12}.tabs-list--segmented{@apply grid grid-flow-col items-center gap-2 rounded-md font-medium text-sm leading-4 w-full sm:w-auto py-0;grid-auto-columns:minmax(max-content,1fr);color:#6b7080}.tabs-button--segmented{@apply border border-transparent px-3 sm:min-w-[5rem] py-1.5 w-full text-center justify-center rounded;color:#6b7080}.tabs-button--segmented:hover:not(:disabled):not(.tabs-button--active){border-color:#42578a26;background:#fff;color:#15191e}.tabs-button--segmented.tabs-button--active{background:#fff;color:#15191e}.tabs-button--segmented.tabs-button--error{background:#fee2e2;border-color:#fca5a5;color:#c10007}.tabs-button--segmented.tabs-button--error.tabs-button--active{background:#fff;border-color:#c10007;color:#c10007}.tabs-button--segmented.tabs-button--error:hover:not(:disabled):not(.tabs-button--active){background:#fee2e2;border-color:#c10007;color:#c10007}.tabs-list--segmented-vertical{@apply grid-cols-1 grid-flow-row auto-rows-max gap-1;}.tabs-list--segmented-vertical .tabs-button--segmented{@apply justify-start text-left;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: BKTooltipDirective, selector: "[bkTooltip]", inputs: ["bkTooltip", "bkTooltipPosition", "bkTooltipScrollable", "bkTooltipMaxHeight", "bkTooltipSize", "bkTooltipAutoHeight"] }] });
5740
6289
  }
5741
6290
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTabs, decorators: [{
5742
6291
  type: Component,
5743
- args: [{ selector: 'bk-tabs', standalone: true, imports: [CommonModule, BKTooltipDirective], template: "<div class=\"tabs-container\" [class.tabs-container--segmented]=\"isSegmented\"\r\n [ngClass]=\"isSegmented ? wrapperClass : (isVertical ? 'w-auto' : 'overflow-x-auto whitespace-nowrap')\">\r\n <ul class=\"tabs-list\" [class.tabs-list--segmented]=\"isSegmented\"\r\n [class.tabs-list--segmented-vertical]=\"isSegmented && isVertical\"\r\n [class.tabs-list--vertical]=\"isVertical && !isSegmented\" [attr.aria-orientation]=\"orientation\" role=\"tablist\">\r\n @for (tab of list; track tab.id; let i = $index) {\r\n <li class=\"tabs-item\" role=\"presentation\">\r\n <!--\r\n Tooltip logic:\r\n - Icon present (error or not) \u2192 tooltip on the icon, button gets no tooltip\r\n - No icon + error state \u2192 tooltip on the button\r\n - No icon + no error \u2192 no tooltip\r\n -->\r\n <button type=\"button\" [id]=\"'tab-' + tab.id\" [attr.aria-selected]=\"isActive(tab.id)\"\r\n [attr.aria-controls]=\"'panel-' + tab.id\" [disabled]=\"tab.disabled\"\r\n [class.tabs-button--active]=\"isActive(tab.id)\" [class.tabs-button--error]=\"tab.error\"\r\n [class.tabs-button--disabled]=\"disabled || tab.disabled\"\r\n [class.tabs-button--icon-right]=\"tab.direction === 'right'\" [class.tabs-button--segmented]=\"isSegmented\"\r\n [ngClass]=\"[\r\n isSegmented ? segmentedTabClass(tab) : '',\r\n (isVertical && !isSegmented) ? 'w-full justify-start' : ''\r\n ]\" [bkTooltip]=\"(!getTabIcon(tab) && tab.error) ? (tab.iconTooltip || []) : []\"\r\n [bkTooltipPosition]=\"tab.iconTooltipDirection || 'top'\" class=\"tabs-button\" (click)=\"setActiveTab(tab)\"\r\n role=\"tab\">\r\n <!-- Left icon: tooltip lives on the icon when an icon is present -->\r\n <img [bkTooltip]=\"getTabIcon(tab) ? (tab.iconTooltip || []) : []\"\r\n [bkTooltipPosition]=\"tab.iconTooltipDirection || 'top'\" [attr.src]=\"getTabIcon(tab)\"\r\n [alt]=\"tab.iconAlt || tab.label\" [class.tabs-icon--hidden]=\"!getTabIcon(tab) || tab.direction === 'right'\"\r\n class=\"tabs-icon\">\r\n <span class=\"tabs-label\">{{ tab.label }}</span>\r\n <!-- Right icon: same tooltip rule, shown when direction is 'right' -->\r\n <img [bkTooltip]=\"getTabIcon(tab) ? (tab.iconTooltip || []) : []\"\r\n [bkTooltipPosition]=\"tab.iconTooltipDirection || 'top'\" [attr.src]=\"getTabIcon(tab)\"\r\n [alt]=\"tab.iconAlt || tab.label\" [class.tabs-icon--hidden]=\"!getTabIcon(tab) || tab.direction !== 'right'\"\r\n class=\"tabs-icon\">\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n</div>", styles: [".tabs-container{@apply w-full;}.tabs-list{@apply grid grid-flow-col auto-cols-max gap-[4px] list-none m-0 px-0 py-0.5;}.tabs-item{@apply min-w-0;}.tabs-list--vertical{@apply grid-cols-1 grid-flow-row auto-rows-max;}.tabs-button{@apply flex items-center gap-[6px] px-3 py-2 rounded-md border-0 bg-transparent cursor-pointer transition-all duration-100 outline-none;@apply text-sm leading-[11px] font-medium text-[#141414] tracking-[-.28];}.tabs-button:hover:not(:disabled):not(.tabs-button--active){@apply text-[#141414] bg-[#EDEEF0];}.tabs-list--vertical .tabs-button{@apply py-[9px];}.tabs-button--active{@apply bg-[#141414] text-white;}.tabs-button--error{@apply bg-[#C10007] text-white border-0;}.tabs-button--disabled{@apply opacity-50 cursor-not-allowed;}.tabs-icon{@apply size-4 flex-shrink-0;max-width:1rem;opacity:1;overflow:hidden;transition:max-width .2s ease,opacity .2s ease}.tabs-icon--hidden{max-width:0;opacity:0}.tabs-label{@apply whitespace-nowrap;}.tabs-container--segmented{@apply p-[3px] rounded-md w-full md:w-auto overflow-x-auto;background:#54578e12}.tabs-list--segmented{@apply grid grid-flow-col items-center gap-2 rounded-md font-medium text-sm leading-4 w-full sm:w-auto py-0;grid-auto-columns:minmax(max-content,1fr);color:#6b7080}.tabs-button--segmented{@apply border border-transparent px-3 sm:min-w-[5rem] py-1.5 w-full text-center justify-center rounded;color:#6b7080}.tabs-button--segmented:hover:not(:disabled):not(.tabs-button--active){border-color:#42578a26;background:#fff;color:#15191e}.tabs-button--segmented.tabs-button--active{background:#fff;color:#15191e}.tabs-list--segmented-vertical{@apply grid-cols-1 grid-flow-row auto-rows-max gap-1;}.tabs-list--segmented-vertical .tabs-button--segmented{@apply justify-start text-left;}\n"] }]
6292
+ args: [{ selector: 'bk-tabs', standalone: true, imports: [CommonModule, BKTooltipDirective], template: "<div\r\n class=\"tabs-container\"\r\n [class.tabs-container--segmented]=\"isSegmented\"\r\n [ngClass]=\"isSegmented ? wrapperClass : (isVertical ? 'w-auto' : 'overflow-x-auto whitespace-nowrap')\">\r\n <ul\r\n class=\"tabs-list\"\r\n [class.tabs-list--segmented]=\"isSegmented\"\r\n [class.tabs-list--segmented-vertical]=\"isSegmented && isVertical\"\r\n [class.tabs-list--vertical]=\"isVertical && !isSegmented\"\r\n [attr.aria-orientation]=\"orientation\"\r\n role=\"tablist\">\r\n @for (tab of list; track tab.id; let i = $index) {\r\n <li class=\"tabs-item\" role=\"presentation\">\r\n <!--\r\n Tooltip logic:\r\n - Icon present (error or not) \u2192 tooltip on the icon, button gets no tooltip\r\n - No icon + error state \u2192 tooltip on the button\r\n - No icon + no error \u2192 no tooltip\r\n -->\r\n <button\r\n type=\"button\"\r\n [id]=\"'tab-' + tab.id\"\r\n [attr.aria-selected]=\"isActive(tab.id)\"\r\n [attr.aria-controls]=\"'panel-' + tab.id\"\r\n [disabled]=\"tab.disabled || isLocked(tab)\"\r\n [class.tabs-button--active]=\"isActive(tab.id)\"\r\n [class.tabs-button--error]=\"tab.error\"\r\n [class.tabs-button--disabled]=\"disabled || tab.disabled || isLocked(tab)\"\r\n [class.tabs-button--icon-right]=\"tab.direction === 'right'\"\r\n [class.tabs-button--segmented]=\"isSegmented\"\r\n [ngClass]=\"[\r\n isSegmented ? segmentedTabClass(tab) : '',\r\n (isVertical && !isSegmented) ? 'w-full justify-start' : ''\r\n ]\"\r\n [bkTooltip]=\"(!getTabIcon(tab) && tab.error) ? (tab.iconTooltip || []) : []\"\r\n [bkTooltipPosition]=\"tab.iconTooltipDirection || 'top'\"\r\n class=\"tabs-button\"\r\n (click)=\"setActiveTab(tab)\"\r\n role=\"tab\">\r\n <!-- Left icon: tooltip lives on the icon when an icon is present -->\r\n <img\r\n [bkTooltip]=\"getTabIcon(tab) ? (tab.iconTooltip || []) : []\" [bkTooltipPosition]=\"tab.iconTooltipDirection || 'top'\"\r\n [attr.src]=\"getTabIcon(tab)\"\r\n [alt]=\"tab.iconAlt || tab.label\"\r\n [class.tabs-icon--hidden]=\"!getTabIcon(tab) || tab.direction === 'right'\"\r\n class=\"tabs-icon\">\r\n <span class=\"tabs-label\">{{ tab.label }}</span>\r\n <!-- Right icon: same tooltip rule, shown when direction is 'right' -->\r\n <img\r\n [bkTooltip]=\"getTabIcon(tab) ? (tab.iconTooltip || []) : []\" [bkTooltipPosition]=\"tab.iconTooltipDirection || 'top'\"\r\n [attr.src]=\"getTabIcon(tab)\"\r\n [alt]=\"tab.iconAlt || tab.label\"\r\n [class.tabs-icon--hidden]=\"!getTabIcon(tab) || tab.direction !== 'right'\"\r\n class=\"tabs-icon\">\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n</div>\r\n\r\n", styles: [".tabs-container{@apply w-full;}.tabs-list{@apply grid grid-flow-col auto-cols-max gap-[4px] list-none m-0 px-0 py-0.5;}.tabs-item{@apply min-w-0;}.tabs-list--vertical{@apply grid-cols-1 grid-flow-row auto-rows-max;}.tabs-button{@apply flex items-center gap-[6px] px-3 py-2 rounded-md border-0 bg-transparent cursor-pointer transition-all duration-100 outline-none;@apply text-sm leading-[11px] font-medium text-[#141414] tracking-[-.28];}.tabs-button:hover:not(:disabled):not(.tabs-button--active){@apply text-[#141414] bg-[#EDEEF0];}.tabs-list--vertical .tabs-button{@apply py-[9px];}.tabs-button--active{@apply bg-[#141414] text-white;}.tabs-button--error{@apply bg-[#C10007] text-white border-0;}.tabs-button--disabled{@apply opacity-50 cursor-not-allowed;}.tabs-icon{@apply size-4 flex-shrink-0;max-width:1rem;opacity:1;overflow:hidden;transition:max-width .2s ease,opacity .2s ease}.tabs-icon--hidden{max-width:0;opacity:0}.tabs-label{@apply whitespace-nowrap;}.tabs-container--segmented{@apply p-[3px] rounded-md w-full md:w-auto overflow-x-auto;background:#54578e12}.tabs-list--segmented{@apply grid grid-flow-col items-center gap-2 rounded-md font-medium text-sm leading-4 w-full sm:w-auto py-0;grid-auto-columns:minmax(max-content,1fr);color:#6b7080}.tabs-button--segmented{@apply border border-transparent px-3 sm:min-w-[5rem] py-1.5 w-full text-center justify-center rounded;color:#6b7080}.tabs-button--segmented:hover:not(:disabled):not(.tabs-button--active){border-color:#42578a26;background:#fff;color:#15191e}.tabs-button--segmented.tabs-button--active{background:#fff;color:#15191e}.tabs-button--segmented.tabs-button--error{background:#fee2e2;border-color:#fca5a5;color:#c10007}.tabs-button--segmented.tabs-button--error.tabs-button--active{background:#fff;border-color:#c10007;color:#c10007}.tabs-button--segmented.tabs-button--error:hover:not(:disabled):not(.tabs-button--active){background:#fee2e2;border-color:#c10007;color:#c10007}.tabs-list--segmented-vertical{@apply grid-cols-1 grid-flow-row auto-rows-max gap-1;}.tabs-list--segmented-vertical .tabs-button--segmented{@apply justify-start text-left;}\n"] }]
5744
6293
  }], propDecorators: { list: [{
5745
6294
  type: Input
5746
6295
  }], activeTabId: [{
@@ -5753,6 +6302,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
5753
6302
  type: Input
5754
6303
  }], colors: [{
5755
6304
  type: Input
6305
+ }], lockNavigationOnError: [{
6306
+ type: Input
5756
6307
  }], change: [{
5757
6308
  type: Output
5758
6309
  }] } });
@@ -7380,7 +7931,17 @@ class BkHierarchicalSelect {
7380
7931
  clear = output();
7381
7932
  searchInput;
7382
7933
  controlWrapper;
7934
+ dropdownPanel;
7383
7935
  el = inject(ElementRef);
7936
+ // Side the panel is actually rendered on. Starts from the requested
7937
+ // `dropdownPosition` but is auto-flipped based on available viewport space.
7938
+ placement = signal('bottom', ...(ngDevMode ? [{ debugName: "placement" }] : []));
7939
+ // When appendToBody is on we physically relocate the panel to <body> so it
7940
+ // escapes any transformed/overflow ancestor (e.g. an animated dialog). These
7941
+ // track its home so we can put it back before Angular removes it on close.
7942
+ originalPanelParent = null;
7943
+ originalPanelAnchor = null;
7944
+ panelInBody = false;
7384
7945
  constructor() {
7385
7946
  effect(() => {
7386
7947
  const list = this.items();
@@ -7393,6 +7954,94 @@ class BkHierarchicalSelect {
7393
7954
  this.selected.set(node ?? null);
7394
7955
  });
7395
7956
  }
7957
+ ngAfterViewInit() {
7958
+ // Keep the panel glued to the control while any ancestor scrolls or the
7959
+ // window resizes. Capture phase (`true`) catches scrolling inside nested
7960
+ // overflow containers (e.g. a modal body), not just the window.
7961
+ window.addEventListener('scroll', this.reposition, true);
7962
+ window.addEventListener('resize', this.reposition);
7963
+ }
7964
+ ngOnDestroy() {
7965
+ window.removeEventListener('scroll', this.reposition, true);
7966
+ window.removeEventListener('resize', this.reposition);
7967
+ // If we're torn down while open, don't leave the relocated panel orphaned in <body>.
7968
+ if (this.panelInBody) {
7969
+ this.dropdownPanel?.nativeElement.remove();
7970
+ this.panelInBody = false;
7971
+ }
7972
+ }
7973
+ // Re-evaluate placement as the page scrolls/resizes. For append-to-body this
7974
+ // recomputes the fixed coordinates so the panel follows the control while it's
7975
+ // visible, and closes once the control is fully scrolled out of view (viewport
7976
+ // OR any scroll container such as a modal body). Inline just re-flips up/down.
7977
+ reposition = () => {
7978
+ if (!this.isOpen())
7979
+ return;
7980
+ if (this.appendToBody()) {
7981
+ const rect = this.controlWrapper?.nativeElement.getBoundingClientRect();
7982
+ if (rect && this.isControlClipped(rect)) {
7983
+ this.closeDropdown();
7984
+ return;
7985
+ }
7986
+ }
7987
+ this.applyPlacement();
7988
+ };
7989
+ /**
7990
+ * True when the control is fully outside the visible area — either the
7991
+ * viewport or a scrollable/clipping ancestor (e.g. a dialog's scroll body).
7992
+ */
7993
+ isControlClipped(rect) {
7994
+ if (rect.bottom <= 0 || rect.top >= window.innerHeight ||
7995
+ rect.right <= 0 || rect.left >= window.innerWidth) {
7996
+ return true;
7997
+ }
7998
+ let el = this.controlWrapper?.nativeElement.parentElement;
7999
+ while (el && el !== document.body) {
8000
+ const style = getComputedStyle(el);
8001
+ const clips = /(auto|scroll|hidden|clip|overlay)/;
8002
+ if (clips.test(style.overflowY) || clips.test(style.overflowX)) {
8003
+ const r = el.getBoundingClientRect();
8004
+ if (rect.bottom <= r.top || rect.top >= r.bottom ||
8005
+ rect.right <= r.left || rect.left >= r.right) {
8006
+ return true;
8007
+ }
8008
+ }
8009
+ el = el.parentElement;
8010
+ }
8011
+ return false;
8012
+ }
8013
+ /**
8014
+ * Relocate the panel node to <body> so it truly escapes any transformed or
8015
+ * overflow-clipped ancestor (dialogs, drawers, overflow cards, etc.).
8016
+ */
8017
+ movePanelToBody() {
8018
+ const panel = this.dropdownPanel?.nativeElement;
8019
+ if (!panel || this.panelInBody)
8020
+ return;
8021
+ this.originalPanelParent = panel.parentNode;
8022
+ this.originalPanelAnchor = panel.nextSibling;
8023
+ document.body.appendChild(panel);
8024
+ this.panelInBody = true;
8025
+ }
8026
+ /** Return the panel to its original DOM position before Angular removes it. */
8027
+ restorePanel() {
8028
+ const panel = this.dropdownPanel?.nativeElement;
8029
+ if (!panel || !this.panelInBody)
8030
+ return;
8031
+ if (this.originalPanelParent) {
8032
+ this.originalPanelParent.insertBefore(panel, this.originalPanelAnchor);
8033
+ }
8034
+ this.panelInBody = false;
8035
+ this.originalPanelParent = null;
8036
+ this.originalPanelAnchor = null;
8037
+ }
8038
+ /** Runs after the panel has rendered: relocate (append mode) + position + focus. */
8039
+ afterOpenInit() {
8040
+ if (this.appendToBody())
8041
+ this.movePanelToBody();
8042
+ this.applyPlacement();
8043
+ this.searchInput?.nativeElement?.focus();
8044
+ }
7396
8045
  isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
7397
8046
  dropdownStyle = signal({
7398
8047
  left: '0px',
@@ -7554,12 +8203,12 @@ class BkHierarchicalSelect {
7554
8203
  else {
7555
8204
  this.breadcrumb.set([]);
7556
8205
  }
7557
- if (this.appendToBody()) {
7558
- this.updatePosition();
7559
- }
8206
+ // Decide the initial side before the panel paints (estimated height;
8207
+ // corrected after render in afterOpenInit).
8208
+ this.applyPlacement();
7560
8209
  this.isOpen.set(true);
7561
8210
  this.searchTerm.set('');
7562
- setTimeout(() => this.searchInput?.nativeElement?.focus(), 0);
8211
+ setTimeout(() => this.afterOpenInit(), 0);
7563
8212
  return;
7564
8213
  }
7565
8214
  const sel = this.selected();
@@ -7570,30 +8219,50 @@ class BkHierarchicalSelect {
7570
8219
  else {
7571
8220
  this.breadcrumb.set([]);
7572
8221
  }
7573
- if (this.appendToBody()) {
7574
- this.updatePosition();
7575
- }
8222
+ this.applyPlacement();
7576
8223
  this.isOpen.set(true);
7577
8224
  this.searchTerm.set('');
7578
- setTimeout(() => this.searchInput?.nativeElement?.focus(), 0);
8225
+ setTimeout(() => this.afterOpenInit(), 0);
7579
8226
  }
7580
- updatePosition() {
8227
+ /**
8228
+ * Decides which side the panel opens on (auto-flip) and, for append-to-body
8229
+ * mode, computes the fixed coordinates. Re-run on open and on scroll/resize so
8230
+ * the panel snaps to whichever side has room — honouring `dropdownPosition`
8231
+ * when it fits. Inline mode is positioned by CSS via the `placement` signal.
8232
+ */
8233
+ applyPlacement() {
7581
8234
  const el = this.controlWrapper?.nativeElement;
7582
8235
  if (!el)
7583
8236
  return;
7584
8237
  const rect = el.getBoundingClientRect();
7585
- if (this.dropdownPosition() === 'bottom') {
8238
+ const gap = 4;
8239
+ const panelHeight = this.dropdownPanel?.nativeElement.offsetHeight || 300;
8240
+ const spaceBelow = window.innerHeight - rect.bottom - gap;
8241
+ const spaceAbove = rect.top - gap;
8242
+ const preferred = this.dropdownPosition();
8243
+ let placeTop;
8244
+ if (preferred === 'top') {
8245
+ placeTop = spaceAbove >= panelHeight || spaceAbove > spaceBelow;
8246
+ }
8247
+ else {
8248
+ placeTop = spaceBelow < panelHeight && spaceAbove > spaceBelow;
8249
+ }
8250
+ this.placement.set(placeTop ? 'top' : 'bottom');
8251
+ // Inline mode uses CSS (data-position) — the placement signal is enough.
8252
+ if (!this.appendToBody())
8253
+ return;
8254
+ if (placeTop) {
7586
8255
  this.dropdownStyle.set({
7587
- top: `${rect.bottom + 4}px`,
7588
- bottom: undefined,
8256
+ top: undefined,
8257
+ bottom: `${window.innerHeight - rect.top + gap}px`,
7589
8258
  left: `${rect.left}px`,
7590
8259
  width: `${rect.width}px`,
7591
8260
  });
7592
8261
  }
7593
8262
  else {
7594
8263
  this.dropdownStyle.set({
7595
- top: undefined,
7596
- bottom: `${window.innerHeight - rect.top + 4}px`,
8264
+ top: `${rect.bottom + gap}px`,
8265
+ bottom: undefined,
7597
8266
  left: `${rect.left}px`,
7598
8267
  width: `${rect.width}px`,
7599
8268
  });
@@ -7610,12 +8279,13 @@ class BkHierarchicalSelect {
7610
8279
  return null;
7611
8280
  return this.dropdownStyle().bottom ?? null;
7612
8281
  }
7613
- onWindowScrollOrResize() {
7614
- if (this.isOpen() && this.appendToBody())
7615
- this.closeDropdown();
7616
- }
8282
+ // Scroll/resize are handled by the capture-phase listeners in ngAfterViewInit
8283
+ // (see `reposition`): they keep the panel attached, re-flip it, and only close
8284
+ // it once the control scrolls fully out of view.
7617
8285
  closeDropdown() {
7618
8286
  const wasOpen = this.isOpen();
8287
+ // Put the panel back where Angular expects it before the @if removes it.
8288
+ this.restorePanel();
7619
8289
  this.isOpen.set(false);
7620
8290
  this.searchTerm.set('');
7621
8291
  this.breadcrumb.set([]);
@@ -7660,8 +8330,14 @@ class BkHierarchicalSelect {
7660
8330
  this.openDropdown();
7661
8331
  }
7662
8332
  onClickOutside(e) {
7663
- if (!this.el.nativeElement.contains(e.target))
7664
- this.closeDropdown();
8333
+ const target = e.target;
8334
+ // When appendToBody relocates the panel to <body>, it's no longer inside the
8335
+ // host element — treat clicks within the panel as "inside" too.
8336
+ if (this.el.nativeElement.contains(target))
8337
+ return;
8338
+ if (this.dropdownPanel?.nativeElement.contains(target))
8339
+ return;
8340
+ this.closeDropdown();
7665
8341
  }
7666
8342
  // --- ControlValueAccessor ---
7667
8343
  _value = null;
@@ -7705,13 +8381,13 @@ class BkHierarchicalSelect {
7705
8381
  this.clear.emit(null);
7706
8382
  }
7707
8383
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkHierarchicalSelect, deps: [], target: i0.ɵɵFactoryTarget.Component });
7708
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkHierarchicalSelect, isStandalone: true, selector: "bk-hierarchical-select", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, labelKey: { classPropertyName: "labelKey", publicName: "labelKey", isSignal: true, isRequired: false, transformFunction: null }, valueKey: { classPropertyName: "valueKey", publicName: "valueKey", isSignal: true, isRequired: false, transformFunction: null }, childrenKey: { classPropertyName: "childrenKey", publicName: "childrenKey", isSignal: true, isRequired: false, transformFunction: null }, clearTooltip: { classPropertyName: "clearTooltip", publicName: "clearTooltip", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, iconSrc: { classPropertyName: "iconSrc", publicName: "iconSrc", isSignal: true, isRequired: false, transformFunction: null }, iconAlt: { classPropertyName: "iconAlt", publicName: "iconAlt", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, allowParentSelection: { classPropertyName: "allowParentSelection", publicName: "allowParentSelection", isSignal: true, isRequired: false, transformFunction: null }, backToMainText: { classPropertyName: "backToMainText", publicName: "backToMainText", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, appendToBody: { classPropertyName: "appendToBody", publicName: "appendToBody", isSignal: true, isRequired: false, transformFunction: null }, dropdownPosition: { classPropertyName: "dropdownPosition", publicName: "dropdownPosition", isSignal: true, isRequired: false, transformFunction: null }, colorKey: { classPropertyName: "colorKey", publicName: "colorKey", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, restrictKey: { classPropertyName: "restrictKey", publicName: "restrictKey", isSignal: true, isRequired: false, transformFunction: null }, hasError: { classPropertyName: "hasError", publicName: "hasError", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionChange: "selectionChange", valueChange: "valueChange", clear: "clear" }, host: { listeners: { "window:scroll": "onWindowScrollOrResize()", "window:resize": "onWindowScrollOrResize()", "document:click": "onClickOutside($event)" } }, providers: [
8384
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkHierarchicalSelect, isStandalone: true, selector: "bk-hierarchical-select", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, labelKey: { classPropertyName: "labelKey", publicName: "labelKey", isSignal: true, isRequired: false, transformFunction: null }, valueKey: { classPropertyName: "valueKey", publicName: "valueKey", isSignal: true, isRequired: false, transformFunction: null }, childrenKey: { classPropertyName: "childrenKey", publicName: "childrenKey", isSignal: true, isRequired: false, transformFunction: null }, clearTooltip: { classPropertyName: "clearTooltip", publicName: "clearTooltip", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, iconSrc: { classPropertyName: "iconSrc", publicName: "iconSrc", isSignal: true, isRequired: false, transformFunction: null }, iconAlt: { classPropertyName: "iconAlt", publicName: "iconAlt", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, allowParentSelection: { classPropertyName: "allowParentSelection", publicName: "allowParentSelection", isSignal: true, isRequired: false, transformFunction: null }, backToMainText: { classPropertyName: "backToMainText", publicName: "backToMainText", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, appendToBody: { classPropertyName: "appendToBody", publicName: "appendToBody", isSignal: true, isRequired: false, transformFunction: null }, dropdownPosition: { classPropertyName: "dropdownPosition", publicName: "dropdownPosition", isSignal: true, isRequired: false, transformFunction: null }, colorKey: { classPropertyName: "colorKey", publicName: "colorKey", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, restrictKey: { classPropertyName: "restrictKey", publicName: "restrictKey", isSignal: true, isRequired: false, transformFunction: null }, hasError: { classPropertyName: "hasError", publicName: "hasError", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionChange: "selectionChange", valueChange: "valueChange", clear: "clear" }, host: { listeners: { "document:click": "onClickOutside($event)" } }, providers: [
7709
8385
  {
7710
8386
  provide: NG_VALUE_ACCESSOR,
7711
8387
  useExisting: forwardRef(() => BkHierarchicalSelect),
7712
8388
  multi: true,
7713
8389
  },
7714
- ], viewQueries: [{ propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true }, { propertyName: "controlWrapper", first: true, predicate: ["controlWrapper"], 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 <div\r\n #controlWrapper\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 (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 <div class=\"hierarchical-value-label\" [style.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\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)\" [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 @if (isOpen()) {\r\n <div\r\n class=\"hierarchical-dropdown-panel\"\r\n [attr.data-position]=\"dropdownPosition()\"\r\n [class.hierarchical-dropdown-panel-fixed]=\"appendToBody()\"\r\n [style.position]=\"appendToBody() ? 'fixed' : 'absolute'\"\r\n [style.top]=\"appendToBody() ? getTop() : null\"\r\n [style.bottom]=\"appendToBody() ? getBottom() : null\"\r\n [style.left]=\"appendToBody() ? dropdownStyle().left : null\"\r\n [style.width]=\"appendToBody() ? dropdownStyle().width : '100%'\">\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 (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 (click)=\"goBack(); $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 class=\"hierarchical-options-list\">\r\n @for (item of filteredItems(); track getValue(item)) {\r\n <div\r\n class=\"hierarchical-option\"\r\n [class.selected]=\"isSelected(item)\"\r\n [class.disabled-item]=\"item.disabled\"\r\n [class.cursor-not-allowed]=\"item.disabled\"\r\n (mousedown)=\"selectItem(item, $event)\">\r\n <span\r\n #optLabel\r\n class=\"hierarchical-option-label\"\r\n [style.color]=\"resolveColor(item)\"\r\n [bkTooltip]=\"optLabel.scrollWidth > optLabel.clientWidth ? getLabel(item) : ''\"\r\n bkTooltipPosition=\"top\">{{ getLabel(item) }}</span>\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 }\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 bg-[#F4F4F6] cursor-not-allowed opacity-60;}.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-label{@apply font-normal text-sm leading-[18px] text-[#141414] truncate w-full flex items-center;}.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 absolute left-0 w-full min-w-[250px] max-w-full bg-white border border-[#E3E3E7] rounded-xl shadow-lg z-[99] overflow-hidden cursor-default p-2.5;}.hierarchical-dropdown-panel[data-position=bottom]{top:calc(100% + 4px);bottom:auto}.hierarchical-dropdown-panel[data-position=top]{bottom:calc(100% + 4px);top:auto}.hierarchical-dropdown-panel-fixed{z-index:10050}.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-search-input:-moz-focusring{outline:none}.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.selected{@apply bg-[#F8F8F8];}.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-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{@apply border-[#d11e14];}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: BKTooltipDirective, selector: "[bkTooltip]", inputs: ["bkTooltip", "bkTooltipPosition", "bkTooltipScrollable", "bkTooltipMaxHeight", "bkTooltipSize", "bkTooltipAutoHeight"] }] });
8390
+ ], 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 }], 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 <div\r\n #controlWrapper\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 (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 <div class=\"hierarchical-value-label\" [style.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\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 @if (isOpen()) {\r\n <div\r\n #dropdownPanel\r\n class=\"hierarchical-dropdown-panel\"\r\n [attr.data-position]=\"placement()\"\r\n [class.hierarchical-dropdown-panel-fixed]=\"appendToBody()\"\r\n [style.position]=\"appendToBody() ? 'fixed' : 'absolute'\"\r\n [style.top]=\"appendToBody() ? getTop() : null\"\r\n [style.bottom]=\"appendToBody() ? getBottom() : null\"\r\n [style.left]=\"appendToBody() ? dropdownStyle().left : null\"\r\n [style.width]=\"appendToBody() ? dropdownStyle().width : '100%'\">\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 (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 (click)=\"goBack(); $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 class=\"hierarchical-options-list\">\r\n @for (item of filteredItems(); track getValue(item)) {\r\n <div\r\n class=\"hierarchical-option\"\r\n [class.selected]=\"isSelected(item)\"\r\n [class.disabled-item]=\"item.disabled\"\r\n [class.cursor-not-allowed]=\"item.disabled\"\r\n (mousedown)=\"selectItem(item, $event)\">\r\n <span\r\n #optLabel\r\n class=\"hierarchical-option-label\"\r\n [style.color]=\"resolveColor(item)\"\r\n [bkTooltip]=\"optLabel.scrollWidth > optLabel.clientWidth ? getLabel(item) : ''\"\r\n bkTooltipPosition=\"top\">{{ getLabel(item) }}</span>\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 }\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 bg-[#F4F4F6] cursor-not-allowed opacity-60;}.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-label{@apply font-normal text-sm leading-[18px] text-[#141414] truncate w-full flex items-center;}.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 absolute left-0 w-full min-w-[250px] max-w-full bg-white border border-[#E3E3E7] rounded-xl shadow-lg z-[99] overflow-hidden cursor-default p-2.5;}.hierarchical-dropdown-panel[data-position=bottom]{top:calc(100% + 4px);bottom:auto}.hierarchical-dropdown-panel[data-position=top]{bottom:calc(100% + 4px);top:auto}.hierarchical-dropdown-panel-fixed{z-index:10050}.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-search-input:-moz-focusring{outline:none}.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.selected{@apply bg-[#F8F8F8];}.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-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{@apply border-[#d11e14];}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: BKTooltipDirective, selector: "[bkTooltip]", inputs: ["bkTooltip", "bkTooltipPosition", "bkTooltipScrollable", "bkTooltipMaxHeight", "bkTooltipSize", "bkTooltipAutoHeight"] }] });
7715
8391
  }
7716
8392
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkHierarchicalSelect, decorators: [{
7717
8393
  type: Component,
@@ -7721,19 +8397,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
7721
8397
  useExisting: forwardRef(() => BkHierarchicalSelect),
7722
8398
  multi: true,
7723
8399
  },
7724
- ], 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 <div\r\n #controlWrapper\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 (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 <div class=\"hierarchical-value-label\" [style.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\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)\" [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 @if (isOpen()) {\r\n <div\r\n class=\"hierarchical-dropdown-panel\"\r\n [attr.data-position]=\"dropdownPosition()\"\r\n [class.hierarchical-dropdown-panel-fixed]=\"appendToBody()\"\r\n [style.position]=\"appendToBody() ? 'fixed' : 'absolute'\"\r\n [style.top]=\"appendToBody() ? getTop() : null\"\r\n [style.bottom]=\"appendToBody() ? getBottom() : null\"\r\n [style.left]=\"appendToBody() ? dropdownStyle().left : null\"\r\n [style.width]=\"appendToBody() ? dropdownStyle().width : '100%'\">\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 (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 (click)=\"goBack(); $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 class=\"hierarchical-options-list\">\r\n @for (item of filteredItems(); track getValue(item)) {\r\n <div\r\n class=\"hierarchical-option\"\r\n [class.selected]=\"isSelected(item)\"\r\n [class.disabled-item]=\"item.disabled\"\r\n [class.cursor-not-allowed]=\"item.disabled\"\r\n (mousedown)=\"selectItem(item, $event)\">\r\n <span\r\n #optLabel\r\n class=\"hierarchical-option-label\"\r\n [style.color]=\"resolveColor(item)\"\r\n [bkTooltip]=\"optLabel.scrollWidth > optLabel.clientWidth ? getLabel(item) : ''\"\r\n bkTooltipPosition=\"top\">{{ getLabel(item) }}</span>\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 }\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 bg-[#F4F4F6] cursor-not-allowed opacity-60;}.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-label{@apply font-normal text-sm leading-[18px] text-[#141414] truncate w-full flex items-center;}.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 absolute left-0 w-full min-w-[250px] max-w-full bg-white border border-[#E3E3E7] rounded-xl shadow-lg z-[99] overflow-hidden cursor-default p-2.5;}.hierarchical-dropdown-panel[data-position=bottom]{top:calc(100% + 4px);bottom:auto}.hierarchical-dropdown-panel[data-position=top]{bottom:calc(100% + 4px);top:auto}.hierarchical-dropdown-panel-fixed{z-index:10050}.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-search-input:-moz-focusring{outline:none}.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.selected{@apply bg-[#F8F8F8];}.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-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{@apply border-[#d11e14];}\n"] }]
8400
+ ], 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 <div\r\n #controlWrapper\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 (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 <div class=\"hierarchical-value-label\" [style.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\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 @if (isOpen()) {\r\n <div\r\n #dropdownPanel\r\n class=\"hierarchical-dropdown-panel\"\r\n [attr.data-position]=\"placement()\"\r\n [class.hierarchical-dropdown-panel-fixed]=\"appendToBody()\"\r\n [style.position]=\"appendToBody() ? 'fixed' : 'absolute'\"\r\n [style.top]=\"appendToBody() ? getTop() : null\"\r\n [style.bottom]=\"appendToBody() ? getBottom() : null\"\r\n [style.left]=\"appendToBody() ? dropdownStyle().left : null\"\r\n [style.width]=\"appendToBody() ? dropdownStyle().width : '100%'\">\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 (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 (click)=\"goBack(); $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 class=\"hierarchical-options-list\">\r\n @for (item of filteredItems(); track getValue(item)) {\r\n <div\r\n class=\"hierarchical-option\"\r\n [class.selected]=\"isSelected(item)\"\r\n [class.disabled-item]=\"item.disabled\"\r\n [class.cursor-not-allowed]=\"item.disabled\"\r\n (mousedown)=\"selectItem(item, $event)\">\r\n <span\r\n #optLabel\r\n class=\"hierarchical-option-label\"\r\n [style.color]=\"resolveColor(item)\"\r\n [bkTooltip]=\"optLabel.scrollWidth > optLabel.clientWidth ? getLabel(item) : ''\"\r\n bkTooltipPosition=\"top\">{{ getLabel(item) }}</span>\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 }\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 bg-[#F4F4F6] cursor-not-allowed opacity-60;}.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-label{@apply font-normal text-sm leading-[18px] text-[#141414] truncate w-full flex items-center;}.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 absolute left-0 w-full min-w-[250px] max-w-full bg-white border border-[#E3E3E7] rounded-xl shadow-lg z-[99] overflow-hidden cursor-default p-2.5;}.hierarchical-dropdown-panel[data-position=bottom]{top:calc(100% + 4px);bottom:auto}.hierarchical-dropdown-panel[data-position=top]{bottom:calc(100% + 4px);top:auto}.hierarchical-dropdown-panel-fixed{z-index:10050}.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-search-input:-moz-focusring{outline:none}.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.selected{@apply bg-[#F8F8F8];}.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-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{@apply border-[#d11e14];}\n"] }]
7725
8401
  }], ctorParameters: () => [], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], labelKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelKey", required: false }] }], valueKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueKey", required: false }] }], childrenKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "childrenKey", required: false }] }], clearTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearTooltip", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], iconSrc: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconSrc", required: false }] }], iconAlt: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconAlt", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], allowParentSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowParentSelection", required: false }] }], backToMainText: [{ type: i0.Input, args: [{ isSignal: true, alias: "backToMainText", required: false }] }], searchPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchPlaceholder", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], appendToBody: [{ type: i0.Input, args: [{ isSignal: true, alias: "appendToBody", required: false }] }], dropdownPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "dropdownPosition", required: false }] }], colorKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "colorKey", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], restrictKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "restrictKey", required: false }] }], hasError: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasError", required: false }] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], clear: [{ type: i0.Output, args: ["clear"] }], searchInput: [{
7726
8402
  type: ViewChild,
7727
8403
  args: ['searchInput']
7728
8404
  }], controlWrapper: [{
7729
8405
  type: ViewChild,
7730
8406
  args: ['controlWrapper']
7731
- }], onWindowScrollOrResize: [{
7732
- type: HostListener,
7733
- args: ['window:scroll']
7734
- }, {
7735
- type: HostListener,
7736
- args: ['window:resize']
8407
+ }], dropdownPanel: [{
8408
+ type: ViewChild,
8409
+ args: ['dropdownPanel']
7737
8410
  }], onClickOutside: [{
7738
8411
  type: HostListener,
7739
8412
  args: ['document:click', ['$event']]
@@ -8864,6 +9537,150 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
8864
9537
  args: ['document:keydown.escape']
8865
9538
  }] } });
8866
9539
 
9540
+ /**
9541
+ * A simple, responsive navigation menu. Styled to match the default `bk-tabs`
9542
+ * theme (dark active pill, light hover).
9543
+ *
9544
+ * - Orientation: `vertical` (stacked) / `horizontal` (menubar row).
9545
+ * - Items with `children` are expandable, shown with a chevron that rotates
9546
+ * open/closed.
9547
+ * - Submenus render inline (accordion) or as pop-ups. Pop-ups adapt to the
9548
+ * orientation: they drop *below* a horizontal top-level item and fly out to
9549
+ * the *right* for vertical menus / deeper levels.
9550
+ */
9551
+ class BkMenu {
9552
+ host;
9553
+ items = [];
9554
+ orientation = 'vertical';
9555
+ submenuMode = 'inline';
9556
+ /**
9557
+ * Keep only one submenu open per level: opening a parent collapses its
9558
+ * siblings (and their descendants) so the menu stays compact. Pop-up mode
9559
+ * always behaves this way; this input adds it to inline (accordion) mode.
9560
+ */
9561
+ singleOpen = false;
9562
+ /** Id of the currently selected leaf item. Two-way bindable. */
9563
+ activeItemId = '';
9564
+ /** Tint item icons: dark by default, white on the active (dark) row. */
9565
+ tintIcons = true;
9566
+ activeItemIdChange = new EventEmitter();
9567
+ itemClick = new EventEmitter();
9568
+ /** Ids of currently expanded/opened parent nodes. */
9569
+ openIds = new Set();
9570
+ constructor(host) {
9571
+ this.host = host;
9572
+ }
9573
+ get isVertical() { return this.orientation === 'vertical'; }
9574
+ get isPopup() { return this.submenuMode === 'popup'; }
9575
+ hasChildren(item) {
9576
+ return !!item.children && item.children.length > 0;
9577
+ }
9578
+ isOpen(item) {
9579
+ return this.openIds.has(item.id);
9580
+ }
9581
+ isActive(item) {
9582
+ return this.activeItemId === item.id;
9583
+ }
9584
+ // True when the active leaf lives somewhere inside this item's subtree, so a
9585
+ // parent shows the active state even after its pop-up closes.
9586
+ isActiveAncestor(item) {
9587
+ return !!item.children && item.children.some(child => child.id === this.activeItemId || this.isActiveAncestor(child));
9588
+ }
9589
+ // Highlight = the item itself is active. In pop-up mode a parent also lights
9590
+ // up when one of its descendants is active (so the section stays marked after
9591
+ // the fly-out closes); inline mode highlights the selected leaf only.
9592
+ isHighlighted(item) {
9593
+ return this.isActive(item) || (this.isPopup && this.isActiveAncestor(item));
9594
+ }
9595
+ // Left indent for inline nested items (vertical only).
9596
+ inlineIndent(level) {
9597
+ return this.isVertical && !this.isPopup ? 16 + level * 16 : null;
9598
+ }
9599
+ // Handle a click on any menu button.
9600
+ // Leaves select + emit. Parents toggle in inline mode; in pop-up mode they
9601
+ // are opened by hover, so a click on a parent does nothing.
9602
+ onItemClick(item, siblings, event) {
9603
+ event.stopPropagation();
9604
+ if (item.disabled)
9605
+ return;
9606
+ if (this.hasChildren(item)) {
9607
+ if (!this.isPopup)
9608
+ this.toggle(item, siblings);
9609
+ return;
9610
+ }
9611
+ this.activeItemId = item.id;
9612
+ this.activeItemIdChange.emit(item.id);
9613
+ this.itemClick.emit(item);
9614
+ if (this.isPopup)
9615
+ this.openIds.clear(); // dismiss pop-ups after picking a leaf
9616
+ }
9617
+ // Pop-up mode: open a parent's fly-out on hover (and close its siblings).
9618
+ onItemEnter(item, siblings) {
9619
+ if (!this.isPopup || item.disabled || !this.hasChildren(item))
9620
+ return;
9621
+ for (const sibling of siblings) {
9622
+ if (sibling.id !== item.id)
9623
+ this.closeBranch(sibling);
9624
+ }
9625
+ this.openIds.add(item.id);
9626
+ }
9627
+ // Pop-up mode: close the fly-out (and any nested ones) when the pointer leaves.
9628
+ onItemLeave(item) {
9629
+ if (!this.isPopup || !this.hasChildren(item))
9630
+ return;
9631
+ this.closeBranch(item);
9632
+ }
9633
+ toggle(item, siblings) {
9634
+ const wasOpen = this.openIds.has(item.id);
9635
+ if (this.isPopup || this.singleOpen) {
9636
+ // Keep a single open branch per level — collapse siblings (and their
9637
+ // descendants) first so the menu stays compact.
9638
+ for (const sibling of siblings)
9639
+ this.closeBranch(sibling);
9640
+ }
9641
+ if (wasOpen)
9642
+ this.closeBranch(item);
9643
+ else
9644
+ this.openIds.add(item.id);
9645
+ }
9646
+ // Remove an item and all of its descendants from the open set.
9647
+ closeBranch(item) {
9648
+ this.openIds.delete(item.id);
9649
+ item.children?.forEach(child => this.closeBranch(child));
9650
+ }
9651
+ // Pop-up mode: click outside the menu closes any open fly-outs.
9652
+ onDocumentClick(event) {
9653
+ if (this.isPopup && !this.host.nativeElement.contains(event.target)) {
9654
+ this.openIds.clear();
9655
+ }
9656
+ }
9657
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkMenu, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
9658
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkMenu, isStandalone: true, selector: "bk-menu", inputs: { items: "items", orientation: "orientation", submenuMode: "submenuMode", singleOpen: "singleOpen", activeItemId: "activeItemId", tintIcons: "tintIcons" }, outputs: { activeItemIdChange: "activeItemIdChange", itemClick: "itemClick" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, ngImport: i0, template: "<nav\r\n class=\"bk-menu\"\r\n [class.bk-menu--vertical]=\"isVertical\"\r\n [class.bk-menu--horizontal]=\"!isVertical\"\r\n [class.bk-menu--popup]=\"isPopup\"\r\n [class.bk-menu--tint]=\"tintIcons\"\r\n role=\"menubar\"\r\n [attr.aria-orientation]=\"orientation\">\r\n <ul class=\"bk-menu__list\">\r\n <ng-container *ngTemplateOutlet=\"itemTpl; context: { $implicit: items, level: 0 }\"></ng-container>\r\n </ul>\r\n</nav>\r\n\r\n<!-- Recursive item renderer. Context: $implicit = items at this level, level = depth. -->\r\n<ng-template #itemTpl let-items let-level=\"level\">\r\n @for (item of items; track item.id) {\r\n <li\r\n class=\"bk-menu__item\"\r\n [class.bk-menu__item--has-children]=\"hasChildren(item)\"\r\n [class.bk-menu__item--open]=\"isOpen(item)\"\r\n (mouseenter)=\"onItemEnter(item, items)\"\r\n (mouseleave)=\"onItemLeave(item)\"\r\n role=\"none\">\r\n <button\r\n type=\"button\"\r\n class=\"bk-menu__button\"\r\n [class.bk-menu__button--active]=\"isHighlighted(item)\"\r\n [class.bk-menu__button--disabled]=\"item.disabled\"\r\n [class.bk-menu__button--parent]=\"hasChildren(item)\"\r\n [style.paddingLeft.px]=\"inlineIndent(level)\"\r\n [disabled]=\"item.disabled\"\r\n [attr.aria-haspopup]=\"hasChildren(item) ? 'true' : null\"\r\n [attr.aria-expanded]=\"hasChildren(item) ? isOpen(item) : null\"\r\n role=\"menuitem\"\r\n (click)=\"onItemClick(item, items, $event)\">\r\n @if (item.icon) {\r\n <img class=\"bk-menu__icon\" [attr.src]=\"item.icon\" [alt]=\"item.iconAlt || item.label\" />\r\n }\r\n <span class=\"bk-menu__label\">{{ item.label }}</span>\r\n @if (hasChildren(item)) {\r\n <svg\r\n class=\"bk-menu__chevron\"\r\n [class.bk-menu__chevron--open]=\"!isPopup && isOpen(item)\"\r\n [class.bk-menu__chevron--right]=\"isPopup && (isVertical || level > 0)\"\r\n viewBox=\"0 0 24 24\"\r\n width=\"16\"\r\n height=\"16\"\r\n fill=\"none\"\r\n aria-hidden=\"true\">\r\n <path d=\"M6 9L12 15L18 9\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n </svg>\r\n }\r\n </button>\r\n\r\n @if (hasChildren(item)) {\r\n <ul\r\n class=\"bk-menu__submenu\"\r\n [class.bk-menu__submenu--inline]=\"!isPopup\"\r\n [class.bk-menu__submenu--popup]=\"isPopup\"\r\n [class.bk-menu__submenu--open]=\"isOpen(item)\"\r\n [class.bk-menu__submenu--popup-right]=\"isPopup && (isVertical || level > 0)\"\r\n [class.bk-menu__submenu--popup-down]=\"isPopup && !isVertical && level === 0\"\r\n role=\"menu\">\r\n <ng-container\r\n *ngTemplateOutlet=\"itemTpl; context: { $implicit: item.children, level: level + 1 }\">\r\n </ng-container>\r\n </ul>\r\n }\r\n </li>\r\n }\r\n</ng-template>\r\n", styles: [".bk-menu{--menu-bg: #ffffff;--menu-text: #141414;--menu-subtext: #6b7080;--menu-hover-bg: #edeef0;--menu-hover-text: #141414;--menu-active-bg: #141414;--menu-active-text: #ffffff;--menu-border: #efeff1;--menu-shadow: 0 7px 18px 0 rgba(0, 0, 0, .09);--menu-radius: 8px;--menu-disabled: .5;display:block;width:100%;font-size:.875rem;line-height:1.25rem;font-weight:500;letter-spacing:-.28px;background:var(--menu-bg);color:var(--menu-text);border:1px solid var(--menu-border);border-radius:var(--menu-radius)}.bk-menu:not(.bk-menu--popup){overflow:hidden}.bk-menu--popup.bk-menu--vertical>.bk-menu__list>.bk-menu__item:first-child>.bk-menu__button{border-radius:8px 8px 0 0}.bk-menu--popup.bk-menu--vertical>.bk-menu__list>.bk-menu__item:last-child>.bk-menu__button{border-radius:0 0 8px 8px}.bk-menu--popup.bk-menu--horizontal>.bk-menu__list>.bk-menu__item:first-child>.bk-menu__button{border-radius:8px 0 0 8px}.bk-menu--popup.bk-menu--horizontal>.bk-menu__list>.bk-menu__item:last-child>.bk-menu__button{border-radius:0 8px 8px 0}.bk-menu__list,.bk-menu__submenu{list-style:none;margin:0;padding:0}.bk-menu--horizontal>.bk-menu__list{display:flex;flex-direction:row;align-items:stretch}.bk-menu--horizontal:not(.bk-menu--popup)>.bk-menu__list{overflow-x:auto}.bk-menu__item{position:relative}.bk-menu__button{display:flex;align-items:center;gap:8px;width:100%;padding:10px 12px;margin:0;border:0;background:transparent;color:inherit;font:inherit;letter-spacing:inherit;text-align:left;cursor:pointer;white-space:nowrap;border-radius:6px;transition:background .1s ease,color .1s ease}.bk-menu--horizontal>.bk-menu__list>.bk-menu__item>.bk-menu__button{width:auto}.bk-menu__button:hover:not(:disabled):not(.bk-menu__button--active){background:var(--menu-hover-bg);color:var(--menu-hover-text)}.bk-menu__button--active{background:var(--menu-active-bg);color:var(--menu-active-text)}.bk-menu__button--disabled,.bk-menu__button:disabled{opacity:var(--menu-disabled);cursor:not-allowed}.bk-menu__submenu .bk-menu__button{color:var(--menu-subtext);font-weight:400}.bk-menu__submenu .bk-menu__button--active{color:var(--menu-active-text)}.bk-menu__icon{width:16px;height:16px;flex-shrink:0;object-fit:contain}.bk-menu--tint .bk-menu__icon{filter:brightness(0) saturate(0)}.bk-menu--tint .bk-menu__button--active .bk-menu__icon{filter:brightness(0) invert(1)}.bk-menu__label{flex:1 1 auto;min-width:0}.bk-menu--horizontal>.bk-menu__list>.bk-menu__item>.bk-menu__button>.bk-menu__label{flex:0 0 auto}.bk-menu__chevron{flex-shrink:0;transition:transform .18s ease;opacity:.8}.bk-menu__chevron--open{transform:rotate(180deg)}.bk-menu__chevron--right{transform:rotate(-90deg)}.bk-menu__submenu--inline{overflow:hidden;max-height:0;transition:max-height .2s ease}.bk-menu__submenu--inline.bk-menu__submenu--open{max-height:1000px}.bk-menu__submenu--popup{position:absolute;z-index:50;min-width:200px;background:var(--menu-bg);border:1px solid var(--menu-border);border-radius:12px;box-shadow:var(--menu-shadow);padding:4px;display:none}.bk-menu__submenu--popup.bk-menu__submenu--open{display:block}.bk-menu__submenu--popup-right{top:0;left:100%;margin-left:4px}.bk-menu__submenu--popup-down{top:100%;left:0;margin-top:4px}.bk-menu__submenu--popup-right:before{content:\"\";position:absolute;top:0;left:-6px;width:6px;height:100%}.bk-menu__submenu--popup-down:before{content:\"\";position:absolute;top:-6px;left:0;width:100%;height:6px}@media (max-width: 640px){.bk-menu--horizontal>.bk-menu__list{flex-direction:column;overflow-x:visible}.bk-menu--horizontal>.bk-menu__list>.bk-menu__item>.bk-menu__button{width:100%}.bk-menu--horizontal .bk-menu__submenu--popup-down{position:static;box-shadow:none;border:0;margin:0;border-radius:0}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
9659
+ }
9660
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkMenu, decorators: [{
9661
+ type: Component,
9662
+ args: [{ selector: 'bk-menu', imports: [CommonModule], template: "<nav\r\n class=\"bk-menu\"\r\n [class.bk-menu--vertical]=\"isVertical\"\r\n [class.bk-menu--horizontal]=\"!isVertical\"\r\n [class.bk-menu--popup]=\"isPopup\"\r\n [class.bk-menu--tint]=\"tintIcons\"\r\n role=\"menubar\"\r\n [attr.aria-orientation]=\"orientation\">\r\n <ul class=\"bk-menu__list\">\r\n <ng-container *ngTemplateOutlet=\"itemTpl; context: { $implicit: items, level: 0 }\"></ng-container>\r\n </ul>\r\n</nav>\r\n\r\n<!-- Recursive item renderer. Context: $implicit = items at this level, level = depth. -->\r\n<ng-template #itemTpl let-items let-level=\"level\">\r\n @for (item of items; track item.id) {\r\n <li\r\n class=\"bk-menu__item\"\r\n [class.bk-menu__item--has-children]=\"hasChildren(item)\"\r\n [class.bk-menu__item--open]=\"isOpen(item)\"\r\n (mouseenter)=\"onItemEnter(item, items)\"\r\n (mouseleave)=\"onItemLeave(item)\"\r\n role=\"none\">\r\n <button\r\n type=\"button\"\r\n class=\"bk-menu__button\"\r\n [class.bk-menu__button--active]=\"isHighlighted(item)\"\r\n [class.bk-menu__button--disabled]=\"item.disabled\"\r\n [class.bk-menu__button--parent]=\"hasChildren(item)\"\r\n [style.paddingLeft.px]=\"inlineIndent(level)\"\r\n [disabled]=\"item.disabled\"\r\n [attr.aria-haspopup]=\"hasChildren(item) ? 'true' : null\"\r\n [attr.aria-expanded]=\"hasChildren(item) ? isOpen(item) : null\"\r\n role=\"menuitem\"\r\n (click)=\"onItemClick(item, items, $event)\">\r\n @if (item.icon) {\r\n <img class=\"bk-menu__icon\" [attr.src]=\"item.icon\" [alt]=\"item.iconAlt || item.label\" />\r\n }\r\n <span class=\"bk-menu__label\">{{ item.label }}</span>\r\n @if (hasChildren(item)) {\r\n <svg\r\n class=\"bk-menu__chevron\"\r\n [class.bk-menu__chevron--open]=\"!isPopup && isOpen(item)\"\r\n [class.bk-menu__chevron--right]=\"isPopup && (isVertical || level > 0)\"\r\n viewBox=\"0 0 24 24\"\r\n width=\"16\"\r\n height=\"16\"\r\n fill=\"none\"\r\n aria-hidden=\"true\">\r\n <path d=\"M6 9L12 15L18 9\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n </svg>\r\n }\r\n </button>\r\n\r\n @if (hasChildren(item)) {\r\n <ul\r\n class=\"bk-menu__submenu\"\r\n [class.bk-menu__submenu--inline]=\"!isPopup\"\r\n [class.bk-menu__submenu--popup]=\"isPopup\"\r\n [class.bk-menu__submenu--open]=\"isOpen(item)\"\r\n [class.bk-menu__submenu--popup-right]=\"isPopup && (isVertical || level > 0)\"\r\n [class.bk-menu__submenu--popup-down]=\"isPopup && !isVertical && level === 0\"\r\n role=\"menu\">\r\n <ng-container\r\n *ngTemplateOutlet=\"itemTpl; context: { $implicit: item.children, level: level + 1 }\">\r\n </ng-container>\r\n </ul>\r\n }\r\n </li>\r\n }\r\n</ng-template>\r\n", styles: [".bk-menu{--menu-bg: #ffffff;--menu-text: #141414;--menu-subtext: #6b7080;--menu-hover-bg: #edeef0;--menu-hover-text: #141414;--menu-active-bg: #141414;--menu-active-text: #ffffff;--menu-border: #efeff1;--menu-shadow: 0 7px 18px 0 rgba(0, 0, 0, .09);--menu-radius: 8px;--menu-disabled: .5;display:block;width:100%;font-size:.875rem;line-height:1.25rem;font-weight:500;letter-spacing:-.28px;background:var(--menu-bg);color:var(--menu-text);border:1px solid var(--menu-border);border-radius:var(--menu-radius)}.bk-menu:not(.bk-menu--popup){overflow:hidden}.bk-menu--popup.bk-menu--vertical>.bk-menu__list>.bk-menu__item:first-child>.bk-menu__button{border-radius:8px 8px 0 0}.bk-menu--popup.bk-menu--vertical>.bk-menu__list>.bk-menu__item:last-child>.bk-menu__button{border-radius:0 0 8px 8px}.bk-menu--popup.bk-menu--horizontal>.bk-menu__list>.bk-menu__item:first-child>.bk-menu__button{border-radius:8px 0 0 8px}.bk-menu--popup.bk-menu--horizontal>.bk-menu__list>.bk-menu__item:last-child>.bk-menu__button{border-radius:0 8px 8px 0}.bk-menu__list,.bk-menu__submenu{list-style:none;margin:0;padding:0}.bk-menu--horizontal>.bk-menu__list{display:flex;flex-direction:row;align-items:stretch}.bk-menu--horizontal:not(.bk-menu--popup)>.bk-menu__list{overflow-x:auto}.bk-menu__item{position:relative}.bk-menu__button{display:flex;align-items:center;gap:8px;width:100%;padding:10px 12px;margin:0;border:0;background:transparent;color:inherit;font:inherit;letter-spacing:inherit;text-align:left;cursor:pointer;white-space:nowrap;border-radius:6px;transition:background .1s ease,color .1s ease}.bk-menu--horizontal>.bk-menu__list>.bk-menu__item>.bk-menu__button{width:auto}.bk-menu__button:hover:not(:disabled):not(.bk-menu__button--active){background:var(--menu-hover-bg);color:var(--menu-hover-text)}.bk-menu__button--active{background:var(--menu-active-bg);color:var(--menu-active-text)}.bk-menu__button--disabled,.bk-menu__button:disabled{opacity:var(--menu-disabled);cursor:not-allowed}.bk-menu__submenu .bk-menu__button{color:var(--menu-subtext);font-weight:400}.bk-menu__submenu .bk-menu__button--active{color:var(--menu-active-text)}.bk-menu__icon{width:16px;height:16px;flex-shrink:0;object-fit:contain}.bk-menu--tint .bk-menu__icon{filter:brightness(0) saturate(0)}.bk-menu--tint .bk-menu__button--active .bk-menu__icon{filter:brightness(0) invert(1)}.bk-menu__label{flex:1 1 auto;min-width:0}.bk-menu--horizontal>.bk-menu__list>.bk-menu__item>.bk-menu__button>.bk-menu__label{flex:0 0 auto}.bk-menu__chevron{flex-shrink:0;transition:transform .18s ease;opacity:.8}.bk-menu__chevron--open{transform:rotate(180deg)}.bk-menu__chevron--right{transform:rotate(-90deg)}.bk-menu__submenu--inline{overflow:hidden;max-height:0;transition:max-height .2s ease}.bk-menu__submenu--inline.bk-menu__submenu--open{max-height:1000px}.bk-menu__submenu--popup{position:absolute;z-index:50;min-width:200px;background:var(--menu-bg);border:1px solid var(--menu-border);border-radius:12px;box-shadow:var(--menu-shadow);padding:4px;display:none}.bk-menu__submenu--popup.bk-menu__submenu--open{display:block}.bk-menu__submenu--popup-right{top:0;left:100%;margin-left:4px}.bk-menu__submenu--popup-down{top:100%;left:0;margin-top:4px}.bk-menu__submenu--popup-right:before{content:\"\";position:absolute;top:0;left:-6px;width:6px;height:100%}.bk-menu__submenu--popup-down:before{content:\"\";position:absolute;top:-6px;left:0;width:100%;height:6px}@media (max-width: 640px){.bk-menu--horizontal>.bk-menu__list{flex-direction:column;overflow-x:visible}.bk-menu--horizontal>.bk-menu__list>.bk-menu__item>.bk-menu__button{width:100%}.bk-menu--horizontal .bk-menu__submenu--popup-down{position:static;box-shadow:none;border:0;margin:0;border-radius:0}}\n"] }]
9663
+ }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { items: [{
9664
+ type: Input
9665
+ }], orientation: [{
9666
+ type: Input
9667
+ }], submenuMode: [{
9668
+ type: Input
9669
+ }], singleOpen: [{
9670
+ type: Input
9671
+ }], activeItemId: [{
9672
+ type: Input
9673
+ }], tintIcons: [{
9674
+ type: Input
9675
+ }], activeItemIdChange: [{
9676
+ type: Output
9677
+ }], itemClick: [{
9678
+ type: Output
9679
+ }], onDocumentClick: [{
9680
+ type: HostListener,
9681
+ args: ['document:click', ['$event']]
9682
+ }] } });
9683
+
8867
9684
  /*
8868
9685
  * Public API Surface of brickclay-lib
8869
9686
  */
@@ -8873,5 +9690,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
8873
9690
  * Generated bundle index. Do not edit.
8874
9691
  */
8875
9692
 
8876
- export { BKTooltipDirective, BK_DEFAULT_DIALOG_CONFIG, BK_DIALOG_DATA, BK_DIALOG_GLOBAL_CONFIG, BkAvatar, BkAvatarUploader, BkBadge, BkButton, BkButtonGroup, BkCalendarManagerService, BkCheckbox, BkColumnFilterService, BkColumnSelect, BkCustomCalendar, BkDialogActions, BkDialogClose, BkDialogContent, BkDialogModule, BkDialogRef, BkDialogService, BkDialogTitle, BkDropdown, BkFileCard, BkFilePicker, BkGrid, BkHierarchicalSelect, BkIconButton, BkInput, BkInputChips, BkLoader, BkPagination, BkPill, BkRadioButton, BkScheduledDatePicker, BkSelect, BkSpinner, BkTabs, BkTextarea, BkTimePicker, BkToastr, BkToastrService, BkToggle, BkValidator, BrickclayIcons, BrickclayLib, CalendarModule, CalendarSelection, ColumnFilterOption, getDialogBackdropAnimation, getDialogPanelAnimation };
9693
+ export { BKTooltipDirective, BK_DEFAULT_DIALOG_CONFIG, BK_DIALOG_DATA, BK_DIALOG_GLOBAL_CONFIG, BkAvatar, BkAvatarUploader, BkBadge, BkButton, BkButtonGroup, BkCalendarManagerService, BkCheckbox, BkColumnFilterService, BkColumnSelect, BkCustomCalendar, BkDialogActions, BkDialogClose, BkDialogContent, BkDialogModule, BkDialogRef, BkDialogService, BkDialogTitle, BkDropdown, BkFileCard, BkFilePicker, BkGrid, BkHierarchicalSelect, BkIconButton, BkInput, BkInputChips, BkLoader, BkMenu, BkPagination, BkPill, BkRadioButton, BkScheduledDatePicker, BkSelect, BkSpinner, BkTabs, BkTextarea, BkTimePicker, BkToastr, BkToastrService, BkToggle, BkValidator, BrickclayIcons, BrickclayLib, CalendarModule, CalendarSelection, ColumnFilterOption, getDialogBackdropAnimation, getDialogPanelAnimation };
8877
9694
  //# sourceMappingURL=brickclay-org-ui.mjs.map