Skip to content

Commit af7472b

Browse files
- add styles for hidden day button;
- add showDaysOutsideCurrentMonth property to datetime component; - change month generation to respect new property;
1 parent cd5c27a commit af7472b

File tree

9 files changed

+109
-25
lines changed

9 files changed

+109
-25
lines changed

core/api.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,7 @@ ion-datetime,prop,preferWheel,boolean,false,false,false
529529
ion-datetime,prop,presentation,"date" | "date-time" | "month" | "month-year" | "time" | "time-date" | "year",'date-time',false,false
530530
ion-datetime,prop,readonly,boolean,false,false,false
531531
ion-datetime,prop,showClearButton,boolean,false,false,false
532+
ion-datetime,prop,showDaysOutsideCurrentMonth,boolean | undefined,false,false,false
532533
ion-datetime,prop,showDefaultButtons,boolean,false,false,false
533534
ion-datetime,prop,showDefaultTimeLabel,boolean,true,false,false
534535
ion-datetime,prop,showDefaultTitle,boolean,false,false,false

core/src/components.d.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -936,6 +936,10 @@ export namespace Components {
936936
* If `true`, a "Clear" button will be rendered alongside the default "Cancel" and "OK" buttons at the bottom of the `ion-datetime` component. Developers can also use the `button` slot if they want to customize these buttons. If custom buttons are set in the `button` slot then the default buttons will not be rendered.
937937
*/
938938
"showClearButton": boolean;
939+
/**
940+
* If `true`, the datetime will show the last days of the previous month and the first days of the next month on a table of 42 elements.
941+
*/
942+
"showDaysOutsideCurrentMonth"?: boolean;
939943
/**
940944
* If `true`, the default "Cancel" and "OK" buttons will be rendered at the bottom of the `ion-datetime` component. Developers can also use the `button` slot if they want to customize these buttons. If custom buttons are set in the `button` slot then the default buttons will not be rendered.
941945
*/
@@ -5723,6 +5727,10 @@ declare namespace LocalJSX {
57235727
* If `true`, a "Clear" button will be rendered alongside the default "Cancel" and "OK" buttons at the bottom of the `ion-datetime` component. Developers can also use the `button` slot if they want to customize these buttons. If custom buttons are set in the `button` slot then the default buttons will not be rendered.
57245728
*/
57255729
"showClearButton"?: boolean;
5730+
/**
5731+
* If `true`, the datetime will show the last days of the previous month and the first days of the next month on a table of 42 elements.
5732+
*/
5733+
"showDaysOutsideCurrentMonth"?: boolean;
57265734
/**
57275735
* If `true`, the default "Cancel" and "OK" buttons will be rendered at the bottom of the `ion-datetime` component. Developers can also use the `button` slot if they want to customize these buttons. If custom buttons are set in the `button` slot then the default buttons will not be rendered.
57285736
*/

core/src/components/datetime/datetime-interface.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export interface DatetimeParts {
1515
hour?: number;
1616
minute?: number;
1717
ampm?: 'am' | 'pm';
18+
hiddenDay?: boolean,
1819
}
1920

2021
export type DatetimePresentation = 'date-time' | 'time-date' | 'date' | 'time' | 'month' | 'year' | 'month-year';

core/src/components/datetime/datetime.scss

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,11 @@
364364
opacity: 0.4;
365365
}
366366

367-
.calendar-day:focus {
367+
:host .calendar-day.calendar-day-hidden-day {
368+
opacity: 0.4;
369+
}
370+
371+
.calendar-day:not(.calendar-day-hidden-day):focus {
368372
background: current-color(base, 0.2);
369373

370374
box-shadow: 0px 0px 0px 4px current-color(base, 0.2);

core/src/components/datetime/datetime.tsx

Lines changed: 52 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ export class Datetime implements ComponentInterface {
139139
hour: 13,
140140
minute: 52,
141141
ampm: 'pm',
142+
hiddenDay: false,
142143
};
143144

144145
@Element() el!: HTMLIonDatetimeElement;
@@ -207,6 +208,11 @@ export class Datetime implements ComponentInterface {
207208
*/
208209
@Prop() isDateEnabled?: (dateIsoString: string) => boolean;
209210

211+
/**
212+
* If `true`, the datetime will show the last days of the previous month and the first days of the next month on a table of 42 elements.
213+
*/
214+
@Prop() showDaysOutsideCurrentMonth?:boolean = false;
215+
210216
@Watch('disabled')
211217
protected disabledChanged() {
212218
this.emitStyle();
@@ -810,9 +816,9 @@ export class Datetime implements ComponentInterface {
810816
* to grab the correct calendar-day element.
811817
*/
812818
const padding = currentMonth.querySelectorAll('.calendar-day-padding');
813-
const { day } = this.workingParts;
819+
const { day, hiddenDay } = this.workingParts;
814820

815-
if (day === null) {
821+
if (day === null || hiddenDay) {
816822
return;
817823
}
818824

@@ -2226,10 +2232,34 @@ export class Datetime implements ComponentInterface {
22262232
}}
22272233
>
22282234
<div class="calendar-month-grid">
2229-
{getDaysOfMonth(month, year, this.firstDayOfWeek % 7).map((dateObject, index) => {
2230-
const { day, dayOfWeek } = dateObject;
2231-
const { el, highlightedDates, isDateEnabled, multiple } = this;
2232-
const referenceParts = { month, day, year };
2235+
{getDaysOfMonth(month, year, this.firstDayOfWeek % 7, this.showDaysOutsideCurrentMonth).map((dateObject, index) => {
2236+
const { day, dayOfWeek, hiddenDay } = dateObject;
2237+
const { el, highlightedDates, isDateEnabled, multiple, showDaysOutsideCurrentMonth } = this;
2238+
let _month = month;
2239+
let _year = year;
2240+
if(showDaysOutsideCurrentMonth){
2241+
if(hiddenDay && day !== null && day > 20) {
2242+
// Leading with the hidden day from the previous month
2243+
// if its a hidden day and is higher than '20' (last week even in feb)
2244+
if(month === 1) {
2245+
_year = year - 1;
2246+
_month = 12;
2247+
}else{
2248+
_month = month-1;
2249+
}
2250+
} else if(hiddenDay && day !== null && day < 15) {
2251+
// Leading with the hidden day from the next month
2252+
// if its a hidden day and is lower than '15' (first two weeks)
2253+
if(month === 12) {
2254+
_year = year + 1;
2255+
_month = 1;
2256+
} else {
2257+
_month = month + 1;
2258+
}
2259+
}
2260+
}
2261+
2262+
const referenceParts = { month: _month, day, year:_year, hiddenDay: hiddenDay };
22332263
const isCalendarPadding = day === null;
22342264
const {
22352265
isActive,
@@ -2284,18 +2314,20 @@ export class Datetime implements ComponentInterface {
22842314
* Custom highlight styles should not override the style for selected dates,
22852315
* nor apply to "filler days" at the start of the grid.
22862316
*/
2287-
if (highlightedDates !== undefined && !isActive && day !== null) {
2317+
if (highlightedDates !== undefined && !isActive && day !== null && !hiddenDay) {
22882318
dateStyle = getHighlightStyles(highlightedDates, dateIsoString, el);
22892319
}
22902320

22912321
let dateParts = undefined;
22922322

22932323
// "Filler days" at the beginning of the grid should not get the calendar day
22942324
// CSS parts added to them
2295-
if (!isCalendarPadding) {
2325+
if (!isCalendarPadding && !hiddenDay) {
22962326
dateParts = `calendar-day${isActive ? ' active' : ''}${isToday ? ' today' : ''}${
22972327
isCalDayDisabled ? ' disabled' : ''
22982328
}`;
2329+
} else if(hiddenDay) {
2330+
dateParts = `calendar-day${isCalDayDisabled ? ' disabled' : ''}`;
22992331
}
23002332

23012333
return (
@@ -2319,8 +2351,8 @@ export class Datetime implements ComponentInterface {
23192351
}}
23202352
tabindex="-1"
23212353
data-day={day}
2322-
data-month={month}
2323-
data-year={year}
2354+
data-month={_month}
2355+
data-year={_year}
23242356
data-index={index}
23252357
data-day-of-week={dayOfWeek}
23262358
disabled={isButtonDisabled}
@@ -2330,6 +2362,7 @@ export class Datetime implements ComponentInterface {
23302362
'calendar-day-active': isActive,
23312363
'calendar-day-constrained': isCalDayConstrained,
23322364
'calendar-day-today': isToday,
2365+
'calendar-day-hidden-day': hiddenDay,
23332366
}}
23342367
part={dateParts}
23352368
aria-hidden={isCalendarPadding ? 'true' : null}
@@ -2342,27 +2375,30 @@ export class Datetime implements ComponentInterface {
23422375

23432376
this.setWorkingParts({
23442377
...this.workingParts,
2345-
month,
2378+
month: _month,
23462379
day,
2347-
year,
2380+
year: _year,
2381+
hiddenDay: hiddenDay,
23482382
});
23492383

23502384
// multiple only needs date info, so we can wipe out other fields like time
23512385
if (multiple) {
23522386
this.setActiveParts(
23532387
{
2354-
month,
2388+
month: _month,
23552389
day,
2356-
year,
2390+
year: _year,
2391+
hiddenDay: hiddenDay,
23572392
},
23582393
isActive
23592394
);
23602395
} else {
23612396
this.setActiveParts({
23622397
...activePart,
2363-
month,
2398+
month: _month,
23642399
day,
2365-
year,
2400+
year: _year,
2401+
hiddenDay: hiddenDay,
23662402
});
23672403
}
23682404
}}

core/src/components/datetime/test/custom/index.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@
9191
color: #8462d1;
9292
}
9393

94-
#custom-calendar-days::part(calendar-day):focus {
94+
#custom-calendar-days::part(calendar-day):not(.calendar-day-hidden-day):focus {
9595
background-color: rgb(154 209 98 / 0.2);
9696
box-shadow: 0px 0px 0px 4px rgb(154 209 98 / 0.2);
9797
}
@@ -200,6 +200,8 @@ <h2>Grid Style</h2>
200200

201201
return true;
202202
};
203+
204+
customDatetime.showDaysOutsideCurrentMonth = true
203205
</script>
204206
</body>
205207
</html>

core/src/components/datetime/utils/data.ts

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,14 @@ export const getDaysOfWeek = (locale: string, mode: Mode, firstDayOfWeek = 0) =>
102102
* the firstDayOfWeek value (Sunday by default)
103103
* using null values.
104104
*/
105-
export const getDaysOfMonth = (month: number, year: number, firstDayOfWeek: number) => {
105+
export const getDaysOfMonth = (month: number, year: number, firstDayOfWeek: number, displayHiddenDays = false) => {
106106
const numDays = getNumDaysInMonth(month, year);
107+
let previousNumDays: number; //previous month number of days
108+
if (month === 1) { //If january the previous month should be january and the last year
109+
previousNumDays = getNumDaysInMonth(12, year-1);
110+
} else { //If not the previous month should be month -1 and the current year
111+
previousNumDays = getNumDaysInMonth(month - 1, year);
112+
}
107113
const firstOfMonth = new Date(`${month}/1/${year}`).getDay();
108114

109115
/**
@@ -128,13 +134,38 @@ export const getDaysOfMonth = (month: number, year: number, firstDayOfWeek: numb
128134
const offset =
129135
firstOfMonth >= firstDayOfWeek ? firstOfMonth - (firstDayOfWeek + 1) : 6 - (firstDayOfWeek - firstOfMonth);
130136

131-
let days = [];
137+
let days: ({
138+
day: number;
139+
dayOfWeek: number;
140+
hiddenDay: boolean;
141+
} | {
142+
day: null;
143+
dayOfWeek: null;
144+
hiddenDay: boolean;
145+
})[] = [];
132146
for (let i = 1; i <= numDays; i++) {
133-
days.push({ day: i, dayOfWeek: (offset + i) % 7 });
147+
days.push({ day: i, dayOfWeek: (offset + i) % 7, hiddenDay: false });
134148
}
135149

136-
for (let i = 0; i <= offset; i++) {
137-
days = [{ day: null, dayOfWeek: null }, ...days];
150+
if (displayHiddenDays) {
151+
for (let i = 0; i <= offset; i++) {
152+
// Using offset create previous month hidden day, starting from last day
153+
days = [{ day: previousNumDays-i, dayOfWeek: (previousNumDays - i) % 7, hiddenDay:true }, ...days];
154+
}
155+
156+
// Calculate positiveOffset
157+
// The calendar will display 42 days (6 rows of 7 columns)
158+
// Knowing this the offset is 41 (we start at index 0)
159+
// minus (the previous offset + the current month days)
160+
const positiveOffset = 41 - (numDays + offset);
161+
for (let i = 0; i < positiveOffset; i++) {
162+
days.push( {day:i+1, dayOfWeek:((numDays + offset) + i) % 7, hiddenDay: true} )
163+
}
164+
165+
} else {
166+
for (let i = 0; i <= offset; i++) {
167+
days = [{ day: null, dayOfWeek: null, hiddenDay:false }, ...days];
168+
}
138169
}
139170

140171
return days;

packages/angular/src/directives/proxies.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -634,15 +634,15 @@ Set `scrollEvents` to `true` to enable.
634634

635635

636636
@ProxyCmp({
637-
inputs: ['cancelText', 'clearText', 'color', 'dayValues', 'disabled', 'doneText', 'firstDayOfWeek', 'formatOptions', 'highlightedDates', 'hourCycle', 'hourValues', 'isDateEnabled', 'locale', 'max', 'min', 'minuteValues', 'mode', 'monthValues', 'multiple', 'name', 'preferWheel', 'presentation', 'readonly', 'showClearButton', 'showDefaultButtons', 'showDefaultTimeLabel', 'showDefaultTitle', 'size', 'titleSelectedDatesFormatter', 'value', 'yearValues'],
637+
inputs: ['cancelText', 'clearText', 'color', 'dayValues', 'disabled', 'doneText', 'firstDayOfWeek', 'formatOptions', 'highlightedDates', 'hourCycle', 'hourValues', 'isDateEnabled', 'locale', 'max', 'min', 'minuteValues', 'mode', 'monthValues', 'multiple', 'name', 'preferWheel', 'presentation', 'readonly', 'showClearButton', 'showDaysOutsideCurrentMonth', 'showDefaultButtons', 'showDefaultTimeLabel', 'showDefaultTitle', 'size', 'titleSelectedDatesFormatter', 'value', 'yearValues'],
638638
methods: ['confirm', 'reset', 'cancel']
639639
})
640640
@Component({
641641
selector: 'ion-datetime',
642642
changeDetection: ChangeDetectionStrategy.OnPush,
643643
template: '<ng-content></ng-content>',
644644
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
645-
inputs: ['cancelText', 'clearText', 'color', 'dayValues', 'disabled', 'doneText', 'firstDayOfWeek', 'formatOptions', 'highlightedDates', 'hourCycle', 'hourValues', 'isDateEnabled', 'locale', 'max', 'min', 'minuteValues', 'mode', 'monthValues', 'multiple', 'name', 'preferWheel', 'presentation', 'readonly', 'showClearButton', 'showDefaultButtons', 'showDefaultTimeLabel', 'showDefaultTitle', 'size', 'titleSelectedDatesFormatter', 'value', 'yearValues'],
645+
inputs: ['cancelText', 'clearText', 'color', 'dayValues', 'disabled', 'doneText', 'firstDayOfWeek', 'formatOptions', 'highlightedDates', 'hourCycle', 'hourValues', 'isDateEnabled', 'locale', 'max', 'min', 'minuteValues', 'mode', 'monthValues', 'multiple', 'name', 'preferWheel', 'presentation', 'readonly', 'showClearButton', 'showDaysOutsideCurrentMonth', 'showDefaultButtons', 'showDefaultTimeLabel', 'showDefaultTitle', 'size', 'titleSelectedDatesFormatter', 'value', 'yearValues'],
646646
})
647647
export class IonDatetime {
648648
protected el: HTMLIonDatetimeElement;

packages/vue/src/proxies.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,7 @@ export const IonDatetime = /*@__PURE__*/ defineContainer<JSX.IonDatetime, JSX.Io
306306
'formatOptions',
307307
'readonly',
308308
'isDateEnabled',
309+
'showDaysOutsideCurrentMonth',
309310
'min',
310311
'max',
311312
'presentation',

0 commit comments

Comments
 (0)