@dcsl/flex-ui 0.0.30 → 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,12 +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';
13
- import { hijriToGregorian } from '@tabby_ai/hijri-converter';
10
+ import { hijriToGregorian, gregorianToHijri } from '@tabby_ai/hijri-converter';
14
11
  import { autoUpdate, computePosition, offset, flip, shift } from '@floating-ui/dom';
15
12
 
16
13
  class FlexPanelComponent {
@@ -670,68 +667,64 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImpor
670
667
  }] } });
671
668
 
672
669
  dayjs.extend(utc);
673
- // Extend Day.js with calendar systems support
674
- dayjs.extend(calendarSystems);
675
670
  dayjs.extend(customParseFormat);
676
- // Register the Persian calendar
677
- dayjs.registerCalendarSystem('persian', new PersianCalendarSystem());
678
- dayjs.registerCalendarSystem('islamic', new HijriCalendarSystem());
679
671
  class DateServiceService {
680
672
  constructor() {
681
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
+ }
682
700
  parse(dateString, calendar, format) {
683
701
  //Step 1: User will input gregorian or islamic(hijri) date. for this we will use customParseFormat
684
702
  //in the control we will specify the format using binding.
685
703
  var parsedUtcDate = dayjs.utc(dateString, format, true);
686
- console.log("Parsed string provided by User as Utc Iso: ", parsedUtcDate.toISOString());
687
704
  if (!parsedUtcDate.isValid()) {
688
- console.log("entered date string is invalid: ", dateString);
689
705
  return null;
690
706
  }
691
- //we are writing this to parse the date , month, year only.
692
- //then based on the calender type we will decide.
693
- //but by default system will take gregorian
694
- // month() function return 0-11 months but when it parse 1 then it makes it 0
695
- const customDate = dayjs.fromCalendarSystem(calendar, parsedUtcDate.year(), parsedUtcDate.month() + 1, parsedUtcDate.date());
696
- //here we are assuming the control want to handle islamic calender date, we will take it dynmically.
697
- console.log("Prased Date in Gregorian String as per format ['DD-MM-YYYY']:", customDate.format('DD-MM-YYYY'));
698
- // console.log("Prased Date in Gregorian String as per format ['DD-MM-YYYY']:", customDate.toISOString());
699
- //here it will show gregorian calender, because even if we parse using islamic calender, it will convert the date
700
- //and keep it to gregorian
701
- //to show islamic date, we have to tell the dayjs to use islamic calender
702
- var customDateString = customDate.format('YYYY-MM-DD');
703
- const d2 = dayjs.utc(customDateString);
704
- // console.log("utc", d2.toISOString());
705
- return d2.toDate();
706
- }
707
- parse2(dateString, calendar, format) {
708
- const d = dayjs.utc(dateString, format, true);
709
- if (!d.isValid())
710
- return null;
711
- let gYear = d.year();
712
- let gMonth = d.month();
713
- let gDay = d.date();
714
- if (calendar === "islamic") {
715
- const hijri = { hijriYear: d.year(), hijriMonth: d.month(), hijriDay: d.date() };
716
- const greg = hijriToGregorian({
717
- year: hijri.hijriYear,
718
- month: hijri.hijriMonth,
719
- day: hijri.hijriDay
707
+ if (calendar == "islamic") {
708
+ var grego = hijriToGregorian({
709
+ day: parsedUtcDate.date(),
710
+ month: parsedUtcDate.month() + 1,
711
+ year: parsedUtcDate.year()
720
712
  });
721
- gYear = greg.year;
722
- gMonth = greg.month;
723
- gDay = greg.day;
713
+ parsedUtcDate = dayjs.utc(`${grego.year}-${grego.month}-${grego.day}`);
724
714
  }
725
- // construct a pure UTC date
726
- const fixed = dayjs.utc(new Date(gYear, gMonth, gDay));
727
- return fixed.toDate();
715
+ return parsedUtcDate.toDate();
728
716
  }
729
717
  format(date, calendar, format) {
730
- // const d = dayjs.utc(date.getFullYear(), date.getMonth(), date.getDate() as number);
731
- var c = dayjs.fromCalendarSystem("gregory", date.getFullYear(), date.getMonth() + 1, date.getDate());
732
- if (calendar == "islamic")
733
- c = c.add(1, "day");
734
- 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);
735
728
  }
736
729
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: DateServiceService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
737
730
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: DateServiceService, providedIn: 'root' });
@@ -914,6 +907,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImpor
914
907
  args: ['window:resize']
915
908
  }] } });
