feat(datetime): add animation to adjacent days selection (#30298)
Issue number: internal --------- <!-- Please do not submit updates to dependencies unless it fixes an issue. --> <!-- Please try to limit your pull request to one type (bugfix, feature, etc). Submit multiple pull requests if needed. --> ## What is the new behavior? <!-- Please describe the behavior or changes that are being added by this PR. --> Now when an adjacent day is selected the component will scroll to the pretended month, as it does when a month change via arrow buttons. ## Changes: - add styles for active adjacent day; - scroll animation when adjacentDay is selected; ## Does this introduce a breaking change? - [ ] Yes - [x] No <!-- If this introduces a breaking change: 1. Describe the impact and migration path for existing applications below. 2. Update the BREAKING.md file with the breaking change. 3. Add "BREAKING CHANGE: [...]" to the commit description when merging. See https://github.com/ionic-team/ionic-framework/blob/main/docs/CONTRIBUTING.md#footer for more information. --> ## Other information - [md preview](https://ionic-framework-git-rou-11744-ionic1.vercel.app/src/components/datetime/test/show-adjacent-days?ionic:mode=md) - [ios preview](https://ionic-framework-git-rou-11744-ionic1.vercel.app/src/components/datetime/test/show-adjacent-days?ionic:mode=ios ) <!-- Any other information that is important to this PR such as screenshots of how the component looks before and after the change. --> --------- Co-authored-by: Maria Hutt <thetaPC@users.noreply.github.com> Co-authored-by: ionitron <hi@ionicframework.com>
@ -251,7 +251,8 @@
|
|||||||
* is selected should have ion-color for
|
* is selected should have ion-color for
|
||||||
* text color and be bolder.
|
* text color and be bolder.
|
||||||
*/
|
*/
|
||||||
:host .calendar-day.calendar-day-active {
|
:host .calendar-day.calendar-day-active,
|
||||||
|
:host .calendar-day.calendar-day-adjacent-day.calendar-day-active {
|
||||||
color: current-color(base);
|
color: current-color(base);
|
||||||
|
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
|||||||
@ -117,7 +117,8 @@
|
|||||||
* is selected should have ion-color for
|
* is selected should have ion-color for
|
||||||
* text color and be bolder.
|
* text color and be bolder.
|
||||||
*/
|
*/
|
||||||
:host .calendar-day.calendar-day-active {
|
:host .calendar-day.calendar-day-active,
|
||||||
|
:host .calendar-day.calendar-day-adjacent-day.calendar-day-active {
|
||||||
color: current-color(contrast);
|
color: current-color(contrast);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2383,35 +2383,24 @@ export class Datetime implements ComponentInterface {
|
|||||||
if (isAdjacentDay) {
|
if (isAdjacentDay) {
|
||||||
// The user selected a day outside the current month. Ignore this button, as the month will be re-rendered.
|
// The user selected a day outside the current month. Ignore this button, as the month will be re-rendered.
|
||||||
this.el.blur();
|
this.el.blur();
|
||||||
}
|
this.activeParts = { ...activePart, ...referenceParts };
|
||||||
|
this.animateToDate(referenceParts);
|
||||||
this.setWorkingParts({
|
this.confirm();
|
||||||
...this.workingParts,
|
|
||||||
month: _month,
|
|
||||||
day,
|
|
||||||
year: _year,
|
|
||||||
isAdjacentDay,
|
|
||||||
});
|
|
||||||
|
|
||||||
// multiple only needs date info, so we can wipe out other fields like time
|
|
||||||
if (multiple) {
|
|
||||||
this.setActiveParts(
|
|
||||||
{
|
|
||||||
month: _month,
|
|
||||||
day,
|
|
||||||
year: _year,
|
|
||||||
isAdjacentDay,
|
|
||||||
},
|
|
||||||
isActive
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
this.setActiveParts({
|
this.setWorkingParts({
|
||||||
...activePart,
|
...this.workingParts,
|
||||||
month: _month,
|
...referenceParts,
|
||||||
day,
|
|
||||||
year: _year,
|
|
||||||
isAdjacentDay,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Multiple only needs date info so we can wipe out other fields like time.
|
||||||
|
if (multiple) {
|
||||||
|
this.setActiveParts(referenceParts, isActive);
|
||||||
|
} else {
|
||||||
|
this.setActiveParts({
|
||||||
|
...activePart,
|
||||||
|
...referenceParts,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -47,5 +47,75 @@ configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
|
|||||||
const datetime = page.locator('#display');
|
const datetime = page.locator('#display');
|
||||||
await expect(datetime).toHaveScreenshot(screenshot(`datetime-show-adjacent-days-display`));
|
await expect(datetime).toHaveScreenshot(screenshot(`datetime-show-adjacent-days-display`));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should return the same date format on current month days and on adjacent days', async ({ page }) => {
|
||||||
|
await page.setContent(
|
||||||
|
`
|
||||||
|
<ion-datetime show-adjacent-days="true" value="2022-10-14T16:22:00.000Z" presentation="date"></ion-datetime>
|
||||||
|
`,
|
||||||
|
config
|
||||||
|
);
|
||||||
|
|
||||||
|
// Wait for the datetime to be ready.
|
||||||
|
await page.locator('.datetime-ready').waitFor();
|
||||||
|
|
||||||
|
const ionChange = await page.spyOnEvent('ionChange');
|
||||||
|
|
||||||
|
const calendarMonthYear = page.locator('ion-datetime .calendar-month-year');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make sure to exclude adjacent days from the query since
|
||||||
|
* the previous/next month is rendered hidden. This causes
|
||||||
|
* the query to possibly return different results: one for
|
||||||
|
* the current month and one from the hidden previous/next
|
||||||
|
* month.
|
||||||
|
*/
|
||||||
|
const october20Button = page.locator(
|
||||||
|
'[data-month="10"][data-year="2022"][data-day="20"]:not(.calendar-day-adjacent-day)'
|
||||||
|
);
|
||||||
|
|
||||||
|
await october20Button.click();
|
||||||
|
|
||||||
|
await ionChange.next();
|
||||||
|
await expect(ionChange).toHaveReceivedEventDetail({
|
||||||
|
value: '2022-10-20T16:22:00',
|
||||||
|
});
|
||||||
|
|
||||||
|
const november1Button = page.locator(
|
||||||
|
'.calendar-day-adjacent-day[data-month="11"][data-year="2022"][data-day="1"]'
|
||||||
|
);
|
||||||
|
|
||||||
|
await november1Button.click();
|
||||||
|
// Wait for the datetime to change the month since an adjacent day
|
||||||
|
// was clicked.
|
||||||
|
await page.waitForChanges();
|
||||||
|
|
||||||
|
// Wait for the title to update to the new month since it changes
|
||||||
|
// after the month animation finishes.
|
||||||
|
await expect(calendarMonthYear).toHaveText('November 2022');
|
||||||
|
|
||||||
|
await ionChange.next();
|
||||||
|
await expect(ionChange).toHaveReceivedEventDetail({
|
||||||
|
value: '2022-11-01T16:22:00',
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make sure to exclude adjacent days from the query since
|
||||||
|
* the previous/next month is rendered hidden. This causes
|
||||||
|
* the query to possibly return different results: one for
|
||||||
|
* the current month and one from the hidden previous/next
|
||||||
|
* month.
|
||||||
|
*/
|
||||||
|
const november22Button = page.locator(
|
||||||
|
'[data-month="11"][data-year="2022"][data-day="22"]:not(.calendar-day-adjacent-day)'
|
||||||
|
);
|
||||||
|
|
||||||
|
await november22Button.click();
|
||||||
|
|
||||||
|
await ionChange.next();
|
||||||
|
await expect(ionChange).toHaveReceivedEventDetail({
|
||||||
|
value: '2022-11-22T16:22:00',
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
@ -161,22 +161,35 @@
|
|||||||
<span>FirstDayOfWeek: <span id="start-of-week">1</span></span>
|
<span>FirstDayOfWeek: <span id="start-of-week">1</span></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="grid-item">
|
||||||
|
<h2>DateTime format with IonChange Event (console)</h2>
|
||||||
|
<ion-datetime
|
||||||
|
id="default2"
|
||||||
|
show-adjacent-days="true"
|
||||||
|
locale="en-US"
|
||||||
|
value="2022-10-14T16:22:00.000Z"
|
||||||
|
presentation="date"
|
||||||
|
></ion-datetime>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div class="grid">
|
||||||
<label for="presentation">Presentation</label>
|
<div class="grid-item">
|
||||||
<select id="presentation" onchange="changePresentation(event)">
|
<label for="presentation">Presentation</label>
|
||||||
<option value="date-time" selected>date-time</option>
|
<select id="presentation" onchange="changePresentation(event)">
|
||||||
<option value="time-date">time-date</option>
|
<option value="date-time" selected>date-time</option>
|
||||||
<option value="date">date</option>
|
<option value="time-date">time-date</option>
|
||||||
<option value="time">time</option>
|
<option value="date">date</option>
|
||||||
</select>
|
<option value="time">time</option>
|
||||||
<label for="size">Size</label>
|
</select>
|
||||||
<select id="size" onchange="changeSize(event)">
|
<label for="size">Size</label>
|
||||||
<option value="fixed" selected>fixed</option>
|
<select id="size" onchange="changeSize(event)">
|
||||||
<option value="cover">cover</option>
|
<option value="fixed" selected>fixed</option>
|
||||||
</select>
|
<option value="cover">cover</option>
|
||||||
<br /><br />
|
</select>
|
||||||
<ion-datetime show-adjacent-days="true" id="display" value="2022-02-22T16:30:00"></ion-datetime>
|
<br /><br />
|
||||||
|
<ion-datetime show-adjacent-days="true" id="display" value="2022-02-22T16:30:00"></ion-datetime>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ion-content>
|
</ion-content>
|
||||||
</ion-app>
|
</ion-app>
|
||||||
@ -305,6 +318,11 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
initCalendarMonthChangeObserver();
|
initCalendarMonthChangeObserver();
|
||||||
|
|
||||||
|
const datetimeDefault = document.querySelector('#default2');
|
||||||
|
datetimeDefault.addEventListener('ionChange', (ev) => {
|
||||||
|
console.log(ev.target.value);
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||