@brickclay-org/ui 0.1.24 → 0.1.26
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.
- package/fesm2022/brickclay-org-ui.mjs +485 -109
- package/fesm2022/brickclay-org-ui.mjs.map +1 -1
- package/index.d.ts +74 -8
- package/package.json +1 -1
|
@@ -413,6 +413,69 @@ class BkCalendarManagerService {
|
|
|
413
413
|
calendarInstances = new Set();
|
|
414
414
|
closeAllSubject = new Subject();
|
|
415
415
|
closeAll$ = this.closeAllSubject.asObservable();
|
|
416
|
+
customRanges = {};
|
|
417
|
+
rangeOrder = [];
|
|
418
|
+
constructor() {
|
|
419
|
+
this.initializeDefaultRanges();
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Returns service-defined custom ranges and their display order.
|
|
423
|
+
* Used when the calendar does not pass customRanges via @Input().
|
|
424
|
+
*/
|
|
425
|
+
getCustomRanges() {
|
|
426
|
+
this.initializeDefaultRanges();
|
|
427
|
+
return {
|
|
428
|
+
customRanges: { ...this.customRanges },
|
|
429
|
+
rangeOrder: [...this.rangeOrder],
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
initializeDefaultRanges() {
|
|
433
|
+
const today = new Date();
|
|
434
|
+
this.customRanges = {
|
|
435
|
+
Today: {
|
|
436
|
+
start: new Date(today.getFullYear(), today.getMonth(), today.getDate()),
|
|
437
|
+
end: new Date(today.getFullYear(), today.getMonth(), today.getDate()),
|
|
438
|
+
},
|
|
439
|
+
Yesterday: {
|
|
440
|
+
start: this.addDays(today, -1),
|
|
441
|
+
end: this.addDays(today, -1),
|
|
442
|
+
},
|
|
443
|
+
'Last 7 Days': {
|
|
444
|
+
start: this.addDays(today, -6),
|
|
445
|
+
end: today,
|
|
446
|
+
},
|
|
447
|
+
'Last 30 Days': {
|
|
448
|
+
start: this.addDays(today, -29),
|
|
449
|
+
end: today,
|
|
450
|
+
},
|
|
451
|
+
'This Month': {
|
|
452
|
+
start: new Date(today.getFullYear(), today.getMonth(), 1),
|
|
453
|
+
end: today,
|
|
454
|
+
},
|
|
455
|
+
'Last Month': {
|
|
456
|
+
start: new Date(today.getFullYear(), today.getMonth() - 1, 1),
|
|
457
|
+
end: new Date(today.getFullYear(), today.getMonth(), 0),
|
|
458
|
+
},
|
|
459
|
+
'Custom Range': {
|
|
460
|
+
start: new Date(),
|
|
461
|
+
end: new Date(),
|
|
462
|
+
},
|
|
463
|
+
};
|
|
464
|
+
this.rangeOrder = [
|
|
465
|
+
'Today',
|
|
466
|
+
'Yesterday',
|
|
467
|
+
'Last 7 Days',
|
|
468
|
+
'Last 30 Days',
|
|
469
|
+
'This Month',
|
|
470
|
+
'Last Month',
|
|
471
|
+
'Custom Range',
|
|
472
|
+
];
|
|
473
|
+
}
|
|
474
|
+
addDays(date, days) {
|
|
475
|
+
const d = new Date(date);
|
|
476
|
+
d.setDate(d.getDate() + days);
|
|
477
|
+
return d;
|
|
478
|
+
}
|
|
416
479
|
/**
|
|
417
480
|
* Register a calendar instance with its close function
|
|
418
481
|
*/
|
|
@@ -455,7 +518,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
455
518
|
args: [{
|
|
456
519
|
providedIn: 'root'
|
|
457
520
|
}]
|
|
458
|
-
}] });
|
|
521
|
+
}], ctorParameters: () => [] });
|
|
459
522
|
|
|
460
523
|
class CalendarSelection {
|
|
461
524
|
startDate = null;
|
|
@@ -480,6 +543,8 @@ class BkCustomCalendar {
|
|
|
480
543
|
customRangeDirection = false;
|
|
481
544
|
lockStartDate = false;
|
|
482
545
|
position = 'left';
|
|
546
|
+
/** Vertical placement relative to the input. Takes precedence over {@link drop} for default bottom placement. */
|
|
547
|
+
popupPosition = 'bottom';
|
|
483
548
|
drop = 'down';
|
|
484
549
|
dualCalendar = false;
|
|
485
550
|
showRanges = true;
|
|
@@ -487,6 +552,8 @@ class BkCustomCalendar {
|
|
|
487
552
|
clearableTime = false;
|
|
488
553
|
enableSeconds = false;
|
|
489
554
|
customRanges;
|
|
555
|
+
/** Column headers for weekdays; index 0 is the first column. Default Monday–Sunday. */
|
|
556
|
+
weekDayLabels = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
|
|
490
557
|
multiDateSelection = false; // NEW: Enable multi-date selection
|
|
491
558
|
maxDate; // NEW: Maximum selectable date
|
|
492
559
|
minDate; // NEW: Minimum selectable date
|
|
@@ -499,8 +566,11 @@ class BkCustomCalendar {
|
|
|
499
566
|
errorMessage = '';
|
|
500
567
|
selected = new EventEmitter();
|
|
501
568
|
inputWrapper;
|
|
569
|
+
calendarPopupRef;
|
|
502
570
|
/** Used when appendToBody is true to position the popup in viewport coordinates */
|
|
503
571
|
dropdownStyle = {};
|
|
572
|
+
/** Resolved after layout; used for CSS `drop-up` and appendToBody positioning with viewport flip */
|
|
573
|
+
popupPlacementAbove = false;
|
|
504
574
|
opened = new EventEmitter();
|
|
505
575
|
closed = new EventEmitter();
|
|
506
576
|
showCancelApply = true;
|
|
@@ -564,15 +634,93 @@ class BkCustomCalendar {
|
|
|
564
634
|
// Track open time-picker within this calendar (for single-open behavior)
|
|
565
635
|
openTimePickerId = null;
|
|
566
636
|
closePickerCounter = {};
|
|
567
|
-
defaultRanges = {};
|
|
568
637
|
activeRange = null; // Track which range is currently active
|
|
569
638
|
rangeOrder = []; // Maintain order of ranges
|
|
639
|
+
/** Keyboard roving focus for date grid (local date, midnight) */
|
|
640
|
+
keyboardFocusDate = null;
|
|
570
641
|
unregisterFn;
|
|
571
642
|
closeAllSubscription;
|
|
572
643
|
closeFn;
|
|
573
644
|
constructor(calendarManager) {
|
|
574
645
|
this.calendarManager = calendarManager;
|
|
575
646
|
}
|
|
647
|
+
/** Weekday headers; falls back to Mon–Sun if the input is not length 7. */
|
|
648
|
+
get resolvedWeekDayLabels() {
|
|
649
|
+
const d = this.weekDayLabels;
|
|
650
|
+
if (d?.length === 7)
|
|
651
|
+
return d;
|
|
652
|
+
return ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
|
|
653
|
+
}
|
|
654
|
+
/** When dual range mode, Apply is blocked until both endpoints exist. */
|
|
655
|
+
get isDualRangeApplyBlocked() {
|
|
656
|
+
if (!this.dualCalendar || this.singleDatePicker || this.multiDateSelection)
|
|
657
|
+
return false;
|
|
658
|
+
return !this.startDate || !this.endDate;
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
661
|
+
* Popup single-date with manual Apply: do not push to ngModel / (selected) until Apply.
|
|
662
|
+
* Inline calendars have no Apply footer, so they always commit immediately.
|
|
663
|
+
*/
|
|
664
|
+
shouldDeferSingleDateCommit() {
|
|
665
|
+
return this.singleDatePicker && !this.autoApply && !this.inline;
|
|
666
|
+
}
|
|
667
|
+
emitSelectionUnlessSingleDateDeferred() {
|
|
668
|
+
if (this.shouldDeferSingleDateCommit())
|
|
669
|
+
return;
|
|
670
|
+
this.emitSelection();
|
|
671
|
+
}
|
|
672
|
+
/** Discard in-popup draft and restore last committed value from {@link selectedValue}. */
|
|
673
|
+
revertSingleDateDraftIfNeeded() {
|
|
674
|
+
if (this.shouldDeferSingleDateCommit()) {
|
|
675
|
+
this.applyValueToState(this.selectedValue ?? null);
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
finishPopupDismissal() {
|
|
679
|
+
if (this.inline)
|
|
680
|
+
return;
|
|
681
|
+
this.revertSingleDateDraftIfNeeded();
|
|
682
|
+
this.show = false;
|
|
683
|
+
this.onTouched();
|
|
684
|
+
this.closed.emit();
|
|
685
|
+
}
|
|
686
|
+
/** User preference before viewport adjustment (legacy `drop` still applies when `popupPosition` is `bottom`). */
|
|
687
|
+
preferPopupAbove() {
|
|
688
|
+
return this.popupPosition === 'top' || (this.popupPosition === 'bottom' && this.drop === 'up');
|
|
689
|
+
}
|
|
690
|
+
resolveCustomRangesFromInputsOrService() {
|
|
691
|
+
const svc = this.calendarManager.getCustomRanges();
|
|
692
|
+
if (!this.customRanges) {
|
|
693
|
+
this.customRanges = { ...svc.customRanges };
|
|
694
|
+
this.rangeOrder = [...svc.rangeOrder];
|
|
695
|
+
}
|
|
696
|
+
else {
|
|
697
|
+
if (!this.rangeOrder?.length) {
|
|
698
|
+
const keys = Object.keys(this.customRanges);
|
|
699
|
+
const ordered = svc.rangeOrder.filter(k => keys.includes(k));
|
|
700
|
+
const rest = keys.filter(k => !ordered.includes(k));
|
|
701
|
+
this.rangeOrder = [...ordered, ...rest];
|
|
702
|
+
}
|
|
703
|
+
if (!this.customRanges['Custom Range']) {
|
|
704
|
+
this.customRanges['Custom Range'] = { start: new Date(), end: new Date() };
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
labelToJsWeekday(label) {
|
|
709
|
+
const key = label.replace(/\./g, '').trim().toLowerCase();
|
|
710
|
+
const map = {
|
|
711
|
+
sun: 0, sunday: 0, su: 0,
|
|
712
|
+
mon: 1, monday: 1, mo: 1,
|
|
713
|
+
tue: 2, tues: 2, tuesday: 2, tu: 2,
|
|
714
|
+
wed: 3, wednesday: 3, we: 3,
|
|
715
|
+
thu: 4, thur: 4, thurs: 4, thursday: 4, th: 4,
|
|
716
|
+
fri: 5, friday: 5, fr: 5,
|
|
717
|
+
sat: 6, saturday: 6, sa: 6,
|
|
718
|
+
};
|
|
719
|
+
return map[key] ?? 1;
|
|
720
|
+
}
|
|
721
|
+
getWeekStartDayIndex() {
|
|
722
|
+
return this.labelToJsWeekday(this.resolvedWeekDayLabels[0] ?? 'Mon');
|
|
723
|
+
}
|
|
576
724
|
// --- ControlValueAccessor implementation ---
|
|
577
725
|
writeValue(value) {
|
|
578
726
|
this.selectedValue = value ?? null;
|
|
@@ -608,6 +756,29 @@ class BkCustomCalendar {
|
|
|
608
756
|
markAsTouched() {
|
|
609
757
|
this.onTouched();
|
|
610
758
|
}
|
|
759
|
+
/** Clears embedded time picker ngModels, spinner state, raw minute typing, and forces dropdowns closed. */
|
|
760
|
+
resetEmbeddedTimePickerUiState() {
|
|
761
|
+
this.singleTimeModel = null;
|
|
762
|
+
this.startTimeModel = null;
|
|
763
|
+
this.endTimeModel = null;
|
|
764
|
+
this.selectedHour = 1;
|
|
765
|
+
this.selectedMinute = 0;
|
|
766
|
+
this.selectedSecond = 0;
|
|
767
|
+
this.selectedAMPM = 'AM';
|
|
768
|
+
this.startHour = 1;
|
|
769
|
+
this.startMinute = 0;
|
|
770
|
+
this.startSecond = 0;
|
|
771
|
+
this.startAMPM = 'AM';
|
|
772
|
+
this.endHour = 2;
|
|
773
|
+
this.endMinute = 0;
|
|
774
|
+
this.endSecond = 0;
|
|
775
|
+
this.endAMPM = 'AM';
|
|
776
|
+
this.minuteInputValues = {};
|
|
777
|
+
this.openTimePickerId = null;
|
|
778
|
+
for (const id of ['single-time', 'dual-start', 'dual-end']) {
|
|
779
|
+
this.closePickerCounter[id] = (this.closePickerCounter[id] || 0) + 1;
|
|
780
|
+
}
|
|
781
|
+
}
|
|
611
782
|
/** Apply CalendarSelection to internal state (startDate, endDate, startTime, endTime, selectedDates, calendar view). */
|
|
612
783
|
applyValueToState(value) {
|
|
613
784
|
if (!value) {
|
|
@@ -616,9 +787,8 @@ class BkCustomCalendar {
|
|
|
616
787
|
this.startTime = null;
|
|
617
788
|
this.endTime = null;
|
|
618
789
|
this.selectedDates = [];
|
|
619
|
-
this.
|
|
620
|
-
this.
|
|
621
|
-
this.endTimeModel = null;
|
|
790
|
+
this.activeRange = null;
|
|
791
|
+
this.resetEmbeddedTimePickerUiState();
|
|
622
792
|
this.month = this.today.getMonth();
|
|
623
793
|
this.year = this.today.getFullYear();
|
|
624
794
|
this.generateCalendar();
|
|
@@ -695,8 +865,13 @@ class BkCustomCalendar {
|
|
|
695
865
|
this.selectedAMPM = this.startAMPM;
|
|
696
866
|
}
|
|
697
867
|
else if (this.startDate) {
|
|
868
|
+
// Date-only committed value: keep startTime null; sync spinners for UX only (not emitted until user sets time).
|
|
698
869
|
this.initializeTimeFromDate(this.startDate, true);
|
|
699
|
-
|
|
870
|
+
if (!this.dualCalendar) {
|
|
871
|
+
this.selectedHour = this.startHour;
|
|
872
|
+
this.selectedMinute = this.startMinute;
|
|
873
|
+
this.selectedAMPM = this.startAMPM;
|
|
874
|
+
}
|
|
700
875
|
}
|
|
701
876
|
if (this.endTime) {
|
|
702
877
|
const endParsed = this.parsePickerTimeString(this.endTime);
|
|
@@ -714,7 +889,6 @@ class BkCustomCalendar {
|
|
|
714
889
|
}
|
|
715
890
|
else if (this.endDate) {
|
|
716
891
|
this.initializeTimeFromDate(this.endDate, false);
|
|
717
|
-
this.endTime = this.formatTimeToAmPm(this.endHour, this.endMinute, this.endAMPM);
|
|
718
892
|
}
|
|
719
893
|
if (this.startDate && this.endDate) {
|
|
720
894
|
this.checkAndSetActiveRange();
|
|
@@ -746,33 +920,26 @@ class BkCustomCalendar {
|
|
|
746
920
|
onWindowEvents() {
|
|
747
921
|
if (this.show && this.appendToBody) {
|
|
748
922
|
this.close();
|
|
923
|
+
return;
|
|
924
|
+
}
|
|
925
|
+
if (this.show && !this.inline && !this.appendToBody) {
|
|
926
|
+
setTimeout(() => this.refreshPopupPlacement(), 0);
|
|
749
927
|
}
|
|
750
928
|
}
|
|
751
929
|
ngOnInit() {
|
|
752
|
-
|
|
753
|
-
this.initializeDefaultRanges();
|
|
754
|
-
}
|
|
755
|
-
else {
|
|
756
|
-
// If customRanges is provided via @Input, set the order based on the keys
|
|
757
|
-
// Maintain the desired order if keys match, otherwise use provided order
|
|
758
|
-
const desiredOrder = ['Today', 'Yesterday', 'Last 7 Days', 'Last 30 Days', 'This Month', 'Last Month', 'Custom Range'];
|
|
759
|
-
const providedKeys = Object.keys(this.customRanges);
|
|
760
|
-
// Check if Custom Range exists, if not add it
|
|
761
|
-
if (!this.customRanges['Custom Range']) {
|
|
762
|
-
this.customRanges['Custom Range'] = { start: new Date(), end: new Date() };
|
|
763
|
-
}
|
|
764
|
-
// Build order: first add desired order items that exist, then add any remaining
|
|
765
|
-
this.rangeOrder = desiredOrder.filter(key => providedKeys.includes(key) || key === 'Custom Range');
|
|
766
|
-
const remaining = providedKeys.filter(key => !this.rangeOrder.includes(key));
|
|
767
|
-
this.rangeOrder = [...this.rangeOrder, ...remaining];
|
|
768
|
-
}
|
|
930
|
+
this.resolveCustomRangesFromInputsOrService();
|
|
769
931
|
if (this.dualCalendar)
|
|
770
932
|
this.initializeDual();
|
|
771
933
|
else
|
|
772
934
|
this.generateCalendar();
|
|
773
|
-
// Initialize
|
|
935
|
+
// Initialize spinner state from existing dates (does not set startTime/endTime — those stay null until user picks time).
|
|
774
936
|
if (this.startDate) {
|
|
775
937
|
this.initializeTimeFromDate(this.startDate, true);
|
|
938
|
+
if (!this.dualCalendar) {
|
|
939
|
+
this.selectedHour = this.startHour;
|
|
940
|
+
this.selectedMinute = this.startMinute;
|
|
941
|
+
this.selectedAMPM = this.startAMPM;
|
|
942
|
+
}
|
|
776
943
|
}
|
|
777
944
|
if (this.endDate) {
|
|
778
945
|
this.initializeTimeFromDate(this.endDate, false);
|
|
@@ -784,6 +951,7 @@ class BkCustomCalendar {
|
|
|
784
951
|
// If inline mode, always show calendar
|
|
785
952
|
if (this.inline) {
|
|
786
953
|
this.show = true;
|
|
954
|
+
setTimeout(() => this.initKeyboardFocus(), 0);
|
|
787
955
|
}
|
|
788
956
|
// Register this calendar instance with the manager service
|
|
789
957
|
this.closeFn = () => {
|
|
@@ -803,6 +971,20 @@ class BkCustomCalendar {
|
|
|
803
971
|
if (changes['selectedValue']) {
|
|
804
972
|
this.applyValueToState(this.selectedValue ?? null);
|
|
805
973
|
}
|
|
974
|
+
if (changes['customRanges'] || changes['rangeOrder']) {
|
|
975
|
+
this.resolveCustomRangesFromInputsOrService();
|
|
976
|
+
}
|
|
977
|
+
if (changes['weekDayLabels'] && !changes['weekDayLabels'].firstChange) {
|
|
978
|
+
this.regenerateCalendarsForWeekStart();
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
regenerateCalendarsForWeekStart() {
|
|
982
|
+
if (this.dualCalendar) {
|
|
983
|
+
this.generateDualCalendars();
|
|
984
|
+
}
|
|
985
|
+
else {
|
|
986
|
+
this.generateCalendar();
|
|
987
|
+
}
|
|
806
988
|
}
|
|
807
989
|
ngOnDestroy() {
|
|
808
990
|
// Unregister this calendar instance
|
|
@@ -842,20 +1024,6 @@ class BkCustomCalendar {
|
|
|
842
1024
|
// If no match found, it's a custom range
|
|
843
1025
|
this.activeRange = 'Custom Range';
|
|
844
1026
|
}
|
|
845
|
-
initializeDefaultRanges() {
|
|
846
|
-
const today = new Date();
|
|
847
|
-
this.customRanges = {
|
|
848
|
-
'Today': { start: new Date(today.getFullYear(), today.getMonth(), today.getDate()), end: new Date(today.getFullYear(), today.getMonth(), today.getDate()) },
|
|
849
|
-
'Yesterday': { start: this.addDays(today, -1), end: this.addDays(today, -1) },
|
|
850
|
-
'Last 7 Days': { start: this.addDays(today, -6), end: today },
|
|
851
|
-
'Last 30 Days': { start: this.addDays(today, -29), end: today },
|
|
852
|
-
'This Month': { start: new Date(today.getFullYear(), today.getMonth(), 1), end: today },
|
|
853
|
-
'Last Month': { start: new Date(today.getFullYear(), today.getMonth() - 1, 1), end: new Date(today.getFullYear(), today.getMonth(), 0) },
|
|
854
|
-
'Custom Range': { start: new Date(), end: new Date() }, // Placeholder, won't be used for selection
|
|
855
|
-
};
|
|
856
|
-
// Set the order of ranges
|
|
857
|
-
this.rangeOrder = ['Today', 'Yesterday', 'Last 7 Days', 'Last 30 Days', 'This Month', 'Last Month', 'Custom Range'];
|
|
858
|
-
}
|
|
859
1027
|
initializeTimeFromDate(date, isStart) {
|
|
860
1028
|
// Always use 12-hour format
|
|
861
1029
|
const hours24 = date.getHours();
|
|
@@ -896,18 +1064,25 @@ class BkCustomCalendar {
|
|
|
896
1064
|
const wasOpen = this.show;
|
|
897
1065
|
this.show = !this.show;
|
|
898
1066
|
if (this.show) {
|
|
899
|
-
if (this.appendToBody && this.inputWrapper?.nativeElement) {
|
|
900
|
-
this.updatePosition();
|
|
901
|
-
}
|
|
902
1067
|
// If opening, close all other calendars first
|
|
903
1068
|
if (!wasOpen && this.closeFn) {
|
|
904
1069
|
this.calendarManager.closeAllExcept(this.closeFn);
|
|
905
1070
|
}
|
|
906
1071
|
this.disableHighlight = false;
|
|
1072
|
+
setTimeout(() => {
|
|
1073
|
+
this.initKeyboardFocus();
|
|
1074
|
+
this.calendarPopupRef?.nativeElement?.focus({ preventScroll: true });
|
|
1075
|
+
if (this.appendToBody && this.inputWrapper?.nativeElement) {
|
|
1076
|
+
this.updatePosition();
|
|
1077
|
+
}
|
|
1078
|
+
else if (!this.inline) {
|
|
1079
|
+
this.refreshPopupPlacement();
|
|
1080
|
+
}
|
|
1081
|
+
}, 0);
|
|
907
1082
|
this.opened.emit();
|
|
908
1083
|
}
|
|
909
1084
|
else {
|
|
910
|
-
this.
|
|
1085
|
+
this.finishPopupDismissal();
|
|
911
1086
|
}
|
|
912
1087
|
}
|
|
913
1088
|
/** Update popup position when appendToBody is true (fixed positioning relative to viewport). */
|
|
@@ -915,27 +1090,224 @@ class BkCustomCalendar {
|
|
|
915
1090
|
if (!this.inputWrapper?.nativeElement)
|
|
916
1091
|
return;
|
|
917
1092
|
const rect = this.inputWrapper.nativeElement.getBoundingClientRect();
|
|
918
|
-
|
|
1093
|
+
const popupH = this.calendarPopupRef?.nativeElement?.offsetHeight ?? 360;
|
|
1094
|
+
const placeAbove = this.computePlacementAbove(rect, popupH);
|
|
1095
|
+
this.popupPlacementAbove = placeAbove;
|
|
1096
|
+
const gap = 4;
|
|
1097
|
+
if (placeAbove) {
|
|
919
1098
|
this.dropdownStyle = {
|
|
920
|
-
bottom: `${window.innerHeight - rect.top +
|
|
921
|
-
left: `${rect.left}px
|
|
1099
|
+
bottom: `${window.innerHeight - rect.top + gap}px`,
|
|
1100
|
+
left: `${rect.left}px`,
|
|
922
1101
|
};
|
|
923
1102
|
}
|
|
924
1103
|
else {
|
|
925
1104
|
this.dropdownStyle = {
|
|
926
|
-
top: `${rect.bottom +
|
|
927
|
-
left: `${rect.left}px
|
|
1105
|
+
top: `${rect.bottom + gap}px`,
|
|
1106
|
+
left: `${rect.left}px`,
|
|
928
1107
|
};
|
|
929
1108
|
}
|
|
930
1109
|
}
|
|
1110
|
+
/** Non–append-to-body: set `popupPlacementAbove` for CSS `drop-up` with viewport flip. */
|
|
1111
|
+
refreshPopupPlacement() {
|
|
1112
|
+
if (!this.inputWrapper?.nativeElement)
|
|
1113
|
+
return;
|
|
1114
|
+
const rect = this.inputWrapper.nativeElement.getBoundingClientRect();
|
|
1115
|
+
const popupH = this.calendarPopupRef?.nativeElement?.offsetHeight ?? 360;
|
|
1116
|
+
this.popupPlacementAbove = this.computePlacementAbove(rect, popupH);
|
|
1117
|
+
}
|
|
1118
|
+
computePlacementAbove(rect, popupHeight) {
|
|
1119
|
+
const gap = 12;
|
|
1120
|
+
const spaceBelow = window.innerHeight - rect.bottom - gap;
|
|
1121
|
+
const spaceAbove = rect.top - gap;
|
|
1122
|
+
const preferAbove = this.preferPopupAbove();
|
|
1123
|
+
if (preferAbove) {
|
|
1124
|
+
return spaceAbove >= popupHeight || spaceAbove >= spaceBelow;
|
|
1125
|
+
}
|
|
1126
|
+
if (spaceBelow >= popupHeight || spaceBelow >= spaceAbove)
|
|
1127
|
+
return false;
|
|
1128
|
+
return true;
|
|
1129
|
+
}
|
|
1130
|
+
/** Normalize to local midnight and clamp to min/max selectable day. */
|
|
1131
|
+
clampCalendarDayToSelectableRange(d) {
|
|
1132
|
+
let x = new Date(d.getFullYear(), d.getMonth(), d.getDate());
|
|
1133
|
+
if (this.minDate) {
|
|
1134
|
+
const min = new Date(this.minDate.getFullYear(), this.minDate.getMonth(), this.minDate.getDate());
|
|
1135
|
+
if (x < min)
|
|
1136
|
+
x = new Date(min.getFullYear(), min.getMonth(), min.getDate());
|
|
1137
|
+
}
|
|
1138
|
+
if (this.maxDate) {
|
|
1139
|
+
const max = new Date(this.maxDate.getFullYear(), this.maxDate.getMonth(), this.maxDate.getDate());
|
|
1140
|
+
if (x > max)
|
|
1141
|
+
x = new Date(max.getFullYear(), max.getMonth(), max.getDate());
|
|
1142
|
+
}
|
|
1143
|
+
return x;
|
|
1144
|
+
}
|
|
1145
|
+
initKeyboardFocus() {
|
|
1146
|
+
if (!this.inline && !this.show)
|
|
1147
|
+
return;
|
|
1148
|
+
const base = this.startDate ??
|
|
1149
|
+
this.endDate ??
|
|
1150
|
+
new Date(this.today.getFullYear(), this.today.getMonth(), this.today.getDate());
|
|
1151
|
+
const d = this.clampCalendarDayToSelectableRange(new Date(base.getFullYear(), base.getMonth(), base.getDate()));
|
|
1152
|
+
this.keyboardFocusDate = d;
|
|
1153
|
+
this.ensureKeyboardFocusVisible();
|
|
1154
|
+
}
|
|
1155
|
+
/**
|
|
1156
|
+
* After clearing values, drop stale keyboard highlight (was last start/end) and reset the
|
|
1157
|
+
* visible month(s) to today (clamped). Move DOM focus to the popup when open, else the input.
|
|
1158
|
+
*/
|
|
1159
|
+
resetCalendarFocusAfterClear() {
|
|
1160
|
+
const todayLocal = new Date(this.today.getFullYear(), this.today.getMonth(), this.today.getDate());
|
|
1161
|
+
this.keyboardFocusDate = this.clampCalendarDayToSelectableRange(todayLocal);
|
|
1162
|
+
if (this.dualCalendar) {
|
|
1163
|
+
this.leftMonth = this.keyboardFocusDate.getMonth();
|
|
1164
|
+
this.leftYear = this.keyboardFocusDate.getFullYear();
|
|
1165
|
+
this.rightMonth = this.leftMonth + 1;
|
|
1166
|
+
this.rightYear = this.leftYear;
|
|
1167
|
+
if (this.rightMonth > 11) {
|
|
1168
|
+
this.rightMonth = 0;
|
|
1169
|
+
this.rightYear++;
|
|
1170
|
+
}
|
|
1171
|
+
this.generateDualCalendars();
|
|
1172
|
+
}
|
|
1173
|
+
else {
|
|
1174
|
+
this.month = this.keyboardFocusDate.getMonth();
|
|
1175
|
+
this.year = this.keyboardFocusDate.getFullYear();
|
|
1176
|
+
this.generateCalendar();
|
|
1177
|
+
}
|
|
1178
|
+
this.scheduleDomFocusAfterClear();
|
|
1179
|
+
}
|
|
1180
|
+
scheduleDomFocusAfterClear() {
|
|
1181
|
+
setTimeout(() => {
|
|
1182
|
+
if (this.show || this.inline) {
|
|
1183
|
+
this.calendarPopupRef?.nativeElement?.focus({ preventScroll: true });
|
|
1184
|
+
return;
|
|
1185
|
+
}
|
|
1186
|
+
const inputEl = this.inputWrapper?.nativeElement?.querySelector('.calendar-input');
|
|
1187
|
+
inputEl?.focus({ preventScroll: true });
|
|
1188
|
+
}, 0);
|
|
1189
|
+
}
|
|
1190
|
+
ensureKeyboardFocusVisible() {
|
|
1191
|
+
if (!this.keyboardFocusDate)
|
|
1192
|
+
return;
|
|
1193
|
+
const fd = this.keyboardFocusDate;
|
|
1194
|
+
if (!this.dualCalendar) {
|
|
1195
|
+
if (fd.getMonth() !== this.month || fd.getFullYear() !== this.year) {
|
|
1196
|
+
this.month = fd.getMonth();
|
|
1197
|
+
this.year = fd.getFullYear();
|
|
1198
|
+
this.generateCalendar();
|
|
1199
|
+
}
|
|
1200
|
+
return;
|
|
1201
|
+
}
|
|
1202
|
+
const fm = fd.getMonth();
|
|
1203
|
+
const fy = fd.getFullYear();
|
|
1204
|
+
const inLeft = fm === this.leftMonth && fy === this.leftYear;
|
|
1205
|
+
const inRight = fm === this.rightMonth && fy === this.rightYear;
|
|
1206
|
+
if (inLeft || inRight)
|
|
1207
|
+
return;
|
|
1208
|
+
this.leftMonth = fm;
|
|
1209
|
+
this.leftYear = fy;
|
|
1210
|
+
this.rightMonth = fm + 1;
|
|
1211
|
+
this.rightYear = fy;
|
|
1212
|
+
if (this.rightMonth > 11) {
|
|
1213
|
+
this.rightMonth = 0;
|
|
1214
|
+
this.rightYear++;
|
|
1215
|
+
}
|
|
1216
|
+
this.generateDualCalendars();
|
|
1217
|
+
}
|
|
1218
|
+
moveKeyboardFocus(deltaDays) {
|
|
1219
|
+
if (!this.keyboardFocusDate)
|
|
1220
|
+
this.initKeyboardFocus();
|
|
1221
|
+
if (!this.keyboardFocusDate)
|
|
1222
|
+
return;
|
|
1223
|
+
let next = this.addDays(this.keyboardFocusDate, deltaDays);
|
|
1224
|
+
if (this.minDate) {
|
|
1225
|
+
const min = new Date(this.minDate.getFullYear(), this.minDate.getMonth(), this.minDate.getDate());
|
|
1226
|
+
if (next < min)
|
|
1227
|
+
next = min;
|
|
1228
|
+
}
|
|
1229
|
+
if (this.maxDate) {
|
|
1230
|
+
const max = new Date(this.maxDate.getFullYear(), this.maxDate.getMonth(), this.maxDate.getDate());
|
|
1231
|
+
if (next > max)
|
|
1232
|
+
next = max;
|
|
1233
|
+
}
|
|
1234
|
+
this.keyboardFocusDate = new Date(next.getFullYear(), next.getMonth(), next.getDate());
|
|
1235
|
+
this.ensureKeyboardFocusVisible();
|
|
1236
|
+
}
|
|
1237
|
+
/**
|
|
1238
|
+
* When focus is inside a real control (button, link, field), do not intercept keys here.
|
|
1239
|
+
* Otherwise this handler's preventDefault (Enter/Space) blocks native button activation and
|
|
1240
|
+
* bubbled Enter still runs applyKeyboardSelection — breaking keyboard parity with click.
|
|
1241
|
+
*/
|
|
1242
|
+
isKeyboardEventFromInteractiveDescendant(event) {
|
|
1243
|
+
const t = event.target;
|
|
1244
|
+
if (!(t instanceof Element))
|
|
1245
|
+
return false;
|
|
1246
|
+
return !!t.closest('button, a[href], input, select, textarea, [contenteditable="true"], bk-time-picker');
|
|
1247
|
+
}
|
|
1248
|
+
onCalendarPopupKeydown(event) {
|
|
1249
|
+
if (this.disabled)
|
|
1250
|
+
return;
|
|
1251
|
+
if (event.key === 'Tab')
|
|
1252
|
+
return;
|
|
1253
|
+
if (this.isKeyboardEventFromInteractiveDescendant(event)) {
|
|
1254
|
+
return;
|
|
1255
|
+
}
|
|
1256
|
+
const k = event.key;
|
|
1257
|
+
if (k === 'ArrowLeft' || k === 'ArrowRight' || k === 'ArrowUp' || k === 'ArrowDown' || k === 'Enter' || k === ' ') {
|
|
1258
|
+
event.preventDefault();
|
|
1259
|
+
}
|
|
1260
|
+
if (k === 'ArrowLeft')
|
|
1261
|
+
this.moveKeyboardFocus(-1);
|
|
1262
|
+
else if (k === 'ArrowRight')
|
|
1263
|
+
this.moveKeyboardFocus(1);
|
|
1264
|
+
else if (k === 'ArrowUp')
|
|
1265
|
+
this.moveKeyboardFocus(-7);
|
|
1266
|
+
else if (k === 'ArrowDown')
|
|
1267
|
+
this.moveKeyboardFocus(7);
|
|
1268
|
+
else if (k === 'Enter' || k === ' ')
|
|
1269
|
+
this.applyKeyboardSelection();
|
|
1270
|
+
}
|
|
1271
|
+
applyKeyboardSelection() {
|
|
1272
|
+
if (!this.keyboardFocusDate)
|
|
1273
|
+
return;
|
|
1274
|
+
const day = this.keyboardFocusDate.getDate();
|
|
1275
|
+
if (this.dualCalendar) {
|
|
1276
|
+
const fr = this.keyboardFocusDate.getMonth() === this.rightMonth && this.keyboardFocusDate.getFullYear() === this.rightYear;
|
|
1277
|
+
const fl = this.keyboardFocusDate.getMonth() === this.leftMonth && this.keyboardFocusDate.getFullYear() === this.leftYear;
|
|
1278
|
+
if (fr)
|
|
1279
|
+
this.selectDate(day, true);
|
|
1280
|
+
else if (fl)
|
|
1281
|
+
this.selectDate(day, false);
|
|
1282
|
+
else {
|
|
1283
|
+
this.ensureKeyboardFocusVisible();
|
|
1284
|
+
const fr2 = this.keyboardFocusDate.getMonth() === this.rightMonth && this.keyboardFocusDate.getFullYear() === this.rightYear;
|
|
1285
|
+
this.selectDate(day, fr2);
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
else {
|
|
1289
|
+
this.selectDate(day, false);
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
isKeyboardFocusedCell(year, month, day) {
|
|
1293
|
+
if (!this.keyboardFocusDate || !day)
|
|
1294
|
+
return false;
|
|
1295
|
+
return (this.keyboardFocusDate.getFullYear() === year &&
|
|
1296
|
+
this.keyboardFocusDate.getMonth() === month &&
|
|
1297
|
+
this.keyboardFocusDate.getDate() === day);
|
|
1298
|
+
}
|
|
1299
|
+
onRangeButtonKeydown(event, rangeKey) {
|
|
1300
|
+
if (event.key === ' ' || event.key === 'Enter') {
|
|
1301
|
+
event.preventDefault();
|
|
1302
|
+
event.stopPropagation();
|
|
1303
|
+
this.chooseRange(rangeKey);
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
931
1306
|
close() {
|
|
932
|
-
// Don't close if inline mode is enabled
|
|
933
1307
|
if (this.inline) {
|
|
934
1308
|
return;
|
|
935
1309
|
}
|
|
936
|
-
this.
|
|
937
|
-
this.onTouched();
|
|
938
|
-
this.closed.emit();
|
|
1310
|
+
this.finishPopupDismissal();
|
|
939
1311
|
}
|
|
940
1312
|
onDateHover(day, fromRight = false) {
|
|
941
1313
|
if (!day || this.singleDatePicker || this.multiDateSelection) {
|
|
@@ -978,6 +1350,7 @@ class BkCustomCalendar {
|
|
|
978
1350
|
return;
|
|
979
1351
|
if (this.maxDate && selected > this.maxDate)
|
|
980
1352
|
return;
|
|
1353
|
+
this.keyboardFocusDate = new Date(selected.getFullYear(), selected.getMonth(), selected.getDate());
|
|
981
1354
|
// Multi-date selection mode
|
|
982
1355
|
if (this.multiDateSelection) {
|
|
983
1356
|
this.handleMultiDateSelection(selected);
|
|
@@ -1020,8 +1393,7 @@ class BkCustomCalendar {
|
|
|
1020
1393
|
this.close();
|
|
1021
1394
|
}
|
|
1022
1395
|
else {
|
|
1023
|
-
|
|
1024
|
-
this.emitSelection();
|
|
1396
|
+
this.emitSelectionUnlessSingleDateDeferred();
|
|
1025
1397
|
}
|
|
1026
1398
|
return;
|
|
1027
1399
|
}
|
|
@@ -1154,25 +1526,25 @@ class BkCustomCalendar {
|
|
|
1154
1526
|
apply() {
|
|
1155
1527
|
if (this.disabled)
|
|
1156
1528
|
return;
|
|
1529
|
+
if (this.isDualRangeApplyBlocked)
|
|
1530
|
+
return;
|
|
1157
1531
|
// Format minute inputs to 2 digits before applying
|
|
1158
1532
|
this.formatAllMinuteInputs();
|
|
1159
|
-
// Apply time
|
|
1533
|
+
// Apply time only when the user has an explicit time string (avoids inventing "12:00 AM" from picker defaults).
|
|
1160
1534
|
if (this.enableTimepicker) {
|
|
1161
1535
|
if (this.dualCalendar) {
|
|
1162
|
-
|
|
1163
|
-
if (this.startDate) {
|
|
1536
|
+
if (this.startDate && this.startTime != null) {
|
|
1164
1537
|
this.applyTimeToDate(this.startDate, true);
|
|
1165
1538
|
}
|
|
1166
|
-
if (this.endDate) {
|
|
1539
|
+
if (this.endDate && this.endTime != null) {
|
|
1167
1540
|
this.applyTimeToDate(this.endDate, false);
|
|
1168
1541
|
}
|
|
1169
1542
|
}
|
|
1170
1543
|
else {
|
|
1171
|
-
|
|
1172
|
-
if (this.startDate) {
|
|
1544
|
+
if (this.startDate && this.startTime != null) {
|
|
1173
1545
|
this.applyTimeToDate(this.startDate, true);
|
|
1174
1546
|
}
|
|
1175
|
-
if (this.endDate && !this.singleDatePicker) {
|
|
1547
|
+
if (this.endDate && !this.singleDatePicker && this.startTime != null) {
|
|
1176
1548
|
this.applyTimeToDate(this.endDate, true);
|
|
1177
1549
|
}
|
|
1178
1550
|
}
|
|
@@ -1187,9 +1559,14 @@ class BkCustomCalendar {
|
|
|
1187
1559
|
cancel() {
|
|
1188
1560
|
if (this.disabled)
|
|
1189
1561
|
return;
|
|
1562
|
+
if (this.shouldDeferSingleDateCommit()) {
|
|
1563
|
+
this.finishPopupDismissal();
|
|
1564
|
+
return;
|
|
1565
|
+
}
|
|
1190
1566
|
this.startDate = null;
|
|
1191
1567
|
this.endDate = null;
|
|
1192
1568
|
this.selectedDates = [];
|
|
1569
|
+
this.resetCalendarFocusAfterClear();
|
|
1193
1570
|
this.close();
|
|
1194
1571
|
}
|
|
1195
1572
|
clear() {
|
|
@@ -1199,40 +1576,19 @@ class BkCustomCalendar {
|
|
|
1199
1576
|
this.endDate = null;
|
|
1200
1577
|
this.startTime = null;
|
|
1201
1578
|
this.endTime = null;
|
|
1202
|
-
// Time picker for single calendar (12-hour format: 1-12)
|
|
1203
|
-
this.selectedHour = 1;
|
|
1204
|
-
this.selectedMinute = 0;
|
|
1205
|
-
this.selectedSecond = 0;
|
|
1206
|
-
this.selectedAMPM = 'AM';
|
|
1207
|
-
// NEW: Separate time pickers for dual calendar (12-hour format: 1-12)
|
|
1208
|
-
this.startHour = 1;
|
|
1209
|
-
this.startMinute = 0;
|
|
1210
|
-
this.startSecond = 0;
|
|
1211
|
-
this.startAMPM = 'AM';
|
|
1212
|
-
this.endHour = 2;
|
|
1213
|
-
this.endMinute = 0;
|
|
1214
|
-
this.endSecond = 0;
|
|
1215
|
-
this.endAMPM = 'AM';
|
|
1216
1579
|
this.selectedDates = [];
|
|
1217
|
-
this.activeRange = null;
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
this.rightMonth = this.leftMonth + 1;
|
|
1221
|
-
this.rightYear = this.leftYear;
|
|
1222
|
-
if (this.rightMonth > 11) {
|
|
1223
|
-
this.rightMonth = 0;
|
|
1224
|
-
this.rightYear++;
|
|
1225
|
-
}
|
|
1226
|
-
this.generateDualCalendars();
|
|
1227
|
-
}
|
|
1580
|
+
this.activeRange = null;
|
|
1581
|
+
this.resetEmbeddedTimePickerUiState();
|
|
1582
|
+
this.resetCalendarFocusAfterClear();
|
|
1228
1583
|
this.emitSelection();
|
|
1229
1584
|
}
|
|
1230
1585
|
chooseRange(key) {
|
|
1231
1586
|
if (this.disabled || !this.customRanges)
|
|
1232
1587
|
return;
|
|
1233
|
-
|
|
1234
|
-
|
|
1588
|
+
if (key === 'Custom Range') {
|
|
1589
|
+
this.activeRange = 'Custom Range';
|
|
1235
1590
|
return;
|
|
1591
|
+
}
|
|
1236
1592
|
const r = this.customRanges[key];
|
|
1237
1593
|
if (!r)
|
|
1238
1594
|
return;
|
|
@@ -1296,8 +1652,19 @@ class BkCustomCalendar {
|
|
|
1296
1652
|
}
|
|
1297
1653
|
this.generateCalendar();
|
|
1298
1654
|
}
|
|
1299
|
-
this.
|
|
1300
|
-
|
|
1655
|
+
if (this.endDate) {
|
|
1656
|
+
this.keyboardFocusDate = new Date(this.endDate.getFullYear(), this.endDate.getMonth(), this.endDate.getDate());
|
|
1657
|
+
}
|
|
1658
|
+
else if (this.startDate) {
|
|
1659
|
+
this.keyboardFocusDate = new Date(this.startDate.getFullYear(), this.startDate.getMonth(), this.startDate.getDate());
|
|
1660
|
+
}
|
|
1661
|
+
this.emitSelectionUnlessSingleDateDeferred();
|
|
1662
|
+
if (this.shouldDeferSingleDateCommit()) {
|
|
1663
|
+
if (this.autoApply) {
|
|
1664
|
+
this.apply();
|
|
1665
|
+
}
|
|
1666
|
+
}
|
|
1667
|
+
else if (this.autoApply || this.closeOnAutoApply) {
|
|
1301
1668
|
this.close();
|
|
1302
1669
|
}
|
|
1303
1670
|
}
|
|
@@ -1425,14 +1792,14 @@ class BkCustomCalendar {
|
|
|
1425
1792
|
this.rightCalendar = this.buildCalendar(this.rightYear, this.rightMonth);
|
|
1426
1793
|
}
|
|
1427
1794
|
buildCalendar(year, month) {
|
|
1428
|
-
const
|
|
1795
|
+
const weekStart = this.getWeekStartDayIndex();
|
|
1796
|
+
const firstDayJs = new Date(year, month, 1).getDay();
|
|
1797
|
+
const offset = (firstDayJs - weekStart + 7) % 7;
|
|
1429
1798
|
const daysInMonth = new Date(year, month + 1, 0).getDate();
|
|
1430
1799
|
const prevMonthDays = new Date(year, month, 0).getDate();
|
|
1431
1800
|
const grid = [];
|
|
1432
1801
|
let row = [];
|
|
1433
|
-
|
|
1434
|
-
const adjustedFirstDay = firstDay === 0 ? 6 : firstDay - 1; // Make Monday = 0
|
|
1435
|
-
for (let i = adjustedFirstDay - 1; i >= 0; i--) {
|
|
1802
|
+
for (let i = offset - 1; i >= 0; i--) {
|
|
1436
1803
|
row.push({ day: prevMonthDays - i, currentMonth: false });
|
|
1437
1804
|
}
|
|
1438
1805
|
for (let d = 1; d <= daysInMonth; d++) {
|
|
@@ -1661,7 +2028,7 @@ class BkCustomCalendar {
|
|
|
1661
2028
|
if (this.startDate) {
|
|
1662
2029
|
this.startDate.setHours(0, 0, this.selectedSecond);
|
|
1663
2030
|
}
|
|
1664
|
-
this.
|
|
2031
|
+
this.emitSelectionUnlessSingleDateDeferred();
|
|
1665
2032
|
return;
|
|
1666
2033
|
}
|
|
1667
2034
|
const { hour12, minute, ampm } = this.parsePickerTimeString(time);
|
|
@@ -1678,7 +2045,7 @@ class BkCustomCalendar {
|
|
|
1678
2045
|
h24 = 0;
|
|
1679
2046
|
this.startDate.setHours(h24, minute, this.selectedSecond);
|
|
1680
2047
|
}
|
|
1681
|
-
this.
|
|
2048
|
+
this.emitSelectionUnlessSingleDateDeferred();
|
|
1682
2049
|
}
|
|
1683
2050
|
// NEW: Handle BkTimePicker change for dual calendar
|
|
1684
2051
|
onDualTimePickerChange(time, isStart = true) {
|
|
@@ -1759,7 +2126,7 @@ class BkCustomCalendar {
|
|
|
1759
2126
|
this.selectedMinute = m;
|
|
1760
2127
|
if (this.startDate) {
|
|
1761
2128
|
this.startDate.setHours(h, m, this.selectedSecond);
|
|
1762
|
-
this.
|
|
2129
|
+
this.emitSelectionUnlessSingleDateDeferred();
|
|
1763
2130
|
}
|
|
1764
2131
|
}
|
|
1765
2132
|
// Custom time picker controls
|
|
@@ -1920,7 +2287,7 @@ class BkCustomCalendar {
|
|
|
1920
2287
|
if (this.selectedAMPM === 'AM' && h === 12)
|
|
1921
2288
|
h = 0;
|
|
1922
2289
|
this.startDate.setHours(h, this.selectedMinute, this.selectedSecond);
|
|
1923
|
-
this.
|
|
2290
|
+
this.emitSelectionUnlessSingleDateDeferred();
|
|
1924
2291
|
}
|
|
1925
2292
|
}
|
|
1926
2293
|
decrementSingleHour() {
|
|
@@ -1936,7 +2303,7 @@ class BkCustomCalendar {
|
|
|
1936
2303
|
if (this.selectedAMPM === 'AM' && h === 12)
|
|
1937
2304
|
h = 0;
|
|
1938
2305
|
this.startDate.setHours(h, this.selectedMinute, this.selectedSecond);
|
|
1939
|
-
this.
|
|
2306
|
+
this.emitSelectionUnlessSingleDateDeferred();
|
|
1940
2307
|
}
|
|
1941
2308
|
}
|
|
1942
2309
|
incrementSingleMinute() {
|
|
@@ -1948,7 +2315,7 @@ class BkCustomCalendar {
|
|
|
1948
2315
|
if (this.selectedAMPM === 'AM' && h === 12)
|
|
1949
2316
|
h = 0;
|
|
1950
2317
|
this.startDate.setHours(h, this.selectedMinute, this.selectedSecond);
|
|
1951
|
-
this.
|
|
2318
|
+
this.emitSelectionUnlessSingleDateDeferred();
|
|
1952
2319
|
}
|
|
1953
2320
|
}
|
|
1954
2321
|
decrementSingleMinute() {
|
|
@@ -1960,7 +2327,7 @@ class BkCustomCalendar {
|
|
|
1960
2327
|
if (this.selectedAMPM === 'AM' && h === 12)
|
|
1961
2328
|
h = 0;
|
|
1962
2329
|
this.startDate.setHours(h, this.selectedMinute, this.selectedSecond);
|
|
1963
|
-
this.
|
|
2330
|
+
this.emitSelectionUnlessSingleDateDeferred();
|
|
1964
2331
|
}
|
|
1965
2332
|
}
|
|
1966
2333
|
toggleSingleAMPM() {
|
|
@@ -1972,7 +2339,7 @@ class BkCustomCalendar {
|
|
|
1972
2339
|
if (this.selectedAMPM === 'AM' && h === 12)
|
|
1973
2340
|
h = 0;
|
|
1974
2341
|
this.startDate.setHours(h, this.selectedMinute, this.selectedSecond);
|
|
1975
|
-
this.
|
|
2342
|
+
this.emitSelectionUnlessSingleDateDeferred();
|
|
1976
2343
|
}
|
|
1977
2344
|
}
|
|
1978
2345
|
getMonthName(month) {
|
|
@@ -2001,7 +2368,7 @@ class BkCustomCalendar {
|
|
|
2001
2368
|
if (this.selectedAMPM === 'AM' && h === 12)
|
|
2002
2369
|
h = 0;
|
|
2003
2370
|
this.startDate.setHours(h, this.selectedMinute, this.selectedSecond);
|
|
2004
|
-
this.
|
|
2371
|
+
this.emitSelectionUnlessSingleDateDeferred();
|
|
2005
2372
|
}
|
|
2006
2373
|
}
|
|
2007
2374
|
else if (isStart) {
|
|
@@ -2056,7 +2423,7 @@ class BkCustomCalendar {
|
|
|
2056
2423
|
if (this.selectedAMPM === 'AM' && h === 12)
|
|
2057
2424
|
h = 0;
|
|
2058
2425
|
this.startDate.setHours(h, this.selectedMinute, this.selectedSecond);
|
|
2059
|
-
this.
|
|
2426
|
+
this.emitSelectionUnlessSingleDateDeferred();
|
|
2060
2427
|
}
|
|
2061
2428
|
}
|
|
2062
2429
|
else if (isStart) {
|
|
@@ -2150,7 +2517,7 @@ class BkCustomCalendar {
|
|
|
2150
2517
|
if (this.selectedAMPM === 'AM' && h === 12)
|
|
2151
2518
|
h = 0;
|
|
2152
2519
|
this.startDate.setHours(h, this.selectedMinute, this.selectedSecond);
|
|
2153
|
-
this.
|
|
2520
|
+
this.emitSelectionUnlessSingleDateDeferred();
|
|
2154
2521
|
}
|
|
2155
2522
|
}
|
|
2156
2523
|
else if (isStart) {
|
|
@@ -2270,7 +2637,7 @@ class BkCustomCalendar {
|
|
|
2270
2637
|
return `${yyyy}-${mm}-${dd}`;
|
|
2271
2638
|
}
|
|
2272
2639
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkCustomCalendar, deps: [{ token: BkCalendarManagerService }], target: i0.ɵɵFactoryTarget.Component });
|
|
2273
|
-
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", drop: "drop", dualCalendar: "dualCalendar", showRanges: "showRanges", timeFormat: "timeFormat", clearableTime: "clearableTime", enableSeconds: "enableSeconds", customRanges: "customRanges", multiDateSelection: "multiDateSelection", maxDate: "maxDate", minDate: "minDate", placeholder: "placeholder", opens: "opens", inline: "inline", appendToBody: "appendToBody", isDisplayCrossIcon: "isDisplayCrossIcon", hasError: "hasError", errorMessage: "errorMessage", showCancelApply: "showCancelApply", selectedValue: "selectedValue", displayFormat: "displayFormat", required: "required" }, outputs: { selected: "selected", opened: "opened", closed: "closed" }, host: { listeners: { "document:click": "onClickOutside($event)", "window:scroll": "onWindowEvents()", "window:resize": "onWindowEvents()" } }, providers: [
|
|
2640
|
+
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", 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: [
|
|
2274
2641
|
{
|
|
2275
2642
|
provide: NG_VALUE_ACCESSOR,
|
|
2276
2643
|
useExisting: forwardRef(() => BkCustomCalendar),
|
|
@@ -2281,7 +2648,7 @@ class BkCustomCalendar {
|
|
|
2281
2648
|
useExisting: forwardRef(() => BkCustomCalendar),
|
|
2282
2649
|
multi: true,
|
|
2283
2650
|
},
|
|
2284
|
-
], viewQueries: [{ propertyName: "inputWrapper", first: true, predicate: ["inputWrapper"], 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 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 && drop !== 'up' ? dropdownStyle.top : null\"\r\n [style.bottom]=\"appendToBody && !inline && drop === 'up' ? dropdownStyle.bottom : null\"\r\n [style.left]=\"appendToBody && !inline ? dropdownStyle.left : null\"\r\n [ngClass]=\"{\r\n 'position-right': !inline && !appendToBody && opens === 'right',\r\n 'position-center': !inline && !appendToBody && opens === 'center',\r\n 'drop-up': !inline && drop === 'up',\r\n 'has-ranges': showRanges && customRanges,\r\n 'dual-calendar-mode': dualCalendar\r\n }\"\r\n *ngIf=\"inline || show\">\r\n\r\n <!-- RANGES -->\r\n <div class=\"ranges\" *ngIf=\"showRanges && customRanges\">\r\n <button\r\n *ngFor=\"let rangeKey of rangeOrder\"\r\n (click)=\"chooseRange(rangeKey)\"\r\n [class.active]=\"activeRange === rangeKey\"\r\n [class.custom-range]=\"rangeKey === 'Custom Range'\"\r\n class=\"range-btn\"\r\n [disabled]=\"rangeKey === 'Custom Range'\">\r\n {{ rangeKey }}\r\n </button>\r\n </div>\r\n<div class=\"\" [ngClass]=\"showRanges ? 'w-100 flex-grow-1' : ''\">\r\n\r\n\r\n <!-- SINGLE CALENDAR -->\r\n <div *ngIf=\"!dualCalendar\" class=\"calendar-wrapper\">\r\n <div class=\"header\">\r\n <!-- <button (click)=\"prevMonth()\" class=\"nav-btn\" type=\"button\">\r\n <img src=\"assets/calender/pagination-left-gray.svg\" alt=\"arrow-left\" class=\"arrow-left\">\r\n </button> -->\r\n <button class=\"nav-btn\" type=\"button\" (click)=\"prevMonth()\" matTooltip=\"Prev month\"\r\n >\r\n <img alt=\"prev\" class=\"h-3 w-3\" [src]=\"brickclayIcons.arrowleft\"/>\r\n </button>\r\n <span class=\"month-year\">{{ getMonthName(month) }} {{ year }}</span>\r\n <!-- <button (click)=\"nextMonth()\" class=\"nav-btn\" type=\"button\">\r\n <img src=\"assets/calender/pagination-right-gray.svg\" alt=\"arrow-right\" class=\"arrow-right\">\r\n </button> -->\r\n <button class=\"nav-btn\" type=\"button\" (click)=\"nextMonth()\" matTooltip=\"Next month\"\r\n >\r\n <img alt=\"next\" class=\"h-3 w-3\" [src]='brickclayIcons.arrowRight'/>\r\n <!--<img src=\"assets/calender/pagination-right-gray.svg\" alt=\"next\" class=\"h-3 w-3\" /> -->\r\n </button>\r\n </div>\r\n\r\n <table class=\"calendar-table\">\r\n <thead>\r\n <tr>\r\n <th *ngFor=\"let d of ['Mo','Tu','We','Th','Fr','Sa','Su']\" class=\"weekday-header\">{{ d }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let week of calendar\">\r\n <td\r\n *ngFor=\"let dayObj of week\"\r\n (click)=\"dayObj.currentMonth && !isDateDisabled(year, month, dayObj.day) && selectDate(dayObj.day)\"\r\n (mouseenter)=\"dayObj.currentMonth && !isDateDisabled(year, month, dayObj.day) && onDateHover(dayObj.day, false)\"\r\n (mouseleave)=\"onDateLeave()\"\r\n [class.active]=\"dayObj.currentMonth && isDateSelected(year, month, dayObj.day)\"\r\n [class.in-range]=\"dayObj.currentMonth && isDateInRange(year, month, dayObj.day)\"\r\n [class.other-month]=\"!dayObj.currentMonth\"\r\n [class.disabled]=\"isDateDisabled(year, month, dayObj.day)\"\r\n [class.multi-selected]=\"multiDateSelection && isDateInMultiSelection(year, month, dayObj.day)\"\r\n [class.today]=\"dayObj.currentMonth && isToday(year, month, dayObj.day)\"\r\n class=\"calendar-day\">\r\n {{ dayObj.day }}\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n\r\n <!-- Single Calendar Time Picker -->\r\n <div *ngIf=\"enableTimepicker\" class=\"timepicker-section\">\r\n <div class=\"timepicker-label\">Time</div>\r\n <div class=\"timepicker-controls\">\r\n <bk-time-picker\r\n pickerId=\"single-time\"\r\n [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\">\r\n <thead>\r\n <tr>\r\n <th *ngFor=\"let d of ['Mo','Tu','We','Th','Fr','Sa','Su']\" class=\"weekday-header\">{{ d }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let week of leftCalendar\">\r\n <td\r\n *ngFor=\"let dayObj of week\"\r\n (click)=\"dayObj.currentMonth && !isDateDisabled(leftYear, leftMonth, dayObj.day) && selectDate(dayObj.day, false)\"\r\n (mouseenter)=\"dayObj.currentMonth && !isDateDisabled(leftYear, leftMonth, dayObj.day) && onDateHover(dayObj.day, false)\"\r\n (mouseleave)=\"onDateLeave()\"\r\n [class.active]=\"dayObj.currentMonth && isDateSelected(leftYear, leftMonth, dayObj.day)\"\r\n [class.in-range]=\"dayObj.currentMonth && isDateInRange(leftYear, leftMonth, dayObj.day)\"\r\n [class.other-month]=\"!dayObj.currentMonth\"\r\n [class.disabled]=\"isDateDisabled(leftYear, leftMonth, dayObj.day)\"\r\n [class.multi-selected]=\"multiDateSelection && isDateInMultiSelection(leftYear, leftMonth, dayObj.day)\"\r\n [class.today]=\"dayObj.currentMonth && isToday(leftYear, leftMonth, dayObj.day)\"\r\n class=\"calendar-day\">\r\n {{ dayObj.day }}\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n\r\n <!-- Start Time Picker for Dual Calendar -->\r\n <div *ngIf=\"enableTimepicker\" class=\"timepicker-section\">\r\n <div class=\"timepicker-label\">Start Time</div>\r\n <div class=\"timepicker-controls\">\r\n <bk-time-picker\r\n pickerId=\"dual-start\"\r\n [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\">\r\n <thead>\r\n <tr>\r\n <th *ngFor=\"let d of ['Mo','Tu','We','Th','Fr','Sa','Su']\" class=\"weekday-header\">{{ d }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let week of rightCalendar\">\r\n <td\r\n *ngFor=\"let dayObj of week\"\r\n (click)=\"dayObj.currentMonth && !isDateDisabled(rightYear, rightMonth, dayObj.day) && selectDate(dayObj.day, true)\"\r\n (mouseenter)=\"dayObj.currentMonth && !isDateDisabled(rightYear, rightMonth, dayObj.day) && onDateHover(dayObj.day, true)\"\r\n (mouseleave)=\"onDateLeave()\"\r\n [class.active]=\"dayObj.currentMonth && isDateSelected(rightYear, rightMonth, dayObj.day)\"\r\n [class.in-range]=\"dayObj.currentMonth && isDateInRange(rightYear, rightMonth, dayObj.day)\"\r\n [class.other-month]=\"!dayObj.currentMonth\"\r\n [class.disabled]=\"isDateDisabled(rightYear, rightMonth, dayObj.day)\"\r\n [class.multi-selected]=\"multiDateSelection && isDateInMultiSelection(rightYear, rightMonth, dayObj.day)\"\r\n [class.today]=\"dayObj.currentMonth && isToday(rightYear, rightMonth, dayObj.day)\"\r\n class=\"calendar-day\">\r\n {{ dayObj.day }}\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n\r\n <!-- End Time Picker for Dual Calendar -->\r\n <div *ngIf=\"enableTimepicker\" class=\"timepicker-section\">\r\n <div class=\"timepicker-label\">End Time</div>\r\n <div class=\"timepicker-controls\">\r\n <bk-time-picker\r\n pickerId=\"dual-end\"\r\n [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\">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;box-shadow:0 0 0 3px #6a6a6a1a}.calendar-icon{position:absolute;left:12px;pointer-events:none;font-size:18px}.clear-btn{position:absolute;right:9px;background:none;border:none;font-size:20px;color:#999;cursor:pointer;padding:0;width:20px;height:20px;display:flex;align-items:center;justify-content:center;line-height:1;transition:color .2s;top:8px}.clear-btn:hover{color:#333}.calendar-popup{position:absolute;top:110%;left:0;width:320px;background:#fff;border-radius:12px;box-shadow:0 10px 40px #00000026;z-index:1000;animation:slideDown .2s ease-out}.calendar-popup.inline-calendar{position:relative;top:0;left:0;width:100%;margin-top:0;animation:none;box-shadow:0 2px 8px #0000001a}.calendar-container.inline-mode{display:block;width:100%}.calendar-popup.dual-calendar-mode{width:600px}.calendar-popup.dual-calendar-mode.has-ranges{width:730px}.calendar-popup.has-ranges{width:450px}.calendar-popup.dual-calendar-mode.has-ranges .dual-calendar{border-left:1px solid #eee}.calendar-popup.drop-up{top:auto;bottom:110%;animation:slideUp .2s ease-out}.calendar-popup.position-right{left:auto;right:0}.calendar-popup.position-center{left:50%;transform:translate(-50%)}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes slideUp{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.ranges{display:flex;flex-direction:column;gap:4px;margin-bottom:16px;padding-bottom:16px;border-bottom:1px solid #eee;min-width:150px;padding-right:8px}.range-btn{padding:7px 10px;border:1px solid transparent;background:transparent;border-radius:4px;cursor:pointer;text-align:left;font-size:14px;transition:all .2s;color:#838383;font-weight:500}.range-btn:hover{background:#f5f5f5;color:#000}.range-btn.active{background:#f0f0f0;color:#000;font-weight:500}.calendar-wrapper{padding:0 12px 12px;border-left:1px solid #eee}.header{display:flex;justify-content:space-between;align-items:center;padding:12px 0}.month-year{font-size:15px;font-weight:500;color:#333;flex:1;text-align:center;text-transform:capitalize}.nav-btn{background:none;border:none;font-size:24px;cursor:pointer;padding:11.5px 14px;color:#666;border-radius:4px;transition:all .2s;line-height:1;height:30px;width:30px;display:flex;justify-content:center;align-items:center}.nav-btn:hover{background:#f0f0f0;color:#000}.nav-btn img{width:auto;max-width:none!important}.calendar-table{width:100%;border-collapse:collapse;text-align:center}.weekday-header{font-size:12px;color:#7e7e7e;font-weight:600;padding:8px 4px;letter-spacing:.3px}.calendar-day{padding:8px 4px;font-size:14px;cursor:pointer;border-radius:6px;transition:all .2s;position:relative;color:#333;font-weight:500;line-height:1.5}.calendar-day:hover:not(.disabled):not(.other-month){background:#efefef;color:#000}.calendar-day.other-month{color:#ccc;cursor:default}.calendar-day.disabled{color:#ddd;cursor:not-allowed;opacity:.5}.calendar-day.active{background:#000!important;color:#fff!important;font-weight:600}.calendar-day.today{font-weight:600}.calendar-day.today:not(.active){background:#e5e4e4}.calendar-day.active:hover{background:#000!important}.calendar-day.in-range{background:#f5f5f5;color:#333;border-radius:0;position:relative}.calendar-day.in-range:hover{background:#e8e8e8}.calendar-day.in-range:before{content:\"\";position:absolute;inset:0;background:#f5f5f5;z-index:-1}.calendar-day.in-range:hover:before{background:#e8e8e8}.calendar-day.multi-selected{background:#4caf50;color:#fff;font-weight:600;border-radius:6px}.calendar-day.multi-selected:hover{background:#45a049}.dual-calendar{display:flex;width:100%;border-left:1px solid #eee}.calendar-left,.calendar-right{flex:1;min-width:0;padding:0 12px 12px}.calendar-popup.has-ranges{display:flex;flex-direction:row}.calendar-popup.has-ranges .ranges{margin-bottom:0;border-bottom:none;padding:10px}.calendar-popup.has-ranges .dual-calendar,.calendar-popup.has-ranges .calendar-wrapper{flex:1}.calendar-right .header{justify-content:space-between}.calendar-right .header .month-year{text-align:center;flex:1}.timepicker-section{margin-top:12px;padding-top:12px;border-top:1px solid #eee}.timepicker-label{font-size:12px;font-weight:500;color:#000;margin-bottom:4px;letter-spacing:-.28px}.custom-time-picker{display:flex;flex-direction:column;gap:8px;align-items:start}.time-input-group{display:flex;align-items:center;justify-content:center;gap:8px;background:#f8f9fa;padding:12px;border-radius:8px;border:1px solid #e0e0e0}.time-control{display:flex;flex-direction:column;align-items:center}.time-btn{background:#fff;border:1px solid #ddd;width:28px;height:20px;cursor:pointer;font-size:10px;color:#666;border-radius:4px;transition:all .2s;display:flex;align-items:center;justify-content:center;padding:0;line-height:1}.time-btn:hover{background:#e4e4e4;color:#fff;border-color:#e4e4e4}.time-btn.up{border-bottom-left-radius:0;border-bottom-right-radius:0;border-bottom:none}.time-btn.down{border-top-left-radius:0;border-top-right-radius:0;border-top:none}.time-input{width:40px;height:32px;text-align:center;border:1px solid #ddd;border-radius:4px;font-size:16px;font-weight:600;background:#fff;color:#333}.time-separator{font-size:18px;font-weight:600;color:#666;margin:0 2px}.ampm-control{display:flex;flex-direction:column;gap:4px;margin-left:8px}.ampm-btn{padding:6px 12px;border:1px solid #ddd;background:#fff;border-radius:4px;cursor:pointer;font-size:12px;font-weight:600;color:#666;transition:all .2s;min-width:45px}.ampm-btn:hover{background:#f0f0f0}.ampm-btn.active{background:#000;color:#fff;border-color:#000}.html5-time-input{margin-top:8px;padding:8px;border:1px solid #ddd;border-radius:6px;font-size:14px;width:100%;max-width:120px}.footer{padding:12px;display:flex;justify-content:flex-end;gap:8px;border-top:1px solid #eee}.btn-cancel,.btn-apply{padding:8px 16px;border:none;border-radius:4px;font-size:14px;font-weight:500;cursor:pointer;transition:all .2s;min-width:80px}.btn-cancel{background:#fff;color:#666;border:1px solid #ddd}.btn-cancel:hover{background:#f5f5f5;border-color:#bbb}.btn-apply{background:#000;color:#fff}.btn-apply:hover{background:#333}.btn-apply:active{transform:translateY(0)}@media (max-width: 768px){.calendar-popup{width:100%;max-width:320px}.calendar-popup.dual-calendar-mode{width:100%;max-width:100%}.calendar-popup.has-ranges{flex-direction:column}.calendar-popup.has-ranges .ranges{border-right:none;border-bottom:1px solid #eee;padding-right:0;margin-right:0;padding-bottom:16px;margin-bottom:16px}.dual-calendar{flex-direction:column}.time-input-group{flex-wrap:wrap;justify-content:center}}.ranges::-webkit-scrollbar{width:6px}.ranges::-webkit-scrollbar-track{background:#f1f1f1;border-radius:3px}.ranges::-webkit-scrollbar-thumb{background:#888;border-radius:3px}.ranges::-webkit-scrollbar-thumb:hover{background:#555}.w-100{width:100%}.flex-grow-1{flex-grow:1}.calendar-input.calendar-input-has-error{@apply border-[#d11e14];}.calendar-input:disabled{cursor:not-allowed;border-color:#e3e3e7;background-color:#f4f4f6;color:#a1a3ae}\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"] }] });
|
|
2651
|
+
], 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 }\"\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' : ''\">\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 [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 [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 [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;box-shadow:0 0 0 3px #6a6a6a1a}.calendar-icon{position:absolute;left:12px;pointer-events:none;font-size:18px}.clear-btn{position:absolute;right:9px;background:none;border:none;font-size:20px;color:#999;cursor:pointer;padding:0;width:20px;height:20px;display:flex;align-items:center;justify-content:center;line-height:1;transition:color .2s;top:8px}.clear-btn:hover{color:#333}.calendar-popup{position:absolute;top:110%;left:0;width:320px;background:#fff;border-radius:12px;box-shadow:0 10px 40px #00000026;z-index:1000;animation:slideDown .2s ease-out}.calendar-popup: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.dual-calendar-mode.has-ranges .dual-calendar{border-left:1px solid #eee}.calendar-popup.drop-up{top:auto;bottom:110%;animation:slideUp .2s ease-out}.calendar-popup.position-right{left:auto;right:0}.calendar-popup.position-center{left:50%;transform:translate(-50%)}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes slideUp{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.ranges{display:flex;flex-direction:column;gap:4px;margin-bottom:16px;padding-bottom:16px;border-bottom:1px solid #eee;min-width:150px;padding-right:8px}.range-btn{padding:7px 10px;border:1px solid transparent;background:transparent;border-radius:4px;cursor:pointer;text-align:left;font-size:14px;transition:all .2s;color:#838383;font-weight:500}.range-btn:hover{background:#f5f5f5;color:#000}.range-btn.active{background:#f0f0f0;color:#000;font-weight:500}.calendar-wrapper{padding:0 12px 12px;border-left:1px solid #eee}.header{display:flex;justify-content:space-between;align-items:center;padding:12px 0}.month-year{font-size:15px;font-weight:500;color:#333;flex:1;text-align:center;text-transform:capitalize}.nav-btn{background:none;border:none;font-size:24px;cursor:pointer;padding:11.5px 14px;color:#666;border-radius:4px;transition:all .2s;line-height:1;height:30px;width:30px;display:flex;justify-content:center;align-items:center}.nav-btn:hover{background:#f0f0f0;color:#000}.nav-btn img{width:auto;max-width:none!important}.calendar-table{width:100%;border-collapse:collapse;text-align:center}.weekday-header{font-size:12px;color:#7e7e7e;font-weight:600;padding:8px 4px;letter-spacing:.3px}.calendar-day{padding:8px 4px;font-size:14px;cursor:pointer;border-radius:6px;transition:all .2s;position:relative;color:#333;font-weight:500;line-height:1.5}.calendar-day:hover:not(.disabled):not(.other-month){background:#efefef;color:#000}.calendar-day.other-month{color:#ccc;cursor:default}.calendar-day.disabled{color:#ddd;cursor:not-allowed;opacity:.5}.calendar-day.active{background:#000!important;color:#fff!important;font-weight:600}.calendar-day.today{font-weight:600}.calendar-day.today:not(.active){background:#e5e4e4}.calendar-day.active:hover{background:#000!important}.calendar-day.in-range{background:#f5f5f5;color:#333;border-radius:0;position:relative}.calendar-day.in-range:hover{background:#e8e8e8}.calendar-day.in-range:before{content:\"\";position:absolute;inset:0;background:#f5f5f5;z-index:-1}.calendar-day.in-range:hover:before{background:#e8e8e8}.calendar-day.multi-selected{background:#4caf50;color:#fff;font-weight:600;border-radius:6px}.calendar-day.multi-selected:hover{background:#45a049}.dual-calendar{display:flex;width:100%;border-left:1px solid #eee}.calendar-left,.calendar-right{flex:1;min-width:0;padding:0 12px 12px}.calendar-popup.has-ranges{display:flex;flex-direction:row}.calendar-popup.has-ranges .ranges{margin-bottom:0;border-bottom:none;padding:10px}.calendar-popup.has-ranges .dual-calendar,.calendar-popup.has-ranges .calendar-wrapper{flex:1}.calendar-right .header{justify-content:space-between}.calendar-right .header .month-year{text-align:center;flex:1}.timepicker-section{margin-top:12px;padding-top:12px;border-top:1px solid #eee}.timepicker-label{font-size:12px;font-weight:500;color:#000;margin-bottom:4px;letter-spacing:-.28px}.custom-time-picker{display:flex;flex-direction:column;gap:8px;align-items:start}.time-input-group{display:flex;align-items:center;justify-content:center;gap:8px;background:#f8f9fa;padding:12px;border-radius:8px;border:1px solid #e0e0e0}.time-control{display:flex;flex-direction:column;align-items:center}.time-btn{background:#fff;border:1px solid #ddd;width:28px;height:20px;cursor:pointer;font-size:10px;color:#666;border-radius:4px;transition:all .2s;display:flex;align-items:center;justify-content:center;padding:0;line-height:1}.time-btn:hover{background:#e4e4e4;color:#fff;border-color:#e4e4e4}.time-btn.up{border-bottom-left-radius:0;border-bottom-right-radius:0;border-bottom:none}.time-btn.down{border-top-left-radius:0;border-top-right-radius:0;border-top:none}.time-input{width:40px;height:32px;text-align:center;border:1px solid #ddd;border-radius:4px;font-size:16px;font-weight:600;background:#fff;color:#333}.time-separator{font-size:18px;font-weight:600;color:#666;margin:0 2px}.ampm-control{display:flex;flex-direction:column;gap:4px;margin-left:8px}.ampm-btn{padding:6px 12px;border:1px solid #ddd;background:#fff;border-radius:4px;cursor:pointer;font-size:12px;font-weight:600;color:#666;transition:all .2s;min-width:45px}.ampm-btn:hover{background:#f0f0f0}.ampm-btn.active{background:#000;color:#fff;border-color:#000}.html5-time-input{margin-top:8px;padding:8px;border:1px solid #ddd;border-radius:6px;font-size:14px;width:100%;max-width:120px}.footer{padding:12px;display:flex;justify-content:flex-end;gap:8px;border-top:1px solid #eee}.btn-cancel,.btn-apply{padding:8px 16px;border:none;border-radius:4px;font-size:14px;font-weight:500;cursor:pointer;transition:all .2s;min-width:80px}.btn-cancel{background:#fff;color:#666;border:1px solid #ddd}.btn-apply{background:#000;color:#fff}.btn-apply:active{transform:translateY(0)}@media (max-width: 768px){.calendar-popup{width:100%;max-width:320px}.calendar-popup.dual-calendar-mode{width:100%;max-width:100%}.calendar-popup.has-ranges{flex-direction:column}.calendar-popup.has-ranges .ranges{border-right:none;border-bottom:1px solid #eee;padding-right:0;margin-right:0;padding-bottom:16px;margin-bottom:16px}.dual-calendar{flex-direction:column}.time-input-group{flex-wrap:wrap;justify-content:center}}.ranges::-webkit-scrollbar{width:6px}.ranges::-webkit-scrollbar-track{background:#f1f1f1;border-radius:3px}.ranges::-webkit-scrollbar-thumb{background:#888;border-radius:3px}.ranges::-webkit-scrollbar-thumb:hover{background:#555}.w-100{width:100%}.flex-grow-1{flex-grow:1}.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:.5px solid #000;outline-offset:.5px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "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"] }] });
|
|
2285
2652
|
}
|
|
2286
2653
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkCustomCalendar, decorators: [{
|
|
2287
2654
|
type: Component,
|
|
@@ -2296,7 +2663,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
2296
2663
|
useExisting: forwardRef(() => BkCustomCalendar),
|
|
2297
2664
|
multi: true,
|
|
2298
2665
|
},
|
|
2299
|
-
], 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 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 && drop !== 'up' ? dropdownStyle.top : null\"\r\n [style.bottom]=\"appendToBody && !inline && drop === 'up' ? dropdownStyle.bottom : null\"\r\n [style.left]=\"appendToBody && !inline ? dropdownStyle.left : null\"\r\n [ngClass]=\"{\r\n 'position-right': !inline && !appendToBody && opens === 'right',\r\n 'position-center': !inline && !appendToBody && opens === 'center',\r\n 'drop-up': !inline && drop === 'up',\r\n 'has-ranges': showRanges && customRanges,\r\n 'dual-calendar-mode': dualCalendar\r\n }\"\r\n *ngIf=\"inline || show\">\r\n\r\n <!-- RANGES -->\r\n <div class=\"ranges\" *ngIf=\"showRanges && customRanges\">\r\n <button\r\n *ngFor=\"let rangeKey of rangeOrder\"\r\n (click)=\"chooseRange(rangeKey)\"\r\n [class.active]=\"activeRange === rangeKey\"\r\n [class.custom-range]=\"rangeKey === 'Custom Range'\"\r\n class=\"range-btn\"\r\n [disabled]=\"rangeKey === 'Custom Range'\">\r\n {{ rangeKey }}\r\n </button>\r\n </div>\r\n<div class=\"\" [ngClass]=\"showRanges ? 'w-100 flex-grow-1' : ''\">\r\n\r\n\r\n <!-- SINGLE CALENDAR -->\r\n <div *ngIf=\"!dualCalendar\" class=\"calendar-wrapper\">\r\n <div class=\"header\">\r\n <!-- <button (click)=\"prevMonth()\" class=\"nav-btn\" type=\"button\">\r\n <img src=\"assets/calender/pagination-left-gray.svg\" alt=\"arrow-left\" class=\"arrow-left\">\r\n </button> -->\r\n <button class=\"nav-btn\" type=\"button\" (click)=\"prevMonth()\" matTooltip=\"Prev month\"\r\n >\r\n <img alt=\"prev\" class=\"h-3 w-3\" [src]=\"brickclayIcons.arrowleft\"/>\r\n </button>\r\n <span class=\"month-year\">{{ getMonthName(month) }} {{ year }}</span>\r\n <!-- <button (click)=\"nextMonth()\" class=\"nav-btn\" type=\"button\">\r\n <img src=\"assets/calender/pagination-right-gray.svg\" alt=\"arrow-right\" class=\"arrow-right\">\r\n </button> -->\r\n <button class=\"nav-btn\" type=\"button\" (click)=\"nextMonth()\" matTooltip=\"Next month\"\r\n >\r\n <img alt=\"next\" class=\"h-3 w-3\" [src]='brickclayIcons.arrowRight'/>\r\n <!--<img src=\"assets/calender/pagination-right-gray.svg\" alt=\"next\" class=\"h-3 w-3\" /> -->\r\n </button>\r\n </div>\r\n\r\n <table class=\"calendar-table\">\r\n <thead>\r\n <tr>\r\n <th *ngFor=\"let d of ['Mo','Tu','We','Th','Fr','Sa','Su']\" class=\"weekday-header\">{{ d }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let week of calendar\">\r\n <td\r\n *ngFor=\"let dayObj of week\"\r\n (click)=\"dayObj.currentMonth && !isDateDisabled(year, month, dayObj.day) && selectDate(dayObj.day)\"\r\n (mouseenter)=\"dayObj.currentMonth && !isDateDisabled(year, month, dayObj.day) && onDateHover(dayObj.day, false)\"\r\n (mouseleave)=\"onDateLeave()\"\r\n [class.active]=\"dayObj.currentMonth && isDateSelected(year, month, dayObj.day)\"\r\n [class.in-range]=\"dayObj.currentMonth && isDateInRange(year, month, dayObj.day)\"\r\n [class.other-month]=\"!dayObj.currentMonth\"\r\n [class.disabled]=\"isDateDisabled(year, month, dayObj.day)\"\r\n [class.multi-selected]=\"multiDateSelection && isDateInMultiSelection(year, month, dayObj.day)\"\r\n [class.today]=\"dayObj.currentMonth && isToday(year, month, dayObj.day)\"\r\n class=\"calendar-day\">\r\n {{ dayObj.day }}\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n\r\n <!-- Single Calendar Time Picker -->\r\n <div *ngIf=\"enableTimepicker\" class=\"timepicker-section\">\r\n <div class=\"timepicker-label\">Time</div>\r\n <div class=\"timepicker-controls\">\r\n <bk-time-picker\r\n pickerId=\"single-time\"\r\n [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\">\r\n <thead>\r\n <tr>\r\n <th *ngFor=\"let d of ['Mo','Tu','We','Th','Fr','Sa','Su']\" class=\"weekday-header\">{{ d }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let week of leftCalendar\">\r\n <td\r\n *ngFor=\"let dayObj of week\"\r\n (click)=\"dayObj.currentMonth && !isDateDisabled(leftYear, leftMonth, dayObj.day) && selectDate(dayObj.day, false)\"\r\n (mouseenter)=\"dayObj.currentMonth && !isDateDisabled(leftYear, leftMonth, dayObj.day) && onDateHover(dayObj.day, false)\"\r\n (mouseleave)=\"onDateLeave()\"\r\n [class.active]=\"dayObj.currentMonth && isDateSelected(leftYear, leftMonth, dayObj.day)\"\r\n [class.in-range]=\"dayObj.currentMonth && isDateInRange(leftYear, leftMonth, dayObj.day)\"\r\n [class.other-month]=\"!dayObj.currentMonth\"\r\n [class.disabled]=\"isDateDisabled(leftYear, leftMonth, dayObj.day)\"\r\n [class.multi-selected]=\"multiDateSelection && isDateInMultiSelection(leftYear, leftMonth, dayObj.day)\"\r\n [class.today]=\"dayObj.currentMonth && isToday(leftYear, leftMonth, dayObj.day)\"\r\n class=\"calendar-day\">\r\n {{ dayObj.day }}\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n\r\n <!-- Start Time Picker for Dual Calendar -->\r\n <div *ngIf=\"enableTimepicker\" class=\"timepicker-section\">\r\n <div class=\"timepicker-label\">Start Time</div>\r\n <div class=\"timepicker-controls\">\r\n <bk-time-picker\r\n pickerId=\"dual-start\"\r\n [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\">\r\n <thead>\r\n <tr>\r\n <th *ngFor=\"let d of ['Mo','Tu','We','Th','Fr','Sa','Su']\" class=\"weekday-header\">{{ d }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let week of rightCalendar\">\r\n <td\r\n *ngFor=\"let dayObj of week\"\r\n (click)=\"dayObj.currentMonth && !isDateDisabled(rightYear, rightMonth, dayObj.day) && selectDate(dayObj.day, true)\"\r\n (mouseenter)=\"dayObj.currentMonth && !isDateDisabled(rightYear, rightMonth, dayObj.day) && onDateHover(dayObj.day, true)\"\r\n (mouseleave)=\"onDateLeave()\"\r\n [class.active]=\"dayObj.currentMonth && isDateSelected(rightYear, rightMonth, dayObj.day)\"\r\n [class.in-range]=\"dayObj.currentMonth && isDateInRange(rightYear, rightMonth, dayObj.day)\"\r\n [class.other-month]=\"!dayObj.currentMonth\"\r\n [class.disabled]=\"isDateDisabled(rightYear, rightMonth, dayObj.day)\"\r\n [class.multi-selected]=\"multiDateSelection && isDateInMultiSelection(rightYear, rightMonth, dayObj.day)\"\r\n [class.today]=\"dayObj.currentMonth && isToday(rightYear, rightMonth, dayObj.day)\"\r\n class=\"calendar-day\">\r\n {{ dayObj.day }}\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n\r\n <!-- End Time Picker for Dual Calendar -->\r\n <div *ngIf=\"enableTimepicker\" class=\"timepicker-section\">\r\n <div class=\"timepicker-label\">End Time</div>\r\n <div class=\"timepicker-controls\">\r\n <bk-time-picker\r\n pickerId=\"dual-end\"\r\n [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\">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;box-shadow:0 0 0 3px #6a6a6a1a}.calendar-icon{position:absolute;left:12px;pointer-events:none;font-size:18px}.clear-btn{position:absolute;right:9px;background:none;border:none;font-size:20px;color:#999;cursor:pointer;padding:0;width:20px;height:20px;display:flex;align-items:center;justify-content:center;line-height:1;transition:color .2s;top:8px}.clear-btn:hover{color:#333}.calendar-popup{position:absolute;top:110%;left:0;width:320px;background:#fff;border-radius:12px;box-shadow:0 10px 40px #00000026;z-index:1000;animation:slideDown .2s ease-out}.calendar-popup.inline-calendar{position:relative;top:0;left:0;width:100%;margin-top:0;animation:none;box-shadow:0 2px 8px #0000001a}.calendar-container.inline-mode{display:block;width:100%}.calendar-popup.dual-calendar-mode{width:600px}.calendar-popup.dual-calendar-mode.has-ranges{width:730px}.calendar-popup.has-ranges{width:450px}.calendar-popup.dual-calendar-mode.has-ranges .dual-calendar{border-left:1px solid #eee}.calendar-popup.drop-up{top:auto;bottom:110%;animation:slideUp .2s ease-out}.calendar-popup.position-right{left:auto;right:0}.calendar-popup.position-center{left:50%;transform:translate(-50%)}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes slideUp{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.ranges{display:flex;flex-direction:column;gap:4px;margin-bottom:16px;padding-bottom:16px;border-bottom:1px solid #eee;min-width:150px;padding-right:8px}.range-btn{padding:7px 10px;border:1px solid transparent;background:transparent;border-radius:4px;cursor:pointer;text-align:left;font-size:14px;transition:all .2s;color:#838383;font-weight:500}.range-btn:hover{background:#f5f5f5;color:#000}.range-btn.active{background:#f0f0f0;color:#000;font-weight:500}.calendar-wrapper{padding:0 12px 12px;border-left:1px solid #eee}.header{display:flex;justify-content:space-between;align-items:center;padding:12px 0}.month-year{font-size:15px;font-weight:500;color:#333;flex:1;text-align:center;text-transform:capitalize}.nav-btn{background:none;border:none;font-size:24px;cursor:pointer;padding:11.5px 14px;color:#666;border-radius:4px;transition:all .2s;line-height:1;height:30px;width:30px;display:flex;justify-content:center;align-items:center}.nav-btn:hover{background:#f0f0f0;color:#000}.nav-btn img{width:auto;max-width:none!important}.calendar-table{width:100%;border-collapse:collapse;text-align:center}.weekday-header{font-size:12px;color:#7e7e7e;font-weight:600;padding:8px 4px;letter-spacing:.3px}.calendar-day{padding:8px 4px;font-size:14px;cursor:pointer;border-radius:6px;transition:all .2s;position:relative;color:#333;font-weight:500;line-height:1.5}.calendar-day:hover:not(.disabled):not(.other-month){background:#efefef;color:#000}.calendar-day.other-month{color:#ccc;cursor:default}.calendar-day.disabled{color:#ddd;cursor:not-allowed;opacity:.5}.calendar-day.active{background:#000!important;color:#fff!important;font-weight:600}.calendar-day.today{font-weight:600}.calendar-day.today:not(.active){background:#e5e4e4}.calendar-day.active:hover{background:#000!important}.calendar-day.in-range{background:#f5f5f5;color:#333;border-radius:0;position:relative}.calendar-day.in-range:hover{background:#e8e8e8}.calendar-day.in-range:before{content:\"\";position:absolute;inset:0;background:#f5f5f5;z-index:-1}.calendar-day.in-range:hover:before{background:#e8e8e8}.calendar-day.multi-selected{background:#4caf50;color:#fff;font-weight:600;border-radius:6px}.calendar-day.multi-selected:hover{background:#45a049}.dual-calendar{display:flex;width:100%;border-left:1px solid #eee}.calendar-left,.calendar-right{flex:1;min-width:0;padding:0 12px 12px}.calendar-popup.has-ranges{display:flex;flex-direction:row}.calendar-popup.has-ranges .ranges{margin-bottom:0;border-bottom:none;padding:10px}.calendar-popup.has-ranges .dual-calendar,.calendar-popup.has-ranges .calendar-wrapper{flex:1}.calendar-right .header{justify-content:space-between}.calendar-right .header .month-year{text-align:center;flex:1}.timepicker-section{margin-top:12px;padding-top:12px;border-top:1px solid #eee}.timepicker-label{font-size:12px;font-weight:500;color:#000;margin-bottom:4px;letter-spacing:-.28px}.custom-time-picker{display:flex;flex-direction:column;gap:8px;align-items:start}.time-input-group{display:flex;align-items:center;justify-content:center;gap:8px;background:#f8f9fa;padding:12px;border-radius:8px;border:1px solid #e0e0e0}.time-control{display:flex;flex-direction:column;align-items:center}.time-btn{background:#fff;border:1px solid #ddd;width:28px;height:20px;cursor:pointer;font-size:10px;color:#666;border-radius:4px;transition:all .2s;display:flex;align-items:center;justify-content:center;padding:0;line-height:1}.time-btn:hover{background:#e4e4e4;color:#fff;border-color:#e4e4e4}.time-btn.up{border-bottom-left-radius:0;border-bottom-right-radius:0;border-bottom:none}.time-btn.down{border-top-left-radius:0;border-top-right-radius:0;border-top:none}.time-input{width:40px;height:32px;text-align:center;border:1px solid #ddd;border-radius:4px;font-size:16px;font-weight:600;background:#fff;color:#333}.time-separator{font-size:18px;font-weight:600;color:#666;margin:0 2px}.ampm-control{display:flex;flex-direction:column;gap:4px;margin-left:8px}.ampm-btn{padding:6px 12px;border:1px solid #ddd;background:#fff;border-radius:4px;cursor:pointer;font-size:12px;font-weight:600;color:#666;transition:all .2s;min-width:45px}.ampm-btn:hover{background:#f0f0f0}.ampm-btn.active{background:#000;color:#fff;border-color:#000}.html5-time-input{margin-top:8px;padding:8px;border:1px solid #ddd;border-radius:6px;font-size:14px;width:100%;max-width:120px}.footer{padding:12px;display:flex;justify-content:flex-end;gap:8px;border-top:1px solid #eee}.btn-cancel,.btn-apply{padding:8px 16px;border:none;border-radius:4px;font-size:14px;font-weight:500;cursor:pointer;transition:all .2s;min-width:80px}.btn-cancel{background:#fff;color:#666;border:1px solid #ddd}.btn-cancel:hover{background:#f5f5f5;border-color:#bbb}.btn-apply{background:#000;color:#fff}.btn-apply:hover{background:#333}.btn-apply:active{transform:translateY(0)}@media (max-width: 768px){.calendar-popup{width:100%;max-width:320px}.calendar-popup.dual-calendar-mode{width:100%;max-width:100%}.calendar-popup.has-ranges{flex-direction:column}.calendar-popup.has-ranges .ranges{border-right:none;border-bottom:1px solid #eee;padding-right:0;margin-right:0;padding-bottom:16px;margin-bottom:16px}.dual-calendar{flex-direction:column}.time-input-group{flex-wrap:wrap;justify-content:center}}.ranges::-webkit-scrollbar{width:6px}.ranges::-webkit-scrollbar-track{background:#f1f1f1;border-radius:3px}.ranges::-webkit-scrollbar-thumb{background:#888;border-radius:3px}.ranges::-webkit-scrollbar-thumb:hover{background:#555}.w-100{width:100%}.flex-grow-1{flex-grow:1}.calendar-input.calendar-input-has-error{@apply border-[#d11e14];}.calendar-input:disabled{cursor:not-allowed;border-color:#e3e3e7;background-color:#f4f4f6;color:#a1a3ae}\n"] }]
|
|
2666
|
+
], 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 }\"\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' : ''\">\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 [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 [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 [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;box-shadow:0 0 0 3px #6a6a6a1a}.calendar-icon{position:absolute;left:12px;pointer-events:none;font-size:18px}.clear-btn{position:absolute;right:9px;background:none;border:none;font-size:20px;color:#999;cursor:pointer;padding:0;width:20px;height:20px;display:flex;align-items:center;justify-content:center;line-height:1;transition:color .2s;top:8px}.clear-btn:hover{color:#333}.calendar-popup{position:absolute;top:110%;left:0;width:320px;background:#fff;border-radius:12px;box-shadow:0 10px 40px #00000026;z-index:1000;animation:slideDown .2s ease-out}.calendar-popup: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.dual-calendar-mode.has-ranges .dual-calendar{border-left:1px solid #eee}.calendar-popup.drop-up{top:auto;bottom:110%;animation:slideUp .2s ease-out}.calendar-popup.position-right{left:auto;right:0}.calendar-popup.position-center{left:50%;transform:translate(-50%)}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes slideUp{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.ranges{display:flex;flex-direction:column;gap:4px;margin-bottom:16px;padding-bottom:16px;border-bottom:1px solid #eee;min-width:150px;padding-right:8px}.range-btn{padding:7px 10px;border:1px solid transparent;background:transparent;border-radius:4px;cursor:pointer;text-align:left;font-size:14px;transition:all .2s;color:#838383;font-weight:500}.range-btn:hover{background:#f5f5f5;color:#000}.range-btn.active{background:#f0f0f0;color:#000;font-weight:500}.calendar-wrapper{padding:0 12px 12px;border-left:1px solid #eee}.header{display:flex;justify-content:space-between;align-items:center;padding:12px 0}.month-year{font-size:15px;font-weight:500;color:#333;flex:1;text-align:center;text-transform:capitalize}.nav-btn{background:none;border:none;font-size:24px;cursor:pointer;padding:11.5px 14px;color:#666;border-radius:4px;transition:all .2s;line-height:1;height:30px;width:30px;display:flex;justify-content:center;align-items:center}.nav-btn:hover{background:#f0f0f0;color:#000}.nav-btn img{width:auto;max-width:none!important}.calendar-table{width:100%;border-collapse:collapse;text-align:center}.weekday-header{font-size:12px;color:#7e7e7e;font-weight:600;padding:8px 4px;letter-spacing:.3px}.calendar-day{padding:8px 4px;font-size:14px;cursor:pointer;border-radius:6px;transition:all .2s;position:relative;color:#333;font-weight:500;line-height:1.5}.calendar-day:hover:not(.disabled):not(.other-month){background:#efefef;color:#000}.calendar-day.other-month{color:#ccc;cursor:default}.calendar-day.disabled{color:#ddd;cursor:not-allowed;opacity:.5}.calendar-day.active{background:#000!important;color:#fff!important;font-weight:600}.calendar-day.today{font-weight:600}.calendar-day.today:not(.active){background:#e5e4e4}.calendar-day.active:hover{background:#000!important}.calendar-day.in-range{background:#f5f5f5;color:#333;border-radius:0;position:relative}.calendar-day.in-range:hover{background:#e8e8e8}.calendar-day.in-range:before{content:\"\";position:absolute;inset:0;background:#f5f5f5;z-index:-1}.calendar-day.in-range:hover:before{background:#e8e8e8}.calendar-day.multi-selected{background:#4caf50;color:#fff;font-weight:600;border-radius:6px}.calendar-day.multi-selected:hover{background:#45a049}.dual-calendar{display:flex;width:100%;border-left:1px solid #eee}.calendar-left,.calendar-right{flex:1;min-width:0;padding:0 12px 12px}.calendar-popup.has-ranges{display:flex;flex-direction:row}.calendar-popup.has-ranges .ranges{margin-bottom:0;border-bottom:none;padding:10px}.calendar-popup.has-ranges .dual-calendar,.calendar-popup.has-ranges .calendar-wrapper{flex:1}.calendar-right .header{justify-content:space-between}.calendar-right .header .month-year{text-align:center;flex:1}.timepicker-section{margin-top:12px;padding-top:12px;border-top:1px solid #eee}.timepicker-label{font-size:12px;font-weight:500;color:#000;margin-bottom:4px;letter-spacing:-.28px}.custom-time-picker{display:flex;flex-direction:column;gap:8px;align-items:start}.time-input-group{display:flex;align-items:center;justify-content:center;gap:8px;background:#f8f9fa;padding:12px;border-radius:8px;border:1px solid #e0e0e0}.time-control{display:flex;flex-direction:column;align-items:center}.time-btn{background:#fff;border:1px solid #ddd;width:28px;height:20px;cursor:pointer;font-size:10px;color:#666;border-radius:4px;transition:all .2s;display:flex;align-items:center;justify-content:center;padding:0;line-height:1}.time-btn:hover{background:#e4e4e4;color:#fff;border-color:#e4e4e4}.time-btn.up{border-bottom-left-radius:0;border-bottom-right-radius:0;border-bottom:none}.time-btn.down{border-top-left-radius:0;border-top-right-radius:0;border-top:none}.time-input{width:40px;height:32px;text-align:center;border:1px solid #ddd;border-radius:4px;font-size:16px;font-weight:600;background:#fff;color:#333}.time-separator{font-size:18px;font-weight:600;color:#666;margin:0 2px}.ampm-control{display:flex;flex-direction:column;gap:4px;margin-left:8px}.ampm-btn{padding:6px 12px;border:1px solid #ddd;background:#fff;border-radius:4px;cursor:pointer;font-size:12px;font-weight:600;color:#666;transition:all .2s;min-width:45px}.ampm-btn:hover{background:#f0f0f0}.ampm-btn.active{background:#000;color:#fff;border-color:#000}.html5-time-input{margin-top:8px;padding:8px;border:1px solid #ddd;border-radius:6px;font-size:14px;width:100%;max-width:120px}.footer{padding:12px;display:flex;justify-content:flex-end;gap:8px;border-top:1px solid #eee}.btn-cancel,.btn-apply{padding:8px 16px;border:none;border-radius:4px;font-size:14px;font-weight:500;cursor:pointer;transition:all .2s;min-width:80px}.btn-cancel{background:#fff;color:#666;border:1px solid #ddd}.btn-apply{background:#000;color:#fff}.btn-apply:active{transform:translateY(0)}@media (max-width: 768px){.calendar-popup{width:100%;max-width:320px}.calendar-popup.dual-calendar-mode{width:100%;max-width:100%}.calendar-popup.has-ranges{flex-direction:column}.calendar-popup.has-ranges .ranges{border-right:none;border-bottom:1px solid #eee;padding-right:0;margin-right:0;padding-bottom:16px;margin-bottom:16px}.dual-calendar{flex-direction:column}.time-input-group{flex-wrap:wrap;justify-content:center}}.ranges::-webkit-scrollbar{width:6px}.ranges::-webkit-scrollbar-track{background:#f1f1f1;border-radius:3px}.ranges::-webkit-scrollbar-thumb{background:#888;border-radius:3px}.ranges::-webkit-scrollbar-thumb:hover{background:#555}.w-100{width:100%}.flex-grow-1{flex-grow:1}.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:.5px solid #000;outline-offset:.5px}\n"] }]
|
|
2300
2667
|
}], ctorParameters: () => [{ type: BkCalendarManagerService }], propDecorators: { enableTimepicker: [{
|
|
2301
2668
|
type: Input
|
|
2302
2669
|
}], autoApply: [{
|
|
@@ -2319,6 +2686,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
2319
2686
|
type: Input
|
|
2320
2687
|
}], position: [{
|
|
2321
2688
|
type: Input
|
|
2689
|
+
}], popupPosition: [{
|
|
2690
|
+
type: Input
|
|
2322
2691
|
}], drop: [{
|
|
2323
2692
|
type: Input
|
|
2324
2693
|
}], dualCalendar: [{
|
|
@@ -2333,6 +2702,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
2333
2702
|
type: Input
|
|
2334
2703
|
}], customRanges: [{
|
|
2335
2704
|
type: Input
|
|
2705
|
+
}], weekDayLabels: [{
|
|
2706
|
+
type: Input
|
|
2336
2707
|
}], multiDateSelection: [{
|
|
2337
2708
|
type: Input
|
|
2338
2709
|
}], maxDate: [{
|
|
@@ -2358,6 +2729,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
2358
2729
|
}], inputWrapper: [{
|
|
2359
2730
|
type: ViewChild,
|
|
2360
2731
|
args: ['inputWrapper']
|
|
2732
|
+
}], calendarPopupRef: [{
|
|
2733
|
+
type: ViewChild,
|
|
2734
|
+
args: ['calendarPopup']
|
|
2361
2735
|
}], opened: [{
|
|
2362
2736
|
type: Output
|
|
2363
2737
|
}], closed: [{
|
|
@@ -2370,6 +2744,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
2370
2744
|
type: Input
|
|
2371
2745
|
}], required: [{
|
|
2372
2746
|
type: Input
|
|
2747
|
+
}], rangeOrder: [{
|
|
2748
|
+
type: Input
|
|
2373
2749
|
}], onClickOutside: [{
|
|
2374
2750
|
type: HostListener,
|
|
2375
2751
|
args: ['document:click', ['$event']]
|
|
@@ -2684,7 +3060,7 @@ class BkScheduledDatePicker {
|
|
|
2684
3060
|
this.emitScheduled();
|
|
2685
3061
|
}
|
|
2686
3062
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkScheduledDatePicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2687
|
-
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", "drop", "dualCalendar", "showRanges", "timeFormat", "clearableTime", "enableSeconds", "customRanges", "multiDateSelection", "maxDate", "minDate", "placeholder", "opens", "inline", "appendToBody", "isDisplayCrossIcon", "hasError", "errorMessage", "showCancelApply", "selectedValue", "displayFormat", "required"], 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"] }] });
|
|
3063
|
+
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", "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"] }] });
|
|
2688
3064
|
}
|
|
2689
3065
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkScheduledDatePicker, decorators: [{
|
|
2690
3066
|
type: Component,
|