916
909
 
910
+ const MinGregorianDate = new Date(1937, 0, 1).getTime();
911
+ const MaxGregorianDate = new Date(2076, 11, 31).getTime();
917
912
  // ✅ Intl formatters
918
913
  const hijriFmt = new Intl.DateTimeFormat('en-u-ca-islamic-umalqura-nu-latn', {
919
914
  day: 'numeric',
@@ -941,12 +936,17 @@ const gregMonthNamesAr = [
941
936
  const weekDaysEn = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
942
937
  const weekDaysAr = ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'];
943
938
  function hijriFromGregorian(g) {
944
- const parts = hijriFmt.formatToParts(g);
945
- const map = {};
946
- for (const p of parts)
947
- map[p.type] = p.value;
948
- const n = (k) => parseInt(map[k] ?? '0', 10);
949
- 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 };
950
950
  }
951
951
  function compareHijri(a, b) {
952
952
  if (a.hy !== b.hy)
@@ -956,43 +956,60 @@ function compareHijri(a, b) {
956
956
  return a.hd - b.hd;
957
957
  }
958
958
  function findGregorianForHijri(target) {
959
- let lo = new Date(1937, 0, 1).getTime();
960
- let hi = new Date(2076, 11, 31).getTime();
961
- const dayMs = 86400000;
962
- while (lo <= hi) {
963
- const mid = Math.floor((lo + hi) / 2);
964
- const h = hijriFromGregorian(new Date(mid));
965
- compareHijri(h, target) < 0 ? (lo = mid + dayMs) : (hi = mid - dayMs);
966
- }
967
- let d = new Date(lo);
968
- while (true) {
969
- const h = hijriFromGregorian(d);
970
- const cmp = compareHijri(h, target);
971
- if (cmp === 0)
972
- return d;
973
- if (cmp > 0)
974
- throw new Error('Hijri date out of supported range');
975
- d = new Date(d.getTime() + dayMs);
976
- }
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
+ // }
977
992
  }
978
993
  function stripTime(d) {
979
- return new Date(d.getFullYear(), d.getMonth(), d.getDate());
994
+ //return new Date(d.getFullYear(), d.getMonth(), d.getDate());
995
+ return d;
980
996
  }
997
+
981
998
  class FlexDualCalendarComponent {
982
999
  /** Two-way bound selected date (Gregorian) */
983
- value;
984
- valueChange = new EventEmitter();
1000
+ value = model(new Date(), ...(ngDevMode ? [{ debugName: "value" }] : []));
1001
+ // @Output() valueChange = new EventEmitter<Date>();
985
1002
  /** Optional min/max (Gregorian) */
986
1003
  minDate;
987
1004
  maxDate;
988
1005
  /** Month/weekday language */
989
1006
  monthLang = 'en';
990
1007
  /** Start mode, default Hijri */
991
- startMode = 'gregory';
1008
+ //@Input() startMode: FlexCalendarSystem = 'gregory';
992
1009
  // This will be injected by FloatingUiService
993
1010
  close;
994
1011
  /** Current mode (hijri | gregory) */
995
- mode = signal('gregory', ...(ngDevMode ? [{ debugName: "mode" }] : []));
1012
+ mode = model('gregory', ...(ngDevMode ? [{ debugName: "mode" }] : []));
996
1013
  /** Hijri view state */
997
1014
  hy = signal(0, ...(ngDevMode ? [{ debugName: "hy" }] : []));
998
1015
  hm = signal(0, ...(ngDevMode ? [{ debugName: "hm" }] : []));
@@ -1018,6 +1035,7 @@ class FlexDualCalendarComponent {
1018
1035
  ? this.hijriMonths[this.selectedMonth - 1]
1019
1036
  : this.gregMonths[this.selectedMonth - 1];
1020
1037
  }
1038
+ ignoreDropdownSync = false;
1021
1039
  constructor() {
1022
1040
  const today = new Date();
1023
1041
  const h = hijriFromGregorian(today);
@@ -1026,7 +1044,7 @@ class FlexDualCalendarComponent {
1026
1044
  this.gy.set(today.getFullYear());
1027
1045
  this.gm.set(today.getMonth() + 1);
1028
1046
  // initialize selectors with start mode
1029
- this.mode.set(this.startMode);
1047
+ //this.mode.set(this.startMode);
1030
1048
  if (this.mode() === 'islamic') {
1031
1049
  this.selectedYear = this.hy();
1032
1050
  this.selectedMonth = this.hm();
@@ -1035,14 +1053,13 @@ class FlexDualCalendarComponent {
1035
1053
  this.selectedYear = this.gy();
1036
1054
  this.selectedMonth = this.gm();
1037
1055
  }
1038
- }
1039
- ngOnInit() {
1040
- this.buildYearRange();
1041
- }
1042
- ngOnChanges(changes) {
1043
- // If value changed from outside, update both calendars
1044
- if (changes['value'] && this.value instanceof Date) {
1045
- 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());
1046
1063
  const h = hijriFromGregorian(g);
1047
1064
  this.gy.set(g.getFullYear());
1048
1065
  this.gm.set(g.getMonth() + 1);
@@ -1057,7 +1074,29 @@ class FlexDualCalendarComponent {
1057
1074
  this.selectedYear = this.gy();
1058
1075
  this.selectedMonth = this.gm();
1059
1076
  }
1060
- }
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
+ // }
1061
1100
  // Rebuild year range if min/max changed
1062
1101
  if (changes['minDate'] || changes['maxDate'] || changes['value']) {
1063
1102
  this.buildYearRange();
@@ -1082,7 +1121,7 @@ class FlexDualCalendarComponent {
1082
1121
  }
1083
1122
  // 🔁 Mode switch (SYNCED view — keep same instant)
1084
1123
  switchMode(value) {
1085
- 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
1086
1125
  if (value === 'gregory') {
1087
1126
  // To Gregorian mode
1088
1127
  const g = stripTime(pivot);
@@ -1105,6 +1144,7 @@ class FlexDualCalendarComponent {
1105
1144
  }
1106
1145
  // called when dropdowns change
1107
1146
  onMonthYearChange() {
1147
+ this.ignoreDropdownSync = true;
1108
1148
  if (this.mode() === 'islamic') {
1109
1149
  this.hy.set(this.selectedYear);
1110
1150
  this.hm.set(this.selectedMonth);
@@ -1113,10 +1153,12 @@ class FlexDualCalendarComponent {
1113
1153
  this.gy.set(this.selectedYear);
1114
1154
  this.gm.set(this.selectedMonth);
1115
1155
  }
1156
+ setTimeout(() => (this.ignoreDropdownSync = false));
1116
1157
  }
1117
1158
  // Start of visible month (Gregorian date)
1118
1159
  firstOfMonth() {
1119
1160
  if (this.mode() === 'islamic') {
1161
+ //console.log("firstOfMonth function: ", this.hm());
1120
1162
  return findGregorianForHijri({ hy: this.hy(), hm: this.hm(), hd: 1 });
1121
1163
  }
1122
1164
  return new Date(this.gy(), this.gm() - 1, 1);
@@ -1133,6 +1175,7 @@ class FlexDualCalendarComponent {
1133
1175
  const g = new Date(start);
1134
1176
  g.setDate(start.getDate() + i);
1135
1177
  const h = hijriFromGregorian(g);
1178
+ //console.log("month:", h.hm);
1136
1179
  let disabled = false;
1137
1180
  if (this.minDate && g < stripTime(this.minDate))
1138
1181
  disabled = true;
@@ -1148,6 +1191,7 @@ class FlexDualCalendarComponent {
1148
1191
  prevMonth() {
1149
1192
  if (!this.canPrev())
1150
1193
  return;
1194
+ this.ignoreDropdownSync = true;
1151
1195
  if (this.mode() === 'islamic') {
1152
1196
  let m = this.hm(), y = this.hy();
1153
1197
  if (--m < 1) {
@@ -1170,10 +1214,12 @@ class FlexDualCalendarComponent {
1170
1214
  this.selectedYear = y;
1171
1215
  this.selectedMonth = m;
1172
1216
  }
1217
+ setTimeout(() => (this.ignoreDropdownSync = false));
1173
1218
  }
1174
1219
  nextMonth() {
1175
1220
  if (!this.canNext())
1176
1221
  return;
1222
+ this.ignoreDropdownSync = true;
1177
1223
  if (this.mode() === 'islamic') {
1178
1224
  let m = this.hm(), y = this.hy();
1179
1225
  if (++m > 12) {
@@ -1196,6 +1242,7 @@ class FlexDualCalendarComponent {
1196
1242
  this.selectedYear = y;
1197
1243
  this.selectedMonth = m;
1198
1244
  }
1245
+ setTimeout(() => (this.ignoreDropdownSync = false));
1199
1246
  }
1200
1247
  canPrev() {
1201
1248
  if (!this.minDate)
@@ -1223,22 +1270,27 @@ class FlexDualCalendarComponent {
1223
1270
  && g.getDate() === t.getDate();
1224
1271
  }
1225
1272
  isSelected(g) {
1226
- return !!this.value &&
1227
- g.getFullYear() === this.value.getFullYear() &&
1228
- g.getMonth() === this.value.getMonth() &&
1229
- 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();
1230
1280
  }
1231
1281
  select(c) {
1232
1282
  if (c.disabled)
1233
1283
  return;
1234
- this.value = stripTime(c.g);
1235
- 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);
1236
1288
  // keep both views in sync after selection
1237
- const h = hijriFromGregorian(this.value);
1289
+ const h = hijriFromGregorian(this.value());
1238
1290
  this.hy.set(h.hy);
1239
1291
  this.hm.set(h.hm);
1240
- this.gy.set(this.value.getFullYear());
1241
- this.gm.set(this.value.getMonth() + 1);
1292
+ this.gy.set(this.value().getFullYear());
1293
+ this.gm.set(this.value().getMonth() + 1);
1242
1294
  if (this.mode() === 'islamic') {
1243
1295
  this.selectedYear = this.hy();
1244
1296
  this.selectedMonth = this.hm();
@@ -1247,26 +1299,20 @@ class FlexDualCalendarComponent {
1247
1299
  this.selectedYear = this.gy();
1248
1300
  this.selectedMonth = this.gm();
1249
1301
  }
1250
- this.close(this.value);
1302
+ this.close(this.value());
1251
1303
  }
1252
1304
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: FlexDualCalendarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1253
- 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"] }] });
1254
1306
  }
1255
1307
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: FlexDualCalendarComponent, decorators: [{
1256
1308
  type: Component,
1257
- 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"] }]
1258
- }], ctorParameters: () => [], propDecorators: { value: [{
1259
- type: Input
1260
- }], valueChange: [{
1261
- type: Output
1262
- }], 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: [{
1263
1311
  type: Input
1264
1312
  }], maxDate: [{
1265
1313
  type: Input
1266
1314
  }], monthLang: [{
1267
1315
  type: Input
1268
- }], startMode: [{
1269
- type: Input
1270
1316
  }] } });
1271
1317
 
1272
1318
  class DeviceDetectorService {
@@ -1406,7 +1452,6 @@ class FlexDualDatepickerComponent {
1406
1452
  calendarDropdown;
1407
1453
  inputDiv;
1408
1454
  modalDiv;
1409
- // @ViewChild("menu") popupDiv?: ElementRef;
1410
1455
  value = model(...(ngDevMode ? [undefined, { debugName: "value" }] : []));
1411
1456
  enabled = input(true, ...(ngDevMode ? [{ debugName: "enabled" }] : []));
1412
1457
  cssClass = input(...(ngDevMode ? [undefined, { debugName: "cssClass" }] : []));
@@ -1415,8 +1460,8 @@ class FlexDualDatepickerComponent {
1415
1460
  calendarSwitchPosition = input("title", ...(ngDevMode ? [{ debugName: "calendarSwitchPosition" }] : []));
1416
1461
  //selectedDate is needed to keep the current data for process
1417
1462
  selectedDate;
1418
- calendar = input("gregory", ...(ngDevMode ? [{ debugName: "calendar" }] : []));
1419
- _calendar = "gregory";
1463
+ calendar = model("gregory", ...(ngDevMode ? [{ debugName: "calendar" }] : []));
1464
+ // protected _calendar: FlexCalendarSystem = "gregory";
1420
1465
  inputDate = "";
1421
1466
  isMobile = false;
1422
1467
  constructor(dateService, deviceDetector, floating) {
@@ -1425,13 +1470,15 @@ class FlexDualDatepickerComponent {
1425
1470
  this.floating = floating;
1426
1471
  this.isMobile = deviceDetector.isMobile();
1427
1472
  effect(() => {
1428
- this._calendar = this.calendar();
1473
+ //this._calendar = this.calendar();
1474
+ if (!this.selectedDate)
1475
+ return;
1429
1476
  this.inputDate = this.formatDate(this.selectedDate);
1430
1477
  });
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