Skip to content

Commit 6ea186d

Browse files
feat(datetime): add header parts (#30945)
Co-authored-by: Brandy Smith <brandyscarney@users.noreply.github.com>
1 parent 23e998b commit 6ea186d

4 files changed

Lines changed: 267 additions & 7 deletions

File tree

‎core/api.txt‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,15 @@ ion-datetime,part,calendar-day
566566
ion-datetime,part,calendar-day active
567567
ion-datetime,part,calendar-day disabled
568568
ion-datetime,part,calendar-day today
569+
ion-datetime,part,calendar-days-of-week
570+
ion-datetime,part,calendar-header
571+
ion-datetime,part,datetime-header
572+
ion-datetime,part,datetime-selected-date
573+
ion-datetime,part,datetime-title
569574
ion-datetime,part,month-year-button
575+
ion-datetime,part,navigation-button
576+
ion-datetime,part,next-button
577+
ion-datetime,part,previous-button
570578
ion-datetime,part,time-button
571579
ion-datetime,part,time-button active
572580
ion-datetime,part,wheel

‎core/src/components/datetime/datetime.tsx‎

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -88,14 +88,23 @@ import { checkForPresentationFormatMismatch, warnIfTimeZoneProvided } from './ut
8888
* layout with `presentation="date-time"` or `"time-date"`.
8989
* @part time-button active - The time picker button when the picker is open.
9090
*
91+
* @part calendar-header - The calendar header manages the date navigation controls (month/year picker and previous/next buttons) and the days of the week when using a grid style layout.
9192
* @part month-year-button - The button that opens the month/year picker when
9293
* using a grid style layout.
94+
* @part navigation-button - The buttons used to navigate to the next or previous month when using a grid style layout.
95+
* @part previous-button - The button used to navigate to the previous month when using a grid style layout.
96+
* @part next-button - The button used to navigate to the next month when using a grid style layout.
97+
* @part calendar-days-of-week - The container for the day-of-the-week header (both weekdays and weekends) when using a grid style layout.
9398
*
9499
* @part calendar-day - The individual buttons that display a day inside of the datetime
95100
* calendar.
96101
* @part calendar-day active - The currently selected calendar day.
97102
* @part calendar-day today - The calendar day that contains the current day.
98103
* @part calendar-day disabled - The calendar day that is disabled.
104+
*
105+
* @part datetime-header - The datetime header contains the content for the `title` slot and the selected date.
106+
* @part datetime-title - The element that contains the `title` slot content.
107+
* @part datetime-selected-date - The element that contains the selected date.
99108
*/
100109
@Component({
101110
tag: 'ion-datetime',
@@ -2166,7 +2175,7 @@ export class Datetime implements ComponentInterface {
21662175
const hostDir = this.el.getAttribute('dir') || undefined;
21672176

21682177
return (
2169-
<div class="calendar-header">
2178+
<div class="calendar-header" part="calendar-header">
21702179
<div class="calendar-action-buttons">
21712180
<div class="calendar-month-year">
21722181
<button
@@ -2195,7 +2204,12 @@ export class Datetime implements ComponentInterface {
21952204

21962205
<div class="calendar-next-prev">
21972206
<ion-buttons>
2198-
<ion-button aria-label="Previous month" disabled={prevMonthDisabled} onClick={() => this.prevMonth()}>
2207+
<ion-button
2208+
aria-label="Previous month"
2209+
disabled={prevMonthDisabled}
2210+
onClick={() => this.prevMonth()}
2211+
part="navigation-button previous-button"
2212+
>
21992213
<ion-icon
22002214
dir={hostDir}
22012215
aria-hidden="true"
@@ -2205,7 +2219,12 @@ export class Datetime implements ComponentInterface {
22052219
flipRtl
22062220
></ion-icon>
22072221
</ion-button>
2208-
<ion-button aria-label="Next month" disabled={nextMonthDisabled} onClick={() => this.nextMonth()}>
2222+
<ion-button
2223+
aria-label="Next month"
2224+
disabled={nextMonthDisabled}
2225+
onClick={() => this.nextMonth()}
2226+
part="navigation-button next-button"
2227+
>
22092228
<ion-icon
22102229
dir={hostDir}
22112230
aria-hidden="true"
@@ -2218,7 +2237,7 @@ export class Datetime implements ComponentInterface {
22182237
</ion-buttons>
22192238
</div>
22202239
</div>
2221-
<div class="calendar-days-of-week" aria-hidden="true">
2240+
<div class="calendar-days-of-week" aria-hidden="true" part="calendar-days-of-week">
22222241
{getDaysOfWeek(this.locale, mode, this.firstDayOfWeek % 7).map((d) => {
22232242
return <div class="day-of-week">{d}</div>;
22242243
})}
@@ -2571,11 +2590,15 @@ export class Datetime implements ComponentInterface {
25712590
}
25722591

25732592
return (
2574-
<div class="datetime-header">
2575-
<div class="datetime-title">
2593+
<div class="datetime-header" part="datetime-header">
2594+
<div class="datetime-title" part="datetime-title">
25762595
<slot name="title">Select Date</slot>
25772596
</div>
2578-
{showExpandedHeader && <div class="datetime-selected-date">{this.getHeaderSelectedDateText()}</div>}
2597+
{showExpandedHeader && (
2598+
<div class="datetime-selected-date" part="datetime-selected-date">
2599+
{this.getHeaderSelectedDateText()}
2600+
</div>
2601+
)}
25792602
</div>
25802603
);
25812604
}

‎core/src/components/datetime/test/custom/datetime.e2e.ts‎

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,190 @@ configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
175175

176176
expect(backgroundColor).toBe('rgb(0, 0, 255)');
177177
});
178+
179+
test('should be able to customize datetime header parts', async ({ page }, testInfo) => {
180+
testInfo.annotations.push({
181+
type: 'issue',
182+
description: 'https://github.com/ionic-team/ionic-framework/issues/30083',
183+
});
184+
185+
await page.setContent(
186+
`
187+
<style>
188+
ion-datetime::part(datetime-header) {
189+
background-color: orange;
190+
}
191+
192+
ion-datetime::part(datetime-title) {
193+
background-color: pink;
194+
}
195+
196+
ion-datetime::part(datetime-selected-date) {
197+
background-color: violet;
198+
}
199+
</style>
200+
<ion-datetime value="2020-03-14T14:23:00.000Z">
201+
<span slot="title">Select Date</span>
202+
</ion-datetime>
203+
`,
204+
config
205+
);
206+
207+
const datetime = page.locator('ion-datetime');
208+
const header = datetime.locator('.datetime-header');
209+
const title = datetime.locator('.datetime-title');
210+
const selectedDate = datetime.locator('.datetime-selected-date');
211+
212+
const headerBackgroundColor = await header.evaluate((el) => {
213+
return window.getComputedStyle(el).backgroundColor;
214+
});
215+
216+
const titleBackgroundColor = await title.evaluate((el) => {
217+
return window.getComputedStyle(el).backgroundColor;
218+
});
219+
220+
const selectedDateBackgroundColor = await selectedDate.evaluate((el) => {
221+
return window.getComputedStyle(el).backgroundColor;
222+
});
223+
224+
expect(headerBackgroundColor).toBe('rgb(255, 165, 0)');
225+
expect(titleBackgroundColor).toBe('rgb(255, 192, 203)');
226+
expect(selectedDateBackgroundColor).toBe('rgb(238, 130, 238)');
227+
});
228+
229+
test('should be able to customize calendar header part', async ({ page }) => {
230+
await page.setContent(
231+
`
232+
<style>
233+
ion-datetime::part(calendar-header) {
234+
background-color: orange;
235+
}
236+
</style>
237+
<ion-datetime value="2020-03-14T14:23:00.000Z"></ion-datetime>
238+
`,
239+
config
240+
);
241+
242+
const datetime = page.locator('ion-datetime');
243+
const header = datetime.locator('.calendar-header');
244+
245+
const backgroundColor = await header.evaluate((el) => {
246+
return window.getComputedStyle(el).backgroundColor;
247+
});
248+
249+
expect(backgroundColor).toBe('rgb(255, 165, 0)');
250+
});
251+
252+
test('should be able to customize month/year picker part', async ({ page }, testInfo) => {
253+
testInfo.annotations.push({
254+
type: 'issue',
255+
description: 'https://github.com/ionic-team/ionic-framework/issues/26596',
256+
});
257+
258+
await page.setContent(
259+
`
260+
<style>
261+
ion-datetime::part(month-year-button) {
262+
background-color: lightblue;
263+
}
264+
</style>
265+
<ion-datetime value="2020-03-14T14:23:00.000Z"></ion-datetime>
266+
`,
267+
config
268+
);
269+
270+
const datetime = page.locator('ion-datetime');
271+
const monthYearButton = datetime.locator('.calendar-month-year-toggle');
272+
273+
const backgroundColor = await monthYearButton.evaluate((el) => {
274+
return window.getComputedStyle(el).backgroundColor;
275+
});
276+
277+
expect(backgroundColor).toBe('rgb(173, 216, 230)');
278+
});
279+
280+
test('should be able to customize navigation button parts', async ({ page }, testInfo) => {
281+
testInfo.annotations.push({
282+
type: 'issue',
283+
description: 'https://github.com/ionic-team/ionic-framework/issues/30830',
284+
});
285+
286+
await page.setContent(
287+
`
288+
<style>
289+
ion-datetime::part(navigation-button) {
290+
background-color: firebrick;
291+
}
292+
293+
ion-datetime::part(previous-button) {
294+
color: blue;
295+
}
296+
297+
ion-datetime::part(next-button) {
298+
color: green;
299+
}
300+
</style>
301+
<ion-datetime value="2020-03-14T14:23:00.000Z"></ion-datetime>
302+
`,
303+
config
304+
);
305+
306+
const datetime = page.locator('ion-datetime');
307+
const prevButton = datetime.locator('.calendar-next-prev ion-button').first();
308+
const nextButton = datetime.locator('.calendar-next-prev ion-button').last();
309+
310+
const prevBackgroundColor = await prevButton.evaluate((el) => {
311+
return window.getComputedStyle(el).backgroundColor;
312+
});
313+
314+
const prevColor = await prevButton.evaluate((el) => {
315+
return window.getComputedStyle(el).color;
316+
});
317+
318+
const nextBackgroundColor = await nextButton.evaluate((el) => {
319+
return window.getComputedStyle(el).backgroundColor;
320+
});
321+
322+
const nextColor = await nextButton.evaluate((el) => {
323+
return window.getComputedStyle(el).color;
324+
});
325+
326+
// Verify the navigation-button part applies the styles
327+
expect(prevBackgroundColor).toBe('rgb(178, 34, 34)');
328+
expect(nextBackgroundColor).toBe('rgb(178, 34, 34)');
329+
// Verify the previous-button part applies the styles
330+
expect(prevColor).toBe('rgb(0, 0, 255)');
331+
// Verify the next-button part applies the styles
332+
expect(nextColor).toBe('rgb(0, 128, 0)');
333+
});
334+
335+
test('should be able to customize days of the week part', async ({ page }, testInfo) => {
336+
testInfo.annotations.push({
337+
type: 'issue',
338+
description: 'https://github.com/ionic-team/ionic-framework/issues/30830',
339+
});
340+
341+
await page.setContent(
342+
`
343+
<style>
344+
ion-datetime::part(calendar-days-of-week) {
345+
background-color: green;
346+
}
347+
</style>
348+
<ion-datetime value="2020-03-14T14:23:00.000Z"></ion-datetime>
349+
`,
350+
config
351+
);
352+
353+
const datetime = page.locator('ion-datetime');
354+
const daysOfWeek = datetime.locator('.calendar-days-of-week');
355+
356+
const backgroundColor = await daysOfWeek.evaluate((el) => {
357+
return window.getComputedStyle(el).backgroundColor;
358+
});
359+
360+
expect(backgroundColor).toBe('rgb(0, 128, 0)');
361+
});
178362
});
179363
});
180364

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

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,46 @@
134134
background-color: rgb(154 209 98 / 0.2);
135135
color: #9ad162;
136136
}
137+
138+
/*
139+
* Custom Datetime Header Parts
140+
* -------------------------------------------
141+
*/
142+
143+
#custom-grid::part(calendar-header),
144+
#custom-title::part(datetime-header) {
145+
background-color: orange;
146+
}
147+
148+
#custom-grid::part(month-year-button) {
149+
background-color: lightblue;
150+
color: rgb(128, 30, 171);
151+
}
152+
153+
#custom-grid::part(navigation-button) {
154+
background-color: firebrick;
155+
}
156+
157+
#custom-grid::part(previous-button) {
158+
color: white;
159+
}
160+
161+
#custom-grid::part(next-button) {
162+
color: black;
163+
}
164+
165+
#custom-grid::part(calendar-days-of-week) {
166+
background-color: #9ad162;
167+
color: white;
168+
}
169+
170+
#custom-title::part(datetime-title) {
171+
background-color: pink;
172+
}
173+
174+
#custom-title::part(datetime-selected-date) {
175+
background-color: violet;
176+
}
137177
</style>
138178
</head>
139179

@@ -163,6 +203,11 @@ <h2>Wheel Style</h2>
163203
<h2>Grid Style</h2>
164204
<ion-datetime id="custom-calendar-days" value="2023-06-15" presentation="date"></ion-datetime>
165205
</div>
206+
<div class="grid-item">
207+
<ion-datetime id="custom-title" presentation="date">
208+
<span slot="title">Select Date</span>
209+
</ion-datetime>
210+
</div>
166211
</div>
167212
</ion-content>
168213
</ion-app>

0 commit comments

Comments
 (0)