@ionic/core 7.5.3-nightly.20231031 → 7.5.3
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.
- package/components/ion-datetime.js +48 -23
- package/dist/cjs/ion-datetime_3.cjs.entry.js +48 -23
- package/dist/collection/components/datetime/datetime.ios.css +23 -3
- package/dist/collection/components/datetime/datetime.js +47 -22
- package/dist/collection/components/datetime/datetime.md.css +23 -3
- package/dist/collection/components/datetime/test/a11y/datetime.e2e.js +66 -0
- package/dist/collection/components/datetime/test/disabled/datetime.e2e.js +68 -0
- package/dist/collection/components/datetime/test/readonly/datetime.e2e.js +113 -0
- package/dist/docs.json +2 -2
- package/dist/esm/ion-datetime_3.entry.js +48 -23
- package/dist/esm-es5/ion-datetime_3.entry.js +1 -1
- package/dist/html.html-data.json +1 -1
- package/dist/ionic/ionic.esm.js +1 -1
- package/dist/ionic/p-0fb53284.system.js +1 -1
- package/dist/ionic/p-bbf47813.entry.js +4 -0
- package/dist/ionic/p-f10fb4d4.system.entry.js +4 -0
- package/dist/types/components/datetime/datetime.d.ts +1 -1
- package/dist/types/components.d.ts +2 -2
- package/hydrate/index.js +48 -23
- package/package.json +1 -1
- package/dist/ionic/p-5c92c941.entry.js +0 -4
- package/dist/ionic/p-9ebd9c24.system.entry.js +0 -4
|
@@ -94,6 +94,13 @@ export class Datetime {
|
|
|
94
94
|
this.workingParts = Object.assign({}, parts);
|
|
95
95
|
};
|
|
96
96
|
this.setActiveParts = (parts, removeDate = false) => {
|
|
97
|
+
/** if the datetime component is in readonly mode,
|
|
98
|
+
* allow browsing of the calendar without changing
|
|
99
|
+
* the set value
|
|
100
|
+
*/
|
|
101
|
+
if (this.readonly) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
97
104
|
const { multiple, minParts, maxParts, activeParts } = this;
|
|
98
105
|
/**
|
|
99
106
|
* When setting the active parts, it is possible
|
|
@@ -914,7 +921,13 @@ export class Datetime {
|
|
|
914
921
|
* are rendered independently of presentation.
|
|
915
922
|
*/
|
|
916
923
|
renderFooter() {
|
|
917
|
-
const { showDefaultButtons, showClearButton } = this;
|
|
924
|
+
const { disabled, readonly, showDefaultButtons, showClearButton } = this;
|
|
925
|
+
/**
|
|
926
|
+
* The cancel, clear, and confirm buttons
|
|
927
|
+
* should not be interactive if the datetime
|
|
928
|
+
* is disabled or readonly.
|
|
929
|
+
*/
|
|
930
|
+
const isButtonDisabled = disabled || readonly;
|
|
918
931
|
const hasSlottedButtons = this.el.querySelector('[slot="buttons"]') !== null;
|
|
919
932
|
if (!hasSlottedButtons && !showDefaultButtons && !showClearButton) {
|
|
920
933
|
return;
|
|
@@ -933,7 +946,7 @@ export class Datetime {
|
|
|
933
946
|
return (h("div", { class: "datetime-footer" }, h("div", { class: "datetime-buttons" }, h("div", { class: {
|
|
934
947
|
['datetime-action-buttons']: true,
|
|
935
948
|
['has-clear-button']: this.showClearButton,
|
|
936
|
-
} }, h("slot", { name: "buttons" }, h("ion-buttons", null, showDefaultButtons && (h("ion-button", { id: "cancel-button", color: this.color, onClick: () => this.cancel(true) }, this.cancelText)), h("div", { class: "datetime-action-buttons-container" }, showClearButton && (h("ion-button", { id: "clear-button", color: this.color, onClick: () => clearButtonClick() }, this.clearText)), showDefaultButtons && (h("ion-button", { id: "confirm-button", color: this.color, onClick: () => this.confirm(true) }, this.doneText)))))))));
|
|
949
|
+
} }, h("slot", { name: "buttons" }, h("ion-buttons", null, showDefaultButtons && (h("ion-button", { id: "cancel-button", color: this.color, onClick: () => this.cancel(true), disabled: isButtonDisabled }, this.cancelText)), h("div", { class: "datetime-action-buttons-container" }, showClearButton && (h("ion-button", { id: "clear-button", color: this.color, onClick: () => clearButtonClick(), disabled: isButtonDisabled }, this.clearText)), showDefaultButtons && (h("ion-button", { id: "confirm-button", color: this.color, onClick: () => this.confirm(true), disabled: isButtonDisabled }, this.doneText)))))))));
|
|
937
950
|
}
|
|
938
951
|
/**
|
|
939
952
|
* Wheel picker render methods
|
|
@@ -1224,13 +1237,14 @@ export class Datetime {
|
|
|
1224
1237
|
* Grid Render Methods
|
|
1225
1238
|
*/
|
|
1226
1239
|
renderCalendarHeader(mode) {
|
|
1240
|
+
const { disabled } = this;
|
|
1227
1241
|
const expandedIcon = mode === 'ios' ? chevronDown : caretUpSharp;
|
|
1228
1242
|
const collapsedIcon = mode === 'ios' ? chevronForward : caretDownSharp;
|
|
1229
|
-
const prevMonthDisabled = isPrevMonthDisabled(this.workingParts, this.minParts, this.maxParts);
|
|
1230
|
-
const nextMonthDisabled = isNextMonthDisabled(this.workingParts, this.maxParts);
|
|
1243
|
+
const prevMonthDisabled = disabled || isPrevMonthDisabled(this.workingParts, this.minParts, this.maxParts);
|
|
1244
|
+
const nextMonthDisabled = disabled || isNextMonthDisabled(this.workingParts, this.maxParts);
|
|
1231
1245
|
// don't use the inheritAttributes util because it removes dir from the host, and we still need that
|
|
1232
1246
|
const hostDir = this.el.getAttribute('dir') || undefined;
|
|
1233
|
-
return (h("div", { class: "calendar-header" }, h("div", { class: "calendar-action-buttons" }, h("div", { class: "calendar-month-year" }, h("ion-item", { part: "month-year-button", ref: (el) => (this.monthYearToggleItemRef = el), button: true, "aria-label": "Show year picker", detail: false, lines: "none", onClick: () => {
|
|
1247
|
+
return (h("div", { class: "calendar-header" }, h("div", { class: "calendar-action-buttons" }, h("div", { class: "calendar-month-year" }, h("ion-item", { part: "month-year-button", ref: (el) => (this.monthYearToggleItemRef = el), button: true, "aria-label": "Show year picker", detail: false, lines: "none", disabled: disabled, onClick: () => {
|
|
1234
1248
|
var _a;
|
|
1235
1249
|
this.toggleMonthAndYearView();
|
|
1236
1250
|
/**
|
|
@@ -1254,20 +1268,23 @@ export class Datetime {
|
|
|
1254
1268
|
}))));
|
|
1255
1269
|
}
|
|
1256
1270
|
renderMonth(month, year) {
|
|
1271
|
+
const { disabled, readonly } = this;
|
|
1257
1272
|
const yearAllowed = this.parsedYearValues === undefined || this.parsedYearValues.includes(year);
|
|
1258
1273
|
const monthAllowed = this.parsedMonthValues === undefined || this.parsedMonthValues.includes(month);
|
|
1259
1274
|
const isCalMonthDisabled = !yearAllowed || !monthAllowed;
|
|
1260
|
-
const
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1275
|
+
const isDatetimeDisabled = disabled || readonly;
|
|
1276
|
+
const swipeDisabled = disabled ||
|
|
1277
|
+
isMonthDisabled({
|
|
1278
|
+
month,
|
|
1279
|
+
year,
|
|
1280
|
+
day: null,
|
|
1281
|
+
}, {
|
|
1282
|
+
// The day is not used when checking if a month is disabled.
|
|
1283
|
+
// Users should be able to access the min or max month, even if the
|
|
1284
|
+
// min/max date is out of bounds (e.g. min is set to Feb 15, Feb should not be disabled).
|
|
1285
|
+
minParts: Object.assign(Object.assign({}, this.minParts), { day: null }),
|
|
1286
|
+
maxParts: Object.assign(Object.assign({}, this.maxParts), { day: null }),
|
|
1287
|
+
});
|
|
1271
1288
|
// The working month should never have swipe disabled.
|
|
1272
1289
|
// Otherwise the CSS scroll snap will not work and the user
|
|
1273
1290
|
// can free-scroll the calendar.
|
|
@@ -1282,9 +1299,9 @@ export class Datetime {
|
|
|
1282
1299
|
const { el, highlightedDates, isDateEnabled, multiple } = this;
|
|
1283
1300
|
const referenceParts = { month, day, year };
|
|
1284
1301
|
const isCalendarPadding = day === null;
|
|
1285
|
-
const { isActive, isToday, ariaLabel, ariaSelected, disabled, text } = getCalendarDayState(this.locale, referenceParts, this.activeParts, this.todayParts, this.minParts, this.maxParts, this.parsedDayValues);
|
|
1302
|
+
const { isActive, isToday, ariaLabel, ariaSelected, disabled: isDayDisabled, text, } = getCalendarDayState(this.locale, referenceParts, this.activeParts, this.todayParts, this.minParts, this.maxParts, this.parsedDayValues);
|
|
1286
1303
|
const dateIsoString = convertDataToISO(referenceParts);
|
|
1287
|
-
let isCalDayDisabled = isCalMonthDisabled ||
|
|
1304
|
+
let isCalDayDisabled = isCalMonthDisabled || isDayDisabled;
|
|
1288
1305
|
if (!isCalDayDisabled && isDateEnabled !== undefined) {
|
|
1289
1306
|
try {
|
|
1290
1307
|
/**
|
|
@@ -1298,6 +1315,13 @@ export class Datetime {
|
|
|
1298
1315
|
printIonError('Exception thrown from provided `isDateEnabled` function. Please check your function and try again.', el, e);
|
|
1299
1316
|
}
|
|
1300
1317
|
}
|
|
1318
|
+
/**
|
|
1319
|
+
* Some days are constrained through max & min or allowed dates
|
|
1320
|
+
* and also disabled because the component is readonly or disabled.
|
|
1321
|
+
* These need to be displayed differently.
|
|
1322
|
+
*/
|
|
1323
|
+
const isCalDayConstrained = isCalDayDisabled && isDatetimeDisabled;
|
|
1324
|
+
const isButtonDisabled = isCalDayDisabled || isDatetimeDisabled;
|
|
1301
1325
|
let dateStyle = undefined;
|
|
1302
1326
|
/**
|
|
1303
1327
|
* Custom highlight styles should not override the style for selected dates,
|
|
@@ -1324,10 +1348,11 @@ export class Datetime {
|
|
|
1324
1348
|
el.style.setProperty('color', `${dateStyle ? dateStyle.textColor : ''}`, 'important');
|
|
1325
1349
|
el.style.setProperty('background-color', `${dateStyle ? dateStyle.backgroundColor : ''}`, 'important');
|
|
1326
1350
|
}
|
|
1327
|
-
}, tabindex: "-1", "data-day": day, "data-month": month, "data-year": year, "data-index": index, "data-day-of-week": dayOfWeek, disabled:
|
|
1351
|
+
}, tabindex: "-1", "data-day": day, "data-month": month, "data-year": year, "data-index": index, "data-day-of-week": dayOfWeek, disabled: isButtonDisabled, class: {
|
|
1328
1352
|
'calendar-day-padding': isCalendarPadding,
|
|
1329
1353
|
'calendar-day': true,
|
|
1330
1354
|
'calendar-day-active': isActive,
|
|
1355
|
+
'calendar-day-constrained': isCalDayConstrained,
|
|
1331
1356
|
'calendar-day-today': isToday,
|
|
1332
1357
|
}, part: dateParts, "aria-hidden": isCalendarPadding ? 'true' : null, "aria-selected": ariaSelected, "aria-label": ariaLabel, onClick: () => {
|
|
1333
1358
|
if (isCalendarPadding) {
|
|
@@ -1369,7 +1394,7 @@ export class Datetime {
|
|
|
1369
1394
|
return h("slot", { name: "time-label" }, "Time");
|
|
1370
1395
|
}
|
|
1371
1396
|
renderTimeOverlay() {
|
|
1372
|
-
const { hourCycle, isTimePopoverOpen, locale } = this;
|
|
1397
|
+
const { disabled, hourCycle, isTimePopoverOpen, locale } = this;
|
|
1373
1398
|
const computedHourCycle = getHourCycle(locale, hourCycle);
|
|
1374
1399
|
const activePart = this.getActivePartsWithFallback();
|
|
1375
1400
|
return [
|
|
@@ -1377,7 +1402,7 @@ export class Datetime {
|
|
|
1377
1402
|
h("button", { class: {
|
|
1378
1403
|
'time-body': true,
|
|
1379
1404
|
'time-body-active': isTimePopoverOpen,
|
|
1380
|
-
}, part: `time-button${isTimePopoverOpen ? ' active' : ''}`, "aria-expanded": "false", "aria-haspopup": "true", onClick: async (ev) => {
|
|
1405
|
+
}, part: `time-button${isTimePopoverOpen ? ' active' : ''}`, "aria-expanded": "false", "aria-haspopup": "true", disabled: disabled, onClick: async (ev) => {
|
|
1381
1406
|
const { popoverRef } = this;
|
|
1382
1407
|
if (popoverRef) {
|
|
1383
1408
|
this.isTimePopoverOpen = true;
|
|
@@ -1617,7 +1642,7 @@ export class Datetime {
|
|
|
1617
1642
|
"optional": false,
|
|
1618
1643
|
"docs": {
|
|
1619
1644
|
"tags": [],
|
|
1620
|
-
"text": "If `true`, the datetime appears normal but
|
|
1645
|
+
"text": "If `true`, the datetime appears normal but the selected date cannot be changed."
|
|
1621
1646
|
},
|
|
1622
1647
|
"attribute": "readonly",
|
|
1623
1648
|
"reflect": false,
|
|
@@ -224,15 +224,35 @@ ion-picker-column-internal {
|
|
|
224
224
|
display: none;
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
-
:host(.datetime-readonly),
|
|
228
227
|
:host(.datetime-disabled) {
|
|
229
228
|
pointer-events: none;
|
|
230
229
|
}
|
|
231
|
-
|
|
232
|
-
:host(.datetime-disabled) {
|
|
230
|
+
:host(.datetime-disabled) .calendar-days-of-week,
|
|
231
|
+
:host(.datetime-disabled) .datetime-time {
|
|
233
232
|
opacity: 0.4;
|
|
234
233
|
}
|
|
235
234
|
|
|
235
|
+
:host(.datetime-readonly) {
|
|
236
|
+
pointer-events: none;
|
|
237
|
+
/**
|
|
238
|
+
* Allow user to navigate months
|
|
239
|
+
* while in readonly mode
|
|
240
|
+
*/
|
|
241
|
+
/**
|
|
242
|
+
* Disabled buttons should have full opacity
|
|
243
|
+
* in readonly mode
|
|
244
|
+
*/
|
|
245
|
+
}
|
|
246
|
+
:host(.datetime-readonly) .calendar-action-buttons,
|
|
247
|
+
:host(.datetime-readonly) .calendar-body,
|
|
248
|
+
:host(.datetime-readonly) .datetime-year {
|
|
249
|
+
pointer-events: initial;
|
|
250
|
+
}
|
|
251
|
+
:host(.datetime-readonly) .calendar-day[disabled]:not(.calendar-day-constrained),
|
|
252
|
+
:host(.datetime-readonly) .datetime-action-buttons ion-button[disabled] {
|
|
253
|
+
opacity: 1;
|
|
254
|
+
}
|
|
255
|
+
|
|
236
256
|
/**
|
|
237
257
|
* Title should not wrap
|
|
238
258
|
* to the next line and should
|
|
@@ -26,3 +26,69 @@ configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
|
|
|
26
26
|
});
|
|
27
27
|
});
|
|
28
28
|
});
|
|
29
|
+
/**
|
|
30
|
+
* This behavior does not differ across
|
|
31
|
+
* modes/directions.
|
|
32
|
+
*/
|
|
33
|
+
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
|
34
|
+
test.describe(title('datetime: a11y'), () => {
|
|
35
|
+
test('datetime should be keyboard navigable', async ({ page, browserName }) => {
|
|
36
|
+
await page.setContent(`
|
|
37
|
+
<ion-datetime value="2022-02-22T16:30:00"></ion-datetime>
|
|
38
|
+
`, config);
|
|
39
|
+
const tabKey = browserName === 'webkit' ? 'Alt+Tab' : 'Tab';
|
|
40
|
+
const datetime = page.locator('ion-datetime');
|
|
41
|
+
const monthYearButton = page.locator('.calendar-month-year ion-item');
|
|
42
|
+
const prevButton = page.locator('.calendar-next-prev ion-button:nth-child(1)');
|
|
43
|
+
const nextButton = page.locator('.calendar-next-prev ion-button:nth-child(2)');
|
|
44
|
+
await page.keyboard.press(tabKey);
|
|
45
|
+
await expect(monthYearButton).toBeFocused();
|
|
46
|
+
await page.keyboard.press(tabKey);
|
|
47
|
+
await expect(prevButton).toBeFocused();
|
|
48
|
+
await page.keyboard.press(tabKey);
|
|
49
|
+
await expect(nextButton).toBeFocused();
|
|
50
|
+
// check value before & after selecting via keyboard
|
|
51
|
+
const initialValue = await datetime.evaluate((el) => el.value);
|
|
52
|
+
expect(initialValue).toBe('2022-02-22T16:30:00');
|
|
53
|
+
await page.keyboard.press(tabKey);
|
|
54
|
+
await page.waitForChanges();
|
|
55
|
+
await page.keyboard.press('ArrowLeft');
|
|
56
|
+
await page.waitForChanges();
|
|
57
|
+
await page.keyboard.press('Enter');
|
|
58
|
+
await page.waitForChanges();
|
|
59
|
+
const newValue = await datetime.evaluate((el) => el.value);
|
|
60
|
+
expect(newValue).not.toBe('2022-02-22T16:30:00');
|
|
61
|
+
});
|
|
62
|
+
test('buttons should be keyboard navigable', async ({ page }) => {
|
|
63
|
+
await page.setContent(`
|
|
64
|
+
|
|
65
|
+
<ion-datetime value="2022-02-22T16:30:00" show-default-buttons="true" show-clear-button="true"></ion-datetime>
|
|
66
|
+
`, config);
|
|
67
|
+
await page.waitForSelector('.datetime-ready');
|
|
68
|
+
const clearButton = page.locator('#clear-button button');
|
|
69
|
+
const selectedDay = page.locator('.calendar-day-active');
|
|
70
|
+
await expect(selectedDay).toHaveText('22');
|
|
71
|
+
await clearButton.focus();
|
|
72
|
+
await page.waitForChanges();
|
|
73
|
+
await expect(clearButton).toBeFocused();
|
|
74
|
+
await page.keyboard.press('Enter');
|
|
75
|
+
await page.waitForChanges();
|
|
76
|
+
await expect(selectedDay).toHaveCount(0);
|
|
77
|
+
});
|
|
78
|
+
test('should navigate through months via right arrow key', async ({ page }) => {
|
|
79
|
+
await page.setContent(`
|
|
80
|
+
|
|
81
|
+
<ion-datetime value="2022-02-28"></ion-datetime>
|
|
82
|
+
`, config);
|
|
83
|
+
await page.waitForSelector('.datetime-ready');
|
|
84
|
+
const calendarMonthYear = page.locator('ion-datetime .calendar-month-year');
|
|
85
|
+
const calendarBody = page.locator('.calendar-body');
|
|
86
|
+
await expect(calendarMonthYear).toHaveText('February 2022');
|
|
87
|
+
await calendarBody.focus();
|
|
88
|
+
await page.waitForChanges();
|
|
89
|
+
await page.keyboard.press('ArrowRight');
|
|
90
|
+
await page.waitForChanges();
|
|
91
|
+
await expect(calendarMonthYear).toHaveText('March 2022');
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
});
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* (C) Ionic http://ionicframework.com - MIT License
|
|
3
|
+
*/
|
|
4
|
+
import { expect } from "@playwright/test";
|
|
5
|
+
import { configs, test } from "../../../../utils/test/playwright/index";
|
|
6
|
+
/**
|
|
7
|
+
* This behavior does not differ across
|
|
8
|
+
* modes/directions.
|
|
9
|
+
*/
|
|
10
|
+
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config, screenshot }) => {
|
|
11
|
+
test.describe(title('datetime: disabled'), () => {
|
|
12
|
+
test('should not have visual regressions', async ({ page }) => {
|
|
13
|
+
await page.setContent(`
|
|
14
|
+
<ion-datetime value="2022-02-05T00:00:00" min="2022-01-01T00:00:00" max="2022-02-20T23:59:59" day-values="5,6,10,11,15,16,20" show-default-buttons disabled></ion-datetime>
|
|
15
|
+
`, config);
|
|
16
|
+
const datetime = page.locator('ion-datetime');
|
|
17
|
+
await expect(datetime).toHaveScreenshot(screenshot(`datetime-disabled`));
|
|
18
|
+
});
|
|
19
|
+
test('date should be disabled', async ({ page }) => {
|
|
20
|
+
await page.setContent(`
|
|
21
|
+
<ion-datetime value="2022-02-28" disabled></ion-datetime>
|
|
22
|
+
`, config);
|
|
23
|
+
await page.waitForSelector('.datetime-ready');
|
|
24
|
+
const febFirstButton = page.locator(`.calendar-day[data-day='1'][data-month='2']`);
|
|
25
|
+
await expect(febFirstButton).toBeDisabled();
|
|
26
|
+
});
|
|
27
|
+
test('month-year button should be disabled', async ({ page }) => {
|
|
28
|
+
await page.setContent(`
|
|
29
|
+
<ion-datetime value="2022-02-28" disabled></ion-datetime>
|
|
30
|
+
`, config);
|
|
31
|
+
await page.waitForSelector('.datetime-ready');
|
|
32
|
+
const calendarMonthYear = page.locator('ion-datetime .calendar-month-year');
|
|
33
|
+
await expect(calendarMonthYear.locator('button')).toBeDisabled();
|
|
34
|
+
});
|
|
35
|
+
test('next and prev buttons should be disabled', async ({ page }) => {
|
|
36
|
+
await page.setContent(`
|
|
37
|
+
<ion-datetime value="2022-02-28" disabled></ion-datetime>
|
|
38
|
+
`, config);
|
|
39
|
+
const prevMonthButton = page.locator('ion-datetime .calendar-next-prev ion-button:first-of-type button');
|
|
40
|
+
const nextMonthButton = page.locator('ion-datetime .calendar-next-prev ion-button:last-of-type button');
|
|
41
|
+
await expect(prevMonthButton).toBeDisabled();
|
|
42
|
+
await expect(nextMonthButton).toBeDisabled();
|
|
43
|
+
});
|
|
44
|
+
test('clear button should be disabled', async ({ page }) => {
|
|
45
|
+
await page.setContent(`
|
|
46
|
+
|
|
47
|
+
<ion-datetime value="2022-02-22T16:30:00" show-default-buttons="true" show-clear-button="true" disabled></ion-datetime>
|
|
48
|
+
`, config);
|
|
49
|
+
await page.waitForSelector('.datetime-ready');
|
|
50
|
+
const clearButton = page.locator('#clear-button button');
|
|
51
|
+
await expect(clearButton).toBeDisabled();
|
|
52
|
+
});
|
|
53
|
+
test('should not navigate through months via right arrow key', async ({ page }) => {
|
|
54
|
+
await page.setContent(`
|
|
55
|
+
<ion-datetime value="2022-02-28" disabled></ion-datetime>
|
|
56
|
+
`, config);
|
|
57
|
+
await page.waitForSelector('.datetime-ready');
|
|
58
|
+
const calendarMonthYear = page.locator('ion-datetime .calendar-month-year');
|
|
59
|
+
const calendarBody = page.locator('.calendar-body');
|
|
60
|
+
await expect(calendarMonthYear).toHaveText('February 2022');
|
|
61
|
+
await calendarBody.focus();
|
|
62
|
+
await page.waitForChanges();
|
|
63
|
+
await page.keyboard.press('ArrowRight');
|
|
64
|
+
await page.waitForChanges();
|
|
65
|
+
await expect(calendarMonthYear).toHaveText('February 2022');
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
});
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* (C) Ionic http://ionicframework.com - MIT License
|
|
3
|
+
*/
|
|
4
|
+
import { expect } from "@playwright/test";
|
|
5
|
+
import { configs, test } from "../../../../utils/test/playwright/index";
|
|
6
|
+
/**
|
|
7
|
+
* This behavior does not differ across
|
|
8
|
+
* modes/directions.
|
|
9
|
+
*/
|
|
10
|
+
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config, screenshot }) => {
|
|
11
|
+
test.describe(title('datetime: readonly'), () => {
|
|
12
|
+
test('should not have visual regressions', async ({ page }) => {
|
|
13
|
+
await page.setContent(`
|
|
14
|
+
<ion-datetime value="2022-02-05T00:00:00" min="2022-01-01T00:00:00" max="2022-02-20T23:59:59" day-values="5,6,10,11,15,16,20" show-default-buttons readonly></ion-datetime>
|
|
15
|
+
`, config);
|
|
16
|
+
const datetime = page.locator('ion-datetime');
|
|
17
|
+
await expect(datetime).toHaveScreenshot(screenshot(`datetime-readonly`));
|
|
18
|
+
});
|
|
19
|
+
test('date should be disabled', async ({ page }) => {
|
|
20
|
+
await page.setContent(`
|
|
21
|
+
<ion-datetime value="2022-02-28" readonly></ion-datetime>
|
|
22
|
+
`, config);
|
|
23
|
+
await page.waitForSelector('.datetime-ready');
|
|
24
|
+
const febFirstButton = page.locator(`.calendar-day[data-day='1'][data-month='2']`);
|
|
25
|
+
await expect(febFirstButton).toBeDisabled();
|
|
26
|
+
});
|
|
27
|
+
test('should navigate months via month-year button', async ({ page }) => {
|
|
28
|
+
await page.setContent(`
|
|
29
|
+
<ion-datetime value="2022-02-22T16:30:00" readonly></ion-datetime>
|
|
30
|
+
`, config);
|
|
31
|
+
const ionChange = await page.spyOnEvent('ionChange');
|
|
32
|
+
await page.waitForSelector('.datetime-ready');
|
|
33
|
+
const calendarMonthYear = page.locator('ion-datetime .calendar-month-year');
|
|
34
|
+
await expect(calendarMonthYear).toHaveText('February 2022');
|
|
35
|
+
await calendarMonthYear.click();
|
|
36
|
+
await page.waitForChanges();
|
|
37
|
+
await page.locator('.month-column .picker-item[data-value="3"]').click();
|
|
38
|
+
await page.waitForChanges();
|
|
39
|
+
await expect(calendarMonthYear).toHaveText('March 2022');
|
|
40
|
+
await expect(ionChange).not.toHaveReceivedEvent();
|
|
41
|
+
});
|
|
42
|
+
test('should open picker using keyboard navigation', async ({ page, browserName }) => {
|
|
43
|
+
await page.setContent(`
|
|
44
|
+
<ion-datetime value="2022-02-22T16:30:00" readonly></ion-datetime>
|
|
45
|
+
`, config);
|
|
46
|
+
const tabKey = browserName === 'webkit' ? 'Alt+Tab' : 'Tab';
|
|
47
|
+
await page.waitForSelector('.datetime-ready');
|
|
48
|
+
const calendarMonthYear = page.locator('ion-datetime .calendar-month-year');
|
|
49
|
+
const monthYearButton = page.locator('.calendar-month-year ion-item');
|
|
50
|
+
await expect(calendarMonthYear).toHaveText('February 2022');
|
|
51
|
+
await page.keyboard.press(tabKey);
|
|
52
|
+
await expect(monthYearButton).toBeFocused();
|
|
53
|
+
await page.waitForChanges();
|
|
54
|
+
await page.keyboard.press('Enter');
|
|
55
|
+
await page.waitForChanges();
|
|
56
|
+
const marchPickerItem = page.locator('.month-column .picker-item[data-value="3"]');
|
|
57
|
+
await expect(marchPickerItem).toBeVisible();
|
|
58
|
+
});
|
|
59
|
+
test('should view next month via next button', async ({ page }) => {
|
|
60
|
+
await page.setContent(`
|
|
61
|
+
<ion-datetime value="2022-02-22T16:30:00" readonly></ion-datetime>
|
|
62
|
+
`, config);
|
|
63
|
+
const ionChange = await page.spyOnEvent('ionChange');
|
|
64
|
+
const calendarMonthYear = page.locator('ion-datetime .calendar-month-year');
|
|
65
|
+
await expect(calendarMonthYear).toHaveText('February 2022');
|
|
66
|
+
const nextMonthButton = page.locator('ion-datetime .calendar-next-prev ion-button + ion-button');
|
|
67
|
+
await nextMonthButton.click();
|
|
68
|
+
await page.waitForChanges();
|
|
69
|
+
await expect(calendarMonthYear).toHaveText('March 2022');
|
|
70
|
+
await expect(ionChange).not.toHaveReceivedEvent();
|
|
71
|
+
});
|
|
72
|
+
test('should not change value when the month is changed via keyboard navigation', async ({ page, browserName }) => {
|
|
73
|
+
await page.setContent(`
|
|
74
|
+
<ion-datetime value="2022-02-22T16:30:00" readonly></ion-datetime>
|
|
75
|
+
`, config);
|
|
76
|
+
const tabKey = browserName === 'webkit' ? 'Alt+Tab' : 'Tab';
|
|
77
|
+
const datetime = page.locator('ion-datetime');
|
|
78
|
+
const monthYearButton = page.locator('.calendar-month-year ion-item');
|
|
79
|
+
const prevButton = page.locator('.calendar-next-prev ion-button:nth-child(1)');
|
|
80
|
+
const nextButton = page.locator('.calendar-next-prev ion-button:nth-child(2)');
|
|
81
|
+
const calendarMonthYear = page.locator('ion-datetime .calendar-month-year');
|
|
82
|
+
await page.keyboard.press(tabKey);
|
|
83
|
+
await expect(monthYearButton).toBeFocused();
|
|
84
|
+
await page.keyboard.press(tabKey);
|
|
85
|
+
await expect(prevButton).toBeFocused();
|
|
86
|
+
await page.keyboard.press(tabKey);
|
|
87
|
+
await expect(nextButton).toBeFocused();
|
|
88
|
+
// check value before & after selecting via keyboard
|
|
89
|
+
const initialValue = await datetime.evaluate((el) => el.value);
|
|
90
|
+
expect(initialValue).toBe('2022-02-22T16:30:00');
|
|
91
|
+
await expect(calendarMonthYear).toHaveText('February 2022');
|
|
92
|
+
await page.keyboard.press(tabKey);
|
|
93
|
+
await page.waitForChanges();
|
|
94
|
+
await page.keyboard.press('ArrowLeft');
|
|
95
|
+
await page.waitForChanges();
|
|
96
|
+
await expect(calendarMonthYear).toHaveText('January 2022');
|
|
97
|
+
await page.keyboard.press('Enter');
|
|
98
|
+
await page.waitForChanges();
|
|
99
|
+
const newValue = await datetime.evaluate((el) => el.value);
|
|
100
|
+
// should not have changed
|
|
101
|
+
expect(newValue).toBe('2022-02-22T16:30:00');
|
|
102
|
+
});
|
|
103
|
+
test('clear button should be disabled', async ({ page }) => {
|
|
104
|
+
await page.setContent(`
|
|
105
|
+
|
|
106
|
+
<ion-datetime value="2022-02-22T16:30:00" show-default-buttons="true" show-clear-button="true" readonly></ion-datetime>
|
|
107
|
+
`, config);
|
|
108
|
+
await page.waitForSelector('.datetime-ready');
|
|
109
|
+
const clearButton = page.locator('#clear-button button');
|
|
110
|
+
await expect(clearButton).toBeDisabled();
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
});
|
package/dist/docs.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"timestamp": "2023-
|
|
2
|
+
"timestamp": "2023-11-01T13:35:52",
|
|
3
3
|
"compiler": {
|
|
4
4
|
"name": "@stencil/core",
|
|
5
5
|
"version": "4.6.0",
|
|
@@ -7477,7 +7477,7 @@
|
|
|
7477
7477
|
"mutable": false,
|
|
7478
7478
|
"attr": "readonly",
|
|
7479
7479
|
"reflectToAttr": false,
|
|
7480
|
-
"docs": "If `true`, the datetime appears normal but
|
|
7480
|
+
"docs": "If `true`, the datetime appears normal but the selected date cannot be changed.",
|
|
7481
7481
|
"docsTags": [],
|
|
7482
7482
|
"default": "false",
|
|
7483
7483
|
"values": [
|