@@ -85,17 +85,6 @@ export class Datetime implements ComponentInterface {
85
85
private calendarBodyRef ?: HTMLElement ;
86
86
private popoverRef ?: HTMLIonPopoverElement ;
87
87
private clearFocusVisible ?: ( ) => void ;
88
-
89
- /**
90
- * Whether to highlight the active day with a solid circle (as opposed
91
- * to the outline circle around today). If you don't specify an initial
92
- * value for the datetime, it doesn't automatically init to a default to
93
- * avoid unwanted change events firing. If the solid circle were still
94
- * shown then, it would look like a date had already been selected, which
95
- * is misleading UX.
96
- */
97
- private highlightActiveParts = false ;
98
-
99
88
private parsedMinuteValues ?: number [ ] ;
100
89
private parsedHourValues ?: number [ ] ;
101
90
private parsedMonthValues ?: number [ ] ;
@@ -115,18 +104,11 @@ export class Datetime implements ComponentInterface {
115
104
* Duplicate reference to `activeParts` that does not trigger a re-render of the component.
116
105
* Allows caching an instance of the `activeParts` in between render cycles.
117
106
*/
118
- private activePartsClone ! : DatetimeParts | DatetimeParts [ ] ;
107
+ private activePartsClone : DatetimeParts | DatetimeParts [ ] = [ ] ;
119
108
120
109
@State ( ) showMonthAndYear = false ;
121
110
122
- @State ( ) activeParts : DatetimeParts | DatetimeParts [ ] = {
123
- month : 5 ,
124
- day : 28 ,
125
- year : 2021 ,
126
- hour : 13 ,
127
- minute : 52 ,
128
- ampm : 'pm' ,
129
- } ;
111
+ @State ( ) activeParts : DatetimeParts | DatetimeParts [ ] = [ ] ;
130
112
131
113
@State ( ) workingParts : DatetimeParts = {
132
114
month : 5 ,
@@ -506,16 +488,12 @@ export class Datetime implements ComponentInterface {
506
488
*/
507
489
@Method ( )
508
490
async confirm ( closeOverlay = false ) {
509
- const { highlightActiveParts , isCalendarPicker, activeParts } = this ;
491
+ const { isCalendarPicker, activeParts } = this ;
510
492
511
493
/**
512
- * We only update the value if the presentation is not a calendar picker,
513
- * or if `highlightActiveParts` is true; indicating that the user
514
- * has selected a date from the calendar picker.
515
- *
516
- * Otherwise "today" would accidentally be set as the value.
494
+ * We only update the value if the presentation is not a calendar picker.
517
495
*/
518
- if ( highlightActiveParts || ! isCalendarPicker ) {
496
+ if ( activeParts !== undefined || ! isCalendarPicker ) {
519
497
const activePartsIsArray = Array . isArray ( activeParts ) ;
520
498
if ( activePartsIsArray && activeParts . length === 0 ) {
521
499
this . value = undefined ;
@@ -573,6 +551,23 @@ export class Datetime implements ComponentInterface {
573
551
}
574
552
}
575
553
554
+ /**
555
+ * Returns the DatetimePart interface
556
+ * to use when rendering an initial set of
557
+ * data. This should be used when rendering an
558
+ * interface in an environment where the `value`
559
+ * may not be set. This function works
560
+ * by returning the first selected date in
561
+ * "activePartsClone" and then falling back to
562
+ * today's DatetimeParts if no active date is selected.
563
+ */
564
+ private getDefaultPart = ( ) => {
565
+ const { activePartsClone, todayParts } = this ;
566
+
567
+ const firstPart = Array . isArray ( activePartsClone ) ? activePartsClone [ 0 ] : activePartsClone ;
568
+ return firstPart ?? todayParts ;
569
+ } ;
570
+
576
571
private closeParentOverlay = ( ) => {
577
572
const popoverOrModal = this . el . closest ( 'ion-modal, ion-popover' ) as
578
573
| HTMLIonModalElement
@@ -590,7 +585,7 @@ export class Datetime implements ComponentInterface {
590
585
} ;
591
586
592
587
private setActiveParts = ( parts : DatetimeParts , removeDate = false ) => {
593
- const { multiple, activePartsClone, highlightActiveParts } = this ;
588
+ const { multiple, activePartsClone } = this ;
594
589
595
590
/**
596
591
* When setting the active parts, it is possible
@@ -618,34 +613,15 @@ export class Datetime implements ComponentInterface {
618
613
const activePartsArray = Array . isArray ( activePartsClone ) ? activePartsClone : [ activePartsClone ] ;
619
614
if ( removeDate ) {
620
615
this . activeParts = activePartsArray . filter ( ( p ) => ! isSameDay ( p , validatedParts ) ) ;
621
- } else if ( highlightActiveParts ) {
622
- this . activeParts = [ ...activePartsArray , validatedParts ] ;
623
616
} else {
624
- /**
625
- * If highlightActiveParts is false, that means we just have a
626
- * default value of today in activeParts; we need to replace that
627
- * rather than adding to it since it's just a placeholder.
628
- */
629
- this . activeParts = [ validatedParts ] ;
617
+ this . activeParts = [ ...activePartsArray , validatedParts ] ;
630
618
}
631
619
} else {
632
620
this . activeParts = {
633
621
...validatedParts ,
634
622
} ;
635
623
}
636
624
637
- /**
638
- * Now that the user has interacted somehow to select something, we can
639
- * show the solid highlight. This needs to be done after checking it above,
640
- * but before the confirm call below.
641
- *
642
- * Note that for datetimes with confirm/cancel buttons, the value
643
- * isn't updated until you call confirm(). We need to bring the
644
- * solid circle back on day click for UX reasons, rather than only
645
- * show the circle if `value` is truthy.
646
- */
647
- this . highlightActiveParts = true ;
648
-
649
625
const hasSlottedButtons = this . el . querySelector ( '[slot="buttons"]' ) !== null ;
650
626
if ( hasSlottedButtons || this . showDefaultButtons ) {
651
627
return ;
@@ -1178,7 +1154,7 @@ export class Datetime implements ComponentInterface {
1178
1154
}
1179
1155
1180
1156
private processValue = ( value ?: string | string [ ] | null ) => {
1181
- const hasValue = ( this . highlightActiveParts = value !== null && value !== undefined ) ;
1157
+ const hasValue = value !== null && value !== undefined ;
1182
1158
let valueToProcess = parseDate ( value ?? getToday ( ) ) ;
1183
1159
1184
1160
const { minParts, maxParts, multiple } = this ;
@@ -1219,18 +1195,26 @@ export class Datetime implements ComponentInterface {
1219
1195
ampm,
1220
1196
} ) ;
1221
1197
1222
- if ( Array . isArray ( valueToProcess ) ) {
1223
- this . activeParts = [ ...valueToProcess ] ;
1224
- } else {
1225
- this . activeParts = {
1226
- month,
1227
- day,
1228
- year,
1229
- hour,
1230
- minute,
1231
- tzOffset,
1232
- ampm,
1233
- } ;
1198
+ /**
1199
+ * Since `activeParts` indicates a value that
1200
+ * been explicitly selected either by the
1201
+ * user or the app, only update `activeParts`
1202
+ * if the `value` property is set.
1203
+ */
1204
+ if ( hasValue ) {
1205
+ if ( Array . isArray ( valueToProcess ) ) {
1206
+ this . activeParts = [ ...valueToProcess ] ;
1207
+ } else {
1208
+ this . activeParts = {
1209
+ month,
1210
+ day,
1211
+ year,
1212
+ hour,
1213
+ minute,
1214
+ tzOffset,
1215
+ ampm,
1216
+ } ;
1217
+ }
1234
1218
}
1235
1219
} ;
1236
1220
@@ -1747,13 +1731,15 @@ export class Datetime implements ComponentInterface {
1747
1731
}
1748
1732
1749
1733
private renderHourPickerColumn ( hoursData : PickerColumnItem [ ] ) {
1750
- const { workingParts, activePartsClone } = this ;
1734
+ const { workingParts } = this ;
1751
1735
if ( hoursData . length === 0 ) return [ ] ;
1752
1736
1737
+ const activePart = this . getDefaultPart ( ) ;
1738
+
1753
1739
return (
1754
1740
< ion-picker-column-internal
1755
1741
color = { this . color }
1756
- value = { ( activePartsClone as DatetimeParts ) . hour }
1742
+ value = { activePart . hour }
1757
1743
items = { hoursData }
1758
1744
numericInput
1759
1745
onIonChange = { ( ev : CustomEvent ) => {
@@ -1762,9 +1748,9 @@ export class Datetime implements ComponentInterface {
1762
1748
hour : ev . detail . value ,
1763
1749
} ) ;
1764
1750
1765
- if ( ! Array . isArray ( activePartsClone ) ) {
1751
+ if ( ! Array . isArray ( activePart ) ) {
1766
1752
this . setActiveParts ( {
1767
- ...activePartsClone ,
1753
+ ...activePart ,
1768
1754
hour : ev . detail . value ,
1769
1755
} ) ;
1770
1756
}
@@ -1775,13 +1761,15 @@ export class Datetime implements ComponentInterface {
1775
1761
) ;
1776
1762
}
1777
1763
private renderMinutePickerColumn ( minutesData : PickerColumnItem [ ] ) {
1778
- const { workingParts, activePartsClone } = this ;
1764
+ const { workingParts } = this ;
1779
1765
if ( minutesData . length === 0 ) return [ ] ;
1780
1766
1767
+ const activePart = this . getDefaultPart ( ) ;
1768
+
1781
1769
return (
1782
1770
< ion-picker-column-internal
1783
1771
color = { this . color }
1784
- value = { ( activePartsClone as DatetimeParts ) . minute }
1772
+ value = { activePart . minute }
1785
1773
items = { minutesData }
1786
1774
numericInput
1787
1775
onIonChange = { ( ev : CustomEvent ) => {
@@ -1790,9 +1778,9 @@ export class Datetime implements ComponentInterface {
1790
1778
minute : ev . detail . value ,
1791
1779
} ) ;
1792
1780
1793
- if ( ! Array . isArray ( activePartsClone ) ) {
1781
+ if ( ! Array . isArray ( activePart ) ) {
1794
1782
this . setActiveParts ( {
1795
- ...activePartsClone ,
1783
+ ...activePart ,
1796
1784
minute : ev . detail . value ,
1797
1785
} ) ;
1798
1786
}
@@ -1803,18 +1791,19 @@ export class Datetime implements ComponentInterface {
1803
1791
) ;
1804
1792
}
1805
1793
private renderDayPeriodPickerColumn ( dayPeriodData : PickerColumnItem [ ] ) {
1806
- const { workingParts, activePartsClone } = this ;
1794
+ const { workingParts } = this ;
1807
1795
if ( dayPeriodData . length === 0 ) {
1808
1796
return [ ] ;
1809
1797
}
1810
1798
1799
+ const activePart = this . getDefaultPart ( ) ;
1811
1800
const isDayPeriodRTL = isLocaleDayPeriodRTL ( this . locale ) ;
1812
1801
1813
1802
return (
1814
1803
< ion-picker-column-internal
1815
1804
style = { isDayPeriodRTL ? { order : '-1' } : { } }
1816
1805
color = { this . color }
1817
- value = { ( activePartsClone as DatetimeParts ) . ampm }
1806
+ value = { activePart . ampm }
1818
1807
items = { dayPeriodData }
1819
1808
onIonChange = { ( ev : CustomEvent ) => {
1820
1809
const hour = calculateHourFromAMPM ( workingParts , ev . detail . value ) ;
@@ -1825,9 +1814,9 @@ export class Datetime implements ComponentInterface {
1825
1814
hour,
1826
1815
} ) ;
1827
1816
1828
- if ( ! Array . isArray ( activePartsClone ) ) {
1817
+ if ( ! Array . isArray ( activePart ) ) {
1829
1818
this . setActiveParts ( {
1830
- ...activePartsClone ,
1819
+ ...activePart ,
1831
1820
ampm : ev . detail . value ,
1832
1821
hour,
1833
1822
} ) ;
@@ -1901,7 +1890,6 @@ export class Datetime implements ComponentInterface {
1901
1890
) ;
1902
1891
}
1903
1892
private renderMonth ( month : number , year : number ) {
1904
- const { highlightActiveParts } = this ;
1905
1893
const yearAllowed = this . parsedYearValues === undefined || this . parsedYearValues . includes ( year ) ;
1906
1894
const monthAllowed = this . parsedMonthValues === undefined || this . parsedMonthValues . includes ( month ) ;
1907
1895
const isCalMonthDisabled = ! yearAllowed || ! monthAllowed ;
@@ -1979,7 +1967,7 @@ export class Datetime implements ComponentInterface {
1979
1967
class = { {
1980
1968
'calendar-day-padding' : day === null ,
1981
1969
'calendar-day' : true ,
1982
- 'calendar-day-active' : isActive && highlightActiveParts ,
1970
+ 'calendar-day-active' : isActive ,
1983
1971
'calendar-day-today' : isToday ,
1984
1972
} }
1985
1973
aria-selected = { ariaSelected }
@@ -2004,7 +1992,7 @@ export class Datetime implements ComponentInterface {
2004
1992
day,
2005
1993
year,
2006
1994
} ,
2007
- isActive && highlightActiveParts
1995
+ isActive
2008
1996
) ;
2009
1997
} else {
2010
1998
this . setActiveParts ( {
@@ -2052,6 +2040,8 @@ export class Datetime implements ComponentInterface {
2052
2040
2053
2041
private renderTimeOverlay ( ) {
2054
2042
const use24Hour = is24Hour ( this . locale , this . hourCycle ) ;
2043
+ const activePart = this . getDefaultPart ( ) ;
2044
+
2055
2045
return [
2056
2046
< div class = "time-header" > { this . renderTimeLabel ( ) } </ div > ,
2057
2047
< button
@@ -2081,7 +2071,7 @@ export class Datetime implements ComponentInterface {
2081
2071
}
2082
2072
} }
2083
2073
>
2084
- { getLocalizedTime ( this . locale , this . activePartsClone as DatetimeParts , use24Hour ) }
2074
+ { getLocalizedTime ( this . locale , activePart , use24Hour ) }
2085
2075
</ button > ,
2086
2076
< ion-popover
2087
2077
alignment = "center"
@@ -2135,7 +2125,7 @@ export class Datetime implements ComponentInterface {
2135
2125
}
2136
2126
} else {
2137
2127
// for exactly 1 day selected (multiple set or not), show a formatted version of that
2138
- headerText = getMonthAndDay ( this . locale , isArray ? activeParts [ 0 ] : activeParts ) ;
2128
+ headerText = getMonthAndDay ( this . locale , this . getDefaultPart ( ) ) ;
2139
2129
}
2140
2130
2141
2131
return (
0 commit comments