chore: sync with feature-7.5

This commit is contained in:
Liam DeBeasi
2023-10-05 14:47:24 -04:00
61 changed files with 1073 additions and 341 deletions

View File

@@ -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<boolean>

530
core/package-lock.json generated
View File

@@ -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",

View File

@@ -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",

View File

@@ -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": <T = any>() => Promise<OverlayEventDetail<T>>;
"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>) => 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).
*/

View File

@@ -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 (

View File

@@ -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!);
});
});
});

View File

@@ -25,6 +25,7 @@
<ion-button id="noMessage" expand="block" onclick="presentNoMessage()">No Message</ion-button>
<ion-button id="customAria" expand="block" onclick="presentCustomAria()">Custom Aria</ion-button>
<ion-button id="ariaLabelButton" expand="block" onclick="presentAriaLabelButton()">Aria Label Button</ion-button>
<ion-button id="checkbox" expand="block" onclick="presentAlertCheckbox()">Checkbox</ion-button>
</main>
<script>
@@ -94,6 +95,21 @@
],
});
}
function presentAlertCheckbox() {
openAlert({
header: 'Checkbox',
inputs: [
{
type: 'checkbox',
label: 'Checkbox 1',
value: 'value1',
checked: true,
},
],
buttons: ['OK'],
});
}
</script>
</body>
</html>

View File

@@ -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);

View File

@@ -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';

View File

@@ -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)}
</button>,
<ion-popover
alignment="center"

View File

@@ -1,4 +1,125 @@
import { generateMonths, getDaysOfWeek, generateTime, getToday, getCombinedDateColumnData } from '../utils/data';
import {
generateMonths,
getDaysOfWeek,
generateTime,
getToday,
getCombinedDateColumnData,
getTimeColumnsData,
} from '../utils/data';
// The minutes are the same across all hour cycles, so we don't check those
describe('getTimeColumnsData()', () => {
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);
});

View File

@@ -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');
});
});

View File

@@ -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');
});
});

View File

@@ -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(
`
<ion-datetime hour-cycle="h11" value="2022-01-01T00:30:00"></ion-datetime>
`,
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(
`
<ion-datetime hour-cycle="h24" value="2022-01-01T00:30:00"></ion-datetime>
`,
config
);
const timeButton = page.locator('ion-datetime .time-body');
await expect(timeButton).toHaveText('24:30');
});
});
});

View File

@@ -51,6 +51,14 @@
<h2>h12 Hour cycle</h2>
<ion-datetime hour-cycle="h12"></ion-datetime>
</div>
<div class="grid-item">
<h2>h11 Hour cycle</h2>
<ion-datetime hour-cycle="h11"></ion-datetime>
</div>
<div class="grid-item">
<h2>h24 Hour cycle</h2>
<ion-datetime hour-cycle="h24"></ion-datetime>
</div>
<div class="grid-item">
<h2>h23 Hour cycle (Extension Tag)</h2>
<ion-datetime locale="en-US-u-hc-h23"></ion-datetime>

View File

@@ -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),
};
});

View File

