diff --git a/core/api.txt b/core/api.txt index d8ddc4ae8f..d54e7a6f40 100644 --- a/core/api.txt +++ b/core/api.txt @@ -394,7 +394,7 @@ ion-datetime,prop,disabled,boolean,false,false,false ion-datetime,prop,doneText,string,'Done',false,false ion-datetime,prop,firstDayOfWeek,number,0,false,false ion-datetime,prop,highlightedDates,((dateIsoString: string) => DatetimeHighlightStyle | undefined) | DatetimeHighlight[] | undefined,undefined,false,false -ion-datetime,prop,hourCycle,"h12" | "h23" | undefined,undefined,false,false +ion-datetime,prop,hourCycle,"h11" | "h12" | "h23" | "h24" | undefined,undefined,false,false ion-datetime,prop,hourValues,number | number[] | string | undefined,undefined,false,false ion-datetime,prop,isDateEnabled,((dateIsoString: string) => boolean) | undefined,undefined,false,false ion-datetime,prop,locale,string,'default',false,false @@ -1445,6 +1445,7 @@ ion-toast,prop,leaveAnimation,((baseEl: any, opts?: any) => Animation) | undefin ion-toast,prop,message,IonicSafeString | string | undefined,undefined,false,false ion-toast,prop,mode,"ios" | "md",undefined,false,false ion-toast,prop,position,"bottom" | "middle" | "top",'bottom',false,false +ion-toast,prop,positionAnchor,HTMLElement | string | undefined,undefined,false,false ion-toast,prop,translucent,boolean,false,false,false ion-toast,prop,trigger,string | undefined,undefined,false,false ion-toast,method,dismiss,dismiss(data?: any, role?: string) => Promise diff --git a/core/package-lock.json b/core/package-lock.json index 65e49ba30a..a0197e3a25 100644 --- a/core/package-lock.json +++ b/core/package-lock.json @@ -31,8 +31,8 @@ "@stencil/vue-output-target": "^0.8.6", "@types/jest": "^27.5.2", "@types/node": "^14.6.0", - "@typescript-eslint/eslint-plugin": "^5.17.0", - "@typescript-eslint/parser": "^5.17.0", + "@typescript-eslint/eslint-plugin": "^6.7.2", + "@typescript-eslint/parser": "^6.7.2", "clean-css-cli": "^5.6.1", "domino": "^2.1.6", "eslint": "^7.32.0", @@ -47,8 +47,7 @@ "sass": "^1.26.10", "serve": "^14.0.1", "stylelint": "^13.13.1", - "stylelint-order": "^4.1.0", - "typescript": "^4.0.5" + "stylelint-order": "^4.1.0" } }, "custom-rules": { @@ -642,6 +641,30 @@ "@capacitor/core": "^5.0.0" } }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.1.tgz", + "integrity": "sha512-PWiOzLIUAjN/w5K17PoF4n6sKBw0gqLHPhywmYHP4t1VFQQVYeb1yWsJwnMVEMl3tUHME7X/SJPZLmtG7XBDxQ==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, "node_modules/@eslint/eslintrc": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", @@ -1785,9 +1808,9 @@ } }, "node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "version": "7.0.13", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.13.tgz", + "integrity": "sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==", "dev": true }, "node_modules/@types/json5": { @@ -1844,6 +1867,12 @@ "@types/node": "*" } }, + "node_modules/@types/semver": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.2.tgz", + "integrity": "sha512-7aqorHYgdNO4DM36stTiGO3DvKoex9TQRwsJU6vMaFGyqpBA1MNZkz+PG3gaNUPpTAOYhT1WR7M1JyA3fbS9Cw==", + "dev": true + }, "node_modules/@types/stack-utils": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", @@ -1863,31 +1892,33 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.17.0.tgz", - "integrity": "sha512-qVstvQilEd89HJk3qcbKt/zZrfBZ+9h2ynpAGlWjWiizA7m/MtLT9RoX6gjtpE500vfIg8jogAkDzdCxbsFASQ==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.2.tgz", + "integrity": "sha512-ooaHxlmSgZTM6CHYAFRlifqh1OAr3PAQEwi7lhYhaegbnXrnh7CDcHmc3+ihhbQC7H0i4JF0psI5ehzkF6Yl6Q==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.17.0", - "@typescript-eslint/type-utils": "5.17.0", - "@typescript-eslint/utils": "5.17.0", - "debug": "^4.3.2", - "functional-red-black-tree": "^1.0.1", - "ignore": "^5.1.8", - "regexpp": "^3.2.0", - "semver": "^7.3.5", - "tsutils": "^3.21.0" + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.7.2", + "@typescript-eslint/type-utils": "6.7.2", + "@typescript-eslint/utils": "6.7.2", + "@typescript-eslint/visitor-keys": "6.7.2", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -1895,30 +1926,6 @@ } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "5.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.17.0.tgz", - "integrity": "sha512-DVvndq1QoxQH+hFv+MUQHrrWZ7gQ5KcJzyjhzcqB1Y2Xes1UQQkTRPUfRpqhS8mhTWsSb2+iyvDW1Lef5DD7vA==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.17.0", - "@typescript-eslint/types": "5.17.0", - "@typescript-eslint/typescript-estree": "5.17.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -1937,9 +1944,9 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -2091,25 +2098,26 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "5.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.17.0.tgz", - "integrity": "sha512-aRzW9Jg5Rlj2t2/crzhA2f23SIYFlF9mchGudyP0uiD6SenIxzKoLjwzHbafgHn39dNV/TV7xwQkLfFTZlJ4ig==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.2.tgz", + "integrity": "sha512-KA3E4ox0ws+SPyxQf9iSI25R6b4Ne78ORhNHeVKrPQnoYsb9UhieoiRoJgrzgEeKGOXhcY1i8YtOeCHHTDa6Fw==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.17.0", - "@typescript-eslint/types": "5.17.0", - "@typescript-eslint/typescript-estree": "5.17.0", - "debug": "^4.3.2" + "@typescript-eslint/scope-manager": "6.7.2", + "@typescript-eslint/types": "6.7.2", + "@typescript-eslint/typescript-estree": "6.7.2", + "@typescript-eslint/visitor-keys": "6.7.2", + "debug": "^4.3.4" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -2135,16 +2143,16 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.17.0.tgz", - "integrity": "sha512-062iCYQF/doQ9T2WWfJohQKKN1zmmXVfAcS3xaiialiw8ZUGy05Em6QVNYJGO34/sU1a7a+90U3dUNfqUDHr3w==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.2.tgz", + "integrity": "sha512-bgi6plgyZjEqapr7u2mhxGR6E8WCzKNUFWNh6fkpVe9+yzRZeYtDTbsIBzKbcxI+r1qVWt6VIoMSNZ4r2A+6Yw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.17.0", - "@typescript-eslint/visitor-keys": "5.17.0" + "@typescript-eslint/types": "6.7.2", + "@typescript-eslint/visitor-keys": "6.7.2" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", @@ -2152,24 +2160,25 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.17.0.tgz", - "integrity": "sha512-3hU0RynUIlEuqMJA7dragb0/75gZmwNwFf/QJokWzPehTZousP/MNifVSgjxNcDCkM5HI2K22TjQWUmmHUINSg==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.7.2.tgz", + "integrity": "sha512-36F4fOYIROYRl0qj95dYKx6kybddLtsbmPIYNK0OBeXv2j9L5nZ17j9jmfy+bIDHKQgn2EZX+cofsqi8NPATBQ==", "dev": true, "dependencies": { - "@typescript-eslint/utils": "5.17.0", - "debug": "^4.3.2", - "tsutils": "^3.21.0" + "@typescript-eslint/typescript-estree": "6.7.2", + "@typescript-eslint/utils": "6.7.2", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "*" + "eslint": "^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -2177,30 +2186,6 @@ } } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/utils": { - "version": "5.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.17.0.tgz", - "integrity": "sha512-DVvndq1QoxQH+hFv+MUQHrrWZ7gQ5KcJzyjhzcqB1Y2Xes1UQQkTRPUfRpqhS8mhTWsSb2+iyvDW1Lef5DD7vA==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.17.0", - "@typescript-eslint/types": "5.17.0", - "@typescript-eslint/typescript-estree": "5.17.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, "node_modules/@typescript-eslint/type-utils/node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -2219,12 +2204,12 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.17.0.tgz", - "integrity": "sha512-AgQ4rWzmCxOZLioFEjlzOI3Ch8giDWx8aUDxyNw9iOeCvD3GEYAB7dxWGQy4T/rPVe8iPmu73jPHuaSqcjKvxw==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.2.tgz", + "integrity": "sha512-flJYwMYgnUNDAN9/GAI3l8+wTmvTYdv64fcH8aoJK76Y+1FCZ08RtI5zDerM/FYT5DMkAc+19E4aLmd5KqdFyg==", "dev": true, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", @@ -2232,21 +2217,21 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.17.0.tgz", - "integrity": "sha512-X1gtjEcmM7Je+qJRhq7ZAAaNXYhTgqMkR10euC4Si6PIjb+kwEQHSxGazXUQXFyqfEXdkGf6JijUu5R0uceQzg==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.2.tgz", + "integrity": "sha512-kiJKVMLkoSciGyFU0TOY0fRxnp9qq1AzVOHNeN1+B9erKFCJ4Z8WdjAkKQPP+b1pWStGFqezMLltxO+308dJTQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.17.0", - "@typescript-eslint/visitor-keys": "5.17.0", - "debug": "^4.3.2", - "globby": "^11.0.4", + "@typescript-eslint/types": "6.7.2", + "@typescript-eslint/visitor-keys": "6.7.2", + "debug": "^4.3.4", + "globby": "^11.1.0", "is-glob": "^4.0.3", - "semver": "^7.3.5", - "tsutils": "^3.21.0" + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", @@ -2276,9 +2261,49 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.7.2.tgz", + "integrity": "sha512-ZCcBJug/TS6fXRTsoTkgnsvyWSiXwMNiPzBUani7hDidBdj1779qwM1FIAmpH4lvlOZNF3EScsxxuGifjpLSWQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.7.2", + "@typescript-eslint/types": "6.7.2", + "@typescript-eslint/typescript-estree": "6.7.2", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -2291,16 +2316,16 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.17.0.tgz", - "integrity": "sha512-6K/zlc4OfCagUu7Am/BD5k8PSWQOgh34Nrv9Rxe2tBzlJ7uOeJ/h7ugCGDCeEZHT6k2CJBhbk9IsbkPI0uvUkA==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.2.tgz", + "integrity": "sha512-uVw9VIMFBUTz8rIeaUT3fFe8xIUx8r4ywAdlQv1ifH+6acn/XF8Y6rwJ7XNmkNMDrTW+7+vxFFPIF40nJCVsMQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.17.0", - "eslint-visitor-keys": "^3.0.0" + "@typescript-eslint/types": "6.7.2", + "eslint-visitor-keys": "^3.4.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", @@ -4154,12 +4179,15 @@ } }, "node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint/node_modules/@babel/code-frame": { @@ -4981,6 +5009,12 @@ "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", "dev": true }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, "node_modules/hard-rejection": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", @@ -5177,9 +5211,9 @@ } }, "node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", "dev": true, "engines": { "node": ">= 4" @@ -9724,6 +9758,18 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/ts-api-utils": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", + "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", + "dev": true, + "engines": { + "node": ">=16.13.0" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, "node_modules/tsconfig-paths": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", @@ -9826,16 +9872,17 @@ } }, "node_modules/typescript": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz", - "integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", "dev": true, + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" } }, "node_modules/unbox-primitive": { @@ -10831,6 +10878,21 @@ "dev": true, "requires": {} }, + "@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^3.3.0" + } + }, + "@eslint-community/regexpp": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.1.tgz", + "integrity": "sha512-PWiOzLIUAjN/w5K17PoF4n6sKBw0gqLHPhywmYHP4t1VFQQVYeb1yWsJwnMVEMl3tUHME7X/SJPZLmtG7XBDxQ==", + "dev": true + }, "@eslint/eslintrc": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", @@ -11667,9 +11729,9 @@ } }, "@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "version": "7.0.13", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.13.tgz", + "integrity": "sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==", "dev": true }, "@types/json5": { @@ -11726,6 +11788,12 @@ "@types/node": "*" } }, + "@types/semver": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.2.tgz", + "integrity": "sha512-7aqorHYgdNO4DM36stTiGO3DvKoex9TQRwsJU6vMaFGyqpBA1MNZkz+PG3gaNUPpTAOYhT1WR7M1JyA3fbS9Cw==", + "dev": true + }, "@types/stack-utils": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", @@ -11745,36 +11813,24 @@ "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "5.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.17.0.tgz", - "integrity": "sha512-qVstvQilEd89HJk3qcbKt/zZrfBZ+9h2ynpAGlWjWiizA7m/MtLT9RoX6gjtpE500vfIg8jogAkDzdCxbsFASQ==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.2.tgz", + "integrity": "sha512-ooaHxlmSgZTM6CHYAFRlifqh1OAr3PAQEwi7lhYhaegbnXrnh7CDcHmc3+ihhbQC7H0i4JF0psI5ehzkF6Yl6Q==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.17.0", - "@typescript-eslint/type-utils": "5.17.0", - "@typescript-eslint/utils": "5.17.0", - "debug": "^4.3.2", - "functional-red-black-tree": "^1.0.1", - "ignore": "^5.1.8", - "regexpp": "^3.2.0", - "semver": "^7.3.5", - "tsutils": "^3.21.0" + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.7.2", + "@typescript-eslint/type-utils": "6.7.2", + "@typescript-eslint/utils": "6.7.2", + "@typescript-eslint/visitor-keys": "6.7.2", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" }, "dependencies": { - "@typescript-eslint/utils": { - "version": "5.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.17.0.tgz", - "integrity": "sha512-DVvndq1QoxQH+hFv+MUQHrrWZ7gQ5KcJzyjhzcqB1Y2Xes1UQQkTRPUfRpqhS8mhTWsSb2+iyvDW1Lef5DD7vA==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.17.0", - "@typescript-eslint/types": "5.17.0", - "@typescript-eslint/typescript-estree": "5.17.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" - } - }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -11785,9 +11841,9 @@ } }, "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -11877,15 +11933,16 @@ } }, "@typescript-eslint/parser": { - "version": "5.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.17.0.tgz", - "integrity": "sha512-aRzW9Jg5Rlj2t2/crzhA2f23SIYFlF9mchGudyP0uiD6SenIxzKoLjwzHbafgHn39dNV/TV7xwQkLfFTZlJ4ig==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.2.tgz", + "integrity": "sha512-KA3E4ox0ws+SPyxQf9iSI25R6b4Ne78ORhNHeVKrPQnoYsb9UhieoiRoJgrzgEeKGOXhcY1i8YtOeCHHTDa6Fw==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.17.0", - "@typescript-eslint/types": "5.17.0", - "@typescript-eslint/typescript-estree": "5.17.0", - "debug": "^4.3.2" + "@typescript-eslint/scope-manager": "6.7.2", + "@typescript-eslint/types": "6.7.2", + "@typescript-eslint/typescript-estree": "6.7.2", + "@typescript-eslint/visitor-keys": "6.7.2", + "debug": "^4.3.4" }, "dependencies": { "debug": { @@ -11900,40 +11957,27 @@ } }, "@typescript-eslint/scope-manager": { - "version": "5.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.17.0.tgz", - "integrity": "sha512-062iCYQF/doQ9T2WWfJohQKKN1zmmXVfAcS3xaiialiw8ZUGy05Em6QVNYJGO34/sU1a7a+90U3dUNfqUDHr3w==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.2.tgz", + "integrity": "sha512-bgi6plgyZjEqapr7u2mhxGR6E8WCzKNUFWNh6fkpVe9+yzRZeYtDTbsIBzKbcxI+r1qVWt6VIoMSNZ4r2A+6Yw==", "dev": true, "requires": { - "@typescript-eslint/types": "5.17.0", - "@typescript-eslint/visitor-keys": "5.17.0" + "@typescript-eslint/types": "6.7.2", + "@typescript-eslint/visitor-keys": "6.7.2" } }, "@typescript-eslint/type-utils": { - "version": "5.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.17.0.tgz", - "integrity": "sha512-3hU0RynUIlEuqMJA7dragb0/75gZmwNwFf/QJokWzPehTZousP/MNifVSgjxNcDCkM5HI2K22TjQWUmmHUINSg==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.7.2.tgz", + "integrity": "sha512-36F4fOYIROYRl0qj95dYKx6kybddLtsbmPIYNK0OBeXv2j9L5nZ17j9jmfy+bIDHKQgn2EZX+cofsqi8NPATBQ==", "dev": true, "requires": { - "@typescript-eslint/utils": "5.17.0", - "debug": "^4.3.2", - "tsutils": "^3.21.0" + "@typescript-eslint/typescript-estree": "6.7.2", + "@typescript-eslint/utils": "6.7.2", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" }, "dependencies": { - "@typescript-eslint/utils": { - "version": "5.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.17.0.tgz", - "integrity": "sha512-DVvndq1QoxQH+hFv+MUQHrrWZ7gQ5KcJzyjhzcqB1Y2Xes1UQQkTRPUfRpqhS8mhTWsSb2+iyvDW1Lef5DD7vA==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.17.0", - "@typescript-eslint/types": "5.17.0", - "@typescript-eslint/typescript-estree": "5.17.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" - } - }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -11946,24 +11990,24 @@ } }, "@typescript-eslint/types": { - "version": "5.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.17.0.tgz", - "integrity": "sha512-AgQ4rWzmCxOZLioFEjlzOI3Ch8giDWx8aUDxyNw9iOeCvD3GEYAB7dxWGQy4T/rPVe8iPmu73jPHuaSqcjKvxw==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.2.tgz", + "integrity": "sha512-flJYwMYgnUNDAN9/GAI3l8+wTmvTYdv64fcH8aoJK76Y+1FCZ08RtI5zDerM/FYT5DMkAc+19E4aLmd5KqdFyg==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.17.0.tgz", - "integrity": "sha512-X1gtjEcmM7Je+qJRhq7ZAAaNXYhTgqMkR10euC4Si6PIjb+kwEQHSxGazXUQXFyqfEXdkGf6JijUu5R0uceQzg==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.2.tgz", + "integrity": "sha512-kiJKVMLkoSciGyFU0TOY0fRxnp9qq1AzVOHNeN1+B9erKFCJ4Z8WdjAkKQPP+b1pWStGFqezMLltxO+308dJTQ==", "dev": true, "requires": { - "@typescript-eslint/types": "5.17.0", - "@typescript-eslint/visitor-keys": "5.17.0", - "debug": "^4.3.2", - "globby": "^11.0.4", + "@typescript-eslint/types": "6.7.2", + "@typescript-eslint/visitor-keys": "6.7.2", + "debug": "^4.3.4", + "globby": "^11.1.0", "is-glob": "^4.0.3", - "semver": "^7.3.5", - "tsutils": "^3.21.0" + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" }, "dependencies": { "debug": { @@ -11976,9 +12020,35 @@ } }, "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@typescript-eslint/utils": { + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.7.2.tgz", + "integrity": "sha512-ZCcBJug/TS6fXRTsoTkgnsvyWSiXwMNiPzBUani7hDidBdj1779qwM1FIAmpH4lvlOZNF3EScsxxuGifjpLSWQ==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.7.2", + "@typescript-eslint/types": "6.7.2", + "@typescript-eslint/typescript-estree": "6.7.2", + "semver": "^7.5.4" + }, + "dependencies": { + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -11987,13 +12057,13 @@ } }, "@typescript-eslint/visitor-keys": { - "version": "5.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.17.0.tgz", - "integrity": "sha512-6K/zlc4OfCagUu7Am/BD5k8PSWQOgh34Nrv9Rxe2tBzlJ7uOeJ/h7ugCGDCeEZHT6k2CJBhbk9IsbkPI0uvUkA==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.2.tgz", + "integrity": "sha512-uVw9VIMFBUTz8rIeaUT3fFe8xIUx8r4ywAdlQv1ifH+6acn/XF8Y6rwJ7XNmkNMDrTW+7+vxFFPIF40nJCVsMQ==", "dev": true, "requires": { - "@typescript-eslint/types": "5.17.0", - "eslint-visitor-keys": "^3.0.0" + "@typescript-eslint/types": "6.7.2", + "eslint-visitor-keys": "^3.4.1" } }, "@zeit/schemas": { @@ -13542,9 +13612,9 @@ } }, "eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true }, "espree": { @@ -13994,6 +14064,12 @@ "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", "dev": true }, + "graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, "hard-rejection": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", @@ -14136,9 +14212,9 @@ } }, "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", "dev": true }, "import-fresh": { @@ -17500,6 +17576,13 @@ "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==", "dev": true }, + "ts-api-utils": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", + "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", + "dev": true, + "requires": {} + }, "tsconfig-paths": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", @@ -17582,10 +17665,11 @@ } }, "typescript": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz", - "integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==", - "dev": true + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "dev": true, + "peer": true }, "unbox-primitive": { "version": "1.0.1", diff --git a/core/package.json b/core/package.json index ca6c09783e..1dcf447537 100644 --- a/core/package.json +++ b/core/package.json @@ -53,8 +53,8 @@ "@stencil/vue-output-target": "^0.8.6", "@types/jest": "^27.5.2", "@types/node": "^14.6.0", - "@typescript-eslint/eslint-plugin": "^5.17.0", - "@typescript-eslint/parser": "^5.17.0", + "@typescript-eslint/eslint-plugin": "^6.7.2", + "@typescript-eslint/parser": "^6.7.2", "clean-css-cli": "^5.6.1", "domino": "^2.1.6", "eslint": "^7.32.0", @@ -69,8 +69,7 @@ "sass": "^1.26.10", "serve": "^14.0.1", "stylelint": "^13.13.1", - "stylelint-order": "^4.1.0", - "typescript": "^4.0.5" + "stylelint-order": "^4.1.0" }, "scripts": { "build": "npm run clean && npm run build.css && stencil build --es5 --docs-json dist/docs.json", diff --git a/core/src/components.d.ts b/core/src/components.d.ts index 62cfd30764..44ba508e79 100644 --- a/core/src/components.d.ts +++ b/core/src/components.d.ts @@ -15,7 +15,7 @@ import { RouteID, RouterDirection, RouterEventDetail, RouteWrite } from "./compo import { BreadcrumbCollapsedClickEventDetail } from "./components/breadcrumb/breadcrumb-interface"; import { CheckboxChangeEventDetail } from "./components/checkbox/checkbox-interface"; import { ScrollBaseDetail, ScrollDetail } from "./components/content/content-interface"; -import { DatetimeChangeEventDetail, DatetimeHighlight, DatetimeHighlightCallback, DatetimePresentation, TitleSelectedDatesFormatter } from "./components/datetime/datetime-interface"; +import { DatetimeChangeEventDetail, DatetimeHighlight, DatetimeHighlightCallback, DatetimeHourCycle, DatetimePresentation, TitleSelectedDatesFormatter } from "./components/datetime/datetime-interface"; import { SpinnerTypes } from "./components/spinner/spinner-configs"; import { InputChangeEventDetail, InputInputEventDetail } from "./components/input/input-interface"; import { CounterFormatter } from "./components/item/item-interface"; @@ -39,7 +39,7 @@ import { SelectChangeEventDetail, SelectCompareFn, SelectInterface } from "./com import { SelectPopoverOption } from "./components/select-popover/select-popover-interface"; import { TabBarChangedEventDetail, TabButtonClickEventDetail, TabButtonLayout } from "./components/tab-bar/tab-bar-interface"; import { TextareaChangeEventDetail, TextareaInputEventDetail } from "./components/textarea/textarea-interface"; -import { ToastButton, ToastLayout, ToastPosition } from "./components/toast/toast-interface"; +import { ToastButton, ToastDismissOptions, ToastLayout, ToastPosition, ToastPresentOptions } from "./components/toast/toast-interface"; import { ToggleChangeEventDetail } from "./components/toggle/toggle-interface"; export { AccordionGroupChangeEventDetail } from "./components/accordion-group/accordion-group-interface"; export { AnimationBuilder, AutocompleteTypes, Color, ComponentProps, ComponentRef, FrameworkDelegate, StyleEventDetail, TextFieldTypes } from "./interface"; @@ -51,7 +51,7 @@ export { RouteID, RouterDirection, RouterEventDetail, RouteWrite } from "./compo export { BreadcrumbCollapsedClickEventDetail } from "./components/breadcrumb/breadcrumb-interface"; export { CheckboxChangeEventDetail } from "./components/checkbox/checkbox-interface"; export { ScrollBaseDetail, ScrollDetail } from "./components/content/content-interface"; -export { DatetimeChangeEventDetail, DatetimeHighlight, DatetimeHighlightCallback, DatetimePresentation, TitleSelectedDatesFormatter } from "./components/datetime/datetime-interface"; +export { DatetimeChangeEventDetail, DatetimeHighlight, DatetimeHighlightCallback, DatetimeHourCycle, DatetimePresentation, TitleSelectedDatesFormatter } from "./components/datetime/datetime-interface"; export { SpinnerTypes } from "./components/spinner/spinner-configs"; export { InputChangeEventDetail, InputInputEventDetail } from "./components/input/input-interface"; export { CounterFormatter } from "./components/item/item-interface"; @@ -75,7 +75,7 @@ export { SelectChangeEventDetail, SelectCompareFn, SelectInterface } from "./com export { SelectPopoverOption } from "./components/select-popover/select-popover-interface"; export { TabBarChangedEventDetail, TabButtonClickEventDetail, TabButtonLayout } from "./components/tab-bar/tab-bar-interface"; export { TextareaChangeEventDetail, TextareaInputEventDetail } from "./components/textarea/textarea-interface"; -export { ToastButton, ToastLayout, ToastPosition } from "./components/toast/toast-interface"; +export { ToastButton, ToastDismissOptions, ToastLayout, ToastPosition, ToastPresentOptions } from "./components/toast/toast-interface"; export { ToggleChangeEventDetail } from "./components/toggle/toggle-interface"; export namespace Components { interface IonAccordion { @@ -865,7 +865,7 @@ export namespace Components { /** * The hour cycle of the `ion-datetime`. If no value is set, this is specified by the current locale. */ - "hourCycle"?: 'h23' | 'h12'; + "hourCycle"?: DatetimeHourCycle; /** * Values used to create the list of selectable hours. By default the hour values range from `0` to `23` for 24-hour, or `1` to `12` for 12-hour. However, to control exactly which hours to display, the `hourValues` input can take a number, an array of numbers, or a string of comma separated numbers. */ @@ -3157,9 +3157,13 @@ export namespace Components { "onWillDismiss": () => Promise>; "overlayIndex": number; /** - * The position of the toast on the screen. + * The starting position of the toast on the screen. Can be tweaked further using the `positionAnchor` property. */ "position": ToastPosition; + /** + * The element to anchor the toast's position to. Can be set as a direct reference or the ID of the element. With `position="bottom"`, the toast will sit above the chosen element. With `position="top"`, the toast will sit below the chosen element. With `position="middle"`, the value of `positionAnchor` is ignored. + */ + "positionAnchor"?: HTMLElement | string; /** * Present the toast overlay after it has been created. */ @@ -4889,7 +4893,7 @@ declare namespace LocalJSX { /** * The hour cycle of the `ion-datetime`. If no value is set, this is specified by the current locale. */ - "hourCycle"?: 'h23' | 'h12'; + "hourCycle"?: DatetimeHourCycle; /** * Values used to create the list of selectable hours. By default the hour values range from `0` to `23` for 24-hour, or `1` to `12` for 12-hour. However, to control exactly which hours to display, the `hourValues` input can take a number, an array of numbers, or a string of comma separated numbers. */ @@ -7307,9 +7311,13 @@ declare namespace LocalJSX { "onWillPresent"?: (event: IonToastCustomEvent) => void; "overlayIndex": number; /** - * The position of the toast on the screen. + * The starting position of the toast on the screen. Can be tweaked further using the `positionAnchor` property. */ "position"?: ToastPosition; + /** + * The element to anchor the toast's position to. Can be set as a direct reference or the ID of the element. With `position="bottom"`, the toast will sit above the chosen element. With `position="top"`, the toast will sit below the chosen element. With `position="middle"`, the value of `positionAnchor` is ignored. + */ + "positionAnchor"?: HTMLElement | string; /** * If `true`, the toast will be translucent. Only applies when the mode is `"ios"` and the device supports [`backdrop-filter`](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter#Browser_compatibility). */ diff --git a/core/src/components/alert/alert.tsx b/core/src/components/alert/alert.tsx index b8b7de6b8f..4568e45a38 100644 --- a/core/src/components/alert/alert.tsx +++ b/core/src/components/alert/alert.tsx @@ -228,6 +228,15 @@ export class Alert implements ComponentInterface, OverlayInterface { onKeydown(ev: any) { const inputTypes = new Set(this.processedInputs.map((i) => i.type)); + /** + * Based on keyboard navigation requirements, the + * checkbox should not respond to the enter keydown event. + */ + if (inputTypes.has('checkbox') && ev.key === 'Enter') { + ev.preventDefault(); + return; + } + // The only inputs we want to navigate between using arrow keys are the radios // ignore the keydown event if it is not on a radio button if ( diff --git a/core/src/components/alert/test/a11y/alert.e2e.ts b/core/src/components/alert/test/a11y/alert.e2e.ts index 3301cb82fa..f86dc5c841 100644 --- a/core/src/components/alert/test/a11y/alert.e2e.ts +++ b/core/src/components/alert/test/a11y/alert.e2e.ts @@ -76,5 +76,22 @@ configs({ directions: ['ltr'] }).forEach(({ config, title }) => { await expect(alertButton).toHaveAttribute('aria-labelledby', 'close-label'); await expect(alertButton).toHaveAttribute('aria-label', 'close button'); }); + + test('should not toggle the checkbox when pressing the Enter key', async ({ page }) => { + const didPresent = await page.spyOnEvent('ionAlertDidPresent'); + + const button = page.locator('#checkbox'); + await button.click(); + + await didPresent.next(); + + const alertCheckbox = page.locator('ion-alert .alert-checkbox'); + const ariaChecked = await alertCheckbox.getAttribute('aria-checked'); + + await expect(alertCheckbox).toHaveAttribute('aria-checked', ariaChecked!); + + await alertCheckbox.press('Enter'); + await expect(alertCheckbox).toHaveAttribute('aria-checked', ariaChecked!); + }); }); }); diff --git a/core/src/components/alert/test/a11y/index.html b/core/src/components/alert/test/a11y/index.html index 2d642e85cb..180e901782 100644 --- a/core/src/components/alert/test/a11y/index.html +++ b/core/src/components/alert/test/a11y/index.html @@ -25,6 +25,7 @@ No Message Custom Aria Aria Label Button + Checkbox diff --git a/core/src/components/datetime-button/datetime-button.tsx b/core/src/components/datetime-button/datetime-button.tsx index 43467911c8..7ce3ca4163 100644 --- a/core/src/components/datetime-button/datetime-button.tsx +++ b/core/src/components/datetime-button/datetime-button.tsx @@ -9,7 +9,7 @@ import type { Color } from '../../interface'; import type { DatetimePresentation } from '../datetime/datetime-interface'; import { getToday } from '../datetime/utils/data'; import { getMonthAndYear, getMonthDayAndYear, getLocalizedDateTime, getLocalizedTime } from '../datetime/utils/format'; -import { is24Hour } from '../datetime/utils/helpers'; +import { getHourCycle } from '../datetime/utils/helpers'; import { parseDate } from '../datetime/utils/parse'; /** * @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use. @@ -218,7 +218,7 @@ export class DatetimeButton implements ComponentInterface { * warning in the console. */ const firstParsedDatetime = parsedDatetimes[0]; - const use24Hour = is24Hour(locale, hourCycle); + const computedHourCycle = getHourCycle(locale, hourCycle); this.dateText = this.timeText = undefined; @@ -226,7 +226,7 @@ export class DatetimeButton implements ComponentInterface { case 'date-time': case 'time-date': const dateText = getMonthDayAndYear(locale, firstParsedDatetime); - const timeText = getLocalizedTime(locale, firstParsedDatetime, use24Hour); + const timeText = getLocalizedTime(locale, firstParsedDatetime, computedHourCycle); if (preferWheel) { this.dateText = `${dateText} ${timeText}`; } else { @@ -250,7 +250,7 @@ export class DatetimeButton implements ComponentInterface { } break; case 'time': - this.timeText = getLocalizedTime(locale, firstParsedDatetime, use24Hour); + this.timeText = getLocalizedTime(locale, firstParsedDatetime, computedHourCycle); break; case 'month-year': this.dateText = getMonthAndYear(locale, firstParsedDatetime); diff --git a/core/src/components/datetime/datetime-interface.ts b/core/src/components/datetime/datetime-interface.ts index 5f2772d6c4..255f39e22d 100644 --- a/core/src/components/datetime/datetime-interface.ts +++ b/core/src/components/datetime/datetime-interface.ts @@ -34,3 +34,5 @@ export type DatetimeHighlightStyle = export type DatetimeHighlight = { date: string } & DatetimeHighlightStyle; export type DatetimeHighlightCallback = (dateIsoString: string) => DatetimeHighlightStyle | undefined; + +export type DatetimeHourCycle = 'h11' | 'h12' | 'h23' | 'h24'; diff --git a/core/src/components/datetime/datetime.tsx b/core/src/components/datetime/datetime.tsx index d0b596d67c..6f9cd669ac 100644 --- a/core/src/components/datetime/datetime.tsx +++ b/core/src/components/datetime/datetime.tsx @@ -19,6 +19,7 @@ import type { DatetimeHighlight, DatetimeHighlightStyle, DatetimeHighlightCallback, + DatetimeHourCycle, } from './datetime-interface'; import { isSameDay, warnIfValueOutOfBounds, isBefore, isAfter } from './utils/comparison'; import { @@ -33,7 +34,7 @@ import { getCombinedDateColumnData, } from './utils/data'; import { formatValue, getLocalizedTime, getMonthAndDay, getMonthAndYear } from './utils/format'; -import { is24Hour, isLocaleDayPeriodRTL, isMonthFirstLocale, getNumDaysInMonth } from './utils/helpers'; +import { isLocaleDayPeriodRTL, isMonthFirstLocale, getNumDaysInMonth, getHourCycle } from './utils/helpers'; import { calculateHourFromAMPM, convertDataToISO, @@ -422,7 +423,7 @@ export class Datetime implements ComponentInterface { * The hour cycle of the `ion-datetime`. If no value is set, this is * specified by the current locale. */ - @Prop() hourCycle?: 'h23' | 'h12'; + @Prop() hourCycle?: DatetimeHourCycle; /** * If `cover`, the `ion-datetime` will expand to cover the full width of its container. @@ -2237,7 +2238,7 @@ export class Datetime implements ComponentInterface { private renderTimeOverlay() { const { hourCycle, isTimePopoverOpen, locale } = this; - const use24Hour = is24Hour(locale, hourCycle); + const computedHourCycle = getHourCycle(locale, hourCycle); const activePart = this.getActivePartsWithFallback(); return [ @@ -2270,7 +2271,7 @@ export class Datetime implements ComponentInterface { } }} > - {getLocalizedTime(locale, activePart, use24Hour)} + {getLocalizedTime(locale, activePart, computedHourCycle)} , { + it('should generate formatted h12 hours and AM/PM data data', () => { + const refParts = { month: 5, year: 2021, day: 1, hour: 4, minute: 30 }; + const results = getTimeColumnsData('en-US', refParts, 'h12'); + + expect(results.hoursData).toEqual([ + { text: '12', value: 0 }, + { text: '1', value: 1 }, + { text: '2', value: 2 }, + { text: '3', value: 3 }, + { text: '4', value: 4 }, + { text: '5', value: 5 }, + { text: '6', value: 6 }, + { text: '7', value: 7 }, + { text: '8', value: 8 }, + { text: '9', value: 9 }, + { text: '10', value: 10 }, + { text: '11', value: 11 }, + ]); + expect(results.dayPeriodData).toEqual([ + { text: 'AM', value: 'am' }, + { text: 'PM', value: 'pm' }, + ]); + }); + it('should generate formatted h23 hours and AM/PM data data', () => { + const refParts = { month: 5, year: 2021, day: 1, hour: 4, minute: 30 }; + const results = getTimeColumnsData('en-US', refParts, 'h23'); + + expect(results.hoursData).toEqual([ + { text: '00', value: 0 }, + { text: '01', value: 1 }, + { text: '02', value: 2 }, + { text: '03', value: 3 }, + { text: '04', value: 4 }, + { text: '05', value: 5 }, + { text: '06', value: 6 }, + { text: '07', value: 7 }, + { text: '08', value: 8 }, + { text: '09', value: 9 }, + { text: '10', value: 10 }, + { text: '11', value: 11 }, + { text: '12', value: 12 }, + { text: '13', value: 13 }, + { text: '14', value: 14 }, + { text: '15', value: 15 }, + { text: '16', value: 16 }, + { text: '17', value: 17 }, + { text: '18', value: 18 }, + { text: '19', value: 19 }, + { text: '20', value: 20 }, + { text: '21', value: 21 }, + { text: '22', value: 22 }, + { text: '23', value: 23 }, + ]); + expect(results.dayPeriodData).toEqual([]); + }); + it('should generate formatted h11 hours and AM/PM data data', () => { + const refParts = { month: 5, year: 2021, day: 1, hour: 4, minute: 30 }; + const results = getTimeColumnsData('en-US', refParts, 'h11'); + + expect(results.hoursData).toEqual([ + { text: '0', value: 0 }, + { text: '1', value: 1 }, + { text: '2', value: 2 }, + { text: '3', value: 3 }, + { text: '4', value: 4 }, + { text: '5', value: 5 }, + { text: '6', value: 6 }, + { text: '7', value: 7 }, + { text: '8', value: 8 }, + { text: '9', value: 9 }, + { text: '10', value: 10 }, + { text: '11', value: 11 }, + ]); + expect(results.dayPeriodData).toEqual([ + { text: 'AM', value: 'am' }, + { text: 'PM', value: 'pm' }, + ]); + }); + it('should generate formatted h24 hours and AM/PM data data', () => { + const refParts = { month: 5, year: 2021, day: 1, hour: 4, minute: 30 }; + const results = getTimeColumnsData('en-US', refParts, 'h24'); + + expect(results.hoursData).toEqual([ + { text: '01', value: 1 }, + { text: '02', value: 2 }, + { text: '03', value: 3 }, + { text: '04', value: 4 }, + { text: '05', value: 5 }, + { text: '06', value: 6 }, + { text: '07', value: 7 }, + { text: '08', value: 8 }, + { text: '09', value: 9 }, + { text: '10', value: 10 }, + { text: '11', value: 11 }, + { text: '12', value: 12 }, + { text: '13', value: 13 }, + { text: '14', value: 14 }, + { text: '15', value: 15 }, + { text: '16', value: 16 }, + { text: '17', value: 17 }, + { text: '18', value: 18 }, + { text: '19', value: 19 }, + { text: '20', value: 20 }, + { text: '21', value: 21 }, + { text: '22', value: 22 }, + { text: '23', value: 23 }, + { text: '24', value: 0 }, + ]); + expect(results.dayPeriodData).toEqual([]); + }); +}); describe('generateMonths()', () => { it('should generate correct month data', () => { @@ -41,7 +162,7 @@ describe('generateTime()', () => { hour: 5, minute: 43, }; - const { hours, minutes } = generateTime(today); + const { hours, minutes } = generateTime('en-US', today); expect(hours.length).toEqual(12); expect(minutes.length).toEqual(60); @@ -61,7 +182,7 @@ describe('generateTime()', () => { hour: 2, minute: 40, }; - const { hours, minutes } = generateTime(today, 'h12', min); + const { hours, minutes } = generateTime('en-US', today, 'h12', min); expect(hours.length).toEqual(10); expect(minutes.length).toEqual(60); @@ -81,7 +202,7 @@ describe('generateTime()', () => { hour: 2, minute: 40, }; - const { hours, minutes } = generateTime(today, 'h12', min); + const { hours, minutes } = generateTime('en-US', today, 'h12', min); expect(hours.length).toEqual(12); expect(minutes.length).toEqual(60); @@ -101,7 +222,7 @@ describe('generateTime()', () => { hour: 7, minute: 44, }; - const { hours, minutes } = generateTime(today, 'h12', undefined, max); + const { hours, minutes } = generateTime('en-US', today, 'h12', undefined, max); expect(hours.length).toEqual(8); expect(minutes.length).toEqual(45); @@ -121,7 +242,7 @@ describe('generateTime()', () => { hour: 2, minute: 40, }; - const { hours, minutes } = generateTime(today, 'h12', undefined, max); + const { hours, minutes } = generateTime('en-US', today, 'h12', undefined, max); expect(hours.length).toEqual(12); expect(minutes.length).toEqual(60); @@ -141,7 +262,7 @@ describe('generateTime()', () => { hour: 2, minute: 40, }; - const { hours, minutes } = generateTime(today, 'h12', min); + const { hours, minutes } = generateTime('en-US', today, 'h12', min); expect(hours.length).toEqual(0); expect(minutes.length).toEqual(0); @@ -161,7 +282,7 @@ describe('generateTime()', () => { hour: 2, minute: 40, }; - const { hours, minutes } = generateTime(today, 'h12', undefined, max); + const { hours, minutes } = generateTime('en-US', today, 'h12', undefined, max); expect(hours.length).toEqual(0); expect(minutes.length).toEqual(0); @@ -185,7 +306,7 @@ describe('generateTime()', () => { year: 2021, }; - const { hours, minutes } = generateTime(today, 'h12', min, max); + const { hours, minutes } = generateTime('en-US', today, 'h12', min, max); expect(hours.length).toEqual(12); expect(minutes.length).toEqual(60); @@ -199,7 +320,7 @@ describe('generateTime()', () => { minute: 43, }; - const { hours, minutes } = generateTime(today, 'h12', undefined, undefined, [1, 2, 3], [10, 15, 20]); + const { hours, minutes } = generateTime('en-US', today, 'h12', undefined, undefined, [1, 2, 3], [10, 15, 20]); expect(hours).toStrictEqual([1, 2, 3]); expect(minutes).toStrictEqual([10, 15, 20]); @@ -229,7 +350,7 @@ describe('generateTime()', () => { minute: 14, }; - const { am, pm } = generateTime(today, 'h12', min, max); + const { am, pm } = generateTime('en-US', today, 'h12', min, max); expect(am).toBe(true); expect(pm).toBe(true); @@ -253,7 +374,7 @@ describe('generateTime()', () => { minute: 50, }; - const { hours } = generateTime(refValue, 'h23', minParts); + const { hours } = generateTime('en-US', refValue, 'h23', minParts); expect(hours).toStrictEqual([19, 20, 21, 22, 23]); }); @@ -276,7 +397,7 @@ describe('generateTime()', () => { minute: 30, }; - const { hours, minutes } = generateTime(refValue, 'h23', minParts); + const { hours, minutes } = generateTime('en-US', refValue, 'h23', minParts); expect(hours).toStrictEqual([19, 20, 21, 22, 23]); expect(minutes.length).toEqual(60); @@ -308,7 +429,7 @@ describe('generateTime()', () => { minute: 40, }; - const { hours } = generateTime(refValue, 'h23', minParts, maxParts); + const { hours } = generateTime('en-US', refValue, 'h23', minParts, maxParts); expect(hours).toStrictEqual([19, 20]); }); @@ -330,7 +451,7 @@ describe('generateTime()', () => { minute: 2, }; - const { minutes } = generateTime(refValue, 'h23', undefined, maxParts); + const { minutes } = generateTime('en-US', refValue, 'h23', undefined, maxParts); expect(minutes).toStrictEqual([0, 1, 2]); }); @@ -352,7 +473,7 @@ describe('generateTime()', () => { minute: 2, }; - const { minutes } = generateTime(refValue, 'h23', undefined, maxParts); + const { minutes } = generateTime('en-US', refValue, 'h23', undefined, maxParts); expect(minutes.length).toEqual(60); }); diff --git a/core/src/components/datetime/test/format.spec.ts b/core/src/components/datetime/test/format.spec.ts index d15de48788..b4d5f693bd 100644 --- a/core/src/components/datetime/test/format.spec.ts +++ b/core/src/components/datetime/test/format.spec.ts @@ -56,11 +56,17 @@ describe('getMonthAndDay()', () => { describe('getFormattedHour()', () => { it('should only add padding if using 24 hour time', () => { - expect(getFormattedHour(0, true)).toEqual('00'); - expect(getFormattedHour(0, false)).toEqual('12'); + expect(getFormattedHour(1, 'h11')).toEqual('1'); + expect(getFormattedHour(1, 'h12')).toEqual('1'); + expect(getFormattedHour(1, 'h23')).toEqual('01'); + expect(getFormattedHour(1, 'h24')).toEqual('01'); + }); - expect(getFormattedHour(10, true)).toEqual('10'); - expect(getFormattedHour(10, false)).toEqual('10'); + it('should return correct hour value for hour cycle', () => { + expect(getFormattedHour(0, 'h11')).toEqual('0'); + expect(getFormattedHour(0, 'h12')).toEqual('12'); + expect(getFormattedHour(0, 'h23')).toEqual('00'); + expect(getFormattedHour(0, 'h24')).toEqual('24'); }); }); @@ -111,7 +117,7 @@ describe('getLocalizedTime', () => { minute: 40, }; - expect(getLocalizedTime('en-US', datetimeParts, false)).toEqual('1:40 PM'); + expect(getLocalizedTime('en-US', datetimeParts, 'h12')).toEqual('1:40 PM'); }); it('should localize the time to AM', () => { @@ -123,7 +129,7 @@ describe('getLocalizedTime', () => { minute: 40, }; - expect(getLocalizedTime('en-US', datetimeParts, false)).toEqual('9:40 AM'); + expect(getLocalizedTime('en-US', datetimeParts, 'h12')).toEqual('9:40 AM'); }); it('should avoid Chromium bug when using 12 hour time in a 24 hour locale', () => { @@ -135,7 +141,7 @@ describe('getLocalizedTime', () => { minute: 0, }; - expect(getLocalizedTime('en-GB', datetimeParts, false)).toEqual('12:00 am'); + expect(getLocalizedTime('en-GB', datetimeParts, 'h12')).toEqual('12:00 am'); }); it('should parse time-only values correctly', () => { const datetimeParts = { @@ -143,7 +149,7 @@ describe('getLocalizedTime', () => { minute: 40, }; - expect(getLocalizedTime('en-US', datetimeParts, false)).toEqual('10:40 PM'); - expect(getLocalizedTime('en-US', datetimeParts, true)).toEqual('22:40'); + expect(getLocalizedTime('en-US', datetimeParts, 'h12')).toEqual('10:40 PM'); + expect(getLocalizedTime('en-US', datetimeParts, 'h23')).toEqual('22:40'); }); }); diff --git a/core/src/components/datetime/test/helpers.spec.ts b/core/src/components/datetime/test/helpers.spec.ts index e51f5181f3..2edd72574f 100644 --- a/core/src/components/datetime/test/helpers.spec.ts +++ b/core/src/components/datetime/test/helpers.spec.ts @@ -1,4 +1,4 @@ -import { isLeapYear, getNumDaysInMonth, is24Hour, isMonthFirstLocale } from '../utils/helpers'; +import { isLeapYear, getNumDaysInMonth, is24Hour, isMonthFirstLocale, getHourCycle } from '../utils/helpers'; describe('daysInMonth()', () => { it('should return correct days in month for month and year', () => { @@ -37,14 +37,29 @@ describe('isLeapYear()', () => { describe('is24Hour()', () => { it('should return true if the locale uses 24 hour time', () => { - expect(is24Hour('en-US')).toBe(false); - expect(is24Hour('en-US', 'h23')).toBe(true); - expect(is24Hour('en-US', 'h12')).toBe(false); - expect(is24Hour('en-US-u-hc-h23')).toBe(true); - expect(is24Hour('en-GB')).toBe(true); - expect(is24Hour('en-GB', 'h23')).toBe(true); - expect(is24Hour('en-GB', 'h12')).toBe(false); - expect(is24Hour('en-GB-u-hc-h12')).toBe(false); + expect(is24Hour('h11')).toBe(false); + expect(is24Hour('h12')).toBe(false); + expect(is24Hour('h23')).toBe(true); + expect(is24Hour('h24')).toBe(true); + }); +}); + +describe('getHourCycle()', () => { + it('should return the correct hour cycle', () => { + expect(getHourCycle('en-US')).toBe('h12'); + expect(getHourCycle('en-US', 'h23')).toBe('h23'); + expect(getHourCycle('en-US', 'h12')).toBe('h12'); + expect(getHourCycle('en-US-u-hc-h23')).toBe('h23'); + expect(getHourCycle('en-GB')).toBe('h23'); + expect(getHourCycle('en-GB', 'h23')).toBe('h23'); + expect(getHourCycle('en-GB', 'h12')).toBe('h12'); + expect(getHourCycle('en-GB-u-hc-h12')).toBe('h12'); + + expect(getHourCycle('en-GB', 'h11')).toBe('h11'); + expect(getHourCycle('en-GB-u-hc-h11')).toBe('h11'); + + expect(getHourCycle('en-GB', 'h24')).toBe('h24'); + expect(getHourCycle('en-GB-u-hc-h24')).toBe('h24'); }); }); diff --git a/core/src/components/datetime/test/hour-cycle/datetime.e2e.ts b/core/src/components/datetime/test/hour-cycle/datetime.e2e.ts index 1206b70298..73820a74b4 100644 --- a/core/src/components/datetime/test/hour-cycle/datetime.e2e.ts +++ b/core/src/components/datetime/test/hour-cycle/datetime.e2e.ts @@ -25,5 +25,27 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => const timeButton = page.locator('ion-datetime .time-body'); await expect(timeButton).toHaveText('4:30 PM'); }); + test('should set the h11 hour cycle correctly', async ({ page }) => { + await page.setContent( + ` + + `, + config + ); + + const timeButton = page.locator('ion-datetime .time-body'); + await expect(timeButton).toHaveText('0:30 AM'); + }); + test('should set the h24 hour cycle correctly', async ({ page }) => { + await page.setContent( + ` + + `, + config + ); + + const timeButton = page.locator('ion-datetime .time-body'); + await expect(timeButton).toHaveText('24:30'); + }); }); }); diff --git a/core/src/components/datetime/test/hour-cycle/index.html b/core/src/components/datetime/test/hour-cycle/index.html index 0c9450e48c..1c0f64bbca 100644 --- a/core/src/components/datetime/test/hour-cycle/index.html +++ b/core/src/components/datetime/test/hour-cycle/index.html @@ -51,6 +51,14 @@

h12 Hour cycle

+
+

h11 Hour cycle

+ +
+
+

h24 Hour cycle

+ +

h23 Hour cycle (Extension Tag)

diff --git a/core/src/components/datetime/utils/data.ts b/core/src/components/datetime/utils/data.ts index faf782f202..8841e58ffc 100644 --- a/core/src/components/datetime/utils/data.ts +++ b/core/src/components/datetime/utils/data.ts @@ -1,6 +1,6 @@ import type { Mode } from '../../../interface'; import type { PickerColumnItem } from '../../picker-column-internal/picker-column-internal-interfaces'; -import type { DatetimeParts } from '../datetime-interface'; +import type { DatetimeParts, DatetimeHourCycle } from '../datetime-interface'; import { isAfter, isBefore, isSameDay } from './comparison'; import { @@ -11,7 +11,7 @@ import { getTodayLabel, getYear, } from './format'; -import { getNumDaysInMonth, is24Hour } from './helpers'; +import { getNumDaysInMonth, is24Hour, getHourCycle } from './helpers'; import { getNextMonth, getPreviousMonth, getInternalHourValue } from './manipulation'; /** @@ -44,9 +44,19 @@ const minutes = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, ]; + +// h11 hour system uses 0-11. Midnight starts at 0:00am. +const hour11 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; + +// h12 hour system uses 0-12. Midnight starts at 12:00am. const hour12 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; + +// h23 hour system uses 0-23. Midnight starts at 0:00. const hour23 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]; +// h24 hour system uses 1-24. Midnight starts at 24:00. +const hour24 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 0]; + /** * Given a locale and a mode, * return an array with formatted days @@ -125,21 +135,42 @@ export const getDaysOfMonth = (month: number, year: number, firstDayOfWeek: numb return days; }; +/** + * Returns an array of pre-defined hour + * values based on the provided hourCycle. + */ +const getHourData = (hourCycle: DatetimeHourCycle) => { + switch (hourCycle) { + case 'h11': + return hour11; + case 'h12': + return hour12; + case 'h23': + return hour23; + case 'h24': + return hour24; + default: + throw new Error(`Invalid hour cycle "${hourCycle}"`); + } +}; + /** * Given a local, reference datetime parts and option * max/min bound datetime parts, calculate the acceptable * hour and minute values according to the bounds and locale. */ export const generateTime = ( + locale: string, refParts: DatetimeParts, - hourCycle: 'h12' | 'h23' = 'h12', + hourCycle: DatetimeHourCycle = 'h12', minParts?: DatetimeParts, maxParts?: DatetimeParts, hourValues?: number[], minuteValues?: number[] ) => { - const use24Hour = hourCycle === 'h23'; - let processedHours = use24Hour ? hour23 : hour12; + const computedHourCycle = getHourCycle(locale, hourCycle); + const use24Hour = is24Hour(computedHourCycle); + let processedHours = getHourData(computedHourCycle); let processedMinutes = minutes; let isAMAllowed = true; let isPMAllowed = true; @@ -540,16 +571,18 @@ export const getCombinedDateColumnData = ( export const getTimeColumnsData = ( locale: string, refParts: DatetimeParts, - hourCycle?: 'h23' | 'h12', + hourCycle?: DatetimeHourCycle, minParts?: DatetimeParts, maxParts?: DatetimeParts, allowedHourValues?: number[], allowedMinuteValues?: number[] ): { [key: string]: PickerColumnItem[] } => { - const use24Hour = is24Hour(locale, hourCycle); + const computedHourCycle = getHourCycle(locale, hourCycle); + const use24Hour = is24Hour(computedHourCycle); const { hours, minutes, am, pm } = generateTime( + locale, refParts, - use24Hour ? 'h23' : 'h12', + computedHourCycle, minParts, maxParts, allowedHourValues, @@ -558,7 +591,7 @@ export const getTimeColumnsData = ( const hoursItems = hours.map((hour) => { return { - text: getFormattedHour(hour, use24Hour), + text: getFormattedHour(hour, computedHourCycle), value: getInternalHourValue(hour, use24Hour, refParts.ampm), }; }); diff --git a/core/src/components/datetime/utils/format.ts b/core/src/components/datetime/utils/format.ts index 179bf515e0..0f70299dc5 100644 --- a/core/src/components/datetime/utils/format.ts +++ b/core/src/components/datetime/utils/format.ts @@ -1,5 +1,6 @@ -import type { DatetimeParts } from '../datetime-interface'; +import type { DatetimeParts, DatetimeHourCycle } from '../datetime-interface'; +import { is24Hour } from './helpers'; import { convertDataToISO } from './manipulation'; const getFormattedDayPeriod = (dayPeriod?: string) => { @@ -10,7 +11,7 @@ const getFormattedDayPeriod = (dayPeriod?: string) => { return dayPeriod.toUpperCase(); }; -export const getLocalizedTime = (locale: string, refParts: DatetimeParts, use24Hour: boolean): string => { +export const getLocalizedTime = (locale: string, refParts: DatetimeParts, hourCycle: DatetimeHourCycle): string => { const timeParts: Pick = { hour: refParts.hour, minute: refParts.minute, @@ -34,7 +35,7 @@ export const getLocalizedTime = (locale: string, refParts: DatetimeParts, use24H * We use hourCycle here instead of hour12 due to: * https://bugs.chromium.org/p/chromium/issues/detail?id=1347316&q=hour12&can=2 */ - hourCycle: use24Hour ? 'h23' : 'h12', + hourCycle, /** * Setting Z at the end indicates that this * date string is in the UTC time zone. This @@ -83,18 +84,34 @@ export const addTimePadding = (value: number): string => { * 12 hour times it ensures that * hour 0 is formatted as '12'. */ -export const getFormattedHour = (hour: number, use24Hour: boolean): string => { - if (use24Hour) { - return addTimePadding(hour); - } - +export const getFormattedHour = (hour: number, hourCycle: DatetimeHourCycle): string => { /** - * If using 12 hour - * format, make sure hour - * 0 is formatted as '12'. + * Midnight for h11 starts at 0:00am + * Midnight for h12 starts at 12:00am + * Midnight for h23 starts at 00:00 + * Midnight for h24 starts at 24:00 */ if (hour === 0) { - return '12'; + switch (hourCycle) { + case 'h11': + return '0'; + case 'h12': + return '12'; + case 'h23': + return '00'; + case 'h24': + return '24'; + default: + throw new Error(`Invalid hour cycle "${hourCycle}"`); + } + } + + const use24Hour = is24Hour(hourCycle); + /** + * h23 and h24 use 24 hour times. + */ + if (use24Hour) { + return addTimePadding(hour); } return hour.toString(); diff --git a/core/src/components/datetime/utils/helpers.ts b/core/src/components/datetime/utils/helpers.ts index 370de63b42..a0df7a9946 100644 --- a/core/src/components/datetime/utils/helpers.ts +++ b/core/src/components/datetime/utils/helpers.ts @@ -1,10 +1,4 @@ -/** - * Typescript 4.x does not recognize hourCycle as a valid option. - * See https://github.com/microsoft/TypeScript/issues/34399. - */ -interface DatetimeFormatOptions extends Intl.ResolvedDateTimeFormatOptions { - hourCycle?: 'h11' | 'h12' | 'h23' | 'h24'; -} +import type { DatetimeHourCycle } from '../datetime-interface'; /** * Determines if given year is a @@ -16,13 +10,19 @@ export const isLeapYear = (year: number) => { return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; }; -export const is24Hour = (locale: string, hourCycle?: 'h23' | 'h12') => { +/** + * Determines the hour cycle for a user. + * If the hour cycle is explicitly defined, just use that. + * Otherwise, we try to derive it from either the specified + * locale extension tags or from Intl.DateTimeFormat directly. + */ +export const getHourCycle = (locale: string, hourCycle?: DatetimeHourCycle) => { /** - * If developer has explicitly enabled h23 time + * If developer has explicitly enabled 24-hour time * then return early and do not look at the system default. */ if (hourCycle !== undefined) { - return hourCycle === 'h23'; + return hourCycle; } /** @@ -32,9 +32,9 @@ export const is24Hour = (locale: string, hourCycle?: 'h23' | 'h12') => { * option into the locale string. Example: `en-US-u-hc-h23` */ const formatted = new Intl.DateTimeFormat(locale, { hour: 'numeric' }); - const options = formatted.resolvedOptions() as DatetimeFormatOptions; + const options = formatted.resolvedOptions(); if (options.hourCycle !== undefined) { - return options.hourCycle === 'h23'; + return options.hourCycle; } /** @@ -50,7 +50,34 @@ export const is24Hour = (locale: string, hourCycle?: 'h23' | 'h12') => { throw new Error('Hour value not found from DateTimeFormat'); } - return hour.value === '00'; + /** + * Midnight for h11 starts at 0:00am + * Midnight for h12 starts at 12:00am + * Midnight for h23 starts at 00:00 + * Midnight for h24 starts at 24:00 + */ + switch (hour.value) { + case '0': + return 'h11'; + case '12': + return 'h12'; + case '00': + return 'h23'; + case '24': + return 'h24'; + default: + throw new Error(`Invalid hour cycle "${hourCycle}"`); + } +}; + +/** + * Determine if the hour cycle uses a 24-hour format. + * Returns true for h23 and h24. Returns false otherwise. + * If you don't know the hourCycle, use getHourCycle above + * and pass the result into this function. + */ +export const is24Hour = (hourCycle: DatetimeHourCycle) => { + return hourCycle === 'h23' || hourCycle === 'h24'; }; /** diff --git a/core/src/components/nav/nav.tsx b/core/src/components/nav/nav.tsx index 6cc7a321f3..de3c65e93e 100644 --- a/core/src/components/nav/nav.tsx +++ b/core/src/components/nav/nav.tsx @@ -901,6 +901,7 @@ export class Nav implements NavOutlet { : undefined; const mode = getIonMode(this); const enteringEl = enteringView.element!; + // eslint-disable-next-line @typescript-eslint/prefer-optional-chain const leavingEl = leavingView && leavingView.element!; const animationOpts: TransitionOptions = { mode, diff --git a/core/src/components/router/router.tsx b/core/src/components/router/router.tsx index 7a4b73a818..cc80971996 100644 --- a/core/src/components/router/router.tsx +++ b/core/src/components/router/router.tsx @@ -312,6 +312,7 @@ export class Router implements ComponentInterface { const routes = readRoutes(this.el); const fromChain = findChainForSegments(from, routes); + // eslint-disable-next-line @typescript-eslint/prefer-optional-chain const beforeLeaveHook = fromChain && fromChain[fromChain.length - 1].beforeLeave; const canLeave = beforeLeaveHook ? await beforeLeaveHook() : true; @@ -320,6 +321,7 @@ export class Router implements ComponentInterface { } const toChain = findChainForSegments(to, routes); + // eslint-disable-next-line @typescript-eslint/prefer-optional-chain const beforeEnterHook = toChain && toChain[toChain.length - 1].beforeEnter; return beforeEnterHook ? beforeEnterHook() : true; diff --git a/core/src/components/router/utils/path.ts b/core/src/components/router/utils/path.ts index 7b4ed544e5..4305d84e98 100644 --- a/core/src/components/router/utils/path.ts +++ b/core/src/components/router/utils/path.ts @@ -48,6 +48,7 @@ export const chainToSegments = (chain: RouteChain): string[] | null => { for (const route of chain) { for (const segment of route.segments) { if (segment[0] === ':') { + // eslint-disable-next-line @typescript-eslint/prefer-optional-chain const param = route.params && route.params[segment.slice(1)]; if (!param) { return null; diff --git a/core/src/components/select/select.tsx b/core/src/components/select/select.tsx index 639d8e22a3..a508709400 100644 --- a/core/src/components/select/select.tsx +++ b/core/src/components/select/select.tsx @@ -1041,7 +1041,7 @@ Developers can use the "legacy" property to continue using the legacy form marku disabled={disabled} id={inputId} aria-label={this.ariaLabel} - aria-haspopup="listbox" + aria-haspopup="dialog" aria-expanded={`${isExpanded}`} onFocus={this.onFocus} onBlur={this.onBlur} diff --git a/core/src/components/toast/animations/ios.enter.ts b/core/src/components/toast/animations/ios.enter.ts index a515924323..55baa3bdd3 100644 --- a/core/src/components/toast/animations/ios.enter.ts +++ b/core/src/components/toast/animations/ios.enter.ts @@ -2,20 +2,19 @@ import { createAnimation } from '@utils/animation/animation'; import { getElementRoot } from '@utils/helpers'; import type { Animation } from '../../../interface'; +import type { ToastPresentOptions } from '../toast-interface'; /** * iOS Toast Enter Animation */ -export const iosEnterAnimation = (baseEl: HTMLElement, position: string): Animation => { +export const iosEnterAnimation = (baseEl: HTMLElement, opts: ToastPresentOptions): Animation => { const baseAnimation = createAnimation(); const wrapperAnimation = createAnimation(); + const { position, top, bottom } = opts; const root = getElementRoot(baseEl); const wrapperEl = root.querySelector('.toast-wrapper') as HTMLElement; - const bottom = `calc(-10px - var(--ion-safe-area-bottom, 0px))`; - const top = `calc(10px + var(--ion-safe-area-top, 0px))`; - wrapperAnimation.addElement(wrapperEl); switch (position) { diff --git a/core/src/components/toast/animations/ios.leave.ts b/core/src/components/toast/animations/ios.leave.ts index 8a7a131045..272003d5f9 100644 --- a/core/src/components/toast/animations/ios.leave.ts +++ b/core/src/components/toast/animations/ios.leave.ts @@ -1,21 +1,19 @@ import { createAnimation } from '@utils/animation/animation'; import { getElementRoot } from '@utils/helpers'; -import type { Animation } from '../../../interface'; +import type { Animation, ToastDismissOptions } from '../../../interface'; /** * iOS Toast Leave Animation */ -export const iosLeaveAnimation = (baseEl: HTMLElement, position: string): Animation => { +export const iosLeaveAnimation = (baseEl: HTMLElement, opts: ToastDismissOptions): Animation => { const baseAnimation = createAnimation(); const wrapperAnimation = createAnimation(); + const { position, top, bottom } = opts; const root = getElementRoot(baseEl); const wrapperEl = root.querySelector('.toast-wrapper') as HTMLElement; - const bottom = `calc(-10px - var(--ion-safe-area-bottom, 0px))`; - const top = `calc(10px + var(--ion-safe-area-top, 0px))`; - wrapperAnimation.addElement(wrapperEl); switch (position) { diff --git a/core/src/components/toast/animations/md.enter.ts b/core/src/components/toast/animations/md.enter.ts index 3d60caf5bf..f8f73f383a 100644 --- a/core/src/components/toast/animations/md.enter.ts +++ b/core/src/components/toast/animations/md.enter.ts @@ -2,20 +2,19 @@ import { createAnimation } from '@utils/animation/animation'; import { getElementRoot } from '@utils/helpers'; import type { Animation } from '../../../interface'; +import type { ToastPresentOptions } from '../toast-interface'; /** * MD Toast Enter Animation */ -export const mdEnterAnimation = (baseEl: HTMLElement, position: string): Animation => { +export const mdEnterAnimation = (baseEl: HTMLElement, opts: ToastPresentOptions): Animation => { const baseAnimation = createAnimation(); const wrapperAnimation = createAnimation(); + const { position, top, bottom } = opts; const root = getElementRoot(baseEl); const wrapperEl = root.querySelector('.toast-wrapper') as HTMLElement; - const bottom = `calc(8px + var(--ion-safe-area-bottom, 0px))`; - const top = `calc(8px + var(--ion-safe-area-top, 0px))`; - wrapperAnimation.addElement(wrapperEl); switch (position) { diff --git a/core/src/components/toast/animations/utils.ts b/core/src/components/toast/animations/utils.ts new file mode 100644 index 0000000000..47e883d57e --- /dev/null +++ b/core/src/components/toast/animations/utils.ts @@ -0,0 +1,95 @@ +import { win } from '@utils/browser'; +import { printIonWarning } from '@utils/logging'; +import type { Mode } from 'src/interface'; + +import type { ToastAnimationPosition, ToastPosition } from '../toast-interface'; + +/** + * Calculate the CSS top and bottom position of the toast, to be used + * as starting points for the animation keyframes. + * + * Note that MD animates bottom-positioned toasts using style.bottom, + * which calculates from the bottom edge of the screen, while iOS uses + * translateY, which calculates from the top edge of the screen. This + * is why the bottom calculates differ slightly between modes. + * + * @param position The value of the toast's position prop. + * @param positionAnchor The element the toast should be anchored to, + * if applicable. + * @param mode The toast component's mode (md, ios, etc). + * @param toast A reference to the toast element itself. + */ +export function getAnimationPosition( + position: ToastPosition, + positionAnchor: HTMLElement | undefined, + mode: Mode, + toast: HTMLElement +): ToastAnimationPosition { + /** + * Start with a predefined offset from the edge the toast will be + * positioned relative to, whether on the screen or anchor element. + */ + let offset: number; + if (mode === 'md') { + offset = 8; + } else { + offset = position === 'top' ? 10 : -10; + } + + /** + * If positionAnchor is defined, add in the distance from the target + * screen edge to the target anchor edge. For position="top", the + * bottom anchor edge is targeted. For position="bottom", the top + * anchor edge is targeted. + */ + if (positionAnchor && win) { + warnIfAnchorIsHidden(positionAnchor, toast); + + const box = positionAnchor.getBoundingClientRect(); + if (position === 'top') { + offset += box.bottom; + } else if (position === 'bottom') { + /** + * Just box.top is the distance from the top edge of the screen + * to the top edge of the anchor. We want to calculate from the + * bottom edge of the screen instead. + */ + if (mode === 'md') { + offset += win.innerHeight - box.top; + } else { + offset -= win.innerHeight - box.top; + } + } + + /** + * We don't include safe area here because that should already be + * accounted for when checking the position of the anchor. + */ + return { + top: `${offset}px`, + bottom: `${offset}px`, + }; + } else { + return { + top: `calc(${offset}px + var(--ion-safe-area-top, 0px))`, + bottom: + mode === 'md' + ? `calc(${offset}px + var(--ion-safe-area-bottom, 0px))` + : `calc(${offset}px - var(--ion-safe-area-bottom, 0px))`, + }; + } +} + +/** + * If the anchor element is hidden, getBoundingClientRect() + * will return all 0s for it, which can cause unexpected + * results in the position calculation when animating. + */ +function warnIfAnchorIsHidden(positionAnchor: HTMLElement, toast: HTMLElement) { + if (positionAnchor.offsetParent === null) { + printIonWarning( + 'The positionAnchor element for ion-toast was found in the DOM, but appears to be hidden. This may lead to unexpected positioning of the toast.', + toast + ); + } +} diff --git a/core/src/components/toast/test/position-anchor/index.html b/core/src/components/toast/test/position-anchor/index.html new file mode 100644 index 0000000000..b504912bf1 --- /dev/null +++ b/core/src/components/toast/test/position-anchor/index.html @@ -0,0 +1,94 @@ + + + + + Toast - positionAnchor + + + + + + + + + + + + + + Toast - positionAnchor + + + + + Anchor to Header + Anchor to Footer + Anchor to Header (Middle Position) + Anchor to Header (Element Ref) + Anchor to Hidden Element + + + + + + + + + + + + + Footer + + + + + + + diff --git a/core/src/components/toast/test/position-anchor/toast.e2e.ts b/core/src/components/toast/test/position-anchor/toast.e2e.ts new file mode 100644 index 0000000000..cfac7ac682 --- /dev/null +++ b/core/src/components/toast/test/position-anchor/toast.e2e.ts @@ -0,0 +1,56 @@ +import { expect } from '@playwright/test'; +import { configs, test } from '@utils/test/playwright'; + +configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => { + test.describe(title('toast: positionAnchor'), () => { + test.beforeEach(async ({ page }) => { + await page.goto('/src/components/toast/test/position-anchor', config); + + /** + * We need to screenshot the whole page to ensure the toasts are positioned + * correctly, but we don't need much extra white space between the header + * and footer. + */ + await page.setViewportSize({ + width: 425, + height: 425, + }); + }); + + test('should place top-position toast underneath anchor', async ({ page }) => { + const ionToastDidPresent = await page.spyOnEvent('ionToastDidPresent'); + + await page.click('#headerAnchor'); + await ionToastDidPresent.next(); + + await expect(page).toHaveScreenshot(screenshot(`toast-header-anchor`)); + }); + + test('should place bottom-position toast above anchor', async ({ page }) => { + const ionToastDidPresent = await page.spyOnEvent('ionToastDidPresent'); + + await page.click('#footerAnchor'); + await ionToastDidPresent.next(); + + await expect(page).toHaveScreenshot(screenshot(`toast-footer-anchor`)); + }); + + test('should ignore anchor for middle-position toast', async ({ page }) => { + const ionToastDidPresent = await page.spyOnEvent('ionToastDidPresent'); + + await page.click('#middleAnchor'); + await ionToastDidPresent.next(); + + await expect(page).toHaveScreenshot(screenshot(`toast-middle-anchor`)); + }); + + test('should correctly anchor toast when using an element reference', async ({ page }) => { + const ionToastDidPresent = await page.spyOnEvent('ionToastDidPresent'); + + await page.click('#headerElAnchor'); + await ionToastDidPresent.next(); + + await expect(page).toHaveScreenshot(screenshot(`toast-header-el-anchor`)); + }); + }); +}); diff --git a/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-footer-anchor-ios-ltr-Mobile-Chrome-linux.png b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-footer-anchor-ios-ltr-Mobile-Chrome-linux.png new file mode 100644 index 0000000000..e6d9e1e350 Binary files /dev/null and b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-footer-anchor-ios-ltr-Mobile-Chrome-linux.png differ diff --git a/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-footer-anchor-ios-ltr-Mobile-Firefox-linux.png b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-footer-anchor-ios-ltr-Mobile-Firefox-linux.png new file mode 100644 index 0000000000..4253e51a59 Binary files /dev/null and b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-footer-anchor-ios-ltr-Mobile-Firefox-linux.png differ diff --git a/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-footer-anchor-ios-ltr-Mobile-Safari-linux.png b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-footer-anchor-ios-ltr-Mobile-Safari-linux.png new file mode 100644 index 0000000000..826e0c0c8f Binary files /dev/null and b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-footer-anchor-ios-ltr-Mobile-Safari-linux.png differ diff --git a/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-footer-anchor-md-ltr-Mobile-Chrome-linux.png b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-footer-anchor-md-ltr-Mobile-Chrome-linux.png new file mode 100644 index 0000000000..6118471866 Binary files /dev/null and b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-footer-anchor-md-ltr-Mobile-Chrome-linux.png differ diff --git a/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-footer-anchor-md-ltr-Mobile-Firefox-linux.png b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-footer-anchor-md-ltr-Mobile-Firefox-linux.png new file mode 100644 index 0000000000..1f814424a3 Binary files /dev/null and b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-footer-anchor-md-ltr-Mobile-Firefox-linux.png differ diff --git a/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-footer-anchor-md-ltr-Mobile-Safari-linux.png b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-footer-anchor-md-ltr-Mobile-Safari-linux.png new file mode 100644 index 0000000000..0f032e947f Binary files /dev/null and b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-footer-anchor-md-ltr-Mobile-Safari-linux.png differ diff --git a/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-header-anchor-ios-ltr-Mobile-Chrome-linux.png b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-header-anchor-ios-ltr-Mobile-Chrome-linux.png new file mode 100644 index 0000000000..b5b7fe18c5 Binary files /dev/null and b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-header-anchor-ios-ltr-Mobile-Chrome-linux.png differ diff --git a/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-header-anchor-ios-ltr-Mobile-Firefox-linux.png b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-header-anchor-ios-ltr-Mobile-Firefox-linux.png new file mode 100644 index 0000000000..4a1063286a Binary files /dev/null and b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-header-anchor-ios-ltr-Mobile-Firefox-linux.png differ diff --git a/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-header-anchor-ios-ltr-Mobile-Safari-linux.png b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-header-anchor-ios-ltr-Mobile-Safari-linux.png new file mode 100644 index 0000000000..133edec6d3 Binary files /dev/null and b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-header-anchor-ios-ltr-Mobile-Safari-linux.png differ diff --git a/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-header-anchor-md-ltr-Mobile-Chrome-linux.png b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-header-anchor-md-ltr-Mobile-Chrome-linux.png new file mode 100644 index 0000000000..643d08ba84 Binary files /dev/null and b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-header-anchor-md-ltr-Mobile-Chrome-linux.png differ diff --git a/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-header-anchor-md-ltr-Mobile-Firefox-linux.png b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-header-anchor-md-ltr-Mobile-Firefox-linux.png new file mode 100644 index 0000000000..ed34cd5f40 Binary files /dev/null and b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-header-anchor-md-ltr-Mobile-Firefox-linux.png differ diff --git a/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-header-anchor-md-ltr-Mobile-Safari-linux.png b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-header-anchor-md-ltr-Mobile-Safari-linux.png new file mode 100644 index 0000000000..00aaba0520 Binary files /dev/null and b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-header-anchor-md-ltr-Mobile-Safari-linux.png differ diff --git a/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-header-el-anchor-ios-ltr-Mobile-Chrome-linux.png b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-header-el-anchor-ios-ltr-Mobile-Chrome-linux.png new file mode 100644 index 0000000000..b5b7fe18c5 Binary files /dev/null and b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-header-el-anchor-ios-ltr-Mobile-Chrome-linux.png differ diff --git a/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-header-el-anchor-ios-ltr-Mobile-Firefox-linux.png b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-header-el-anchor-ios-ltr-Mobile-Firefox-linux.png new file mode 100644 index 0000000000..4a1063286a Binary files /dev/null and b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-header-el-anchor-ios-ltr-Mobile-Firefox-linux.png differ diff --git a/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-header-el-anchor-ios-ltr-Mobile-Safari-linux.png b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-header-el-anchor-ios-ltr-Mobile-Safari-linux.png new file mode 100644 index 0000000000..133edec6d3 Binary files /dev/null and b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-header-el-anchor-ios-ltr-Mobile-Safari-linux.png differ diff --git a/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-header-el-anchor-md-ltr-Mobile-Chrome-linux.png b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-header-el-anchor-md-ltr-Mobile-Chrome-linux.png new file mode 100644 index 0000000000..643d08ba84 Binary files /dev/null and b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-header-el-anchor-md-ltr-Mobile-Chrome-linux.png differ diff --git a/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-header-el-anchor-md-ltr-Mobile-Firefox-linux.png b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-header-el-anchor-md-ltr-Mobile-Firefox-linux.png new file mode 100644 index 0000000000..ed34cd5f40 Binary files /dev/null and b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-header-el-anchor-md-ltr-Mobile-Firefox-linux.png differ diff --git a/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-header-el-anchor-md-ltr-Mobile-Safari-linux.png b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-header-el-anchor-md-ltr-Mobile-Safari-linux.png new file mode 100644 index 0000000000..00aaba0520 Binary files /dev/null and b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-header-el-anchor-md-ltr-Mobile-Safari-linux.png differ diff --git a/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-middle-anchor-ios-ltr-Mobile-Chrome-linux.png b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-middle-anchor-ios-ltr-Mobile-Chrome-linux.png new file mode 100644 index 0000000000..a0afd7b860 Binary files /dev/null and b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-middle-anchor-ios-ltr-Mobile-Chrome-linux.png differ diff --git a/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-middle-anchor-ios-ltr-Mobile-Firefox-linux.png b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-middle-anchor-ios-ltr-Mobile-Firefox-linux.png new file mode 100644 index 0000000000..53521cef0d Binary files /dev/null and b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-middle-anchor-ios-ltr-Mobile-Firefox-linux.png differ diff --git a/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-middle-anchor-ios-ltr-Mobile-Safari-linux.png b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-middle-anchor-ios-ltr-Mobile-Safari-linux.png new file mode 100644 index 0000000000..a0fbfcd2ca Binary files /dev/null and b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-middle-anchor-ios-ltr-Mobile-Safari-linux.png differ diff --git a/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-middle-anchor-md-ltr-Mobile-Chrome-linux.png b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-middle-anchor-md-ltr-Mobile-Chrome-linux.png new file mode 100644 index 0000000000..8a081906cf Binary files /dev/null and b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-middle-anchor-md-ltr-Mobile-Chrome-linux.png differ diff --git a/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-middle-anchor-md-ltr-Mobile-Firefox-linux.png b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-middle-anchor-md-ltr-Mobile-Firefox-linux.png new file mode 100644 index 0000000000..9dbe628572 Binary files /dev/null and b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-middle-anchor-md-ltr-Mobile-Firefox-linux.png differ diff --git a/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-middle-anchor-md-ltr-Mobile-Safari-linux.png b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-middle-anchor-md-ltr-Mobile-Safari-linux.png new file mode 100644 index 0000000000..3dfcc43907 Binary files /dev/null and b/core/src/components/toast/test/position-anchor/toast.e2e.ts-snapshots/toast-middle-anchor-md-ltr-Mobile-Safari-linux.png differ diff --git a/core/src/components/toast/toast-interface.ts b/core/src/components/toast/toast-interface.ts index 3bd76eba96..19cb83ae4a 100644 --- a/core/src/components/toast/toast-interface.ts +++ b/core/src/components/toast/toast-interface.ts @@ -8,6 +8,7 @@ export interface ToastOptions { duration?: number; buttons?: (ToastButton | string)[]; position?: 'top' | 'bottom' | 'middle'; + positionAnchor?: HTMLElement | string; translucent?: boolean; animated?: boolean; icon?: string; @@ -42,3 +43,15 @@ export interface ToastButton { } export type ToastPosition = 'top' | 'bottom' | 'middle'; + +interface ToastPositionAlias { + position: ToastPosition; +} + +export interface ToastAnimationPosition { + top: string; + bottom: string; +} + +export type ToastPresentOptions = ToastPositionAlias & ToastAnimationPosition; +export type ToastDismissOptions = ToastPositionAlias & ToastAnimationPosition; diff --git a/core/src/components/toast/toast.tsx b/core/src/components/toast/toast.tsx index 3137e73d54..9a14b2bfd0 100644 --- a/core/src/components/toast/toast.tsx +++ b/core/src/components/toast/toast.tsx @@ -28,7 +28,15 @@ import { iosEnterAnimation } from './animations/ios.enter'; import { iosLeaveAnimation } from './animations/ios.leave'; import { mdEnterAnimation } from './animations/md.enter'; import { mdLeaveAnimation } from './animations/md.leave'; -import type { ToastButton, ToastPosition, ToastLayout } from './toast-interface'; +import { getAnimationPosition } from './animations/utils'; +import type { + ToastButton, + ToastPosition, + ToastLayout, + ToastPresentOptions, + ToastDismissOptions, + ToastAnimationPosition, +} from './toast-interface'; // TODO(FW-2832): types @@ -57,6 +65,13 @@ export class Toast implements ComponentInterface, OverlayInterface { private customHTMLEnabled = config.get('innerHTMLTemplatesEnabled', ENABLE_HTML_CONTENT_DEFAULT); private durationTimeout?: ReturnType; + /** + * Holds the position of the toast calculated in the present + * animation, to be passed along to the dismiss animation so + * we don't have to calculate the position twice. + */ + private lastPresentedPosition?: ToastAnimationPosition; + presented = false; /** @@ -137,10 +152,19 @@ export class Toast implements ComponentInterface, OverlayInterface { @Prop() keyboardClose = false; /** - * The position of the toast on the screen. + * The starting position of the toast on the screen. Can be tweaked further + * using the `positionAnchor` property. */ @Prop() position: ToastPosition = 'bottom'; + /** + * The element to anchor the toast's position to. Can be set as a direct reference + * or the ID of the element. With `position="bottom"`, the toast will sit above the + * chosen element. With `position="top"`, the toast will sit below the chosen element. + * With `position="middle"`, the value of `positionAnchor` is ignored. + */ + @Prop() positionAnchor?: HTMLElement | string; + /** * An array of buttons for the toast. */ @@ -275,7 +299,21 @@ export class Toast implements ComponentInterface, OverlayInterface { await this.delegateController.attachViewToDom(); - await present(this, 'toastEnter', iosEnterAnimation, mdEnterAnimation, this.position); + const { el, position } = this; + const anchor = this.getAnchorElement(); + const animationPosition = getAnimationPosition(position, anchor, getIonMode(this), el); + + /** + * Cache the calculated position of the toast, so we can re-use it + * in the dismiss animation. + */ + this.lastPresentedPosition = animationPosition; + + await present(this, 'toastEnter', iosEnterAnimation, mdEnterAnimation, { + position, + top: animationPosition.top, + bottom: animationPosition.bottom, + }); /** * Content is revealed to screen readers after @@ -304,8 +342,10 @@ export class Toast implements ComponentInterface, OverlayInterface { async dismiss(data?: any, role?: string): Promise { const unlock = await this.lockController.lock(); - if (this.durationTimeout) { - clearTimeout(this.durationTimeout); + const { durationTimeout, position, lastPresentedPosition } = this; + + if (durationTimeout) { + clearTimeout(durationTimeout); } const dismissed = await dismiss( @@ -315,7 +355,16 @@ export class Toast implements ComponentInterface, OverlayInterface { 'toastLeave', iosLeaveAnimation, mdLeaveAnimation, - this.position + /** + * Fetch the cached position that was calculated back in the present + * animation. We always want to animate the dismiss from the same + * position the present stopped at, so the animation looks continuous. + */ + { + position, + top: lastPresentedPosition?.top ?? '', + bottom: lastPresentedPosition?.bottom ?? '', + } ); if (dismissed) { @@ -323,6 +372,7 @@ export class Toast implements ComponentInterface, OverlayInterface { this.revealContentToScreenReader = false; } + this.lastPresentedPosition = undefined; unlock(); return dismissed; @@ -354,6 +404,43 @@ export class Toast implements ComponentInterface, OverlayInterface { return buttons; } + /** + * Returns the element specified by the positionAnchor prop, + * or undefined if prop's value is an ID string and the element + * is not found in the DOM. + */ + private getAnchorElement(): HTMLElement | undefined { + const { position, positionAnchor, el } = this; + + if (position === 'middle' && positionAnchor !== undefined) { + printIonWarning('The positionAnchor property is ignored when using position="middle".', this.el); + return undefined; + } + + if (typeof positionAnchor === 'string') { + /** + * If the anchor is defined as an ID, find the element. + * We do this on every present so the toast doesn't need + * to account for the surrounding DOM changing since the + * last time it was presented. + */ + const foundEl = document.getElementById(positionAnchor); + if (foundEl === null) { + printIonWarning(`An anchor element with an ID of "${positionAnchor}" was not found in the DOM.`, el); + return undefined; + } + + return foundEl; + } + + if (positionAnchor instanceof HTMLElement) { + return positionAnchor; + } + + printIonWarning('Invalid positionAnchor value:', positionAnchor, el); + return undefined; + } + private async buttonClick(button: ToastButton) { const role = button.role; if (isCancel(role)) { @@ -577,6 +664,3 @@ const buttonClass = (button: ToastButton): CssClassMap => { const buttonPart = (button: ToastButton): string => { return isCancel(button.role) ? 'button cancel' : 'button'; }; - -type ToastPresentOptions = ToastPosition; -type ToastDismissOptions = ToastPosition; diff --git a/core/src/utils/native/haptic.ts b/core/src/utils/native/haptic.ts index cbcc909586..76f07c5c5b 100644 --- a/core/src/utils/native/haptic.ts +++ b/core/src/utils/native/haptic.ts @@ -96,6 +96,7 @@ const HapticEngine = { * if the browser does not support the Vibrate API. */ if (capacitor?.getPlatform() === 'web') { + // eslint-disable-next-line @typescript-eslint/prefer-optional-chain return typeof navigator !== 'undefined' && navigator.vibrate !== undefined; } diff --git a/core/src/utils/overlays.ts b/core/src/utils/overlays.ts index 9a01438aca..07d8fc8c1d 100644 --- a/core/src/utils/overlays.ts +++ b/core/src/utils/overlays.ts @@ -95,6 +95,7 @@ export const createOverlay = ( tagName: string, opts: object | undefined ): Promise => { + // eslint-disable-next-line @typescript-eslint/prefer-optional-chain if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined') { return window.customElements.whenDefined(tagName).then(() => { const element = document.createElement(tagName) as HTMLIonOverlayElement; diff --git a/core/src/utils/transition/ios.transition.ts b/core/src/utils/transition/ios.transition.ts index 3145564e21..b1d5a80150 100644 --- a/core/src/utils/transition/ios.transition.ts +++ b/core/src/utils/transition/ios.transition.ts @@ -294,6 +294,7 @@ export const iosTransitionAnimation = (navEl: HTMLElement, opts: TransitionOptio .fill('both') .beforeRemoveClass('ion-page-invisible'); + // eslint-disable-next-line @typescript-eslint/prefer-optional-chain if (leavingEl && navEl !== null && navEl !== undefined) { const navDecorAnimation = createAnimation(); navDecorAnimation.addElement(navEl); diff --git a/core/tsconfig.json b/core/tsconfig.json index b75814eb06..862a6b84af 100644 --- a/core/tsconfig.json +++ b/core/tsconfig.json @@ -14,7 +14,8 @@ "dom", "dom.iterable", "es2017", - "es2020" + "es2020", + "es2021" ], "module": "esnext", "moduleResolution": "node", diff --git a/packages/angular/common/src/providers/platform.ts b/packages/angular/common/src/providers/platform.ts index c8e27c1e26..50b4083f65 100644 --- a/packages/angular/common/src/providers/platform.ts +++ b/packages/angular/common/src/providers/platform.ts @@ -23,13 +23,13 @@ export class Platform { /** * @hidden */ - backButton: BackButtonEmitter = new Subject() as any; + backButton = new Subject() as BackButtonEmitter; /** * The keyboardDidShow event emits when the * on-screen keyboard is presented. */ - keyboardDidShow = new Subject() as any; + keyboardDidShow = new Subject(); /** * The keyboardDidHide event emits when the diff --git a/packages/angular/src/directives/proxies.ts b/packages/angular/src/directives/proxies.ts index 433c839a7a..2e4766de23 100644 --- a/packages/angular/src/directives/proxies.ts +++ b/packages/angular/src/directives/proxies.ts @@ -2201,7 +2201,7 @@ export declare interface IonTitle extends Components.IonTitle {} @ProxyCmp({ - inputs: ['animated', 'buttons', 'color', 'cssClass', 'duration', 'enterAnimation', 'header', 'htmlAttributes', 'icon', 'isOpen', 'keyboardClose', 'layout', 'leaveAnimation', 'message', 'mode', 'position', 'translucent', 'trigger'], + inputs: ['animated', 'buttons', 'color', 'cssClass', 'duration', 'enterAnimation', 'header', 'htmlAttributes', 'icon', 'isOpen', 'keyboardClose', 'layout', 'leaveAnimation', 'message', 'mode', 'position', 'positionAnchor', 'translucent', 'trigger'], methods: ['present', 'dismiss', 'onDidDismiss', 'onWillDismiss'] }) @Component({ @@ -2209,7 +2209,7 @@ export declare interface IonTitle extends Components.IonTitle {} changeDetection: ChangeDetectionStrategy.OnPush, template: '', // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property - inputs: ['animated', 'buttons', 'color', 'cssClass', 'duration', 'enterAnimation', 'header', 'htmlAttributes', 'icon', 'isOpen', 'keyboardClose', 'layout', 'leaveAnimation', 'message', 'mode', 'position', 'translucent', 'trigger'], + inputs: ['animated', 'buttons', 'color', 'cssClass', 'duration', 'enterAnimation', 'header', 'htmlAttributes', 'icon', 'isOpen', 'keyboardClose', 'layout', 'leaveAnimation', 'message', 'mode', 'position', 'positionAnchor', 'translucent', 'trigger'], }) export class IonToast { protected el: HTMLElement; diff --git a/packages/vue/src/components/Overlays.ts b/packages/vue/src/components/Overlays.ts index 62df98436b..d938438c6f 100644 --- a/packages/vue/src/components/Overlays.ts +++ b/packages/vue/src/components/Overlays.ts @@ -25,7 +25,7 @@ export const IonLoading = /*@__PURE__*/ defineOverlayContainer(' export const IonPicker = /*@__PURE__*/ defineOverlayContainer('ion-picker', defineIonPickerCustomElement, ['animated', 'backdropDismiss', 'buttons', 'columns', 'cssClass', 'duration', 'enterAnimation', 'htmlAttributes', 'isOpen', 'keyboardClose', 'leaveAnimation', 'mode', 'showBackdrop', 'trigger']); -export const IonToast = /*@__PURE__*/ defineOverlayContainer('ion-toast', defineIonToastCustomElement, ['animated', 'buttons', 'color', 'cssClass', 'duration', 'enterAnimation', 'header', 'htmlAttributes', 'icon', 'isOpen', 'keyboardClose', 'layout', 'leaveAnimation', 'message', 'mode', 'position', 'translucent', 'trigger']); +export const IonToast = /*@__PURE__*/ defineOverlayContainer('ion-toast', defineIonToastCustomElement, ['animated', 'buttons', 'color', 'cssClass', 'duration', 'enterAnimation', 'header', 'htmlAttributes', 'icon', 'isOpen', 'keyboardClose', 'layout', 'leaveAnimation', 'message', 'mode', 'position', 'positionAnchor', 'translucent', 'trigger']); export const IonModal = /*@__PURE__*/ defineOverlayContainer('ion-modal', defineIonModalCustomElement, ['animated', 'backdropBreakpoint', 'backdropDismiss', 'breakpoints', 'canDismiss', 'enterAnimation', 'handle', 'handleBehavior', 'htmlAttributes', 'initialBreakpoint', 'isOpen', 'keepContentsMounted', 'keyboardClose', 'leaveAnimation', 'mode', 'presentingElement', 'showBackdrop', 'trigger'], true);