diff --git a/package-lock.json b/package-lock.json index 62ea5e1d2bf..6a256489f9d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "packages/calcite-components-angular/projects/component-library" ], "devDependencies": { - "@babel/preset-react": "7.22.15", + "@babel/preset-react": "7.23.3", "@cspell/eslint-plugin": "7.3.9", "@esri/calcite-base": "1.2.0", "@esri/calcite-colors": "6.1.0", @@ -28,7 +28,7 @@ "@storybook/testing-library": "0.2.2", "@tokens-studio/sd-transforms": "0.12.1", "@types/dedent": "0.7.2", - "@types/eslint": "8.40.2", + "@types/eslint": "8.44.8", "@types/estree": "1.0.5", "@types/jest": "29.5.7", "@types/jest-axe": "3.5.9", @@ -55,7 +55,7 @@ "cpy": "10.1.0", "cpy-cli": "5.0.0", "dedent": "0.7.0", - "eslint": "8.44.0", + "eslint": "8.55.0", "eslint-config-prettier": "8.8.0", "eslint-plugin-import": "2.27.5", "eslint-plugin-jest": "27.6.0", @@ -71,7 +71,7 @@ "lerna": "7.1.5", "lint-staged": "13.2.3", "markdownlint-cli": "0.34.0", - "postcss": "8.4.31", + "postcss": "8.4.32", "prettier": "2.8.8", "puppeteer": "21.5.0", "quicktype-core": "23.0.80", @@ -1789,6 +1789,34 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@angular-devkit/build-angular/node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, "node_modules/@angular-devkit/build-angular/node_modules/postcss-loader": { "version": "7.3.3", "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.3.3.tgz", @@ -2823,9 +2851,9 @@ } }, "node_modules/@angular/animations": { - "version": "17.0.5", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-17.0.5.tgz", - "integrity": "sha512-NZ9Y3QWqrn0THypVNwsztMV9rnjxNMRIf6to8aZv+ehIUOvskqcA/lW5qAdcMr1uNoyloB9vahJrDniWWEKT5A==", + "version": "17.0.6", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-17.0.6.tgz", + "integrity": "sha512-fic61LjLHry79c5H9UGM8Ff311MJnf9an7EukLj2aLJ3J0uadL/H9de7dDp8PaIT10DX9g+aRTIKOmF3PmmXIQ==", "dependencies": { "tslib": "^2.3.0" }, @@ -2833,7 +2861,7 @@ "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/core": "17.0.5" + "@angular/core": "17.0.6" } }, "node_modules/@angular/cli": { @@ -3654,9 +3682,9 @@ } }, "node_modules/@angular/common": { - "version": "17.0.5", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-17.0.5.tgz", - "integrity": "sha512-1vFZ7nd8xyAYh/DwFtRuSieP8Dy/6QuOxl914/TOUr26F1a4e+7ywCyMLVjmYjx+WkZe7uu/Hgpr2raBaVTnQw==", + "version": "17.0.6", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-17.0.6.tgz", + "integrity": "sha512-FZtf8ol8W2V21ZDgFtcxmJ6JJKUO97QZ+wr/bosyYEryWMmn6VGrbOARhfW7BlrEgn14NdFkLb72KKtqoqRjrg==", "dependencies": { "tslib": "^2.3.0" }, @@ -3664,14 +3692,14 @@ "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/core": "17.0.5", + "@angular/core": "17.0.6", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "17.0.5", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-17.0.5.tgz", - "integrity": "sha512-V6LnX/B2YXpzXeNWavtX/XPNUnWrVUFpiOniKqHYhAxXnibhyXL9DRsyVs8QbKgIcPPcQeJMHdAjklCWJsePvg==", + "version": "17.0.6", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-17.0.6.tgz", + "integrity": "sha512-PaCNnlPcL0rvByKCBUUyLWkKJYXOrcfKlYYvcacjOzEUgZeEpekG81hMRb9u/Pz+A+M4HJSTmdgzwGP35zo8qw==", "dependencies": { "tslib": "^2.3.0" }, @@ -3679,7 +3707,7 @@ "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/core": "17.0.5" + "@angular/core": "17.0.6" }, "peerDependenciesMeta": { "@angular/core": { @@ -3688,9 +3716,9 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "17.0.5", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-17.0.5.tgz", - "integrity": "sha512-Nb99iKz8LMoc5HC9iu5rbWblXb68sHHI6bcN8sdqvc2g+PohkGNbtRjVZFhP+WKMaNFYDSvLWcHFFYItLRkT4g==", + "version": "17.0.6", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-17.0.6.tgz", + "integrity": "sha512-C1Gfh9kbjYZezEMOwxnvUTHuPXa+6pk7mAfSj8e5oAO6E+wfo2dTxv1J5zxa3KYzxPYMNfF8OFvLuMKsw7lXjA==", "dev": true, "dependencies": { "@babel/core": "7.23.2", @@ -3711,7 +3739,7 @@ "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/compiler": "17.0.5", + "@angular/compiler": "17.0.6", "typescript": ">=5.2 <5.3" } }, @@ -3803,9 +3831,9 @@ } }, "node_modules/@angular/core": { - "version": "17.0.5", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-17.0.5.tgz", - "integrity": "sha512-siWUrdBWgTAqMnRF+qxGZznj5AdR/x3+8l0/bj4CkSZzwZGL/CHy40ec71bbgiPkYob1v4v40voXu2aSSeCLPg==", + "version": "17.0.6", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-17.0.6.tgz", + "integrity": "sha512-QzfKRTDNgGOY9D5VxenUUz20cvPVC+uVw9xiqkDuHgGfLYVFlCAK9ymFYkdUCLTcVzJPxckP+spMpPX8nc4Aqw==", "dependencies": { "tslib": "^2.3.0" }, @@ -3818,9 +3846,9 @@ } }, "node_modules/@angular/forms": { - "version": "17.0.5", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-17.0.5.tgz", - "integrity": "sha512-d91Rre/NK+SgamF1OJmDJUx+Zs8M7qFmrKu7c+hNsXPe8J/fkMNoWFikne/WSsegwY929E1xpeqvu/KXQt90ug==", + "version": "17.0.6", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-17.0.6.tgz", + "integrity": "sha512-n/trsMtQHUBGiWz5lFaggMcMOuw0gH+96TCtHxQiUYJOdrbOemkFdGrNh3B4fGHmogWuOYJVF5FAm97WRES2XA==", "dependencies": { "tslib": "^2.3.0" }, @@ -3828,16 +3856,16 @@ "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/common": "17.0.5", - "@angular/core": "17.0.5", - "@angular/platform-browser": "17.0.5", + "@angular/common": "17.0.6", + "@angular/core": "17.0.6", + "@angular/platform-browser": "17.0.6", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/platform-browser": { - "version": "17.0.5", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-17.0.5.tgz", - "integrity": "sha512-VJQ6bVS40xJLNGNcX59/QFPrZesIm2zETOqAc6K04onuWF1EnJqvcDog9eYJsm0sLWhQeCdWVmAFRenTkDoqng==", + "version": "17.0.6", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-17.0.6.tgz", + "integrity": "sha512-nBhWH1MKT2WswgRNIoMnmNAt0n5/fG59BanJtodW71//Aj5aIE+BuVoFgK3wmO8IMoeP4i4GXRInBXs6lUMOJw==", "dependencies": { "tslib": "^2.3.0" }, @@ -3845,9 +3873,9 @@ "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/animations": "17.0.5", - "@angular/common": "17.0.5", - "@angular/core": "17.0.5" + "@angular/animations": "17.0.6", + "@angular/common": "17.0.6", + "@angular/core": "17.0.6" }, "peerDependenciesMeta": { "@angular/animations": { @@ -3856,9 +3884,9 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "17.0.5", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-17.0.5.tgz", - "integrity": "sha512-Ki+0B3/S+Rv3O4jf+tbDBPs0m+VUMoS6VVCCLviaurYGPLPtGblhCzRv49Zoyo5gEVoEOgnxS6CI91Tv6My9ug==", + "version": "17.0.6", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-17.0.6.tgz", + "integrity": "sha512-5ZEmBtBkqamTaWjUXCls7G1f3xyK/ykXE7hnUV9CgGqXKrNkxblmbtOhoWdsbuIYjjdxQcAk1qtg/Rg21wcc4w==", "dependencies": { "tslib": "^2.3.0" }, @@ -3866,16 +3894,16 @@ "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/common": "17.0.5", - "@angular/compiler": "17.0.5", - "@angular/core": "17.0.5", - "@angular/platform-browser": "17.0.5" + "@angular/common": "17.0.6", + "@angular/compiler": "17.0.6", + "@angular/core": "17.0.6", + "@angular/platform-browser": "17.0.6" } }, "node_modules/@angular/router": { - "version": "17.0.5", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-17.0.5.tgz", - "integrity": "sha512-9e5MQJzDdfhXKSYrduIDmDf73GBRcjx6qE+k5CliGY4sFza10wdbrM4LkiuA3Z2Ja+2AKkotrGG3ZMCtAsFY1g==", + "version": "17.0.6", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-17.0.6.tgz", + "integrity": "sha512-xW6yDxREpBOB9MoODSfIw5HwkwLK+OgK34Q6sGYs0ft9UryMoFwft+pHGAaDz2nzhA72n+Ht9B2eai78UE9jGQ==", "dependencies": { "tslib": "^2.3.0" }, @@ -3883,9 +3911,9 @@ "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/common": "17.0.5", - "@angular/core": "17.0.5", - "@angular/platform-browser": "17.0.5", + "@angular/common": "17.0.6", + "@angular/core": "17.0.6", + "@angular/platform-browser": "17.0.6", "rxjs": "^6.5.3 || ^7.4.0" } }, @@ -5884,17 +5912,17 @@ } }, "node_modules/@babel/preset-react": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.22.15.tgz", - "integrity": "sha512-Csy1IJ2uEh/PecCBXXoZGAZBeCATTuePzCSB7dLYWS0vOEj6CNpjxIhW4duWwZodBNueH7QO14WbGn8YyeuN9w==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.23.3.tgz", + "integrity": "sha512-tbkHOS9axH6Ysf2OUEqoSZ6T3Fa2SrNH6WTWSPBboxKzdxNc9qOICeLXkNG0ZEwbQ1HY8liwOce4aN/Ceyuq6w==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-validator-option": "^7.22.15", - "@babel/plugin-transform-react-display-name": "^7.22.5", + "@babel/plugin-transform-react-display-name": "^7.23.3", "@babel/plugin-transform-react-jsx": "^7.22.15", "@babel/plugin-transform-react-jsx-development": "^7.22.5", - "@babel/plugin-transform-react-pure-annotations": "^7.22.5" + "@babel/plugin-transform-react-pure-annotations": "^7.23.3" }, "engines": { "node": ">=6.9.0" @@ -7228,9 +7256,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.44.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.44.0.tgz", - "integrity": "sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==", + "version": "8.55.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.55.0.tgz", + "integrity": "sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } @@ -7264,9 +7292,9 @@ "link": true }, "node_modules/@esri/calcite-ui-icons": { - "version": "3.25.1", - "resolved": "https://registry.npmjs.org/@esri/calcite-ui-icons/-/calcite-ui-icons-3.25.1.tgz", - "integrity": "sha512-QZtJefmY+szhMUPhmlnzKE49yY6QcjstexdYLmBJ15/WaZXroYeKUBlXvsoQo9a+v3ZCwkfz7fcLOO6x1ciMaw==", + "version": "3.25.2", + "resolved": "https://registry.npmjs.org/@esri/calcite-ui-icons/-/calcite-ui-icons-3.25.2.tgz", + "integrity": "sha512-R3lU99DDpFBjIpHFYfm3L86DJm9lZGxxXxA7Ha2MEYhgAziynzPQf8WzAgZcpVa4zpAHEqYs7KguYYiV3rxYvQ==", "dev": true, "bin": { "spriter": "bin/spriter.js" @@ -10639,9 +10667,9 @@ } }, "node_modules/@stencil/core": { - "version": "4.7.2", - "resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.7.2.tgz", - "integrity": "sha512-sPPDYrXiTbfeUF5CCyfqysXK/yfTHC4xYR1+nHzGkS2vhRSBOLp0oPuB+xkJLKA+K2ZqDJUxpOnDxy1CLWwBXA==", + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.8.1.tgz", + "integrity": "sha512-KG1H10j24rlyxIqOI4CG8/h9T7ObTv7giW2H3u1qXV4KKrLykDOpMcLzpqNXqL2Fki3s1QvHyl/oaRvi5waWVw==", "bin": { "stencil": "bin/stencil" }, @@ -13685,9 +13713,9 @@ "dev": true }, "node_modules/@types/eslint": { - "version": "8.40.2", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.40.2.tgz", - "integrity": "sha512-PRVjQ4Eh9z9pmmtaq8nTjZjQwKFk7YIHIud3lRoKRBgUQjgjRmoGxxGEPXQkF+lH7QkHJRNr5F4aBgYCW0lqpQ==", + "version": "8.44.8", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.8.tgz", + "integrity": "sha512-4K8GavROwhrYl2QXDXm0Rv9epkA8GBFu0EI+XrrnnuCl7u8CWBRusX7fXJfanhZTDWSAL24gDI/UqXyUM0Injw==", "dev": true, "dependencies": { "@types/estree": "*", @@ -14442,6 +14470,11 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" + }, "node_modules/@webassemblyjs/ast": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", @@ -22016,26 +22049,27 @@ } }, "node_modules/eslint": { - "version": "8.44.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.44.0.tgz", - "integrity": "sha512-0wpHoUbDUHgNCyvFB5aXLiQVfK9B0at6gUvzy83k4kAsQ/u769TQDX6iKC+aO4upIHO9WSaA3QoXYQDHbNwf1A==", + "version": "8.55.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.55.0.tgz", + "integrity": "sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA==", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.1.0", - "@eslint/js": "8.44.0", - "@humanwhocodes/config-array": "^0.11.10", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.55.0", + "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.0", - "eslint-visitor-keys": "^3.4.1", - "espree": "^9.6.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -22045,7 +22079,6 @@ "globals": "^13.19.0", "graphemer": "^1.4.0", "ignore": "^5.2.0", - "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", @@ -22057,7 +22090,6 @@ "natural-compare": "^1.4.0", "optionator": "^0.9.3", "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" }, "bin": { @@ -36576,9 +36608,9 @@ } }, "node_modules/postcss": { - "version": "8.4.31", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", - "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "version": "8.4.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz", + "integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==", "dev": true, "funding": [ { @@ -36595,7 +36627,7 @@ } ], "dependencies": { - "nanoid": "^3.3.6", + "nanoid": "^3.3.7", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" }, @@ -47411,11 +47443,11 @@ }, "packages/calcite-components": { "name": "@esri/calcite-components", - "version": "2.1.0-next.4", + "version": "2.1.0-next.10", "license": "SEE LICENSE.md", "dependencies": { "@floating-ui/dom": "1.5.3", - "@stencil/core": "4.7.2", + "@stencil/core": "4.8.1", "@types/color": "3.0.6", "color": "4.2.3", "composed-offset-position": "0.0.4", @@ -47427,8 +47459,8 @@ "timezone-groups": "0.8.0" }, "devDependencies": { - "@esri/calcite-design-tokens": "^2.0.1-next.2", - "@esri/calcite-ui-icons": "3.25.1", + "@esri/calcite-design-tokens": "^2.0.1-next.3", + "@esri/calcite-ui-icons": "3.25.2", "@esri/eslint-plugin-calcite-components": "^1.0.1-next.1", "@stencil-community/eslint-plugin": "0.7.1", "@stencil-community/postcss": "2.2.0", @@ -47441,14 +47473,14 @@ "packages/calcite-components-angular": { "name": "angular-workspace", "dependencies": { - "@angular/animations": "17.0.5", - "@angular/common": "17.0.5", - "@angular/compiler": "17.0.5", - "@angular/core": "17.0.5", - "@angular/forms": "17.0.5", - "@angular/platform-browser": "17.0.5", - "@angular/platform-browser-dynamic": "17.0.5", - "@angular/router": "17.0.5", + "@angular/animations": "17.0.6", + "@angular/common": "17.0.6", + "@angular/compiler": "17.0.6", + "@angular/core": "17.0.6", + "@angular/forms": "17.0.6", + "@angular/platform-browser": "17.0.6", + "@angular/platform-browser-dynamic": "17.0.6", + "@angular/router": "17.0.6", "rxjs": "7.8.1", "tslib": "2.6.2", "zone.js": "0.14.2" @@ -47456,16 +47488,16 @@ "devDependencies": { "@angular-devkit/build-angular": "17.0.5", "@angular/cli": "17.0.5", - "@angular/compiler-cli": "17.0.5", + "@angular/compiler-cli": "17.0.6", "ng-packagr": "17.0.2" } }, "packages/calcite-components-angular/projects/component-library": { "name": "@esri/calcite-components-angular", - "version": "2.1.0-next.4", + "version": "2.1.0-next.10", "license": "SEE LICENSE.md", "dependencies": { - "@esri/calcite-components": "^2.1.0-next.4", + "@esri/calcite-components": "^2.1.0-next.10", "tslib": "2.6.2" }, "peerDependencies": { @@ -47475,10 +47507,10 @@ }, "packages/calcite-components-react": { "name": "@esri/calcite-components-react", - "version": "2.1.0-next.4", + "version": "2.1.0-next.10", "license": "SEE LICENSE.md", "dependencies": { - "@esri/calcite-components": "^2.1.0-next.4" + "@esri/calcite-components": "^2.1.0-next.10" }, "peerDependencies": { "react": ">=16.7", @@ -47487,7 +47519,7 @@ }, "packages/calcite-design-tokens": { "name": "@esri/calcite-design-tokens", - "version": "2.0.1-next.2" + "version": "2.0.1-next.3" }, "packages/eslint-plugin-calcite-components": { "name": "@esri/eslint-plugin-calcite-components", diff --git a/package.json b/package.json index 84d95781e8a..ad3d5e5c840 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "util:sync-linked-package-versions": "tsx support/syncLinkedPackageVersions.ts" }, "devDependencies": { - "@babel/preset-react": "7.22.15", + "@babel/preset-react": "7.23.3", "@cspell/eslint-plugin": "7.3.9", "@esri/calcite-base": "1.2.0", "@esri/calcite-colors": "6.1.0", @@ -43,7 +43,7 @@ "@storybook/testing-library": "0.2.2", "@tokens-studio/sd-transforms": "0.12.1", "@types/dedent": "0.7.2", - "@types/eslint": "8.40.2", + "@types/eslint": "8.44.8", "@types/estree": "1.0.5", "@types/jest": "29.5.7", "@types/jest-axe": "3.5.9", @@ -70,7 +70,7 @@ "cpy": "10.1.0", "cpy-cli": "5.0.0", "dedent": "0.7.0", - "eslint": "8.44.0", + "eslint": "8.55.0", "eslint-config-prettier": "8.8.0", "eslint-plugin-import": "2.27.5", "eslint-plugin-jest": "27.6.0", @@ -86,7 +86,7 @@ "lerna": "7.1.5", "lint-staged": "13.2.3", "markdownlint-cli": "0.34.0", - "postcss": "8.4.31", + "postcss": "8.4.32", "prettier": "2.8.8", "puppeteer": "21.5.0", "quicktype-core": "23.0.80", diff --git a/packages/calcite-components-angular/package.json b/packages/calcite-components-angular/package.json index cba0cbfd7d6..4243d59060d 100644 --- a/packages/calcite-components-angular/package.json +++ b/packages/calcite-components-angular/package.json @@ -8,14 +8,14 @@ "clean": "rimraf dist node_modules .turbo .angular projects/component-library/dist" }, "dependencies": { - "@angular/animations": "17.0.5", - "@angular/common": "17.0.5", - "@angular/compiler": "17.0.5", - "@angular/core": "17.0.5", - "@angular/forms": "17.0.5", - "@angular/platform-browser": "17.0.5", - "@angular/platform-browser-dynamic": "17.0.5", - "@angular/router": "17.0.5", + "@angular/animations": "17.0.6", + "@angular/common": "17.0.6", + "@angular/compiler": "17.0.6", + "@angular/core": "17.0.6", + "@angular/forms": "17.0.6", + "@angular/platform-browser": "17.0.6", + "@angular/platform-browser-dynamic": "17.0.6", + "@angular/router": "17.0.6", "rxjs": "7.8.1", "tslib": "2.6.2", "zone.js": "0.14.2" @@ -23,7 +23,7 @@ "devDependencies": { "@angular-devkit/build-angular": "17.0.5", "@angular/cli": "17.0.5", - "@angular/compiler-cli": "17.0.5", + "@angular/compiler-cli": "17.0.6", "ng-packagr": "17.0.2" }, "volta": { diff --git a/packages/calcite-components-angular/projects/component-library/CHANGELOG.md b/packages/calcite-components-angular/projects/component-library/CHANGELOG.md index 3d23ac4328a..e5b8c680fd2 100644 --- a/packages/calcite-components-angular/projects/component-library/CHANGELOG.md +++ b/packages/calcite-components-angular/projects/component-library/CHANGELOG.md @@ -3,6 +3,30 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [2.1.0-next.10](https://github.com/Esri/calcite-design-system/compare/@esri/calcite-components-angular@2.1.0-next.9...@esri/calcite-components-angular@2.1.0-next.10) (2023-12-16) + +__Note:__ Version bump only for package @esri/calcite-components-angular + +## [2.1.0-next.9](https://github.com/Esri/calcite-design-system/compare/@esri/calcite-components-angular@2.1.0-next.8...@esri/calcite-components-angular@2.1.0-next.9) (2023-12-15) + +__Note:__ Version bump only for package @esri/calcite-components-angular + +## [2.1.0-next.8](https://github.com/Esri/calcite-design-system/compare/@esri/calcite-components-angular@2.1.0-next.7...@esri/calcite-components-angular@2.1.0-next.8) (2023-12-13) + +__Note:__ Version bump only for package @esri/calcite-components-angular + +## [2.1.0-next.7](https://github.com/Esri/calcite-design-system/compare/@esri/calcite-components-angular@2.1.0-next.6...@esri/calcite-components-angular@2.1.0-next.7) (2023-12-13) + +__Note:__ Version bump only for package @esri/calcite-components-angular + +## [2.1.0-next.6](https://github.com/Esri/calcite-design-system/compare/@esri/calcite-components-angular@2.1.0-next.5...@esri/calcite-components-angular@2.1.0-next.6) (2023-12-12) + +__Note:__ Version bump only for package @esri/calcite-components-angular + +## [2.1.0-next.5](https://github.com/Esri/calcite-design-system/compare/@esri/calcite-components-angular@2.1.0-next.4...@esri/calcite-components-angular@2.1.0-next.5) (2023-12-11) + +__Note:__ Version bump only for package @esri/calcite-components-angular + ## [2.1.0-next.4](https://github.com/Esri/calcite-design-system/compare/@esri/calcite-components-angular@2.1.0-next.3...@esri/calcite-components-angular@2.1.0-next.4) (2023-12-09) __Note:__ Version bump only for package @esri/calcite-components-angular diff --git a/packages/calcite-components-angular/projects/component-library/package.json b/packages/calcite-components-angular/projects/component-library/package.json index 74bb2001ab6..50ce6e7aa15 100644 --- a/packages/calcite-components-angular/projects/component-library/package.json +++ b/packages/calcite-components-angular/projects/component-library/package.json @@ -1,6 +1,6 @@ { "name": "@esri/calcite-components-angular", - "version": "2.1.0-next.4", + "version": "2.1.0-next.10", "sideEffects": false, "homepage": "https://developers.arcgis.com/calcite-design-system/", "description": "A set of Angular components that wrap Esri's Calcite Components.", @@ -20,7 +20,7 @@ "@angular/core": ">=16.0.0" }, "dependencies": { - "@esri/calcite-components": "^2.1.0-next.4", + "@esri/calcite-components": "^2.1.0-next.10", "tslib": "2.6.2" }, "lerna": { diff --git a/packages/calcite-components-react/CHANGELOG.md b/packages/calcite-components-react/CHANGELOG.md index 0ee04e90464..44734976878 100644 --- a/packages/calcite-components-react/CHANGELOG.md +++ b/packages/calcite-components-react/CHANGELOG.md @@ -3,6 +3,30 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [2.1.0-next.10](https://github.com/Esri/calcite-design-system/compare/@esri/calcite-components-react@2.1.0-next.9...@esri/calcite-components-react@2.1.0-next.10) (2023-12-16) + +__Note:__ Version bump only for package @esri/calcite-components-react + +## [2.1.0-next.9](https://github.com/Esri/calcite-design-system/compare/@esri/calcite-components-react@2.1.0-next.8...@esri/calcite-components-react@2.1.0-next.9) (2023-12-15) + +__Note:__ Version bump only for package @esri/calcite-components-react + +## [2.1.0-next.8](https://github.com/Esri/calcite-design-system/compare/@esri/calcite-components-react@2.1.0-next.7...@esri/calcite-components-react@2.1.0-next.8) (2023-12-13) + +__Note:__ Version bump only for package @esri/calcite-components-react + +## [2.1.0-next.7](https://github.com/Esri/calcite-design-system/compare/@esri/calcite-components-react@2.1.0-next.6...@esri/calcite-components-react@2.1.0-next.7) (2023-12-13) + +__Note:__ Version bump only for package @esri/calcite-components-react + +## [2.1.0-next.6](https://github.com/Esri/calcite-design-system/compare/@esri/calcite-components-react@2.1.0-next.5...@esri/calcite-components-react@2.1.0-next.6) (2023-12-12) + +__Note:__ Version bump only for package @esri/calcite-components-react + +## [2.1.0-next.5](https://github.com/Esri/calcite-design-system/compare/@esri/calcite-components-react@2.1.0-next.4...@esri/calcite-components-react@2.1.0-next.5) (2023-12-11) + +__Note:__ Version bump only for package @esri/calcite-components-react + ## [2.1.0-next.4](https://github.com/Esri/calcite-design-system/compare/@esri/calcite-components-react@2.1.0-next.3...@esri/calcite-components-react@2.1.0-next.4) (2023-12-09) __Note:__ Version bump only for package @esri/calcite-components-react diff --git a/packages/calcite-components-react/package.json b/packages/calcite-components-react/package.json index 3fcd0f8eabd..bacdee0d86a 100644 --- a/packages/calcite-components-react/package.json +++ b/packages/calcite-components-react/package.json @@ -1,7 +1,7 @@ { "name": "@esri/calcite-components-react", "sideEffects": false, - "version": "2.1.0-next.4", + "version": "2.1.0-next.10", "homepage": "https://developers.arcgis.com/calcite-design-system/", "description": "A set of React components that wrap calcite components", "license": "SEE LICENSE.md", @@ -20,7 +20,7 @@ "dist/" ], "dependencies": { - "@esri/calcite-components": "^2.1.0-next.4" + "@esri/calcite-components": "^2.1.0-next.10" }, "peerDependencies": { "react": ">=16.7", diff --git a/packages/calcite-components/CHANGELOG.md b/packages/calcite-components/CHANGELOG.md index 2533f37c641..4a77f3b9c8b 100644 --- a/packages/calcite-components/CHANGELOG.md +++ b/packages/calcite-components/CHANGELOG.md @@ -3,6 +3,50 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [2.1.0-next.10](https://github.com/Esri/calcite-design-system/compare/@esri/calcite-components@2.1.0-next.9...@esri/calcite-components@2.1.0-next.10) (2023-12-16) + +### Features + +- __list-item:__ Add calciteListItemToggle event. ([#8433](https://github.com/Esri/calcite-design-system/issues/8433)) ([1d2fa04](https://github.com/Esri/calcite-design-system/commit/1d2fa0406a303f9ae45861c3006eed0b896a207b)), closes [#8434](https://github.com/Esri/calcite-design-system/issues/8434) +- __list:__ Add drag event details to `calciteListDragStart` and `calciteListDragEnd` events ([#8438](https://github.com/Esri/calcite-design-system/issues/8438)) ([e199c08](https://github.com/Esri/calcite-design-system/commit/e199c080128d339b987512454f70a3370d9bdf98)), closes [#8437](https://github.com/Esri/calcite-design-system/issues/8437) + +### Bug Fixes + +- __input-date-picker:__ ensure range input toggling is consistent ([#8414](https://github.com/Esri/calcite-design-system/issues/8414)) ([cd92586](https://github.com/Esri/calcite-design-system/commit/cd925869e36f63d9ba21d77ed1dc8c765bbaf30f)), closes [#6501](https://github.com/Esri/calcite-design-system/issues/6501) +- __menu-item:__ Improve keyboard navigability when `href` populated ([#8408](https://github.com/Esri/calcite-design-system/issues/8408)) ([5b44798](https://github.com/Esri/calcite-design-system/commit/5b447981efabddf2aeab961b8be826aaab5cbd9e)), closes [#8135](https://github.com/Esri/calcite-design-system/issues/8135) +- __table-cell:__ Fix background css variable ([#8439](https://github.com/Esri/calcite-design-system/issues/8439)) ([9e5c59b](https://github.com/Esri/calcite-design-system/commit/9e5c59b94f4f8291788cd9a8734b2ea47fd60329)), closes [#8380](https://github.com/Esri/calcite-design-system/issues/8380) + +## [2.1.0-next.9](https://github.com/Esri/calcite-design-system/compare/@esri/calcite-components@2.1.0-next.8...@esri/calcite-components@2.1.0-next.9) (2023-12-15) + +### Bug Fixes + +- __stepper:__ emits `calciteStepperItemChange` event when switched to first step ([#8422](https://github.com/Esri/calcite-design-system/issues/8422)) ([508979f](https://github.com/Esri/calcite-design-system/commit/508979f25196556af730c984929d232858623c78)), closes [#8397](https://github.com/Esri/calcite-design-system/issues/8397) + +## [2.1.0-next.8](https://github.com/Esri/calcite-design-system/compare/@esri/calcite-components@2.1.0-next.7...@esri/calcite-components@2.1.0-next.8) (2023-12-13) + +### Bug Fixes + +- __floating-ui:__ improve floating element performance ([#8409](https://github.com/Esri/calcite-design-system/issues/8409)) ([4d8cfb8](https://github.com/Esri/calcite-design-system/commit/4d8cfb899857960268226db5c2a47514ea20ad18)), closes [#7979](https://github.com/Esri/calcite-design-system/issues/7979) [#8214](https://github.com/Esri/calcite-design-system/issues/8214) [#8386](https://github.com/Esri/calcite-design-system/issues/8386) [#8419](https://github.com/Esri/calcite-design-system/issues/8419) [#5697](https://github.com/Esri/calcite-design-system/issues/5697) [#8001](https://github.com/Esri/calcite-design-system/issues/8001) [#8230](https://github.com/Esri/calcite-design-system/issues/8230) + +## [2.1.0-next.7](https://github.com/Esri/calcite-design-system/compare/@esri/calcite-components@2.1.0-next.6...@esri/calcite-components@2.1.0-next.7) (2023-12-13) + +### Bug Fixes + +- use Stencil watchers instead of global attributes util ([#8407](https://github.com/Esri/calcite-design-system/issues/8407)) ([c531d81](https://github.com/Esri/calcite-design-system/commit/c531d815477fb2a6629c875d585f465240e2e929)), closes [#8193](https://github.com/Esri/calcite-design-system/issues/8193) + +## [2.1.0-next.6](https://github.com/Esri/calcite-design-system/compare/@esri/calcite-components@2.1.0-next.5...@esri/calcite-components@2.1.0-next.6) (2023-12-12) + +### Bug Fixes + +- __dropdown-item:__ avoid hover/active styling when disabled ([#8398](https://github.com/Esri/calcite-design-system/issues/8398)) ([35817dc](https://github.com/Esri/calcite-design-system/commit/35817dc6a8fc6eb3dd1d3e1b267869b39d6e8d8c)), closes [#6667](https://github.com/Esri/calcite-design-system/issues/6667) +- __modal:__ ensure document overflow styles are properly restored when multiple modals are closed/removed ([#8390](https://github.com/Esri/calcite-design-system/issues/8390)) ([f2c6b09](https://github.com/Esri/calcite-design-system/commit/f2c6b0990d23e080ca665d72fb3bd05c1f3e227d)), closes [#6594](https://github.com/Esri/calcite-design-system/issues/6594) + +## [2.1.0-next.5](https://github.com/Esri/calcite-design-system/compare/@esri/calcite-components@2.1.0-next.4...@esri/calcite-components@2.1.0-next.5) (2023-12-11) + +### Bug Fixes + +- __tab:__ prevent vertical scrollbar on content pane when the height of outer elements are specified ([#8399](https://github.com/Esri/calcite-design-system/issues/8399)) ([9e6d901](https://github.com/Esri/calcite-design-system/commit/9e6d9013fead27aa5c816d0c21429f62c1f224af)), closes [#8139](https://github.com/Esri/calcite-design-system/issues/8139) + ## [2.1.0-next.4](https://github.com/Esri/calcite-design-system/compare/@esri/calcite-components@2.1.0-next.3...@esri/calcite-components@2.1.0-next.4) (2023-12-09) ### Bug Fixes diff --git a/packages/calcite-components/conventions/Accessibility/AccessibilityDeveloper.md b/packages/calcite-components/conventions/Accessibility/AccessibilityDeveloper.md index 9d0aa9bf49e..84cd785c686 100644 --- a/packages/calcite-components/conventions/Accessibility/AccessibilityDeveloper.md +++ b/packages/calcite-components/conventions/Accessibility/AccessibilityDeveloper.md @@ -68,11 +68,11 @@ However, you _could_ extend the native element to allow an association. ## 2. Tests -**The best tools only find 30% of known issues**, so they can't be relied upon. But they can be the first step towards accessibility. +__The best tools only find 30% of known issues__, so they can't be relied upon. But they can be the first step towards accessibility. Calcite Components uses the [axe-core](https://github.com/dequelabs/axe-core) and [jest-axe](https://github.com/nickcolley/jest-axe) accessibility engines throughout its components. `axe-core` contains a number of best practices to help identify accessibility practices, such as ensuring every page has an h1 heading, and to help avoid "gotchas" in ARIA like where an ARIA attribute you used will get ignored. `axe-core` can mitigate over half of WCAG issues automatically. Additionally, it will return elements as "incomplete" where it's not certain, and manual review is needed. -When a new component is added, breaking changes are introduced, and/or as new functionality is added, accessibility tests must take place. **All components should have automated tests pertaining to accessibility.** +When a new component is added, breaking changes are introduced, and/or as new functionality is added, accessibility tests must take place. __All components should have automated tests pertaining to accessibility.__ ### Adding a test @@ -96,7 +96,7 @@ describe("calcite-tree", () => { Child 2 - Grandchild 1 + Grandchild 1 @@ -152,7 +152,7 @@ FAIL src/components/tree/tree.e2e.ts (23.34 s) ## 3. Storybook -We've already added the a11y add on, [storybook-addon-a11y](https://storybook.js.org/addons/@storybook/addon-a11y) which uses `axe-core`, the same accessibility engine used for automated testing in CC. As new components and enhancements are added, **ensure stories are updated to test accessibility**. This includes as properties are added to components, to ensure we're upholding high standards to fit our audience's needs. +We've already added the a11y add on, [storybook-addon-a11y](https://storybook.js.org/addons/@storybook/addon-a11y) which uses `axe-core`, the same accessibility engine used for automated testing in CC. As new components and enhancements are added, __ensure stories are updated to test accessibility__. This includes as properties are added to components, to ensure we're upholding high standards to fit our audience's needs. [Learn more on writing stories](https://github.com/Esri/calcite-design-system/blob/main/CONTRIBUTING.md#writing-stories) from our contributing docs. diff --git a/packages/calcite-components/conventions/README.md b/packages/calcite-components/conventions/README.md index 425ed2ef917..eaf4fab13f9 100644 --- a/packages/calcite-components/conventions/README.md +++ b/packages/calcite-components/conventions/README.md @@ -366,45 +366,7 @@ There are utilities for common workflows in [`src/utils`](../src/utils). ### Global attributes -The [`globalAttributes`](../src/utils/globalAttributes.ts) util was specifically made to access the `lang` global attribute when set on a Calcite component. However, it can be extended to allow additional [global attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes#list_of_global_attributes) by adding to the [`allowedGlobalAttributes`](https://github.com/Esri/calcite-design-system/blob/a33aa0df0c5bf103f91187826e6b12b8ff266d90/src/utils/globalAttributes.ts#L4-L5) array. The util is used in [`calcite-pagination`](../src/components/pagination/pagination.tsx), which you can use as a reference. - -#### Usage steps - -1. Import the interface and watch/unwatch methods - - ```js - import { GlobalAttrComponent, watchGlobalAttributes, unwatchGlobalAttributes } from "../../utils/globalAttributes"; - ``` - -2. Implement the interface - - ```js - export class ComponentName implements GlobalAttrComponent { - ``` - -3. Add `globalAttributes` state - - ```js - @State() globalAttributes = {}; - ``` - -4. Add connect/disconnect callbacks - - ```js - connectedCallback(): void { - watchGlobalAttributes(this, ["lang"]); - } - - disconnectedCallback(): void { - unwatchGlobalAttributes(this); - } - ``` - -5. Use the state to access `lang` (or another global attribute that may be allowed in the future). - - ```js - const lang = this.globalAttributes["lang"] || document.documentElement.lang || "en"; - ``` +Watching global attributes on components is now possible with Stencil v4. Please refer to the [documentation page](https://stenciljs.com/docs/reactive-data#watching-native-html-attributes) for more information. ### BigDecimal diff --git a/packages/calcite-components/conventions/Styling.md b/packages/calcite-components/conventions/Styling.md index f7624eb9daa..977e3becf32 100644 --- a/packages/calcite-components/conventions/Styling.md +++ b/packages/calcite-components/conventions/Styling.md @@ -32,59 +32,97 @@ Add a class to handle the logic in the component class. ## Light Mode/Dark Mode -In the [global CSS file](https://github.com/Esri/calcite-design-system/blob/main/packages/calcite-components/src/assets/styles/global.scss), we specify the values of each color for both light and dark mode. This enables theming to be inherited throughout a component tree. Consider this valid example: +Light and dark modes are now provided via Calcite Design Tokens. Color context modes can serve as an important aspect in your apps, and may help your users reduce eye strain and save power. The light or dark mode can also be set explicitly to meet an app's requirements. + +### Set mode via a class + +Calcite provides two CSS classes `calcite-mode-dark` and `calcite-mode-light` which will explicitly set the value of the Calcite CSS custom props. This is useful when always want to display a set of components in a specific color mode. + +This will require that you have imported Calcite token styles either through Calcite Components or directly, `@esri/calcite-design-tokens/dist/css/index.css` ```html
+

All the components in this div will always use dark mode styles

+ Button text + +
+``` + +If you want your components to respond to a device's `@media (prefers-color-scheme)` you should use the `calcite-mode-auto` class. + +```html +
+

All the components in this div will respond to the light or dark mode set by your device.

Button text
``` -This will cause both the button and the date picker to use the dark mode color variables declared in the global file. This makes it very easy for developers to move an entire app from light to dark mode and vice versa. +#### Styling a component's SASS file + +Along with Calcite Components you can use Calcite Design Tokens to build your own components that automatically have Calcite colors and styles. -To make this work, inside a component's SASS file, _you must use colors from the theme variables_. For example +These design tokens are provided as CSS custom props through `calicte.css` or import them from `@esri/calcite-design-tokens/dist/css/index.css`. You can [read more on custom theming with Calcite here](#custom-themes). ```scss -// 🙅‍♀️ using the sass var will not correctly inherit or change in light/dark mode +// 👍 Using the CSS var will inherit the value correctly :host { - color: $ui-brand-light; + color: var(--calcite-color-brand); } +``` + +There are some edge cases where you may wish to isolate and use only the values of a specific mode. In that case you can import a set of mode tokens directly. + +```scss +@import "~@esri/calcite-design-tokens/dist/scss/dark"; -// 👍 using the CSS var will inherit correctly +// 🙅‍♀️ However, it will not correctly inherit or change it's value when swapping light/dark mode :host { - color: var(--calcite-color-brand); + /* The color property of this component will always be #007ac2 */ + color: $calcite-color-brand; } ``` +## Legacy Tokens + +In Calcite's [2.0.0](https://github.com/Esri/calcite-design-system/releases/tag/%40esri%2Fcalcite-design-tokens%402.0.0) release, design tokens were refactored, which included the removal and refactoring of legacy CSS custom properties. Refer to the [map of token changes from 2.0.0](https://github.com/Esri/calcite-design-tokens/CHANGELOG.md#20-map-of-token-changes) for a more comprehensive list of changes. + +In the release of 2.0 Calcite Component styles got a major refactor which included the removal and reassignment of legacy CSS Custom Properties originally introduced through calcite-styles/calcite-colors. To see a full list of CSS Custom Property additions, deletions, and renamed tokens please refer to the [Calcite Design Tokens 2.0 Changelog > Map of token changes](../../calcite-design-tokens/CHANGELOG.md#20-map-of-token-changes). + +For backwards compatibility, deprecated tokens will continue to be provided until the next major release via [\_legacy.scss](../src/assets/styles/_legacy.scss) + ## Custom Themes -Since Calcite Components might be used in many different contexts such as configurable apps, multiple themes and appearances need to be supported. The most common use case for custom themes are applications where the end user needs to be able to customize brand colors and typography. To this end custom theming can be accomplished by overriding the [CSS Custom Properties (CSS Variables)](https://developer.mozilla.org/en-US/docs/Web/CSS/--*) from the main light and dark modes with new values: +Since Calcite Components might be used in many different contexts, multiple themes and appearances need to be supported. The most common use case for custom themes are applications where the end-user needs to be able to customize brand colors and typography. To this end, custom theming can be accomplished by overriding the [CSS Custom Properties (CSS Variables)](https://developer.mozilla.org/en-US/docs/Web/CSS/--*) from the main light and dark modes with new values: ```css -:root { - --calcite-color-brand: red; +@media (prefers-color-scheme: light) { + :root { + --calcite-color-brand: red; + } } ``` -You can apply these overrides to individual components as well: +You can override tokens on specific Calcite Components: ```css calcite-slider { - --calcite-color-brand: red; + --calcite-color-brand: blue; } ``` -Or, add a class to the specific instance: +Or, override it in a class: ```css .my-custom-theme { - --calcite-color-brand: red; + --calcite-color-brand: green; } ``` +Additionally, inline styling can be achieved: + ```html - + ``` ### Typography @@ -93,7 +131,7 @@ All components have been constructed to inherit their `font-family`. This enable ```css :root { - font-family: "Comic Sans"; + --calcite-font-family: "Comic Sans"; } ``` diff --git a/packages/calcite-components/package.json b/packages/calcite-components/package.json index 0063e52c865..c17458f22a9 100644 --- a/packages/calcite-components/package.json +++ b/packages/calcite-components/package.json @@ -1,6 +1,6 @@ { "name": "@esri/calcite-components", - "version": "2.1.0-next.4", + "version": "2.1.0-next.10", "homepage": "https://developers.arcgis.com/calcite-design-system/", "description": "Web Components for Esri's Calcite Design System.", "main": "dist/index.cjs.js", @@ -19,7 +19,8 @@ "hydrate/" ], "scripts": { - "build": "npm run util:prep-build-reqs && stencil build && npm run util:patch && npm run util:generate-t9n-docs-json && npm run util:clean-readmes", + "build": "npm run util:prep-build-reqs && stencil build", + "postbuild": "npm run util:patch && npm run util:generate-t9n-docs-json && npm run util:clean-readmes", "build:watch": "npm run util:prep-build-reqs && stencil build --no-docs --watch", "build:watch-dev": "npm run util:prep-build-reqs && stencil build --no-docs --dev --watch", "build-storybook": "npm run util:build-docs && NODE_OPTIONS=--openssl-legacy-provider build-storybook --output-dir ./docs --quiet", @@ -37,7 +38,7 @@ "release:docs": "npm run docs && storybook-to-ghpages --existing-output-dir=docs", "start": "npm run util:clean-js-files && concurrently --kill-others --raw \"tsc --project ./tsconfig-demos.json --watch\" \"npm run build:watch-dev -- --serve\"", "test": "stencil test --no-docs --no-build --spec --e2e", - "test:prerender": "stencil build --no-docs --prerender", + "test:prerender": "npm run build -- --prerender", "test:watch": "npm run build && npm run test -- -- --watchAll", "util:build-docs": "npm run util:prep-build-reqs && stencil build --docs --config stencil.storybook.config.ts", "util:clean-tested-build": "npm ci && npm test && npm run build", @@ -62,7 +63,7 @@ }, "dependencies": { "@floating-ui/dom": "1.5.3", - "@stencil/core": "4.7.2", + "@stencil/core": "4.8.1", "@types/color": "3.0.6", "color": "4.2.3", "composed-offset-position": "0.0.4", @@ -74,8 +75,8 @@ "timezone-groups": "0.8.0" }, "devDependencies": { - "@esri/calcite-design-tokens": "^2.0.1-next.2", - "@esri/calcite-ui-icons": "3.25.1", + "@esri/calcite-design-tokens": "^2.0.1-next.3", + "@esri/calcite-ui-icons": "3.25.2", "@esri/eslint-plugin-calcite-components": "^1.0.1-next.1", "@stencil-community/eslint-plugin": "0.7.1", "@stencil-community/postcss": "2.2.0", diff --git a/packages/calcite-components/src/assets/styles/_sortable.scss b/packages/calcite-components/src/assets/styles/_sortable.scss index b701a80fb39..82d9714b688 100644 --- a/packages/calcite-components/src/assets/styles/_sortable.scss +++ b/packages/calcite-components/src/assets/styles/_sortable.scss @@ -1,4 +1,5 @@ @mixin sortable-helper-classes() { + .calcite-sortable--chosen, .calcite-sortable--ghost, .calcite-sortable--drag { overflow: hidden; diff --git a/packages/calcite-components/src/components.d.ts b/packages/calcite-components/src/components.d.ts index ce68881ce6c..7dc40046c31 100644 --- a/packages/calcite-components/src/components.d.ts +++ b/packages/calcite-components/src/components.d.ts @@ -6260,6 +6260,8 @@ declare global { }; interface HTMLCalciteListElementEventMap { "calciteListChange": void; + "calciteListDragEnd": ListDragDetail; + "calciteListDragStart": ListDragDetail; "calciteListFilter": void; "calciteListOrderChange": ListDragDetail; "calciteInternalListDefaultSlotChange": void; @@ -6284,6 +6286,7 @@ declare global { interface HTMLCalciteListItemElementEventMap { "calciteListItemSelect": void; "calciteListItemClose": void; + "calciteListItemToggle": void; "calciteInternalListItemSelect": void; "calciteInternalListItemSelectMultiple": { selectMultiple: boolean; @@ -9984,6 +9987,14 @@ declare namespace LocalJSX { * Emits when any of the list item selections have changed. */ "onCalciteListChange"?: (event: CalciteListCustomEvent) => void; + /** + * Emits when the component's dragging has ended. + */ + "onCalciteListDragEnd"?: (event: CalciteListCustomEvent) => void; + /** + * Emits when the component's dragging has started. + */ + "onCalciteListDragStart"?: (event: CalciteListCustomEvent) => void; /** * Emits when the component's filter has changed. */ @@ -10073,6 +10084,10 @@ declare namespace LocalJSX { * Emits when the item's content is selected. */ "onCalciteListItemSelect"?: (event: CalciteListItemCustomEvent) => void; + /** + * Fires when the open button is clicked. + */ + "onCalciteListItemToggle"?: (event: CalciteListItemCustomEvent) => void; /** * When `true`, the item is open to show child components. */ diff --git a/packages/calcite-components/src/components/avatar/avatar.e2e.ts b/packages/calcite-components/src/components/avatar/avatar.e2e.ts index 83b7e688cd3..8c769695707 100644 --- a/packages/calcite-components/src/components/avatar/avatar.e2e.ts +++ b/packages/calcite-components/src/components/avatar/avatar.e2e.ts @@ -1,5 +1,11 @@ import { newE2EPage } from "@stencil/core/testing"; import { accessible, defaults, hidden, renders } from "../../tests/commonTests"; +import { placeholderImage } from "../../../.storybook/placeholderImage"; + +const placeholderUrl = placeholderImage({ + width: 120, + height: 120, +}); describe("calcite-avatar", () => { describe("renders", () => { @@ -12,7 +18,7 @@ describe("calcite-avatar", () => { describe("accessible", () => { accessible("calcite-avatar"); - accessible(""); + accessible(``); }); describe("defaults", () => { @@ -26,9 +32,9 @@ describe("calcite-avatar", () => { it("renders thumbnail when provided", async () => { const page = await newE2EPage(); - await page.setContent(""); + await page.setContent(``); const thumbnail = await page.find("calcite-avatar >>> .thumbnail"); - expect(thumbnail).toEqualAttribute("src", "http://placekitten.com/120/120"); + expect(thumbnail).toEqualAttribute("src", placeholderUrl); }); it("renders initials when no thumbnail is provided", async () => { diff --git a/packages/calcite-components/src/components/button/button.tsx b/packages/calcite-components/src/components/button/button.tsx index 8af673deaf5..f9de70225ec 100644 --- a/packages/calcite-components/src/components/button/button.tsx +++ b/packages/calcite-components/src/components/button/button.tsx @@ -1,4 +1,15 @@ -import { Build, Component, Element, h, Method, Prop, State, VNode, Watch } from "@stencil/core"; +import { + Build, + Component, + Element, + forceUpdate, + h, + Method, + Prop, + State, + VNode, + Watch, +} from "@stencil/core"; import { findAssociatedForm, FormOwner, resetForm, submitForm } from "../../utils/form"; import { connectInteractive, @@ -27,11 +38,6 @@ import { Appearance, FlipContext, Kind, Scale, Width } from "../interfaces"; import { ButtonMessages } from "./assets/button/t9n"; import { ButtonAlignment } from "./interfaces"; import { CSS } from "./resources"; -import { - GlobalAttrComponent, - unwatchGlobalAttributes, - watchGlobalAttributes, -} from "../../utils/globalAttributes"; import { toAriaBoolean } from "../../utils/dom"; /** Passing a 'href' will render an anchor link, instead of a button. Role will be set to link, or button, depending on this. */ @@ -46,7 +52,6 @@ import { toAriaBoolean } from "../../utils/dom"; }) export class Button implements - GlobalAttrComponent, LabelableComponent, InteractiveComponent, FormOwner, @@ -56,6 +61,17 @@ export class Button { //-------------------------------------------------------------------------- // + // Global attributes + // + //-------------------------------------------------------------------------- + + @Watch("aria-expanded") + handleGlobalAttributesChanged(): void { + forceUpdate(this); + } + + // -------------------------------------------------------------------------- + // // Properties // //-------------------------------------------------------------------------- @@ -183,7 +199,6 @@ export class Button connectInteractive(this); connectLocalized(this); connectMessages(this); - watchGlobalAttributes(this, ["aria-expanded"]); this.hasLoader = this.loading; this.setupTextContentObserver(); connectLabel(this); @@ -198,7 +213,6 @@ export class Button disconnectMessages(this); this.resizeObserver?.disconnect(); this.formEl = null; - unwatchGlobalAttributes(this); } async componentWillLoad(): Promise { @@ -260,6 +274,7 @@ export class Button return ( @@ -357,10 +371,6 @@ export class Button resizeObserver = createObserver("resize", () => this.setTooltipText()); - @State() globalAttributes = { - ariaExpanded: undefined, - }; - //-------------------------------------------------------------------------- // // Private Methods diff --git a/packages/calcite-components/src/components/dropdown-item/dropdown-item.scss b/packages/calcite-components/src/components/dropdown-item/dropdown-item.scss index e409cc47d7f..550b02f7151 100644 --- a/packages/calcite-components/src/components/dropdown-item/dropdown-item.scss +++ b/packages/calcite-components/src/components/dropdown-item/dropdown-item.scss @@ -103,59 +103,33 @@ padding-inline-start: theme("padding.10"); } -:host(:hover) .container, -:host(:active) .container { - @apply bg-foreground-2 text-color-1 no-underline; -} - -:host(:hover) .container--link .dropdown-link, -:host(:active) .container--link .dropdown-link { - @apply text-color-1; -} +:host(:hover:not([disabled])), +:host(:active:not([disabled])) { + .container { + @apply bg-foreground-2 text-color-1 no-underline; + } -:host(:focus) .container { - @apply text-color-1 no-underline; + .container--link .dropdown-link { + @apply text-color-1; + } } -:host(:active) .container { +:host(:active:not([disabled])) .container { @apply bg-foreground-3; } -:host(:hover) .container:before, -:host(:active) .container:before, -:host(:focus) .container:before { - @apply opacity-100; +:host(:focus) .container { + @apply text-color-1 no-underline; } :host([selected]) .container:not(.container--none-selection), :host([selected]) .container--link .dropdown-link { @apply text-color-1 font-medium; - &:before { - @apply opacity-100; - color: theme("backgroundColor.brand"); - } & calcite-icon { color: theme("backgroundColor.brand"); } } -// no dot for none and multi modes -.container--multi-selection:before, -.container--none-selection:before { - @apply hidden; -} - -// single select "icon" -.container--s:before { - inset-inline-start: theme("spacing.2"); -} -.container--m:before { - inset-inline-start: theme("spacing.3"); -} -.container--l:before { - inset-inline-start: theme("spacing.4"); -} - // item icon .dropdown-item-icon { @apply absolute @@ -177,7 +151,7 @@ inset-inline-start: theme("spacing.3"); } -:host(:hover) .dropdown-item-icon { +:host(:hover:not([disabled])) .dropdown-item-icon { color: theme("borderColor.color.1"); @apply opacity-100; } diff --git a/packages/calcite-components/src/components/dropdown/dropdown.stories.ts b/packages/calcite-components/src/components/dropdown/dropdown.stories.ts index 1f3e4aace0a..840347786ed 100644 --- a/packages/calcite-components/src/components/dropdown/dropdown.stories.ts +++ b/packages/calcite-components/src/components/dropdown/dropdown.stories.ts @@ -164,19 +164,19 @@ export const itemsAsLinks = (): string => html` > Open Dropdown - Throw Apples - Visit Oranges - Eat Grapes - Plant beans - Add peas @@ -200,19 +200,25 @@ export const darkModeRTL_TestOnly = (): string => html` List Grid Table - A link + A link List Grid Table - A link + A link List Grid Table - A link + A link `; @@ -232,19 +238,19 @@ export const itemsAsLinksDarkMode = (): string => html` > Open Dropdown - Throw Apples - Visit Oranges - Eat Grapes - Plant beans - Add peas diff --git a/packages/calcite-components/src/components/dropdown/dropdown.tsx b/packages/calcite-components/src/components/dropdown/dropdown.tsx index 55e77ea0302..475b879f9eb 100644 --- a/packages/calcite-components/src/components/dropdown/dropdown.tsx +++ b/packages/calcite-components/src/components/dropdown/dropdown.tsx @@ -78,12 +78,14 @@ export class Dropdown @Watch("open") openHandler(): void { - if (!this.disabled) { - onToggleOpenCloseComponent(this); + onToggleOpenCloseComponent(this); + + if (this.disabled) { + this.open = false; return; } - this.open = false; + this.reposition(true); } /** @@ -549,7 +551,6 @@ export class Dropdown }; onBeforeOpen(): void { - this.reposition(true); this.calciteDropdownBeforeOpen.emit(); } @@ -563,7 +564,6 @@ export class Dropdown onClose(): void { this.calciteDropdownClose.emit(); - this.reposition(true); } setReferenceEl = (el: HTMLDivElement): void => { diff --git a/packages/calcite-components/src/components/input-date-picker/input-date-picker.e2e.ts b/packages/calcite-components/src/components/input-date-picker/input-date-picker.e2e.ts index 0b4e889c1fa..d1cf070c3b6 100644 --- a/packages/calcite-components/src/components/input-date-picker/input-date-picker.e2e.ts +++ b/packages/calcite-components/src/components/input-date-picker/input-date-picker.e2e.ts @@ -133,8 +133,11 @@ describe("calcite-input-date-picker", () => { await input.click(); await page.waitForChanges(); await page.waitForTimeout(animationDurationInMs); - const wrapper = await page.waitForFunction(() => - document.querySelector("calcite-input-date-picker").shadowRoot.querySelector(".calendar-picker-wrapper") + const wrapper = await page.waitForFunction( + (calendarWrapperClass: string) => + document.querySelector("calcite-input-date-picker").shadowRoot.querySelector(`.${calendarWrapperClass}`), + {}, + CSS.calendarWrapper ); expect(await wrapper.isIntersectingViewport()).toBe(true); @@ -202,9 +205,13 @@ describe("calcite-input-date-picker", () => { await page.waitForChanges(); await page.waitForTimeout(animationDurationInMs); - const wrapper = await page.waitForFunction(() => - document.querySelector("calcite-input-date-picker").shadowRoot.querySelector(".calendar-picker-wrapper") + const wrapper = await page.waitForFunction( + (calendarWrapperClass: string) => + document.querySelector("calcite-input-date-picker").shadowRoot.querySelector(`.${calendarWrapperClass}`), + {}, + CSS.calendarWrapper ); + expect(await wrapper.isIntersectingViewport()).toBe(true); const inputtedStartDate = "1/1/2020"; @@ -318,50 +325,267 @@ describe("calcite-input-date-picker", () => { let page: E2EPage; let inputDatePicker: E2EElement; - beforeEach(async () => { - page = await newE2EPage(); - await page.setContent(html` `); - await skipAnimations(page); - await page.waitForChanges(); - inputDatePicker = await page.find("calcite-input-date-picker"); - }); + describe("single value", () => { + beforeEach(async () => { + page = await newE2EPage(); + await page.setContent(html` `); + await skipAnimations(page); + await page.waitForChanges(); + inputDatePicker = await page.find("calcite-input-date-picker"); + }); - it("toggles the date picker when clicked", async () => { - let calendar = await page.find("calcite-input-date-picker >>> .calendar-picker-wrapper"); + it("toggles the date picker when clicked", async () => { + let calendar = await page.find(`calcite-input-date-picker >>> .${CSS.calendarWrapper}`); - expect(await calendar.isVisible()).toBe(false); + expect(await calendar.isVisible()).toBe(false); - await inputDatePicker.click(); - await page.waitForChanges(); - calendar = await page.find("calcite-input-date-picker >>> .calendar-picker-wrapper"); + await inputDatePicker.click(); + await page.waitForChanges(); + calendar = await page.find(`calcite-input-date-picker >>> .${CSS.calendarWrapper}`); - expect(await calendar.isVisible()).toBe(true); + expect(await calendar.isVisible()).toBe(true); - await inputDatePicker.click(); - await page.waitForChanges(); - calendar = await page.find("calcite-input-date-picker >>> .calendar-picker-wrapper"); + await inputDatePicker.click(); + await page.waitForChanges(); + calendar = await page.find(`calcite-input-date-picker >>> .${CSS.calendarWrapper}`); + + expect(await calendar.isVisible()).toBe(false); + }); + + it("toggles the date picker when using arrow down/escape key", async () => { + let calendar = await page.find(`calcite-input-date-picker >>> .${CSS.calendarWrapper}`); + + expect(await calendar.isVisible()).toBe(false); - expect(await calendar.isVisible()).toBe(false); + await inputDatePicker.callMethod("setFocus"); + await page.waitForChanges(); + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + calendar = await page.find(`calcite-input-date-picker >>> .${CSS.calendarWrapper}`); + + expect(await calendar.isVisible()).toBe(true); + + await page.keyboard.press("Escape"); + await page.waitForChanges(); + calendar = await page.find(`calcite-input-date-picker >>> .${CSS.calendarWrapper}`); + + expect(await calendar.isVisible()).toBe(false); + }); }); - it("toggles the date picker when using arrow down/escape key", async () => { - let calendar = await page.find("calcite-input-date-picker >>> .calendar-picker-wrapper"); + describe("range", () => { + beforeEach(async () => { + page = await newE2EPage(); + await page.setContent(html` `); + await skipAnimations(page); + await page.waitForChanges(); + inputDatePicker = await page.find("calcite-input-date-picker"); + }); - expect(await calendar.isVisible()).toBe(false); + async function isCalendarVisible(calendar: E2EElement, type: "start" | "end"): Promise { + const calendarPosition = calendar.classList.contains(CSS.calendarWrapperEnd) ? "end" : "start"; + return (await calendar.isVisible()) && calendarPosition === type; + } - await inputDatePicker.callMethod("setFocus"); - await page.waitForChanges(); - await page.keyboard.press("ArrowDown"); - await page.waitForChanges(); - calendar = await page.find("calcite-input-date-picker >>> .calendar-picker-wrapper"); + it("toggles the date picker when clicked", async () => { + const calendar = await page.find(`calcite-input-date-picker >>> .${CSS.calendarWrapper}`); - expect(await calendar.isVisible()).toBe(true); + expect(await isCalendarVisible(calendar, "start")).toBe(false); + expect(await isCalendarVisible(calendar, "end")).toBe(false); - await page.keyboard.press("Escape"); - await page.waitForChanges(); - calendar = await page.find("calcite-input-date-picker >>> .calendar-picker-wrapper"); + const startInput = await page.find( + `calcite-input-date-picker >>> .${CSS.inputWrapper}[data-position="start"] calcite-input-text` + ); + const startInputToggle = await page.find( + `calcite-input-date-picker >>> .${CSS.inputWrapper}[data-position="start"] .${CSS.toggleIcon}` + ); + + const endInput = await page.find( + `calcite-input-date-picker >>> .${CSS.inputWrapper}[data-position="end"] calcite-input-text` + ); + const endInputToggle = await page.find( + `calcite-input-date-picker >>> .${CSS.inputWrapper}[data-position="end"] .${CSS.toggleIcon}` + ); + + // toggling via start date input + + await startInput.click(); + await page.waitForChanges(); + + expect(await isCalendarVisible(calendar, "start")).toBe(true); + + await startInput.click(); + await page.waitForChanges(); + + expect(await isCalendarVisible(calendar, "start")).toBe(false); + + // toggling via start date toggle icon + + await startInputToggle.click(); + await page.waitForChanges(); + + expect(await isCalendarVisible(calendar, "start")).toBe(true); + + await startInputToggle.click(); + await page.waitForChanges(); + + expect(await isCalendarVisible(calendar, "start")).toBe(false); + + // toggling via end date input + + await endInput.click(); + await page.waitForChanges(); + + expect(await isCalendarVisible(calendar, "end")).toBe(true); + + await endInput.click(); + await page.waitForChanges(); + + expect(await isCalendarVisible(calendar, "end")).toBe(false); + + // toggling via end date toggle icon + + await endInputToggle.click(); + await page.waitForChanges(); + + expect(await isCalendarVisible(calendar, "end")).toBe(true); + + await endInputToggle.click(); + await page.waitForChanges(); + + expect(await isCalendarVisible(calendar, "end")).toBe(false); + + // toggling via start date input and toggle icon + + await startInput.click(); + await page.waitForChanges(); + + expect(await isCalendarVisible(calendar, "start")).toBe(true); + + await startInputToggle.click(); + await page.waitForChanges(); + + expect(await isCalendarVisible(calendar, "start")).toBe(false); - expect(await calendar.isVisible()).toBe(false); + // toggling via start toggle icon and date input + + await startInputToggle.click(); + await page.waitForChanges(); + + expect(await isCalendarVisible(calendar, "start")).toBe(true); + + await startInput.click(); + await page.waitForChanges(); + + expect(await isCalendarVisible(calendar, "start")).toBe(false); + + // toggling via end date input and toggle icon + + await endInput.click(); + await page.waitForChanges(); + + expect(await isCalendarVisible(calendar, "end")).toBe(true); + + await endInputToggle.click(); + await page.waitForChanges(); + + expect(await isCalendarVisible(calendar, "end")).toBe(false); + + // toggling via end toggle icon and date input + + await endInputToggle.click(); + await page.waitForChanges(); + + expect(await isCalendarVisible(calendar, "end")).toBe(true); + + await endInput.click(); + await page.waitForChanges(); + + expect(await isCalendarVisible(calendar, "end")).toBe(false); + + // toggling via start date input and end toggle icon + + await startInput.click(); + await page.waitForChanges(); + + expect(await isCalendarVisible(calendar, "start")).toBe(true); + + await endInputToggle.click(); + await page.waitForChanges(); + + expect(await isCalendarVisible(calendar, "end")).toBe(true); + + // toggling via start toggle icon and date input + + await startInputToggle.click(); + await page.waitForChanges(); + + expect(await isCalendarVisible(calendar, "start")).toBe(true); + + await endInput.click(); + await page.waitForChanges(); + + expect(await isCalendarVisible(calendar, "end")).toBe(true); + + // close + await endInput.click(); + await page.waitForChanges(); + + // toggling via end date input and start toggle icon + + await endInput.click(); + await page.waitForChanges(); + + expect(await isCalendarVisible(calendar, "end")).toBe(true); + + await startInputToggle.click(); + await page.waitForChanges(); + + expect(await isCalendarVisible(calendar, "start")).toBe(true); + + // toggling via end toggle icon and start date input + + await endInputToggle.click(); + await page.waitForChanges(); + + expect(await isCalendarVisible(calendar, "end")).toBe(true); + + await startInput.click(); + await page.waitForChanges(); + + expect(await isCalendarVisible(calendar, "start")).toBe(true); + }); + + it("toggles the date picker when using arrow down/escape key", async () => { + const calendar = await page.find(`calcite-input-date-picker >>> .${CSS.calendarWrapper}`); + + expect(await isCalendarVisible(calendar, "start")).toBe(false); + expect(await isCalendarVisible(calendar, "end")).toBe(false); + + await inputDatePicker.callMethod("setFocus"); + await page.waitForChanges(); + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + + expect(await isCalendarVisible(calendar, "start")).toBe(true); + + await page.keyboard.press("Escape"); + await page.waitForChanges(); + + expect(await isCalendarVisible(calendar, "start")).toBe(false); + + await page.keyboard.press("Tab"); + + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + + expect(await isCalendarVisible(calendar, "end")).toBe(true); + + await page.keyboard.press("Escape"); + await page.waitForChanges(); + + expect(await isCalendarVisible(calendar, "end")).toBe(false); + }); }); }); diff --git a/packages/calcite-components/src/components/input-date-picker/input-date-picker.scss b/packages/calcite-components/src/components/input-date-picker/input-date-picker.scss index b05e82c9474..b844167889f 100644 --- a/packages/calcite-components/src/components/input-date-picker/input-date-picker.scss +++ b/packages/calcite-components/src/components/input-date-picker/input-date-picker.scss @@ -30,7 +30,7 @@ @include disabled(); -.calendar-picker-wrapper { +.calendar-wrapper { @apply shadow-none; transform: translate3d(0, 0, 0); } @@ -79,7 +79,7 @@ items-start; } - .calendar-picker-wrapper--end { + .calendar-wrapper--end { transform: translate3d(0, 0, 0); } diff --git a/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx b/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx index 360d9cbc606..0785d108309 100644 --- a/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx +++ b/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx @@ -264,6 +264,8 @@ export class InputDatePicker this.open = false; return; } + + this.reposition(true); } /** @@ -517,12 +519,14 @@ export class InputDatePicker }; return ( - + {this.localeData && ( -
+
@@ -532,15 +536,15 @@ export class InputDatePicker aria-describedby={this.placeholderTextId} aria-expanded={toAriaBoolean(this.open)} aria-haspopup="dialog" - class={`input ${ - this.layout === "vertical" && this.range ? `no-bottom-border` : `` - }`} + class={{ + [CSS.input]: true, + [CSS.inputNoBottomBorder]: this.layout === "vertical" && this.range, + }} disabled={disabled} icon="calendar" onCalciteInputTextInput={this.calciteInternalInputInputHandler} onCalciteInternalInputTextBlur={this.calciteInternalInputBlurHandler} onCalciteInternalInputTextFocus={this.startInputFocus} - onFocus={this.startEndInputFocus} placeholder={this.localeData?.placeholder} readOnly={readOnly} role="combobox" @@ -570,8 +574,8 @@ export class InputDatePicker >
{this.range && this.layout === "horizontal" && ( -
+
)} {this.range && this.layout === "vertical" && this.scale !== "s" && ( -
+
)} {this.range && (
@@ -624,15 +630,14 @@ export class InputDatePicker aria-expanded={toAriaBoolean(this.open)} aria-haspopup="dialog" class={{ - input: true, - "border-top-color-one": this.layout === "vertical" && this.range, + [CSS.input]: true, + [CSS.inputBorderTopColorOne]: this.layout === "vertical" && this.range, }} disabled={disabled} icon="calendar" onCalciteInputTextInput={this.calciteInternalInputInputHandler} onCalciteInternalInputTextBlur={this.calciteInternalInputBlurHandler} onCalciteInternalInputTextFocus={this.endInputFocus} - onFocus={this.startEndInputFocus} placeholder={this.localeData?.placeholder} readOnly={readOnly} role="combobox" @@ -670,6 +675,8 @@ export class InputDatePicker @Element() el: HTMLCalciteInputDatePickerElement; + private currentOpenInput: "start" | "end"; + private datePickerEl: HTMLCalciteDatePickerElement; private dialogId = `date-picker-dialog--${guid()}`; @@ -694,8 +701,6 @@ export class InputDatePicker @State() focusedInput: "start" | "end" = "start"; - private lastBlurredInput: "start" | "end" | "none" = "none"; - @State() private localeData: DateLocaleData; private startInput: HTMLCalciteInputElement; @@ -739,14 +744,32 @@ export class InputDatePicker // //-------------------------------------------------------------------------- - private onInputWrapperClick = () => { - if (this.range && this.lastBlurredInput !== "none" && this.open) { - // we keep the date-picker open when moving between inputs - } else { + private onInputWrapperPointerDown = (): void => { + this.currentOpenInput = this.focusedInput; + }; + + private onInputWrapperClick = (event: MouseEvent) => { + const { range, endInput, startInput, currentOpenInput } = this; + if (!range || !this.open) { this.open = !this.open; + return; } - this.lastBlurredInput = "none"; + const currentTarget = event.currentTarget as HTMLDivElement; + const position = currentTarget.getAttribute("data-position") as "start" | "end"; + const path = event.composedPath(); + const wasToggleClicked = path.find((el: HTMLElement) => { + return el.classList?.contains(CSS.toggleIcon); + }); + + if (wasToggleClicked) { + const targetInput = position === "start" ? startInput : endInput; + targetInput.setFocus(); + } + + if (currentOpenInput === position) { + this.open = !this.open; + } }; setFilteredPlacements = (): void => { @@ -766,7 +789,6 @@ export class InputDatePicker } onBeforeOpen(): void { - this.reposition(true); this.calciteInputDatePickerBeforeOpen.emit(); } @@ -792,7 +814,6 @@ export class InputDatePicker this.restoreInputFocus(); this.focusOnOpen = false; this.datePickerEl.reset(); - this.reposition(true); } setStartInput = (el: HTMLCalciteInputElement): void => { @@ -803,9 +824,8 @@ export class InputDatePicker this.endInput = el; }; - deactivate = (): void => { + private blurHandler = (): void => { this.open = false; - this.lastBlurredInput = "none"; }; private commitValue(): void { @@ -886,12 +906,6 @@ export class InputDatePicker this.focusedInput = "start"; }; - startEndInputFocus = (event: FocusEvent): void => { - const blurredEl = event.relatedTarget as HTMLElement; - this.lastBlurredInput = - blurredEl === this.startInput ? "start" : blurredEl === this.endInput ? "end" : "none"; - }; - endInputFocus = (): void => { this.focusedInput = "end"; }; diff --git a/packages/calcite-components/src/components/input-date-picker/resources.ts b/packages/calcite-components/src/components/input-date-picker/resources.ts index e79b51c7e74..5c3a881fab2 100644 --- a/packages/calcite-components/src/components/input-date-picker/resources.ts +++ b/packages/calcite-components/src/components/input-date-picker/resources.ts @@ -1,6 +1,15 @@ export const CSS = { assistiveText: "assistive-text", + calendarWrapper: "calendar-wrapper", + calendarWrapperEnd: "calendar-wrapper--end", + horizontalArrowContainer: "horizontal-arrow-container", + inputBorderTopColorOne: "border-top-color-one", + inputContainer: "input-container", + inputNoBottomBorder: "no-bottom-border", + inputWrapper: "input-wrapper", + input: "input", menu: "menu-container", menuActive: "menu-container--active", toggleIcon: "toggle-icon", + verticalArrowContainer: "vertical-arrow-container", }; diff --git a/packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx b/packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx index 0e26fa6cd5d..36cfbbf7f68 100644 --- a/packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx +++ b/packages/calcite-components/src/components/input-time-picker/input-time-picker.tsx @@ -172,16 +172,15 @@ export class InputTimePicker @Prop({ reflect: true, mutable: true }) open = false; @Watch("open") - openHandler(open: boolean): void { + openHandler(): void { onToggleOpenCloseComponent(this); + if (this.disabled || this.readOnly) { this.open = false; return; } - if (open) { - this.reposition(true); - } + this.reposition(true); } /** When `true`, interaction is prevented and the component is displayed with lower opacity. */ diff --git a/packages/calcite-components/src/components/input/input.e2e.ts b/packages/calcite-components/src/components/input/input.e2e.ts index e54a6f85a2b..080db981a62 100644 --- a/packages/calcite-components/src/components/input/input.e2e.ts +++ b/packages/calcite-components/src/components/input/input.e2e.ts @@ -2006,7 +2006,7 @@ describe("calcite-input", () => { }, { type: "url", - value: "http://www.example.com", + value: "http://www.esri.com", }, { type: "week", diff --git a/packages/calcite-components/src/components/list-item/list-item.e2e.ts b/packages/calcite-components/src/components/list-item/list-item.e2e.ts index 6ffe4f73cd8..ae6705b3fb7 100755 --- a/packages/calcite-components/src/components/list-item/list-item.e2e.ts +++ b/packages/calcite-components/src/components/list-item/list-item.e2e.ts @@ -275,4 +275,27 @@ describe("calcite-list-item", () => { expect(calciteListItemClose).toHaveReceivedEventTimes(1); }); + + it("should fire calciteListItemToggle event when opened and closed", async () => { + const page = await newE2EPage({ + html: html``, + }); + + const listItem = await page.find("calcite-list-item"); + const calciteListItemToggle = await page.spyOnEvent("calciteListItemToggle", "window"); + + expect(await listItem.getProperty("open")).toBe(false); + + const openButton = await page.find(`calcite-list-item >>> .${CSS.openContainer}`); + + await openButton.click(); + expect(await listItem.getProperty("open")).toBe(true); + expect(calciteListItemToggle).toHaveReceivedEventTimes(1); + + await openButton.click(); + expect(await listItem.getProperty("open")).toBe(false); + expect(calciteListItemToggle).toHaveReceivedEventTimes(2); + }); }); diff --git a/packages/calcite-components/src/components/list-item/list-item.tsx b/packages/calcite-components/src/components/list-item/list-item.tsx index 5fc5e11a8bf..60a2455adb2 100644 --- a/packages/calcite-components/src/components/list-item/list-item.tsx +++ b/packages/calcite-components/src/components/list-item/list-item.tsx @@ -232,6 +232,11 @@ export class ListItem */ @Event({ cancelable: false }) calciteListItemClose: EventEmitter; + /** + * Fires when the open button is clicked. + */ + @Event({ cancelable: false }) calciteListItemToggle: EventEmitter; + /** * * @internal @@ -397,7 +402,7 @@ export class ListItem } return ( - + @@ -491,7 +496,7 @@ export class ListItem icon={ICONS.close} key="close-action" label={messages.close} - onClick={this.closeClickHandler} + onClick={this.handleCloseClick} text={messages.close} /> ) : null} @@ -593,7 +598,7 @@ export class ListItem [CSS.contentContainerHasCenterContent]: hasCenterContent, }} key="content-container" - onClick={this.itemClicked} + onClick={this.handleItemClick} role="gridcell" // eslint-disable-next-line react/jsx-sort-props -- ref should be last so node attrs/props are in sync (see https://github.com/Esri/calcite-design-system/pull/6530) ref={(el) => (this.contentEl = el)} @@ -669,36 +674,36 @@ export class ListItem this.calciteInternalListItemChange.emit(); } - closeClickHandler = (): void => { + private handleCloseClick = (): void => { this.closed = true; this.calciteListItemClose.emit(); }; - handleContentSlotChange = (event: Event): void => { + private handleContentSlotChange = (event: Event): void => { this.hasCustomContent = slotChangeHasAssignedElement(event); }; - handleActionsStartSlotChange = (event: Event): void => { + private handleActionsStartSlotChange = (event: Event): void => { this.hasActionsStart = slotChangeHasAssignedElement(event); }; - handleActionsEndSlotChange = (event: Event): void => { + private handleActionsEndSlotChange = (event: Event): void => { this.hasActionsEnd = slotChangeHasAssignedElement(event); }; - handleContentStartSlotChange = (event: Event): void => { + private handleContentStartSlotChange = (event: Event): void => { this.hasContentStart = slotChangeHasAssignedElement(event); }; - handleContentEndSlotChange = (event: Event): void => { + private handleContentEndSlotChange = (event: Event): void => { this.hasContentEnd = slotChangeHasAssignedElement(event); }; - handleContentBottomSlotChange = (event: Event): void => { + private handleContentBottomSlotChange = (event: Event): void => { this.hasContentBottom = slotChangeHasAssignedElement(event); }; - setSelectionDefaults(): void { + private setSelectionDefaults(): void { const { parentListEl, selectionMode, selectionAppearance } = this; if (!parentListEl) { @@ -714,7 +719,7 @@ export class ListItem } } - handleOpenableChange(slotEl: HTMLSlotElement): void { + private handleOpenableChange(slotEl: HTMLSlotElement): void { if (!slotEl) { return; } @@ -736,15 +741,20 @@ export class ListItem } } - handleDefaultSlotChange = (event: Event): void => { + private handleDefaultSlotChange = (event: Event): void => { this.handleOpenableChange(event.target as HTMLSlotElement); }; - toggleOpen = (): void => { - this.open = !this.open; + private handleToggleClick = (): void => { + this.toggle(); + }; + + private toggle = (value = !this.open): void => { + this.open = value; + this.calciteListItemToggle.emit(); }; - itemClicked = (event: PointerEvent): void => { + private handleItemClick = (event: PointerEvent): void => { if (event.defaultPrevented) { return; } @@ -753,7 +763,7 @@ export class ListItem this.calciteInternalListItemActive.emit(); }; - toggleSelected = (shiftKey: boolean): void => { + private toggleSelected = (shiftKey: boolean): void => { const { selectionMode, selected } = this; if (this.disabled) { @@ -772,13 +782,13 @@ export class ListItem this.calciteListItemSelect.emit(); }; - getGridCells(): HTMLTableCellElement[] { + private getGridCells(): HTMLTableCellElement[] { return [this.handleGridEl, this.actionsStartEl, this.contentEl, this.actionsEndEl].filter( (el) => el && !el.hidden ); } - handleItemKeyDown = (event: KeyboardEvent): void => { + private handleItemKeyDown = (event: KeyboardEvent): void => { if (event.defaultPrevented) { return; } @@ -802,7 +812,7 @@ export class ListItem const nextIndex = currentIndex + 1; if (currentIndex === -1) { if (!open && openable) { - this.open = true; + this.toggle(true); this.focusCell(null); } else if (cells[0]) { this.focusCell(cells[0]); @@ -816,7 +826,7 @@ export class ListItem if (currentIndex === -1) { this.focusCell(null); if (open && openable) { - this.open = false; + this.toggle(false); } else { this.calciteInternalFocusPreviousItem.emit(); } @@ -829,11 +839,11 @@ export class ListItem } }; - focusCellNull = (): void => { + private focusCellNull = (): void => { this.focusCell(null); }; - focusCell = (focusEl: HTMLTableCellElement, saveFocusIndex = true): void => { + private focusCell = (focusEl: HTMLTableCellElement, saveFocusIndex = true): void => { const { parentListEl } = this; if (saveFocusIndex) { diff --git a/packages/calcite-components/src/components/list/list.e2e.ts b/packages/calcite-components/src/components/list/list.e2e.ts index 451634335b1..9ad63ed58fd 100755 --- a/packages/calcite-components/src/components/list/list.e2e.ts +++ b/packages/calcite-components/src/components/list/list.e2e.ts @@ -6,7 +6,7 @@ import { debounceTimeout } from "./resources"; import { CSS } from "../list-item/resources"; import { DEBOUNCE_TIMEOUT as FILTER_DEBOUNCE_TIMEOUT } from "../filter/resources"; import { GlobalTestProps, dragAndDrop, isElementFocused, getFocusedElementProp } from "../../tests/utils"; -import { DragDetail } from "../../utils/sortableComponent"; +import { ListDragDetail } from "./interfaces"; const placeholder = placeholderImage({ width: 140, @@ -733,6 +733,10 @@ describe("calcite-list", () => { oldIndex: number; startCalledTimes: number; endCalledTimes: number; + endNewIndex: number; + endOldIndex: number; + startNewIndex: number; + startOldIndex: number; }>; it("works using a mouse", async () => { @@ -746,16 +750,20 @@ describe("calcite-list", () => { testWindow.oldIndex = -1; testWindow.startCalledTimes = 0; testWindow.endCalledTimes = 0; - list.addEventListener("calciteListOrderChange", (event: CustomEvent) => { + list.addEventListener("calciteListOrderChange", (event: CustomEvent) => { testWindow.calledTimes++; testWindow.newIndex = event?.detail?.newIndex; testWindow.oldIndex = event?.detail?.oldIndex; }); - list.addEventListener("calciteListDragEnd", () => { + list.addEventListener("calciteListDragEnd", (event: CustomEvent) => { testWindow.endCalledTimes++; + testWindow.endNewIndex = event.detail.newIndex; + testWindow.endOldIndex = event.detail.oldIndex; }); - list.addEventListener("calciteListDragStart", () => { + list.addEventListener("calciteListDragStart", (event: CustomEvent) => { testWindow.startCalledTimes++; + testWindow.startNewIndex = event.detail.newIndex; + testWindow.startOldIndex = event.detail.oldIndex; }); }); @@ -785,6 +793,10 @@ describe("calcite-list", () => { newIndex: testWindow.newIndex, endCalledTimes: testWindow.endCalledTimes, startCalledTimes: testWindow.startCalledTimes, + endNewIndex: testWindow.endNewIndex, + endOldIndex: testWindow.endOldIndex, + startNewIndex: testWindow.startNewIndex, + startOldIndex: testWindow.startOldIndex, }; }); @@ -793,6 +805,10 @@ describe("calcite-list", () => { expect(results.endCalledTimes).toBe(1); expect(results.oldIndex).toBe(0); expect(results.newIndex).toBe(1); + expect(results.startNewIndex).toBe(null); + expect(results.startOldIndex).toBe(0); + expect(results.endNewIndex).toBe(1); + expect(results.endOldIndex).toBe(0); }); it("supports dragging items between lists", async () => { diff --git a/packages/calcite-components/src/components/list/list.tsx b/packages/calcite-components/src/components/list/list.tsx index b10cd486b6f..44331d6c61f 100755 --- a/packages/calcite-components/src/components/list/list.tsx +++ b/packages/calcite-components/src/components/list/list.tsx @@ -616,12 +616,12 @@ export class List this.connectObserver(); } - onDragEnd(): void { - this.calciteListDragEnd.emit(); + onDragEnd(detail: ListDragDetail): void { + this.calciteListDragEnd.emit(detail); } - onDragStart(): void { - this.calciteListDragStart.emit(); + onDragStart(detail: ListDragDetail): void { + this.calciteListDragStart.emit(detail); } onDragSort(detail: ListDragDetail): void { diff --git a/packages/calcite-components/src/components/list/usage/Advanced.md b/packages/calcite-components/src/components/list/usage/Advanced.md index 8a9365ad85e..2776d15f963 100644 --- a/packages/calcite-components/src/components/list/usage/Advanced.md +++ b/packages/calcite-components/src/components/list/usage/Advanced.md @@ -4,7 +4,7 @@ label="Dog" description="Also known as Canis familiaris, a carnivorous mammal closely related to the gray wolf that has been domesticated as a pet." > - + - + - + - + - - + + + + - - + + + + ``` diff --git a/packages/calcite-components/src/components/list/usage/Nested.md b/packages/calcite-components/src/components/list/usage/Nested.md index df2dcbf6640..1f1f2f0b1a1 100644 --- a/packages/calcite-components/src/components/list/usage/Nested.md +++ b/packages/calcite-components/src/components/list/usage/Nested.md @@ -4,11 +4,16 @@ label="United States of America" description="A country located in North America consisting of 50 states." > - - + + + + + + + + ``` diff --git a/packages/calcite-components/src/components/menu-item/menu-item.e2e.ts b/packages/calcite-components/src/components/menu-item/menu-item.e2e.ts index f8beb28371b..057d12bf700 100644 --- a/packages/calcite-components/src/components/menu-item/menu-item.e2e.ts +++ b/packages/calcite-components/src/components/menu-item/menu-item.e2e.ts @@ -50,6 +50,39 @@ describe("calcite-menu-item", () => { expect(eventSpy).toHaveReceivedEventTimes(1); }); + describe("href support", () => { + const testHref = "#nature"; + const testEl = ``; + + it("should navigate to a new url when href provided and user interacts with click", async () => { + const page = await newE2EPage(); + await page.setContent(html`${testEl}`); + const originalUrl = page.url(); + await page.waitForChanges(); + + const menuItem = await page.find("calcite-menu-item"); + await page.waitForChanges(); + await menuItem.click(); + await page.waitForChanges(); + const newUrl = page.url(); + expect(newUrl).toEqual(originalUrl + testHref); + }); + + it("should navigate to a new url when href provided and user interacts with `enter` key", async () => { + const page = await newE2EPage(); + await page.setContent(html`${testEl}`); + const originalUrl = page.url(); + await page.waitForChanges(); + + await page.keyboard.press("Tab"); + await page.waitForChanges(); + await page.keyboard.press("Enter"); + await page.waitForChanges(); + const newUrl = page.url(); + expect(newUrl).toEqual(originalUrl + testHref); + }); + }); + it("should emit calciteMenuItemSelect event when user select the text area of the component using Enter or Space key", async () => { const page = await newE2EPage(); await page.setContent(html` diff --git a/packages/calcite-components/src/components/menu-item/menu-item.tsx b/packages/calcite-components/src/components/menu-item/menu-item.tsx index bac34ddeec4..fe7c342d585 100644 --- a/packages/calcite-components/src/components/menu-item/menu-item.tsx +++ b/packages/calcite-components/src/components/menu-item/menu-item.tsx @@ -266,61 +266,54 @@ export class CalciteMenuItem implements LoadableComponent, T9nComponent, Localiz }; private keyDownHandler = async (event: KeyboardEvent): Promise => { - // opening and closing of submenu is handled here. Any other functionality is bubbled to parent menu. - if (event.key === " " || event.key === "Enter") { - this.selectMenuItem(event); - if ( - this.hasSubmenu && - (!this.href || (this.href && event.target === this.dropdownActionEl)) - ) { - this.open = !this.open; + const { hasSubmenu, href, layout, open, submenuItems } = this; + const key = event.key; + const targetIsDropdown = event.target === this.dropdownActionEl; + if (key === " " || key === "Enter") { + if (hasSubmenu && (!href || (href && targetIsDropdown))) { + this.open = !open; } - event.preventDefault(); - } else if (event.key === "Escape") { - if (this.open) { + if (!(href && targetIsDropdown) && key !== "Enter") { + this.selectMenuItem(event); + } + if (key === " " || (href && targetIsDropdown)) { + event.preventDefault(); + } + } else if (key === "Escape") { + if (open) { this.open = false; return; } this.calciteInternalMenuItemKeyEvent.emit({ event }); event.preventDefault(); - } else if (event.key === "ArrowDown" || event.key === "ArrowUp") { + } else if (key === "ArrowDown" || key === "ArrowUp") { event.preventDefault(); - if ( - (event.target === this.dropdownActionEl || !this.href) && - this.hasSubmenu && - !this.open && - this.layout === "horizontal" - ) { + if ((targetIsDropdown || !href) && hasSubmenu && !open && layout === "horizontal") { this.open = true; return; } this.calciteInternalMenuItemKeyEvent.emit({ event, - children: this.submenuItems, - isSubmenuOpen: this.open && this.hasSubmenu, + children: submenuItems, + isSubmenuOpen: open && hasSubmenu, }); - } else if (event.key === "ArrowLeft") { + } else if (key === "ArrowLeft") { event.preventDefault(); this.calciteInternalMenuItemKeyEvent.emit({ event, - children: this.submenuItems, + children: submenuItems, isSubmenuOpen: true, }); - } else if (event.key === "ArrowRight") { + } else if (key === "ArrowRight") { event.preventDefault(); - if ( - (event.target === this.dropdownActionEl || !this.href) && - this.hasSubmenu && - !this.open && - this.layout === "vertical" - ) { + if ((targetIsDropdown || !href) && hasSubmenu && !open && layout === "vertical") { this.open = true; return; } this.calciteInternalMenuItemKeyEvent.emit({ event, - children: this.submenuItems, - isSubmenuOpen: this.open && this.hasSubmenu, + children: submenuItems, + isSubmenuOpen: open && hasSubmenu, }); } }; diff --git a/packages/calcite-components/src/components/menu/menu.tsx b/packages/calcite-components/src/components/menu/menu.tsx index 42d212c7440..9136fc47e7c 100644 --- a/packages/calcite-components/src/components/menu/menu.tsx +++ b/packages/calcite-components/src/components/menu/menu.tsx @@ -9,6 +9,7 @@ import { Watch, Method, VNode, + forceUpdate, } from "@stencil/core"; import { focusElement, focusElementInGroup, slotChangeGetAssignedElements } from "../../utils/dom"; import { @@ -26,11 +27,6 @@ import { updateMessages, } from "../../utils/t9n"; import { MenuMessages } from "./assets/menu/t9n"; -import { - GlobalAttrComponent, - unwatchGlobalAttributes, - watchGlobalAttributes, -} from "../../utils/globalAttributes"; type Layout = "horizontal" | "vertical"; @@ -42,12 +38,22 @@ type Layout = "horizontal" | "vertical"; }, assetsDirs: ["assets"], }) -export class CalciteMenu - implements GlobalAttrComponent, LocalizedComponent, T9nComponent, LoadableComponent -{ +export class CalciteMenu implements LocalizedComponent, T9nComponent, LoadableComponent { //-------------------------------------------------------------------------- // - // Public Properties + // Global attributes + // + //-------------------------------------------------------------------------- + + @Watch("role") + handleGlobalAttributesChanged(): void { + forceUpdate(this); + this.setMenuItemLayout(this.menuItems, this.layout); + } + + //-------------------------------------------------------------------------- + // + // Properties // //-------------------------------------------------------------------------- @@ -102,10 +108,6 @@ export class CalciteMenu updateMessages(this, this.effectiveLocale); } - @State() globalAttributes = { - role: "menubar", - }; - menuItems: HTMLCalciteMenuItemElement[] = []; //-------------------------------------------------------------------------- @@ -117,7 +119,6 @@ export class CalciteMenu connectedCallback(): void { connectLocalized(this); connectMessages(this); - watchGlobalAttributes(this, ["role"]); } async componentWillLoad(): Promise { @@ -132,7 +133,6 @@ export class CalciteMenu disconnectedCallback(): void { disconnectLocalized(this); disconnectMessages(this); - unwatchGlobalAttributes(this); } //-------------------------------------------------------------------------- @@ -220,13 +220,17 @@ export class CalciteMenu setMenuItemLayout(items: HTMLCalciteMenuItemElement[], layout: Layout): void { items.forEach((item) => { item.layout = layout; - if (this.globalAttributes.role === "menubar") { + if (this.getEffectiveRole() === "menubar") { item.isTopLevelItem = true; item.topLevelMenuLayout = this.layout; } }); } + private getEffectiveRole(): string { + return this.el.getAttribute("role") || "menubar"; + } + // -------------------------------------------------------------------------- // // Render Methods @@ -236,7 +240,7 @@ export class CalciteMenu render(): VNode { return ( -
    +
    diff --git a/packages/calcite-components/src/components/modal/modal.e2e.ts b/packages/calcite-components/src/components/modal/modal.e2e.ts index eea592cbe82..6f97b2481e4 100644 --- a/packages/calcite-components/src/components/modal/modal.e2e.ts +++ b/packages/calcite-components/src/components/modal/modal.e2e.ts @@ -1,10 +1,10 @@ -import { newE2EPage } from "@stencil/core/testing"; +import { E2EPage, newE2EPage } from "@stencil/core/testing"; import { focusable, hidden, openClose, renders, slots, t9n } from "../../tests/commonTests"; import { html } from "../../../support/formatting"; import { CSS, SLOTS } from "./resources"; import { GlobalTestProps, isElementFocused, newProgrammaticE2EPage, skipAnimations } from "../../tests/utils"; -describe("calcite-modal properties", () => { +describe("calcite-modal", () => { describe("renders", () => { renders("calcite-modal", { display: "flex", visible: false }); }); @@ -26,6 +26,10 @@ describe("calcite-modal properties", () => { slots("calcite-modal", SLOTS); }); + describe("translation support", () => { + t9n("calcite-modal"); + }); + it("should hide closeButton when disabled", async () => { const page = await newE2EPage(); await page.setContent(""); @@ -169,363 +173,363 @@ describe("calcite-modal properties", () => { expect(mockCallBack).toHaveBeenCalledTimes(1); expect(await modal.getProperty("opened")).toBe(false); }); -}); -it("calls the beforeClose method prior to closing via attribute", async () => { - const page = await newE2EPage(); - const mockCallBack = jest.fn(); - await page.exposeFunction("beforeClose", mockCallBack); - await page.setContent(` + it("calls the beforeClose method prior to closing via attribute", async () => { + const page = await newE2EPage(); + const mockCallBack = jest.fn(); + await page.exposeFunction("beforeClose", mockCallBack); + await page.setContent(` `); - const modal = await page.find("calcite-modal"); - await page.$eval( - "calcite-modal", - (el: HTMLCalciteModalElement) => - (el.beforeClose = ( - window as GlobalTestProps<{ beforeClose: HTMLCalciteModalElement["beforeClose"] }> - ).beforeClose) - ); - await page.waitForChanges(); - modal.setProperty("open", true); - await page.waitForChanges(); - expect(await modal.getProperty("opened")).toBe(true); - modal.removeAttribute("open"); - await page.waitForChanges(); - expect(mockCallBack).toHaveBeenCalledTimes(1); - expect(await modal.getProperty("opened")).toBe(false); -}); - -it("should handle rejected 'beforeClose' promise'", async () => { - const page = await newE2EPage(); - - const mockCallBack = jest.fn().mockReturnValue(() => Promise.reject()); - await page.exposeFunction("beforeClose", mockCallBack); + const modal = await page.find("calcite-modal"); + await page.$eval( + "calcite-modal", + (el: HTMLCalciteModalElement) => + (el.beforeClose = ( + window as GlobalTestProps<{ beforeClose: HTMLCalciteModalElement["beforeClose"] }> + ).beforeClose) + ); + await page.waitForChanges(); + modal.setProperty("open", true); + await page.waitForChanges(); + expect(await modal.getProperty("opened")).toBe(true); + modal.removeAttribute("open"); + await page.waitForChanges(); + expect(mockCallBack).toHaveBeenCalledTimes(1); + expect(await modal.getProperty("opened")).toBe(false); + }); - await page.setContent(``); + it("should handle rejected 'beforeClose' promise'", async () => { + const page = await newE2EPage(); - await page.$eval( - "calcite-modal", - (elm: HTMLCalciteModalElement) => - (elm.beforeClose = (window as typeof window & Pick).beforeClose) - ); + const mockCallBack = jest.fn().mockReturnValue(() => Promise.reject()); + await page.exposeFunction("beforeClose", mockCallBack); - const modal = await page.find("calcite-modal"); - modal.setProperty("open", false); - await page.waitForChanges(); + await page.setContent(``); - expect(mockCallBack).toHaveBeenCalledTimes(1); -}); + await page.$eval( + "calcite-modal", + (elm: HTMLCalciteModalElement) => + (elm.beforeClose = (window as typeof window & Pick).beforeClose) + ); -it("should remain open with rejected 'beforeClose' promise'", async () => { - const page = await newE2EPage(); + const modal = await page.find("calcite-modal"); + modal.setProperty("open", false); + await page.waitForChanges(); - await page.exposeFunction("beforeClose", () => Promise.reject()); - await page.setContent(``); + expect(mockCallBack).toHaveBeenCalledTimes(1); + }); - await page.$eval( - "calcite-modal", - (elm: HTMLCalciteModalElement) => - (elm.beforeClose = (window as typeof window & Pick).beforeClose) - ); + it("should remain open with rejected 'beforeClose' promise'", async () => { + const page = await newE2EPage(); - const modal = await page.find("calcite-modal"); - modal.setProperty("open", false); - await page.waitForChanges(); + await page.exposeFunction("beforeClose", () => Promise.reject()); + await page.setContent(``); - expect(await modal.getProperty("open")).toBe(true); - expect(await modal.getProperty("opened")).toBe(true); - expect(modal.getAttribute("open")).toBe(""); // Makes sure attribute is added back -}); + await page.$eval( + "calcite-modal", + (elm: HTMLCalciteModalElement) => + (elm.beforeClose = (window as typeof window & Pick).beforeClose) + ); -describe("opening and closing behavior", () => { - it("opens and closes", async () => { - const page = await newE2EPage(); - await page.setContent(html``); const modal = await page.find("calcite-modal"); + modal.setProperty("open", false); + await page.waitForChanges(); - type ModalEventOrderWindow = GlobalTestProps<{ events: string[] }>; - - await page.$eval("calcite-modal", (modal: HTMLCalciteModalElement) => { - const receivedEvents: string[] = []; - (window as ModalEventOrderWindow).events = receivedEvents; + expect(await modal.getProperty("open")).toBe(true); + expect(await modal.getProperty("opened")).toBe(true); + expect(modal.getAttribute("open")).toBe(""); // Makes sure attribute is added back + }); - ["calciteModalBeforeOpen", "calciteModalOpen", "calciteModalBeforeClose", "calciteModalClose"].forEach( - (eventType) => { - modal.addEventListener(eventType, (event) => receivedEvents.push(event.type)); - } - ); - }); + describe("opening and closing behavior", () => { + it("opens and closes", async () => { + const page = await newE2EPage(); + await page.setContent(html``); + const modal = await page.find("calcite-modal"); - const beforeOpenSpy = await modal.spyOnEvent("calciteModalBeforeOpen"); - const openSpy = await modal.spyOnEvent("calciteModalOpen"); - const beforeCloseSpy = await modal.spyOnEvent("calciteModalBeforeClose"); - const closeSpy = await modal.spyOnEvent("calciteModalClose"); + type ModalEventOrderWindow = GlobalTestProps<{ events: string[] }>; - expect(beforeOpenSpy).toHaveReceivedEventTimes(0); - expect(openSpy).toHaveReceivedEventTimes(0); - expect(beforeCloseSpy).toHaveReceivedEventTimes(0); - expect(closeSpy).toHaveReceivedEventTimes(0); + await page.$eval("calcite-modal", (modal: HTMLCalciteModalElement) => { + const receivedEvents: string[] = []; + (window as ModalEventOrderWindow).events = receivedEvents; - expect(await modal.isVisible()).toBe(false); - - const modalBeforeOpen = page.waitForEvent("calciteModalBeforeOpen"); - const modalOpen = page.waitForEvent("calciteModalOpen"); - await modal.setProperty("open", true); - await page.waitForChanges(); + ["calciteModalBeforeOpen", "calciteModalOpen", "calciteModalBeforeClose", "calciteModalClose"].forEach( + (eventType) => { + modal.addEventListener(eventType, (event) => receivedEvents.push(event.type)); + } + ); + }); - await modalBeforeOpen; - await modalOpen; + const beforeOpenSpy = await modal.spyOnEvent("calciteModalBeforeOpen"); + const openSpy = await modal.spyOnEvent("calciteModalOpen"); + const beforeCloseSpy = await modal.spyOnEvent("calciteModalBeforeClose"); + const closeSpy = await modal.spyOnEvent("calciteModalClose"); - expect(beforeOpenSpy).toHaveReceivedEventTimes(1); - expect(openSpy).toHaveReceivedEventTimes(1); - expect(beforeCloseSpy).toHaveReceivedEventTimes(0); - expect(closeSpy).toHaveReceivedEventTimes(0); + expect(beforeOpenSpy).toHaveReceivedEventTimes(0); + expect(openSpy).toHaveReceivedEventTimes(0); + expect(beforeCloseSpy).toHaveReceivedEventTimes(0); + expect(closeSpy).toHaveReceivedEventTimes(0); - expect(await modal.isVisible()).toBe(true); + expect(await modal.isVisible()).toBe(false); - const modalBeforeClose = page.waitForEvent("calciteModalBeforeClose"); - const modalClose = page.waitForEvent("calciteModalClose"); - await modal.setProperty("open", false); - await page.waitForChanges(); + const modalBeforeOpen = page.waitForEvent("calciteModalBeforeOpen"); + const modalOpen = page.waitForEvent("calciteModalOpen"); + await modal.setProperty("open", true); + await page.waitForChanges(); - await modalBeforeClose; - await modalClose; + await modalBeforeOpen; + await modalOpen; - expect(beforeOpenSpy).toHaveReceivedEventTimes(1); - expect(openSpy).toHaveReceivedEventTimes(1); - expect(beforeCloseSpy).toHaveReceivedEventTimes(1); - expect(closeSpy).toHaveReceivedEventTimes(1); + expect(beforeOpenSpy).toHaveReceivedEventTimes(1); + expect(openSpy).toHaveReceivedEventTimes(1); + expect(beforeCloseSpy).toHaveReceivedEventTimes(0); + expect(closeSpy).toHaveReceivedEventTimes(0); - expect(await modal.isVisible()).toBe(false); + expect(await modal.isVisible()).toBe(true); - expect(await page.evaluate(() => (window as ModalEventOrderWindow).events)).toEqual([ - "calciteModalBeforeOpen", - "calciteModalOpen", - "calciteModalBeforeClose", - "calciteModalClose", - ]); - }); + const modalBeforeClose = page.waitForEvent("calciteModalBeforeClose"); + const modalClose = page.waitForEvent("calciteModalClose"); + await modal.setProperty("open", false); + await page.waitForChanges(); - it("emits when closing on click", async () => { - const page = await newE2EPage(); - await page.setContent(html``); - const modal = await page.find("calcite-modal"); + await modalBeforeClose; + await modalClose; - const beforeOpenSpy = await modal.spyOnEvent("calciteModalBeforeOpen"); - const openSpy = await modal.spyOnEvent("calciteModalOpen"); - const beforeCloseSpy = await modal.spyOnEvent("calciteModalBeforeClose"); - const closeSpy = await modal.spyOnEvent("calciteModalClose"); + expect(beforeOpenSpy).toHaveReceivedEventTimes(1); + expect(openSpy).toHaveReceivedEventTimes(1); + expect(beforeCloseSpy).toHaveReceivedEventTimes(1); + expect(closeSpy).toHaveReceivedEventTimes(1); - expect(beforeOpenSpy).toHaveReceivedEventTimes(0); - expect(openSpy).toHaveReceivedEventTimes(0); - expect(beforeCloseSpy).toHaveReceivedEventTimes(0); - expect(closeSpy).toHaveReceivedEventTimes(0); + expect(await modal.isVisible()).toBe(false); - expect(await modal.isVisible()).toBe(false); + expect(await page.evaluate(() => (window as ModalEventOrderWindow).events)).toEqual([ + "calciteModalBeforeOpen", + "calciteModalOpen", + "calciteModalBeforeClose", + "calciteModalClose", + ]); + }); - const modalBeforeOpen = page.waitForEvent("calciteModalBeforeOpen"); - const modalOpen = page.waitForEvent("calciteModalOpen"); - modal.setProperty("open", true); - await page.waitForChanges(); + it("emits when closing on click", async () => { + const page = await newE2EPage(); + await page.setContent(html``); + const modal = await page.find("calcite-modal"); - await modalBeforeOpen; - await modalOpen; + const beforeOpenSpy = await modal.spyOnEvent("calciteModalBeforeOpen"); + const openSpy = await modal.spyOnEvent("calciteModalOpen"); + const beforeCloseSpy = await modal.spyOnEvent("calciteModalBeforeClose"); + const closeSpy = await modal.spyOnEvent("calciteModalClose"); - expect(beforeOpenSpy).toHaveReceivedEventTimes(1); - expect(openSpy).toHaveReceivedEventTimes(1); - expect(beforeCloseSpy).toHaveReceivedEventTimes(0); - expect(closeSpy).toHaveReceivedEventTimes(0); + expect(beforeOpenSpy).toHaveReceivedEventTimes(0); + expect(openSpy).toHaveReceivedEventTimes(0); + expect(beforeCloseSpy).toHaveReceivedEventTimes(0); + expect(closeSpy).toHaveReceivedEventTimes(0); - expect(await modal.isVisible()).toBe(true); + expect(await modal.isVisible()).toBe(false); - const modalBeforeClose = page.waitForEvent("calciteModalBeforeClose"); - const modalClose = page.waitForEvent("calciteModalClose"); - const closeButton = await page.find(`calcite-modal >>> .${CSS.close}`); - await closeButton.click(); - await page.waitForChanges(); + const modalBeforeOpen = page.waitForEvent("calciteModalBeforeOpen"); + const modalOpen = page.waitForEvent("calciteModalOpen"); + modal.setProperty("open", true); + await page.waitForChanges(); - await modalBeforeClose; - await modalClose; + await modalBeforeOpen; + await modalOpen; - expect(beforeOpenSpy).toHaveReceivedEventTimes(1); - expect(openSpy).toHaveReceivedEventTimes(1); - expect(beforeCloseSpy).toHaveReceivedEventTimes(1); - expect(closeSpy).toHaveReceivedEventTimes(1); + expect(beforeOpenSpy).toHaveReceivedEventTimes(1); + expect(openSpy).toHaveReceivedEventTimes(1); + expect(beforeCloseSpy).toHaveReceivedEventTimes(0); + expect(closeSpy).toHaveReceivedEventTimes(0); - expect(await modal.isVisible()).toBe(false); - }); + expect(await modal.isVisible()).toBe(true); - it("emits when set to open on initial render", async () => { - const page = await newProgrammaticE2EPage(); + const modalBeforeClose = page.waitForEvent("calciteModalBeforeClose"); + const modalClose = page.waitForEvent("calciteModalClose"); + const closeButton = await page.find(`calcite-modal >>> .${CSS.close}`); + await closeButton.click(); + await page.waitForChanges(); - const beforeOpenSpy = await page.spyOnEvent("calciteModalBeforeOpen"); - const openSpy = await page.spyOnEvent("calciteModalOpen"); + await modalBeforeClose; + await modalClose; - const waitForBeforeOpenEvent = page.waitForEvent("calciteModalBeforeOpen"); - const waitForOpenEvent = page.waitForEvent("calciteModalOpen"); + expect(beforeOpenSpy).toHaveReceivedEventTimes(1); + expect(openSpy).toHaveReceivedEventTimes(1); + expect(beforeCloseSpy).toHaveReceivedEventTimes(1); + expect(closeSpy).toHaveReceivedEventTimes(1); - await page.evaluate((): void => { - const modal = document.createElement("calcite-modal"); - modal.open = true; - document.body.append(modal); + expect(await modal.isVisible()).toBe(false); }); - await page.waitForChanges(); - await waitForBeforeOpenEvent; - await waitForOpenEvent; + it("emits when set to open on initial render", async () => { + const page = await newProgrammaticE2EPage(); - expect(beforeOpenSpy).toHaveReceivedEventTimes(1); - expect(openSpy).toHaveReceivedEventTimes(1); - }); + const beforeOpenSpy = await page.spyOnEvent("calciteModalBeforeOpen"); + const openSpy = await page.spyOnEvent("calciteModalOpen"); - it("emits when set to open on initial render and duration is 0", async () => { - const page = await newProgrammaticE2EPage(); - await skipAnimations(page); + const waitForBeforeOpenEvent = page.waitForEvent("calciteModalBeforeOpen"); + const waitForOpenEvent = page.waitForEvent("calciteModalOpen"); - const beforeOpenSpy = await page.spyOnEvent("calciteModalBeforeOpen"); - const openSpy = await page.spyOnEvent("calciteModalOpen"); + await page.evaluate((): void => { + const modal = document.createElement("calcite-modal"); + modal.open = true; + document.body.append(modal); + }); - const waitForOpenEvent = page.waitForEvent("calciteModalOpen"); - const waitForBeforeOpenEvent = page.waitForEvent("calciteModalBeforeOpen"); + await page.waitForChanges(); + await waitForBeforeOpenEvent; + await waitForOpenEvent; - await page.evaluate((): void => { - const modal = document.createElement("calcite-modal"); - modal.open = true; - document.body.append(modal); + expect(beforeOpenSpy).toHaveReceivedEventTimes(1); + expect(openSpy).toHaveReceivedEventTimes(1); }); - await page.waitForChanges(); - await waitForBeforeOpenEvent; - await waitForOpenEvent; + it("emits when set to open on initial render and duration is 0", async () => { + const page = await newProgrammaticE2EPage(); + await skipAnimations(page); - expect(beforeOpenSpy).toHaveReceivedEventTimes(1); - expect(openSpy).toHaveReceivedEventTimes(1); - }); + const beforeOpenSpy = await page.spyOnEvent("calciteModalBeforeOpen"); + const openSpy = await page.spyOnEvent("calciteModalOpen"); - it("emits when duration is set to 0", async () => { - const page = await newProgrammaticE2EPage(); - await skipAnimations(page); + const waitForOpenEvent = page.waitForEvent("calciteModalOpen"); + const waitForBeforeOpenEvent = page.waitForEvent("calciteModalBeforeOpen"); - const beforeOpenSpy = await page.spyOnEvent("calciteModalBeforeOpen"); - const openSpy = await page.spyOnEvent("calciteModalOpen"); + await page.evaluate((): void => { + const modal = document.createElement("calcite-modal"); + modal.open = true; + document.body.append(modal); + }); - const beforeCloseSpy = await page.spyOnEvent("calciteModalBeforeClose"); - const closeSpy = await page.spyOnEvent("calciteModalClose"); + await page.waitForChanges(); + await waitForBeforeOpenEvent; + await waitForOpenEvent; - await page.evaluate((): void => { - const modal = document.createElement("calcite-modal"); - modal.open = true; - document.body.append(modal); + expect(beforeOpenSpy).toHaveReceivedEventTimes(1); + expect(openSpy).toHaveReceivedEventTimes(1); }); - await page.waitForChanges(); - await beforeOpenSpy; - await openSpy; - - expect(beforeOpenSpy).toHaveReceivedEventTimes(1); - expect(openSpy).toHaveReceivedEventTimes(1); + it("emits when duration is set to 0", async () => { + const page = await newProgrammaticE2EPage(); + await skipAnimations(page); - await page.evaluate(() => { - const modal = document.querySelector("calcite-modal"); - modal.open = false; - }); + const beforeOpenSpy = await page.spyOnEvent("calciteModalBeforeOpen"); + const openSpy = await page.spyOnEvent("calciteModalOpen"); - await page.waitForChanges(); - await beforeCloseSpy; - await closeSpy; + const beforeCloseSpy = await page.spyOnEvent("calciteModalBeforeClose"); + const closeSpy = await page.spyOnEvent("calciteModalClose"); - expect(beforeCloseSpy).toHaveReceivedEventTimes(1); - expect(closeSpy).toHaveReceivedEventTimes(1); - }); -}); + await page.evaluate((): void => { + const modal = document.createElement("calcite-modal"); + modal.open = true; + document.body.append(modal); + }); -describe("calcite-modal accessibility checks", () => { - it("traps focus within the modal when open", async () => { - const button1Id = "button1"; - const button2Id = "button2"; - const page = await newE2EPage(); - await page.setContent( - html` -
    - - -
    -
    ` - ); - const modal = await page.find("calcite-modal"); - const opened = page.waitForEvent("calciteModalOpen"); - modal.setProperty("open", true); - await page.waitForChanges(); - await opened; + await page.waitForChanges(); + await beforeOpenSpy; + await openSpy; - expect(await isElementFocused(page, `.${CSS.close}`, { shadowed: true })).toBe(true); - await page.keyboard.press("Tab"); - expect(await isElementFocused(page, `#${button1Id}`)).toBe(true); - await page.keyboard.press("Tab"); - expect(await isElementFocused(page, `#${button2Id}`)).toBe(true); + expect(beforeOpenSpy).toHaveReceivedEventTimes(1); + expect(openSpy).toHaveReceivedEventTimes(1); - await page.keyboard.press("Tab"); - expect(await isElementFocused(page, `.${CSS.close}`, { shadowed: true })).toBe(true); - await page.keyboard.down("Shift"); - await page.keyboard.press("Tab"); - expect(await isElementFocused(page, `#${button2Id}`)).toBe(true); + await page.evaluate(() => { + const modal = document.querySelector("calcite-modal"); + modal.open = false; + }); - await page.keyboard.press("Tab"); - expect(await isElementFocused(page, `#${button1Id}`)).toBe(true); - }); + await page.waitForChanges(); + await beforeCloseSpy; + await closeSpy; - it("restores focus to previously focused element when closed", async () => { - const initiallyFocusedId = "initially-focused"; - const initiallyFocusedIdSelector = `#${initiallyFocusedId}`; - const page = await newE2EPage(); - await page.setContent( - html` - - - ` - ); - await skipAnimations(page); - const modal = await page.find("calcite-modal"); - await page.$eval(initiallyFocusedIdSelector, (button: HTMLButtonElement) => { - button.focus(); + expect(beforeCloseSpy).toHaveReceivedEventTimes(1); + expect(closeSpy).toHaveReceivedEventTimes(1); }); - await modal.setProperty("open", true); - await page.waitForChanges(); - await modal.setProperty("open", false); - await page.waitForChanges(); - expect(await isElementFocused(page, initiallyFocusedIdSelector)).toBe(true); }); - it("traps focus within the modal when open and disabled close button", async () => { - const button1Id = "button1"; - const button2Id = "button2"; - const page = await newE2EPage(); - await page.setContent( - html` -
    - - -
    -
    ` - ); - await skipAnimations(page); - const modal = await page.find("calcite-modal"); - - await modal.setProperty("open", true); - await page.waitForChanges(); - expect(await isElementFocused(page, `#${button1Id}`)).toBe(true); + describe("calcite-modal accessibility checks", () => { + it("traps focus within the modal when open", async () => { + const button1Id = "button1"; + const button2Id = "button2"; + const page = await newE2EPage(); + await page.setContent( + html` +
    + + +
    +
    ` + ); + const modal = await page.find("calcite-modal"); + const opened = page.waitForEvent("calciteModalOpen"); + modal.setProperty("open", true); + await page.waitForChanges(); + await opened; + + expect(await isElementFocused(page, `.${CSS.close}`, { shadowed: true })).toBe(true); + await page.keyboard.press("Tab"); + expect(await isElementFocused(page, `#${button1Id}`)).toBe(true); + await page.keyboard.press("Tab"); + expect(await isElementFocused(page, `#${button2Id}`)).toBe(true); + + await page.keyboard.press("Tab"); + expect(await isElementFocused(page, `.${CSS.close}`, { shadowed: true })).toBe(true); + await page.keyboard.down("Shift"); + await page.keyboard.press("Tab"); + expect(await isElementFocused(page, `#${button2Id}`)).toBe(true); + + await page.keyboard.press("Tab"); + expect(await isElementFocused(page, `#${button1Id}`)).toBe(true); + }); - await page.keyboard.press("Tab"); - expect(await isElementFocused(page, `#${button2Id}`)).toBe(true); + it("restores focus to previously focused element when closed", async () => { + const initiallyFocusedId = "initially-focused"; + const initiallyFocusedIdSelector = `#${initiallyFocusedId}`; + const page = await newE2EPage(); + await page.setContent( + html` + + + ` + ); + await skipAnimations(page); + const modal = await page.find("calcite-modal"); + await page.$eval(initiallyFocusedIdSelector, (button: HTMLButtonElement) => { + button.focus(); + }); + await modal.setProperty("open", true); + await page.waitForChanges(); + await modal.setProperty("open", false); + await page.waitForChanges(); + expect(await isElementFocused(page, initiallyFocusedIdSelector)).toBe(true); + }); - await page.keyboard.press("Tab"); - expect(await isElementFocused(page, `#${button1Id}`)).toBe(true); - await page.keyboard.down("Shift"); - await page.keyboard.press("Tab"); - expect(await isElementFocused(page, `#${button2Id}`)).toBe(true); - await page.keyboard.press("Tab"); - expect(await isElementFocused(page, `#${button1Id}`)).toBe(true); + it("traps focus within the modal when open and disabled close button", async () => { + const button1Id = "button1"; + const button2Id = "button2"; + const page = await newE2EPage(); + await page.setContent( + html` +
    + + +
    +
    ` + ); + await skipAnimations(page); + const modal = await page.find("calcite-modal"); + + await modal.setProperty("open", true); + await page.waitForChanges(); + expect(await isElementFocused(page, `#${button1Id}`)).toBe(true); + + await page.keyboard.press("Tab"); + expect(await isElementFocused(page, `#${button2Id}`)).toBe(true); + + await page.keyboard.press("Tab"); + expect(await isElementFocused(page, `#${button1Id}`)).toBe(true); + await page.keyboard.down("Shift"); + await page.keyboard.press("Tab"); + expect(await isElementFocused(page, `#${button2Id}`)).toBe(true); + await page.keyboard.press("Tab"); + expect(await isElementFocused(page, `#${button1Id}`)).toBe(true); + }); }); describe("setFocus", () => { @@ -595,7 +599,7 @@ describe("calcite-modal accessibility checks", () => { it("closes and allows re-opening when Close button is clicked", async () => { const page = await newE2EPage(); - await page.setContent(``); + await page.setContent(``); await skipAnimations(page); const modal = await page.find("calcite-modal"); modal.setProperty("open", true); @@ -647,42 +651,102 @@ describe("calcite-modal accessibility checks", () => { expect(modal).toHaveAttribute("open"); }); - it("correctly adds overflow class on document when open", async () => { - const page = await newE2EPage(); - await page.setContent(``); - const modal = await page.find("calcite-modal"); - await modal.setProperty("open", true); - await page.waitForChanges(); - const isOverflowHidden = await page.evaluate(() => { - return document.documentElement.style.overflow === "hidden"; + describe("overflow prevention", () => { + async function hasOverflowStyle(page: E2EPage): Promise { + return page.evaluate(() => document.documentElement.style.overflow === "hidden"); + } + + it("correctly sets overflow style on document when opened/closed", async () => { + const page = await newE2EPage(); + await page.setContent(``); + const modal = await page.find("calcite-modal"); + + await modal.setProperty("open", true); + await page.waitForChanges(); + + expect(await hasOverflowStyle(page)).toEqual(true); + + await modal.setProperty("open", false); + await page.waitForChanges(); + + expect(await hasOverflowStyle(page)).toEqual(false); }); - expect(isOverflowHidden).toEqual(true); - }); - it("correctly does not add overflow class on document when open and slotted in shell modals slot", async () => { - const page = await newE2EPage(); - await page.setContent(``); - const modal = await page.find("calcite-modal"); - await modal.setProperty("open", true); - await page.waitForChanges(); - const isOverflowHidden = await page.evaluate(() => { - return document.documentElement.style.overflow === "hidden"; + it("preserves existing overflow style when modal is opened/closed", async () => { + const page = await newE2EPage(); + await page.setContent(``); + await page.evaluate(() => (document.documentElement.style.overflow = "scroll")); + const modal = await page.find("calcite-modal"); + + await modal.setProperty("open", true); + await page.waitForChanges(); + + expect(await hasOverflowStyle(page)).toEqual(true); + + await modal.setProperty("open", false); + await page.waitForChanges(); + + expect(await page.evaluate(() => document.documentElement.style.overflow)).toEqual("scroll"); }); - expect(isOverflowHidden).toEqual(false); - }); - it("correctly removes overflow class on document once closed", async () => { - const page = await newE2EPage(); - await page.setContent(``); - const modal = await page.find("calcite-modal"); - await modal.setProperty("open", true); - await page.waitForChanges(); - await modal.setProperty("open", false); - await page.waitForChanges(); - const documentClass = await page.evaluate(() => { - return document.documentElement.classList.contains("overflow-hidden"); + it("correctly does not add overflow style on document when open and slotted in shell modals slot", async () => { + const page = await newE2EPage(); + await page.setContent(``); + const modal = await page.find("calcite-modal"); + + await modal.setProperty("open", true); + await page.waitForChanges(); + + expect(await hasOverflowStyle(page)).toEqual(false); + }); + + it("correctly removes overflow style on document when multiple modals are closed in first-in-last-out order", async () => { + const page = await newE2EPage(); + await page.setContent(html` + + + `); + const modal1 = await page.find("#modal-1"); + const modal2 = await page.find("#modal-2"); + + await modal1.setProperty("open", true); + await page.waitForChanges(); + await modal2.setProperty("open", true); + await page.waitForChanges(); + + expect(await hasOverflowStyle(page)).toEqual(true); + + await modal2.setProperty("open", false); + await page.waitForChanges(); + await modal1.setProperty("open", false); + await page.waitForChanges(); + + expect(await hasOverflowStyle(page)).toEqual(false); + }); + + it("correctly removes overflow style on document when multiple modals are closed in first-in-first-out order", async () => { + const page = await newE2EPage(); + await page.setContent(html` + + + `); + const modal1 = await page.find("#modal-1"); + const modal2 = await page.find("#modal-2"); + + await modal1.setProperty("open", true); + await page.waitForChanges(); + await modal2.setProperty("open", true); + await page.waitForChanges(); + + expect(await hasOverflowStyle(page)).toEqual(true); + + await modal1.setProperty("open", false); + await page.waitForChanges(); + await modal2.setProperty("open", false); + await page.waitForChanges(); + + expect(await hasOverflowStyle(page)).toEqual(false); }); - expect(documentClass).toEqual(false); }); it("renders correctly with no footer", async () => { @@ -762,8 +826,4 @@ describe("calcite-modal accessibility checks", () => { closeIcon = await page.find('calcite-modal >>> calcite-icon[scale="m"]'); expect(closeIcon).not.toBe(null); }); - - describe("translation support", () => { - t9n("calcite-modal"); - }); }); diff --git a/packages/calcite-components/src/components/modal/modal.tsx b/packages/calcite-components/src/components/modal/modal.tsx index e05d3b1d1d2..e5b0877592c 100644 --- a/packages/calcite-components/src/components/modal/modal.tsx +++ b/packages/calcite-components/src/components/modal/modal.tsx @@ -54,6 +54,9 @@ import { ModalMessages } from "./assets/modal/t9n"; import { getIconScale } from "../../utils/component"; +let totalOpenModals: number = 0; +let initialDocumentOverflowStyle: string = ""; + /** * @slot header - A slot for adding header text. * @slot content - A slot for adding the component's content. @@ -539,7 +542,11 @@ export class Modal this.contentId = ensureId(contentEl); if (!this.slottedInShell) { - this.initialOverflowCSS = document.documentElement.style.overflow; + if (totalOpenModals === 0) { + initialDocumentOverflowStyle = document.documentElement.style.overflow; + } + + totalOpenModals++; // use an inline style instead of a utility class to avoid global class declarations. document.documentElement.style.setProperty("overflow", "hidden"); } @@ -568,12 +575,13 @@ export class Modal } } + totalOpenModals--; this.opened = false; this.removeOverflowHiddenClass(); }; private removeOverflowHiddenClass(): void { - document.documentElement.style.setProperty("overflow", this.initialOverflowCSS); + document.documentElement.style.setProperty("overflow", initialDocumentOverflowStyle); } private handleMutationObserver = (): void => { diff --git a/packages/calcite-components/src/components/popover/popover.tsx b/packages/calcite-components/src/components/popover/popover.tsx index a00109a3d9c..e3cc9098cd5 100644 --- a/packages/calcite-components/src/components/popover/popover.tsx +++ b/packages/calcite-components/src/components/popover/popover.tsx @@ -194,7 +194,7 @@ export class Popover @Watch("open") openHandler(): void { onToggleOpenCloseComponent(this); - + this.reposition(true); this.setExpandedAttr(); } @@ -499,7 +499,6 @@ export class Popover }; onBeforeOpen(): void { - this.reposition(true); this.calcitePopoverBeforeOpen.emit(); } @@ -515,7 +514,6 @@ export class Popover onClose(): void { this.calcitePopoverClose.emit(); deactivateFocusTrap(this); - this.reposition(true); } storeArrowEl = (el: SVGElement): void => { diff --git a/packages/calcite-components/src/components/scrim/usage/Basic.md b/packages/calcite-components/src/components/scrim/usage/Basic.md index f648a7d74e1..9bb4945d880 100644 --- a/packages/calcite-components/src/components/scrim/usage/Basic.md +++ b/packages/calcite-components/src/components/scrim/usage/Basic.md @@ -1,12 +1,33 @@ ```html -
    +

    I'm a panel that is not loading.

    -

    This content can have any zIndex and it will not be placed above

    -

    .

    -

    .

    -

    .

    -

    .

    +

    The content below can have any zIndex and it will not be placed above.

    +
    +

    + Lorem ipsum dolor sit amet consectetur adipisicing elit. Fugit libero sint eveniet suscipit voluptatibus esse + neque ipsa cum placeat sequi deserunt hic facere sunt quisquam nostrum itaque officia, labore maiores obcaecati + repudiandae rerum! Debitis, delectus enim, dignissimos excepturi, accusantium ullam aspernatur quae numquam optio + porro laudantium. A eaque accusantium quo? +

    +
      +
    • + Lorem ipsum dolor, sit amet consectetur adipisicing elit. Sit ipsum vitae doloribus praesentium numquam iure + harum, sequi quibusdam at odio. +
    • +
    • + Lorem, ipsum dolor sit amet consectetur adipisicing elit. Nesciunt at aliquam suscipit nostrum, nulla dolor sunt + eum, quasi tenetur similique voluptatem corrupti neque voluptatum sint! +
    • +
    • + Lorem ipsum dolor sit amet consectetur adipisicing elit. Nam corporis quos, dolorem veritatis aliquid aut nihil + sint velit obcaecati praesentium? +
    • +
    +
    ``` diff --git a/packages/calcite-components/src/components/scrim/usage/Loading-scrim-panel.md b/packages/calcite-components/src/components/scrim/usage/Loading-scrim-panel.md index bbb0f5095f3..8adce8b3548 100644 --- a/packages/calcite-components/src/components/scrim/usage/Loading-scrim-panel.md +++ b/packages/calcite-components/src/components/scrim/usage/Loading-scrim-panel.md @@ -1,12 +1,30 @@ ```html -
    - -

    I'm a panel that is not loading.

    -

    I have a loading spinner over my content.

    -

    .

    -

    .

    -

    .

    -

    .

    -
    +
    + Loading +
    +

    + Lorem ipsum dolor sit amet consectetur adipisicing elit. Fugit libero sint eveniet suscipit voluptatibus esse + neque ipsa cum placeat sequi deserunt hic facere sunt quisquam nostrum itaque officia, labore maiores obcaecati + repudiandae rerum! Debitis, delectus enim, dignissimos excepturi, accusantium ullam aspernatur quae numquam optio + porro laudantium. A eaque accusantium quo? +

    +
      +
    • + Lorem ipsum dolor, sit amet consectetur adipisicing elit. Sit ipsum vitae doloribus praesentium numquam iure + harum, sequi quibusdam at odio. +
    • +
    • + Lorem, ipsum dolor sit amet consectetur adipisicing elit. Nesciunt at aliquam suscipit nostrum, nulla dolor sunt + eum, quasi tenetur similique voluptatem corrupti neque voluptatum sint! +
    • +
    • + Lorem ipsum dolor sit amet consectetur adipisicing elit. Nam corporis quos, dolorem veritatis aliquid aut nihil + sint velit obcaecati praesentium? +
    • +
    +
    ``` diff --git a/packages/calcite-components/src/components/shell-panel/usage/With-custom-element.md b/packages/calcite-components/src/components/shell-panel/usage/With-custom-element.md index 887158714a7..453c06cf22c 100644 --- a/packages/calcite-components/src/components/shell-panel/usage/With-custom-element.md +++ b/packages/calcite-components/src/components/shell-panel/usage/With-custom-element.md @@ -8,7 +8,7 @@ Add `calcite-match-height` to a wrapping element to ensure proper height, scroll - ... + ``` diff --git a/packages/calcite-components/src/components/shell-panel/usage/With-flow.md b/packages/calcite-components/src/components/shell-panel/usage/With-flow.md index 156b4fcb2c9..89eceb22efb 100644 --- a/packages/calcite-components/src/components/shell-panel/usage/With-flow.md +++ b/packages/calcite-components/src/components/shell-panel/usage/With-flow.md @@ -6,8 +6,8 @@ - ... - ... + + ``` diff --git a/packages/calcite-components/src/components/shell-panel/usage/With-panel.md b/packages/calcite-components/src/components/shell-panel/usage/With-panel.md index 385bfcb3177..819170a6081 100644 --- a/packages/calcite-components/src/components/shell-panel/usage/With-panel.md +++ b/packages/calcite-components/src/components/shell-panel/usage/With-panel.md @@ -5,6 +5,6 @@ - ... + ``` diff --git a/packages/calcite-components/src/components/shell/usage/Advanced.md b/packages/calcite-components/src/components/shell/usage/Advanced.md index 4b0fe649805..d3d659467e9 100644 --- a/packages/calcite-components/src/components/shell/usage/Advanced.md +++ b/packages/calcite-components/src/components/shell/usage/Advanced.md @@ -9,61 +9,79 @@ Renders a shell with leading and trailing floating panels, action bar/pad, block - - - - - + - - - + + + - + -

    Cool thing.

    + + +
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + +

    + Lorem, ipsum dolor sit amet consectetur adipisicing elit. Fugiat, reiciendis est quisquam dolor deserunt saepe + corrupti temporibus a totam adipisci accusantium ex non quidem et veritatis asperiores molestias eligendi + provident magni nostrum, vero, laboriosam cupiditate! +

    +
    -
    Footer
    +
    + + + + + + +
    ``` diff --git a/packages/calcite-components/src/components/shell/usage/With-panels.md b/packages/calcite-components/src/components/shell/usage/With-panels.md index 4cba3fe15f7..cc1c5402da7 100644 --- a/packages/calcite-components/src/components/shell/usage/With-panels.md +++ b/packages/calcite-components/src/components/shell/usage/With-panels.md @@ -2,18 +2,37 @@ Renders a shell with a header and panels on the left and right sides of the app. ```html - - Leading panel! (on the left side, since this is a LTR app) - - Trailing panel! (right side) - - Center Row! (center bottom) -

    Shell Header: My App

    + + + + + + + + + + + + + + + + + + + + + + + + + +

    Shell Content

    diff --git a/packages/calcite-components/src/components/split-button/usage/Basic.md b/packages/calcite-components/src/components/split-button/usage/Basic.md index 92d2d0f1eb9..ce03023a9de 100644 --- a/packages/calcite-components/src/components/split-button/usage/Basic.md +++ b/packages/calcite-components/src/components/split-button/usage/Basic.md @@ -1,9 +1,9 @@ ```html - + - Option 2 - Option 3 - Option 4 + Trails + Lakes + Rivers ``` diff --git a/packages/calcite-components/src/components/stack/readme.md b/packages/calcite-components/src/components/stack/readme.md index 1398d8ac883..45a2adaee9b 100644 --- a/packages/calcite-components/src/components/stack/readme.md +++ b/packages/calcite-components/src/components/stack/readme.md @@ -11,7 +11,7 @@ My great chip Hello World - + ``` @@ -22,7 +22,7 @@ Hello World - + My great chip diff --git a/packages/calcite-components/src/components/stack/usage/Basic.md b/packages/calcite-components/src/components/stack/usage/Basic.md index b3d65047608..4c3f3017ff0 100644 --- a/packages/calcite-components/src/components/stack/usage/Basic.md +++ b/packages/calcite-components/src/components/stack/usage/Basic.md @@ -3,7 +3,7 @@ My great chip Hello World - + ``` diff --git a/packages/calcite-components/src/components/stack/usage/Disabled.md b/packages/calcite-components/src/components/stack/usage/Disabled.md index efee3991545..f42a472b8c7 100644 --- a/packages/calcite-components/src/components/stack/usage/Disabled.md +++ b/packages/calcite-components/src/components/stack/usage/Disabled.md @@ -2,7 +2,7 @@ Hello World - + My great chip diff --git a/packages/calcite-components/src/components/stepper/stepper.e2e.ts b/packages/calcite-components/src/components/stepper/stepper.e2e.ts index c37cc28a9c1..cc6539013ad 100644 --- a/packages/calcite-components/src/components/stepper/stepper.e2e.ts +++ b/packages/calcite-components/src/components/stepper/stepper.e2e.ts @@ -798,10 +798,10 @@ describe("calcite-stepper", () => { it("should emit calciteStepperItemChange on user interaction", async () => { const page = await newE2EPage(); await page.setContent(html` - +
    Step 1 content
    - +
    Step 2 content
    @@ -811,27 +811,26 @@ describe("calcite-stepper", () => { const stepper = await page.find("calcite-stepper"); const [actionStart, actionEnd] = await page.findAll("calcite-stepper >>> calcite-action"); - const [stepperItem1] = await page.findAll("calcite-stepper-item"); const eventSpy = await stepper.spyOnEvent("calciteStepperItemChange"); expect(eventSpy).toHaveReceivedEventTimes(0); + // shouldn't emit change event when disabled element is visible await actionEnd.click(); await page.waitForChanges(); - expect(eventSpy).toHaveReceivedEventTimes(1); + expect(eventSpy).toHaveReceivedEventTimes(0); - await actionStart.click(); + await actionEnd.click(); await page.waitForChanges(); - expect(eventSpy).toHaveReceivedEventTimes(2); + expect(eventSpy).toHaveReceivedEventTimes(1); // shouldn't emit change event when disabled element is visible - stepperItem1.setProperty("disabled", true); await actionStart.click(); await page.waitForChanges(); - expect(eventSpy).toHaveReceivedEventTimes(2); + expect(eventSpy).toHaveReceivedEventTimes(1); - await actionEnd.click(); + await actionStart.click(); await page.waitForChanges(); - expect(eventSpy).toHaveReceivedEventTimes(3); + expect(eventSpy).toHaveReceivedEventTimes(2); }); }); }); diff --git a/packages/calcite-components/src/components/stepper/stepper.tsx b/packages/calcite-components/src/components/stepper/stepper.tsx index a2805837f08..625ca1dba4d 100644 --- a/packages/calcite-components/src/components/stepper/stepper.tsx +++ b/packages/calcite-components/src/components/stepper/stepper.tsx @@ -118,8 +118,7 @@ export class Stepper implements LocalizedComponent, T9nComponent { * Fires when the active `calcite-stepper-item` changes. * */ - @Event({ cancelable: false }) - calciteStepperItemChange: EventEmitter; + @Event({ cancelable: false }) calciteStepperItemChange: EventEmitter; /** * Fires when the active `calcite-stepper-item` changes. @@ -242,7 +241,6 @@ export class Stepper implements LocalizedComponent, T9nComponent { @Listen("calciteInternalStepperItemSelect") updateItem(event: CustomEvent): void { const { position } = event.detail; - if (typeof position === "number") { this.currentActivePosition = position; this.selectedItem = event.target as HTMLCalciteStepperItemElement; @@ -506,7 +504,7 @@ export class Stepper implements LocalizedComponent, T9nComponent { } if ( - this.currentActivePosition && + typeof this.currentActivePosition === "number" && currentActivePosition !== this.currentActivePosition && !this.items[this.currentActivePosition].disabled ) { diff --git a/packages/calcite-components/src/components/stepper/usage/Basic.md b/packages/calcite-components/src/components/stepper/usage/Basic.md index 443b1409e17..7db2e28a814 100644 --- a/packages/calcite-components/src/components/stepper/usage/Basic.md +++ b/packages/calcite-components/src/components/stepper/usage/Basic.md @@ -1,14 +1,34 @@ ```html - - Step 1 Content Goes Here + + +
    + In this step, choose a group from the list to make changes. Make sure to select the right one for your updates. +
    +
    - Step 2 Content Goes Here - - Step 3 Content Goes Here + + +
    + Now, compile the member list. Add or remove members as needed. Ensure the list is accurate before proceeding to + the next step. +
    +
    - - Step 4 Content Goes Here + + +
    + In this step, set individual properties for each member. Customize their details to meet your requirements. +
    +
    +
    + + +
    + Review the changes you've made in the previous steps. Once confirmed, proceed to complete the process. This step + is currently disabled. +
    +
    ``` diff --git a/packages/calcite-components/src/components/switch/usage/Basic.md b/packages/calcite-components/src/components/switch/usage/Basic.md index 5a3f7951db5..225663c12d9 100644 --- a/packages/calcite-components/src/components/switch/usage/Basic.md +++ b/packages/calcite-components/src/components/switch/usage/Basic.md @@ -1,3 +1,7 @@ ```html - + ``` diff --git a/packages/calcite-components/src/components/tab/tab.scss b/packages/calcite-components/src/components/tab/tab.scss index 1a794bcdf7b..0877bde5694 100644 --- a/packages/calcite-components/src/components/tab/tab.scss +++ b/packages/calcite-components/src/components/tab/tab.scss @@ -13,6 +13,10 @@ @apply block h-full w-full overflow-auto; } +.content { + @apply box-border; +} + .scale-s .content { @apply text-n2h py-1; } diff --git a/packages/calcite-components/src/components/table-cell/table-cell.scss b/packages/calcite-components/src/components/table-cell/table-cell.scss index c8f1206a6ec..493332b12ba 100644 --- a/packages/calcite-components/src/components/table-cell/table-cell.scss +++ b/packages/calcite-components/src/components/table-cell/table-cell.scss @@ -4,12 +4,10 @@ * These properties can be overridden using the component's tag as selector. * * @prop --calcite-table-cell-background: Specifies the background color of the component. - * @prop --calcite-table-cell-border-color: Specifies the border color of the component. */ :host { - --calcite-internal-table-cell-background-internal: var(--calcite-table-cell-background, transparent); - --calcite-internal-table-cell-border-color-internal: var(--calcite-table-cell-border-color, transparent); + --calcite-internal-table-cell-background: var(--calcite-table-cell-background, transparent); @apply contents; } @@ -58,8 +56,7 @@ td { } .selected-cell:not(.number-cell):not(.footer-cell) { - --calcite-table-cell-background: var(--calcite-color-foreground-current); - background: var(--calcite-color-foreground-current); + --calcite-internal-table-cell-background: var(--calcite-color-foreground-current); } .selection-cell.selected-cell { diff --git a/packages/calcite-components/src/components/table/interfaces.ts b/packages/calcite-components/src/components/table/interfaces.ts index 90f24e94c7f..96a7a7e9fbd 100644 --- a/packages/calcite-components/src/components/table/interfaces.ts +++ b/packages/calcite-components/src/components/table/interfaces.ts @@ -9,6 +9,4 @@ export interface TableRowFocusEvent { export type RowType = "head" | "body" | "foot"; -export type TableAppearance = "bordered" | "simple" | "bordered-zebra" | "simple-zebra"; - export type TableLayout = "auto" | "fixed"; diff --git a/packages/calcite-components/src/components/table/resources.ts b/packages/calcite-components/src/components/table/resources.ts index 93646dda10f..7b5eb0af9e0 100644 --- a/packages/calcite-components/src/components/table/resources.ts +++ b/packages/calcite-components/src/components/table/resources.ts @@ -1,6 +1,6 @@ export const CSS = { bordered: "bordered", - zebra: "zebra", + striped: "striped", selectionArea: "selection-area", paginationArea: "pagination-area", container: "container", diff --git a/packages/calcite-components/src/components/table/table.e2e.ts b/packages/calcite-components/src/components/table/table.e2e.ts index d50d1e7e011..bcf88a8e5b1 100644 --- a/packages/calcite-components/src/components/table/table.e2e.ts +++ b/packages/calcite-components/src/components/table/table.e2e.ts @@ -62,7 +62,7 @@ describe("calcite-table", () => { defaultValue: "none", }, { - propertyName: "zebra", + propertyName: "striped", defaultValue: false, }, ]); diff --git a/packages/calcite-components/src/components/table/table.scss b/packages/calcite-components/src/components/table/table.scss index 48c20fc0a76..00c83d0695f 100644 --- a/packages/calcite-components/src/components/table/table.scss +++ b/packages/calcite-components/src/components/table/table.scss @@ -57,7 +57,7 @@ tbody { } } -.zebra { +.striped { ::slotted(calcite-table-row:nth-child(2n + 1)) { --calcite-table-row-background: var(--calcite-color-foreground-2); } diff --git a/packages/calcite-components/src/components/table/table.stories.ts b/packages/calcite-components/src/components/table/table.stories.ts index 9cfe4e47a22..766b2c5ed43 100644 --- a/packages/calcite-components/src/components/table/table.stories.ts +++ b/packages/calcite-components/src/components/table/table.stories.ts @@ -21,7 +21,7 @@ export const simple = (): string => caption="${text("caption", "Simple table")}" ${boolean("numbered", false)} ${boolean("bordered", false)} - ${boolean("zebra", false)} + ${boolean("striped", false)} caption="Simple table" > @@ -50,7 +50,7 @@ export const simple = (): string => `; -export const simpleZebra_TestOnly = (): string => html` +export const simpleStriped_TestOnly = (): string => html` @@ -104,7 +104,42 @@ export const bordered_TestOnly = (): string => html` `; -export const borderedZebra_TestOnly = (): string => html` +export const borderedStriped_TestOnly = (): string => html` + + + + + + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + +`; + +export const deprecatedZebraStriped_TestOnly = (): string => html` @@ -158,7 +193,7 @@ export const alignments_TestOnly = (): string => html` `; -export const disabledRows_TestOnly = (): string => html` +export const disabledRows_TestOnly = (): string => html` @@ -278,7 +313,7 @@ export const layoutFixed_TestOnly = (): string => html` @@ -318,7 +353,7 @@ export const rowSpanAndColSpan_TestOnly = (): string => html` html` @@ -359,7 +394,7 @@ export const rowSpanAndColSpanNumbered_TestOnly = (): string => html` html` @@ -956,8 +991,36 @@ export const localized_TestOnly = (): string => html` `; +export const tableCellCssBackgroundVariable_TestOnly = (): string => + html` + + + + + + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + `; + export const darkModeRTL_TestOnly = (): string => - html` + html` @@ -987,7 +1050,7 @@ export const darkModeRTL_TestOnly = (): string => darkModeRTL_TestOnly.parameters = { modes: modesDarkDefault }; export const darkModeRTLWithSelection_TestOnly = (): string => - html` + html` diff --git a/packages/calcite-components/src/components/table/table.tsx b/packages/calcite-components/src/components/table/table.tsx index b502f50caec..886684ee452 100644 --- a/packages/calcite-components/src/components/table/table.tsx +++ b/packages/calcite-components/src/components/table/table.tsx @@ -84,9 +84,16 @@ export class Table implements LocalizedComponent, LoadableComponent, T9nComponen @Prop({ reflect: true }) selectionMode: Extract<"none" | "multiple" | "single", SelectionMode> = "none"; - /** When `true`, displays zebra styling in the component. */ + /** + * When `true`, displays striped styling in the component. + * + * @deprecated Use the `striped` property instead. + */ @Prop({ reflect: true }) zebra = false; + /** When `true`, displays striped styling in the component. */ + @Prop({ reflect: true }) striped = false; + @Watch("groupSeparator") @Watch("numbered") @Watch("numberingSystem") @@ -499,7 +506,7 @@ export class Table implements LocalizedComponent, LoadableComponent, T9nComponen
    diff --git a/packages/calcite-components/src/components/tabs/tabs.stories.ts b/packages/calcite-components/src/components/tabs/tabs.stories.ts index d7497dc1af1..d5a7cd1f3ca 100644 --- a/packages/calcite-components/src/components/tabs/tabs.stories.ts +++ b/packages/calcite-components/src/components/tabs/tabs.stories.ts @@ -346,7 +346,7 @@ export const inlineTabsJustifyAgainstTheStartOfTheNavWidth_TestOnly = (): string `; -export const TabChildrenWithPercentageHeights = (): string => html` +export const Tab100PercentHeightNoVerticalScroll = (): string => html` Boats @@ -356,7 +356,21 @@ export const TabChildrenWithPercentageHeights = (): string => html` `; -TabChildrenWithPercentageHeights.parameters = { +Tab100PercentHeightNoVerticalScroll.parameters = { + chromatic: { delay: 1000 }, +}; + +export const Tab200PercentHeightWithVerticalScroll = (): string => html` + + + Boats + + +
    Tab 1 content
    +
    +
    +`; +Tab200PercentHeightWithVerticalScroll.parameters = { chromatic: { delay: 1000 }, }; @@ -378,3 +392,71 @@ export const updateIndicatorOffset_TestOnly = (): string => html` updateIndicatorOffset_TestOnly.parameters = { chromatic: { delay: 1000 }, }; + +export const fixedHeightNoVerticalScrollbar_TestOnly = (): string => html` + + + Watercraft + Automobiles + Aircrafts + + + +
    Recommended for coastal use
    +
    + +
    Why is there a vertical scroll bar in this panel?
    +
    +
    + + +
    A good choice for inland adventure
    +
    + +
    A good choice for inland adventure 2
    +
    +
    + + +
    Cross continents quickly
    +
    +
    +
    +`; + +export const noVerticalScrollbarInsideShellPanel_TestOnly = (): string => html` + + + + + + Watercraft + Automobiles + Aircrafts + + + +
    Recommended for coastal use
    +
    + +
    Why is there a vertical scroll bar in this panel?
    +
    +
    + + +
    A good choice for inland adventure
    +
    + +
    A good choice for inland adventure 2
    +
    +
    + + +
    Cross continents quickly
    +
    +
    +
    +
    +
    +
    +`; diff --git a/packages/calcite-components/src/components/tabs/usage/Basic.md b/packages/calcite-components/src/components/tabs/usage/Basic.md index 4fdb091da55..eeda316ee85 100644 --- a/packages/calcite-components/src/components/tabs/usage/Basic.md +++ b/packages/calcite-components/src/components/tabs/usage/Basic.md @@ -3,11 +3,12 @@ ```html - Tab 1 Title - Tab 2 Title + Dogs + Cats + Bears - - Tab 1 Content - Tab 2 Content + + + ``` diff --git a/packages/calcite-components/src/components/tabs/usage/Bordered.md b/packages/calcite-components/src/components/tabs/usage/Bordered.md index e610210899b..8cc9d0b58d6 100644 --- a/packages/calcite-components/src/components/tabs/usage/Bordered.md +++ b/packages/calcite-components/src/components/tabs/usage/Bordered.md @@ -1,14 +1,12 @@ ```html - + - Tab 1 Title - Tab 2 Title - Tab 3 Title - Tab 4 Title + Dogs + Cats + Bears - Tab 1 Content - Tab 2 Content - Tab 3 Content - Tab 4 Content + + + ``` diff --git a/packages/calcite-components/src/components/tile-select-group/usage/Basic.md b/packages/calcite-components/src/components/tile-select-group/usage/Basic.md new file mode 100644 index 00000000000..85d1f632e0e --- /dev/null +++ b/packages/calcite-components/src/components/tile-select-group/usage/Basic.md @@ -0,0 +1,32 @@ +```html + + + + + +``` diff --git a/packages/calcite-components/src/components/tile-select/resources.ts b/packages/calcite-components/src/components/tile-select/resources.ts index 611844f20d7..c12c7ce8473 100644 --- a/packages/calcite-components/src/components/tile-select/resources.ts +++ b/packages/calcite-components/src/components/tile-select/resources.ts @@ -11,6 +11,12 @@ export const CSS = { inputAlignmentStart: "input-alignment-start", inputEnabled: "input-enabled", largeVisual: "large-visual", + tile: "tile", + tileContentContainer: "tile-content-container", + tileContent: "tile-content", + tileDescription: "tile-description", + tileHeading: "tile-heading", + tileLargeVisual: "tile--large-visual", widthAuto: "width-auto", widthFull: "width-full", }; diff --git a/packages/calcite-components/src/components/tile-select/tile-select.scss b/packages/calcite-components/src/components/tile-select/tile-select.scss index a6c262448da..4364c7eb072 100644 --- a/packages/calcite-components/src/components/tile-select/tile-select.scss +++ b/packages/calcite-components/src/components/tile-select/tile-select.scss @@ -64,7 +64,7 @@ $spacing: $baseline * 0.5; &.heading.icon.description { gap: $spacing; } - calcite-tile { + .tile { @apply order-1; } &.large-visual { @@ -113,13 +113,79 @@ $spacing: $baseline * 0.5; &.width-full { @apply flex max-w-none; - calcite-tile { + .tile { @apply flex-auto; } } } } +.tile { + @apply bg-foreground-1 + box-border + duration-150 + ease-in-out + flex + flex-col + gap-2 + pointer-events-none + select-none + text-color-3; +} + +.tile-content-container { + @apply flex + focus-base + items-stretch + p-0 + text-color-2 + w-full; +} + +.tile-content { + @apply flex + flex-auto + flex-col + gap-2; + // set width handles slotted content and heading word wrap + inline-size: 10%; +} + +.tile-heading { + @apply break-words + duration-150 + ease-in-out + font-medium + pointer-events-none + text-color-2 + text-n1-wrap; +} + +.tile-description { + @apply break-words + duration-150 + ease-in-out + pointer-events-none + text-color-3 + text-n2-wrap; +} + +.tile--large-visual { + @apply grid justify-center + text-center; + min-block-size: theme("spacing.48"); + .icon { + @apply self-end; + } + calcite-icon { + block-size: 64px; + inline-size: 64px; + } + .tile-content-container { + @apply self-center; + } +} + :host(:hover) { .container { &:not(.input-enabled) { @@ -128,5 +194,15 @@ $spacing: $baseline * 0.5; } } +:host(:hover), +.checked { + .tile-heading { + @apply text-color-1; + } + .tile-description { + @apply text-color-2; + } +} + @include disabled(); @include base-component(); diff --git a/packages/calcite-components/src/components/tile-select/tile-select.tsx b/packages/calcite-components/src/components/tile-select/tile-select.tsx index 9d3ae576e4a..2da6c7b5523 100644 --- a/packages/calcite-components/src/components/tile-select/tile-select.tsx +++ b/packages/calcite-components/src/components/tile-select/tile-select.tsx @@ -308,6 +308,8 @@ export class TileSelect implements InteractiveComponent, LoadableComponent { width, iconFlipRtl, } = this; + const isLargeVisual = heading && icon && !description; + const renderIcon = Boolean(icon); return (
    - +
    + {icon && ( +
    + +
    + )} +
    +
    + {heading &&
    {heading}
    } + {description &&
    {description}
    } +
    +
    +
    ); diff --git a/packages/calcite-components/src/components/tile-select/usage/Basic.md b/packages/calcite-components/src/components/tile-select/usage/Basic.md index 21d443e80b7..f9e5341b837 100644 --- a/packages/calcite-components/src/components/tile-select/usage/Basic.md +++ b/packages/calcite-components/src/components/tile-select/usage/Basic.md @@ -2,9 +2,9 @@ diff --git a/packages/calcite-components/src/components/time-picker/usage/Basic.md b/packages/calcite-components/src/components/time-picker/usage/Basic.md new file mode 100644 index 00000000000..17d7232e1fe --- /dev/null +++ b/packages/calcite-components/src/components/time-picker/usage/Basic.md @@ -0,0 +1,3 @@ +```html + +``` diff --git a/packages/calcite-components/src/components/tip-manager/usage/Basic.md b/packages/calcite-components/src/components/tip-manager/usage/Basic.md index b631cadd0a8..d83ab320b27 100644 --- a/packages/calcite-components/src/components/tip-manager/usage/Basic.md +++ b/packages/calcite-components/src/components/tip-manager/usage/Basic.md @@ -2,44 +2,40 @@ Renders a tip manager using a group of tips as well as a single tip. ```html - - - This is an image. + + +

    - Tip description lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut - labore et dolore magna aliqua. + Did you know that a dog's sense of smell is so powerful that it can detect certain diseases, including cancer, + with remarkable accuracy?

    - This is another slotted paragraph. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut - aliquip ex ea commodo consequat. + Explore the incredible abilities of dogs with our + Canine Marvels.

    - A calcite-link
    -
    -
    ``` diff --git a/packages/calcite-components/src/components/tip/readme.md b/packages/calcite-components/src/components/tip/readme.md index 5702fd5794c..16768bc919b 100644 --- a/packages/calcite-components/src/components/tip/readme.md +++ b/packages/calcite-components/src/components/tip/readme.md @@ -12,7 +12,7 @@ Renders a close-disabled tip with a heading, thumbnail, info and a link. ```html - This is an image of nature. + This is an image of nature.

    Normal tip with a landscape or square image and a small amount of text in the "info" slot.

    Put a link hurr!
    diff --git a/packages/calcite-components/src/components/tip/usage/Basic.md b/packages/calcite-components/src/components/tip/usage/Basic.md index 46d560e29e7..78f40095dfa 100644 --- a/packages/calcite-components/src/components/tip/usage/Basic.md +++ b/packages/calcite-components/src/components/tip/usage/Basic.md @@ -1,9 +1,11 @@ Renders a close-disabled tip with a heading, thumbnail, info and a link. ```html - - This is an image of nature. -

    Normal tip with a landscape or square image and a small amount of text in the "info" slot.

    - Put a link hurr! + + +

    + Did you know that kittens are born with their eyes shut and ears folded? They start to open their eyes and unfold + their ears after about a week. +

    ``` diff --git a/packages/calcite-components/src/components/tooltip/tooltip.tsx b/packages/calcite-components/src/components/tooltip/tooltip.tsx index 25f4b63dcd3..75fe42ecd08 100644 --- a/packages/calcite-components/src/components/tooltip/tooltip.tsx +++ b/packages/calcite-components/src/components/tooltip/tooltip.tsx @@ -89,6 +89,7 @@ export class Tooltip implements FloatingUIComponent, OpenCloseComponent { @Watch("open") openHandler(): void { onToggleOpenCloseComponent(this); + this.reposition(true); } /** @@ -249,7 +250,6 @@ export class Tooltip implements FloatingUIComponent, OpenCloseComponent { // -------------------------------------------------------------------------- onBeforeOpen(): void { - this.reposition(true); this.calciteTooltipBeforeOpen.emit(); } @@ -263,7 +263,6 @@ export class Tooltip implements FloatingUIComponent, OpenCloseComponent { onClose(): void { this.calciteTooltipClose.emit(); - this.reposition(true); } private setTransitionEl = (el): void => { diff --git a/packages/calcite-components/src/components/tooltip/usage/Basic.md b/packages/calcite-components/src/components/tooltip/usage/Basic.md index 665fec5083d..748019f06a8 100644 --- a/packages/calcite-components/src/components/tooltip/usage/Basic.md +++ b/packages/calcite-components/src/components/tooltip/usage/Basic.md @@ -1,9 +1,11 @@ ```html -This is the message of the tooltip + + Honeybees communicate through intricate dances, navigate using the sun's position, and play a vital role in + maintaining biodiversity by pollinating flowers and crops. + - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor - incididunt ut labore et dolore magna aliqua. + Discover fascinating facts about the + secret lives of honeybees and their crucial + role in pollination. ``` diff --git a/packages/calcite-components/src/components/tree-item/tree-item.e2e.ts b/packages/calcite-components/src/components/tree-item/tree-item.e2e.ts index 1f7e070d9aa..f8ba96e0c45 100644 --- a/packages/calcite-components/src/components/tree-item/tree-item.e2e.ts +++ b/packages/calcite-components/src/components/tree-item/tree-item.e2e.ts @@ -22,7 +22,7 @@ describe("calcite-tree-item", () => { Child 2 - Grandchild 1 + Grandchild 1 @@ -87,7 +87,7 @@ describe("calcite-tree-item", () => { - Grandchild 1 + Grandchild 1 diff --git a/packages/calcite-components/src/components/tree/tree.e2e.ts b/packages/calcite-components/src/components/tree/tree.e2e.ts index 6593e6370cd..c2d146e3f9e 100644 --- a/packages/calcite-components/src/components/tree/tree.e2e.ts +++ b/packages/calcite-components/src/components/tree/tree.e2e.ts @@ -118,7 +118,7 @@ describe("calcite-tree", () => { Child 2 - Grandchild 1 + Grandchild 1 diff --git a/packages/calcite-components/src/components/tree/usage/Basic.md b/packages/calcite-components/src/components/tree/usage/Basic.md index a976e1158cd..e429b261b4b 100644 --- a/packages/calcite-components/src/components/tree/usage/Basic.md +++ b/packages/calcite-components/src/components/tree/usage/Basic.md @@ -3,13 +3,29 @@ ```html - Child 1 + Technology - Grandchild 1 + Programming Languages + + + JavaScript + + + Python + + - Grandchild 2 + Frameworks + + + React + + + Vue.js + + diff --git a/packages/calcite-components/src/demos/dropdown.html b/packages/calcite-components/src/demos/dropdown.html index 8822e668821..c1613f131e0 100644 --- a/packages/calcite-components/src/demos/dropdown.html +++ b/packages/calcite-components/src/demos/dropdown.html @@ -210,9 +210,9 @@
    icon-start + multi select
    - + Scale S - + List Grid Table @@ -221,9 +221,9 @@
    - + Scale M - + List Grid Table @@ -232,9 +232,9 @@
    - + Scale L - + List Grid Table @@ -248,9 +248,9 @@
    icon-start + multi select
    - + Scale S - + List Grid Table @@ -259,9 +259,9 @@
    - + Scale M - + List Grid Table @@ -270,9 +270,9 @@
    - + Scale L - + List Grid Table @@ -286,9 +286,9 @@
    icon-end + multi select
    - + Scale S - + List Grid Table @@ -297,9 +297,9 @@
    - + Scale M - + List Grid Table @@ -308,9 +308,9 @@
    - + Scale L - + List Grid Table @@ -326,9 +326,9 @@
    scale + icon + none select
    - + Scale S - + List Grid Table @@ -337,9 +337,9 @@
    - + Scale M - + List Grid Table @@ -348,9 +348,9 @@
    - + Scale L - + List Grid Table @@ -600,7 +600,7 @@
    - Click me + Click me Relevance Date modified @@ -616,7 +616,7 @@
    - Click me + Click me Relevance Date modified @@ -632,7 +632,7 @@
    - Click me + Click me Relevance Date modified diff --git a/packages/calcite-components/src/demos/list.html b/packages/calcite-components/src/demos/list.html index db81e624c71..e355dd4a08a 100644 --- a/packages/calcite-components/src/demos/list.html +++ b/packages/calcite-components/src/demos/list.html @@ -80,8 +80,8 @@

    List

    slot="content-start" style="color: var(--calcite-color-status-success)" --calcite-color-status-success - > --calcite-color-status-success + > + List label="menu" slot="actions-end" --calcite-color-status-success - > --calcite-color-status-success + > + --calcite-color-status-success + > + + diff --git a/packages/calcite-components/src/demos/table.html b/packages/calcite-components/src/demos/table.html index 131372d4d6a..6c5e16eea12 100644 --- a/packages/calcite-components/src/demos/table.html +++ b/packages/calcite-components/src/demos/table.html @@ -1439,8 +1439,8 @@

    Interactive

    Features Numbered - Zebra - Bordered + Striped + Bordered
    @@ -2885,8 +2885,8 @@

    Simple

    -

    zebra

    - +

    striped

    + @@ -2941,8 +2941,8 @@

    Bordered

    -

    Bordered-zebra

    - +

    Bordered-striped

    + @@ -2998,7 +2998,7 @@

    Various alignments

    Disabled rows

    - + @@ -3187,7 +3187,7 @@

    Layout fixed

    Using row-span and col-span

    - + @@ -3224,7 +3224,7 @@

    Using row-span and col-span

    Using row-span and col-span and numbered

    - + @@ -3261,7 +3261,7 @@

    Using row-span and col-span and numbered

    Using row-span and col-span

    - + diff --git a/packages/calcite-components/src/demos/tile-select.html b/packages/calcite-components/src/demos/tile-select.html index 182d8646a37..87a8a656f05 100644 --- a/packages/calcite-components/src/demos/tile-select.html +++ b/packages/calcite-components/src/demos/tile-select.html @@ -8,7 +8,6 @@