@ionic/core 7.6.1-dev.11702048520.13c82dad → 7.6.1-dev.11702322681.17e39348

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.
Files changed (32) hide show
  1. package/components/data.js +64 -14
  2. package/components/ion-datetime.js +22 -3
  3. package/dist/cjs/{data-36b9094e.js → data-a5109f09.js} +64 -14
  4. package/dist/cjs/ion-datetime-button.cjs.entry.js +1 -1
  5. package/dist/cjs/ion-datetime_3.cjs.entry.js +23 -4
  6. package/dist/collection/components/datetime/datetime.js +22 -3
  7. package/dist/collection/components/datetime/test/manipulation.spec.js +133 -1
  8. package/dist/collection/components/datetime/test/prefer-wheel/datetime.spec.js +27 -0
  9. package/dist/collection/components/datetime/utils/manipulation.js +65 -15
  10. package/dist/docs.json +1 -1
  11. package/dist/esm/{data-f5c75b4e.js → data-775093f5.js} +64 -14
  12. package/dist/esm/ion-datetime-button.entry.js +1 -1
  13. package/dist/esm/ion-datetime_3.entry.js +23 -4
  14. package/dist/esm-es5/data-775093f5.js +4 -0
  15. package/dist/esm-es5/ion-datetime-button.entry.js +1 -1
  16. package/dist/esm-es5/ion-datetime_3.entry.js +1 -1
  17. package/dist/ionic/ionic.esm.js +1 -1
  18. package/dist/ionic/{p-9eec42cc.system.entry.js → p-10437cc2.system.entry.js} +1 -1
  19. package/dist/ionic/p-18cae04f.js +4 -0
  20. package/dist/ionic/p-4b4c7343.system.entry.js +4 -0
  21. package/dist/ionic/p-87bb3735.system.js +4 -0
  22. package/dist/ionic/p-b936ec9d.entry.js +4 -0
  23. package/dist/ionic/p-e3584231.system.js +1 -1
  24. package/dist/ionic/{p-ddb30596.entry.js → p-f3752035.entry.js} +1 -1
  25. package/dist/types/components/datetime/utils/manipulation.d.ts +34 -7
  26. package/hydrate/index.js +86 -17
  27. package/package.json +1 -1
  28. package/dist/esm-es5/data-f5c75b4e.js +0 -4
  29. package/dist/ionic/p-2aea8b1e.js +0 -4
  30. package/dist/ionic/p-5e4eec2e.entry.js +0 -4
  31. package/dist/ionic/p-82e3d633.system.js +0 -4
  32. package/dist/ionic/p-f0445d82.system.entry.js +0 -4
