@dcsl/flex-ui 0.0.31 → 0.0.32

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.
@@ -5,11 +5,9 @@ import { CommonModule } from '@angular/common';
5
5
  import * as i2 from '@angular/forms';
6
6
  import { FormsModule } from '@angular/forms';
7
7
  import dayjs from 'dayjs';
8
- import calendarSystems from '@calidy/dayjs-calendarsystems';
9
- import PersianCalendarSystem from '@calidy/dayjs-calendarsystems/calendarSystems/PersianCalendarSystem';
10
- import HijriCalendarSystem from '@calidy/dayjs-calendarsystems/calendarSystems/HijriCalendarSystem';
11
8
  import customParseFormat from 'dayjs/plugin/customParseFormat';
12
9
  import utc from 'dayjs/plugin/utc';
10
+ import { hijriToGregorian, gregorianToHijri } from '@tabby_ai/hijri-converter';
13
11
  import { autoUpdate, computePosition, offset, flip, shift } from '@floating-ui/dom';
14
12
 
15
13
  class FlexPanelComponent {
@@ -669,67 +667,64 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImpor
669
667
  }] } });
670
668
 
671
669
  dayjs.extend(utc);
672
- // Extend Day.js with calendar systems support
673
- dayjs.extend(calendarSystems);
674
670
  dayjs.extend(customParseFormat);
675
- // Register the Persian calendar
676
- dayjs.registerCalendarSystem('persian', new PersianCalendarSystem());
677
- dayjs.registerCalendarSystem('islamic', new HijriCalendarSystem());
678
671
  class DateServiceService {
679
672
  constructor() {
680
673
  }
674
+ //month will start from 1
675
+ convertToGregorian(date) {
676
+ var grego = hijriToGregorian({
677
+ day: date.day,
678
+ month: date.month,
679
+ year: date.year
680
+ });
681
+ return {
682
+ day: grego.day,
683
+ month: grego.month,
684
+ year: grego.year
685
+ };
686
+ }
687
+ //month will start from 1
688
+ convertToHijri(date) {
689
+ var hijri = gregorianToHijri({
690
+ day: date.day,
691
+ month: date.month,
692
+ year: date.year
693
+ });
694
+ return {
695
+ day: hijri.day,
696
+ month: hijri.month,
697
+ year: hijri.year
698
+ };
699
+ }
681
700
  parse(dateString, calendar, format) {
682
701
  //Step 1: User will input gregorian or islamic(hijri) date. for this we will use customParseFormat
683
702
  //in the control we will specify the format using binding.
684
703
  var parsedUtcDate = dayjs.utc(dateString, format, true);
685
- console.log("Parsed string provided by User as Utc Iso: ", parsedUtcDate.toISOString());
686
704
  if (!parsedUtcDate.isValid()) {
687
- console.log("entered date string is invalid: ", dateString);
688
705
  return null;
689
706
  }
690
- //we are writing this to parse the date , month, year only.
691
- //then based on the calender type we will decide.
692
- //but by default system will take gregorian
693
- // month() function return 0-11 months but when it parse 1 then it makes it 0
694
- const customDate = dayjs.fromCalendarSystem(calendar, parsedUtcDate.year(), parsedUtcDate.month() + 1, parsedUtcDate.date());
695
- //here we are assuming the control want to handle islamic calender date, we will take it dynmically.
696
- console.log("Prased Date in Gregorian String as per format ['DD-MM-YYYY']:", customDate.format('DD-MM-YYYY'));
697
- // console.log("Prased Date in Gregorian String as per format ['DD-MM-YYYY']:", customDate.toISOString());
698
- //here it will show gregorian calender, because even if we parse using islamic calender, it will convert the date
699
- //and keep it to gregorian
700
- //to show islamic date, we have to tell the dayjs to use islamic calender
701
- var customDateString = customDate.format('YYYY-MM-DD');
702
- const d2 = dayjs.utc(customDateString);
703
- // console.log("utc", d2.toISOString());
704
- return d2.toDate();
705
- }
706
- // parse2(dateString: string, calendar: FlexCalendarSystem, format: string): Date | null {
707
- // const d = dayjs.utc(dateString, format, true);
708
- // if (!d.isValid()) return null;
709
- // let gYear = d.year();
710
- // let gMonth = d.month();
711
- // let gDay = d.date();
712
- // if (calendar === "islamic") {
713
- // const hijri = { hijriYear: d.year(), hijriMonth: d.month(), hijriDay: d.date() };
714
- // const greg = hijriToGregorian({
715
- // year: hijri.hijriYear,
716
- // month: hijri.hijriMonth,
717
- // day: hijri.hijriDay as number
718
- // });
719
- // gYear = greg.year;
720
- // gMonth = greg.month;
721
- // gDay = greg.day;
722
- // }
723
- // // construct a pure UTC date
724
- // const fixed = dayjs.utc(new Date(gYear, gMonth, gDay as number));
725
- // return fixed.toDate();
726
- // }
707
+ if (calendar == "islamic") {
708
+ var grego = hijriToGregorian({
709
+ day: parsedUtcDate.date(),
710
+ month: parsedUtcDate.month() + 1,
711
+ year: parsedUtcDate.year()
712
+ });
713
+ parsedUtcDate = dayjs.utc(`${grego.year}-${grego.month}-${grego.day}`);
714
+ }
715
+ return parsedUtcDate.toDate();
716
+ }
727
717
  format(date, calendar, format) {
728
- // const d = dayjs.utc(date.getFullYear(), date.getMonth(), date.getDate() as number);
729
- var c = dayjs.fromCalendarSystem("gregory", date.getFullYear(), date.getMonth() + 1, date.getDate());
730
- if (calendar == "islamic")
731
- c = c.add(1, "day");
732
- return c.toCalendarSystem(calendar).format(format);
718
+ var day = dayjs.utc(`${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`);
719
+ if (calendar == "islamic") {
720
+ var hijri = gregorianToHijri({
721
+ day: date.getDate(),
722
+ month: date.getMonth() + 1,
723
+ year: date.getFullYear()
724
+ });
725
+ day = dayjs.utc(`${hijri.year}-${hijri.month}-${hijri.day}`);
726
+ }
727
+ return day.format(format);
733
728
  }
734
729
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: DateServiceService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
735
730
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: DateServiceService, providedIn: 'root' });
@@ -912,6 +907,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImpor
912
907
  args: ['window:resize']
913
908
  }] } });
914
909
 
910
+ const MinGregorianDate = new Date(1937, 0, 1).getTime();
911
+ const MaxGregorianDate = new Date(2076, 11, 31).getTime();
915
912
  // ✅ Intl formatters