@@ -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<DatetimeParts, 'hour' | 'minute'> = {
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();

View File

@@ -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';
};
/**

View File

@@ -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,

View File

@@ -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;

View File

@@ -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;

View File

@@ -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}

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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
);
}
}

View File

@@ -0,0 +1,94 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8" />
<title>Toast - positionAnchor</title>
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"
/>
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet" />
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet" />
<script src="../../../../../scripts/testing/scripts.js"></script>
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
<style>
html {
--ion-safe-area-top: 30px;
--ion-safe-area-bottom: 30px;
}
</style>
</head>
<body>
<ion-app>
<ion-header id="header">
<ion-toolbar>
<ion-title>Toast - positionAnchor</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
<ion-button id="headerAnchor">Anchor to Header</ion-button>
<ion-button id="footerAnchor">Anchor to Footer</ion-button>
<ion-button id="middleAnchor">Anchor to Header (Middle Position)</ion-button>
<ion-button id="headerElAnchor">Anchor to Header (Element Ref)</ion-button>
<ion-button id="hiddenElAnchor">Anchor to Hidden Element</ion-button>
<ion-toast
id="headerToast"
trigger="headerAnchor"
position="top"
position-anchor="header"
message="Hello World"
duration="2000"
></ion-toast>
<ion-toast
id="footerToast"
trigger="footerAnchor"
position="bottom"
position-anchor="footer"
message="Hello World"
duration="2000"
></ion-toast>
<ion-toast
id="middleToast"
trigger="middleAnchor"
position="middle"
position-anchor="header"
message="Hello World"
duration="2000"
></ion-toast>
<ion-toast
id="headerElToast"
trigger="headerElAnchor"
position="top"
message="Hello World"
duration="2000"
></ion-toast>
<ion-toast
id="hiddenElToast"
trigger="hiddenElAnchor"
position="bottom"
position-anchor="hiddenEl"
message="Hello World"
duration="2000"
></ion-toast>
<div id="hiddenEl" style="display: none">Shh I'm hiding</div>
</ion-content>
<ion-footer id="footer">
<ion-toolbar>
<ion-title>Footer</ion-title>
</ion-toolbar>
</ion-footer>
</ion-app>
<script>
const headerElToast = document.querySelector('#headerElToast');
const header = document.querySelector('ion-header');
headerElToast.positionAnchor = header;
</script>
</body>
</html>

View File

@@ -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`));
});
});
});

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -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;

View File

@@ -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<typeof setTimeout>;
/**
* 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<ToastPresentOptions>(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<ToastPresentOptions>(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<boolean> {
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<ToastDismissOptions>(
@@ -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;

View File

@@ -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;
}

View File

@@ -95,6 +95,7 @@ export const createOverlay = <T extends HTMLIonOverlayElement>(
tagName: string,
opts: object | undefined
): Promise<T> => {
// 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;

View File

@@ -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);

View File

@@ -14,7 +14,8 @@
"dom",
"dom.iterable",
"es2017",
"es2020"
"es2020",
"es2021"
],
"module": "esnext",
"moduleResolution": "node",

View File

@@ -23,13 +23,13 @@ export class Platform {
/**
* @hidden
*/
backButton: BackButtonEmitter = new Subject<BackButtonEventDetail>() as any;
backButton = new Subject<BackButtonEventDetail>() as BackButtonEmitter;
/**
* The keyboardDidShow event emits when the
* on-screen keyboard is presented.
*/
keyboardDidShow = new Subject<KeyboardEventDetail>() as any;
keyboardDidShow = new Subject<KeyboardEventDetail>();
/**
* The keyboardDidHide event emits when the

View File

@@ -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: '<ng-content></ng-content>',
// 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;

View File

@@ -25,7 +25,7 @@ export const IonLoading = /*@__PURE__*/ defineOverlayContainer<JSX.IonLoading>('
export const IonPicker = /*@__PURE__*/ defineOverlayContainer<JSX.IonPicker>('ion-picker', defineIonPickerCustomElement, ['animated', 'backdropDismiss', 'buttons', 'columns', 'cssClass', 'duration', 'enterAnimation', 'htmlAttributes', 'isOpen', 'keyboardClose', 'leaveAnimation', 'mode', 'showBackdrop', 'trigger']);
export const IonToast = /*@__PURE__*/ defineOverlayContainer<JSX.IonToast>('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<JSX.IonToast>('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<JSX.IonModal>('ion-modal', defineIonModalCustomElement, ['animated', 'backdropBreakpoint', 'backdropDismiss', 'breakpoints', 'canDismiss', 'enterAnimation', 'handle', 'handleBehavior', 'htmlAttributes', 'initialBreakpoint', 'isOpen', 'keepContentsMounted', 'keyboardClose', 'leaveAnimation', 'mode', 'presentingElement', 'showBackdrop', 'trigger'], true);