@@ -716,32 +716,82 @@ const validateParts = (parts, minParts, maxParts) => {
716
716
  * Returns the closest date to refParts
717
717
  * that also meets the constraints of
718
718
  * the *Values params.
719
- * @param refParts The reference date
720
- * @param monthValues The allowed month values
721
- * @param dayValues The allowed day (of the month) values
722
- * @param yearValues The allowed year values
723
- * @param hourValues The allowed hour values
724
- * @param minuteValues The allowed minute values
725
719
  */
726
- const getClosestValidDate = (refParts, monthValues, dayValues, yearValues, hourValues, minuteValues) => {
720
+ const getClosestValidDate = ({ refParts, monthValues, dayValues, yearValues, hourValues, minuteValues, minParts, maxParts, }) => {
727
721
  const { hour, minute, day, month, year } = refParts;
728
722
  const copyParts = Object.assign(Object.assign({}, refParts), { dayOfWeek: undefined });
723
+ if (yearValues !== undefined) {
724
+ // Filters out years that are out of the min/max bounds
725
+ const filteredYears = yearValues.filter((year) => {
726
+ if (minParts !== undefined && year < minParts.year) {
727
+ return false;
728
+ }
729
+ if (maxParts !== undefined && year > maxParts.year) {
730
+ return false;
731
+ }
732
+ return true;
733
+ });
734
+ copyParts.year = findClosestValue(year, filteredYears);
735
+ }
729
736
  if (monthValues !== undefined) {
730
- copyParts.month = findClosestValue(month, monthValues);
737
+ // Filters out months that are out of the min/max bounds
738
+ const filteredMonths = monthValues.filter((month) => {
739
+ if (minParts !== undefined && copyParts.year === minParts.year && month < minParts.month) {
740
+ return false;
741
+ }
742
+ if (maxParts !== undefined && copyParts.year === maxParts.year && month > maxParts.month) {
743
+ return false;
744
+ }
745
+ return true;
746
+ });
747
+ copyParts.month = findClosestValue(month, filteredMonths);
731
748
  }
732
749
  // Day is nullable but cannot be undefined
733
750
  if (day !== null && dayValues !== undefined) {
734
- copyParts.day = findClosestValue(day, dayValues);
735
- }
736
- if (yearValues !== undefined) {
737
- copyParts.year = findClosestValue(year, yearValues);
751
+ // Filters out days that are out of the min/max bounds
752
+ const filteredDays = dayValues.filter((day) => {
753
+ if (minParts !== undefined && isBefore(Object.assign(Object.assign({}, copyParts), { day }), minParts)) {
754
+ return false;
755
+ }
756
+ if (maxParts !== undefined && isAfter(Object.assign(Object.assign({}, copyParts), { day }), maxParts)) {
757
+ return false;
758
+ }
759
+ return true;
760
+ });
761
+ copyParts.day = findClosestValue(day, filteredDays);
738
762
  }
739
763
  if (hour !== undefined && hourValues !== undefined) {
740
- copyParts.hour = findClosestValue(hour, hourValues);
764
+ // Filters out hours that are out of the min/max bounds
765
+ const filteredHours = hourValues.filter((hour) => {
766
+ if ((minParts === null || minParts === void 0 ? void 0 : minParts.hour) !== undefined && isSameDay(copyParts, minParts) && hour < minParts.hour) {
767
+ return false;
768
+ }
769
+ if ((maxParts === null || maxParts === void 0 ? void 0 : maxParts.hour) !== undefined && isSameDay(copyParts, maxParts) && hour > maxParts.hour) {
770
+ return false;
771
+ }
772
+ return true;
773
+ });
774
+ copyParts.hour = findClosestValue(hour, filteredHours);
741
775
  copyParts.ampm = parseAmPm(copyParts.hour);
742
776
  }
743
777
  if (minute !== undefined && minuteValues !== undefined) {
744
- copyParts.minute = findClosestValue(minute, minuteValues);
778
+ // Filters out minutes that are out of the min/max bounds
779
+ const filteredMinutes = minuteValues.filter((minute) => {
780
+ if ((minParts === null || minParts === void 0 ? void 0 : minParts.minute) !== undefined &&
781
+ isSameDay(copyParts, minParts) &&
782
+ copyParts.hour === minParts.hour &&
783
+ minute < minParts.minute) {
784
+ return false;
785
+ }
786
+ if ((maxParts === null || maxParts === void 0 ? void 0 : maxParts.minute) !== undefined &&
787
+ isSameDay(copyParts, maxParts) &&
788
+ copyParts.hour === maxParts.hour &&
789
+ minute > maxParts.minute) {
790
+ return false;
791
+ }
792
+ return true;
793
+ });
794
+ copyParts.minute = findClosestValue(minute, filteredMinutes);
745
795
  }
746
796
  return copyParts;
747
797
  };
@@ -867,14 +867,24 @@ const Datetime = /*@__PURE__*/ proxyCustomElement(class Datetime extends HTMLEle
867
867
  * or modal that the datetime was presented in.
868
868
  */
869
869
  async confirm(closeOverlay = false) {
870
- const { isCalendarPicker, activeParts } = this;
870
+ const { isCalendarPicker, activeParts, preferWheel, workingParts } = this;
871
871
  /**
872
872
  * We only update the value if the presentation is not a calendar picker.
873
873
  */
874
874
  if (activeParts !== undefined || !isCalendarPicker) {
875
875
  const activePartsIsArray = Array.isArray(activeParts);
876
876
  if (activePartsIsArray && activeParts.length === 0) {
877
- this.setValue(undefined);
877
+ if (preferWheel) {
878
+ /**
879
+ * If the datetime is using a wheel picker, but the
880
+ * active parts are empty, then the user has confirmed the
881
+ * initial value (working parts) presented to them.
882
+ */
883
+ this.setValue(convertDataToISO(workingParts));
884
+ }
885
+ else {
886
+ this.setValue(undefined);
887
+ }
878
888
  }
879
889
  else {
880
890
  this.setValue(convertDataToISO(activeParts));
@@ -1078,9 +1088,18 @@ const Datetime = /*@__PURE__*/ proxyCustomElement(class Datetime extends HTMLEle
1078
1088
  const yearValues = (this.parsedYearValues = convertToArrayOfNumbers(this.yearValues));
1079
1089
  const dayValues = (this.parsedDayValues = convertToArrayOfNumbers(this.dayValues));
1080
1090
  const todayParts = (this.todayParts = parseDate(getToday()));
1081
- this.defaultParts = getClosestValidDate(todayParts, monthValues, dayValues, yearValues, hourValues, minuteValues);
1082
1091
  this.processMinParts();
1083
1092
  this.processMaxParts();
1093
+ this.defaultParts = getClosestValidDate({
1094
+ refParts: todayParts,
1095
+ monthValues,
1096
+ dayValues,
1097
+ yearValues,
1098
+ hourValues,
1099
+ minuteValues,
1100
+ minParts: this.minParts,
1101
+ maxParts: this.maxParts,
1102
+ });
1084
1103
  this.processValue(this.value);
1085
1104
  this.emitStyle();
1086
1105
  }
@@ -718,32 +718,82 @@ const validateParts = (parts, minParts, maxParts) => {
718
718
  * Returns the closest date to refParts
719
719
  * that also meets the constraints of
720
720
  * the *Values params.
721
- * @param refParts The reference date
722
- * @param monthValues The allowed month values
723
- * @param dayValues The allowed day (of the month) values
724
- * @param yearValues The allowed year values
725
- * @param hourValues The allowed hour values
726
- * @param minuteValues The allowed minute values
727
721
  */
728
- const getClosestValidDate = (refParts, monthValues, dayValues, yearValues, hourValues, minuteValues) => {
722
+ const getClosestValidDate = ({ refParts, monthValues, dayValues, yearValues, hourValues, minuteValues, minParts, maxParts, }) => {
729
723
  const { hour, minute, day, month, year } = refParts;
730
724
  const copyParts = Object.assign(Object.assign({}, refParts), { dayOfWeek: undefined });
725
+ if (yearValues !== undefined) {
726
+ // Filters out years that are out of the min/max bounds
727
+ const filteredYears = yearValues.filter((year) => {
728
+ if (minParts !== undefined && year < minParts.year) {
729
+ return false;
730
+ }
731
+ if (maxParts !== undefined && year > maxParts.year) {
732
+ return false;
733
+ }
734
+ return true;
735
+ });
736
+ copyParts.year = findClosestValue(year, filteredYears);
737
+ }
731
738
  if (monthValues !== undefined) {
732
- copyParts.month = findClosestValue(month, monthValues);
739
+ // Filters out months that are out of the min/max bounds
740
+ const filteredMonths = monthValues.filter((month) => {
741
+ if (minParts !== undefined && copyParts.year === minParts.year && month < minParts.month) {
742
+ return false;
743
+ }
744
+ if (maxParts !== undefined && copyParts.year === maxParts.year && month > maxParts.month) {
745
+ return false;
746
+ }
747
+ return true;
748
+ });
749
+ copyParts.month = findClosestValue(month, filteredMonths);
733
750
  }
734
751
  // Day is nullable but cannot be undefined
735
752
  if (day !== null && dayValues !== undefined) {
736
- copyParts.day = findClosestValue(day, dayValues);
737
- }
738
- if (yearValues !== undefined) {
739
- copyParts.year = findClosestValue(year, yearValues);
753
+ // Filters out days that are out of the min/max bounds
754
+ const filteredDays = dayValues.filter((day) => {
755
+ if (minParts !== undefined && isBefore(Object.assign(Object.assign({}, copyParts), { day }), minParts)) {
756
+ return false;
757
+ }
758
+ if (maxParts !== undefined && isAfter(Object.assign(Object.assign({}, copyParts), { day }), maxParts)) {
759
+ return false;
760
+ }
761
+ return true;
762
+ });
763
+ copyParts.day = findClosestValue(day, filteredDays);
740
764
  }
741
765
  if (hour !== undefined && hourValues !== undefined) {
742
- copyParts.hour = findClosestValue(hour, hourValues);
766
+ // Filters out hours that are out of the min/max bounds
767
+ const filteredHours = hourValues.filter((hour) => {
768
+ if ((minParts === null || minParts === void 0 ? void 0 : minParts.hour) !== undefined && isSameDay(copyParts, minParts) && hour < minParts.hour) {
769
+ return false;
770
+ }
771
+ if ((maxParts === null || maxParts === void 0 ? void 0 : maxParts.hour) !== undefined && isSameDay(copyParts, maxParts) && hour > maxParts.hour) {
772
+ return false;
773
+ }
774
+ return true;
775
+ });
776
+ copyParts.hour = findClosestValue(hour, filteredHours);
743
777
  copyParts.ampm = parseAmPm(copyParts.hour);
744
778
  }
745
779
  if (minute !== undefined && minuteValues !== undefined) {
746
- copyParts.minute = findClosestValue(minute, minuteValues);
780
+ // Filters out minutes that are out of the min/max bounds
781
+ const filteredMinutes = minuteValues.filter((minute) => {
782
+ if ((minParts === null || minParts === void 0 ? void 0 : minParts.minute) !== undefined &&
783
+ isSameDay(copyParts, minParts) &&
784
+ copyParts.hour === minParts.hour &&
785
+ minute < minParts.minute) {
786
+ return false;
787
+ }
788
+ if ((maxParts === null || maxParts === void 0 ? void 0 : maxParts.minute) !== undefined &&
789
+ isSameDay(copyParts, maxParts) &&
790
+ copyParts.hour === maxParts.hour &&
791
+ minute > maxParts.minute) {
792
+ return false;
793
+ }
794
+ return true;
795
+ });
796
+ copyParts.minute = findClosestValue(minute, filteredMinutes);
747
797
  }
748
798
  return copyParts;
749
799
  };
@@ -10,7 +10,7 @@ const helpers = require('./helpers-76bb7efb.js');
10
10
  const index$1 = require('./index-5915f9b3.js');
11
11
  const theme = require('./theme-d1c573d2.js');
12
12
  const ionicGlobal = require('./ionic-global-f4a2093b.js');
13
- const data = require('./data-36b9094e.js');
13
+ const data = require('./data-a5109f09.js');
14
14
 
15
15
  const iosDatetimeButtonCss = ":host{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center}:host button{border-radius:8px;-webkit-padding-start:12px;padding-inline-start:12px;-webkit-padding-end:12px;padding-inline-end:12px;padding-top:6px;padding-bottom:6px;-webkit-margin-start:2px;margin-inline-start:2px;-webkit-margin-end:2px;margin-inline-end:2px;margin-top:0px;margin-bottom:0px;position:relative;-webkit-transition:150ms color ease-in-out;transition:150ms color ease-in-out;border:none;background:var(--ion-color-step-300, #edeef0);color:var(--ion-text-color, #000);font-family:inherit;font-size:1rem;cursor:pointer;overflow:hidden;-webkit-appearance:none;-moz-appearance:none;appearance:none}:host(.time-active) #time-button,:host(.date-active) #date-button{color:var(--ion-color-base)}:host(.datetime-button-disabled){pointer-events:none}:host(.datetime-button-disabled) button{opacity:0.4}";
16
16
 
@@ -13,7 +13,7 @@ const dir = require('./dir-94c21456.js');
13
13
  const theme = require('./theme-d1c573d2.js');
14
14
  const index$2 = require('./index-09471526.js');
15
15
  const ionicGlobal = require('./ionic-global-f4a2093b.js');
16
- const data = require('./data-36b9094e.js');
16
+ const data = require('./data-a5109f09.js');
17
17
  const lockController = require('./lock-controller-6585a42a.js');
18
18
  const overlays = require('./overlays-27a6fb16.js');
19
19
  const animation = require('./animation-9b401d39.js');
@@ -866,14 +866,24 @@ const Datetime = class {
866
866
  * or modal that the datetime was presented in.
867
867
  */
868
868
  async confirm(closeOverlay = false) {
869
- const { isCalendarPicker, activeParts } = this;
869
+ const { isCalendarPicker, activeParts, preferWheel, workingParts } = this;
870
870
  /**
871
871
  * We only update the value if the presentation is not a calendar picker.
872
872
  */
873
873
  if (activeParts !== undefined || !isCalendarPicker) {
874
874
  const activePartsIsArray = Array.isArray(activeParts);
875
875
  if (activePartsIsArray && activeParts.length === 0) {
876
- this.setValue(undefined);
876
+ if (preferWheel) {
877
+ /**
878
+ * If the datetime is using a wheel picker, but the
879
+ * active parts are empty, then the user has confirmed the
880
+ * initial value (working parts) presented to them.
881
+ */
882
+ this.setValue(data.convertDataToISO(workingParts));
883
+ }
884
+ else {
885
+ this.setValue(undefined);
886
+ }
877
887
  }
878
888
  else {
879
889
  this.setValue(data.convertDataToISO(activeParts));
@@ -1077,9 +1087,18 @@ const Datetime = class {
1077
1087
  const yearValues = (this.parsedYearValues = data.convertToArrayOfNumbers(this.yearValues));
1078
1088
  const dayValues = (this.parsedDayValues = data.convertToArrayOfNumbers(this.dayValues));
1079
1089
  const todayParts = (this.todayParts = data.parseDate(data.getToday()));
1080
- this.defaultParts = data.getClosestValidDate(todayParts, monthValues, dayValues, yearValues, hourValues, minuteValues);
1081
1090
  this.processMinParts();
1082
1091
  this.processMaxParts();
1092
+ this.defaultParts = data.getClosestValidDate({
1093
+ refParts: todayParts,
1094
+ monthValues,
1095
+ dayValues,
1096
+ yearValues,
1097
+ hourValues,
1098
+ minuteValues,
1099
+ minParts: this.minParts,
1100
+ maxParts: this.maxParts,
1101
+ });
1083
1102
  this.processValue(this.value);
1084
1103
  this.emitStyle();
1085
1104
  }
@@ -704,14 +704,24 @@ export class Datetime {
704
704
  * or modal that the datetime was presented in.
705
705
  */
706
706
  async confirm(closeOverlay = false) {
707
- const { isCalendarPicker, activeParts } = this;
707
+ const { isCalendarPicker, activeParts, preferWheel, workingParts } = this;
708
708
  /**
709
709
  * We only update the value if the presentation is not a calendar picker.
710
710
  */
711
711
  if (activeParts !== undefined || !isCalendarPicker) {
712
712
  const activePartsIsArray = Array.isArray(activeParts);
713
713
  if (activePartsIsArray && activeParts.length === 0) {
714
- this.setValue(undefined);
714
+ if (preferWheel) {
715
+ /**
716
+ * If the datetime is using a wheel picker, but the
717
+ * active parts are empty, then the user has confirmed the
718
+ * initial value (working parts) presented to them.
719
+ */
720
+ this.setValue(convertDataToISO(workingParts));
721
+ }
722
+ else {
723
+ this.setValue(undefined);
724
+ }
715
725
  }
716
726
  else {
717
727
  this.setValue(convertDataToISO(activeParts));
@@ -915,9 +925,18 @@ export class Datetime {
915
925
  const yearValues = (this.parsedYearValues = convertToArrayOfNumbers(this.yearValues));
916
926
  const dayValues = (this.parsedDayValues = convertToArrayOfNumbers(this.dayValues));
917
927
  const todayParts = (this.todayParts = parseDate(getToday()));
918
- this.defaultParts = getClosestValidDate(todayParts, monthValues, dayValues, yearValues, hourValues, minuteValues);
919
928
  this.processMinParts();
920
929
  this.processMaxParts();
930
+ this.defaultParts = getClosestValidDate({
931
+ refParts: todayParts,
932
+ monthValues,
933
+ dayValues,
934
+ yearValues,
935
+ hourValues,
936
+ minuteValues,
937
+ minParts: this.minParts,
938
+ maxParts: this.maxParts,
939
+ });
921
940
  this.processValue(this.value);
922
941
  this.emitStyle();
923
942
  }
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * (C) Ionic http://ionicframework.com - MIT License
3
3
  */
4
- import { getPreviousYear, getNextYear, getPreviousMonth, getNextMonth, getPreviousDay, getNextDay, getPreviousWeek, getNextWeek, getEndOfWeek, getStartOfWeek, convert12HourTo24Hour, getInternalHourValue, calculateHourFromAMPM, subtractDays, addDays, validateParts, } from "../utils/manipulation";
4
+ import { getPreviousYear, getNextYear, getPreviousMonth, getNextMonth, getPreviousDay, getNextDay, getPreviousWeek, getNextWeek, getEndOfWeek, getStartOfWeek, convert12HourTo24Hour, getInternalHourValue, calculateHourFromAMPM, subtractDays, addDays, validateParts, getClosestValidDate, } from "../utils/manipulation";
5
5
  describe('addDays()', () => {
6
6
  it('should correctly add days', () => {
7
7
  expect(addDays({
@@ -431,3 +431,135 @@ describe('validateParts()', () => {
431
431
  })).toEqual({ month: 1, day: 1, year: 2022, hour: 9, minute: 30 });
432
432
  });
433
433
  });
434
+ describe('getClosestValidDate()', () => {
435
+ it('should match a date with only month/day/year', () => {
436
+ // October 10, 2023
437
+ const refParts = { month: 10, day: 10, year: 2023 };
438
+ // April 10, 2021
439
+ const minParts = { month: 4, day: 10, year: 2021 };
440
+ // September 14, 2021
441
+ const maxParts = { month: 9, day: 14, year: 2021 };
442
+ // September 4, 2021
443
+ const expected = { month: 9, day: 4, year: 2021, dayOfWeek: undefined };
444
+ expect(getClosestValidDate({
445
+ refParts,
446
+ monthValues: [2, 3, 7, 9, 10],
447
+ dayValues: [4, 15, 25],
448
+ yearValues: [2020, 2021, 2023],
449
+ maxParts,
450
+ minParts,
451
+ })).toEqual(expected);
452
+ });
453
+ it('should match a date when the reference date is before the min', () => {
454
+ // April 2, 2020 3:20 PM
455
+ const refParts = { month: 4, day: 2, year: 2020, hour: 15, minute: 20 };
456
+ // September 10, 2021 10:10 AM
457
+ const minParts = { month: 9, day: 10, year: 2021, hour: 10, minute: 10 };
458
+ // September 14, 2021 10:11 AM
459
+ const maxParts = { month: 9, day: 14, year: 2021, hour: 10, minute: 11 };
460
+ // September 11, 2021 11:15 AM
461
+ const expected = {
462
+ year: 2021,
463
+ day: 11,
464
+ month: 9,
465
+ hour: 11,
466
+ minute: 15,
467
+ ampm: 'am',
468
+ dayOfWeek: undefined,
469
+ };
470
+ expect(getClosestValidDate({
471
+ refParts,
472
+ monthValues: [4, 9, 11],
473
+ dayValues: [11, 12, 13, 14],
474
+ yearValues: [2020, 2021, 2023],
475
+ hourValues: [9, 10, 11],
476
+ minuteValues: [11, 12, 13, 14, 15],
477
+ maxParts,
478
+ minParts,
479
+ })).toEqual(expected);
480
+ });
481
+ it('should match a date when the reference date is before the min', () => {
482
+ // April 2, 2020 3:20 PM
483
+ const refParts = { month: 4, day: 2, year: 2020, hour: 15, minute: 20 };
484
+ // September 10, 2021 10:10 AM
485
+ const minParts = { month: 9, day: 10, year: 2021, hour: 10, minute: 10 };
486
+ // September 10, 2021 10:15 AM
487
+ const maxParts = { month: 9, day: 10, year: 2021, hour: 10, minute: 15 };
488
+ // September 10, 2021 10:15 AM
489
+ const expected = {
490
+ month: 9,
491
+ day: 10,
492
+ year: 2021,
493
+ hour: 10,
494
+ minute: 15,
495
+ ampm: 'am',
496
+ dayOfWeek: undefined,
497
+ };
498
+ expect(getClosestValidDate({
499
+ refParts,
500
+ monthValues: [4, 9, 11],
501
+ dayValues: [10, 12, 13, 14],
502
+ yearValues: [2020, 2021, 2023],
503
+ hourValues: [9, 10, 11],
504
+ minuteValues: [11, 12, 13, 14, 15],
505
+ minParts,
506
+ maxParts,
507
+ })).toEqual(expected);
508
+ });
509
+ it('should only clamp minutes if within the same day and hour as min/max', () => {
510
+ // April 2, 2020 9:16 AM
511
+ const refParts = { month: 4, day: 2, year: 2020, hour: 9, minute: 16 };
512
+ // September 10, 2021 10:10 AM
513
+ const minParts = { month: 9, day: 10, year: 2021, hour: 10, minute: 10 };
514
+ // September 10, 2021 11:15 AM
515
+ const maxParts = { month: 9, day: 10, year: 2021, hour: 11, minute: 15 };
516
+ // September 10, 2021 10:16 AM
517
+ const expected = {
518
+ month: 9,
519
+ day: 10,
520
+ year: 2021,
521
+ hour: 10,
522
+ minute: 16,
523
+ ampm: 'am',
524
+ dayOfWeek: undefined,
525
+ };
526
+ expect(getClosestValidDate({
527
+ refParts,
528
+ monthValues: [4, 9, 11],
529
+ dayValues: [10, 12, 13, 14],
530
+ yearValues: [2020, 2021, 2023],
531
+ hourValues: [9, 10, 11],
532
+ minuteValues: [10, 15, 16],
533
+ minParts,
534
+ maxParts,
535
+ })).toEqual(expected);
536
+ });
537
+ it('should return the closest valid date after adjusting the allowed year', () => {
538
+ // April 2, 2022 9:16 AM
539
+ const refParts = { month: 4, day: 2, year: 2022, hour: 9, minute: 16 };
540
+ // September 10, 2021 10:10 AM
541
+ const minParts = { month: 9, day: 10, year: 2021, hour: 10, minute: 10 };
542
+ // September 10, 2023 11:15 AM
543
+ const maxParts = { month: 9, day: 10, year: 2023, hour: 11, minute: 15 };
544
+ // April 2, 2022 9:16 AM
545
+ const expected = {
546
+ month: 4,
547
+ day: 2,
548
+ year: 2022,
549
+ hour: 9,
550
+ minute: 16,
551
+ ampm: 'am',
552
+ dayOfWeek: undefined,
553
+ };
554
+ expect(getClosestValidDate({
555
+ refParts,
556
+ monthValues: [4, 9, 11],
557
+ dayValues: [2, 10, 12, 13, 14],
558
+ yearValues: [2020, 2021, 2022, 2023],
559
+ hourValues: [9, 10, 11],
560
+ minuteValues: [10, 15, 16],
561
+ minParts,
562
+ maxParts,
563
+ })).toEqual(expected);
564
+ });
565
+ });
@@ -0,0 +1,27 @@
1
+ /*!
2
+ * (C) Ionic http://ionicframework.com - MIT License
3
+ */
4
+ import { newSpecPage } from "@stencil/core/testing";
5
+ import { Datetime } from "../../datetime";
6
+ describe('datetime: preferWheel', () => {
7
+ beforeEach(() => {
8
+ const mockIntersectionObserver = jest.fn();
9
+ mockIntersectionObserver.mockReturnValue({
10
+ observe: () => null,
11
+ unobserve: () => null,
12
+ disconnect: () => null,
13
+ });
14
+ global.IntersectionObserver = mockIntersectionObserver;
15
+ });
16
+ it('should select the working day when clicking the confirm button', async () => {
17
+ const page = await newSpecPage({
18
+ components: [Datetime],
19
+ html: '<ion-datetime prefer-wheel="true" max="2021" show-default-buttons="true"></ion-datetime>',
20
+ });
21
+ const datetime = page.body.querySelector('ion-datetime');
22
+ const confirmButton = datetime.shadowRoot.querySelector('#confirm-button');
23
+ confirmButton.click();
24
+ await page.waitForChanges();
25
+ expect(datetime.value).toBe('2021-12-31T23:59:00');
26
+ });
27
+ });
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * (C) Ionic http://ionicframework.com - MIT License
3
3
  */
4
- import { isSameDay } from "./comparison";
4
+ import { isAfter, isBefore, isSameDay } from "./comparison";
5
5
  import { getNumDaysInMonth } from "./helpers";
6
6
  import { clampDate, parseAmPm } from "./parse";
7
7
  const twoDigit = (val) => {
@@ -355,32 +355,82 @@ export const validateParts = (parts, minParts, maxParts) => {
355
355
  * Returns the closest date to refParts
356
356
  * that also meets the constraints of
357
357
  * the *Values params.
358
- * @param refParts The reference date
359
- * @param monthValues The allowed month values
360
- * @param dayValues The allowed day (of the month) values
361
- * @param yearValues The allowed year values
362
- * @param hourValues The allowed hour values
363
- * @param minuteValues The allowed minute values
364
358
  */
365
- export const getClosestValidDate = (refParts, monthValues, dayValues, yearValues, hourValues, minuteValues) => {
359
+ export const getClosestValidDate = ({ refParts, monthValues, dayValues, yearValues, hourValues, minuteValues, minParts, maxParts, }) => {
366
360
  const { hour, minute, day, month, year } = refParts;
367
361
  const copyParts = Object.assign(Object.assign({}, refParts), { dayOfWeek: undefined });
362
+ if (yearValues !== undefined) {
363
+ // Filters out years that are out of the min/max bounds
364
+ const filteredYears = yearValues.filter((year) => {
365
+ if (minParts !== undefined && year < minParts.year) {
366
+ return false;
367
+ }
368
+ if (maxParts !== undefined && year > maxParts.year) {
369
+ return false;
370
+ }
371
+ return true;
372
+ });
373
+ copyParts.year = findClosestValue(year, filteredYears);
374
+ }
368
375
  if (monthValues !== undefined) {
369
- copyParts.month = findClosestValue(month, monthValues);
376
+ // Filters out months that are out of the min/max bounds
377
+ const filteredMonths = monthValues.filter((month) => {
378
+ if (minParts !== undefined && copyParts.year === minParts.year && month < minParts.month) {
379
+ return false;
380
+ }
381
+ if (maxParts !== undefined && copyParts.year === maxParts.year && month > maxParts.month) {
382
+ return false;
383
+ }
384
+ return true;
385
+ });
386
+ copyParts.month = findClosestValue(month, filteredMonths);
370
387
  }
371
388
  // Day is nullable but cannot be undefined
372
389
  if (day !== null && dayValues !== undefined) {
373
- copyParts.day = findClosestValue(day, dayValues);
374
- }
375
- if (yearValues !== undefined) {
376
- copyParts.year = findClosestValue(year, yearValues);
390
+ // Filters out days that are out of the min/max bounds
391
+ const filteredDays = dayValues.filter((day) => {
392
+ if (minParts !== undefined && isBefore(Object.assign(Object.assign({}, copyParts), { day }), minParts)) {
393
+ return false;
394
+ }
395
+ if (maxParts !== undefined && isAfter(Object.assign(Object.assign({}, copyParts), { day }), maxParts)) {
396
+ return false;
397
+ }
398
+ return true;
399
+ });
400
+ copyParts.day = findClosestValue(day, filteredDays);
377
401
  }
378
402
  if (hour !== undefined && hourValues !== undefined) {
379
- copyParts.hour = findClosestValue(hour, hourValues);
403
+ // Filters out hours that are out of the min/max bounds
404
+ const filteredHours = hourValues.filter((hour) => {
405
+ if ((minParts === null || minParts === void 0 ? void 0 : minParts.hour) !== undefined && isSameDay(copyParts, minParts) && hour < minParts.hour) {
406
+ return false;
407
+ }
408
+ if ((maxParts === null || maxParts === void 0 ? void 0 : maxParts.hour) !== undefined && isSameDay(copyParts, maxParts) && hour > maxParts.hour) {
409
+ return false;
410
+ }
411
+ return true;
412
+ });
413
+ copyParts.hour = findClosestValue(hour, filteredHours);
380
414
  copyParts.ampm = parseAmPm(copyParts.hour);
381
415
  }
382
416
  if (minute !== undefined && minuteValues !== undefined) {
383
- copyParts.minute = findClosestValue(minute, minuteValues);
417
+ // Filters out minutes that are out of the min/max bounds
418
+ const filteredMinutes = minuteValues.filter((minute) => {
419
+ if ((minParts === null || minParts === void 0 ? void 0 : minParts.minute) !== undefined &&
420
+ isSameDay(copyParts, minParts) &&
421
+ copyParts.hour === minParts.hour &&
422
+ minute < minParts.minute) {
423
+ return false;
424
+ }
425
+ if ((maxParts === null || maxParts === void 0 ? void 0 : maxParts.minute) !== undefined &&
426
+ isSameDay(copyParts, maxParts) &&
427
+ copyParts.hour === maxParts.hour &&
428
+ minute > maxParts.minute) {
429
+ return false;
430
+ }
431
+ return true;
432
+ });
433
+ copyParts.minute = findClosestValue(minute, filteredMinutes);
384
434
  }
385
435
  return copyParts;
386
436
  };
package/dist/docs.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "timestamp": "2023-12-08T15:17:06",
2
+ "timestamp": "2023-12-11T19:26:40",
3
3
  "compiler": {
4
4
  "name": "@stencil/core",
5
5
  "version": "4.8.1",