916
913
  const hijriFmt = new Intl.DateTimeFormat('en-u-ca-islamic-umalqura-nu-latn', {
917
914
  day: 'numeric',
@@ -939,12 +936,17 @@ const gregMonthNamesAr = [
939
936
  const weekDaysEn = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
940
937
  const weekDaysAr = ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'];
941
938
  function hijriFromGregorian(g) {
942
- const parts = hijriFmt.formatToParts(g);
943
- const map = {};
944
- for (const p of parts)
945
- map[p.type] = p.value;
946
- const n = (k) => parseInt(map[k] ?? '0', 10);
947
- return { hy: n('year'), hm: n('month'), hd: n('day') };
939
+ // const parts = hijriFmt.formatToParts(g);
940
+ // const map: Record<string, string> = {};
941
+ // for (const p of parts) map[p.type] = p.value;
942
+ // const n = (k: string) => parseInt(map[k] ?? '0', 10);
943
+ // return { hy: n('year'), hm: n('month'), hd: n('day') };
944
+ var hijri = gregorianToHijri({
945
+ day: g.getDate(),
946
+ month: g.getMonth() + 1,
947
+ year: g.getFullYear()
948
+ });
949
+ return { hy: hijri.year, hm: hijri.month, hd: hijri.day };
948
950
  }
949
951
  function compareHijri(a, b) {
950
952
  if (a.hy !== b.hy)
@@ -954,43 +956,60 @@ function compareHijri(a, b) {
954
956
  return a.hd - b.hd;
955
957
  }
956
958
  function findGregorianForHijri(target) {
957
- let lo = new Date(1937, 0, 1).getTime();
958
- let hi = new Date(2076, 11, 31).getTime();
959
- const dayMs = 86400000;
960
- while (lo <= hi) {
961
- const mid = Math.floor((lo + hi) / 2);
962
- const h = hijriFromGregorian(new Date(mid));
963
- compareHijri(h, target) < 0 ? (lo = mid + dayMs) : (hi = mid - dayMs);
964
- }
965
- let d = new Date(lo);
966
- while (true) {
967
- const h = hijriFromGregorian(d);
968
- const cmp = compareHijri(h, target);
969
- if (cmp === 0)
970
- return d;
971
- if (cmp > 0)
972
- throw new Error('Hijri date out of supported range');
973
- d = new Date(d.getTime() + dayMs);
974
- }
959
+ console.log(target);
960
+ console.log("findGregorianForHijri => ", target.hm, "M");
961
+ console.log(typeof target.hm);
962
+ console.log(typeof target.hy);
963
+ var month = parseInt(target.hm.toString());
964
+ //var year = parseInt(target.hy.toString());
965
+ // console.log(month);
966
+ var grego = hijriToGregorian({
967
+ day: 1,
968
+ month: month,
969
+ year: target.hy
970
+ });
971
+ console.log("findGregorianForHijri Greg => ", grego.month, "M");
972
+ return new Date(grego.year, grego.month - 1, grego.day);
973
+ // let lo = new Date(1937, 0, 1).getTime();
974
+ // let hi = new Date(2076, 11, 31).getTime();
975
+ // const dayMs = 86400000;
976
+ // while (lo <= hi) {
977
+ // const mid = Math.floor((lo + hi) / 2);
978
+ // const h = hijriFromGregorian(new Date(mid));
979
+ // compareHijri(h, target) < 0 ? (lo = mid + dayMs) : (hi = mid - dayMs);
980
+ // }
981
+ // let d = new Date(lo);
982
+ // while (true) {
983
+ // const h = hijriFromGregorian(d);
984
+ // const cmp = compareHijri(h, target);
985
+ // if (cmp === 0) {
986
+ // console.log(d);
987
+ // return d;
988
+ // }
989
+ // if (cmp > 0) throw new Error('Hijri date out of supported range');
990
+ // d = new Date(d.getTime() + dayMs);
991
+ // }
975
992
  }
976
993
  function stripTime(d) {
977
- return new Date(d.getFullYear(), d.getMonth(), d.getDate());
994
+ //return new Date(d.getFullYear(), d.getMonth(), d.getDate());
995
+ return d;
978
996
  }
997
+
979
998
  class FlexDualCalendarComponent {
980
999
  /** Two-way bound selected date (Gregorian) */
981
- value;
982
- valueChange = new EventEmitter();
1000
+ value = model(new Date(), ...(ngDevMode ? [{ debugName: "value" }] : []));
1001
+ // @Output() valueChange = new EventEmitter<Date>();
983
1002
  /** Optional min/max (Gregorian) */
984
1003
  minDate;
985
1004
  maxDate;
986
1005
  /** Month/weekday language */
987
1006
  monthLang = 'en';
988
1007
  /** Start mode, default Hijri */
989
- startMode = 'gregory';
1008
+ //@Input() startMode: FlexCalendarSystem = 'gregory';
990
1009
  // This will be injected by FloatingUiService
991
1010
  close;
992
1011
  /** Current mode (hijri | gregory) */
993
- mode = signal('gregory', ...(ngDevMode ? [{ debugName: "mode" }] : []));
1012
+ mode = model('gregory', ...(ngDevMode ? [{ debugName: "mode" }] : []));
994
1013
  /** Hijri view state */
995
1014
  hy = signal(0, ...(ngDevMode ? [{ debugName: "hy" }] : []));
996
1015
  hm = signal(0, ...(ngDevMode ? [{ debugName: "hm" }] : []));
@@ -1016,6 +1035,7 @@ class FlexDualCalendarComponent {
1016
1035
  ? this.hijriMonths[this.selectedMonth - 1]
1017
1036
  : this.gregMonths[this.selectedMonth - 1];
1018
1037
  }
1038
+ ignoreDropdownSync = false;
1019
1039
  constructor() {
1020
1040
  const today = new Date();
1021
1041
  const h = hijriFromGregorian(today);
@@ -1024,7 +1044,7 @@ class FlexDualCalendarComponent {
1024
1044
  this.gy.set(today.getFullYear());
1025
1045
  this.gm.set(today.getMonth() + 1);
1026
1046
  // initialize selectors with start mode
1027
- this.mode.set(this.startMode);
1047
+ //this.mode.set(this.startMode);
1028
1048
  if (this.mode() === 'islamic') {
1029
1049
  this.selectedYear = this.hy();
1030
1050
  this.selectedMonth = this.hm();
@@ -1033,14 +1053,13 @@ class FlexDualCalendarComponent {
1033
1053
  this.selectedYear = this.gy();
1034
1054
  this.selectedMonth = this.gm();
1035
1055
  }
1036
- }
1037
- ngOnInit() {
1038
- this.buildYearRange();
1039
- }
1040
- ngOnChanges(changes) {
1041
- // If value changed from outside, update both calendars
1042
- if (changes['value'] && this.value instanceof Date) {
1043
- const g = stripTime(this.value);
1056
+ effect((() => {
1057
+ if (this.ignoreDropdownSync)
1058
+ return;
1059
+ const v = this.value();
1060
+ if (!v)
1061
+ return;
1062
+ const g = stripTime(this.value());
1044
1063
  const h = hijriFromGregorian(g);
1045
1064
  this.gy.set(g.getFullYear());
1046
1065
  this.gm.set(g.getMonth() + 1);
@@ -1055,7 +1074,29 @@ class FlexDualCalendarComponent {
1055
1074
  this.selectedYear = this.gy();
1056
1075
  this.selectedMonth = this.gm();
1057
1076
  }
1058
- }
1077
+ }));
1078
+ }
1079
+ ngOnInit() {
1080
+ this.buildYearRange();
1081
+ }
1082
+ ngOnChanges(changes) {
1083
+ // If value changed from outside, update both calendars
1084
+ // if (changes['value'] && this.value() instanceof Date) {
1085
+ // const g = stripTime(this.value());
1086
+ // const h = hijriFromGregorian(g);
1087
+ // this.gy.set(g.getFullYear());
1088
+ // this.gm.set(g.getMonth() + 1);
1089
+ // this.hy.set(h.hy);
1090
+ // this.hm.set(h.hm);
1091
+ // // Update dropdowns based on current mode
1092
+ // if (this.mode() === 'islamic') {
1093
+ // this.selectedYear = this.hy();
1094
+ // this.selectedMonth = this.hm();
1095
+ // } else {
1096
+ // this.selectedYear = this.gy();
1097
+ // this.selectedMonth = this.gm();
1098
+ // }
1099
+ // }
1059
1100
  // Rebuild year range if min/max changed
1060
1101
  if (changes['minDate'] || changes['maxDate'] || changes['value']) {
1061
1102
  this.buildYearRange();
@@ -1080,7 +1121,7 @@ class FlexDualCalendarComponent {
1080
1121
  }
1081
1122
  // 🔁 Mode switch (SYNCED view — keep same instant)
1082
1123
  switchMode(value) {
1083
- const pivot = this.value ?? this.firstOfMonth(); // use selected date or current view start
1124
+ const pivot = this.value(); // use selected date or current view start
1084
1125
  if (value === 'gregory') {
1085
1126
  // To Gregorian mode
1086
1127
  const g = stripTime(pivot);
@@ -1103,6 +1144,7 @@ class FlexDualCalendarComponent {
1103
1144
  }
1104
1145
  // called when dropdowns change
1105
1146
  onMonthYearChange() {
1147
+ this.ignoreDropdownSync = true;
1106
1148
  if (this.mode() === 'islamic') {
1107
1149
  this.hy.set(this.selectedYear);
1108
1150
  this.hm.set(this.selectedMonth);
@@ -1111,10 +1153,12 @@ class FlexDualCalendarComponent {
1111
1153
  this.gy.set(this.selectedYear);
1112
1154
  this.gm.set(this.selectedMonth);
1113
1155
  }
1156
+ setTimeout(() => (this.ignoreDropdownSync = false));
1114
1157
  }
1115
1158
  // Start of visible month (Gregorian date)
1116
1159
  firstOfMonth() {
1117
1160
  if (this.mode() === 'islamic') {
1161
+ //console.log("firstOfMonth function: ", this.hm());
1118
1162
  return findGregorianForHijri({ hy: this.hy(), hm: this.hm(), hd: 1 });
1119
1163
  }
1120
1164
  return new Date(this.gy(), this.gm() - 1, 1);
@@ -1131,6 +1175,7 @@ class FlexDualCalendarComponent {
1131
1175
  const g = new Date(start);
1132
1176
  g.setDate(start.getDate() + i);
1133
1177
  const h = hijriFromGregorian(g);
1178
+ //console.log("month:", h.hm);
1134
1179
  let disabled = false;
1135
1180
  if (this.minDate && g < stripTime(this.minDate))
1136
1181
  disabled = true;
@@ -1146,6 +1191,7 @@ class FlexDualCalendarComponent {
1146
1191
  prevMonth() {
1147
1192
  if (!this.canPrev())
1148
1193
  return;
1194
+ this.ignoreDropdownSync = true;
1149
1195
  if (this.mode() === 'islamic') {
1150
1196
  let m = this.hm(), y = this.hy();
1151
1197
  if (--m < 1) {
@@ -1168,10 +1214,12 @@ class FlexDualCalendarComponent {
1168
1214
  this.selectedYear = y;
1169
1215
  this.selectedMonth = m;
1170
1216
  }
1217
+ setTimeout(() => (this.ignoreDropdownSync = false));
1171
1218
  }
1172
1219
  nextMonth() {
1173
1220
  if (!this.canNext())
1174
1221
  return;
1222
+ this.ignoreDropdownSync = true;
1175
1223
  if (this.mode() === 'islamic') {
1176
1224
  let m = this.hm(), y = this.hy();
1177
1225
  if (++m > 12) {
@@ -1194,6 +1242,7 @@ class FlexDualCalendarComponent {
1194
1242
  this.selectedYear = y;
1195
1243
  this.selectedMonth = m;
1196
1244
  }
1245
+ setTimeout(() => (this.ignoreDropdownSync = false));
1197
1246
  }
1198
1247
  canPrev() {
1199
1248
  if (!this.minDate)
@@ -1221,22 +1270,27 @@ class FlexDualCalendarComponent {
1221
1270
  && g.getDate() === t.getDate();
1222
1271
  }
1223
1272
  isSelected(g) {
1224
- return !!this.value &&
1225
- g.getFullYear() === this.value.getFullYear() &&
1226
- g.getMonth() === this.value.getMonth() &&
1227
- g.getDate() === this.value.getDate();
1273
+ const v = this.value();
1274
+ if (!v)
1275
+ return false;
1276
+ return !!this.value() &&
1277
+ g.getFullYear() === v.getFullYear() &&
1278
+ g.getMonth() === v.getMonth() &&
1279
+ g.getDate() === v.getDate();
1228
1280
  }
1229
1281
  select(c) {
1230
1282
  if (c.disabled)
1231
1283
  return;
1232
- this.value = stripTime(c.g);
1233
- this.valueChange.emit(this.value);
1284
+ var g = c.g;
1285
+ var st = stripTime(c.g);
1286
+ this.value.set(st);
1287
+ //this.valueChange.emit(this.value);
1234
1288
  // keep both views in sync after selection
1235
- const h = hijriFromGregorian(this.value);
1289
+ const h = hijriFromGregorian(this.value());
1236
1290
  this.hy.set(h.hy);
1237
1291
  this.hm.set(h.hm);
1238
- this.gy.set(this.value.getFullYear());
1239
- this.gm.set(this.value.getMonth() + 1);
1292
+ this.gy.set(this.value().getFullYear());
1293
+ this.gm.set(this.value().getMonth() + 1);
1240
1294
  if (this.mode() === 'islamic') {
1241
1295
  this.selectedYear = this.hy();
1242
1296
  this.selectedMonth = this.hm();
@@ -1245,26 +1299,20 @@ class FlexDualCalendarComponent {
1245
1299
  this.selectedYear = this.gy();
1246
1300
  this.selectedMonth = this.gm();
1247
1301
  }
1248
- this.close(this.value);
1302
+ this.close(this.value());
1249
1303
  }
1250
1304
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: FlexDualCalendarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1251
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: FlexDualCalendarComponent, isStandalone: true, selector: "flex-dual-calendar", inputs: { value: "value", minDate: "minDate", maxDate: "maxDate", monthLang: "monthLang", startMode: "startMode" }, outputs: { valueChange: "valueChange" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"card\">\r\n <div class=\"card-header p-1\">\r\n <div class=\"d-flex gap-1\">\r\n\r\n <div>\r\n <button class=\"btn btn-sm w-100 \" (click)=\"prevMonth()\" [disabled]=\"!canPrev()\"><i\r\n class=\"bi bi-caret-left-fill\"></i></button>\r\n </div>\r\n <div class=\"flex-grow-1\">\r\n <select class=\"form-select form-select-sm\" [(ngModel)]=\"selectedMonth\" (change)=\"onMonthYearChange()\">\r\n @if (mode() === 'islamic') {\r\n @for (m of hijriMonths; track $index) {\r\n <option [value]=\"$index + 1\">{{ hijriMonths[$index] }}-{{$index + 1}}</option>\r\n }\r\n } @else {\r\n @for (m of gregMonths; track $index) {\r\n <option [value]=\"$index + 1\">{{$index + 1}}-{{ gregMonths[$index] }}</option>\r\n }\r\n }\r\n </select>\r\n </div>\r\n <div> <select class=\"form-select form-select-sm\" [(ngModel)]=\"selectedYear\" (change)=\"onMonthYearChange()\">\r\n @for (y of yearRange; track y) {\r\n <option [value]=\"y\">{{ y }}</option>\r\n }\r\n </select></div>\r\n <div>\r\n <button class=\"btn btn-sm w-100 \" (click)=\"nextMonth()\" [disabled]=\"!canNext()\"><i\r\n class=\"bi bi-caret-right-fill\"></i></button>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"card-body p-0\">\r\n <!-- Weekday labels -->\r\n <div class=\"grid\">\r\n @for (w of weekDays; track $index) {\r\n <div class=\"col fw-bold border pb-1\">{{ w }}</div>\r\n }\r\n </div>\r\n\r\n <!-- Calendar cells -->\r\n <div class=\"grid\">\r\n @for (c of cells(); track $index) {\r\n <div class=\"cell\">\r\n <button class=\"btn w-100\" [class.muted]=\"!c.inCurrentMonth\" [class.today]=\"isToday(c.g)\"\r\n [class.selected]=\"isSelected(c.g)\" [disabled]=\"c.disabled\" (click)=\"select(c)\">\r\n <!-- show Hijri day in Hijri mode, otherwise Gregorian -->\r\n @if(mode() === 'islamic'){\r\n {{ c.h.hd }}\r\n }\r\n @else{\r\n {{ c.g.getDate() }}\r\n }\r\n </button>\r\n </div>\r\n }\r\n\r\n </div>\r\n </div>\r\n <div class=\"card-footer px-0 py-1\">\r\n <div class=\"d-flex justify-content-center\">\r\n <div class=\"btn-group\" role=\"group\" aria-label=\"Basic example\">\r\n <button class=\"btn btn-sm btn-outline-secondary\" type=\"button\" (click)=\"switchMode('gregory')\">\r\n Gregorian\r\n </button>\r\n <button class=\"btn btn-sm btn-outline-secondary\" type=\"button\" (click)=\"switchMode('islamic')\">\r\n \u0647\u062C\u0631\u064A\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n</div>", styles: [".grid{display:grid;grid-template-columns:repeat(7,1fr)}.cell{border:1px solid #ddd}.cell.muted{opacity:.5}.cell.today{outline:2px solid #0d6efd}.cell.selected{background-color:#0d6efd;color:#fff}.cell:disabled{background-color:#f8f9fa;color:#aaa;cursor:not-allowed}.col{text-align:center}.btn{font-size:90%;--bs-btn-padding-x: .5rem;--bs-btn-padding-y: .25rem}.btn:hover{background-color:azure}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
1305
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: FlexDualCalendarComponent, isStandalone: true, selector: "flex-dual-calendar", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: false, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: false, isRequired: false, transformFunction: null }, monthLang: { classPropertyName: "monthLang", publicName: "monthLang", isSignal: false, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", mode: "modeChange" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"card\">\r\n <div class=\"card-header p-1\">\r\n <div class=\"d-flex gap-1\">\r\n\r\n <div>\r\n <button class=\"btn btn-sm w-100 \" (click)=\"prevMonth()\" [disabled]=\"!canPrev()\"><i\r\n class=\"bi bi-caret-left-fill\"></i></button>\r\n </div>\r\n <div class=\"flex-grow-1\">\r\n <select class=\"form-select form-select-sm\" [(ngModel)]=\"selectedMonth\"\r\n (ngModelChange)=\"onMonthYearChange()\">\r\n @if (mode() === 'islamic') {\r\n @for (m of hijriMonths; track $index) {\r\n <option [value]=\"$index + 1\">{{ hijriMonths[$index] }}-{{$index + 1}}</option>\r\n }\r\n } @else {\r\n @for (m of gregMonths; track $index) {\r\n <option [value]=\"$index + 1\">{{$index + 1}}-{{ gregMonths[$index] }}</option>\r\n }\r\n }\r\n </select>\r\n </div>\r\n <div> <select class=\"form-select form-select-sm\" [(ngModel)]=\"selectedYear\"\r\n (ngModelChange)=\"onMonthYearChange()\">\r\n @for (y of yearRange; track y) {\r\n <option [value]=\"y\">{{ y }}</option>\r\n }\r\n </select></div>\r\n <div>\r\n <button class=\"btn btn-sm w-100 \" (click)=\"nextMonth()\" [disabled]=\"!canNext()\"><i\r\n class=\"bi bi-caret-right-fill\"></i></button>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"card-body p-0\">\r\n <!-- Weekday labels -->\r\n <div class=\"grid\">\r\n @for (w of weekDays; track $index) {\r\n <div class=\"col fw-bold border pb-1\">{{ w }}</div>\r\n }\r\n </div>\r\n\r\n <!-- Calendar cells -->\r\n <div class=\"grid\">\r\n @for (c of cells(); track $index) {\r\n <div class=\"cell\">\r\n <button class=\"btn w-100 rounded-0\" [class.muted]=\"!c.inCurrentMonth\" [class.fw-bold]=\"isToday(c.g)\"\r\n [class.btn-info]=\"isSelected(c.g)\" [disabled]=\"c.disabled\" (click)=\"select(c)\">\r\n <!-- show Hijri day in Hijri mode, otherwise Gregorian -->\r\n @if(mode() === 'islamic'){\r\n {{ c.h.hd }}\r\n }\r\n @else{\r\n {{ c.g.getDate() }}\r\n }\r\n </button>\r\n </div>\r\n }\r\n\r\n </div>\r\n </div>\r\n <div class=\"card-footer px-0 py-1\">\r\n <div class=\"d-flex justify-content-center\">\r\n <div class=\"btn-group\" role=\"group\" aria-label=\"Basic example\">\r\n <button class=\"btn btn-sm btn-outline-secondary\" [class.btn-info]=\"mode() == 'gregory'\" type=\"button\"\r\n (click)=\"switchMode('gregory')\">\r\n Gregorian\r\n </button>\r\n <button class=\"btn btn-sm btn-outline-secondary\" [class.btn-info]=\"mode() == 'islamic'\" type=\"button\"\r\n (click)=\"switchMode('islamic')\">\r\n \u0647\u062C\u0631\u064A\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n</div>", styles: [".grid{display:grid;grid-template-columns:repeat(7,1fr)}.cell{border:1px solid #ddd}.cell>.muted{opacity:.5;color:#aaa}.cell>.today{background-color:#647998}.cell>.selected{background-color:#0d6efd;color:#fff}.cell>.btn:disabled{background-color:#f8f9fa;color:#aaa;cursor:not-allowed}.col{text-align:center}.btn{font-size:90%;--bs-btn-padding-x: .5rem;--bs-btn-padding-y: .25rem}.btn:hover{background-color:azure}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
1252
1306
  }
1253
1307
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: FlexDualCalendarComponent, decorators: [{
1254
1308
  type: Component,
1255
- args: [{ selector: 'flex-dual-calendar', standalone: true, imports: [CommonModule, FormsModule], template: "<div class=\"card\">\r\n <div class=\"card-header p-1\">\r\n <div class=\"d-flex gap-1\">\r\n\r\n <div>\r\n <button class=\"btn btn-sm w-100 \" (click)=\"prevMonth()\" [disabled]=\"!canPrev()\"><i\r\n class=\"bi bi-caret-left-fill\"></i></button>\r\n </div>\r\n <div class=\"flex-grow-1\">\r\n <select class=\"form-select form-select-sm\" [(ngModel)]=\"selectedMonth\" (change)=\"onMonthYearChange()\">\r\n @if (mode() === 'islamic') {\r\n @for (m of hijriMonths; track $index) {\r\n <option [value]=\"$index + 1\">{{ hijriMonths[$index] }}-{{$index + 1}}</option>\r\n }\r\n } @else {\r\n @for (m of gregMonths; track $index) {\r\n <option [value]=\"$index + 1\">{{$index + 1}}-{{ gregMonths[$index] }}</option>\r\n }\r\n }\r\n </select>\r\n </div>\r\n <div> <select class=\"form-select form-select-sm\" [(ngModel)]=\"selectedYear\" (change)=\"onMonthYearChange()\">\r\n @for (y of yearRange; track y) {\r\n <option [value]=\"y\">{{ y }}</option>\r\n }\r\n </select></div>\r\n <div>\r\n <button class=\"btn btn-sm w-100 \" (click)=\"nextMonth()\" [disabled]=\"!canNext()\"><i\r\n class=\"bi bi-caret-right-fill\"></i></button>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"card-body p-0\">\r\n <!-- Weekday labels -->\r\n <div class=\"grid\">\r\n @for (w of weekDays; track $index) {\r\n <div class=\"col fw-bold border pb-1\">{{ w }}</div>\r\n }\r\n </div>\r\n\r\n <!-- Calendar cells -->\r\n <div class=\"grid\">\r\n @for (c of cells(); track $index) {\r\n <div class=\"cell\">\r\n <button class=\"btn w-100\" [class.muted]=\"!c.inCurrentMonth\" [class.today]=\"isToday(c.g)\"\r\n [class.selected]=\"isSelected(c.g)\" [disabled]=\"c.disabled\" (click)=\"select(c)\">\r\n <!-- show Hijri day in Hijri mode, otherwise Gregorian -->\r\n @if(mode() === 'islamic'){\r\n {{ c.h.hd }}\r\n }\r\n @else{\r\n {{ c.g.getDate() }}\r\n }\r\n </button>\r\n </div>\r\n }\r\n\r\n </div>\r\n </div>\r\n <div class=\"card-footer px-0 py-1\">\r\n <div class=\"d-flex justify-content-center\">\r\n <div class=\"btn-group\" role=\"group\" aria-label=\"Basic example\">\r\n <button class=\"btn btn-sm btn-outline-secondary\" type=\"button\" (click)=\"switchMode('gregory')\">\r\n Gregorian\r\n </button>\r\n <button class=\"btn btn-sm btn-outline-secondary\" type=\"button\" (click)=\"switchMode('islamic')\">\r\n \u0647\u062C\u0631\u064A\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n</div>", styles: [".grid{display:grid;grid-template-columns:repeat(7,1fr)}.cell{border:1px solid #ddd}.cell.muted{opacity:.5}.cell.today{outline:2px solid #0d6efd}.cell.selected{background-color:#0d6efd;color:#fff}.cell:disabled{background-color:#f8f9fa;color:#aaa;cursor:not-allowed}.col{text-align:center}.btn{font-size:90%;--bs-btn-padding-x: .5rem;--bs-btn-padding-y: .25rem}.btn:hover{background-color:azure}\n"] }]
1256
- }], ctorParameters: () => [], propDecorators: { value: [{
1257
- type: Input
1258
- }], valueChange: [{
1259
- type: Output
1260
- }], minDate: [{
1309
+ args: [{ selector: 'flex-dual-calendar', standalone: true, imports: [CommonModule, FormsModule], template: "<div class=\"card\">\r\n <div class=\"card-header p-1\">\r\n <div class=\"d-flex gap-1\">\r\n\r\n <div>\r\n <button class=\"btn btn-sm w-100 \" (click)=\"prevMonth()\" [disabled]=\"!canPrev()\"><i\r\n class=\"bi bi-caret-left-fill\"></i></button>\r\n </div>\r\n <div class=\"flex-grow-1\">\r\n <select class=\"form-select form-select-sm\" [(ngModel)]=\"selectedMonth\"\r\n (ngModelChange)=\"onMonthYearChange()\">\r\n @if (mode() === 'islamic') {\r\n @for (m of hijriMonths; track $index) {\r\n <option [value]=\"$index + 1\">{{ hijriMonths[$index] }}-{{$index + 1}}</option>\r\n }\r\n } @else {\r\n @for (m of gregMonths; track $index) {\r\n <option [value]=\"$index + 1\">{{$index + 1}}-{{ gregMonths[$index] }}</option>\r\n }\r\n }\r\n </select>\r\n </div>\r\n <div> <select class=\"form-select form-select-sm\" [(ngModel)]=\"selectedYear\"\r\n (ngModelChange)=\"onMonthYearChange()\">\r\n @for (y of yearRange; track y) {\r\n <option [value]=\"y\">{{ y }}</option>\r\n }\r\n </select></div>\r\n <div>\r\n <button class=\"btn btn-sm w-100 \" (click)=\"nextMonth()\" [disabled]=\"!canNext()\"><i\r\n class=\"bi bi-caret-right-fill\"></i></button>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"card-body p-0\">\r\n <!-- Weekday labels -->\r\n <div class=\"grid\">\r\n @for (w of weekDays; track $index) {\r\n <div class=\"col fw-bold border pb-1\">{{ w }}</div>\r\n }\r\n </div>\r\n\r\n <!-- Calendar cells -->\r\n <div class=\"grid\">\r\n @for (c of cells(); track $index) {\r\n <div class=\"cell\">\r\n <button class=\"btn w-100 rounded-0\" [class.muted]=\"!c.inCurrentMonth\" [class.fw-bold]=\"isToday(c.g)\"\r\n [class.btn-info]=\"isSelected(c.g)\" [disabled]=\"c.disabled\" (click)=\"select(c)\">\r\n <!-- show Hijri day in Hijri mode, otherwise Gregorian -->\r\n @if(mode() === 'islamic'){\r\n {{ c.h.hd }}\r\n }\r\n @else{\r\n {{ c.g.getDate() }}\r\n }\r\n </button>\r\n </div>\r\n }\r\n\r\n </div>\r\n </div>\r\n <div class=\"card-footer px-0 py-1\">\r\n <div class=\"d-flex justify-content-center\">\r\n <div class=\"btn-group\" role=\"group\" aria-label=\"Basic example\">\r\n <button class=\"btn btn-sm btn-outline-secondary\" [class.btn-info]=\"mode() == 'gregory'\" type=\"button\"\r\n (click)=\"switchMode('gregory')\">\r\n Gregorian\r\n </button>\r\n <button class=\"btn btn-sm btn-outline-secondary\" [class.btn-info]=\"mode() == 'islamic'\" type=\"button\"\r\n (click)=\"switchMode('islamic')\">\r\n \u0647\u062C\u0631\u064A\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n</div>", styles: [".grid{display:grid;grid-template-columns:repeat(7,1fr)}.cell{border:1px solid #ddd}.cell>.muted{opacity:.5;color:#aaa}.cell>.today{background-color:#647998}.cell>.selected{background-color:#0d6efd;color:#fff}.cell>.btn:disabled{background-color:#f8f9fa;color:#aaa;cursor:not-allowed}.col{text-align:center}.btn{font-size:90%;--bs-btn-padding-x: .5rem;--bs-btn-padding-y: .25rem}.btn:hover{background-color:azure}\n"] }]
1310
+ }], ctorParameters: () => [], propDecorators: { minDate: [{
1261
1311
  type: Input
1262
1312
  }], maxDate: [{
1263
1313
  type: Input
1264
1314
  }], monthLang: [{
1265
1315
  type: Input
1266
- }], startMode: [{
1267
- type: Input
1268
1316
  }] } });
1269
1317
 
1270
1318
  class DeviceDetectorService {
@@ -1404,7 +1452,6 @@ class FlexDualDatepickerComponent {
1404
1452
  calendarDropdown;
1405
1453
  inputDiv;
1406
1454
  modalDiv;
1407
- // @ViewChild("menu") popupDiv?: ElementRef;
1408
1455
  value = model(...(ngDevMode ? [undefined, { debugName: "value" }] : []));
1409
1456
  enabled = input(true, ...(ngDevMode ? [{ debugName: "enabled" }] : []));
1410
1457
  cssClass = input(...(ngDevMode ? [undefined, { debugName: "cssClass" }] : []));
@@ -1413,8 +1460,8 @@ class FlexDualDatepickerComponent {
1413
1460
  calendarSwitchPosition = input("title", ...(ngDevMode ? [{ debugName: "calendarSwitchPosition" }] : []));
1414
1461
  //selectedDate is needed to keep the current data for process
1415
1462
  selectedDate;
1416
- calendar = input("gregory", ...(ngDevMode ? [{ debugName: "calendar" }] : []));
1417
- _calendar = "gregory";
1463
+ calendar = model("gregory", ...(ngDevMode ? [{ debugName: "calendar" }] : []));
1464
+ // protected _calendar: FlexCalendarSystem = "gregory";
1418
1465
  inputDate = "";
1419
1466
  isMobile = false;
1420
1467
  constructor(dateService, deviceDetector, floating) {
@@ -1423,7 +1470,7 @@ class FlexDualDatepickerComponent {
1423
1470
  this.floating = floating;
1424
1471
  this.isMobile = deviceDetector.isMobile();
1425
1472
  effect(() => {
1426
- this._calendar = this.calendar();
1473
+ //this._calendar = this.calendar();
1427
1474
  if (!this.selectedDate)
1428
1475
  return;
1429
1476
  this.inputDate = this.formatDate(this.selectedDate);
@@ -1431,7 +1478,7 @@ class FlexDualDatepickerComponent {
1431
1478
  effect(() => {
1432
1479
  const iso = this.value();
1433
1480
  if (iso) {
1434
- const date = dayjs(iso);
1481
+ const date = dayjs.utc(iso);
1435
1482
  if (date.isValid()) {
1436
1483
  this.selectedDate = date.toDate();
1437
1484
  this.inputDate = this.formatDate(this.selectedDate);
@@ -1443,11 +1490,13 @@ class FlexDualDatepickerComponent {
1443
1490
  });
1444
1491
  }
1445
1492
  switchCalendar() {
1446
- if (this._calendar == "gregory") {
1447
- this._calendar = "islamic";
1493
+ if (this.calendar() == "gregory") {
1494
+ // this._calendar = "islamic";
1495
+ this.calendar.set("islamic");
1448
1496
  }
1449
1497
  else {
1450
- this._calendar = "gregory";
1498
+ //this._calendar = "gregory";
1499
+ this.calendar.set("gregory");
1451
1500
  }
1452
1501
  this.inputDate = this.formatDate(this.selectedDate);
1453
1502
  }
@@ -1476,7 +1525,7 @@ class FlexDualDatepickerComponent {
1476
1525
  this.value.set(d);
1477
1526
  }
1478
1527
  formatDate(date) {
1479
- return this.dateService.format(date, this._calendar, this.format());
1528
+ return this.dateService.format(date, this.calendar(), this.format());
1480
1529
  }
1481
1530
  parseInputDate(str) {
1482
1531
  /*if the user clear the text in input box then we must accept as the user
@@ -1490,7 +1539,7 @@ class FlexDualDatepickerComponent {
1490
1539
  so we will should not show null or empty value, instead we will
1491
1540
  return current date or last selected date
1492
1541
  */
1493
- var parsedDate = this.dateService.parse(str, this._calendar, this.format());
1542
+ var parsedDate = this.dateService.parse(str, this.calendar(), this.format());
1494
1543
  if (parsedDate)
1495
1544
  return parsedDate;
1496
1545
  //if parseDate is null this means user entered wrong date, in this case we will return
@@ -1513,10 +1562,12 @@ class FlexDualDatepickerComponent {
1513
1562
  async openCalendar() {
1514
1563
  const button = this.calendarButton?.nativeElement;
1515
1564
  const result = await this.floating.open(button, FlexDualCalendarComponent, {
1516
- placement: 'bottom-start',
1565
+ placement: 'bottom',
1517
1566
  inputs: {
1518
1567
  // You can pass any props here
1519
1568
  initialDate: this.selectedDate,
1569
+ mode: this.calendar,
1570
+ value: this.value
1520
1571
  },
1521
1572
  });
1522
1573
  if (result) {
@@ -1526,11 +1577,11 @@ class FlexDualDatepickerComponent {
1526
1577
  }
1527
1578
  isOpen = false;
1528
1579
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: FlexDualDatepickerComponent, deps: [{ token: DateServiceService }, { token: DeviceDetectorService }, { token: FloatingUiService }], target: i0.ɵɵFactoryTarget.Component });
1529
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: FlexDualDatepickerComponent, isStandalone: true, selector: "flex-dual-datepicker", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, enabled: { classPropertyName: "enabled", publicName: "enabled", isSignal: true, isRequired: false, transformFunction: null }, cssClass: { classPropertyName: "cssClass", publicName: "cssClass", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, calendarSwitchPosition: { classPropertyName: "calendarSwitchPosition", publicName: "calendarSwitchPosition", isSignal: true, isRequired: false, transformFunction: null }, calendar: { classPropertyName: "calendar", publicName: "calendar", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, viewQueries: [{ propertyName: "calendarButton", first: true, predicate: ["calendarButton"], descendants: true }, { propertyName: "calendarDropdown", first: true, predicate: ["calendarDropdown"], descendants: true }, { propertyName: "inputDiv", first: true, predicate: ["inputDiv"], descendants: true }, { propertyName: "modalDiv", first: true, predicate: ["modalDiv"], descendants: true }], ngImport: i0, template: "@if(calendarSwitchPosition() == 'title'){\r\n<div class=\"d-flex align-items-center gap-1\">\r\n <label>{{ title() }}</label>\r\n <button type=\"button\" class=\"btn btn-sm btn-light\" style=\"cursor: pointer; padding-bottom: 1px; padding-top: 1px;\"\r\n (click)=\"switchCalendar()\">\r\n @if(_calendar == 'gregory') {G}\r\n @else{H}\r\n </button>\r\n</div>\r\n\r\n}\r\n<div class=\"input-group flex-nowrap\" #inputDiv>\r\n @if(calendarSwitchPosition() == 'inline'){\r\n <span class=\"input-group-text\" style=\"cursor: pointer;\" (click)=\"switchCalendar()\"> @if(_calendar == 'gregory') {G}\r\n @else{H}</span>\r\n }\r\n <input type=\"text\" class=\"form-control\" [(ngModel)]=\"inputDate\" (blur)=\"onManualDateEntered()\"\r\n [disabled]=\"!enabled()\" [placeholder]=\"format()\" (keyup.enter)=\"onManualDateEntered()\">\r\n\r\n\r\n <!-- <button class=\"btn btn-outline-secondary\" type=\"button\" (click)=\"toggleCalendar()\" [disabled]=\"!enabled()\">\r\n <i class=\"bi bi-calendar3\"></i>\r\n </button> -->\r\n <button #calendarButton class=\"btn btn-outline-secondary\" (click)=\"openCalendar()\" [disabled]=\"!enabled()\">\r\n <i class=\"bi bi-calendar3\"></i>\r\n </button>\r\n\r\n</div>\r\n\r\n<!-- \r\n@if(isMobile && isOpen){\r\n<div class=\"modal modal-backdrop\" tabindex=\"-1\" role=\"dialog\" style=\"display: block;\" #modalDiv>\r\n <div class=\"modal-dialog modal-dialog-scrollable\" role=\"document\">\r\n <div class=\"modal-content\">\r\n <div class=\"modal-header\">\r\n <button type=\"button\" class=\"btn btn-danger close ms-auto btn-sm\" (click)=\"isOpen = false\">\r\n <i class=\"bi bi-x\"></i>\r\n </button>\r\n </div>\r\n <div class=\"modal-body\">\r\n <flex-dual-calendar (valueChange)=\"onDateSelectedFromCalender($event)\"\r\n [(value)]=\"selectedDate\"></flex-dual-calendar>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n} -->\r\n\r\n\r\n<!-- <div #calendarDropdown class=\"calendar-dropdown\">\r\n <flex-dual-calendar (valueChange)=\"onDateSelectedFromCalender($event)\"\r\n [(value)]=\"selectedDate\"></flex-dual-calendar>\r\n</div> -->", styles: [".dropdown-menu{--bs-dropdown-padding-y: 0}.card-body{padding:0!important}.dropdown-panel{position:fixed;border-radius:4px;z-index:9999}.calendar-dropdown{width:max-content;position:absolute;top:0;left:0;visibility:hidden;z-index:\"1080\",}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
1580
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: FlexDualDatepickerComponent, isStandalone: true, selector: "flex-dual-datepicker", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, enabled: { classPropertyName: "enabled", publicName: "enabled", isSignal: true, isRequired: false, transformFunction: null }, cssClass: { classPropertyName: "cssClass", publicName: "cssClass", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, calendarSwitchPosition: { classPropertyName: "calendarSwitchPosition", publicName: "calendarSwitchPosition", isSignal: true, isRequired: false, transformFunction: null }, calendar: { classPropertyName: "calendar", publicName: "calendar", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", calendar: "calendarChange" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, viewQueries: [{ propertyName: "calendarButton", first: true, predicate: ["calendarButton"], descendants: true }, { propertyName: "calendarDropdown", first: true, predicate: ["calendarDropdown"], descendants: true }, { propertyName: "inputDiv", first: true, predicate: ["inputDiv"], descendants: true }, { propertyName: "modalDiv", first: true, predicate: ["modalDiv"], descendants: true }], ngImport: i0, template: "@if(calendarSwitchPosition() == 'title'){\r\n<div class=\"d-flex align-items-center gap-1\">\r\n <label>{{ title() }}</label>\r\n <button type=\"button\" class=\"btn btn-sm btn-light\" style=\"cursor: pointer; padding-bottom: 1px; padding-top: 1px;\"\r\n (click)=\"switchCalendar()\">\r\n @if(calendar() == 'gregory') {G}\r\n @else{H}\r\n </button>\r\n</div>\r\n}\r\n<div class=\"input-group flex-nowrap\" #inputDiv>\r\n @if(calendarSwitchPosition() == 'inline'){\r\n <span class=\"input-group-text\" style=\"cursor: pointer;\" (click)=\"switchCalendar()\"> @if(calendar() == 'gregory') {G}\r\n @else{H}</span>\r\n }\r\n <input type=\"text\" class=\"form-control\" [(ngModel)]=\"inputDate\" (blur)=\"onManualDateEntered()\"\r\n [disabled]=\"!enabled()\" [placeholder]=\"format()\" (keyup.enter)=\"onManualDateEntered()\">\r\n <button #calendarButton class=\"btn btn-outline-secondary\" (click)=\"openCalendar()\" [disabled]=\"!enabled()\">\r\n <i class=\"bi bi-calendar3\"></i>\r\n </button>\r\n</div>", styles: [".dropdown-menu{--bs-dropdown-padding-y: 0}.card-body{padding:0!important}.dropdown-panel{position:fixed;border-radius:4px;z-index:9999}.calendar-dropdown{width:max-content;position:absolute;top:0;left:0;visibility:hidden;z-index:\"1080\",}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
1530
1581
  }
1531
1582
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: FlexDualDatepickerComponent, decorators: [{
1532
1583
  type: Component,
1533
- args: [{ selector: 'flex-dual-datepicker', imports: [CommonModule, FormsModule], template: "@if(calendarSwitchPosition() == 'title'){\r\n<div class=\"d-flex align-items-center gap-1\">\r\n <label>{{ title() }}</label>\r\n <button type=\"button\" class=\"btn btn-sm btn-light\" style=\"cursor: pointer; padding-bottom: 1px; padding-top: 1px;\"\r\n (click)=\"switchCalendar()\">\r\n @if(_calendar == 'gregory') {G}\r\n @else{H}\r\n </button>\r\n</div>\r\n\r\n}\r\n<div class=\"input-group flex-nowrap\" #inputDiv>\r\n @if(calendarSwitchPosition() == 'inline'){\r\n <span class=\"input-group-text\" style=\"cursor: pointer;\" (click)=\"switchCalendar()\"> @if(_calendar == 'gregory') {G}\r\n @else{H}</span>\r\n }\r\n <input type=\"text\" class=\"form-control\" [(ngModel)]=\"inputDate\" (blur)=\"onManualDateEntered()\"\r\n [disabled]=\"!enabled()\" [placeholder]=\"format()\" (keyup.enter)=\"onManualDateEntered()\">\r\n\r\n\r\n <!-- <button class=\"btn btn-outline-secondary\" type=\"button\" (click)=\"toggleCalendar()\" [disabled]=\"!enabled()\">\r\n <i class=\"bi bi-calendar3\"></i>\r\n </button> -->\r\n <button #calendarButton class=\"btn btn-outline-secondary\" (click)=\"openCalendar()\" [disabled]=\"!enabled()\">\r\n <i class=\"bi bi-calendar3\"></i>\r\n </button>\r\n\r\n</div>\r\n\r\n<!-- \r\n@if(isMobile && isOpen){\r\n<div class=\"modal modal-backdrop\" tabindex=\"-1\" role=\"dialog\" style=\"display: block;\" #modalDiv>\r\n <div class=\"modal-dialog modal-dialog-scrollable\" role=\"document\">\r\n <div class=\"modal-content\">\r\n <div class=\"modal-header\">\r\n <button type=\"button\" class=\"btn btn-danger close ms-auto btn-sm\" (click)=\"isOpen = false\">\r\n <i class=\"bi bi-x\"></i>\r\n </button>\r\n </div>\r\n <div class=\"modal-body\">\r\n <flex-dual-calendar (valueChange)=\"onDateSelectedFromCalender($event)\"\r\n [(value)]=\"selectedDate\"></flex-dual-calendar>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n} -->\r\n\r\n\r\n<!-- <div #calendarDropdown class=\"calendar-dropdown\">\r\n <flex-dual-calendar (valueChange)=\"onDateSelectedFromCalender($event)\"\r\n [(value)]=\"selectedDate\"></flex-dual-calendar>\r\n</div> -->", styles: [".dropdown-menu{--bs-dropdown-padding-y: 0}.card-body{padding:0!important}.dropdown-panel{position:fixed;border-radius:4px;z-index:9999}.calendar-dropdown{width:max-content;position:absolute;top:0;left:0;visibility:hidden;z-index:\"1080\",}\n"] }]
1584
+ args: [{ selector: 'flex-dual-datepicker', imports: [CommonModule, FormsModule], template: "@if(calendarSwitchPosition() == 'title'){\r\n<div class=\"d-flex align-items-center gap-1\">\r\n <label>{{ title() }}</label>\r\n <button type=\"button\" class=\"btn btn-sm btn-light\" style=\"cursor: pointer; padding-bottom: 1px; padding-top: 1px;\"\r\n (click)=\"switchCalendar()\">\r\n @if(calendar() == 'gregory') {G}\r\n @else{H}\r\n </button>\r\n</div>\r\n}\r\n<div class=\"input-group flex-nowrap\" #inputDiv>\r\n @if(calendarSwitchPosition() == 'inline'){\r\n <span class=\"input-group-text\" style=\"cursor: pointer;\" (click)=\"switchCalendar()\"> @if(calendar() == 'gregory') {G}\r\n @else{H}</span>\r\n }\r\n <input type=\"text\" class=\"form-control\" [(ngModel)]=\"inputDate\" (blur)=\"onManualDateEntered()\"\r\n [disabled]=\"!enabled()\" [placeholder]=\"format()\" (keyup.enter)=\"onManualDateEntered()\">\r\n <button #calendarButton class=\"btn btn-outline-secondary\" (click)=\"openCalendar()\" [disabled]=\"!enabled()\">\r\n <i class=\"bi bi-calendar3\"></i>\r\n </button>\r\n</div>", styles: [".dropdown-menu{--bs-dropdown-padding-y: 0}.card-body{padding:0!important}.dropdown-panel{position:fixed;border-radius:4px;z-index:9999}.calendar-dropdown{width:max-content;position:absolute;top:0;left:0;visibility:hidden;z-index:\"1080\",}\n"] }]
1534
1585
  }], ctorParameters: () => [{ type: DateServiceService }, { type: DeviceDetectorService }, { type: FloatingUiService }], propDecorators: { calendarButton: [{
1535
1586
  type: ViewChild,
1536
1587
  args: ['calendarButton']
@@ -1548,6 +1599,50 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImpor
1548
1599
  args: ['document:click', ['$event']]
1549
1600
  }] } });
1550
1601
 
1602
+ class FlexTableComponent {
1603
+ columns = Array.from({ length: 50 }, (_, index) => `Item ${index + 1}`);
1604
+ items = Array.from({ length: 50 }, (_, index) => `Item ${index + 1}`);
1605
+ enablePaging = input(false, ...(ngDevMode ? [{ debugName: "enablePaging" }] : []));
1606
+ totalDataCount = input(0, ...(ngDevMode ? [{ debugName: "totalDataCount" }] : []));
1607
+ pageChange = output();
1608
+ currentPage = 1;
1609
+ pageSize = 50;
1610
+ selectedIndex = -1;
1611
+ gridColumns;
1612
+ tableHeader;
1613
+ dataSource = input([], ...(ngDevMode ? [{ debugName: "dataSource" }] : []));
1614
+ rowClicked = output();
1615
+ rowDblClicked = output();
1616
+ syncScroll(e) {
1617
+ const body = e.target;
1618
+ const header = this.tableHeader?.nativeElement; //document.querySelector('.grid-header');
1619
+ if (header)
1620
+ header.scrollLeft = body.scrollLeft;
1621
+ }
1622
+ onRowDblClick(index, data) {
1623
+ this.selectedIndex = index;
1624
+ // console.log(index);
1625
+ this.rowDblClicked.emit({ index: index, data: data });
1626
+ }
1627
+ onRowClick(index, data) {
1628
+ this.selectedIndex = index;
1629
+ // console.log(index);
1630
+ this.rowClicked.emit({ index: index, data: data });
1631
+ }
1632
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: FlexTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1633
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: FlexTableComponent, isStandalone: true, selector: "flex-table", inputs: { enablePaging: { classPropertyName: "enablePaging", publicName: "enablePaging", isSignal: true, isRequired: false, transformFunction: null }, totalDataCount: { classPropertyName: "totalDataCount", publicName: "totalDataCount", isSignal: true, isRequired: false, transformFunction: null }, dataSource: { classPropertyName: "dataSource", publicName: "dataSource", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { pageChange: "pageChange", rowClicked: "rowClicked", rowDblClicked: "rowDblClicked" }, queries: [{ propertyName: "gridColumns", first: true, predicate: FlexColumnsComponent, descendants: true }], viewQueries: [{ propertyName: "tableHeader", first: true, predicate: ["tableHeader"], descendants: true }], ngImport: i0, template: "<div class=\"table-layout\">\r\n <div style=\"overflow-x: hidden; padding-right: 15px;\" #tableHeader>\r\n <table class=\"table table-bordered mb-0 table-header\">\r\n <colgroup>\r\n @for (col of gridColumns?.columns; track $index) {\r\n <col [style.width.px]=\"col.width\" [style.maxWidth.px]=\"col.width\">\r\n }\r\n </colgroup>\r\n <thead>\r\n <tr>\r\n @for (col of gridColumns?.columns; track $index) {\r\n <th class=\"text-truncate\">\r\n @if (col.headerTemplate) {\r\n <ng-container [ngTemplateOutlet]=\"col.headerTemplate\"></ng-container>\r\n }\r\n @else {\r\n <!-- <ng-template #defaultHeader><span [textContent]=\"col.field\"></span></ng-template> -->\r\n <!-- <span [textContent]=\"col.field\"></span> -->\r\n {{ col.headerText() }}\r\n }\r\n </th>\r\n }\r\n\r\n <!-- <th style=\"width: 20px;\"></th> -->\r\n </tr>\r\n </thead>\r\n </table>\r\n </div>\r\n\r\n <div class=\"content-area\" (scroll)=\"syncScroll($event)\">\r\n <table class=\"table table-bordered\">\r\n <colgroup>\r\n @for (col of gridColumns?.columns; track $index) {\r\n <col [style.width.px]=\"col.width\" [style.maxWidth.px]=\"col.width\">\r\n }\r\n </colgroup>\r\n <tbody>\r\n @for (row of dataSource(); track $index; let i = $index) {\r\n <tr [class.table-active]=\"$index === selectedIndex\" (click)=\"onRowClick($index, row)\"\r\n (dblclick)=\"onRowDblClick($index, row)\">\r\n @for (col of gridColumns?.columns; track $index) {\r\n <td>\r\n @if (col.cellTemplate) {\r\n <ng-container [ngTemplateOutlet]=\"col.cellTemplate\" [ngTemplateOutletContext]=\"{ $implicit: row,\r\n rowIndex: (currentPage - 1) * pageSize + i,\r\n localIndex: i }\">\r\n </ng-container>\r\n } @else {\r\n <!-- {{ row[col.field] }} -->\r\n <span [textContent]=\"row[col.field]\"></span>\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n\r\n <div class=\"border-top\">\r\n <div class=\"d-flex align-items-center gap-1 p-1\">\r\n <div>Page No</div>\r\n <div>\r\n <select class=\"form-select form-sm\">\r\n <option>\r\n Page 1\r\n </option>\r\n </select>\r\n </div>\r\n <div>Page Size</div>\r\n <div>\r\n <select class=\"form-select\">\r\n <option>\r\n 800\r\n </option>\r\n <option>\r\n 400\r\n </option>\r\n </select>\r\n </div>\r\n <div>\r\n {{ \"total-count\" }}: {{ totalDataCount() }}\r\n </div>\r\n </div>\r\n </div>\r\n</div>", styles: [":host{display:block;height:100%;min-height:0;background:var(--bg);color:var(--text)}.table-layout{display:grid;grid-template-rows:auto 1fr auto;height:100%;min-height:0}.content-area{overflow-x:auto;overflow-y:auto;min-height:0;background:var(--scroll-bg)}table{border-collapse:collapse;white-space:nowrap;min-width:max-content}.table-header{--bs-table-bg: #f9f9f9}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
1634
+ }
1635
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: FlexTableComponent, decorators: [{
1636
+ type: Component,
1637
+ args: [{ selector: 'flex-table', imports: [CommonModule], template: "<div class=\"table-layout\">\r\n <div style=\"overflow-x: hidden; padding-right: 15px;\" #tableHeader>\r\n <table class=\"table table-bordered mb-0 table-header\">\r\n <colgroup>\r\n @for (col of gridColumns?.columns; track $index) {\r\n <col [style.width.px]=\"col.width\" [style.maxWidth.px]=\"col.width\">\r\n }\r\n </colgroup>\r\n <thead>\r\n <tr>\r\n @for (col of gridColumns?.columns; track $index) {\r\n <th class=\"text-truncate\">\r\n @if (col.headerTemplate) {\r\n <ng-container [ngTemplateOutlet]=\"col.headerTemplate\"></ng-container>\r\n }\r\n @else {\r\n <!-- <ng-template #defaultHeader><span [textContent]=\"col.field\"></span></ng-template> -->\r\n <!-- <span [textContent]=\"col.field\"></span> -->\r\n {{ col.headerText() }}\r\n }\r\n </th>\r\n }\r\n\r\n <!-- <th style=\"width: 20px;\"></th> -->\r\n </tr>\r\n </thead>\r\n </table>\r\n </div>\r\n\r\n <div class=\"content-area\" (scroll)=\"syncScroll($event)\">\r\n <table class=\"table table-bordered\">\r\n <colgroup>\r\n @for (col of gridColumns?.columns; track $index) {\r\n <col [style.width.px]=\"col.width\" [style.maxWidth.px]=\"col.width\">\r\n }\r\n </colgroup>\r\n <tbody>\r\n @for (row of dataSource(); track $index; let i = $index) {\r\n <tr [class.table-active]=\"$index === selectedIndex\" (click)=\"onRowClick($index, row)\"\r\n (dblclick)=\"onRowDblClick($index, row)\">\r\n @for (col of gridColumns?.columns; track $index) {\r\n <td>\r\n @if (col.cellTemplate) {\r\n <ng-container [ngTemplateOutlet]=\"col.cellTemplate\" [ngTemplateOutletContext]=\"{ $implicit: row,\r\n rowIndex: (currentPage - 1) * pageSize + i,\r\n localIndex: i }\">\r\n </ng-container>\r\n } @else {\r\n <!-- {{ row[col.field] }} -->\r\n <span [textContent]=\"row[col.field]\"></span>\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n\r\n <div class=\"border-top\">\r\n <div class=\"d-flex align-items-center gap-1 p-1\">\r\n <div>Page No</div>\r\n <div>\r\n <select class=\"form-select form-sm\">\r\n <option>\r\n Page 1\r\n </option>\r\n </select>\r\n </div>\r\n <div>Page Size</div>\r\n <div>\r\n <select class=\"form-select\">\r\n <option>\r\n 800\r\n </option>\r\n <option>\r\n 400\r\n </option>\r\n </select>\r\n </div>\r\n <div>\r\n {{ \"total-count\" }}: {{ totalDataCount() }}\r\n </div>\r\n </div>\r\n </div>\r\n</div>", styles: [":host{display:block;height:100%;min-height:0;background:var(--bg);color:var(--text)}.table-layout{display:grid;grid-template-rows:auto 1fr auto;height:100%;min-height:0}.content-area{overflow-x:auto;overflow-y:auto;min-height:0;background:var(--scroll-bg)}table{border-collapse:collapse;white-space:nowrap;min-width:max-content}.table-header{--bs-table-bg: #f9f9f9}\n"] }]
1638
+ }], propDecorators: { gridColumns: [{
1639
+ type: ContentChild,
1640
+ args: [FlexColumnsComponent]
1641
+ }], tableHeader: [{
1642
+ type: ViewChild,
1643
+ args: ["tableHeader"]
1644
+ }] } });
1645
+
1551
1646
  /*
1552
1647
  * Public API Surface of flex-ui-controls
1553
1648
  */
@@ -1556,5 +1651,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImpor
1556
1651
  * Generated bundle index. Do not edit.
1557
1652
  */
1558
1653
 
1559
- export { ComboDatePickerComponent, FlexColumnComponent, FlexColumnsComponent, FlexContainerComponent, FlexDualDatepickerComponent, FlexGridComponent, FlexPaginationComponent, FlexPanelComponent, HijriDatepickerComponent };
1654
+ export { ComboDatePickerComponent, FlexColumnComponent, FlexColumnsComponent, FlexContainerComponent, FlexDualDatepickerComponent, FlexGridComponent, FlexPaginationComponent, FlexPanelComponent, FlexTableComponent, HijriDatepickerComponent };
1560
1655
  //# sourceMappingURL=dcsl-flex-ui.mjs.map