diff --git a/.prettierrc b/.prettierrc index cbfd0b498..55183ec92 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,5 +1,9 @@ { - "tabWidth": 2, - "semi": false, - "singleQuote": true + "trailingComma": "es5", + "tabWidth": 2, + "semi": false, + "singleQuote": true, + "endOfLine": "lf", + "bracketSpacing": true, + "jsxSingleQuote": true } diff --git a/package.json b/package.json index 41df535c4..73663f2d1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@react-google-maps/root", - "version": "1.9.4", + "version": "2.0.0-alpha", "private": true, "description": "@react-google-maps API integration", "license": "MIT", @@ -42,7 +42,7 @@ }, "devDependencies": { "husky": "4.2.5", - "lint-staged": "10.2.7" + "lint-staged": "10.2.9" }, "husky": { "hooks": { diff --git a/packages/react-google-maps-api-gatsby-example/.nvmrc b/packages/react-google-maps-api-gatsby-example/.nvmrc index ecd038577..15d242e46 100644 --- a/packages/react-google-maps-api-gatsby-example/.nvmrc +++ b/packages/react-google-maps-api-gatsby-example/.nvmrc @@ -1 +1 @@ -v13.3.0 \ No newline at end of file +v13.14.0 diff --git a/packages/react-google-maps-api-gatsby-example/package.json b/packages/react-google-maps-api-gatsby-example/package.json index 4192360a5..adf065dca 100644 --- a/packages/react-google-maps-api-gatsby-example/package.json +++ b/packages/react-google-maps-api-gatsby-example/package.json @@ -1,7 +1,7 @@ { "name": "@react-google-maps/gatsby-example", "description": "React Google Maps Gatsby.js example", - "version": "1.9.2", + "version": "2.0.0-alpha", "author": { "name": "Alexey Lyakhov", "email": "justfly1984@gmail.com", @@ -28,9 +28,9 @@ "@babel/preset-react": "7.10.1", "@babel/runtime": "7.10.2", "@getify/eslint-plugin-proper-arrows": "9.1.1", - "@react-google-maps/api": "1.9.5", + "@react-google-maps/api": "2.0.0-alpha", "@sentry/browser": "5.16.1", - "gatsby": "2.22.19", + "gatsby": "2.23.1", "gatsby-plugin-favicon": "3.1.6", "gatsby-plugin-purgecss": "5.0.0", "gatsby-plugin-react-helmet": "3.3.3", @@ -49,14 +49,14 @@ "redux-actions": "2.6.5", "redux-immutable": "4.0.0", "redux-thunk": "2.3.0", - "stylelint": "13.5.0", + "stylelint": "13.6.0", "stylelint-a11y": "1.2.3", "stylelint-config-css-modules": "2.2.0", "stylelint-config-recommended": "3.0.0", "stylelint-config-standard": "20.0.0", "stylelint-css-modules": "0.9.0", "stylelint-high-performance-animation": "1.5.1", - "typescript": "^3.9.3", + "typescript": "3.9.5", "uniqid": "5.2.0" }, "keywords": [ @@ -82,7 +82,7 @@ "@types/react-dom": "16.9.8", "babel-eslint": "10.1.0", "babel-plugin-transform-react-remove-prop-types": "0.4.24", - "eslint": "7.1.0", + "eslint": "7.2.0", "eslint-config-prettier": "6.11.0", "eslint-config-standard": "14.1.1", "eslint-config-standard-react": "9.2.0", diff --git a/packages/react-google-maps-api-gatsby-example/yarn.lock b/packages/react-google-maps-api-gatsby-example/yarn.lock index 63260550f..bbb556246 100644 --- a/packages/react-google-maps-api-gatsby-example/yarn.lock +++ b/packages/react-google-maps-api-gatsby-example/yarn.lock @@ -2422,26 +2422,26 @@ dependencies: tslib "^1.11.2" -"@react-google-maps/api@1.9.5": - version "1.9.5" - resolved "https://registry.yarnpkg.com/@react-google-maps/api/-/api-1.9.5.tgz#5b99d7397cdbb6c48c16623d63592df9a6cfffde" - integrity sha512-DB8Zv+ADwhHdulwec7k9yoMqpgK2VnaGD//rlZSUsDj1gafECFgxOEMcmjPSCDfFCSvX6qr5VVZJqBvrlpkm3Q== - dependencies: - "@react-google-maps/infobox" "1.9.3" - "@react-google-maps/marker-clusterer" "1.9.3" - acorn "^7.2.0" - acorn-jsx "^5.2.0" +"@react-google-maps/api@2.0.0-alpha": + version "2.0.0-alpha" + resolved "https://registry.yarnpkg.com/@react-google-maps/api/-/api-2.0.0-alpha.tgz#0f65bda24ac58af42cffebdbeba2b57c9ab425af" + integrity sha512-cqvk5gYdsyD7hKCyj/N7xrl8lvXw64NpFh7VmgclNW7fxzOwwDd49Qtr+jsD+x8ELQ3/IIzsH37ebBxKnuYMrg== + dependencies: + "@react-google-maps/infobox" "2.0.0-alpha" + "@react-google-maps/marker-clusterer" "2.0.0-alpha" + acorn "7.2.0" + acorn-jsx "5.2.0" invariant "2.2.4" -"@react-google-maps/infobox@1.9.3": - version "1.9.3" - resolved "https://registry.yarnpkg.com/@react-google-maps/infobox/-/infobox-1.9.3.tgz#90a32d57527f5f0476f2fcb41556016b650cc4a3" - integrity sha512-e2EoeS+VSBsU4Gol3m3eaj9n1UGmp4Sz1ORpYHq0TJI2zRNwS7C2rGLe4aT0tHMXcaPSfkPR811IKtmc54ItUQ== +"@react-google-maps/infobox@2.0.0-alpha": + version "2.0.0-alpha" + resolved "https://registry.yarnpkg.com/@react-google-maps/infobox/-/infobox-2.0.0-alpha.tgz#d9fb7b1f091466460e5cc7a3a2c9de4c4b831a3c" + integrity sha512-QOHyH1OfFvubpNB8/U4VSUcOVizIdo4R9jfQBN3klzV8T2h0JA3SQ9bi4isBHSINssvBc7rhAdz0PKe19fkc/w== -"@react-google-maps/marker-clusterer@1.9.3": - version "1.9.3" - resolved "https://registry.yarnpkg.com/@react-google-maps/marker-clusterer/-/marker-clusterer-1.9.3.tgz#6acb6a12cffeef04f11549aaf0a43e6135578116" - integrity sha512-fJoNmtHewep2wM4PnCtpPn3wImUPHBhCyz0YqOx1AxRg8zOwCOauPSMon3xKtGP7m5AmrAZpiYY51vBkubH/aA== +"@react-google-maps/marker-clusterer@2.0.0-alpha": + version "2.0.0-alpha" + resolved "https://registry.yarnpkg.com/@react-google-maps/marker-clusterer/-/marker-clusterer-2.0.0-alpha.tgz#4e55f1ab664a12a227104dc17b999c1cca5d99a3" + integrity sha512-SiDkSBQp5YPcbWGnLMNEzqJuhKP1u455o4h1MnqDLNsuEMjCT/Z8BdgpV+tuFFf4fDOpd5PeD3gEVwtPkcoH8A== "@sentry/browser@5.16.1": version "5.16.1" @@ -3262,7 +3262,7 @@ acorn-globals@^6.0.0: acorn "^7.1.1" acorn-walk "^7.1.1" -acorn-jsx@^5.0.1, acorn-jsx@^5.2.0: +acorn-jsx@5.2.0, acorn-jsx@^5.0.1, acorn-jsx@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.2.0.tgz#4c66069173d6fdd68ed85239fc256226182b2ebe" integrity sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ== @@ -3272,16 +3272,16 @@ acorn-walk@^7.1.1: resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.1.1.tgz#345f0dffad5c735e7373d2fec9a1023e6a44b83e" integrity sha512-wdlPY2tm/9XBr7QkKlq0WQVgiuGTX6YWPyRyBviSoScBuLfTVQhvwg6wJ369GJ/1nPfTLMfnrFIfjqVg6d+jQQ== +acorn@7.2.0, acorn@^7.1.1, acorn@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.2.0.tgz#17ea7e40d7c8640ff54a694c889c26f31704effe" + integrity sha512-apwXVmYVpQ34m/i71vrApRrRKCWQnZZF1+npOD0WV5xZFfwWOmKGQ2RWlfdy9vWITsenisM8M0Qeq8agcFHNiQ== + acorn@^6.1.1, acorn@^6.4.1: version "6.4.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474" integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA== -acorn@^7.1.1, acorn@^7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.2.0.tgz#17ea7e40d7c8640ff54a694c889c26f31704effe" - integrity sha512-apwXVmYVpQ34m/i71vrApRrRKCWQnZZF1+npOD0WV5xZFfwWOmKGQ2RWlfdy9vWITsenisM8M0Qeq8agcFHNiQ== - address@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/address/-/address-1.0.3.tgz#b5f50631f8d6cec8bd20c963963afb55e06cbce9" @@ -3718,7 +3718,7 @@ auto-bind@^4.0.0: resolved "https://registry.yarnpkg.com/auto-bind/-/auto-bind-4.0.0.tgz#e3589fc6c2da8f7ca43ba9f84fa52a744fc997fb" integrity sha512-Hdw8qdNiqdJ8LqT0iK0sVzkFbzg6fhnQqqfWhBDxcHZvU75+B+ayzTy8x+k5Ix0Y92XOhOUlx74ps+bA6BeYMQ== -autoprefixer@^9.7.6, autoprefixer@^9.8.0: +autoprefixer@^9.8.0: version "9.8.0" resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.0.tgz#68e2d2bef7ba4c3a65436f662d0a56a741e56511" integrity sha512-D96ZiIHXbDmU02dBaemyAg53ez+6F5yZmapmgKcjm35yEe1uVDYI8hGW3VYoGRaG290ZFf91YxHrR518vC0u/A== @@ -6664,6 +6664,14 @@ eslint-scope@^5.0.0: esrecurse "^4.1.0" estraverse "^4.1.1" +eslint-scope@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.0.tgz#d0f971dfe59c69e0cada684b23d49dbf82600ce5" + integrity sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + eslint-utils@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" @@ -6683,10 +6691,15 @@ eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== -eslint@7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.1.0.tgz#d9a1df25e5b7859b0a3d86bb05f0940ab676a851" - integrity sha512-DfS3b8iHMK5z/YLSme8K5cge168I8j8o1uiVmFCgnnjxZQbCGyraF8bMl7Ju4yfBmCuxD7shOF7eqGkcuIHfsA== +eslint-visitor-keys@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.2.0.tgz#74415ac884874495f78ec2a97349525344c981fa" + integrity sha512-WFb4ihckKil6hu3Dp798xdzSfddwKKU3+nGniKF6HfeW6OLd2OUDEPP7TcHtB5+QXOKg2s6B2DaMPE1Nn/kxKQ== + +eslint@7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.2.0.tgz#d41b2e47804b30dbabb093a967fb283d560082e6" + integrity sha512-B3BtEyaDKC5MlfDa2Ha8/D6DsS4fju95zs0hjS3HdGazw+LNayai38A25qMppK37wWGWNYSPOR6oYzlz5MHsRQ== dependencies: "@babel/code-frame" "^7.0.0" ajv "^6.10.0" @@ -6694,10 +6707,10 @@ eslint@7.1.0: cross-spawn "^7.0.2" debug "^4.0.1" doctrine "^3.0.0" - eslint-scope "^5.0.0" + eslint-scope "^5.1.0" eslint-utils "^2.0.0" - eslint-visitor-keys "^1.1.0" - espree "^7.0.0" + eslint-visitor-keys "^1.2.0" + espree "^7.1.0" esquery "^1.2.0" esutils "^2.0.2" file-entry-cache "^5.0.1" @@ -6777,14 +6790,14 @@ espree@^6.1.2: acorn-jsx "^5.2.0" eslint-visitor-keys "^1.1.0" -espree@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-7.0.0.tgz#8a7a60f218e69f120a842dc24c5a88aa7748a74e" - integrity sha512-/r2XEx5Mw4pgKdyb7GNLQNsu++asx/dltf/CI8RFi9oGHxmQFgvLbc5Op4U6i8Oaj+kdslhJtVlEZeAqH5qOTw== +espree@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-7.1.0.tgz#a9c7f18a752056735bf1ba14cb1b70adc3a5ce1c" + integrity sha512-dcorZSyfmm4WTuTnE5Y7MEN1DyoPYy1ZR783QW1FJoenn7RailyWFsq/UL6ZAAA7uXurN9FIpYyUs3OfiIW+Qw== dependencies: - acorn "^7.1.1" + acorn "^7.2.0" acorn-jsx "^5.2.0" - eslint-visitor-keys "^1.1.0" + eslint-visitor-keys "^1.2.0" esprima@^4.0.0, esprima@^4.0.1: version "4.0.1" @@ -7606,10 +7619,10 @@ functional-red-black-tree@^1.0.1: resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= -gatsby-admin@^0.1.60: - version "0.1.60" - resolved "https://registry.yarnpkg.com/gatsby-admin/-/gatsby-admin-0.1.60.tgz#93bb6b0becce79858319eda045c214b93c9678e9" - integrity sha512-YILifI5NyVfyLzXXOwovf8o2yCwmzOl5y7e5g/mZqAY30v0Osls1WIA/+sSDX8G4i0vwSRcOogBjQ6NzRuCeaA== +gatsby-admin@^0.1.65: + version "0.1.65" + resolved "https://registry.yarnpkg.com/gatsby-admin/-/gatsby-admin-0.1.65.tgz#643186a8edcb6fd2ac21897c6c082374b5da0042" + integrity sha512-9pwJA4kSMAfQ3xOC/xAGIRY4va515R49EsoWza63UR9vusbrjBOUdqyzCgZhqyhp47sUGr/urrfsbWttqoVOBw== dependencies: "@emotion/core" "^10.0.28" "@emotion/styled" "^10.0.27" @@ -7617,12 +7630,13 @@ gatsby-admin@^0.1.60: "@typescript-eslint/parser" "^2.28.0" csstype "^2.6.10" formik "^2.1.4" - gatsby "^2.22.19" + gatsby "^2.23.1" gatsby-interface "0.0.167" gatsby-plugin-typescript "^2.4.4" gatsby-source-graphql "^2.5.3" react "^16.12.0" react-dom "^16.12.0" + react-helmet "^6.0.0" react-icons "^3.10.0" strict-ui "^0.1.3" subscriptions-transport-ws "^0.9.16" @@ -7631,10 +7645,10 @@ gatsby-admin@^0.1.60: urql "^1.9.7" yup "^0.29.1" -gatsby-cli@^2.12.43: - version "2.12.43" - resolved "https://registry.yarnpkg.com/gatsby-cli/-/gatsby-cli-2.12.43.tgz#4195b0231721135a7d639afd99ca07fc440d4c5d" - integrity sha512-pYWUPXgWoXMrGBNyVshpaT0/n3AfSHP52r21H3MUHEx/zhusNYCbePJTJS49LozfJ/o/XCc+kRu6JHbd4Sf2MQ== +gatsby-cli@^2.12.44: + version "2.12.44" + resolved "https://registry.yarnpkg.com/gatsby-cli/-/gatsby-cli-2.12.44.tgz#db85aecaa56a0a26cd572d613cdd187c106ff9d4" + integrity sha512-7cGZHSt/YFL6q68Cst7qnthYMckzP8zlNTkKQH24hm/vMHUusvl2vPONJL4XbyLZwnQ3tts44B2eMGK4Qoa5Rg== dependencies: "@babel/code-frame" "^7.10.1" "@babel/runtime" "^7.10.2" @@ -7652,7 +7666,7 @@ gatsby-cli@^2.12.43: fs-exists-cached "^1.0.0" fs-extra "^8.1.0" gatsby-core-utils "^1.3.4" - gatsby-recipes "^0.1.37" + gatsby-recipes "^0.1.38" gatsby-telemetry "^1.3.10" hosted-git-info "^3.0.4" ink "^2.7.1" @@ -7818,10 +7832,10 @@ gatsby-react-router-scroll@^3.0.2: scroll-behavior "^0.9.12" warning "^3.0.0" -gatsby-recipes@^0.1.37: - version "0.1.37" - resolved "https://registry.yarnpkg.com/gatsby-recipes/-/gatsby-recipes-0.1.37.tgz#d46a8a82b7d0a0ef15e06eb66785d1bc1d8c1093" - integrity sha512-70C4zeEu8xdTKFlOkXqMmkmDN9+23wjKKErcOR8JhkKr1j5hOgnY7ieX+hHh1ud9AvaKKHlQGGvDNArX35E8tg== +gatsby-recipes@^0.1.38: + version "0.1.38" + resolved "https://registry.yarnpkg.com/gatsby-recipes/-/gatsby-recipes-0.1.38.tgz#be832d76537c88f4a2cccc7daa2e658056930487" + integrity sha512-Mly2n47VL0XfiAcK07+ZQvdOAFyYl3TH8cIApOpkJZCMSE0/Zmaz4rpD0W33ZXe2yIDnlVJkQPNDjAdYHN8ePA== dependencies: "@babel/core" "^7.10.2" "@babel/generator" "^7.10.2" @@ -7924,10 +7938,10 @@ gatsby-telemetry@^1.3.10: stack-utils "1.0.2" uuid "3.4.0" -gatsby@2.22.19, gatsby@^2.22.19: - version "2.22.19" - resolved "https://registry.yarnpkg.com/gatsby/-/gatsby-2.22.19.tgz#1e27a7e826deea62d64e3fac8500175ad3074369" - integrity sha512-Ch5FrPKQA/BpR3zFRUecedfCS2dG1kh6XI/lO8rzd/+/HzSLRpi3nXc+nxLIGpahyBrRZRKyJjkiiFRHg/Ymdg== +gatsby@2.23.1, gatsby@^2.23.1: + version "2.23.1" + resolved "https://registry.yarnpkg.com/gatsby/-/gatsby-2.23.1.tgz#a3738757e89efd8f437c7989b72284672ac4e41a" + integrity sha512-PFl8uTeA9D1HolCOSbaFSYTf6nG0DcSghe3fXrYLD4daov4IYGzM6+eGQkVNFwBbFEZod/7QzA4r1Rx6awkZDw== dependencies: "@babel/code-frame" "^7.10.1" "@babel/core" "^7.10.2" @@ -7991,8 +8005,8 @@ gatsby@2.22.19, gatsby@^2.22.19: flat "^4.1.0" fs-exists-cached "1.0.0" fs-extra "^8.1.0" - gatsby-admin "^0.1.60" - gatsby-cli "^2.12.43" + gatsby-admin "^0.1.65" + gatsby-cli "^2.12.44" gatsby-core-utils "^1.3.4" gatsby-graphiql-explorer "^0.4.4" gatsby-link "^2.4.5" @@ -8283,7 +8297,7 @@ globals@^12.1.0: dependencies: type-fest "^0.8.1" -globby@11.0.1: +globby@11.0.1, globby@^11.0.1: version "11.0.1" resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.1.tgz#9a2bf107a068f3ffeabc49ad702c79ede8cfd357" integrity sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ== @@ -8309,18 +8323,6 @@ globby@^10.0.1: merge2 "^1.2.3" slash "^3.0.0" -globby@^11.0.0: - version "11.0.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.0.tgz#56fd0e9f0d4f8fb0c456f1ab0dee96e1380bc154" - integrity sha512-iuehFnR3xu5wBBtm4xi0dMe92Ob87ufyu/dHwpDYfbcpYpIbrO5OnS8M1vWvrBhSGEJ3/Ecj7gnX76P8YxpPEg== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.1.1" - ignore "^5.1.4" - merge2 "^1.3.0" - slash "^3.0.0" - globby@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" @@ -9027,6 +9029,11 @@ ignore@^5.1.1, ignore@^5.1.4: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.4.tgz#84b7b3dbe64552b6ef0eca99f6743dbec6d97adf" integrity sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A== +ignore@^5.1.8: + version "5.1.8" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" + integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== + image-size@^0.5.0: version "0.5.5" resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c" @@ -12798,7 +12805,7 @@ postcss-sass@^0.4.4: gonzales-pe "^4.3.0" postcss "^7.0.21" -postcss-scss@^2.0.0: +postcss-scss@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/postcss-scss/-/postcss-scss-2.1.1.tgz#ec3a75fa29a55e016b90bf3269026c53c1d2b383" integrity sha512-jQmGnj0hSGLd9RscFw9LyuSVAa5Bl1/KBPqG1NQw9w8ND55nY4ZEsdlVuYJvLPpV+y0nwTV5v/4rHPzZRihQbA== @@ -12884,6 +12891,15 @@ postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.2, postcss@^7.0.21 source-map "^0.6.1" supports-color "^6.1.0" +postcss@^7.0.32: + version "7.0.32" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.32.tgz#4310d6ee347053da3433db2be492883d62cec59d" + integrity sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw== + dependencies: + chalk "^2.4.2" + source-map "^0.6.1" + supports-color "^6.1.0" + prebuild-install@^5.3.3: version "5.3.3" resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-5.3.3.tgz#ef4052baac60d465f5ba6bf003c9c1de79b9da8e" @@ -13323,7 +13339,7 @@ react-focus-lock@^2.3.1: use-callback-ref "^1.2.1" use-sidecar "^1.0.1" -react-helmet@6.0.0: +react-helmet@6.0.0, react-helmet@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/react-helmet/-/react-helmet-6.0.0.tgz#fcb93ebaca3ba562a686eb2f1f9d46093d83b5f8" integrity sha512-My6S4sa0uHN/IuVUn0HFmasW5xj9clTkB9qmMngscVycQ5vVG51Qp44BEvLJ4lixupTwDlU9qX1/sCrMN4AEPg== @@ -15214,14 +15230,14 @@ stylelint-high-performance-animation@1.5.1: resolved "https://registry.yarnpkg.com/stylelint-high-performance-animation/-/stylelint-high-performance-animation-1.5.1.tgz#055e66d4618d8f6b731d595e338df68a5fb92418" integrity sha512-HLG+fx5JV6VBVVmvXUoKL5rYiHAom7AaDKCu4WcxtX0eeAZ1SUL7p+RPYd8LD+2PMp2kqyTb3R59KSlUrwA70g== -stylelint@13.5.0: - version "13.5.0" - resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-13.5.0.tgz#9edbf90c8c02c47fd0c4818376e3799145f22cab" - integrity sha512-+Jy7ieKAWKTf2tmcAE7jgScxH39Urb87i0bjK/enScFaGWWaFn4kAPwepGOSk2b7CLUDVt/O6kwA0x0p/V7moQ== +stylelint@13.6.0: + version "13.6.0" + resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-13.6.0.tgz#3528bc402a71f2af2a3de32fa4e9f1c24e49666d" + integrity sha512-55gG2pNjVr183JJM/tlr3KAua6vTVX7Ho/lgKKuCIWszTZ1gmrXjX4Wok53SI8wRYFPbwKAcJGULQ77OJxTcNw== dependencies: "@stylelint/postcss-css-in-js" "^0.37.1" "@stylelint/postcss-markdown" "^0.36.1" - autoprefixer "^9.7.6" + autoprefixer "^9.8.0" balanced-match "^1.0.0" chalk "^4.0.0" cosmiconfig "^6.0.0" @@ -15230,10 +15246,10 @@ stylelint@13.5.0: file-entry-cache "^5.0.1" get-stdin "^8.0.0" global-modules "^2.0.0" - globby "^11.0.0" + globby "^11.0.1" globjoin "^0.1.4" html-tags "^3.1.0" - ignore "^5.1.4" + ignore "^5.1.8" import-lazy "^4.0.0" imurmurhash "^0.1.4" known-css-properties "^0.19.0" @@ -15244,7 +15260,7 @@ stylelint@13.5.0: meow "^7.0.1" micromatch "^4.0.2" normalize-selector "^0.2.0" - postcss "^7.0.30" + postcss "^7.0.32" postcss-html "^0.36.0" postcss-less "^3.1.4" postcss-media-query-parser "^0.2.3" @@ -15252,7 +15268,7 @@ stylelint@13.5.0: postcss-resolve-nested-selector "^0.1.1" postcss-safe-parser "^4.0.2" postcss-sass "^0.4.4" - postcss-scss "^2.0.0" + postcss-scss "^2.1.1" postcss-selector-parser "^6.0.2" postcss-syntax "^0.36.2" postcss-value-parser "^4.1.0" @@ -15265,7 +15281,7 @@ stylelint@13.5.0: sugarss "^2.0.0" svg-tags "^1.0.0" table "^5.4.6" - v8-compile-cache "^2.1.0" + v8-compile-cache "^2.1.1" write-file-atomic "^3.0.3" subscriptions-transport-ws@0.9.16, subscriptions-transport-ws@^0.9.16: @@ -15875,6 +15891,11 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= +typescript@3.9.5: + version "3.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.5.tgz#586f0dba300cde8be52dd1ac4f7e1009c1b13f36" + integrity sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ== + typescript@^3.9.3: version "3.9.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.3.tgz#d3ac8883a97c26139e42df5e93eeece33d610b8a" @@ -16299,11 +16320,16 @@ v8-compile-cache@^1.1.2: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-1.1.2.tgz#8d32e4f16974654657e676e0e467a348e89b0dc4" integrity sha512-ejdrifsIydN1XDH7EuR2hn8ZrkRKUYF7tUcBjBy/lhrCvs2K+zRlbW9UHc0IQ9RsYFZJFqJrieoIHfkCa0DBRA== -v8-compile-cache@^2.0.3, v8-compile-cache@^2.1.0: +v8-compile-cache@^2.0.3: version "2.1.0" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e" integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g== +v8-compile-cache@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz#54bc3cdd43317bca91e35dcaf305b1a7237de745" + integrity sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ== + v8-to-istanbul@^4.1.3: version "4.1.4" resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-4.1.4.tgz#b97936f21c0e2d9996d4985e5c5156e9d4e49cd6" diff --git a/packages/react-google-maps-api-infobox/.editorconfig b/packages/react-google-maps-api-infobox/.editorconfig index d7ad826cb..ef7e215d9 100644 --- a/packages/react-google-maps-api-infobox/.editorconfig +++ b/packages/react-google-maps-api-infobox/.editorconfig @@ -6,7 +6,7 @@ end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true -max_line_length = 100 +max_line_length = 80 indent_size = 2 [*.md] diff --git a/packages/react-google-maps-api-infobox/.eslintrc.js b/packages/react-google-maps-api-infobox/.eslintrc.js index c007e15ff..14a2e16a6 100644 --- a/packages/react-google-maps-api-infobox/.eslintrc.js +++ b/packages/react-google-maps-api-infobox/.eslintrc.js @@ -1,151 +1,144 @@ module.exports = { parser: '@typescript-eslint/parser', extends: [ - 'plugin:you-dont-need-lodash-underscore/compatible', - 'plugin:import/errors', - 'plugin:import/warnings', + 'eslint:recommended', + 'plugin:@typescript-eslint/eslint-recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:cypress/recommended', + 'plugin:import/typescript', + 'plugin:jest/recommended', + 'plugin:json/recommended', + 'plugin:jsx-a11y/recommended', + 'plugin:optimize-regex/all', + 'plugin:promise/recommended', 'plugin:react/recommended', - 'plugin:react-perf/recommended', + 'plugin:react-hooks/recommended', + 'plugin:react-perf/all', + 'standard', 'standard-react', - 'plugin:jsx-a11y/recommended', - 'plugin:@typescript-eslint/recommended', // Uses the recommended rules from @typescript-eslint/eslint-plugin -// 'plugin:@typescript-eslint/recommended', // Uses the recommended rules from @typescript-eslint/eslint-plugin - 'prettier/@typescript-eslint', // Uses eslint-config-prettier to disable ESLint rules from @typescript-eslint/eslint-plugin that would conflict with prettier + // Prettier always last + 'prettier', + 'plugin:prettier/recommended', + 'prettier/@typescript-eslint', 'prettier/react', 'prettier/standard', - 'prettier/@typescript-eslint', - 'plugin:prettier/recommended', // Enables eslint-plugin-prettier and displays prettier errors as ESLint errors. Make sure this is always the last configuration in the extends array. ], plugins: [ - '@getify/proper-arrows', - 'you-dont-need-lodash-underscore', - 'json', - 'babel', - 'import', - 'filenames', - 'jsx-a11y', - 'html', - 'ascii', - 'promise', - 'react', - 'optimize-regex', - 'react-perf', - 'standard', + 'chai-expect', + 'import', // connects in extends + '@typescript-eslint', // connects in extends + 'react', // connects in extends + 'jsx-a11y', // connects in extends + 'react-hooks', // connects in extends + 'react-perf', // connects in extends + 'jest', // connects in extends 'no-inferred-method-name', - 'react-functional-set-state', - '@typescript-eslint' - // 'prettier' + 'optimize-regex', // connects in extends + 'promise', // connects in extends + 'cypress', // connects in extends + 'prettier', // connects in extends + 'standard', // connects in extends + 'markdown', + 'json', // connects in extends + 'xss', // unused + 'perf-standard', + 'es', + 'babel', // unused + 'tree-shaking', // unused ], + settings: { + react: { + version: 'detect', + }, + node: { + allowModules: ['src'], + resolvePaths: [__dirname], + tryExtensions: ['.ts', '.tsx', '.js', '.jsx', '.json'], + }, + }, env: { + 'cypress/globals': true, browser: true, - es6: true + node: true, + es6: true, }, globals: { __DEV__: false, __PROD__: false, __PLAYER_DEBUG__: false, __BASENAME__: false, - google: true + google: true, }, - settings: { - ecmascript: 6, - 'import/parsers': { - '@typescript-eslint/parser': ['.ts', '.tsx'] - }, - 'import/resolver': { - // use /path/to/folder/tsconfig.json - 'typescript': { - 'directory': './tsconfig.json' - } + parserOptions: { + ecmaFeatures: { + jsx: true, }, - react: { - version: 'detect' - } + ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features + sourceType: 'module', // Allows for the use of imports }, rules: { - '@getify/proper-arrows/params': [ - 'error', { - 'unused': 'trailing' - } - ], - '@getify/proper-arrows/name': [ - 'error', { 'trivial': false } + camelcase: 'off', + 'jest/expect-expect': 'off', + 'no-useless-return': 'off', + 'node/no-missing-import': 'off', + 'node/no-missing-require': 'off', + 'node/no-unsupported-features/es-syntax': 'off', + 'sort-requires/sort-requires': 'off', + 'no-console': ['error', { allow: ['warn', 'error', 'info', 'table'] }], + 'no-unused-vars': 'off', + 'no-restricted-globals': [ + 'error', + { + name: 'name', + message: 'Use local parameter instead.', + }, + { + name: 'event', + message: 'Use local parameter instead.', + }, + { + name: 'fdescribe', + message: 'Do not commit fdescribe. Use describe instead.', + }, ], - '@getify/proper-arrows/where': [ - 'error', { 'global': true } + '@typescript-eslint/explicit-function-return-type': [ + 'warn', + { allowExpressions: true }, ], - '@getify/proper-arrows/return': [ - 'error', { 'object': true } + '@typescript-eslint/explicit-member-accessibility': 'off', + '@typescript-eslint/no-use-before-define': [ + 'error', + { functions: false, classes: false, typedefs: false }, ], - '@getify/proper-arrows/this': [ + '@typescript-eslint/no-unused-vars': [ 'error', - 'never', { - 'no-global': true - } + { varsIgnorePattern: '^_', argsIgnorePattern: '^_' }, ], - - 'ascii/valid-name': 2, + 'react-hooks/rules-of-hooks': 'error', + 'react-hooks/exhaustive-deps': 'warn', 'optimize-regex/optimize-regex': 'warn', - 'filenames/no-index': 0, - 'filenames/match-regex': [2, '^[a-z0-9-.]+$', true], - 'filenames/match-exported': [2, ['camel', 'kebab', null]], - 'template-curly-spacing': ['error', 'never'], - 'react-functional-set-state/no-this-state-props': 2, - 'no-void': 2, - 'no-restricted-globals': 2, - 'no-use-before-define': 2, - 'func-names': 1, - 'guard-for-in': 2, - 'no-restricted-syntax': 2, - - 'jsx-a11y/label-has-for': 'off', - 'no-console': 'off', - // 'react/no-typos': 'off', - 'max-len': 'off', - 'no-nested-ternary': 'off', - camelcase: [ - 2, - { - properties: 'never' - } - ], - 'react-redux/prefer-separate-component-file': 'off', - 'react/destructuring-assignment': 'off', - 'babel/no-invalid-this': 1, - 'babel/semi': 0, - 'spaced-comment': 0, - 'brace-style': 0, - 'no-trailing-spaces': 0, - 'import/default': 2, - 'import/no-unresolved': [ - 2, - { - commonjs: true, - amd: true - } - ], - 'import/named': 'off', - 'import/namespace': 2, - 'import/export': 2, - 'import/no-duplicates': 0, - 'import/imports-first': 2, - 'semi': ['error', 'never'], - // 'prettier/prettier': ['error', {trailingComma: 'none', semi: false, singleQuote: true, printWidth: 80, tabWidth: 2, parser: 'typescript'}], - // @typescript-eslint rule overrides - "indent": "off", - '@typescript-eslint/indent': ["error", 2], - '@typescript-eslint/explicit-function-return-type': 0, - '@typescript-eslint/explicit-member-accessibility': 0, - '@typescript-eslint/no-explicit-any': 0 + 'es/no-async-iteration': 'error', + 'es/no-malformed-template-literals': 'error', + 'es/no-regexp-lookbehind-assertions': 'error', + 'es/no-regexp-named-capture-groups': 'error', + 'es/no-regexp-s-flag': 'error', + 'es/no-regexp-unicode-property-escapes': 'error', + 'chai-expect/missing-assertion': 2, + 'chai-expect/terminating-properties': 1, + 'no-inferred-method-name/no-inferred-method-name': 'error', + // "tree-shaking/no-side-effects-in-initialization": 2, }, - parserOptions: { - 'ecmaVersion': 2018, - 'sourceType': 'module', - 'ecmaFeatures': { - jsx: true + overrides: [ + // Override some TypeScript rules just for .js files + { + files: ['*.js'], + rules: { + semi: ['error', 'never'], + 'jsx-quotes': ['error', 'prefer-single'], + '@typescript-eslint/no-var-requires': 'off', + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/explicit-module-boundary-types': 'off', + }, }, - 'useJSXTextNode': true, - 'project': './tsconfig.json', - 'tsconfigRootDir': './' - } + ], } diff --git a/packages/react-google-maps-api-infobox/package.json b/packages/react-google-maps-api-infobox/package.json index dd8b7df55..53629e02b 100644 --- a/packages/react-google-maps-api-infobox/package.json +++ b/packages/react-google-maps-api-infobox/package.json @@ -1,7 +1,7 @@ { "name": "@react-google-maps/infobox", "sideEffects": false, - "version": "1.9.3", + "version": "2.0.0-alpha", "description": "InfoBox for React.js Google Maps API", "license": "MIT", "author": { @@ -52,39 +52,48 @@ "@types/babel-types": "7.0.7", "@types/googlemaps": "3.39.6", "@types/react-dom": "16.9.8", - "@typescript-eslint/eslint-plugin": "3.0.2", - "@typescript-eslint/parser": "3.0.2", + "@typescript-eslint/eslint-plugin": "3.1.0", + "@typescript-eslint/parser": "3.1.0", "awesome-typescript-loader": "5.2.1", - "eslint": "7.1.0", + "eslint": "7.2.0", + "eslint-config-prettier": "6.11.0", "eslint-config-standard": "14.1.1", "eslint-config-standard-react": "9.2.0", "eslint-import-resolver-typescript": "2.0.0", "eslint-plugin-ascii": "1.0.0", "eslint-plugin-babel": "5.3.0", - "eslint-plugin-dependencies": "2.4.0", + "eslint-plugin-chai-expect": "2.1.0", + "eslint-plugin-cypress": "2.11.1", "eslint-plugin-filenames": "1.3.2", "eslint-plugin-html": "6.0.2", "eslint-plugin-import": "2.20.2", + "eslint-plugin-jest": "23.13.2", "eslint-plugin-json": "2.1.1", "eslint-plugin-jsx-a11y": "6.2.3", + "eslint-plugin-markdown": "1.0.2", "eslint-plugin-no-inferred-method-name": "2.0.0", "eslint-plugin-node": "11.1.0", "eslint-plugin-optimize-regex": "1.2.0", + "eslint-plugin-perf-standard": "1.0.3", + "eslint-plugin-prettier": "3.1.3", "eslint-plugin-promise": "4.2.1", "eslint-plugin-react": "7.20.0", "eslint-plugin-react-functional-set-state": "1.2.1", "eslint-plugin-react-hooks": "4.0.4", "eslint-plugin-react-perf": "3.2.3", + "eslint-plugin-security-node": "1.0.12", "eslint-plugin-standard": "4.0.1", + "eslint-plugin-tree-shaking": "1.8.0", + "eslint-plugin-xss": "0.1.10", "eslint-plugin-you-dont-need-lodash-underscore": "6.10.0", "jest": "26.0.1", "jest-cli": "26.0.1", "react": "16.13.1", "react-dom": "16.13.1", "rimraf": "3.0.2", - "ts-jest": "26.0.0", + "ts-jest": "26.1.0", "tsdx": "0.13.2", - "typescript": "3.9.3", + "typescript": "3.9.5", "webpack": "4.43.0" }, "gitHead": "80167ddcc3d8e356dbf0b0c3a6292c6a3a989f83" diff --git a/packages/react-google-maps-api-infobox/src/InfoBox.tsx b/packages/react-google-maps-api-infobox/src/InfoBox.tsx index 0f443ff12..130eea661 100644 --- a/packages/react-google-maps-api-infobox/src/InfoBox.tsx +++ b/packages/react-google-maps-api-infobox/src/InfoBox.tsx @@ -1,5 +1,4 @@ /* global google */ -/* eslint-disable filenames/match-regex */ import { InfoBoxOptions } from './types' export class InfoBox { @@ -11,8 +10,9 @@ export class InfoBox { zIndex: number | undefined | null boxClass: string boxStyle: { - [key: string]: any + [key: string]: unknown } + closeBoxMargin: string closeBoxURL: string infoBoxClearance: google.maps.Size @@ -43,11 +43,14 @@ export class InfoBox { this.boxClass = options.boxClass || 'infoBox' this.boxStyle = options.boxStyle || {} this.closeBoxMargin = options.closeBoxMargin || '2px' - this.closeBoxURL = options.closeBoxURL || 'http://www.google.com/intl/en_us/mapfiles/close.gif' + this.closeBoxURL = + options.closeBoxURL || + 'http://www.google.com/intl/en_us/mapfiles/close.gif' if (options.closeBoxURL === '') { this.closeBoxURL = '' } - this.infoBoxClearance = options.infoBoxClearance || new google.maps.Size(1, 1) + this.infoBoxClearance = + options.infoBoxClearance || new google.maps.Size(1, 1) if (typeof options.visible === 'undefined') { if (typeof options.isHidden === 'undefined') { @@ -73,7 +76,7 @@ export class InfoBox { createInfoBoxDiv(): void { // This handler prevents an event in the InfoBox from being passed on to the map. - function cancelHandler(event: Event) { + function cancelHandler(event: Event): void { event.cancelBubble = true if (event.stopPropagation) { event.stopPropagation() @@ -82,8 +85,7 @@ export class InfoBox { // This handler ignores the current event in the InfoBox and conditionally prevents // the event from being passed on to the map. It is used for the contextmenu event. - // eslint-disable-next-line @getify/proper-arrows/this - const ignoreHandler = (event: Event) => { + const ignoreHandler = (event: Event): void => { event.returnValue = false if (event.preventDefault) { @@ -106,7 +108,7 @@ export class InfoBox { this.div.appendChild(this.content) } - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore const panes = this.getPanes() panes[this.pane].appendChild(this.div) // Add the InfoBox div to the DOM @@ -122,7 +124,8 @@ export class InfoBox { } else { // The following code is needed to overcome problems with MSIE const bw = this.getBoxWidths() - this.div.style.width = this.div.offsetWidth - bw.left - bw.right + 'px' + this.div.style.width = + this.div.offsetWidth - bw.left - bw.right + 'px' this.fixedWidthSet = false } } @@ -155,16 +158,11 @@ export class InfoBox { // Workaround for Google bug that causes the cursor to change to a pointer // when the mouse moves over a marker underneath InfoBox. this.eventListeners.push( - google.maps.event.addDomListener( - this.div, - 'mouseover', - // eslint-disable-next-line @getify/proper-arrows/this, @getify/proper-arrows/name - () => { - if (this.div) { - this.div.style.cursor = 'default' - } + google.maps.event.addDomListener(this.div, 'mouseover', () => { + if (this.div) { + this.div.style.cursor = 'default' } - ) + }) ) } @@ -214,8 +212,7 @@ export class InfoBox { } getCloseClickHandler() { - // eslint-disable-next-line @getify/proper-arrows/this, @getify/proper-arrows/name - return (event: Event) => { + return (event: Event): void => { // 1.0.3 fix: Always prevent propagation of a close box click to the map: event.cancelBubble = true @@ -236,9 +233,13 @@ export class InfoBox { panBox(disablePan?: boolean): void { if (this.div && !disablePan) { - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore - // @ts-ignore - const map: google.maps.Map | google.maps.StreetViewPanorama | null | undefined = this.getMap() + const map: + | google.maps.Map + | google.maps.StreetViewPanorama + | null + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + | undefined = this.getMap() // Only pan if attached to map, not panorama if (map instanceof google.maps.Map) { @@ -253,10 +254,10 @@ export class InfoBox { } const mapDiv = map.getDiv() - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore const mapWidth = mapDiv.offsetWidth - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore const mapHeight = mapDiv.offsetHeight const iwOffsetX = this.pixelOffset.width @@ -266,7 +267,7 @@ export class InfoBox { const padX = this.infoBoxClearance.width const padY = this.infoBoxClearance.height - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore const projection: google.maps.MapCanvasProjection = this.getProjection() const pixPosition = projection.fromLatLngToContainerPixel(this.position) @@ -308,9 +309,11 @@ export class InfoBox { // Apply style values defined in the boxStyle parameter: const boxStyle = this.boxStyle + for (const i in boxStyle) { + // eslint-disable-next-line no-prototype-builtins if (boxStyle.hasOwnProperty(i)) { - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore this.div.style[i] = boxStyle[i] } @@ -321,14 +324,19 @@ export class InfoBox { this.div.style.webkitTransform = 'translateZ(0)' // Fix up opacity style for benefit of MSIE - if (typeof this.div.style.opacity !== 'undefined' && this.div.style.opacity !== '') { + if ( + typeof this.div.style.opacity !== 'undefined' && + this.div.style.opacity !== '' + ) { // See http://www.quirksmode.org/css/opacity.html const opacity = parseFloat(this.div.style.opacity || '') - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore this.div.style.msFilter = - '"progid:DXImageTransform.Microsoft.Alpha(Opacity=' + opacity * 100 + ')"' + '"progid:DXImageTransform.Microsoft.Alpha(Opacity=' + + opacity * 100 + + ')"' this.div.style.filter = 'alpha(opacity=' + opacity * 100 + ')' } @@ -366,16 +374,16 @@ export class InfoBox { bw.right = parseInt(computedStyle.borderRightWidth || '', 10) || 0 } } else if ( - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore document.documentElement.currentStyle // MSIE ) { - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore const currentStyle = this.div.currentStyle if (currentStyle) { - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // The current styles may not be in pixel units, but assume they are (bad!) bw.top = parseInt(currentStyle.borderTopWidth || '', 10) || 0 bw.bottom = parseInt(currentStyle.borderBottomWidth || '', 10) || 0 @@ -398,7 +406,7 @@ export class InfoBox { this.createInfoBoxDiv() if (this.div) { - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore const projection: google.maps.MapCanvasProjection = this.getProjection() const pixPosition = projection.fromLatLngToDivPixel(this.position) @@ -406,7 +414,8 @@ export class InfoBox { this.div.style.left = pixPosition.x + this.pixelOffset.width + 'px' if (this.alignBottom) { - this.div.style.bottom = -(pixPosition.y + this.pixelOffset.height) + 'px' + this.div.style.bottom = + -(pixPosition.y + this.pixelOffset.height) + 'px' } else { this.div.style.top = pixPosition.y + this.pixelOffset.height + 'px' } @@ -569,10 +578,15 @@ export class InfoBox { } getVisible(): boolean { - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore - // @ts-ignore - const map: google.maps.Map | google.maps.StreetViewPanorama | null | undefined = this.getMap() - let isVisible + const map: + | google.maps.Map + | google.maps.StreetViewPanorama + | null + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + | undefined = this.getMap() + + let isVisible: boolean if (typeof map === 'undefined' || map === null) { isVisible = false @@ -602,15 +616,14 @@ export class InfoBox { anchor?: google.maps.MVCObject ): void { if (anchor) { - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore this.position = anchor.getPosition() this.moveListener = google.maps.event.addListener( anchor, 'position_changed', - // eslint-disable-next-line @getify/proper-arrows/this, @getify/proper-arrows/name () => { - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore const position = anchor.getPosition() this.setPosition(position) @@ -620,16 +633,15 @@ export class InfoBox { this.mapListener = google.maps.event.addListener( anchor, 'map_changed', - // eslint-disable-next-line @getify/proper-arrows/this, @getify/proper-arrows/name () => { - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore this.setMap(anchor.map) } ) } - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore this.setMap(map) @@ -638,7 +650,7 @@ export class InfoBox { } } - close() { + close(): void { if (this.closeListener) { google.maps.event.removeListener(this.closeListener) this.closeListener = null @@ -666,25 +678,29 @@ export class InfoBox { this.contextListener = null } - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore this.setMap(null) } - extend(obj1: any, obj2: any): any { - return function applyExtend(object: any) { - // eslint-disable-next-line guard-for-in + // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types + extend(obj1: unknown, obj2: unknown): (object: unknown) => unknown { + // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types + return function applyExtend(object: unknown) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore for (const property in object.prototype) { - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore + // eslint-disable-next-line no-prototype-builtins if (!this.prototype.hasOwnProperty(property)) { - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore this.prototype[property] = object.prototype[property] } } - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore return this }.apply(obj1, [obj2]) diff --git a/packages/react-google-maps-api-infobox/src/index.ts b/packages/react-google-maps-api-infobox/src/index.ts index 3cd776275..8f9b2f5da 100644 --- a/packages/react-google-maps-api-infobox/src/index.ts +++ b/packages/react-google-maps-api-infobox/src/index.ts @@ -1,4 +1,3 @@ -/* eslint-disable filenames/match-exported */ /** * @name InfoBox * @version 1.1.13 [March 19, 2014] diff --git a/packages/react-google-maps-api-infobox/yarn.lock b/packages/react-google-maps-api-infobox/yarn.lock index 9d4ece815..a4d309ae8 100644 --- a/packages/react-google-maps-api-infobox/yarn.lock +++ b/packages/react-google-maps-api-infobox/yarn.lock @@ -1426,12 +1426,12 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.0.2.tgz#4a114a066e2f9659b25682ee59d4866e15a17ec3" - integrity sha512-ER3bSS/A/pKQT/hjMGCK8UQzlL0yLjuCZ/G8CDFJFVTfl3X65fvq2lNYqOG8JPTfrPa2RULCdwfOyFjZEMNExQ== +"@typescript-eslint/eslint-plugin@3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.1.0.tgz#4ac00ecca3bbea740c577f1843bc54fa69c3def2" + integrity sha512-D52KwdgkjYc+fmTZKW7CZpH5ZBJREJKZXRrveMiRCmlzZ+Rw9wRVJ1JAmHQ9b/+Ehy1ZeaylofDB9wwXUt83wg== dependencies: - "@typescript-eslint/experimental-utils" "3.0.2" + "@typescript-eslint/experimental-utils" "3.1.0" functional-red-black-tree "^1.0.1" regexpp "^3.0.0" semver "^7.3.2" @@ -1466,24 +1466,34 @@ "@typescript-eslint/typescript-estree" "2.24.0" eslint-scope "^5.0.0" -"@typescript-eslint/experimental-utils@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-3.0.2.tgz#bb2131baede8df28ec5eacfa540308ca895e5fee" - integrity sha512-4Wc4EczvoY183SSEnKgqAfkj1eLtRgBQ04AAeG+m4RhTVyaazxc1uI8IHf0qLmu7xXe9j1nn+UoDJjbmGmuqXQ== +"@typescript-eslint/experimental-utils@3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-3.1.0.tgz#2d5dba7c2ac2a3da3bfa3f461ff64de38587a872" + integrity sha512-Zf8JVC2K1svqPIk1CB/ehCiWPaERJBBokbMfNTNRczCbQSlQXaXtO/7OfYz9wZaecNvdSvVADt6/XQuIxhC79w== dependencies: "@types/json-schema" "^7.0.3" - "@typescript-eslint/typescript-estree" "3.0.2" + "@typescript-eslint/typescript-estree" "3.1.0" eslint-scope "^5.0.0" eslint-utils "^2.0.0" -"@typescript-eslint/parser@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-3.0.2.tgz#a92ef339added9bf7fb92605ac99c93ef243e834" - integrity sha512-80Z7s83e8QXHNUspqVlWwb4t5gdz/1bBBmafElbK1wwAwiD/yvJsFyHRxlEpNrt4rdK6eB3p+2WEFkEDHAKk9w== +"@typescript-eslint/experimental-utils@^2.5.0": + version "2.34.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.34.0.tgz#d3524b644cdb40eebceca67f8cf3e4cc9c8f980f" + integrity sha512-eS6FTkq+wuMJ+sgtuNTtcqavWXqsflWcfBnlYhg/nS4aZ1leewkXGbvBhaapn1q6qf4M71bsR1tez5JTRMuqwA== + dependencies: + "@types/json-schema" "^7.0.3" + "@typescript-eslint/typescript-estree" "2.34.0" + eslint-scope "^5.0.0" + eslint-utils "^2.0.0" + +"@typescript-eslint/parser@3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-3.1.0.tgz#9c02ba5d88ad2355672f39e6cd4176f172dd47f8" + integrity sha512-NcDSJK8qTA2tPfyGiPes9HtVKLbksmuYjlgGAUs7Ld2K0swdWibnCq9IJx9kJN8JJdgUJSorFiGaPHBgH81F/Q== dependencies: "@types/eslint-visitor-keys" "^1.0.0" - "@typescript-eslint/experimental-utils" "3.0.2" - "@typescript-eslint/typescript-estree" "3.0.2" + "@typescript-eslint/experimental-utils" "3.1.0" + "@typescript-eslint/typescript-estree" "3.1.0" eslint-visitor-keys "^1.1.0" "@typescript-eslint/parser@^2.12.0": @@ -1522,10 +1532,23 @@ semver "^6.3.0" tsutils "^3.17.1" -"@typescript-eslint/typescript-estree@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-3.0.2.tgz#67a1ce4307ebaea43443fbf3f3be7e2627157293" - integrity sha512-cs84mxgC9zQ6viV8MEcigfIKQmKtBkZNDYf8Gru2M+MhnA6z9q0NFMZm2IEzKqAwN8lY5mFVd1Z8DiHj6zQ3Tw== +"@typescript-eslint/typescript-estree@2.34.0": + version "2.34.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz#14aeb6353b39ef0732cc7f1b8285294937cf37d5" + integrity sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg== + dependencies: + debug "^4.1.1" + eslint-visitor-keys "^1.1.0" + glob "^7.1.6" + is-glob "^4.0.1" + lodash "^4.17.15" + semver "^7.3.2" + tsutils "^3.17.1" + +"@typescript-eslint/typescript-estree@3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-3.1.0.tgz#eaff52d31e615e05b894f8b9d2c3d8af152a5dd2" + integrity sha512-+4nfYauqeQvK55PgFrmBWFVYb6IskLyOosYEmhH3mSVhfBp9AIJnjExdgDmKWoOBHRcPM8Ihfm2BFpZf0euUZQ== dependencies: debug "^4.1.1" eslint-visitor-keys "^1.1.0" @@ -1751,7 +1774,7 @@ acorn@^7.1.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.0.tgz#949d36f2c292535da602283586c2477c57eb2d6c" integrity sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ== -acorn@^7.1.1: +acorn@^7.1.1, acorn@^7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.2.0.tgz#17ea7e40d7c8640ff54a694c889c26f31704effe" integrity sha512-apwXVmYVpQ34m/i71vrApRrRKCWQnZZF1+npOD0WV5xZFfwWOmKGQ2RWlfdy9vWITsenisM8M0Qeq8agcFHNiQ== @@ -2210,6 +2233,11 @@ babylon@^6.18.0: resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ== +bail@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.5.tgz#b6fa133404a392cbc1f8c4bf63f5953351e7a776" + integrity sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ== + balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" @@ -2550,6 +2578,21 @@ char-regex@^1.0.2: resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== +character-entities-legacy@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1" + integrity sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA== + +character-entities@^1.0.0: + version "1.2.4" + resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.4.tgz#e12c3939b7eaf4e5b15e7ad4c5e28e1d48c5b16b" + integrity sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw== + +character-reference-invalid@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560" + integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg== + chardet@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" @@ -2681,6 +2724,11 @@ co@^4.6.0: resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= +collapse-white-space@^1.0.2: + version "1.0.6" + resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-1.0.6.tgz#e63629c0016665792060dbbeb79c42239d2c5287" + integrity sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ== + collect-v8-coverage@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.0.tgz#150ee634ac3650b71d9c985eb7f608942334feb1" @@ -3348,6 +3396,13 @@ escodegen@^1.9.1: optionalDependencies: source-map "~0.6.1" +eslint-config-prettier@6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.11.0.tgz#f6d2238c1290d01c859a8b5c1f7d352a0b0da8b1" + integrity sha512-oB8cpLWSAjOVFEJhhyMZh6NOEOtBVziaqdDQ86+qhDHFbZXoRTM7pNSvFRfW/W/L/LrQ38C99J5CGuRBBzBsdA== + dependencies: + get-stdin "^6.0.0" + eslint-config-prettier@^6.0.0: version "6.9.0" resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.9.0.tgz#430d24822e82f7deb1e22a435bfa3999fae4ad64" @@ -3418,13 +3473,17 @@ eslint-plugin-babel@5.3.0: dependencies: eslint-rule-composer "^0.3.0" -eslint-plugin-dependencies@2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-dependencies/-/eslint-plugin-dependencies-2.4.0.tgz#e0d3f32c097281a8afd6c6bef7bb025585e92d6f" - integrity sha512-IaW2phNpktrok2eDziZLYxmNaGysXjNj6NVji7LEv/qagHG2oshsmV+mUSxAGG5Jv9seuRBdX1YXEIaNlhkFJg== +eslint-plugin-chai-expect@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-chai-expect/-/eslint-plugin-chai-expect-2.1.0.tgz#9dd1d8e5a80543fdec956f6aef7f83f2241ca92b" + integrity sha512-rd0/4mjMV6c3i0o4DKkWI4uaFN9DK707kW+/fDphaDI6HVgxXnhML9Xgt5vHnTXmSSnDhupuCFBgsEAEpchXmQ== + +eslint-plugin-cypress@2.11.1: + version "2.11.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-cypress/-/eslint-plugin-cypress-2.11.1.tgz#a945e2774b88211e2c706a059d431e262b5c2862" + integrity sha512-MxMYoReSO5+IZMGgpBZHHSx64zYPSPTpXDwsgW7ChlJTF/sA+obqRbHplxD6sBStE+g4Mi0LCLkG4t9liu//mQ== dependencies: - commondir "^1.0.1" - resolve "^1.1.6" + globals "^11.12.0" eslint-plugin-es@^3.0.0: version "3.0.0" @@ -3494,6 +3553,13 @@ eslint-plugin-import@^2.18.2: read-pkg-up "^2.0.0" resolve "^1.12.0" +eslint-plugin-jest@23.13.2: + version "23.13.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-23.13.2.tgz#7b7993b4e09be708c696b02555083ddefd7e4cc7" + integrity sha512-qZit+moTXTyZFNDqSIR88/L3rdBlTU7CuW6XmyErD2FfHEkdoLgThkRbiQjzgYnX6rfgLx3Ci4eJmF4Ui5v1Cw== + dependencies: + "@typescript-eslint/experimental-utils" "^2.5.0" + eslint-plugin-json@2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/eslint-plugin-json/-/eslint-plugin-json-2.1.1.tgz#7b9c4da2121f6f48d44efceb9a99ac0d4d12b299" @@ -3517,6 +3583,15 @@ eslint-plugin-jsx-a11y@6.2.3, eslint-plugin-jsx-a11y@^6.2.3: has "^1.0.3" jsx-ast-utils "^2.2.1" +eslint-plugin-markdown@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-markdown/-/eslint-plugin-markdown-1.0.2.tgz#79274bf17ce3ead48e4a55cbcb6d7ce735754280" + integrity sha512-BfvXKsO0K+zvdarNc801jsE/NTLmig4oKhZ1U3aSUgTf2dB/US5+CrfGxMsCK2Ki1vS1R3HPok+uYpufFndhzw== + dependencies: + object-assign "^4.0.1" + remark-parse "^5.0.0" + unified "^6.1.2" + eslint-plugin-no-inferred-method-name@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/eslint-plugin-no-inferred-method-name/-/eslint-plugin-no-inferred-method-name-2.0.0.tgz#99e2c9c921dfcb98c3874b427e26f8889f516c8e" @@ -3541,6 +3616,18 @@ eslint-plugin-optimize-regex@1.2.0: dependencies: regexp-tree "^0.1.20" +eslint-plugin-perf-standard@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-perf-standard/-/eslint-plugin-perf-standard-1.0.3.tgz#f2477073b40f7ae8c42093b9a08d84835d146b69" + integrity sha1-8kdwc7QPeujEIJO5oI2Eg10Ua2k= + +eslint-plugin-prettier@3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.3.tgz#ae116a0fc0e598fdae48743a4430903de5b4e6ca" + integrity sha512-+HG5jmu/dN3ZV3T6eCD7a4BlAySdN7mLIbJYo0z1cFQuI+r2DiTJEFeF68ots93PsnrMxbzIZ2S/ieX+mkrBeQ== + dependencies: + prettier-linter-helpers "^1.0.0" + eslint-plugin-prettier@^3.1.0: version "3.1.2" resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.2.tgz#432e5a667666ab84ce72f945c72f77d996a5c9ba" @@ -3608,11 +3695,28 @@ eslint-plugin-react@^7.14.3: resolve "^1.14.2" string.prototype.matchall "^4.0.2" +eslint-plugin-security-node@1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/eslint-plugin-security-node/-/eslint-plugin-security-node-1.0.12.tgz#b2573cdee01e9b66470a61b7a2377f197ecf1539" + integrity sha512-jd0iWPrbqIbu/P+0YKDz2Aqyqc8Y6jLFO66N2b/vjRQw8PSR/Jc3ef2ioPN+O7FAD1cqjImWnHrkoNW10hLzaA== + eslint-plugin-standard@4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-4.0.1.tgz#ff0519f7ffaff114f76d1bd7c3996eef0f6e20b4" integrity sha512-v/KBnfyaOMPmZc/dmc6ozOdWqekGp7bBGq4jLAecEfPGmfKiWS4sA8sC0LqiV9w5qmXAtXVn4M3p1jSyhY85SQ== +eslint-plugin-tree-shaking@1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-tree-shaking/-/eslint-plugin-tree-shaking-1.8.0.tgz#6ac08485481a5406142d0652bf894e45c46f3d5d" + integrity sha512-5jrqlyka6MCaV8efwAIIo/3cvmhurA4gUaFoTWoWw6wLhmHUS0/42NDKubKOMlQJXm5Z7/i4hbzyIcDXbHAnVw== + +eslint-plugin-xss@0.1.10: + version "0.1.10" + resolved "https://registry.yarnpkg.com/eslint-plugin-xss/-/eslint-plugin-xss-0.1.10.tgz#4d2dd121475cfd73c0062883f33e330c0c3db5ee" + integrity sha512-Wm2QIokqBq/IYi529xDXf9EOmVoQdAclaTEw1PNk+iyzyTiWssc1dqFz00PuB6nh01vA4phw0dnseY9b3Tsg1w== + dependencies: + requireindex "~1.1.0" + eslint-plugin-you-dont-need-lodash-underscore@6.10.0: version "6.10.0" resolved "https://registry.yarnpkg.com/eslint-plugin-you-dont-need-lodash-underscore/-/eslint-plugin-you-dont-need-lodash-underscore-6.10.0.tgz#63df0785ee1a07365ef77db907692f1ac928e000" @@ -3641,6 +3745,14 @@ eslint-scope@^5.0.0: esrecurse "^4.1.0" estraverse "^4.1.1" +eslint-scope@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.0.tgz#d0f971dfe59c69e0cada684b23d49dbf82600ce5" + integrity sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + eslint-utils@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" @@ -3660,10 +3772,15 @@ eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== -eslint@7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.1.0.tgz#d9a1df25e5b7859b0a3d86bb05f0940ab676a851" - integrity sha512-DfS3b8iHMK5z/YLSme8K5cge168I8j8o1uiVmFCgnnjxZQbCGyraF8bMl7Ju4yfBmCuxD7shOF7eqGkcuIHfsA== +eslint-visitor-keys@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.2.0.tgz#74415ac884874495f78ec2a97349525344c981fa" + integrity sha512-WFb4ihckKil6hu3Dp798xdzSfddwKKU3+nGniKF6HfeW6OLd2OUDEPP7TcHtB5+QXOKg2s6B2DaMPE1Nn/kxKQ== + +eslint@7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.2.0.tgz#d41b2e47804b30dbabb093a967fb283d560082e6" + integrity sha512-B3BtEyaDKC5MlfDa2Ha8/D6DsS4fju95zs0hjS3HdGazw+LNayai38A25qMppK37wWGWNYSPOR6oYzlz5MHsRQ== dependencies: "@babel/code-frame" "^7.0.0" ajv "^6.10.0" @@ -3671,10 +3788,10 @@ eslint@7.1.0: cross-spawn "^7.0.2" debug "^4.0.1" doctrine "^3.0.0" - eslint-scope "^5.0.0" + eslint-scope "^5.1.0" eslint-utils "^2.0.0" - eslint-visitor-keys "^1.1.0" - espree "^7.0.0" + eslint-visitor-keys "^1.2.0" + espree "^7.1.0" esquery "^1.2.0" esutils "^2.0.2" file-entry-cache "^5.0.1" @@ -3754,14 +3871,14 @@ espree@^6.1.2: acorn-jsx "^5.1.0" eslint-visitor-keys "^1.1.0" -espree@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-7.0.0.tgz#8a7a60f218e69f120a842dc24c5a88aa7748a74e" - integrity sha512-/r2XEx5Mw4pgKdyb7GNLQNsu++asx/dltf/CI8RFi9oGHxmQFgvLbc5Op4U6i8Oaj+kdslhJtVlEZeAqH5qOTw== +espree@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-7.1.0.tgz#a9c7f18a752056735bf1ba14cb1b70adc3a5ce1c" + integrity sha512-dcorZSyfmm4WTuTnE5Y7MEN1DyoPYy1ZR783QW1FJoenn7RailyWFsq/UL6ZAAA7uXurN9FIpYyUs3OfiIW+Qw== dependencies: - acorn "^7.1.1" + acorn "^7.2.0" acorn-jsx "^5.2.0" - eslint-visitor-keys "^1.1.0" + eslint-visitor-keys "^1.2.0" esprima@^3.1.3: version "3.1.3" @@ -3945,7 +4062,7 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: assign-symbols "^1.0.0" is-extendable "^1.0.1" -extend@~3.0.2: +extend@^3.0.0, extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== @@ -4274,7 +4391,7 @@ glob@^7.0.0, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: once "^1.3.0" path-is-absolute "^1.0.0" -globals@^11.1.0: +globals@^11.1.0, globals@^11.12.0: version "11.12.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== @@ -4541,7 +4658,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@^2.0.0, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -4615,6 +4732,19 @@ is-accessor-descriptor@^1.0.0: dependencies: kind-of "^6.0.0" +is-alphabetical@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d" + integrity sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg== + +is-alphanumerical@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz#7eb9a2431f855f6b1ef1a78e326df515696c4dbf" + integrity sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A== + dependencies: + is-alphabetical "^1.0.0" + is-decimal "^1.0.0" + is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" @@ -4634,7 +4764,7 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" -is-buffer@^1.1.5: +is-buffer@^1.1.4, is-buffer@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== @@ -4670,6 +4800,11 @@ is-date-object@^1.0.1: resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== +is-decimal@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5" + integrity sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw== + is-descriptor@^0.1.0: version "0.1.6" resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" @@ -4734,6 +4869,11 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" +is-hexadecimal@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" + integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw== + is-module@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" @@ -4751,6 +4891,11 @@ is-number@^7.0.0: resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== +is-plain-obj@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= + is-plain-object@^2.0.3, is-plain-object@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" @@ -4809,11 +4954,21 @@ is-typedarray@^1.0.0, is-typedarray@~1.0.0: resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= +is-whitespace-character@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz#0858edd94a95594c7c9dd0b5c174ec6e45ee4aa7" + integrity sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w== + is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== +is-word-character@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-word-character/-/is-word-character-1.0.4.tgz#ce0e73216f98599060592f62ff31354ddbeb0230" + integrity sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA== + is-wsl@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" @@ -6098,6 +6253,11 @@ map-visit@^1.0.0: dependencies: object-visit "^1.0.0" +markdown-escapes@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/markdown-escapes/-/markdown-escapes-1.0.4.tgz#c95415ef451499d7602b91095f3c8e8975f78535" + integrity sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg== + md5.js@^1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" @@ -6456,7 +6616,7 @@ oauth-sign@~0.9.0: resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== -object-assign@^4.1.1: +object-assign@^4.0.1, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= @@ -6714,6 +6874,18 @@ parse-asn1@^5.0.0: pbkdf2 "^3.0.3" safe-buffer "^5.1.1" +parse-entities@^1.1.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-1.2.2.tgz#c31bf0f653b6661354f8973559cb86dd1d5edf50" + integrity sha512-NzfpbxW/NPrzZ/yYSoQxyqUZMZXIdCfE0OIN4ESsnptHJECoUk3FZktxNuzQf4tjt5UEopnxpYJbvYuxIFDdsg== + dependencies: + character-entities "^1.0.0" + character-entities-legacy "^1.0.0" + character-reference-invalid "^1.0.0" + is-alphanumerical "^1.0.0" + is-decimal "^1.0.0" + is-hexadecimal "^1.0.0" + parse-json@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" @@ -7300,6 +7472,27 @@ regjsparser@^0.6.0: dependencies: jsesc "~0.5.0" +remark-parse@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-5.0.0.tgz#4c077f9e499044d1d5c13f80d7a98cf7b9285d95" + integrity sha512-b3iXszZLH1TLoyUzrATcTQUZrwNl1rE70rVdSruJFlDaJ9z5aMkhrG43Pp68OgfHndL/ADz6V69Zow8cTQu+JA== + dependencies: + collapse-white-space "^1.0.2" + is-alphabetical "^1.0.0" + is-decimal "^1.0.0" + is-whitespace-character "^1.0.0" + is-word-character "^1.0.0" + markdown-escapes "^1.0.0" + parse-entities "^1.1.0" + repeat-string "^1.5.4" + state-toggle "^1.0.0" + trim "0.0.1" + trim-trailing-lines "^1.0.0" + unherit "^1.0.4" + unist-util-remove-position "^1.0.0" + vfile-location "^2.0.0" + xtend "^4.0.1" + remove-trailing-separator@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" @@ -7310,11 +7503,16 @@ repeat-element@^1.1.2: resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== -repeat-string@^1.6.1: +repeat-string@^1.5.4, repeat-string@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= +replace-ext@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb" + integrity sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs= + request-promise-core@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.3.tgz#e9a3c081b51380dfea677336061fea879a829ee9" @@ -7947,6 +8145,11 @@ stack-utils@^2.0.2: dependencies: escape-string-regexp "^2.0.0" +state-toggle@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/state-toggle/-/state-toggle-1.0.3.tgz#e123b16a88e143139b09c6852221bc9815917dfe" + integrity sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ== + static-extend@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" @@ -8388,10 +8591,25 @@ tr46@^2.0.2: dependencies: punycode "^2.1.1" -ts-jest@26.0.0: - version "26.0.0" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.0.0.tgz#957b802978249aaf74180b9dcb17b4fd787ad6f3" - integrity sha512-eBpWH65mGgzobuw7UZy+uPP9lwu+tPp60o324ASRX4Ijg8UC5dl2zcge4kkmqr2Zeuk9FwIjvCTOPuNMEyGWWw== +trim-trailing-lines@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/trim-trailing-lines/-/trim-trailing-lines-1.1.3.tgz#7f0739881ff76657b7776e10874128004b625a94" + integrity sha512-4ku0mmjXifQcTVfYDfR5lpgV7zVqPg6zV9rdZmwOPqq0+Zq19xDqEgagqVbc4pOOShbncuAOIs59R3+3gcF3ZA== + +trim@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/trim/-/trim-0.0.1.tgz#5858547f6b290757ee95cccc666fb50084c460dd" + integrity sha1-WFhUf2spB1fulczMZm+1AITEYN0= + +trough@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" + integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== + +ts-jest@26.1.0: + version "26.1.0" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.1.0.tgz#e9070fc97b3ea5557a48b67c631c74eb35e15417" + integrity sha512-JbhQdyDMYN5nfKXaAwCIyaWLGwevcT2/dbqRPsQeh6NZPUuXjZQZEfeLb75tz0ubCIgEELNm6xAzTe5NXs5Y4Q== dependencies: bs-logger "0.x" buffer-from "1.x" @@ -8577,16 +8795,24 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@3.9.3: - version "3.9.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.3.tgz#d3ac8883a97c26139e42df5e93eeece33d610b8a" - integrity sha512-D/wqnB2xzNFIcoBG9FG8cXRDjiqSTbG2wd8DMZeQyJlP1vfTkIxH4GKveWaEBYySKIg+USu+E+EDIR47SqnaMQ== +typescript@3.9.5: + version "3.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.5.tgz#586f0dba300cde8be52dd1ac4f7e1009c1b13f36" + integrity sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ== typescript@^3.7.3: version "3.7.5" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae" integrity sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw== +unherit@^1.0.4: + version "1.1.3" + resolved "https://registry.yarnpkg.com/unherit/-/unherit-1.1.3.tgz#6c9b503f2b41b262330c80e91c8614abdaa69c22" + integrity sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ== + dependencies: + inherits "^2.0.0" + xtend "^4.0.0" + unicode-canonical-property-names-ecmascript@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" @@ -8610,6 +8836,18 @@ unicode-property-aliases-ecmascript@^1.0.4: resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz#a9cc6cc7ce63a0a3023fc99e341b94431d405a57" integrity sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw== +unified@^6.1.2: + version "6.2.0" + resolved "https://registry.yarnpkg.com/unified/-/unified-6.2.0.tgz#7fbd630f719126d67d40c644b7e3f617035f6dba" + integrity sha512-1k+KPhlVtqmG99RaTbAv/usu85fcSRu3wY8X+vnsEhIxNP5VbVIDiXnLqyKIG+UMdyTg0ZX9EI6k2AfjJkHPtA== + dependencies: + bail "^1.0.0" + extend "^3.0.0" + is-plain-obj "^1.1.0" + trough "^1.0.0" + vfile "^2.0.0" + x-is-string "^0.1.0" + union-value@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" @@ -8634,6 +8872,37 @@ unique-slug@^2.0.0: dependencies: imurmurhash "^0.1.4" +unist-util-is@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-3.0.0.tgz#d9e84381c2468e82629e4a5be9d7d05a2dd324cd" + integrity sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A== + +unist-util-remove-position@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/unist-util-remove-position/-/unist-util-remove-position-1.1.4.tgz#ec037348b6102c897703eee6d0294ca4755a2020" + integrity sha512-tLqd653ArxJIPnKII6LMZwH+mb5q+n/GtXQZo6S6csPRs5zB0u79Yw8ouR3wTw8wxvdJFhpP6Y7jorWdCgLO0A== + dependencies: + unist-util-visit "^1.1.0" + +unist-util-stringify-position@^1.0.0, unist-util-stringify-position@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-1.1.2.tgz#3f37fcf351279dcbca7480ab5889bb8a832ee1c6" + integrity sha512-pNCVrk64LZv1kElr0N1wPiHEUoXNVFERp+mlTg/s9R5Lwg87f9bM/3sQB99w+N9D/qnM9ar3+AKDBwo/gm/iQQ== + +unist-util-visit-parents@^2.0.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-2.1.2.tgz#25e43e55312166f3348cae6743588781d112c1e9" + integrity sha512-DyN5vD4NE3aSeB+PXYNKxzGsfocxp6asDc2XXE3b0ekO2BaRUpBicbbUygfSvYfUz1IkmjFR1YF7dPklraMZ2g== + dependencies: + unist-util-is "^3.0.0" + +unist-util-visit@^1.1.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-1.4.1.tgz#4724aaa8486e6ee6e26d7ff3c8685960d560b1e3" + integrity sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw== + dependencies: + unist-util-visit-parents "^2.0.0" + universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" @@ -8759,6 +9028,28 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" +vfile-location@^2.0.0: + version "2.0.6" + resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-2.0.6.tgz#8a274f39411b8719ea5728802e10d9e0dff1519e" + integrity sha512-sSFdyCP3G6Ka0CEmN83A2YCMKIieHx0EDaj5IDP4g1pa5ZJ4FJDvpO0WODLxo4LUX4oe52gmSCK7Jw4SBghqxA== + +vfile-message@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-1.1.1.tgz#5833ae078a1dfa2d96e9647886cd32993ab313e1" + integrity sha512-1WmsopSGhWt5laNir+633LszXvZ+Z/lxveBf6yhGsqnQIhlhzooZae7zV6YVM1Sdkw68dtAW3ow0pOdPANugvA== + dependencies: + unist-util-stringify-position "^1.1.1" + +vfile@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/vfile/-/vfile-2.3.0.tgz#e62d8e72b20e83c324bc6c67278ee272488bf84a" + integrity sha512-ASt4mBUHcTpMKD/l5Q+WJXNtshlWxOogYyGYYrg4lt/vuRjC1EFQtlAofL5VmtVNIZJzWYFJjzGWZ0Gw8pzW1w== + dependencies: + is-buffer "^1.1.4" + replace-ext "1.0.0" + unist-util-stringify-position "^1.0.0" + vfile-message "^1.0.0" + vm-browserify@^1.0.1: version "1.1.2" resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" @@ -9049,6 +9340,11 @@ ws@^7.2.3: resolved "https://registry.yarnpkg.com/ws/-/ws-7.3.0.tgz#4b2f7f219b3d3737bc1a2fbf145d825b94d38ffd" integrity sha512-iFtXzngZVXPGgpTlP1rBqsUK82p9tKqsWRPg5L56egiljujJT3vGAYnHANvFxBieXrTFavhzhxW52jnaWV+w2w== +x-is-string@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/x-is-string/-/x-is-string-0.1.0.tgz#474b50865af3a49a9c4657f05acd145458f77d82" + integrity sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI= + xml-name-validator@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" @@ -9066,7 +9362,7 @@ xregexp@^4.3.0: dependencies: "@babel/runtime-corejs3" "^7.8.3" -xtend@^4.0.0, xtend@~4.0.1: +xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== diff --git a/packages/react-google-maps-api-marker-clusterer/.editorconfig b/packages/react-google-maps-api-marker-clusterer/.editorconfig index d7ad826cb..ef7e215d9 100644 --- a/packages/react-google-maps-api-marker-clusterer/.editorconfig +++ b/packages/react-google-maps-api-marker-clusterer/.editorconfig @@ -6,7 +6,7 @@ end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true -max_line_length = 100 +max_line_length = 80 indent_size = 2 [*.md] diff --git a/packages/react-google-maps-api-marker-clusterer/.eslintrc.js b/packages/react-google-maps-api-marker-clusterer/.eslintrc.js index 9ed80f0f3..14a2e16a6 100644 --- a/packages/react-google-maps-api-marker-clusterer/.eslintrc.js +++ b/packages/react-google-maps-api-marker-clusterer/.eslintrc.js @@ -1,87 +1,144 @@ module.exports = { parser: '@typescript-eslint/parser', - plugins: [ - '@typescript-eslint', - 'security-node', - 'standard', - 'promise', - 'import', - 'node', - 'you-dont-need-lodash-underscore', - 'no-inferred-method-name', - 'json', - 'babel', - 'import', - 'filenames', - 'optimize-regex', - 'html', - 'ascii', - 'react', - 'jsx-a11y', - 'react-perf', - 'prettier', - 'react-functional-set-state', - ], extends: [ 'eslint:recommended', 'plugin:@typescript-eslint/eslint-recommended', 'plugin:@typescript-eslint/recommended', - 'standard', - 'plugin:node/recommended', + 'plugin:cypress/recommended', 'plugin:import/typescript', + 'plugin:jest/recommended', + 'plugin:json/recommended', + 'plugin:jsx-a11y/recommended', + 'plugin:optimize-regex/all', 'plugin:promise/recommended', - 'plugin:security-node/recommended', - 'plugin:you-dont-need-lodash-underscore/compatible', - // Always last + 'plugin:react/recommended', + 'plugin:react-hooks/recommended', + 'plugin:react-perf/all', + 'standard', + 'standard-react', + // Prettier always last 'prettier', 'plugin:prettier/recommended', 'prettier/@typescript-eslint', + 'prettier/react', 'prettier/standard', ], - rules: { - 'no-unused-vars': 'off', - 'no-useless-return': 'off', - 'node/no-missing-import': 'off', - 'node/no-unsupported-features/es-syntax': 'off', - '@typescript-eslint/no-var-requires': 'off', - "@typescript-eslint/no-unused-vars": ["error", { varsIgnorePattern: "^_", argsIgnorePattern: "^_" }], - "@typescript-eslint/no-use-before-define": ["error", { functions: false, classes: false }], - 'security-node/detect-crlf': 'off', - }, + plugins: [ + 'chai-expect', + 'import', // connects in extends + '@typescript-eslint', // connects in extends + 'react', // connects in extends + 'jsx-a11y', // connects in extends + 'react-hooks', // connects in extends + 'react-perf', // connects in extends + 'jest', // connects in extends + 'no-inferred-method-name', + 'optimize-regex', // connects in extends + 'promise', // connects in extends + 'cypress', // connects in extends + 'prettier', // connects in extends + 'standard', // connects in extends + 'markdown', + 'json', // connects in extends + 'xss', // unused + 'perf-standard', + 'es', + 'babel', // unused + 'tree-shaking', // unused + ], settings: { - ecmascript: 6, - 'import/parsers': { - '@typescript-eslint/parser': ['.ts', '.tsx'] + react: { + version: 'detect', }, - 'import/resolver': { - // use /path/to/folder/tsconfig.json - 'typescript': { - 'directory': './tsconfig.json' - } + node: { + allowModules: ['src'], + resolvePaths: [__dirname], + tryExtensions: ['.ts', '.tsx', '.js', '.jsx', '.json'], }, - react: { - version: 'detect' - } + }, + env: { + 'cypress/globals': true, + browser: true, + node: true, + es6: true, }, globals: { __DEV__: false, __PROD__: false, __PLAYER_DEBUG__: false, __BASENAME__: false, - google: true + google: true, }, parserOptions: { - 'ecmaVersion': 2018, - 'sourceType': 'module', - 'ecmaFeatures': { - jsx: true + ecmaFeatures: { + jsx: true, }, - 'useJSXTextNode': true, - 'project': './tsconfig.json', - 'tsconfigRootDir': './' + ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features + sourceType: 'module', // Allows for the use of imports }, - env: { - browser: true, - es6: true + rules: { + camelcase: 'off', + 'jest/expect-expect': 'off', + 'no-useless-return': 'off', + 'node/no-missing-import': 'off', + 'node/no-missing-require': 'off', + 'node/no-unsupported-features/es-syntax': 'off', + 'sort-requires/sort-requires': 'off', + 'no-console': ['error', { allow: ['warn', 'error', 'info', 'table'] }], + 'no-unused-vars': 'off', + 'no-restricted-globals': [ + 'error', + { + name: 'name', + message: 'Use local parameter instead.', + }, + { + name: 'event', + message: 'Use local parameter instead.', + }, + { + name: 'fdescribe', + message: 'Do not commit fdescribe. Use describe instead.', + }, + ], + '@typescript-eslint/explicit-function-return-type': [ + 'warn', + { allowExpressions: true }, + ], + '@typescript-eslint/explicit-member-accessibility': 'off', + '@typescript-eslint/no-use-before-define': [ + 'error', + { functions: false, classes: false, typedefs: false }, + ], + '@typescript-eslint/no-unused-vars': [ + 'error', + { varsIgnorePattern: '^_', argsIgnorePattern: '^_' }, + ], + 'react-hooks/rules-of-hooks': 'error', + 'react-hooks/exhaustive-deps': 'warn', + 'optimize-regex/optimize-regex': 'warn', + 'es/no-async-iteration': 'error', + 'es/no-malformed-template-literals': 'error', + 'es/no-regexp-lookbehind-assertions': 'error', + 'es/no-regexp-named-capture-groups': 'error', + 'es/no-regexp-s-flag': 'error', + 'es/no-regexp-unicode-property-escapes': 'error', + 'chai-expect/missing-assertion': 2, + 'chai-expect/terminating-properties': 1, + 'no-inferred-method-name/no-inferred-method-name': 'error', + // "tree-shaking/no-side-effects-in-initialization": 2, }, + overrides: [ + // Override some TypeScript rules just for .js files + { + files: ['*.js'], + rules: { + semi: ['error', 'never'], + 'jsx-quotes': ['error', 'prefer-single'], + '@typescript-eslint/no-var-requires': 'off', + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/explicit-module-boundary-types': 'off', + }, + }, + ], } diff --git a/packages/react-google-maps-api-marker-clusterer/package.json b/packages/react-google-maps-api-marker-clusterer/package.json index a37f7c957..7d99535a3 100644 --- a/packages/react-google-maps-api-marker-clusterer/package.json +++ b/packages/react-google-maps-api-marker-clusterer/package.json @@ -1,7 +1,7 @@ { "name": "@react-google-maps/marker-clusterer", "sideEffects": false, - "version": "1.9.3", + "version": "2.0.0-alpha", "description": "Marker Clusterer for React.js Google Maps API", "license": "MIT", "author": { @@ -56,26 +56,36 @@ "@typescript-eslint/eslint-plugin": "3.0.2", "@typescript-eslint/parser": "3.0.2", "awesome-typescript-loader": "5.2.1", - "eslint": "7.1.0", + "eslint": "7.2.0", + "eslint-config-prettier": "6.11.0", "eslint-config-standard": "14.1.1", "eslint-config-standard-react": "9.2.0", "eslint-import-resolver-typescript": "2.0.0", "eslint-plugin-ascii": "1.0.0", "eslint-plugin-babel": "5.3.0", + "eslint-plugin-chai-expect": "2.1.0", + "eslint-plugin-cypress": "2.11.1", "eslint-plugin-filenames": "1.3.2", "eslint-plugin-html": "6.0.2", "eslint-plugin-import": "2.20.2", + "eslint-plugin-jest": "23.13.2", "eslint-plugin-json": "2.1.1", "eslint-plugin-jsx-a11y": "6.2.3", + "eslint-plugin-markdown": "1.0.2", "eslint-plugin-no-inferred-method-name": "2.0.0", "eslint-plugin-node": "11.1.0", "eslint-plugin-optimize-regex": "1.2.0", + "eslint-plugin-perf-standard": "1.0.3", + "eslint-plugin-prettier": "3.1.3", "eslint-plugin-promise": "4.2.1", "eslint-plugin-react": "7.20.0", "eslint-plugin-react-functional-set-state": "1.2.1", "eslint-plugin-react-hooks": "4.0.4", "eslint-plugin-react-perf": "3.2.3", + "eslint-plugin-security-node": "1.0.12", "eslint-plugin-standard": "4.0.1", + "eslint-plugin-tree-shaking": "1.8.0", + "eslint-plugin-xss": "0.1.10", "eslint-plugin-you-dont-need-lodash-underscore": "6.10.0", "jest": "26.0.1", "jest-cli": "26.0.1", diff --git a/packages/react-google-maps-api-marker-clusterer/src/Cluster.tsx b/packages/react-google-maps-api-marker-clusterer/src/Cluster.tsx index 87989a322..d0ead753b 100644 --- a/packages/react-google-maps-api-marker-clusterer/src/Cluster.tsx +++ b/packages/react-google-maps-api-marker-clusterer/src/Cluster.tsx @@ -1,5 +1,4 @@ /* global google */ -/* eslint-disable filenames/match-regex */ import { Clusterer } from './Clusterer' import { ClusterIcon } from './ClusterIcon' @@ -19,7 +18,7 @@ export class Cluster { constructor(markerClusterer: Clusterer) { this.markerClusterer = markerClusterer - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore this.map = this.markerClusterer.getMap() @@ -74,8 +73,8 @@ export class Cluster { return bounds } - remove() { - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + remove(): void { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore this.clusterIcon.setMap(null) @@ -156,13 +155,13 @@ export class Cluster { return false } - calculateBounds() { + calculateBounds(): void { this.bounds = this.markerClusterer.getExtendedBounds( new google.maps.LatLngBounds(this.center, this.center) ) } - updateIcon() { + updateIcon(): void { const mCount = this.markers.length const maxZoom = this.markerClusterer.getMaxZoom() @@ -185,7 +184,10 @@ export class Cluster { } this.clusterIcon.useStyle( - this.markerClusterer.getCalculator()(this.markers, this.markerClusterer.getStyles().length) + this.markerClusterer.getCalculator()( + this.markers, + this.markerClusterer.getStyles().length + ) ) this.clusterIcon.show() diff --git a/packages/react-google-maps-api-marker-clusterer/src/ClusterIcon.tsx b/packages/react-google-maps-api-marker-clusterer/src/ClusterIcon.tsx index 681140a07..5d551c5fe 100644 --- a/packages/react-google-maps-api-marker-clusterer/src/ClusterIcon.tsx +++ b/packages/react-google-maps-api-marker-clusterer/src/ClusterIcon.tsx @@ -1,5 +1,4 @@ /* global google */ -/* eslint-disable filenames/match-regex */ import { Cluster } from './Cluster' import { ClusterIconStyle, ClusterIconInfo } from './types' @@ -49,12 +48,12 @@ export class ClusterIcon { this.fontStyle = 'normal' this.fontFamily = 'Arial,sans-serif' this.backgroundPosition = '0 0' - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore this.setMap(cluster.getMap()) // Note: this causes onAdd to be called } - onAdd() { + onAdd(): void { let cMouseDownInCluster: boolean let cDraggingMapByCluster: boolean @@ -64,13 +63,13 @@ export class ClusterIcon { this.show() } - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore this.getPanes().overlayMouseTarget.appendChild(this.div) // Fix for Issue 157 this.boundsChangedListener = google.maps.event.addListener( - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore this.getMap(), 'boundschanged', @@ -79,103 +78,101 @@ export class ClusterIcon { } ) - google.maps.event.addDomListener(this.div, 'mousedown', function onMouseDown() { - cMouseDownInCluster = true - cDraggingMapByCluster = false - }) - - // eslint-disable-next-line @getify/proper-arrows/this, @getify/proper-arrows/name google.maps.event.addDomListener( this.div, - 'click', - // eslint-disable-next-line @getify/proper-arrows/this, @getify/proper-arrows/name - (event: Event) => { - cMouseDownInCluster = false - - if (!cDraggingMapByCluster) { - const markerClusterer = this.cluster.getClusterer() - - /** - * This event is fired when a cluster marker is clicked. - * @name MarkerClusterer#click - * @param {Cluster} c The cluster that was clicked. - * @event - */ - google.maps.event.trigger(markerClusterer, 'click', this.cluster) - google.maps.event.trigger(markerClusterer, 'clusterclick', this.cluster) // deprecated name - - // The default click handler follows. Disable it by setting - // the zoomOnClick property to false. - if (markerClusterer.getZoomOnClick()) { - // Zoom into the cluster. - const maxZoom = markerClusterer.getMaxZoom() - - const bounds = this.cluster.getBounds() - - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + 'mousedown', + function onMouseDown() { + cMouseDownInCluster = true + cDraggingMapByCluster = false + } + ) + + google.maps.event.addDomListener(this.div, 'click', (event: Event) => { + cMouseDownInCluster = false + + if (!cDraggingMapByCluster) { + const markerClusterer = this.cluster.getClusterer() + + /** + * This event is fired when a cluster marker is clicked. + * @name MarkerClusterer#click + * @param {Cluster} c The cluster that was clicked. + * @event + */ + google.maps.event.trigger(markerClusterer, 'click', this.cluster) + google.maps.event.trigger(markerClusterer, 'clusterclick', this.cluster) // deprecated name + + // The default click handler follows. Disable it by setting + // the zoomOnClick property to false. + if (markerClusterer.getZoomOnClick()) { + // Zoom into the cluster. + const maxZoom = markerClusterer.getMaxZoom() + + const bounds = this.cluster.getBounds() + + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + markerClusterer.getMap().fitBounds(bounds) + + // There is a fix for Issue 170 here: + setTimeout(function timeout() { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore markerClusterer.getMap().fitBounds(bounds) - // There is a fix for Issue 170 here: - setTimeout(function timeout() { - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // Don't zoom beyond the max zoom level + if ( + maxZoom !== null && + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - markerClusterer.getMap().fitBounds(bounds) - - // Don't zoom beyond the max zoom level - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + markerClusterer.getMap().getZoom() > maxZoom + ) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - if (maxZoom !== null && markerClusterer.getMap().getZoom() > maxZoom) { - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore - // @ts-ignore - markerClusterer.getMap().setZoom(maxZoom + 1) - } - }, 100) - } - - // Prevent event propagation to the map: - event.cancelBubble = true - - if (event.stopPropagation) { - event.stopPropagation() - } + markerClusterer.getMap().setZoom(maxZoom + 1) + } + }, 100) } - } - ) - google.maps.event.addDomListener( - this.div, - 'mouseover', - // eslint-disable-next-line @getify/proper-arrows/this, @getify/proper-arrows/name - () => { - /** - * This event is fired when the mouse moves over a cluster marker. - * @name MarkerClusterer#mouseover - * @param {Cluster} c The cluster that the mouse moved over. - * @event - */ - google.maps.event.trigger(this.cluster.getClusterer(), 'mouseover', this.cluster) - } - ) + // Prevent event propagation to the map: + event.cancelBubble = true - // eslint-disable-next-line @getify/proper-arrows/this, @getify/proper-arrows/name - google.maps.event.addDomListener( - this.div, - 'mouseout', - // eslint-disable-next-line @getify/proper-arrows/this, @getify/proper-arrows/name - () => { - /** - * This event is fired when the mouse moves out of a cluster marker. - * @name MarkerClusterer#mouseout - * @param {Cluster} c The cluster that the mouse moved out of. - * @event - */ - google.maps.event.trigger(this.cluster.getClusterer(), 'mouseout', this.cluster) + if (event.stopPropagation) { + event.stopPropagation() + } } - ) + }) + + google.maps.event.addDomListener(this.div, 'mouseover', () => { + /** + * This event is fired when the mouse moves over a cluster marker. + * @name MarkerClusterer#mouseover + * @param {Cluster} c The cluster that the mouse moved over. + * @event + */ + google.maps.event.trigger( + this.cluster.getClusterer(), + 'mouseover', + this.cluster + ) + }) + + google.maps.event.addDomListener(this.div, 'mouseout', () => { + /** + * This event is fired when the mouse moves out of a cluster marker. + * @name MarkerClusterer#mouseout + * @param {Cluster} c The cluster that the mouse moved out of. + * @event + */ + google.maps.event.trigger( + this.cluster.getClusterer(), + 'mouseout', + this.cluster + ) + }) } - onRemove() { + onRemove(): void { if (this.div && this.div.parentNode) { this.hide() @@ -191,7 +188,7 @@ export class ClusterIcon { } } - draw() { + draw(): void { if (this.visible && this.div !== null && this.center) { const { x, y } = this.getPosFromLatLng(this.center) @@ -200,7 +197,7 @@ export class ClusterIcon { } } - hide() { + hide(): void { if (this.div) { this.div.style.display = 'none' } @@ -208,10 +205,10 @@ export class ClusterIcon { this.visible = false } - show() { + show(): void { if (this.div && this.center) { - let img = '', - divTitle = '' + let img = '' + let divTitle = '' // NOTE: values must be specified in px units const bp = this.backgroundPosition.split(' ') @@ -222,7 +219,11 @@ export class ClusterIcon { const pos = this.getPosFromLatLng(this.center) - if (this.sums === null || typeof this.sums.title === 'undefined' || this.sums.title === '') { + if ( + this.sums === null || + typeof this.sums.title === 'undefined' || + this.sums.title === '' + ) { divTitle = this.cluster.getClusterer().getTitle() } else { divTitle = this.sums.title @@ -241,8 +242,8 @@ export class ClusterIcon { spriteH + 'px; ' - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore - //@ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore if (!this.cluster.getClusterer().enableRetinaIcons) { img += 'clip: rect(' + @@ -294,7 +295,7 @@ export class ClusterIcon { this.height + 'px;' + "'>" + - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore this.sums.text + '' @@ -307,10 +308,12 @@ export class ClusterIcon { this.visible = true } - useStyle(sums: ClusterIconInfo) { + useStyle(sums: ClusterIconInfo): void { this.sums = sums - const style = this.styles[Math.min(this.styles.length - 1, Math.max(0, sums.index - 1))] + const style = this.styles[ + Math.min(this.styles.length - 1, Math.max(0, sums.index - 1)) + ] this.url = style.url this.height = style.height @@ -333,7 +336,7 @@ export class ClusterIcon { this.backgroundPosition = style.backgroundPosition || '0 0' } - setCenter(center: google.maps.LatLng) { + setCenter(center: google.maps.LatLng): void { this.center = center } @@ -342,7 +345,9 @@ export class ClusterIcon { style.push('cursor: pointer;') - style.push('position: absolute; top: ' + pos.y + 'px; left: ' + pos.x + 'px;') + style.push( + 'position: absolute; top: ' + pos.y + 'px; left: ' + pos.x + 'px;' + ) style.push('width: ' + this.width + 'px; height: ' + this.height + 'px;') @@ -350,7 +355,7 @@ export class ClusterIcon { } getPosFromLatLng(latlng: google.maps.LatLng): google.maps.Point { - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore const pos = this.getProjection().fromLatLngToDivPixel(latlng) diff --git a/packages/react-google-maps-api-marker-clusterer/src/Clusterer.tsx b/packages/react-google-maps-api-marker-clusterer/src/Clusterer.tsx index 3b156e54b..89933d8b7 100644 --- a/packages/react-google-maps-api-marker-clusterer/src/Clusterer.tsx +++ b/packages/react-google-maps-api-marker-clusterer/src/Clusterer.tsx @@ -1,5 +1,4 @@ /* global google */ -/* eslint-disable filenames/match-regex */ import { Cluster } from './Cluster' import { @@ -23,7 +22,7 @@ const CALCULATOR = function CALCULATOR( let dv: string | number = count while (dv !== 0) { - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore dv = parseInt(dv, 10) / 10 @@ -142,13 +141,13 @@ export class Clusterer { this.setupStyles() this.addMarkers(optMarkers, true) - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore this.setMap(map) // Note: this causes onAdd to be called } - onAdd() { - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + onAdd(): void { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore this.activeMap = this.getMap() @@ -159,11 +158,10 @@ export class Clusterer { // Add the map event listeners this.listeners = [ google.maps.event.addListener( - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore this.getMap(), 'zoom_changed', - // eslint-disable-next-line @getify/proper-arrows/this, @getify/proper-arrows/name () => { this.resetViewport(false) // Workaround for this Google bug: when map is at level 0 and "-" of @@ -172,10 +170,10 @@ export class Clusterer { // event is triggered so the cluster markers that have been removed // do not get redrawn. Same goes for a zoom in at maxZoom. if ( - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore this.getMap().getZoom() === (this.get('minZoom') || 0) || - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore this.getMap().getZoom() === this.get('maxZoom') ) { @@ -184,11 +182,10 @@ export class Clusterer { } ), google.maps.event.addListener( - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore this.getMap(), 'idle', - // eslint-disable-next-line @getify/proper-arrows/this, @getify/proper-arrows/name () => { this.redraw() } @@ -196,8 +193,7 @@ export class Clusterer { ] } - // eslint-disable-next-line @getify/proper-arrows/this - onRemove() { + onRemove(): void { // Put all the managed markers back on the map: for (let i = 0; i < this.markers.length; i++) { if (this.markers[i].getMap() !== this.activeMap) { @@ -224,10 +220,11 @@ export class Clusterer { this.ready = false } - // eslint-disable-next-line @typescript-eslint/no-empty-function - draw() {} + draw(): void { + return + } - setupStyles() { + setupStyles(): void { if (this.styles.length > 0) { return } @@ -241,7 +238,7 @@ export class Clusterer { } } - fitMapToMarkers() { + fitMapToMarkers(): void { const markers = this.getMarkers() const bounds = new google.maps.LatLngBounds() @@ -253,7 +250,7 @@ export class Clusterer { } } - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore this.getMap().fitBounds(bounds) } @@ -262,7 +259,7 @@ export class Clusterer { return this.gridSize } - setGridSize(gridSize: number) { + setGridSize(gridSize: number): void { this.gridSize = gridSize } @@ -270,7 +267,7 @@ export class Clusterer { return this.minClusterSize } - setMinimumClusterSize(minimumClusterSize: number) { + setMinimumClusterSize(minimumClusterSize: number): void { this.minClusterSize = minimumClusterSize } @@ -278,7 +275,7 @@ export class Clusterer { return this.maxZoom } - setMaxZoom(maxZoom: number) { + setMaxZoom(maxZoom: number): void { this.maxZoom = maxZoom } @@ -286,7 +283,7 @@ export class Clusterer { return this.styles } - setStyles(styles: ClusterIconStyle[]) { + setStyles(styles: ClusterIconStyle[]): void { this.styles = styles } @@ -294,7 +291,7 @@ export class Clusterer { return this.title } - setTitle(title: string) { + setTitle(title: string): void { this.title = title } @@ -302,7 +299,7 @@ export class Clusterer { return this.zoomOnClick } - setZoomOnClick(zoomOnClick: boolean) { + setZoomOnClick(zoomOnClick: boolean): void { this.zoomOnClick = zoomOnClick } @@ -310,7 +307,7 @@ export class Clusterer { return this.averageCenter } - setAverageCenter(averageCenter: boolean) { + setAverageCenter(averageCenter: boolean): void { this.averageCenter = averageCenter } @@ -318,7 +315,7 @@ export class Clusterer { return this.ignoreHidden } - setIgnoreHidden(ignoreHidden: boolean) { + setIgnoreHidden(ignoreHidden: boolean): void { this.ignoreHidden = ignoreHidden } @@ -326,7 +323,7 @@ export class Clusterer { return this.enableRetinaIcons } - setEnableRetinaIcons(enableRetinaIcons: boolean) { + setEnableRetinaIcons(enableRetinaIcons: boolean): void { this.enableRetinaIcons = enableRetinaIcons } @@ -334,7 +331,7 @@ export class Clusterer { return this.imageExtension } - setImageExtension(imageExtension: string) { + setImageExtension(imageExtension: string): void { this.imageExtension = imageExtension } @@ -342,7 +339,7 @@ export class Clusterer { return this.imagePath } - setImagePath(imagePath: string) { + setImagePath(imagePath: string): void { this.imagePath = imagePath } @@ -350,7 +347,7 @@ export class Clusterer { return this.imageSizes } - setImageSizes(imageSizes: number[]) { + setImageSizes(imageSizes: number[]): void { this.imageSizes = imageSizes } @@ -358,7 +355,7 @@ export class Clusterer { return this.calculator } - setCalculator(calculator: TCalculator) { + setCalculator(calculator: TCalculator): void { this.calculator = calculator } @@ -366,7 +363,7 @@ export class Clusterer { return this.batchSizeIE } - setBatchSizeIE(batchSizeIE: number) { + setBatchSizeIE(batchSizeIE: number): void { this.batchSizeIE = batchSizeIE } @@ -374,7 +371,7 @@ export class Clusterer { return this.clusterClass } - setClusterClass(clusterClass: string) { + setClusterClass(clusterClass: string): void { this.clusterClass = clusterClass } @@ -394,7 +391,7 @@ export class Clusterer { return this.clusters.length } - addMarker(marker: MarkerExtended, optNoDraw: boolean) { + addMarker(marker: MarkerExtended, optNoDraw: boolean): void { this.pushMarkerTo(marker) if (!optNoDraw) { @@ -402,8 +399,9 @@ export class Clusterer { } } - addMarkers(markers: MarkerExtended[], optNoDraw: boolean) { + addMarkers(markers: MarkerExtended[], optNoDraw: boolean): void { for (const key in markers) { + // eslint-disable-next-line no-prototype-builtins if (markers.hasOwnProperty(key)) { this.pushMarkerTo(markers[key]) } @@ -414,10 +412,9 @@ export class Clusterer { } } - pushMarkerTo(marker: MarkerExtended) { + pushMarkerTo(marker: MarkerExtended): void { // If the marker is draggable add a listener so we can update the clusters on the dragend: if (marker.getDraggable()) { - // eslint-disable-next-line @getify/proper-arrows/name, @getify/proper-arrows/this google.maps.event.addListener(marker, 'dragend', () => { if (this.ready) { marker.isAdded = false @@ -483,13 +480,13 @@ export class Clusterer { return removed } - clearMarkers() { + clearMarkers(): void { this.resetViewport(true) this.markers = [] } - repaint() { + repaint(): void { const oldClusters = this.clusters.slice() this.clusters = [] @@ -507,14 +504,19 @@ export class Clusterer { }, 0) } - getExtendedBounds(bounds: google.maps.LatLngBounds): google.maps.LatLngBounds { - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + getExtendedBounds( + bounds: google.maps.LatLngBounds + ): google.maps.LatLngBounds { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore const projection = this.getProjection() // Convert the points to pixels and the extend out by the grid size. const trPix = projection.fromLatLngToDivPixel( // Turn the bounds into latlng. - new google.maps.LatLng(bounds.getNorthEast().lat(), bounds.getNorthEast().lng()) + new google.maps.LatLng( + bounds.getNorthEast().lat(), + bounds.getNorthEast().lng() + ) ) trPix.x += this.gridSize @@ -522,7 +524,10 @@ export class Clusterer { const blPix = projection.fromLatLngToDivPixel( // Turn the bounds into latlng. - new google.maps.LatLng(bounds.getSouthWest().lat(), bounds.getSouthWest().lng()) + new google.maps.LatLng( + bounds.getSouthWest().lat(), + bounds.getSouthWest().lng() + ) ) blPix.x -= this.gridSize @@ -542,12 +547,12 @@ export class Clusterer { return bounds } - redraw() { + redraw(): void { // Redraws all the clusters. this.createClusters(0) } - resetViewport(optHide: boolean) { + resetViewport(optHide: boolean): void { // Remove all the clusters for (let i = 0; i < this.clusters.length; i++) { this.clusters[i].remove() @@ -567,7 +572,10 @@ export class Clusterer { } } - distanceBetweenPoints(p1: google.maps.LatLng, p2: google.maps.LatLng): number { + distanceBetweenPoints( + p1: google.maps.LatLng, + p2: google.maps.LatLng + ): number { const R = 6371 // Radius of the Earth in km const dLat = ((p2.lat() - p1.lat()) * Math.PI) / 180 @@ -583,7 +591,10 @@ export class Clusterer { return R * (2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))) } - isMarkerInBounds(marker: MarkerExtended, bounds: google.maps.LatLngBounds): boolean { + isMarkerInBounds( + marker: MarkerExtended, + bounds: google.maps.LatLngBounds + ): boolean { const position = marker.getPosition() if (position) { @@ -593,7 +604,7 @@ export class Clusterer { return false } - addToClosestCluster(marker: MarkerExtended) { + addToClosestCluster(marker: MarkerExtended): void { let cluster let distance = 40000 // Some large number @@ -629,7 +640,7 @@ export class Clusterer { } } - createClusters(iFirst: number) { + createClusters(iFirst: number): void { if (!this.ready) { return } @@ -657,25 +668,25 @@ export class Clusterer { // // See Comments 9 & 11 on Issue 3651 relating to this workaround for a Google Maps bug: const mapBounds = - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore - // @ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore this.getMap().getZoom() > 3 ? new google.maps.LatLngBounds( - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore - // @ts-ignore - this.getMap() - .getBounds() - .getSouthWest(), - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore - // @ts-ignore - this.getMap() - .getBounds() - .getNorthEast() - ) + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + this.getMap() + .getBounds() + .getSouthWest(), + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + this.getMap() + .getBounds() + .getNorthEast() + ) : new google.maps.LatLngBounds( - new google.maps.LatLng(85.02070771743472, -178.48388434375), - new google.maps.LatLng(-85.08136444384544, 178.00048865625) - ) + new google.maps.LatLng(85.02070771743472, -178.48388434375), + new google.maps.LatLng(-85.08136444384544, 178.00048865625) + ) const bounds = this.getExtendedBounds(mapBounds) @@ -692,13 +703,9 @@ export class Clusterer { } if (iLast < this.markers.length) { - this.timerRefStatic = window.setTimeout( - // eslint-disable-next-line @getify/proper-arrows/this, @getify/proper-arrows/name - () => { - this.createClusters(iLast) - }, - 0 - ) + this.timerRefStatic = window.setTimeout(() => { + this.createClusters(iLast) + }, 0) } else { this.timerRefStatic = null @@ -709,7 +716,7 @@ export class Clusterer { * @param {Clusterer} mc The Clusterer whose markers are being clustered. * @event */ - google.maps.event.trigger(this, 'clusteringend', this) + google.maps.event.trigger(this, 'clusteringend', this) for (let i = 0; i < this.clusters.length; i++) { this.clusters[i].updateIcon() @@ -717,16 +724,18 @@ export class Clusterer { } } - extend(obj1: any, obj2: any): any { - return function applyExtend(object: any) { + extend(obj1: unknown, obj2: unknown): unknown { + return function applyExtend(object: unknown) { // eslint-disable-next-line guard-for-in + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore for (const property in object.prototype) { - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore this.prototype[property] = object.prototype[property] } - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore return this }.apply(obj1, [obj2]) diff --git a/packages/react-google-maps-api-marker-clusterer/src/index.ts b/packages/react-google-maps-api-marker-clusterer/src/index.ts index a54a97677..f1a2ccb79 100644 --- a/packages/react-google-maps-api-marker-clusterer/src/index.ts +++ b/packages/react-google-maps-api-marker-clusterer/src/index.ts @@ -1,4 +1,3 @@ -/* eslint-disable filenames/match-exported */ /** * @name MarkerClusterer for Google Maps V3 * @version 1.0.0 [March 2019] diff --git a/packages/react-google-maps-api-marker-clusterer/src/types.tsx b/packages/react-google-maps-api-marker-clusterer/src/types.tsx index 016530d1c..220662a19 100644 --- a/packages/react-google-maps-api-marker-clusterer/src/types.tsx +++ b/packages/react-google-maps-api-marker-clusterer/src/types.tsx @@ -9,7 +9,10 @@ export type MarkerExtended = google.maps.Marker & { isAdded?: boolean } -export type TCalculator = (markers: MarkerExtended[], num: number) => ClusterIconInfo +export type TCalculator = ( + markers: MarkerExtended[], + num: number +) => ClusterIconInfo export interface ClustererOptions { gridSize?: number diff --git a/packages/react-google-maps-api-marker-clusterer/yarn.lock b/packages/react-google-maps-api-marker-clusterer/yarn.lock index 363a3572a..4b1c4afd4 100644 --- a/packages/react-google-maps-api-marker-clusterer/yarn.lock +++ b/packages/react-google-maps-api-marker-clusterer/yarn.lock @@ -1467,6 +1467,16 @@ eslint-scope "^5.0.0" eslint-utils "^2.0.0" +"@typescript-eslint/experimental-utils@^2.5.0": + version "2.34.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.34.0.tgz#d3524b644cdb40eebceca67f8cf3e4cc9c8f980f" + integrity sha512-eS6FTkq+wuMJ+sgtuNTtcqavWXqsflWcfBnlYhg/nS4aZ1leewkXGbvBhaapn1q6qf4M71bsR1tez5JTRMuqwA== + dependencies: + "@types/json-schema" "^7.0.3" + "@typescript-eslint/typescript-estree" "2.34.0" + eslint-scope "^5.0.0" + eslint-utils "^2.0.0" + "@typescript-eslint/parser@3.0.2": version "3.0.2" resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-3.0.2.tgz#a92ef339added9bf7fb92605ac99c93ef243e834" @@ -1500,6 +1510,19 @@ semver "^6.3.0" tsutils "^3.17.1" +"@typescript-eslint/typescript-estree@2.34.0": + version "2.34.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz#14aeb6353b39ef0732cc7f1b8285294937cf37d5" + integrity sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg== + dependencies: + debug "^4.1.1" + eslint-visitor-keys "^1.1.0" + glob "^7.1.6" + is-glob "^4.0.1" + lodash "^4.17.15" + semver "^7.3.2" + tsutils "^3.17.1" + "@typescript-eslint/typescript-estree@3.0.2": version "3.0.2" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-3.0.2.tgz#67a1ce4307ebaea43443fbf3f3be7e2627157293" @@ -1729,7 +1752,7 @@ acorn@^7.1.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.0.tgz#949d36f2c292535da602283586c2477c57eb2d6c" integrity sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ== -acorn@^7.1.1: +acorn@^7.1.1, acorn@^7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.2.0.tgz#17ea7e40d7c8640ff54a694c889c26f31704effe" integrity sha512-apwXVmYVpQ34m/i71vrApRrRKCWQnZZF1+npOD0WV5xZFfwWOmKGQ2RWlfdy9vWITsenisM8M0Qeq8agcFHNiQ== @@ -2188,6 +2211,11 @@ babylon@^6.18.0: resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ== +bail@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.5.tgz#b6fa133404a392cbc1f8c4bf63f5953351e7a776" + integrity sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ== + balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" @@ -2528,6 +2556,21 @@ char-regex@^1.0.2: resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== +character-entities-legacy@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1" + integrity sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA== + +character-entities@^1.0.0: + version "1.2.4" + resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.4.tgz#e12c3939b7eaf4e5b15e7ad4c5e28e1d48c5b16b" + integrity sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw== + +character-reference-invalid@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560" + integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg== + chardet@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" @@ -2659,6 +2702,11 @@ co@^4.6.0: resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= +collapse-white-space@^1.0.2: + version "1.0.6" + resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-1.0.6.tgz#e63629c0016665792060dbbeb79c42239d2c5287" + integrity sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ== + collect-v8-coverage@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.0.tgz#150ee634ac3650b71d9c985eb7f608942334feb1" @@ -3326,6 +3374,13 @@ escodegen@^1.9.1: optionalDependencies: source-map "~0.6.1" +eslint-config-prettier@6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.11.0.tgz#f6d2238c1290d01c859a8b5c1f7d352a0b0da8b1" + integrity sha512-oB8cpLWSAjOVFEJhhyMZh6NOEOtBVziaqdDQ86+qhDHFbZXoRTM7pNSvFRfW/W/L/LrQ38C99J5CGuRBBzBsdA== + dependencies: + get-stdin "^6.0.0" + eslint-config-prettier@^6.0.0: version "6.9.0" resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.9.0.tgz#430d24822e82f7deb1e22a435bfa3999fae4ad64" @@ -3396,6 +3451,18 @@ eslint-plugin-babel@5.3.0: dependencies: eslint-rule-composer "^0.3.0" +eslint-plugin-chai-expect@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-chai-expect/-/eslint-plugin-chai-expect-2.1.0.tgz#9dd1d8e5a80543fdec956f6aef7f83f2241ca92b" + integrity sha512-rd0/4mjMV6c3i0o4DKkWI4uaFN9DK707kW+/fDphaDI6HVgxXnhML9Xgt5vHnTXmSSnDhupuCFBgsEAEpchXmQ== + +eslint-plugin-cypress@2.11.1: + version "2.11.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-cypress/-/eslint-plugin-cypress-2.11.1.tgz#a945e2774b88211e2c706a059d431e262b5c2862" + integrity sha512-MxMYoReSO5+IZMGgpBZHHSx64zYPSPTpXDwsgW7ChlJTF/sA+obqRbHplxD6sBStE+g4Mi0LCLkG4t9liu//mQ== + dependencies: + globals "^11.12.0" + eslint-plugin-es@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-3.0.0.tgz#98cb1bc8ab0aa807977855e11ad9d1c9422d014b" @@ -3464,6 +3531,13 @@ eslint-plugin-import@^2.18.2: read-pkg-up "^2.0.0" resolve "^1.12.0" +eslint-plugin-jest@23.13.2: + version "23.13.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-23.13.2.tgz#7b7993b4e09be708c696b02555083ddefd7e4cc7" + integrity sha512-qZit+moTXTyZFNDqSIR88/L3rdBlTU7CuW6XmyErD2FfHEkdoLgThkRbiQjzgYnX6rfgLx3Ci4eJmF4Ui5v1Cw== + dependencies: + "@typescript-eslint/experimental-utils" "^2.5.0" + eslint-plugin-json@2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/eslint-plugin-json/-/eslint-plugin-json-2.1.1.tgz#7b9c4da2121f6f48d44efceb9a99ac0d4d12b299" @@ -3487,6 +3561,15 @@ eslint-plugin-jsx-a11y@6.2.3, eslint-plugin-jsx-a11y@^6.2.3: has "^1.0.3" jsx-ast-utils "^2.2.1" +eslint-plugin-markdown@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-markdown/-/eslint-plugin-markdown-1.0.2.tgz#79274bf17ce3ead48e4a55cbcb6d7ce735754280" + integrity sha512-BfvXKsO0K+zvdarNc801jsE/NTLmig4oKhZ1U3aSUgTf2dB/US5+CrfGxMsCK2Ki1vS1R3HPok+uYpufFndhzw== + dependencies: + object-assign "^4.0.1" + remark-parse "^5.0.0" + unified "^6.1.2" + eslint-plugin-no-inferred-method-name@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/eslint-plugin-no-inferred-method-name/-/eslint-plugin-no-inferred-method-name-2.0.0.tgz#99e2c9c921dfcb98c3874b427e26f8889f516c8e" @@ -3511,6 +3594,18 @@ eslint-plugin-optimize-regex@1.2.0: dependencies: regexp-tree "^0.1.20" +eslint-plugin-perf-standard@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-perf-standard/-/eslint-plugin-perf-standard-1.0.3.tgz#f2477073b40f7ae8c42093b9a08d84835d146b69" + integrity sha1-8kdwc7QPeujEIJO5oI2Eg10Ua2k= + +eslint-plugin-prettier@3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.3.tgz#ae116a0fc0e598fdae48743a4430903de5b4e6ca" + integrity sha512-+HG5jmu/dN3ZV3T6eCD7a4BlAySdN7mLIbJYo0z1cFQuI+r2DiTJEFeF68ots93PsnrMxbzIZ2S/ieX+mkrBeQ== + dependencies: + prettier-linter-helpers "^1.0.0" + eslint-plugin-prettier@^3.1.0: version "3.1.2" resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.2.tgz#432e5a667666ab84ce72f945c72f77d996a5c9ba" @@ -3578,11 +3673,28 @@ eslint-plugin-react@^7.14.3: resolve "^1.14.2" string.prototype.matchall "^4.0.2" +eslint-plugin-security-node@1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/eslint-plugin-security-node/-/eslint-plugin-security-node-1.0.12.tgz#b2573cdee01e9b66470a61b7a2377f197ecf1539" + integrity sha512-jd0iWPrbqIbu/P+0YKDz2Aqyqc8Y6jLFO66N2b/vjRQw8PSR/Jc3ef2ioPN+O7FAD1cqjImWnHrkoNW10hLzaA== + eslint-plugin-standard@4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-4.0.1.tgz#ff0519f7ffaff114f76d1bd7c3996eef0f6e20b4" integrity sha512-v/KBnfyaOMPmZc/dmc6ozOdWqekGp7bBGq4jLAecEfPGmfKiWS4sA8sC0LqiV9w5qmXAtXVn4M3p1jSyhY85SQ== +eslint-plugin-tree-shaking@1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-tree-shaking/-/eslint-plugin-tree-shaking-1.8.0.tgz#6ac08485481a5406142d0652bf894e45c46f3d5d" + integrity sha512-5jrqlyka6MCaV8efwAIIo/3cvmhurA4gUaFoTWoWw6wLhmHUS0/42NDKubKOMlQJXm5Z7/i4hbzyIcDXbHAnVw== + +eslint-plugin-xss@0.1.10: + version "0.1.10" + resolved "https://registry.yarnpkg.com/eslint-plugin-xss/-/eslint-plugin-xss-0.1.10.tgz#4d2dd121475cfd73c0062883f33e330c0c3db5ee" + integrity sha512-Wm2QIokqBq/IYi529xDXf9EOmVoQdAclaTEw1PNk+iyzyTiWssc1dqFz00PuB6nh01vA4phw0dnseY9b3Tsg1w== + dependencies: + requireindex "~1.1.0" + eslint-plugin-you-dont-need-lodash-underscore@6.10.0: version "6.10.0" resolved "https://registry.yarnpkg.com/eslint-plugin-you-dont-need-lodash-underscore/-/eslint-plugin-you-dont-need-lodash-underscore-6.10.0.tgz#63df0785ee1a07365ef77db907692f1ac928e000" @@ -3611,6 +3723,14 @@ eslint-scope@^5.0.0: esrecurse "^4.1.0" estraverse "^4.1.1" +eslint-scope@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.0.tgz#d0f971dfe59c69e0cada684b23d49dbf82600ce5" + integrity sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + eslint-utils@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" @@ -3630,10 +3750,15 @@ eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== -eslint@7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.1.0.tgz#d9a1df25e5b7859b0a3d86bb05f0940ab676a851" - integrity sha512-DfS3b8iHMK5z/YLSme8K5cge168I8j8o1uiVmFCgnnjxZQbCGyraF8bMl7Ju4yfBmCuxD7shOF7eqGkcuIHfsA== +eslint-visitor-keys@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.2.0.tgz#74415ac884874495f78ec2a97349525344c981fa" + integrity sha512-WFb4ihckKil6hu3Dp798xdzSfddwKKU3+nGniKF6HfeW6OLd2OUDEPP7TcHtB5+QXOKg2s6B2DaMPE1Nn/kxKQ== + +eslint@7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.2.0.tgz#d41b2e47804b30dbabb093a967fb283d560082e6" + integrity sha512-B3BtEyaDKC5MlfDa2Ha8/D6DsS4fju95zs0hjS3HdGazw+LNayai38A25qMppK37wWGWNYSPOR6oYzlz5MHsRQ== dependencies: "@babel/code-frame" "^7.0.0" ajv "^6.10.0" @@ -3641,10 +3766,10 @@ eslint@7.1.0: cross-spawn "^7.0.2" debug "^4.0.1" doctrine "^3.0.0" - eslint-scope "^5.0.0" + eslint-scope "^5.1.0" eslint-utils "^2.0.0" - eslint-visitor-keys "^1.1.0" - espree "^7.0.0" + eslint-visitor-keys "^1.2.0" + espree "^7.1.0" esquery "^1.2.0" esutils "^2.0.2" file-entry-cache "^5.0.1" @@ -3724,14 +3849,14 @@ espree@^6.1.2: acorn-jsx "^5.1.0" eslint-visitor-keys "^1.1.0" -espree@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-7.0.0.tgz#8a7a60f218e69f120a842dc24c5a88aa7748a74e" - integrity sha512-/r2XEx5Mw4pgKdyb7GNLQNsu++asx/dltf/CI8RFi9oGHxmQFgvLbc5Op4U6i8Oaj+kdslhJtVlEZeAqH5qOTw== +espree@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-7.1.0.tgz#a9c7f18a752056735bf1ba14cb1b70adc3a5ce1c" + integrity sha512-dcorZSyfmm4WTuTnE5Y7MEN1DyoPYy1ZR783QW1FJoenn7RailyWFsq/UL6ZAAA7uXurN9FIpYyUs3OfiIW+Qw== dependencies: - acorn "^7.1.1" + acorn "^7.2.0" acorn-jsx "^5.2.0" - eslint-visitor-keys "^1.1.0" + eslint-visitor-keys "^1.2.0" esprima@^3.1.3: version "3.1.3" @@ -3915,7 +4040,7 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: assign-symbols "^1.0.0" is-extendable "^1.0.1" -extend@~3.0.2: +extend@^3.0.0, extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== @@ -4244,7 +4369,7 @@ glob@^7.0.0, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: once "^1.3.0" path-is-absolute "^1.0.0" -globals@^11.1.0: +globals@^11.1.0, globals@^11.12.0: version "11.12.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== @@ -4511,7 +4636,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@^2.0.0, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -4585,6 +4710,19 @@ is-accessor-descriptor@^1.0.0: dependencies: kind-of "^6.0.0" +is-alphabetical@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d" + integrity sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg== + +is-alphanumerical@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz#7eb9a2431f855f6b1ef1a78e326df515696c4dbf" + integrity sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A== + dependencies: + is-alphabetical "^1.0.0" + is-decimal "^1.0.0" + is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" @@ -4604,7 +4742,7 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" -is-buffer@^1.1.5: +is-buffer@^1.1.4, is-buffer@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== @@ -4640,6 +4778,11 @@ is-date-object@^1.0.1: resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== +is-decimal@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5" + integrity sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw== + is-descriptor@^0.1.0: version "0.1.6" resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" @@ -4704,6 +4847,11 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" +is-hexadecimal@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" + integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw== + is-module@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" @@ -4721,6 +4869,11 @@ is-number@^7.0.0: resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== +is-plain-obj@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= + is-plain-object@^2.0.3, is-plain-object@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" @@ -4779,11 +4932,21 @@ is-typedarray@^1.0.0, is-typedarray@~1.0.0: resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= +is-whitespace-character@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz#0858edd94a95594c7c9dd0b5c174ec6e45ee4aa7" + integrity sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w== + is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== +is-word-character@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-word-character/-/is-word-character-1.0.4.tgz#ce0e73216f98599060592f62ff31354ddbeb0230" + integrity sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA== + is-wsl@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" @@ -6068,6 +6231,11 @@ map-visit@^1.0.0: dependencies: object-visit "^1.0.0" +markdown-escapes@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/markdown-escapes/-/markdown-escapes-1.0.4.tgz#c95415ef451499d7602b91095f3c8e8975f78535" + integrity sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg== + md5.js@^1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" @@ -6426,7 +6594,7 @@ oauth-sign@~0.9.0: resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== -object-assign@^4.1.1: +object-assign@^4.0.1, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= @@ -6684,6 +6852,18 @@ parse-asn1@^5.0.0: pbkdf2 "^3.0.3" safe-buffer "^5.1.1" +parse-entities@^1.1.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-1.2.2.tgz#c31bf0f653b6661354f8973559cb86dd1d5edf50" + integrity sha512-NzfpbxW/NPrzZ/yYSoQxyqUZMZXIdCfE0OIN4ESsnptHJECoUk3FZktxNuzQf4tjt5UEopnxpYJbvYuxIFDdsg== + dependencies: + character-entities "^1.0.0" + character-entities-legacy "^1.0.0" + character-reference-invalid "^1.0.0" + is-alphanumerical "^1.0.0" + is-decimal "^1.0.0" + is-hexadecimal "^1.0.0" + parse-json@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" @@ -7270,6 +7450,27 @@ regjsparser@^0.6.0: dependencies: jsesc "~0.5.0" +remark-parse@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-5.0.0.tgz#4c077f9e499044d1d5c13f80d7a98cf7b9285d95" + integrity sha512-b3iXszZLH1TLoyUzrATcTQUZrwNl1rE70rVdSruJFlDaJ9z5aMkhrG43Pp68OgfHndL/ADz6V69Zow8cTQu+JA== + dependencies: + collapse-white-space "^1.0.2" + is-alphabetical "^1.0.0" + is-decimal "^1.0.0" + is-whitespace-character "^1.0.0" + is-word-character "^1.0.0" + markdown-escapes "^1.0.0" + parse-entities "^1.1.0" + repeat-string "^1.5.4" + state-toggle "^1.0.0" + trim "0.0.1" + trim-trailing-lines "^1.0.0" + unherit "^1.0.4" + unist-util-remove-position "^1.0.0" + vfile-location "^2.0.0" + xtend "^4.0.1" + remove-trailing-separator@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" @@ -7280,11 +7481,16 @@ repeat-element@^1.1.2: resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== -repeat-string@^1.6.1: +repeat-string@^1.5.4, repeat-string@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= +replace-ext@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb" + integrity sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs= + request-promise-core@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.3.tgz#e9a3c081b51380dfea677336061fea879a829ee9" @@ -7922,6 +8128,11 @@ stack-utils@^2.0.2: dependencies: escape-string-regexp "^2.0.0" +state-toggle@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/state-toggle/-/state-toggle-1.0.3.tgz#e123b16a88e143139b09c6852221bc9815917dfe" + integrity sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ== + static-extend@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" @@ -8363,6 +8574,21 @@ tr46@^2.0.2: dependencies: punycode "^2.1.1" +trim-trailing-lines@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/trim-trailing-lines/-/trim-trailing-lines-1.1.3.tgz#7f0739881ff76657b7776e10874128004b625a94" + integrity sha512-4ku0mmjXifQcTVfYDfR5lpgV7zVqPg6zV9rdZmwOPqq0+Zq19xDqEgagqVbc4pOOShbncuAOIs59R3+3gcF3ZA== + +trim@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/trim/-/trim-0.0.1.tgz#5858547f6b290757ee95cccc666fb50084c460dd" + integrity sha1-WFhUf2spB1fulczMZm+1AITEYN0= + +trough@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" + integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== + ts-jest@26.0.0: version "26.0.0" resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.0.0.tgz#957b802978249aaf74180b9dcb17b4fd787ad6f3" @@ -8562,6 +8788,14 @@ typescript@^3.7.3: resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae" integrity sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw== +unherit@^1.0.4: + version "1.1.3" + resolved "https://registry.yarnpkg.com/unherit/-/unherit-1.1.3.tgz#6c9b503f2b41b262330c80e91c8614abdaa69c22" + integrity sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ== + dependencies: + inherits "^2.0.0" + xtend "^4.0.0" + unicode-canonical-property-names-ecmascript@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" @@ -8585,6 +8819,18 @@ unicode-property-aliases-ecmascript@^1.0.4: resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz#a9cc6cc7ce63a0a3023fc99e341b94431d405a57" integrity sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw== +unified@^6.1.2: + version "6.2.0" + resolved "https://registry.yarnpkg.com/unified/-/unified-6.2.0.tgz#7fbd630f719126d67d40c644b7e3f617035f6dba" + integrity sha512-1k+KPhlVtqmG99RaTbAv/usu85fcSRu3wY8X+vnsEhIxNP5VbVIDiXnLqyKIG+UMdyTg0ZX9EI6k2AfjJkHPtA== + dependencies: + bail "^1.0.0" + extend "^3.0.0" + is-plain-obj "^1.1.0" + trough "^1.0.0" + vfile "^2.0.0" + x-is-string "^0.1.0" + union-value@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" @@ -8609,6 +8855,37 @@ unique-slug@^2.0.0: dependencies: imurmurhash "^0.1.4" +unist-util-is@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-3.0.0.tgz#d9e84381c2468e82629e4a5be9d7d05a2dd324cd" + integrity sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A== + +unist-util-remove-position@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/unist-util-remove-position/-/unist-util-remove-position-1.1.4.tgz#ec037348b6102c897703eee6d0294ca4755a2020" + integrity sha512-tLqd653ArxJIPnKII6LMZwH+mb5q+n/GtXQZo6S6csPRs5zB0u79Yw8ouR3wTw8wxvdJFhpP6Y7jorWdCgLO0A== + dependencies: + unist-util-visit "^1.1.0" + +unist-util-stringify-position@^1.0.0, unist-util-stringify-position@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-1.1.2.tgz#3f37fcf351279dcbca7480ab5889bb8a832ee1c6" + integrity sha512-pNCVrk64LZv1kElr0N1wPiHEUoXNVFERp+mlTg/s9R5Lwg87f9bM/3sQB99w+N9D/qnM9ar3+AKDBwo/gm/iQQ== + +unist-util-visit-parents@^2.0.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-2.1.2.tgz#25e43e55312166f3348cae6743588781d112c1e9" + integrity sha512-DyN5vD4NE3aSeB+PXYNKxzGsfocxp6asDc2XXE3b0ekO2BaRUpBicbbUygfSvYfUz1IkmjFR1YF7dPklraMZ2g== + dependencies: + unist-util-is "^3.0.0" + +unist-util-visit@^1.1.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-1.4.1.tgz#4724aaa8486e6ee6e26d7ff3c8685960d560b1e3" + integrity sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw== + dependencies: + unist-util-visit-parents "^2.0.0" + universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" @@ -8734,6 +9011,28 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" +vfile-location@^2.0.0: + version "2.0.6" + resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-2.0.6.tgz#8a274f39411b8719ea5728802e10d9e0dff1519e" + integrity sha512-sSFdyCP3G6Ka0CEmN83A2YCMKIieHx0EDaj5IDP4g1pa5ZJ4FJDvpO0WODLxo4LUX4oe52gmSCK7Jw4SBghqxA== + +vfile-message@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-1.1.1.tgz#5833ae078a1dfa2d96e9647886cd32993ab313e1" + integrity sha512-1WmsopSGhWt5laNir+633LszXvZ+Z/lxveBf6yhGsqnQIhlhzooZae7zV6YVM1Sdkw68dtAW3ow0pOdPANugvA== + dependencies: + unist-util-stringify-position "^1.1.1" + +vfile@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/vfile/-/vfile-2.3.0.tgz#e62d8e72b20e83c324bc6c67278ee272488bf84a" + integrity sha512-ASt4mBUHcTpMKD/l5Q+WJXNtshlWxOogYyGYYrg4lt/vuRjC1EFQtlAofL5VmtVNIZJzWYFJjzGWZ0Gw8pzW1w== + dependencies: + is-buffer "^1.1.4" + replace-ext "1.0.0" + unist-util-stringify-position "^1.0.0" + vfile-message "^1.0.0" + vm-browserify@^1.0.1: version "1.1.2" resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" @@ -9024,6 +9323,11 @@ ws@^7.2.3: resolved "https://registry.yarnpkg.com/ws/-/ws-7.3.0.tgz#4b2f7f219b3d3737bc1a2fbf145d825b94d38ffd" integrity sha512-iFtXzngZVXPGgpTlP1rBqsUK82p9tKqsWRPg5L56egiljujJT3vGAYnHANvFxBieXrTFavhzhxW52jnaWV+w2w== +x-is-string@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/x-is-string/-/x-is-string-0.1.0.tgz#474b50865af3a49a9c4657f05acd145458f77d82" + integrity sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI= + xml-name-validator@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" @@ -9041,7 +9345,7 @@ xregexp@^4.3.0: dependencies: "@babel/runtime-corejs3" "^7.8.3" -xtend@^4.0.0, xtend@~4.0.1: +xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== diff --git a/packages/react-google-maps-api-marker-with-label/.editorconfig b/packages/react-google-maps-api-marker-with-label/.editorconfig new file mode 100644 index 000000000..ef7e215d9 --- /dev/null +++ b/packages/react-google-maps-api-marker-with-label/.editorconfig @@ -0,0 +1,13 @@ +root = true + +[*] +indent_style = space +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true +max_line_length = 80 +indent_size = 2 + +[*.md] +trim_trailing_whitespace = false diff --git a/packages/react-google-maps-api-marker-with-label/.eslintignore b/packages/react-google-maps-api-marker-with-label/.eslintignore new file mode 100644 index 000000000..3076368cb --- /dev/null +++ b/packages/react-google-maps-api-marker-with-label/.eslintignore @@ -0,0 +1,4 @@ +lib/ +dist/ +node_modules/ +types/ diff --git a/packages/react-google-maps-api-marker-with-label/.eslintrc.js b/packages/react-google-maps-api-marker-with-label/.eslintrc.js new file mode 100644 index 000000000..14a2e16a6 --- /dev/null +++ b/packages/react-google-maps-api-marker-with-label/.eslintrc.js @@ -0,0 +1,144 @@ +module.exports = { + parser: '@typescript-eslint/parser', + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/eslint-recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:cypress/recommended', + 'plugin:import/typescript', + 'plugin:jest/recommended', + 'plugin:json/recommended', + 'plugin:jsx-a11y/recommended', + 'plugin:optimize-regex/all', + 'plugin:promise/recommended', + 'plugin:react/recommended', + 'plugin:react-hooks/recommended', + 'plugin:react-perf/all', + 'standard', + 'standard-react', + // Prettier always last + 'prettier', + 'plugin:prettier/recommended', + 'prettier/@typescript-eslint', + 'prettier/react', + 'prettier/standard', + ], + plugins: [ + 'chai-expect', + 'import', // connects in extends + '@typescript-eslint', // connects in extends + 'react', // connects in extends + 'jsx-a11y', // connects in extends + 'react-hooks', // connects in extends + 'react-perf', // connects in extends + 'jest', // connects in extends + 'no-inferred-method-name', + 'optimize-regex', // connects in extends + 'promise', // connects in extends + 'cypress', // connects in extends + 'prettier', // connects in extends + 'standard', // connects in extends + 'markdown', + 'json', // connects in extends + 'xss', // unused + 'perf-standard', + 'es', + 'babel', // unused + 'tree-shaking', // unused + ], + settings: { + react: { + version: 'detect', + }, + node: { + allowModules: ['src'], + resolvePaths: [__dirname], + tryExtensions: ['.ts', '.tsx', '.js', '.jsx', '.json'], + }, + }, + env: { + 'cypress/globals': true, + browser: true, + node: true, + es6: true, + }, + globals: { + __DEV__: false, + __PROD__: false, + __PLAYER_DEBUG__: false, + __BASENAME__: false, + google: true, + }, + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features + sourceType: 'module', // Allows for the use of imports + }, + rules: { + camelcase: 'off', + 'jest/expect-expect': 'off', + 'no-useless-return': 'off', + 'node/no-missing-import': 'off', + 'node/no-missing-require': 'off', + 'node/no-unsupported-features/es-syntax': 'off', + 'sort-requires/sort-requires': 'off', + 'no-console': ['error', { allow: ['warn', 'error', 'info', 'table'] }], + 'no-unused-vars': 'off', + 'no-restricted-globals': [ + 'error', + { + name: 'name', + message: 'Use local parameter instead.', + }, + { + name: 'event', + message: 'Use local parameter instead.', + }, + { + name: 'fdescribe', + message: 'Do not commit fdescribe. Use describe instead.', + }, + ], + '@typescript-eslint/explicit-function-return-type': [ + 'warn', + { allowExpressions: true }, + ], + '@typescript-eslint/explicit-member-accessibility': 'off', + '@typescript-eslint/no-use-before-define': [ + 'error', + { functions: false, classes: false, typedefs: false }, + ], + '@typescript-eslint/no-unused-vars': [ + 'error', + { varsIgnorePattern: '^_', argsIgnorePattern: '^_' }, + ], + 'react-hooks/rules-of-hooks': 'error', + 'react-hooks/exhaustive-deps': 'warn', + 'optimize-regex/optimize-regex': 'warn', + 'es/no-async-iteration': 'error', + 'es/no-malformed-template-literals': 'error', + 'es/no-regexp-lookbehind-assertions': 'error', + 'es/no-regexp-named-capture-groups': 'error', + 'es/no-regexp-s-flag': 'error', + 'es/no-regexp-unicode-property-escapes': 'error', + 'chai-expect/missing-assertion': 2, + 'chai-expect/terminating-properties': 1, + 'no-inferred-method-name/no-inferred-method-name': 'error', + // "tree-shaking/no-side-effects-in-initialization": 2, + }, + overrides: [ + // Override some TypeScript rules just for .js files + { + files: ['*.js'], + rules: { + semi: ['error', 'never'], + 'jsx-quotes': ['error', 'prefer-single'], + '@typescript-eslint/no-var-requires': 'off', + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/explicit-module-boundary-types': 'off', + }, + }, + ], +} diff --git a/packages/react-google-maps-api-marker-with-label/.prettierrc.js b/packages/react-google-maps-api-marker-with-label/.prettierrc.js new file mode 100644 index 000000000..c47aa3352 --- /dev/null +++ b/packages/react-google-maps-api-marker-with-label/.prettierrc.js @@ -0,0 +1,9 @@ +module.exports = { + trailingComma: "es5", + tabWidth: 2, + semi: false, + singleQuote: true, + endOfLine: "lf", + bracketSpacing: true, + jsxSingleQuote: true, +} diff --git a/packages/react-google-maps-api-marker-with-label/README.md b/packages/react-google-maps-api-marker-with-label/README.md new file mode 100644 index 000000000..30b888a0e --- /dev/null +++ b/packages/react-google-maps-api-marker-with-label/README.md @@ -0,0 +1,13 @@ +# @react-google-maps/marker-with-label + +![logo](https://raw.githubusercontent.com/JustFly1984/react-google-maps-api/master/logo.png) + +[![npm package](https://img.shields.io/npm/v/@react-google-maps/marker-with-label)](https://www.npmjs.com/package/@react-google-maps/marker-with-label) +[![npm downloads](https://img.shields.io/npm/dt/@react-google-maps/marker-with-label)](https://www.npmjs.com/package/@react-google-maps/marker-with-label) +[![npm bundle size](https://img.shields.io/bundlephobia/min/@react-google-maps/marker-with-label)](https://www.npmjs.com/package/@react-google-maps/marker-with-label) +[![npm bundle size](https://img.shields.io/bundlephobia/min/@react-google-maps/marker-with-label)](https://www.npmjs.com/package/@react-google-maps/marker-with-label) +[![Join the community on Spectrum](https://withspectrum.github.io/badge/badge.svg)](https://spectrum.chat/react-google-maps) + +@react-google-maps/marker-with-label + +> This library is dependency of main project @react-google-maps/api diff --git a/packages/react-google-maps-api-marker-with-label/package.json b/packages/react-google-maps-api-marker-with-label/package.json new file mode 100644 index 000000000..e281000da --- /dev/null +++ b/packages/react-google-maps-api-marker-with-label/package.json @@ -0,0 +1,100 @@ +{ + "name": "@react-google-maps/marker-with-label", + "sideEffects": false, + "version": "1.9.3", + "description": "InfoBox for React.js Google Maps API", + "license": "MIT", + "author": { + "name": "Alexey Lyakhov", + "email": "justfly1984@gmail.com", + "url": "https://github.com/JustFly1984" + }, + "repository": { + "type": "git", + "url": "https://github.com/JustFly1984/react-google-maps-api.git", + "directory": "packages/react-google-maps-api-marker-with-label" + }, + "bugs": { + "url": "https://github.com/JustFly1984/react-google-maps-api/issues" + }, + "homepage": "https://react-google-maps-api-docs.netlify.app", + "publishConfig": { + "access": "public" + }, + "main": "dist/index.js", + "types": "dist/index.d.ts", + "unpkg": "dist/marker-with-label.umd.production.min.js", + "module": "dist/marker-with-label.esm.js", + "files": [ + "src/", + "dist/" + ], + "keywords": [ + "React", + "Google", + "Map", + "API", + "addons/InfoBox" + ], + "scripts": { + "prebuild": "rimraf dist", + "build": "npx tsdx build --name infoBox --format=cjs,esm,umd", + "clean": "rimraf ./package-lock.json ./yarn.lock ./node_modules/ && yarn", + "update": "yarn-check -u", + "lint": "npx eslint ./src/**/*.{ts,tsx}", + "pub": "yarn publish .", + "tc": "tsc -p ./tsconfig.json --noEmit --traceResolution", + "prepublishOnly": "yarn build" + }, + "dependencies": {}, + "devDependencies": { + "@getify/eslint-plugin-proper-arrows": "9.1.1", + "@types/babel-types": "7.0.7", + "@types/googlemaps": "3.39.6", + "@types/react-dom": "16.9.8", + "@typescript-eslint/eslint-plugin": "3.1.0", + "@typescript-eslint/parser": "3.1.0", + "awesome-typescript-loader": "5.2.1", + "eslint": "7.2.0", + "eslint-config-prettier": "6.11.0", + "eslint-config-standard": "14.1.1", + "eslint-config-standard-react": "9.2.0", + "eslint-import-resolver-typescript": "2.0.0", + "eslint-plugin-ascii": "1.0.0", + "eslint-plugin-babel": "5.3.0", + "eslint-plugin-chai-expect": "2.1.0", + "eslint-plugin-cypress": "2.11.1", + "eslint-plugin-filenames": "1.3.2", + "eslint-plugin-html": "6.0.2", + "eslint-plugin-import": "2.20.2", + "eslint-plugin-jest": "23.13.2", + "eslint-plugin-json": "2.1.1", + "eslint-plugin-jsx-a11y": "6.2.3", + "eslint-plugin-markdown": "1.0.2", + "eslint-plugin-no-inferred-method-name": "2.0.0", + "eslint-plugin-node": "11.1.0", + "eslint-plugin-optimize-regex": "1.2.0", + "eslint-plugin-perf-standard": "1.0.3", + "eslint-plugin-prettier": "3.1.3", + "eslint-plugin-promise": "4.2.1", + "eslint-plugin-react": "7.20.0", + "eslint-plugin-react-functional-set-state": "1.2.1", + "eslint-plugin-react-hooks": "4.0.4", + "eslint-plugin-react-perf": "3.2.3", + "eslint-plugin-security-node": "1.0.12", + "eslint-plugin-standard": "4.0.1", + "eslint-plugin-tree-shaking": "1.8.0", + "eslint-plugin-xss": "0.1.10", + "eslint-plugin-you-dont-need-lodash-underscore": "6.10.0", + "jest": "26.0.1", + "jest-cli": "26.0.1", + "react": "16.13.1", + "react-dom": "16.13.1", + "rimraf": "3.0.2", + "ts-jest": "26.1.0", + "tsdx": "0.13.2", + "typescript": "3.9.5", + "webpack": "4.43.0" + }, + "gitHead": "80167ddcc3d8e356dbf0b0c3a6292c6a3a989f83" +} diff --git a/packages/react-google-maps-api-marker-with-label/src/index.ts b/packages/react-google-maps-api-marker-with-label/src/index.ts new file mode 100644 index 000000000..5f36db347 --- /dev/null +++ b/packages/react-google-maps-api-marker-with-label/src/index.ts @@ -0,0 +1,39 @@ +/** + * @name MarkerWithLabel for V3 + * @version 1.1.9 [June 30, 2013] + * @author Gary Little (inspired by code from Marc Ridey of Google). + * @copyright Copyright 2012 Gary Little [gary at luxcentral.com] + * @fileoverview MarkerWithLabel extends the Google Maps JavaScript API V3 + * google.maps.Marker class. + *

+ * MarkerWithLabel allows you to define markers with associated labels. As you would expect, + * if the marker is draggable, so too will be the label. In addition, a marker with a label + * responds to all mouse events in the same manner as a regular marker. It also fires mouse + * events and "property changed" events just as a regular marker would. Version 1.1 adds + * support for the raiseOnDrag feature introduced in API V3.3. + *

+ * If you drag a marker by its label, you can cancel the drag and return the marker to its + * original position by pressing the Esc key. This doesn't work if you drag the marker + * itself because this feature is not (yet) supported in the google.maps.Marker class. + */ + +/*! + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Refactored to typescript by Alexey Lyakhov 2020 + */ + +export { MarkerWithLabel } from './marker-with-label' + +export { MarkerWithLabelOptions } from './types' diff --git a/packages/react-google-maps-api-marker-with-label/src/marker-with-label.ts b/packages/react-google-maps-api-marker-with-label/src/marker-with-label.ts new file mode 100644 index 000000000..a4cea3f5f --- /dev/null +++ b/packages/react-google-maps-api-marker-with-label/src/marker-with-label.ts @@ -0,0 +1,567 @@ +/** + * @param {Function} childCtor Child class. + * @param {Function} parentCtor Parent class. + */ +function inherits(childCtor, parentCtor) { + /** @constructor */ + function tempCtor() {}; + tempCtor.prototype = parentCtor.prototype; + childCtor.superClass_ = parentCtor.prototype; + childCtor.prototype = new tempCtor(); + /** @override */ + childCtor.prototype.constructor = childCtor; +} + +/** + * @param {Object} gMapsApi The Google Maps API instance (usually `google.maps`) + * @return {Function} The instantiable MarkerWithLabel class + */ +class MarkerWithLabel () { + /** + * This constructor creates a label and associates it with a marker. + * It is for the private use of the MarkerWithLabel class. + * @constructor + * @param {Marker} marker The marker with which the label is to be associated. + * @param {string} crossURL The URL of the cross image =. + * @param {string} handCursor The URL of the hand cursor. + * @private + */ + constructor(gMapsApi) { + + this.gMapsApi = gMapsApi + + } + + function MarkerLabel_(marker, crossURL, handCursorURL) { + this.marker_ = marker; + this.handCursorURL_ = marker.handCursorURL; + + this.labelDiv_ = document.createElement("div"); + this.labelDiv_.style.cssText = "position: absolute; overflow: hidden;"; + + // Set up the DIV for handling mouse events in the label. This DIV forms a transparent veil + // in the "overlayMouseTarget" pane, a veil that covers just the label. This is done so that + // events can be captured even if the label is in the shadow of a google.maps.InfoWindow. + // Code is included here to ensure the veil is always exactly the same size as the label. + this.eventDiv_ = document.createElement("div"); + this.eventDiv_.style.cssText = this.labelDiv_.style.cssText; + + // This is needed for proper behavior on MSIE: + this.eventDiv_.addEventListener('selectstart', function() { return false; }); + this.eventDiv_.addEventListener('dragstart', function() { return false; }); + + // Get the DIV for the "X" to be displayed when the marker is raised. + this.crossDiv_ = MarkerLabel_.getSharedCross(crossURL); + } + inherits(MarkerLabel_, this.gMapsApi.OverlayView); + + /** + * Returns the DIV for the cross used when dragging a marker when the + * raiseOnDrag parameter set to true. One cross is shared with all markers. + * @param {string} crossURL The URL of the cross image =. + * @private + */ + MarkerLabel_.getSharedCross = function getSharedCross(crossURL) { + var div; + if (typeof MarkerLabel_.getSharedCross.crossDiv === "undefined") { + div = document.createElement("img"); + div.style.cssText = "position: absolute; z-index: 1000002; display: none;"; + // Hopefully Google never changes the standard "X" attributes: + div.style.marginLeft = "-8px"; + div.style.marginTop = "-9px"; + div.src = crossURL; + MarkerLabel_.getSharedCross.crossDiv = div; + } + return MarkerLabel_.getSharedCross.crossDiv; + }; + + /** + * Adds the DIV representing the label to the DOM. This method is called + * automatically when the marker's setMap method is called. + * @private + */ + MarkerLabel_.prototype.onAdd = function onAdd() { + var me = this; + var cMouseIsDown = false; + var cDraggingLabel = false; + var cSavedZIndex; + var cLatOffset, cLngOffset; + var cIgnoreClick; + var cRaiseEnabled; + var cStartPosition; + var cStartCenter; + // Constants: + var cRaiseOffset = 20; + var cDraggingCursor = "url(" + this.handCursorURL_ + ")"; + + // Stops all processing of an event. + // + var cAbortEvent = function (e) { + if (e.preventDefault) { + e.preventDefault(); + } + e.cancelBubble = true; + if (e.stopPropagation) { + e.stopPropagation(); + } + }; + + var cStopBounce = function () { + me.marker_.setAnimation(null); + }; + + this.getPanes().markerLayer.appendChild(this.labelDiv_); + this.getPanes().overlayMouseTarget.appendChild(this.eventDiv_); + // One cross is shared with all markers, so only add it once: + if (typeof MarkerLabel_.getSharedCross.processed === "undefined") { + this.getPanes().markerLayer.appendChild(this.crossDiv_); + MarkerLabel_.getSharedCross.processed = true; + } + + this.listeners_ = [ + gMapsApi.event.addDomListener(this.eventDiv_, "mouseover", function (e) { + if (me.marker_.getDraggable() || me.marker_.getClickable()) { + this.style.cursor = "pointer"; + gMapsApi.event.trigger(me.marker_, "mouseover", e); + } + }), + gMapsApi.event.addDomListener(this.eventDiv_, "mouseout", function (e) { + if ((me.marker_.getDraggable() || me.marker_.getClickable()) && !cDraggingLabel) { + this.style.cursor = me.marker_.getCursor(); + gMapsApi.event.trigger(me.marker_, "mouseout", e); + } + }), + gMapsApi.event.addDomListener(this.eventDiv_, "mousedown", function (e) { + cDraggingLabel = false; + if (me.marker_.getDraggable()) { + cMouseIsDown = true; + this.style.cursor = cDraggingCursor; + } + if (me.marker_.getDraggable() || me.marker_.getClickable()) { + gMapsApi.event.trigger(me.marker_, "mousedown", e); + cAbortEvent(e); // Prevent map pan when starting a drag on a label + } + }), + gMapsApi.event.addDomListener(document, "mouseup", function (mEvent) { + var position; + if (cMouseIsDown) { + cMouseIsDown = false; + me.eventDiv_.style.cursor = "pointer"; + gMapsApi.event.trigger(me.marker_, "mouseup", mEvent); + } + if (cDraggingLabel) { + if (cRaiseEnabled) { // Lower the marker & label + position = me.getProjection().fromLatLngToDivPixel(me.marker_.getPosition()); + position.y += cRaiseOffset; + me.marker_.setPosition(me.getProjection().fromDivPixelToLatLng(position)); + // This is not the same bouncing style as when the marker portion is dragged, + // but it will have to do: + try { // Will fail if running Google Maps API earlier than V3.3 + me.marker_.setAnimation(gMapsApi.Animation.BOUNCE); + setTimeout(cStopBounce, 1406); + } catch (e) {} + } + me.crossDiv_.style.display = "none"; + me.marker_.setZIndex(cSavedZIndex); + cIgnoreClick = true; // Set flag to ignore the click event reported after a label drag + cDraggingLabel = false; + mEvent.latLng = me.marker_.getPosition(); + gMapsApi.event.trigger(me.marker_, "dragend", mEvent); + } + }), + gMapsApi.event.addListener(me.marker_.getMap(), "mousemove", function (mEvent) { + var position; + if (cMouseIsDown) { + if (cDraggingLabel) { + // Change the reported location from the mouse position to the marker position: + mEvent.latLng = new gMapsApi.LatLng(mEvent.latLng.lat() - cLatOffset, mEvent.latLng.lng() - cLngOffset); + position = me.getProjection().fromLatLngToDivPixel(mEvent.latLng); + if (cRaiseEnabled) { + me.crossDiv_.style.left = position.x + "px"; + me.crossDiv_.style.top = position.y + "px"; + me.crossDiv_.style.display = ""; + position.y -= cRaiseOffset; + } + me.marker_.setPosition(me.getProjection().fromDivPixelToLatLng(position)); + if (cRaiseEnabled) { // Don't raise the veil; this hack needed to make MSIE act properly + me.eventDiv_.style.top = (position.y + cRaiseOffset) + "px"; + } + gMapsApi.event.trigger(me.marker_, "drag", mEvent); + } else { + // Calculate offsets from the click point to the marker position: + cLatOffset = mEvent.latLng.lat() - me.marker_.getPosition().lat(); + cLngOffset = mEvent.latLng.lng() - me.marker_.getPosition().lng(); + cSavedZIndex = me.marker_.getZIndex(); + cStartPosition = me.marker_.getPosition(); + cStartCenter = me.marker_.getMap().getCenter(); + cRaiseEnabled = me.marker_.get("raiseOnDrag"); + cDraggingLabel = true; + me.marker_.setZIndex(1000000); // Moves the marker & label to the foreground during a drag + mEvent.latLng = me.marker_.getPosition(); + gMapsApi.event.trigger(me.marker_, "dragstart", mEvent); + } + } + }), + gMapsApi.event.addDomListener(document, "keydown", function (e) { + if (cDraggingLabel) { + if (e.keyCode === 27) { // Esc key + cRaiseEnabled = false; + me.marker_.setPosition(cStartPosition); + me.marker_.getMap().setCenter(cStartCenter); + gMapsApi.event.trigger(document, "mouseup", e); + } + } + }), + gMapsApi.event.addDomListener(this.eventDiv_, "click", function (e) { + if (me.marker_.getDraggable() || me.marker_.getClickable()) { + if (cIgnoreClick) { // Ignore the click reported when a label drag ends + cIgnoreClick = false; + } else { + gMapsApi.event.trigger(me.marker_, "click", e); + cAbortEvent(e); // Prevent click from being passed on to map + } + } + }), + gMapsApi.event.addDomListener(this.eventDiv_, "dblclick", function (e) { + if (me.marker_.getDraggable() || me.marker_.getClickable()) { + gMapsApi.event.trigger(me.marker_, "dblclick", e); + cAbortEvent(e); // Prevent map zoom when double-clicking on a label + } + }), + gMapsApi.event.addListener(this.marker_, "dragstart", function (mEvent) { + if (!cDraggingLabel) { + cRaiseEnabled = this.get("raiseOnDrag"); + } + }), + gMapsApi.event.addListener(this.marker_, "drag", function (mEvent) { + if (!cDraggingLabel) { + if (cRaiseEnabled) { + me.setPosition(cRaiseOffset); + // During a drag, the marker's z-index is temporarily set to 1000000 to + // ensure it appears above all other markers. Also set the label's z-index + // to 1000000 (plus or minus 1 depending on whether the label is supposed + // to be above or below the marker). + me.labelDiv_.style.zIndex = 1000000 + (this.get("labelInBackground") ? -1 : +1); + } + } + }), + gMapsApi.event.addListener(this.marker_, "dragend", function (mEvent) { + if (!cDraggingLabel) { + if (cRaiseEnabled) { + me.setPosition(0); // Also restores z-index of label + } + } + }), + gMapsApi.event.addListener(this.marker_, "position_changed", function () { + me.setPosition(); + }), + gMapsApi.event.addListener(this.marker_, "zindex_changed", function () { + me.setZIndex(); + }), + gMapsApi.event.addListener(this.marker_, "visible_changed", function () { + me.setVisible(); + }), + gMapsApi.event.addListener(this.marker_, "labelvisible_changed", function () { + me.setVisible(); + }), + gMapsApi.event.addListener(this.marker_, "title_changed", function () { + me.setTitle(); + }), + gMapsApi.event.addListener(this.marker_, "labelcontent_changed", function () { + me.setContent(); + }), + gMapsApi.event.addListener(this.marker_, "labelanchor_changed", function () { + me.setAnchor(); + }), + gMapsApi.event.addListener(this.marker_, "labelclass_changed", function () { + me.setStyles(); + }), + gMapsApi.event.addListener(this.marker_, "labelstyle_changed", function () { + me.setStyles(); + }) + ]; + }; + + /** + * Removes the DIV for the label from the DOM. It also removes all event handlers. + * This method is called automatically when the marker's setMap(null) + * method is called. + * @private + */ + MarkerLabel_.prototype.onRemove = function onRemove() { + var i; + if (this.labelDiv_.parentNode) { + this.labelDiv_.parentNode.removeChild(this.labelDiv_); + this.eventDiv_.parentNode.removeChild(this.eventDiv_); + } + + // Remove event listeners: + if (this.listeners_) { + for (i = 0; i < this.listeners_.length; i++) { + gMapsApi.event.removeListener(this.listeners_[i]); + } + } + }; + + /** + * Draws the label on the map. + * @private + */ + MarkerLabel_.prototype.draw = function draw() { + this.setContent(); + this.setTitle(); + this.setStyles(); + }; + + /** + * Sets the content of the label. + * The content can be plain text or an HTML DOM node. + * @private + */ + MarkerLabel_.prototype.setContent = function setContent() { + var content = this.marker_.get("labelContent"); + if (typeof content.nodeType === "undefined") { + this.labelDiv_.innerHTML = content; + this.eventDiv_.innerHTML = this.labelDiv_.innerHTML; + } else { + // Remove current content + while (this.labelDiv_.lastChild) { + this.labelDiv_.removeChild(this.labelDiv_.lastChild); + } + + while (this.eventDiv_.lastChild) { + this.eventDiv_.removeChild(this.eventDiv_.lastChild); + } + + this.labelDiv_.appendChild(content); + content = content.cloneNode(true); + this.eventDiv_.appendChild(content); + } + }; + + /** + * Sets the content of the tool tip for the label. It is + * always set to be the same as for the marker itself. + * @private + */ + MarkerLabel_.prototype.setTitle = function setTitle() { + this.eventDiv_.title = this.marker_.getTitle() || ""; + }; + + /** + * Sets the style of the label by setting the style sheet and applying + * other specific styles requested. + * @private + */ + MarkerLabel_.prototype.setStyles = function () { + var i, labelStyle; + + // Apply style values from the style sheet defined in the labelClass parameter: + this.labelDiv_.className = this.marker_.get("labelClass"); + this.eventDiv_.className = this.labelDiv_.className; + + // Clear existing inline style values: + this.labelDiv_.style.cssText = ""; + this.eventDiv_.style.cssText = ""; + // Apply style values defined in the labelStyle parameter: + labelStyle = this.marker_.get("labelStyle"); + for (i in labelStyle) { + if (labelStyle.hasOwnProperty(i)) { + this.labelDiv_.style[i] = labelStyle[i]; + this.eventDiv_.style[i] = labelStyle[i]; + } + } + this.setMandatoryStyles(); + }; + + /** + * Sets the mandatory styles to the DIV representing the label as well as to the + * associated event DIV. This includes setting the DIV position, z-index, and visibility. + * @private + */ + MarkerLabel_.prototype.setMandatoryStyles = function () { + this.labelDiv_.style.position = "absolute"; + this.labelDiv_.style.overflow = "hidden"; + // Make sure the opacity setting causes the desired effect on MSIE: + if (typeof this.labelDiv_.style.opacity !== "undefined" && this.labelDiv_.style.opacity !== "") { + this.labelDiv_.style.MsFilter = "\"progid:DXImageTransform.Microsoft.Alpha(opacity=" + (this.labelDiv_.style.opacity * 100) + ")\""; + this.labelDiv_.style.filter = "alpha(opacity=" + (this.labelDiv_.style.opacity * 100) + ")"; + } + + this.eventDiv_.style.position = this.labelDiv_.style.position; + this.eventDiv_.style.overflow = this.labelDiv_.style.overflow; + this.eventDiv_.style.opacity = 0.01; // Don't use 0; DIV won't be clickable on MSIE + this.eventDiv_.style.MsFilter = "\"progid:DXImageTransform.Microsoft.Alpha(opacity=1)\""; + this.eventDiv_.style.filter = "alpha(opacity=1)"; // For MSIE + + this.setAnchor(); + this.setPosition(); // This also updates z-index, if necessary. + this.setVisible(); + }; + + /** + * Sets the anchor point of the label. + * @private + */ + MarkerLabel_.prototype.setAnchor = function () { + var anchor = this.marker_.get("labelAnchor"); + this.labelDiv_.style.marginLeft = -anchor.x + "px"; + this.labelDiv_.style.marginTop = -anchor.y + "px"; + this.eventDiv_.style.marginLeft = -anchor.x + "px"; + this.eventDiv_.style.marginTop = -anchor.y + "px"; + }; + + /** + * Sets the position of the label. The z-index is also updated, if necessary. + * @private + */ + MarkerLabel_.prototype.setPosition = function (yOffset) { + var position = this.getProjection().fromLatLngToDivPixel(this.marker_.getPosition()); + if (typeof yOffset === "undefined") { + yOffset = 0; + } + this.labelDiv_.style.left = Math.round(position.x) + "px"; + this.labelDiv_.style.top = Math.round(position.y - yOffset) + "px"; + this.eventDiv_.style.left = this.labelDiv_.style.left; + this.eventDiv_.style.top = this.labelDiv_.style.top; + + this.setZIndex(); + }; + + /** + * Sets the z-index of the label. If the marker's z-index property has not been defined, the z-index + * of the label is set to the vertical coordinate of the label. This is in keeping with the default + * stacking order for Google Maps: markers to the south are in front of markers to the north. + * @private + */ + MarkerLabel_.prototype.setZIndex = function () { + var zAdjust = (this.marker_.get("labelInBackground") ? -1 : +1); + if (typeof this.marker_.getZIndex() === "undefined") { + this.labelDiv_.style.zIndex = parseInt(this.labelDiv_.style.top, 10) + zAdjust; + this.eventDiv_.style.zIndex = this.labelDiv_.style.zIndex; + } else { + this.labelDiv_.style.zIndex = this.marker_.getZIndex() + zAdjust; + this.eventDiv_.style.zIndex = this.labelDiv_.style.zIndex; + } + }; + + /** + * Sets the visibility of the label. The label is visible only if the marker itself is + * visible (i.e., its visible property is true) and the labelVisible property is true. + * @private + */ + MarkerLabel_.prototype.setVisible = function () { + if (this.marker_.get("labelVisible")) { + this.labelDiv_.style.display = this.marker_.getVisible() ? "block" : "none"; + } else { + this.labelDiv_.style.display = "none"; + } + this.eventDiv_.style.display = this.labelDiv_.style.display; + }; + + /** + * @name MarkerWithLabelOptions + * @class This class represents the optional parameter passed to the {@link MarkerWithLabel} constructor. + * The properties available are the same as for google.maps.Marker with the addition + * of the properties listed below. To change any of these additional properties after the labeled + * marker has been created, call google.maps.Marker.set(propertyName, propertyValue). + *

+ * When any of these properties changes, a property changed event is fired. The names of these + * events are derived from the name of the property and are of the form propertyname_changed. + * For example, if the content of the label changes, a labelcontent_changed event + * is fired. + *

+ * @property {string|Node} [labelContent] The content of the label (plain text or an HTML DOM node). + * @property {Point} [labelAnchor] By default, a label is drawn with its anchor point at (0,0) so + * that its top left corner is positioned at the anchor point of the associated marker. Use this + * property to change the anchor point of the label. For example, to center a 50px-wide label + * beneath a marker, specify a labelAnchor of google.maps.Point(25, 0). + * (Note: x-values increase to the right and y-values increase to the top.) + * @property {string} [labelClass] The name of the CSS class defining the styles for the label. + * Note that style values for position, overflow, top, + * left, zIndex, display, marginLeft, and + * marginTop are ignored; these styles are for internal use only. + * @property {Object} [labelStyle] An object literal whose properties define specific CSS + * style values to be applied to the label. Style values defined here override those that may + * be defined in the labelClass style sheet. If this property is changed after the + * label has been created, all previously set styles (except those defined in the style sheet) + * are removed from the label before the new style values are applied. + * Note that style values for position, overflow, top, + * left, zIndex, display, marginLeft, and + * marginTop are ignored; these styles are for internal use only. + * @property {boolean} [labelInBackground] A flag indicating whether a label that overlaps its + * associated marker should appear in the background (i.e., in a plane below the marker). + * The default is false, which causes the label to appear in the foreground. + * @property {boolean} [labelVisible] A flag indicating whether the label is to be visible. + * The default is true. Note that even if labelVisible is + * true, the label will not be visible unless the associated marker is also + * visible (i.e., unless the marker's visible property is true). + * @property {boolean} [raiseOnDrag] A flag indicating whether the label and marker are to be + * raised when the marker is dragged. The default is true. If a draggable marker is + * being created and a version of Google Maps API earlier than V3.3 is being used, this property + * must be set to false. + * @property {boolean} [optimized] A flag indicating whether rendering is to be optimized for the + * marker. Important: The optimized rendering technique is not supported by MarkerWithLabel, + * so the value of this parameter is always forced to false. + * @property {string} [crossImage="http://maps.gstatic.com/intl/en_us/mapfiles/drag_cross_67_16.png"] + * The URL of the cross image to be displayed while dragging a marker. + * @property {string} [handCursor="http://maps.gstatic.com/intl/en_us/mapfiles/closedhand_8_8.cur"] + * The URL of the cursor to be displayed while dragging a marker. + */ + /** + * Creates a MarkerWithLabel with the options specified in {@link MarkerWithLabelOptions}. + * @constructor + * @param {MarkerWithLabelOptions} [opt_options] The optional parameters. + */ + function MarkerWithLabel(opt_options) { + opt_options = opt_options || {}; + opt_options.labelContent = opt_options.labelContent || ""; + opt_options.labelAnchor = opt_options.labelAnchor || new gMapsApi.Point(0, 0); + opt_options.labelClass = opt_options.labelClass || "markerLabels"; + opt_options.labelStyle = opt_options.labelStyle || {}; + opt_options.labelInBackground = opt_options.labelInBackground || false; + if (typeof opt_options.labelVisible === "undefined") { + opt_options.labelVisible = true; + } + if (typeof opt_options.raiseOnDrag === "undefined") { + opt_options.raiseOnDrag = true; + } + if (typeof opt_options.clickable === "undefined") { + opt_options.clickable = true; + } + if (typeof opt_options.draggable === "undefined") { + opt_options.draggable = false; + } + if (typeof opt_options.optimized === "undefined") { + opt_options.optimized = false; + } + opt_options.crossImage = opt_options.crossImage || "http" + (document.location.protocol === "https:" ? "s" : "") + "://maps.gstatic.com/intl/en_us/mapfiles/drag_cross_67_16.png"; + opt_options.handCursor = opt_options.handCursor || "http" + (document.location.protocol === "https:" ? "s" : "") + "://maps.gstatic.com/intl/en_us/mapfiles/closedhand_8_8.cur"; + opt_options.optimized = false; // Optimized rendering is not supported + + this.label = new MarkerLabel_(this, opt_options.crossImage, opt_options.handCursor); // Bind the label to the marker + + // Call the parent constructor. It calls Marker.setValues to initialize, so all + // the new parameters are conveniently saved and can be accessed with get/set. + // Marker.set triggers a property changed event (called "propertyname_changed") + // that the marker label listens for in order to react to state changes. + gMapsApi.Marker.apply(this, arguments); + } + inherits(MarkerWithLabel, gMapsApi.Marker); + + /** + * Overrides the standard Marker setMap function. + * @param {Map} theMap The map to which the marker is to be added. + * @private + */ + MarkerWithLabel.prototype.setMap = function (theMap) { + + // Call the inherited function... + gMapsApi.Marker.prototype.setMap.apply(this, arguments); + + // ... then deal with the label: + this.label.setMap(theMap); + }; + + return MarkerWithLabel; +} diff --git a/packages/react-google-maps-api-marker-with-label/src/types.tsx b/packages/react-google-maps-api-marker-with-label/src/types.tsx new file mode 100644 index 000000000..83f931d96 --- /dev/null +++ b/packages/react-google-maps-api-marker-with-label/src/types.tsx @@ -0,0 +1,20 @@ +// export interface InfoBoxOptions { +// alignBottom?: boolean +// boxClass?: string +// boxStyle?: { +// [key: string]: any +// } +// closeBoxMargin?: string +// closeBoxURL?: string +// content?: string | Node +// disableAutoPan?: boolean +// enableEventPropagation?: boolean +// infoBoxClearance?: google.maps.Size +// isHidden?: boolean +// maxWidth?: number +// pixelOffset?: google.maps.Size +// position?: google.maps.LatLng +// pane?: string +// visible?: boolean +// zIndex?: number +// } diff --git a/packages/react-google-maps-api-storybook/.editorconfig b/packages/react-google-maps-api-storybook/.editorconfig index d7ad826cb..ef7e215d9 100644 --- a/packages/react-google-maps-api-storybook/.editorconfig +++ b/packages/react-google-maps-api-storybook/.editorconfig @@ -6,7 +6,7 @@ end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true -max_line_length = 100 +max_line_length = 80 indent_size = 2 [*.md] diff --git a/packages/react-google-maps-api-storybook/.eslintrc.js b/packages/react-google-maps-api-storybook/.eslintrc.js index 11d338308..df036d597 100644 --- a/packages/react-google-maps-api-storybook/.eslintrc.js +++ b/packages/react-google-maps-api-storybook/.eslintrc.js @@ -1,35 +1,35 @@ module.exports = { - parser: "babel-eslint", + parser: 'babel-eslint', extends: [ - "plugin:you-dont-need-lodash-underscore/compatible", - "eslint:recommended", - "plugin:import/errors", - "plugin:import/warnings", - "plugin:react/recommended", - "plugin:react-perf/recommended", - "standard", - "standard-react", - "plugin:jsx-a11y/recommended", + 'plugin:you-dont-need-lodash-underscore/compatible', + 'eslint:recommended', + 'plugin:import/errors', + 'plugin:import/warnings', + 'plugin:react/recommended', + 'plugin:react-perf/recommended', + 'standard', + 'standard-react', + 'plugin:jsx-a11y/recommended', 'plugin:css-modules/recommended' ], plugins: [ - "you-dont-need-lodash-underscore", - "json", - "babel", - "import", - "filenames", - "jsx-a11y", - "html", - "ascii", - "promise", - "promiseparams", - "react", - "optimize-regex", - "react-perf", - "standard", + 'you-dont-need-lodash-underscore', + 'json', + 'babel', + 'import', + 'filenames', + 'jsx-a11y', + 'html', + 'ascii', + 'promise', + 'promiseparams', + 'react', + 'optimize-regex', + 'react-perf', + 'standard', 'css-modules', - "no-inferred-method-name", - "react-functional-set-state", + 'no-inferred-method-name', + 'react-functional-set-state', ], env: { browser: true, @@ -43,68 +43,68 @@ module.exports = { }, settings: { ecmascript: 6, - "import/resolver": "webpack", + 'import/resolver': 'webpack', }, rules: { - "ascii/valid-name": 2, - "optimize-regex/optimize-regex": "warn", - "promiseparams/promiseparams": 2, - "filenames/no-index": 0, - "filenames/match-regex": [2, "^[a-z0-9-.]+$", true], - "filenames/match-exported": [2, ["camel", "kebab", null]], - "template-curly-spacing": ["error", "never"], - indent: ["error", 2], - "comma-dangle": [ - "error", + 'ascii/valid-name': 2, + 'optimize-regex/optimize-regex': 'warn', + 'promiseparams/promiseparams': 2, + 'filenames/no-index': 0, + 'filenames/match-regex': [2, '^[a-z0-9-.]+$', true], + 'filenames/match-exported': [2, ['camel', 'kebab', null]], + 'template-curly-spacing': ['error', 'never'], + indent: ['error', 2], + 'comma-dangle': [ + 'error', { - objects: "only-multiline", - arrays: "only-multiline", - imports: "only-multiline", - exports: "never", - functions: "never", + objects: 'only-multiline', + arrays: 'only-multiline', + imports: 'only-multiline', + exports: 'never', + functions: 'never', }, ], - "react-functional-set-state/no-this-state-props": 2, - "no-void": 2, - "no-restricted-globals": 2, - "no-use-before-define": 2, - "func-names": 1, - "no-unused-vars": 2, - "guard-for-in": 2, - "no-restricted-syntax": 2, - "jsx-a11y/label-has-for": "off", - "no-console": "off", + 'react-functional-set-state/no-this-state-props': 2, + 'no-void': 2, + 'no-restricted-globals': 2, + 'no-use-before-define': 2, + 'func-names': 1, + 'no-unused-vars': 2, + 'guard-for-in': 2, + 'no-restricted-syntax': 2, + 'jsx-a11y/label-has-for': 'off', + 'no-console': 'off', // 'react/no-typos': 'off', - "max-len": "off", - "no-nested-ternary": "off", + 'max-len': 'off', + 'no-nested-ternary': 'off', camelcase: [ 2, { - properties: "never", + properties: 'never', }, ], - "react-redux/prefer-separate-component-file": "off", - "react/destructuring-assignment": "off", - "babel/no-invalid-this": 1, - "babel/semi": 0, - "spaced-comment": 0, - "brace-style": 0, - "no-trailing-spaces": 0, - "import/default": 2, - "import/no-unresolved": [ + 'react-redux/prefer-separate-component-file': 'off', + 'react/destructuring-assignment': 'off', + 'babel/no-invalid-this': 1, + 'babel/semi': 0, + 'spaced-comment': 0, + 'brace-style': 0, + 'no-trailing-spaces': 0, + 'import/default': 2, + 'import/no-unresolved': [ 2, { commonjs: true, amd: true, }, ], - "import/named": 2, - "import/namespace": 2, - "import/export": 2, - "import/no-duplicates": 2, - "import/imports-first": 2, + 'import/named': 2, + 'import/namespace': 2, + 'import/export': 2, + 'import/no-duplicates': 2, + 'import/imports-first': 2, }, parserOptions: { - sourceType: "module", + sourceType: 'module', }, } diff --git a/packages/react-google-maps-api-storybook/package.json b/packages/react-google-maps-api-storybook/package.json index e3f3dd665..b83817e01 100644 --- a/packages/react-google-maps-api-storybook/package.json +++ b/packages/react-google-maps-api-storybook/package.json @@ -22,7 +22,7 @@ "clean": "rimraf ./package-lock.json ./yarn.lock ./node_modules/ && yarn" }, "dependencies": { - "@react-google-maps/api": "1.9.5" + "@react-google-maps/api": "2.0.0-alpha" }, "devDependencies": { "@babel/core": "7.10.2", @@ -30,7 +30,7 @@ "@storybook/react": "5.3.19", "babel-eslint": "10.1.0", "babel-loader": "8.1.0", - "eslint": "7.1.0", + "eslint": "7.2.0", "eslint-config-standard": "14.1.1", "eslint-config-standard-react": "9.2.0", "eslint-import-resolver-webpack": "0.12.1", diff --git a/packages/react-google-maps-api-storybook/yarn.lock b/packages/react-google-maps-api-storybook/yarn.lock index e992d462a..648d26ba4 100644 --- a/packages/react-google-maps-api-storybook/yarn.lock +++ b/packages/react-google-maps-api-storybook/yarn.lock @@ -1223,26 +1223,26 @@ react-lifecycles-compat "^3.0.4" warning "^3.0.0" -"@react-google-maps/api@1.9.5": - version "1.9.5" - resolved "https://registry.yarnpkg.com/@react-google-maps/api/-/api-1.9.5.tgz#5b99d7397cdbb6c48c16623d63592df9a6cfffde" - integrity sha512-DB8Zv+ADwhHdulwec7k9yoMqpgK2VnaGD//rlZSUsDj1gafECFgxOEMcmjPSCDfFCSvX6qr5VVZJqBvrlpkm3Q== - dependencies: - "@react-google-maps/infobox" "1.9.3" - "@react-google-maps/marker-clusterer" "1.9.3" - acorn "^7.2.0" - acorn-jsx "^5.2.0" +"@react-google-maps/api@2.0.0-alpha": + version "2.0.0-alpha" + resolved "https://registry.yarnpkg.com/@react-google-maps/api/-/api-2.0.0-alpha.tgz#0f65bda24ac58af42cffebdbeba2b57c9ab425af" + integrity sha512-cqvk5gYdsyD7hKCyj/N7xrl8lvXw64NpFh7VmgclNW7fxzOwwDd49Qtr+jsD+x8ELQ3/IIzsH37ebBxKnuYMrg== + dependencies: + "@react-google-maps/infobox" "2.0.0-alpha" + "@react-google-maps/marker-clusterer" "2.0.0-alpha" + acorn "7.2.0" + acorn-jsx "5.2.0" invariant "2.2.4" -"@react-google-maps/infobox@1.9.3": - version "1.9.3" - resolved "https://registry.yarnpkg.com/@react-google-maps/infobox/-/infobox-1.9.3.tgz#90a32d57527f5f0476f2fcb41556016b650cc4a3" - integrity sha512-e2EoeS+VSBsU4Gol3m3eaj9n1UGmp4Sz1ORpYHq0TJI2zRNwS7C2rGLe4aT0tHMXcaPSfkPR811IKtmc54ItUQ== +"@react-google-maps/infobox@2.0.0-alpha": + version "2.0.0-alpha" + resolved "https://registry.yarnpkg.com/@react-google-maps/infobox/-/infobox-2.0.0-alpha.tgz#d9fb7b1f091466460e5cc7a3a2c9de4c4b831a3c" + integrity sha512-QOHyH1OfFvubpNB8/U4VSUcOVizIdo4R9jfQBN3klzV8T2h0JA3SQ9bi4isBHSINssvBc7rhAdz0PKe19fkc/w== -"@react-google-maps/marker-clusterer@1.9.3": - version "1.9.3" - resolved "https://registry.yarnpkg.com/@react-google-maps/marker-clusterer/-/marker-clusterer-1.9.3.tgz#6acb6a12cffeef04f11549aaf0a43e6135578116" - integrity sha512-fJoNmtHewep2wM4PnCtpPn3wImUPHBhCyz0YqOx1AxRg8zOwCOauPSMon3xKtGP7m5AmrAZpiYY51vBkubH/aA== +"@react-google-maps/marker-clusterer@2.0.0-alpha": + version "2.0.0-alpha" + resolved "https://registry.yarnpkg.com/@react-google-maps/marker-clusterer/-/marker-clusterer-2.0.0-alpha.tgz#4e55f1ab664a12a227104dc17b999c1cca5d99a3" + integrity sha512-SiDkSBQp5YPcbWGnLMNEzqJuhKP1u455o4h1MnqDLNsuEMjCT/Z8BdgpV+tuFFf4fDOpd5PeD3gEVwtPkcoH8A== "@storybook/addons@5.3.19": version "5.3.19" @@ -2045,21 +2045,21 @@ accepts@~1.3.7: mime-types "~2.1.24" negotiator "0.6.2" -acorn-jsx@^5.2.0: +acorn-jsx@5.2.0, acorn-jsx@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.2.0.tgz#4c66069173d6fdd68ed85239fc256226182b2ebe" integrity sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ== +acorn@7.2.0, acorn@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.2.0.tgz#17ea7e40d7c8640ff54a694c889c26f31704effe" + integrity sha512-apwXVmYVpQ34m/i71vrApRrRKCWQnZZF1+npOD0WV5xZFfwWOmKGQ2RWlfdy9vWITsenisM8M0Qeq8agcFHNiQ== + acorn@^6.2.1, acorn@^6.4.1: version "6.4.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474" integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA== -acorn@^7.1.1, acorn@^7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.2.0.tgz#17ea7e40d7c8640ff54a694c889c26f31704effe" - integrity sha512-apwXVmYVpQ34m/i71vrApRrRKCWQnZZF1+npOD0WV5xZFfwWOmKGQ2RWlfdy9vWITsenisM8M0Qeq8agcFHNiQ== - address@1.1.2, address@^1.0.1: version "1.1.2" resolved "https://registry.yarnpkg.com/address/-/address-1.1.2.tgz#bf1116c9c758c51b7a933d296b72c221ed9428b6" @@ -4352,10 +4352,10 @@ eslint-scope@^4.0.3: esrecurse "^4.1.0" estraverse "^4.1.1" -eslint-scope@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.0.0.tgz#e87c8887c73e8d1ec84f1ca591645c358bfc8fb9" - integrity sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw== +eslint-scope@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.0.tgz#d0f971dfe59c69e0cada684b23d49dbf82600ce5" + integrity sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w== dependencies: esrecurse "^4.1.0" estraverse "^4.1.1" @@ -4372,10 +4372,15 @@ eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== -eslint@7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.1.0.tgz#d9a1df25e5b7859b0a3d86bb05f0940ab676a851" - integrity sha512-DfS3b8iHMK5z/YLSme8K5cge168I8j8o1uiVmFCgnnjxZQbCGyraF8bMl7Ju4yfBmCuxD7shOF7eqGkcuIHfsA== +eslint-visitor-keys@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.2.0.tgz#74415ac884874495f78ec2a97349525344c981fa" + integrity sha512-WFb4ihckKil6hu3Dp798xdzSfddwKKU3+nGniKF6HfeW6OLd2OUDEPP7TcHtB5+QXOKg2s6B2DaMPE1Nn/kxKQ== + +eslint@7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.2.0.tgz#d41b2e47804b30dbabb093a967fb283d560082e6" + integrity sha512-B3BtEyaDKC5MlfDa2Ha8/D6DsS4fju95zs0hjS3HdGazw+LNayai38A25qMppK37wWGWNYSPOR6oYzlz5MHsRQ== dependencies: "@babel/code-frame" "^7.0.0" ajv "^6.10.0" @@ -4383,10 +4388,10 @@ eslint@7.1.0: cross-spawn "^7.0.2" debug "^4.0.1" doctrine "^3.0.0" - eslint-scope "^5.0.0" + eslint-scope "^5.1.0" eslint-utils "^2.0.0" - eslint-visitor-keys "^1.1.0" - espree "^7.0.0" + eslint-visitor-keys "^1.2.0" + espree "^7.1.0" esquery "^1.2.0" esutils "^2.0.2" file-entry-cache "^5.0.1" @@ -4414,14 +4419,14 @@ eslint@7.1.0: text-table "^0.2.0" v8-compile-cache "^2.0.3" -espree@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-7.0.0.tgz#8a7a60f218e69f120a842dc24c5a88aa7748a74e" - integrity sha512-/r2XEx5Mw4pgKdyb7GNLQNsu++asx/dltf/CI8RFi9oGHxmQFgvLbc5Op4U6i8Oaj+kdslhJtVlEZeAqH5qOTw== +espree@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-7.1.0.tgz#a9c7f18a752056735bf1ba14cb1b70adc3a5ce1c" + integrity sha512-dcorZSyfmm4WTuTnE5Y7MEN1DyoPYy1ZR783QW1FJoenn7RailyWFsq/UL6ZAAA7uXurN9FIpYyUs3OfiIW+Qw== dependencies: - acorn "^7.1.1" + acorn "^7.2.0" acorn-jsx "^5.2.0" - eslint-visitor-keys "^1.1.0" + eslint-visitor-keys "^1.2.0" esprima@^4.0.0, esprima@~4.0.0: version "4.0.1" diff --git a/packages/react-google-maps-api/.editorconfig b/packages/react-google-maps-api/.editorconfig index d7ad826cb..ef7e215d9 100644 --- a/packages/react-google-maps-api/.editorconfig +++ b/packages/react-google-maps-api/.editorconfig @@ -6,7 +6,7 @@ end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true -max_line_length = 100 +max_line_length = 80 indent_size = 2 [*.md] diff --git a/packages/react-google-maps-api/.eslintrc.js b/packages/react-google-maps-api/.eslintrc.js index 9ed80f0f3..14a2e16a6 100644 --- a/packages/react-google-maps-api/.eslintrc.js +++ b/packages/react-google-maps-api/.eslintrc.js @@ -1,87 +1,144 @@ module.exports = { parser: '@typescript-eslint/parser', - plugins: [ - '@typescript-eslint', - 'security-node', - 'standard', - 'promise', - 'import', - 'node', - 'you-dont-need-lodash-underscore', - 'no-inferred-method-name', - 'json', - 'babel', - 'import', - 'filenames', - 'optimize-regex', - 'html', - 'ascii', - 'react', - 'jsx-a11y', - 'react-perf', - 'prettier', - 'react-functional-set-state', - ], extends: [ 'eslint:recommended', 'plugin:@typescript-eslint/eslint-recommended', 'plugin:@typescript-eslint/recommended', - 'standard', - 'plugin:node/recommended', + 'plugin:cypress/recommended', 'plugin:import/typescript', + 'plugin:jest/recommended', + 'plugin:json/recommended', + 'plugin:jsx-a11y/recommended', + 'plugin:optimize-regex/all', 'plugin:promise/recommended', - 'plugin:security-node/recommended', - 'plugin:you-dont-need-lodash-underscore/compatible', - // Always last + 'plugin:react/recommended', + 'plugin:react-hooks/recommended', + 'plugin:react-perf/all', + 'standard', + 'standard-react', + // Prettier always last 'prettier', 'plugin:prettier/recommended', 'prettier/@typescript-eslint', + 'prettier/react', 'prettier/standard', ], - rules: { - 'no-unused-vars': 'off', - 'no-useless-return': 'off', - 'node/no-missing-import': 'off', - 'node/no-unsupported-features/es-syntax': 'off', - '@typescript-eslint/no-var-requires': 'off', - "@typescript-eslint/no-unused-vars": ["error", { varsIgnorePattern: "^_", argsIgnorePattern: "^_" }], - "@typescript-eslint/no-use-before-define": ["error", { functions: false, classes: false }], - 'security-node/detect-crlf': 'off', - }, + plugins: [ + 'chai-expect', + 'import', // connects in extends + '@typescript-eslint', // connects in extends + 'react', // connects in extends + 'jsx-a11y', // connects in extends + 'react-hooks', // connects in extends + 'react-perf', // connects in extends + 'jest', // connects in extends + 'no-inferred-method-name', + 'optimize-regex', // connects in extends + 'promise', // connects in extends + 'cypress', // connects in extends + 'prettier', // connects in extends + 'standard', // connects in extends + 'markdown', + 'json', // connects in extends + 'xss', // unused + 'perf-standard', + 'es', + 'babel', // unused + 'tree-shaking', // unused + ], settings: { - ecmascript: 6, - 'import/parsers': { - '@typescript-eslint/parser': ['.ts', '.tsx'] + react: { + version: 'detect', }, - 'import/resolver': { - // use /path/to/folder/tsconfig.json - 'typescript': { - 'directory': './tsconfig.json' - } + node: { + allowModules: ['src'], + resolvePaths: [__dirname], + tryExtensions: ['.ts', '.tsx', '.js', '.jsx', '.json'], }, - react: { - version: 'detect' - } + }, + env: { + 'cypress/globals': true, + browser: true, + node: true, + es6: true, }, globals: { __DEV__: false, __PROD__: false, __PLAYER_DEBUG__: false, __BASENAME__: false, - google: true + google: true, }, parserOptions: { - 'ecmaVersion': 2018, - 'sourceType': 'module', - 'ecmaFeatures': { - jsx: true + ecmaFeatures: { + jsx: true, }, - 'useJSXTextNode': true, - 'project': './tsconfig.json', - 'tsconfigRootDir': './' + ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features + sourceType: 'module', // Allows for the use of imports }, - env: { - browser: true, - es6: true + rules: { + camelcase: 'off', + 'jest/expect-expect': 'off', + 'no-useless-return': 'off', + 'node/no-missing-import': 'off', + 'node/no-missing-require': 'off', + 'node/no-unsupported-features/es-syntax': 'off', + 'sort-requires/sort-requires': 'off', + 'no-console': ['error', { allow: ['warn', 'error', 'info', 'table'] }], + 'no-unused-vars': 'off', + 'no-restricted-globals': [ + 'error', + { + name: 'name', + message: 'Use local parameter instead.', + }, + { + name: 'event', + message: 'Use local parameter instead.', + }, + { + name: 'fdescribe', + message: 'Do not commit fdescribe. Use describe instead.', + }, + ], + '@typescript-eslint/explicit-function-return-type': [ + 'warn', + { allowExpressions: true }, + ], + '@typescript-eslint/explicit-member-accessibility': 'off', + '@typescript-eslint/no-use-before-define': [ + 'error', + { functions: false, classes: false, typedefs: false }, + ], + '@typescript-eslint/no-unused-vars': [ + 'error', + { varsIgnorePattern: '^_', argsIgnorePattern: '^_' }, + ], + 'react-hooks/rules-of-hooks': 'error', + 'react-hooks/exhaustive-deps': 'warn', + 'optimize-regex/optimize-regex': 'warn', + 'es/no-async-iteration': 'error', + 'es/no-malformed-template-literals': 'error', + 'es/no-regexp-lookbehind-assertions': 'error', + 'es/no-regexp-named-capture-groups': 'error', + 'es/no-regexp-s-flag': 'error', + 'es/no-regexp-unicode-property-escapes': 'error', + 'chai-expect/missing-assertion': 2, + 'chai-expect/terminating-properties': 1, + 'no-inferred-method-name/no-inferred-method-name': 'error', + // "tree-shaking/no-side-effects-in-initialization": 2, }, + overrides: [ + // Override some TypeScript rules just for .js files + { + files: ['*.js'], + rules: { + semi: ['error', 'never'], + 'jsx-quotes': ['error', 'prefer-single'], + '@typescript-eslint/no-var-requires': 'off', + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/explicit-module-boundary-types': 'off', + }, + }, + ], } diff --git a/packages/react-google-maps-api/jest.config.js b/packages/react-google-maps-api/jest.config.js index 9dd314307..66d0ff04f 100644 --- a/packages/react-google-maps-api/jest.config.js +++ b/packages/react-google-maps-api/jest.config.js @@ -1,18 +1,9 @@ module.exports = { - "roots": [ - "/src" - ], - "transform": { - "^.+\\.tsx?$": "ts-jest" + roots: ['/src'], + transform: { + '^.+\\.tsx?$': 'ts-jest', }, - "testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$", - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "jsx", - "json", - "node" - ], - "setupFilesAfterEnv": ["/src/setup-tests.js"] -} \ No newline at end of file + testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$', + moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], + setupFilesAfterEnv: ['/src/setup-tests.js'], +} diff --git a/packages/react-google-maps-api/package.json b/packages/react-google-maps-api/package.json index da7bac212..04d1e259c 100644 --- a/packages/react-google-maps-api/package.json +++ b/packages/react-google-maps-api/package.json @@ -1,7 +1,7 @@ { "name": "@react-google-maps/api", "sideEffects": false, - "version": "1.9.5", + "version": "2.0.0-alpha", "description": "React.js Google Maps API integration", "license": "MIT", "author": { @@ -71,12 +71,12 @@ ], "scripts": { "prebuild": "rimraf dist", - "build": "npx tsdx build --name reactGoogleMapsApi --format=cjs,esm,umd", + "build": "tsdx build --name reactGoogleMapsApi --format=cjs,esm,umd", "clean": "rimraf ./package-lock.json ./yarn.lock ./node_modules/ && yarn", "update": "yarn-check -u", - "lint": "npx eslint ./src/**/*.{ts,tsx} --fix", - "docs:dev": "npx styleguidist server --config ./styleguide.config.js --verbose", - "docs:build": "npx styleguidist build --config ./styleguide.config.js --verbose", + "lint": "eslint ./src --fix", + "docs:dev": "styleguidist server --config ./styleguide.config.js --verbose", + "docs:build": "styleguidist build --config ./styleguide.config.js --verbose", "tc": "tsc -p ./tsconfig.json --noEmit --traceResolution", "test": "jest", "pub": "yarn publish .", @@ -84,10 +84,11 @@ "prepublishOnly": "yarn build" }, "dependencies": { - "@react-google-maps/infobox": "1.9.3", - "@react-google-maps/marker-clusterer": "1.9.3", - "acorn": "^7.2.0", - "acorn-jsx": "^5.2.0", + "@react-google-maps/infobox": "2.0.0-alpha", + "@react-google-maps/marker-clusterer": "2.0.0-alpha", + "markerwithlabel": "^2.0.2", + "acorn": "7.2.0", + "acorn-jsx": "5.2.0", "invariant": "2.2.4" }, "peerDependencies": { @@ -96,7 +97,7 @@ }, "devDependencies": { "@getify/eslint-plugin-proper-arrows": "9.1.1", - "@testing-library/react": "10.0.6", + "@testing-library/react": "10.2.1", "@types/babel-types": "7.0.7", "@types/googlemaps": "3.39.6", "@types/invariant": "2.2.33", @@ -105,20 +106,27 @@ "@typescript-eslint/eslint-plugin": "3.1.0", "@typescript-eslint/parser": "3.1.0", "awesome-typescript-loader": "5.2.1", - "eslint": "7.1.0", + "eslint": "7.2.0", + "eslint-config-prettier": "6.11.0", "eslint-config-standard": "14.1.1", "eslint-config-standard-react": "9.2.0", "eslint-import-resolver-typescript": "2.0.0", "eslint-plugin-ascii": "1.0.0", "eslint-plugin-babel": "5.3.0", + "eslint-plugin-chai-expect": "2.1.0", + "eslint-plugin-cypress": "2.11.1", "eslint-plugin-filenames": "1.3.2", "eslint-plugin-html": "6.0.2", "eslint-plugin-import": "2.20.2", + "eslint-plugin-jest": "23.13.2", "eslint-plugin-json": "2.1.1", "eslint-plugin-jsx-a11y": "6.2.3", + "eslint-plugin-markdown": "1.0.2", "eslint-plugin-no-inferred-method-name": "2.0.0", "eslint-plugin-node": "11.1.0", "eslint-plugin-optimize-regex": "1.2.0", + "eslint-plugin-perf-standard": "1.0.3", + "eslint-plugin-prettier": "3.1.3", "eslint-plugin-promise": "4.2.1", "eslint-plugin-react": "7.20.0", "eslint-plugin-react-functional-set-state": "1.2.1", @@ -126,6 +134,8 @@ "eslint-plugin-react-perf": "3.2.3", "eslint-plugin-security-node": "1.0.12", "eslint-plugin-standard": "4.0.1", + "eslint-plugin-tree-shaking": "1.8.0", + "eslint-plugin-xss": "^0.1.10", "eslint-plugin-you-dont-need-lodash-underscore": "6.10.0", "jest": "26.0.1", "jest-cli": "26.0.1", @@ -137,7 +147,7 @@ "rimraf": "3.0.2", "ts-jest": "26.1.0", "tsdx": "0.13.2", - "typescript": "3.9.3", + "typescript": "3.9.5", "webpack": "4.43.0" }, "gitHead": "80167ddcc3d8e356dbf0b0c3a6292c6a3a989f83" diff --git a/packages/react-google-maps-api/src/GoogleMap.md b/packages/react-google-maps-api/src/GoogleMap.md index 57c30c447..50ebb9bb0 100644 --- a/packages/react-google-maps-api/src/GoogleMap.md +++ b/packages/react-google-maps-api/src/GoogleMap.md @@ -4,18 +4,22 @@ const { LoadScript } = require("./LoadScript"); const ScriptLoaded = require("./docs/ScriptLoaded").default; +const mapContainerStyle = { + height: "400px", + width: "800px" +}; + +const center = { + lat: -3.745, + lng: -38.523 +}; + ; ``` diff --git a/packages/react-google-maps-api/src/GoogleMap.tsx b/packages/react-google-maps-api/src/GoogleMap.tsx index 13b98be80..fff84d2f3 100644 --- a/packages/react-google-maps-api/src/GoogleMap.tsx +++ b/packages/react-google-maps-api/src/GoogleMap.tsx @@ -2,7 +2,11 @@ import * as React from 'react' import MapContext from './map-context' -import { unregisterEvents, applyUpdatersToPropsAndRegisterEvents } from './utils/helper' +import { + unregisterEvents, + applyUpdatersToPropsAndRegisterEvents, +} from './utils/helper' +import { usePrevious } from './utils/use-previous' const eventMap = { onDblClick: 'dblclick', @@ -34,7 +38,10 @@ const updaterMap = { map.mapTypes.set(String(i), it) }) }, - center(map: google.maps.Map, center: google.maps.LatLng | google.maps.LatLngLiteral): void { + center( + map: google.maps.Map, + center: google.maps.LatLng | google.maps.LatLngLiteral + ): void { map.setCenter(center) }, clickableIcons(map: google.maps.Map, clickable: boolean): void { @@ -49,7 +56,10 @@ const updaterMap = { options(map: google.maps.Map, options: google.maps.MapOptions): void { map.setOptions(options) }, - streetView(map: google.maps.Map, streetView: google.maps.StreetViewPanorama): void { + streetView( + map: google.maps.Map, + streetView: google.maps.StreetViewPanorama + ): void { map.setStreetView(streetView) }, tilt(map: google.maps.Map, tilt: number): void { @@ -60,11 +70,8 @@ const updaterMap = { }, } -interface GoogleMapState { - map: google.maps.Map | null -} - export interface GoogleMapProps { + children: React.ReactNode id?: string mapContainerStyle?: React.CSSProperties mapContainerClassName?: string @@ -129,98 +136,74 @@ export interface GoogleMapProps { onUnmount?: (map: google.maps.Map) => void | Promise } -export class GoogleMap extends React.PureComponent { - state: GoogleMapState = { - map: null, - } - - registeredEvents: google.maps.MapsEventListener[] = [] - - mapRef: Element | null = null - - getInstance = (): google.maps.Map | null => { - if (this.mapRef === null) { - return null - } - - return new google.maps.Map(this.mapRef, this.props.options) - } - - panTo = (latLng: google.maps.LatLng | google.maps.LatLngLiteral): void => { - const map = this.getInstance() - if (map) { - map.panTo(latLng) - } - } - - setMapCallback = (): void => { - if (this.state.map !== null) { - if (this.props.onLoad) { - this.props.onLoad(this.state.map) +function GoogleMap(props: GoogleMapProps): JSX.Element { + const { + children, + options, + id, + mapContainerStyle, + mapContainerClassName, + onLoad, + onUnmount, + } = props + const [instance, setInstance] = React.useState(null) + const mapRef = React.createRef() + const prevProps: GoogleMapProps = usePrevious(props) + + React.useEffect( + function effect() { + if (instance === null && mapRef.current !== null) { + setInstance(new google.maps.Map(mapRef.current, options)) } - } - } - - componentDidMount(): void { - const map = this.getInstance() - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps: {}, - nextProps: this.props, - instance: map, - }) - - this.setState(function setMap() { - return { - map, + if (instance !== null) { + if (onLoad) { + onLoad(instance) + } } - }, this.setMapCallback) - } - - componentDidUpdate(prevProps: GoogleMapProps): void { - if (this.state.map !== null) { - unregisterEvents(this.registeredEvents) - - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps, - nextProps: this.props, - instance: this.state.map, - }) - } - } - componentWillUnmount(): void { - if (this.state.map !== null) { - if (this.props.onUnmount) { - this.props.onUnmount(this.state.map) + return function cleanup(): void { + if (instance !== null) { + if (onUnmount) { + onUnmount(instance) + } + } } - - unregisterEvents(this.registeredEvents) - } - } - - getRef = (ref: HTMLDivElement | null): void => { - this.mapRef = ref - } - - render(): React.ReactNode { - return ( -

- - {this.state.map !== null ? this.props.children : <>} - -
- ) - } + }, + [instance, options, onLoad, onUnmount, mapRef] + ) + + React.useEffect( + function effect(): () => void { + const registeredEvents: google.maps.MapsEventListener[] = applyUpdatersToPropsAndRegisterEvents( + { + updaterMap, + eventMap, + prevProps, + nextProps: props, + instance, + } + ) + + return function cleanup(): void { + unregisterEvents(registeredEvents) + } + }, + [props, instance, prevProps] + ) + + return ( +
+ + {instance !== null ? children : <>} + +
+ ) } -export default GoogleMap +export default React.memo(GoogleMap) diff --git a/packages/react-google-maps-api/src/LoadScript.tsx b/packages/react-google-maps-api/src/LoadScript.tsx index 73b503584..851c1a6e9 100644 --- a/packages/react-google-maps-api/src/LoadScript.tsx +++ b/packages/react-google-maps-api/src/LoadScript.tsx @@ -1,19 +1,20 @@ import * as React from 'react' import invariant from 'invariant' -import { injectScript } from './utils/injectscript' +import { injectScript as inject } from './utils/injectscript' import { preventGoogleFonts } from './utils/prevent-google-fonts' import { isBrowser } from './utils/isbrowser' -import { LoadScriptUrlOptions, makeLoadScriptUrl } from './utils/make-load-script-url' +import { + LoadScriptUrlOptions, + makeLoadScriptUrl, +} from './utils/make-load-script-url' +import { usePrevious } from './utils/use-previous' let cleaningUp = false -interface LoadScriptState { - loaded: boolean -} - export interface LoadScriptProps extends LoadScriptUrlOptions { + children: React.ReactNode id: string loadingElement?: React.ReactNode onLoad?: () => void @@ -23,7 +24,7 @@ export interface LoadScriptProps extends LoadScriptUrlOptions { } export function DefaultLoadingElement(): JSX.Element { - return
{`Loading...`}
+ return
Loading...
} export const defaultLoadScriptProps = { @@ -31,76 +32,88 @@ export const defaultLoadScriptProps = { version: 'weekly', } -class LoadScript extends React.PureComponent { - public static defaultProps = defaultLoadScriptProps - - check: React.RefObject = React.createRef() - - state = { - loaded: false, - } - - cleanupCallback = (): void => { - delete window.google - - this.injectScript() - } - - componentDidMount(): void { - if (isBrowser) { - if (window.google && !cleaningUp) { - console.error('google api is already presented') - - return +function LoadScript(props: LoadScriptProps): JSX.Element { + const { + googleMapsApiKey, + googleMapsClientId, + children, + id = 'script-loader', + version = 'weekly', + language, + region, + channel, + libraries, + loadingElement, + onLoad, + onUnmount, + onError, + preventGoogleFontsLoading, + } = props + const prevProps: LoadScriptProps = usePrevious(props) + const [loaded, setLoaded] = React.useState(false) + const check = React.useRef(null) + + const injectScript = React.useCallback( + function callback(): void { + if (preventGoogleFontsLoading) { + preventGoogleFonts() } - this.isCleaningUp() - .then(this.injectScript) - .catch(function error(err) { - console.error('Error at injecting script after cleaning up: ', err) - }) - } - } - - componentDidUpdate(prevProps: LoadScriptProps): void { - if (this.props.libraries !== prevProps.libraries) { - console.warn( - 'Performance warning! LoadScript has been reloaded unintentionally! You should not pass `libraries` prop as new array. Please keep an array of libraries as static class property for Components and PureComponents, or just a const variable outside of component, or somewhere in config files or ENV variables' - ) - } - - if (isBrowser && prevProps.language !== this.props.language) { - this.cleanup() - // TODO: refactor to use gDSFP maybe... wait for hooks refactoring. - // eslint-disable-next-line react/no-did-update-set-state - this.setState(function setLoaded() { - return { - loaded: false, - } - }, this.cleanupCallback) - } - } - - componentWillUnmount(): void { - if (isBrowser) { - this.cleanup() - - const timeoutCallback = (): void => { - if (!this.check.current) { - delete window.google - cleaningUp = false - } + invariant(!!id, 'LoadScript requires "id" prop to be a string: %s', id) + + const injectScriptOptions = { + id: id, + url: makeLoadScriptUrl({ + googleMapsApiKey, + googleMapsClientId, + version, + language, + region, + libraries, + channel, + }), } - window.setTimeout(timeoutCallback, 1) + inject(injectScriptOptions) + .then(function onfulfilled(): void { + if (onLoad) { + onLoad() + } - if (this.props.onUnmount) { - this.props.onUnmount() - } - } - } + setLoaded(true) + + return + }) + .catch(function onrejected(err): void { + if (onError) { + onError(err) + } - isCleaningUp = async (): Promise => { + console.error(` + There has been an Error with loading Google Maps API script, please check that you provided correct google API key (${googleMapsApiKey || + '-'}) or Client ID (${googleMapsClientId || '-'}) to + Otherwise it is a Network issue. + `) + }) + }, + [ + googleMapsApiKey, + id, + version, + language, + region, + channel, + libraries, + googleMapsClientId, + preventGoogleFontsLoading, + onError, + onLoad, + ] + ) + + const isCleaningUp = React.useCallback(async function callback(): Promise< + void + > { function promiseCallback(resolve: () => void): void { if (!cleaningUp) { resolve() @@ -120,107 +133,140 @@ class LoadScript extends React.PureComponent { } return new Promise(promiseCallback) - } + }, + []) - cleanup = (): void => { - cleaningUp = true - const script = document.getElementById(this.props.id) + const cleanup = React.useCallback( + function callback(): void { + cleaningUp = true + const script = document.getElementById(id) - if (script && script.parentNode) { - script.parentNode.removeChild(script) - } + if (script && script.parentNode) { + script.parentNode.removeChild(script) + } - Array.prototype.slice - .call(document.getElementsByTagName('script')) - .filter(function filter(script: HTMLScriptElement): boolean { - return typeof script.src === 'string' && script.src.includes('maps.googleapis') - }) - .forEach(function forEach(script: HTMLScriptElement): void { - if (script.parentNode) { - script.parentNode.removeChild(script) - } - }) + Array.prototype.slice + .call(document.getElementsByTagName('script')) + .filter(function filter(script: HTMLScriptElement): boolean { + return ( + typeof script.src === 'string' && + script.src.includes('maps.googleapis') + ) + }) + .forEach(function forEach(script: HTMLScriptElement): void { + if (script.parentNode) { + script.parentNode.removeChild(script) + } + }) - Array.prototype.slice - .call(document.getElementsByTagName('link')) - .filter(function filter(link: HTMLLinkElement): boolean { - return ( - link.href === 'https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Google+Sans' - ) - }) - .forEach(function forEach(link: HTMLLinkElement) { - if (link.parentNode) { - link.parentNode.removeChild(link) - } - }) - - Array.prototype.slice - .call(document.getElementsByTagName('style')) - .filter(function filter(style: HTMLStyleElement): boolean { - return ( - style.innerText !== undefined && - style.innerText.length > 0 && - style.innerText.includes('.gm-') - ) - }) - .forEach(function forEach(style: HTMLStyleElement) { - if (style.parentNode) { - style.parentNode.removeChild(style) + Array.prototype.slice + .call(document.getElementsByTagName('link')) + .filter(function filter(link: HTMLLinkElement): boolean { + return ( + link.href === + 'https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Google+Sans' + ) + }) + .forEach(function forEach(link: HTMLLinkElement) { + if (link.parentNode) { + link.parentNode.removeChild(link) + } + }) + + Array.prototype.slice + .call(document.getElementsByTagName('style')) + .filter(function filter(style: HTMLStyleElement): boolean { + return ( + style.innerText !== undefined && + style.innerText.length > 0 && + style.innerText.includes('.gm-') + ) + }) + .forEach(function forEach(style: HTMLStyleElement) { + if (style.parentNode) { + style.parentNode.removeChild(style) + } + }) + }, + [id] + ) + + React.useEffect( + function effect(): () => void { + if (isBrowser) { + if (window.google && !cleaningUp) { + console.error('google api is already presented') + + return function cleanup(): void { + return + } } - }) - } - injectScript = (): void => { - if (this.props.preventGoogleFontsLoading) { - preventGoogleFonts() - } + isCleaningUp() + .then(injectScript) + .catch(function onrejected(err: Error) { + console.error('Error at injecting script after cleaning up: ', err) + }) + } - invariant(!!this.props.id, 'LoadScript requires "id" prop to be a string: %s', this.props.id) + return function callback(): void { + if (isBrowser) { + cleanup() - const injectScriptOptions = { - id: this.props.id, - url: makeLoadScriptUrl(this.props), - } + const timeoutCallback = (): void => { + // eslint-disable-next-line react-hooks/exhaustive-deps + if (check.current === null) { + delete window.google + cleaningUp = false + } + } - injectScript(injectScriptOptions) - .then(() => { - if (this.props.onLoad) { - this.props.onLoad() - } + window.setTimeout(timeoutCallback, 1) - this.setState(function setLoaded() { - return { - loaded: true, + if (onUnmount) { + onUnmount() } - }) - - return - }) - .catch(err => { - if (this.props.onError) { - this.props.onError(err) } + } + }, + [cleanup, isCleaningUp, onUnmount, injectScript] + ) + + React.useEffect( + function effect() { + if (libraries !== prevProps.libraries) { + console.warn( + 'Performance warning! LoadScript has been reloaded unintentionally! You should not pass `libraries` prop as new array. Please keep an array of libraries as static class property for Components and PureComponents, or just a const variable outside of component, or somewhere in config files or ENV variables' + ) + } - console.error(` - There has been an Error with loading Google Maps API script, please check that you provided correct google API key (${this - .props.googleMapsApiKey || '-'}) or Client ID (${this.props.googleMapsClientId || - '-'}) to - Otherwise it is a Network issue. - `) - }) - } - - render(): React.ReactNode { - return ( - <> -
- - {this.state.loaded - ? this.props.children - : this.props.loadingElement || } - - ) - } + if (isBrowser && prevProps.language !== language) { + cleanup() + + setLoaded(false) + + delete window.google + + injectScript() + } + }, + [ + cleanup, + injectScript, + language, + libraries, + prevProps.language, + prevProps.libraries, + ] + ) + + return ( + <> +
+ + {loaded ? children : loadingElement || } + + ) } -export default LoadScript +export default React.memo(LoadScript) diff --git a/packages/react-google-maps-api/src/LoadScriptNext.tsx b/packages/react-google-maps-api/src/LoadScriptNext.tsx index 8774354d9..13387fdf2 100644 --- a/packages/react-google-maps-api/src/LoadScriptNext.tsx +++ b/packages/react-google-maps-api/src/LoadScriptNext.tsx @@ -24,7 +24,7 @@ function LoadScriptNext({ const { isLoaded, loadError } = useLoadScript(hookOptions) React.useEffect( - function handleOnLoad() { + function effect() { if (isLoaded && typeof onLoad === 'function') { onLoad() } @@ -33,7 +33,7 @@ function LoadScriptNext({ ) React.useEffect( - function handleOnError() { + function effect() { if (loadError && typeof onError === 'function') { onError(loadError) } @@ -42,7 +42,7 @@ function LoadScriptNext({ ) React.useEffect( - function handleOnUnmount() { + function effect() { return () => { if (onUnmount) { onUnmount() diff --git a/packages/react-google-maps-api/src/components/addons/InfoBox.md b/packages/react-google-maps-api/src/components/addons/InfoBox.md index bb64130d5..3bd42e658 100644 --- a/packages/react-google-maps-api/src/components/addons/InfoBox.md +++ b/packages/react-google-maps-api/src/components/addons/InfoBox.md @@ -20,6 +20,9 @@ const onLoad = infoBox => { console.log('infoBox: ', infoBox) }; +const styleOuterDiv = { backgroundColor: 'yellow', opacity: 0.75, padding: 12 }; +const styleInnerDiv = { fontSize: 16, fontColor: `#08233B` }; + { options={options} position={center} > -
-
+
+
Hello, World!
diff --git a/packages/react-google-maps-api/src/components/addons/InfoBox.tsx b/packages/react-google-maps-api/src/components/addons/InfoBox.tsx index 9fdc1af5b..3aabb8917 100644 --- a/packages/react-google-maps-api/src/components/addons/InfoBox.tsx +++ b/packages/react-google-maps-api/src/components/addons/InfoBox.tsx @@ -1,14 +1,18 @@ /* global google */ -/* eslint-disable filenames/match-exported */ import * as React from 'react' import * as ReactDOM from 'react-dom' -import invariant from 'invariant' import { InfoBox as GoogleMapsInfoBox, InfoBoxOptions as GoogleMapsInfoBoxOptions, } from '@react-google-maps/infobox' -import { unregisterEvents, applyUpdatersToPropsAndRegisterEvents } from '../../utils/helper' +import invariant from 'invariant' + import MapContext from '../../map-context' +import { + unregisterEvents, + applyUpdatersToPropsAndRegisterEvents, +} from '../../utils/helper' +import { usePrevious } from '../../utils/use-previous' const eventMap = { onCloseClick: 'closeclick', @@ -19,7 +23,10 @@ const eventMap = { } const updaterMap = { - options(instance: GoogleMapsInfoBox, options: GoogleMapsInfoBoxOptions): void { + options( + instance: GoogleMapsInfoBox, + options: GoogleMapsInfoBoxOptions + ): void { instance.setOptions(options) }, position( @@ -44,11 +51,8 @@ type InfoBoxOptions = Omit & { position?: google.maps.LatLng | google.maps.LatLngLiteral } -interface InfoBoxState { - infoBox: GoogleMapsInfoBox | null -} - export interface InfoBoxProps { + children: React.ReactNode /** Can be any MVCObject that exposes a LatLng position property and optionally a Point anchorPoint property for calculating the pixelOffset. The anchorPoint is the offset from the anchor's position to the tip of the InfoBox. */ anchor?: google.maps.MVCObject options?: InfoBoxOptions @@ -72,104 +76,110 @@ export interface InfoBoxProps { onUnmount?: (infoBox: GoogleMapsInfoBox) => void } -export class InfoBoxComponent extends React.PureComponent { - static contextType = MapContext - - registeredEvents: google.maps.MapsEventListener[] = [] - containerElement: HTMLElement | null = null - - state: InfoBoxState = { - infoBox: null, - } - - open = (infoBox: GoogleMapsInfoBox, anchor?: google.maps.MVCObject): void => { - if (anchor) { - infoBox.open(this.context, anchor) - } else if (infoBox.getPosition()) { - infoBox.open(this.context) - } else { - invariant(false, 'You must provide either an anchor or a position prop for .') - } - } - - setInfoBoxCallback = (): void => { - const { anchor, onLoad } = this.props - const { infoBox } = this.state - - if (infoBox !== null && this.containerElement !== null) { - infoBox.setContent(this.containerElement) - this.open(infoBox, anchor) - - if (onLoad) { - onLoad(infoBox) +function InfoBoxComponent(props: InfoBoxProps): JSX.Element { + const { children, options, anchor, onLoad, onUnmount } = props + const { position, ...infoBoxOptions }: InfoBoxOptions = options || {} + + const map = React.useContext(MapContext) + const prevProps: InfoBoxProps = usePrevious(props) + const containerElementRef = React.useRef(null) + + const [instance, setInstance] = React.useState(null) + + React.useEffect( + function effect() { + if (map !== null) { + if (instance === null) { + let positionLatLng: google.maps.LatLng | undefined + + if (position && !(position instanceof google.maps.LatLng)) { + positionLatLng = new google.maps.LatLng(position.lat, position.lng) + } + + containerElementRef.current = document.createElement('div') + + const infoBox = new GoogleMapsInfoBox({ + ...infoBoxOptions, + ...(positionLatLng ? { position: positionLatLng } : {}), + }) + + setInstance(infoBox) + } + + if (instance !== null && containerElementRef.current !== null) { + instance.setContent(containerElementRef.current) + + if (anchor) { + instance.open(map, anchor) + } else if (instance.getPosition()) { + instance.open(map) + } else { + invariant( + false, + 'You must provide either an anchor or a position prop for .' + ) + } + + if (onLoad) { + onLoad(instance) + } + } } - } - } - componentDidMount(): void { - const { options } = this.props - const { position, ...infoBoxOptions }: InfoBoxOptions = options || {} + return function cleanup() { + if (instance !== null) { + if (onUnmount) { + onUnmount(instance) + } - let positionLatLng: google.maps.LatLng | undefined - if (position && !(position instanceof google.maps.LatLng)) { - positionLatLng = new google.maps.LatLng(position.lat, position.lng) - } - - const infoBox = new GoogleMapsInfoBox({ - ...infoBoxOptions, - ...(positionLatLng ? { position: positionLatLng } : {}), - }) - - this.containerElement = document.createElement('div') - - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps: {}, - nextProps: this.props, - instance: infoBox, - }) - - this.setState({ infoBox }, this.setInfoBoxCallback) - } - - componentDidUpdate(prevProps: InfoBoxProps): void { - const { infoBox } = this.state - - if (infoBox !== null) { - unregisterEvents(this.registeredEvents) - - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps, - nextProps: this.props, - instance: infoBox, - }) - } - } - - componentWillUnmount(): void { - const { onUnmount } = this.props - const { infoBox } = this.state - - if (infoBox !== null) { - if (onUnmount) { - onUnmount(infoBox) + instance.close() + } } - - unregisterEvents(this.registeredEvents) - infoBox.close() - } - } - - render(): React.ReactPortal | null { - if (!this.containerElement) { - return null - } - - return ReactDOM.createPortal(React.Children.only(this.props.children), this.containerElement) + }, + [ + instance, + map, + options, + onLoad, + onUnmount, + anchor, + containerElementRef, + infoBoxOptions, + position, + ] + ) + + React.useEffect( + function effect(): () => void { + const registeredEvents: google.maps.MapsEventListener[] = applyUpdatersToPropsAndRegisterEvents( + { + updaterMap, + eventMap, + prevProps, + nextProps: props, + instance, + } + ) + + return function cleanup(): void { + unregisterEvents(registeredEvents) + } + }, + [props, instance, prevProps] + ) + + if (containerElementRef.current === null) { + return <> + } else { + return ( + <> + {ReactDOM.createPortal( + React.Children.only(children), + containerElementRef.current + )} + + ) } } -export default InfoBoxComponent +export default React.memo(InfoBoxComponent) diff --git a/packages/react-google-maps-api/src/components/addons/MarkerClusterer.tsx b/packages/react-google-maps-api/src/components/addons/MarkerClusterer.tsx index acc5d92ce..90fb756e9 100644 --- a/packages/react-google-maps-api/src/components/addons/MarkerClusterer.tsx +++ b/packages/react-google-maps-api/src/components/addons/MarkerClusterer.tsx @@ -1,10 +1,4 @@ -/* eslint-disable filenames/match-exported */ import * as React from 'react' - -import { unregisterEvents, applyUpdatersToPropsAndRegisterEvents } from '../../utils/helper' - -import MapContext from '../../map-context' - import { Clusterer, ClusterIconStyle, @@ -13,6 +7,13 @@ import { TCalculator, } from '@react-google-maps/marker-clusterer' +import MapContext from '../../map-context' +import { + unregisterEvents, + applyUpdatersToPropsAndRegisterEvents, +} from '../../utils/helper' +import { usePrevious } from '../../utils/use-previous' + const eventMap = { onClick: 'click', onClusteringBegin: 'clusteringbegin', @@ -30,7 +31,7 @@ const updaterMap = { instance.setBatchSizeIE(batchSizeIE) }, - calculator(instance: Clusterer, calculator: any): void { + calculator(instance: Clusterer, calculator: TCalculator): void { instance.setCalculator(calculator) }, @@ -83,10 +84,6 @@ const updaterMap = { }, } -interface ClustererState { - markerClusterer: Clusterer | null -} - export interface ClustererProps { // required children: (markerClusterer: Clusterer) => React.ReactNode @@ -138,73 +135,61 @@ export interface ClustererProps { onUnmount?: (markerClusterer: Clusterer) => void } -export class ClustererComponent extends React.PureComponent { - static contextType = MapContext +function ClustererComponent(props: ClustererProps): JSX.Element { + const { children, options, onLoad, onUnmount } = props + const map = React.useContext(MapContext) + const prevProps: ClustererProps = usePrevious(props) - registeredEvents: google.maps.MapsEventListener[] = [] + const [instance, setInstance] = React.useState(null) - state: ClustererState = { - markerClusterer: null, - } - - setClustererCallback = (): void => { - if (this.state.markerClusterer !== null && this.props.onLoad) { - this.props.onLoad(this.state.markerClusterer) - } - } - - componentDidMount(): void { - if (this.context) { - const markerClusterer = new Clusterer(this.context, [], this.props.options) + React.useEffect( + function effect() { + if (map !== null) { + if (instance === null) { + setInstance(new Clusterer(map, [], options)) + } - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps: {}, - nextProps: this.props, - instance: markerClusterer, - }) + if (instance !== null) { + if (onLoad) { + onLoad(instance) + } + } + } - this.setState(function setClusterer(): ClustererState { - return { - markerClusterer, + return function cleanup() { + if (instance !== null) { + if (onUnmount) { + onUnmount(instance) + } + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + instance.setMap(null) + } + } + }, + [instance, map, options, onLoad, onUnmount] + ) + + React.useEffect( + function effect(): () => void { + const registeredEvents: google.maps.MapsEventListener[] = applyUpdatersToPropsAndRegisterEvents( + { + updaterMap, + eventMap, + prevProps, + nextProps: props, + instance, } - }, this.setClustererCallback) - } - } - - componentDidUpdate(prevProps: ClustererProps): void { - if (this.state.markerClusterer) { - unregisterEvents(this.registeredEvents) - - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps, - nextProps: this.props, - instance: this.state.markerClusterer, - }) - } - } - - componentWillUnmount(): void { - if (this.state.markerClusterer !== null) { - if (this.props.onUnmount) { - this.props.onUnmount(this.state.markerClusterer) + ) + + return function cleanup(): void { + unregisterEvents(registeredEvents) } + }, + [props, instance, prevProps] + ) - unregisterEvents(this.registeredEvents) - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore - // @ts-ignore - this.state.markerClusterer.setMap(null) - } - } - - render(): React.ReactNode { - return this.state.markerClusterer !== null - ? this.props.children(this.state.markerClusterer) - : null - } + return instance !== null ? <>{children(instance)} : <> } -export default ClustererComponent +export default React.memo(ClustererComponent) diff --git a/packages/react-google-maps-api/src/components/directions/DirectionsRenderer.tsx b/packages/react-google-maps-api/src/components/directions/DirectionsRenderer.tsx index 78e9ce29e..7c5600997 100644 --- a/packages/react-google-maps-api/src/components/directions/DirectionsRenderer.tsx +++ b/packages/react-google-maps-api/src/components/directions/DirectionsRenderer.tsx @@ -1,8 +1,11 @@ import * as React from 'react' -import { unregisterEvents, applyUpdatersToPropsAndRegisterEvents } from '../../utils/helper' - import MapContext from '../../map-context' +import { + unregisterEvents, + applyUpdatersToPropsAndRegisterEvents, +} from '../../utils/helper' +import { usePrevious } from '../../utils/use-previous' const eventMap = { onDirectionsChanged: 'directions_changed', @@ -27,15 +30,14 @@ const updaterMap = { panel(instance: google.maps.DirectionsRenderer, panel: Element): void { instance.setPanel(panel) }, - routeIndex(instance: google.maps.DirectionsRenderer, routeIndex: number): void { + routeIndex( + instance: google.maps.DirectionsRenderer, + routeIndex: number + ): void { instance.setRouteIndex(routeIndex) }, } -interface DirectionsRendererState { - directionsRenderer: google.maps.DirectionsRenderer | null -} - export interface DirectionsRendererProps { options?: google.maps.DirectionsRendererOptions /** The directions to display on the map and/or in a
panel, retrieved as a DirectionsResult object from DirectionsService. */ @@ -52,77 +54,67 @@ export interface DirectionsRendererProps { onUnmount?: (directionsRenderer: google.maps.DirectionsRenderer) => void } -export class DirectionsRenderer extends React.PureComponent< - DirectionsRendererProps, - DirectionsRendererState -> { - static contextType = MapContext - - registeredEvents: google.maps.MapsEventListener[] = [] - - state: DirectionsRendererState = { - directionsRenderer: null, - } - - setDirectionsRendererCallback = (): void => { - if (this.state.directionsRenderer !== null) { - this.state.directionsRenderer.setMap(this.context) - - if (this.props.onLoad) { - this.props.onLoad(this.state.directionsRenderer) - } - } - } - - componentDidMount(): void { - const directionsRenderer = new google.maps.DirectionsRenderer(this.props.options) - - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps: {}, - nextProps: this.props, - instance: directionsRenderer, - }) - - this.setState(function setDirectionsRenderer() { - return { - directionsRenderer, +function DirectionsRenderer(props: DirectionsRendererProps): JSX.Element { + const { options, onLoad, onUnmount } = props + const map = React.useContext(MapContext) + const prevProps: DirectionsRendererProps = usePrevious< + DirectionsRendererProps + >(props) + + const [ + instance, + setInstance, + ] = React.useState(null) + + React.useEffect( + function effect() { + if (map !== null) { + if (instance === null) { + setInstance(new google.maps.DirectionsRenderer(options)) + } + + if (instance !== null) { + instance.setMap(map) + + if (onLoad) { + onLoad(instance) + } + } } - }, this.setDirectionsRendererCallback) - } - - componentDidUpdate(prevProps: DirectionsRendererProps): void { - if (this.state.directionsRenderer !== null) { - unregisterEvents(this.registeredEvents) - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps, - nextProps: this.props, - instance: this.state.directionsRenderer, - }) - } - } + return function cleanup() { + if (instance !== null) { + if (onUnmount) { + onUnmount(instance) + } - componentWillUnmount(): void { - if (this.state.directionsRenderer !== null) { - if (this.props.onUnmount) { - this.props.onUnmount(this.state.directionsRenderer) + instance.setMap(null) + } } - - unregisterEvents(this.registeredEvents) - - if (this.state.directionsRenderer) { - this.state.directionsRenderer.setMap(null) + }, + [instance, map, options, onLoad, onUnmount] + ) + + React.useEffect( + function effect(): () => void { + const registeredEvents: google.maps.MapsEventListener[] = applyUpdatersToPropsAndRegisterEvents( + { + updaterMap, + eventMap, + prevProps, + nextProps: props, + instance, + } + ) + + return function cleanup(): void { + unregisterEvents(registeredEvents) } - } - } + }, + [props, instance, prevProps] + ) - render(): JSX.Element { - return <> - } + return <> } -export default DirectionsRenderer +export default React.memo(DirectionsRenderer) diff --git a/packages/react-google-maps-api/src/components/directions/DirectionsService.tsx b/packages/react-google-maps-api/src/components/directions/DirectionsService.tsx index a26e823bf..7414da129 100644 --- a/packages/react-google-maps-api/src/components/directions/DirectionsService.tsx +++ b/packages/react-google-maps-api/src/components/directions/DirectionsService.tsx @@ -1,10 +1,6 @@ import * as React from 'react' import invariant from 'invariant' -interface DirectionsServiceState { - directionsService: google.maps.DirectionsService | null -} - export interface DirectionsServiceProps { // required for default functionality options: google.maps.DirectionsRequest @@ -24,53 +20,52 @@ export interface DirectionsServiceProps { onUnmount?: (directionsService: google.maps.DirectionsService) => void } -export class DirectionsService extends React.PureComponent< - DirectionsServiceProps, - DirectionsServiceState -> { - state: DirectionsServiceState = { - directionsService: null, - } - - setDirectionsServiceCallback = (): void => { - if (this.state.directionsService !== null && this.props.onLoad) { - this.props.onLoad(this.state.directionsService) - } - } +function DirectionsService(props: DirectionsServiceProps): JSX.Element { + const { options, callback, onLoad, onUnmount } = props + const [ + instance, + setInstance, + ] = React.useState(null) - componentDidMount(): void { - invariant( - !!this.props.options, - 'DirectionsService expected options object as parameter, but got %s', - this.props.options - ) + React.useEffect( + function effect() { + invariant( + !!options, + 'DirectionsService expected options object as parameter, but got %s', + options + ) - const directionsService = new google.maps.DirectionsService() + if (instance === null) { + setInstance(new google.maps.DirectionsService()) + } - this.setState(function setDirectionsService() { - return { - directionsService, + if (instance !== null) { + if (onLoad) { + onLoad(instance) + } } - }, this.setDirectionsServiceCallback) - } - componentDidUpdate(): void { - if (this.state.directionsService !== null) { - this.state.directionsService.route(this.props.options, this.props.callback) - } - } + return function cleanup(): void { + if (instance !== null) { + if (onUnmount) { + onUnmount(instance) + } + } + } + }, + [instance, options, onLoad, onUnmount] + ) - componentWillUnmount(): void { - if (this.state.directionsService !== null) { - if (this.props.onUnmount) { - this.props.onUnmount(this.state.directionsService) + React.useEffect( + function effect() { + if (instance !== null) { + instance.route(options, callback) } - } - } + }, + [instance, options, callback] + ) - render(): JSX.Element { - return <> - } + return <> } -export default DirectionsService +export default React.memo(DirectionsService) diff --git a/packages/react-google-maps-api/src/components/distance-matrix/DistanceMatrixService.tsx b/packages/react-google-maps-api/src/components/distance-matrix/DistanceMatrixService.tsx index 730ce6784..740b0bf23 100644 --- a/packages/react-google-maps-api/src/components/distance-matrix/DistanceMatrixService.tsx +++ b/packages/react-google-maps-api/src/components/distance-matrix/DistanceMatrixService.tsx @@ -2,10 +2,6 @@ import * as React from 'react' import invariant from 'invariant' -interface DistanceMatrixServiceState { - distanceMatrixService: google.maps.DistanceMatrixService | null -} - export interface DistanceMatrixServiceProps { // required for default functionality options: google.maps.DistanceMatrixRequest @@ -25,53 +21,53 @@ export interface DistanceMatrixServiceProps { onUnmount?: (distanceMatrixService: google.maps.DistanceMatrixService) => void } -export class DistanceMatrixService extends React.PureComponent< - DistanceMatrixServiceProps, - DistanceMatrixServiceState -> { - state: DistanceMatrixServiceState = { - distanceMatrixService: null, - } +function DistanceMatrixService(props: DistanceMatrixServiceProps): JSX.Element { + const { options, callback, onLoad, onUnmount } = props - setDistanceMatrixServiceCallback = (): void => { - if (this.state.distanceMatrixService !== null && this.props.onLoad) { - this.props.onLoad(this.state.distanceMatrixService) - } - } + const [ + instance, + setInstance, + ] = React.useState(null) - componentDidMount(): void { - invariant( - !!this.props.options, - 'DistanceMatrixService expected options object as parameter, but go %s', - this.props.options - ) + React.useEffect( + function effect() { + invariant( + !!options, + 'DistanceMatrixService expected options object as parameter, but go %s', + options + ) - const distanceMatrixService = new google.maps.DistanceMatrixService() + if (instance === null) { + setInstance(new google.maps.DistanceMatrixService()) + } - this.setState(function setDistanceMatrixService() { - return { - distanceMatrixService, + if (instance !== null) { + if (onLoad) { + onLoad(instance) + } } - }, this.setDistanceMatrixServiceCallback) - } - componentDidUpdate(): void { - if (this.state.distanceMatrixService !== null) { - this.state.distanceMatrixService.getDistanceMatrix(this.props.options, this.props.callback) - } - } + return function cleanup() { + if (instance !== null) { + if (onUnmount) { + onUnmount(instance) + } + } + } + }, + [instance, options, onLoad, onUnmount] + ) - componentWillUnmount(): void { - if (this.state.distanceMatrixService !== null) { - if (this.props.onUnmount) { - this.props.onUnmount(this.state.distanceMatrixService) + React.useEffect( + function effect() { + if (instance !== null) { + instance.getDistanceMatrix(options, callback) } - } - } + }, + [instance, options, callback] + ) - render(): JSX.Element { - return <> - } + return <> } -export default DistanceMatrixService +export default React.memo(DistanceMatrixService) diff --git a/packages/react-google-maps-api/src/components/dom/CountMountHandler.tsx b/packages/react-google-maps-api/src/components/dom/CountMountHandler.tsx deleted file mode 100644 index a3e6ce61c..000000000 --- a/packages/react-google-maps-api/src/components/dom/CountMountHandler.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import * as React from 'react' - -export interface OverlayViewProps { - mapPaneName: string - getPixelPositionOffset?: (offsetWidth: number, offsetHeight: number) => { x: number; y: number } - bounds?: google.maps.LatLngBounds | google.maps.LatLngBoundsLiteral - position?: google.maps.LatLng | google.maps.LatLngLiteral - onLoad?: (overlayView: google.maps.OverlayView) => void - onUnmount?: (overlayView: google.maps.OverlayView) => void -} - -interface ContentMountHandlerProps { - onLoad?: () => void -} - -class ContentMountHandler extends React.Component { - componentDidMount(): void { - if (this.props.onLoad) { - this.props.onLoad() - } - } - - render(): React.ReactNode { - return this.props.children - } -} - -export default ContentMountHandler diff --git a/packages/react-google-maps-api/src/components/dom/OverlayView.tsx b/packages/react-google-maps-api/src/components/dom/OverlayView.tsx index 0c03fa8ea..9c77d378f 100644 --- a/packages/react-google-maps-api/src/components/dom/OverlayView.tsx +++ b/packages/react-google-maps-api/src/components/dom/OverlayView.tsx @@ -4,193 +4,232 @@ import * as ReactDOM from 'react-dom' import invariant from 'invariant' import MapContext from '../../map-context' +import ContentMountHandler from './count-mount-handler' +import { usePrevious } from '../../utils/use-previous' import { getOffsetOverride, getLayoutStyles } from './dom-helper' -import ContentMountHandler from './CountMountHandler' - -interface OverlayViewState { - overlayView: google.maps.OverlayView | null - containerStyle: React.CSSProperties -} - -function convertToLatLngString(latLngLike?: google.maps.LatLng | google.maps.LatLngLiteral | null) { +function convertToLatLngString( + latLngLike?: google.maps.LatLng | google.maps.LatLngLiteral | null +): string { if (!latLngLike) { return '' } - const latLng = latLngLike instanceof google.maps.LatLng - ? latLngLike - : new google.maps.LatLng(latLngLike.lat, latLngLike.lng) + const latLng = + latLngLike instanceof google.maps.LatLng + ? latLngLike + : new google.maps.LatLng(latLngLike.lat, latLngLike.lng) return latLng + '' } -function convertToLatLngBoundsString(latLngBoundsLike?: google.maps.LatLngBounds | google.maps.LatLngBoundsLiteral | null) { +function convertToLatLngBoundsString( + latLngBoundsLike?: + | google.maps.LatLngBounds + | google.maps.LatLngBoundsLiteral + | null +): string { if (!latLngBoundsLike) { return '' } - const latLngBounds = latLngBoundsLike instanceof google.maps.LatLngBounds - ? latLngBoundsLike - : new google.maps.LatLngBounds( - new google.maps.LatLng(latLngBoundsLike.south, latLngBoundsLike.east), - new google.maps.LatLng(latLngBoundsLike.north, latLngBoundsLike.west) - ) + const latLngBounds = + latLngBoundsLike instanceof google.maps.LatLngBounds + ? latLngBoundsLike + : new google.maps.LatLngBounds( + new google.maps.LatLng(latLngBoundsLike.south, latLngBoundsLike.east), + new google.maps.LatLng(latLngBoundsLike.north, latLngBoundsLike.west) + ) return latLngBounds + '' } export interface OverlayViewProps { // required - mapPaneName: string - getPixelPositionOffset?: (offsetWidth: number, offsetHeight: number) => { x: number; y: number } + children: React.ReactChild + mapPaneName: keyof google.maps.MapPanes + getPixelPositionOffset?: ( + offsetWidth: number, + offsetHeight: number + ) => { x: number; y: number } bounds?: google.maps.LatLngBounds | google.maps.LatLngBoundsLiteral position?: google.maps.LatLng | google.maps.LatLngLiteral onLoad?: (overlayView: google.maps.OverlayView) => void onUnmount?: (overlayView: google.maps.OverlayView) => void } -export class OverlayView extends React.PureComponent { - static FLOAT_PANE = `floatPane` - static MAP_PANE = `mapPane` - static MARKER_LAYER = `markerLayer` - static OVERLAY_LAYER = `overlayLayer` - static OVERLAY_MOUSE_TARGET = `overlayMouseTarget` - - static contextType = MapContext - - state: OverlayViewState = { - overlayView: null, - containerStyle: {}, - } - - mapPaneEl: Element | null = null - - containerRef: React.RefObject - - setOverlayViewCallback = (): void => { - if (this.state.overlayView !== null && this.props.onLoad) { - this.props.onLoad(this.state.overlayView) - } - - this.onPositionElement() - } - - onAdd = (): void => { - invariant( - !!this.props.mapPaneName, - `OverlayView requires props.mapPaneName but got %s`, - this.props.mapPaneName - ) - - // https://developers.google.com/maps/documentation/javascript/3.exp/reference#MapPanes - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const mapPanes: any = this.state.overlayView?.getPanes() - - if (!mapPanes) { - return - } - - this.mapPaneEl = mapPanes[this.props.mapPaneName] - } - - onPositionElement = (): void => { - if (this.state.overlayView !== null) { - const mapCanvasProjection = this.state.overlayView.getProjection() - - const offset = { - x: 0, - y: 0, - ...(this.containerRef.current - ? getOffsetOverride(this.containerRef.current, this.props.getPixelPositionOffset) - : {}), +// const FLOAT_PANE = `floatPane` +// const MAP_PANE = `mapPane` +// const MARKER_LAYER = `markerLayer` +// const OVERLAY_LAYER = `overlayLayer` +// const OVERLAY_MOUSE_TARGET = `overlayMouseTarget` + +function OverlayView(props: OverlayViewProps): JSX.Element { + const { + children, + mapPaneName, + bounds, + getPixelPositionOffset, + onLoad, + onUnmount, + position, + } = props + const prevProps: OverlayViewProps = usePrevious(props) + + const map = React.useContext(MapContext) + const [ + instance, + setInstance, + ] = React.useState(null) + const [ + containerStyle, + setContainerStyle, + ] = React.useState(null) + const mapPanelRef = React.useRef(null) + const containerRef = React.useRef(null) + + const onPositionElement = React.useCallback( + function callback(): void { + if (instance !== null) { + const mapCanvasProjection = instance.getProjection() + + const offset = { + x: 0, + y: 0, + ...(containerRef.current + ? getOffsetOverride(containerRef.current, getPixelPositionOffset) + : {}), + } + + const layoutStyles: React.CSSProperties | null = getLayoutStyles( + mapCanvasProjection, + offset, + bounds, + position + ) + + setContainerStyle(layoutStyles) + } + }, + [bounds, getPixelPositionOffset, instance, position] + ) + + const draw = React.useCallback( + function callback(): void { + onPositionElement() + }, + [onPositionElement] + ) + + const onRemove = React.useCallback(function callback(): void { + mapPanelRef.current = null + }, []) + + const handleOverlayViewCallback = React.useCallback( + function callback(): void { + if (instance !== null && onLoad) { + onLoad(instance) } - const layoutStyles = getLayoutStyles( - mapCanvasProjection, - offset, - this.props.bounds, - this.props.position + onPositionElement() + }, + [instance, onLoad, onPositionElement] + ) + + const onAdd = React.useCallback( + function callback(): void { + invariant( + !!mapPaneName, + `OverlayView requires mapPaneName but got %s`, + mapPaneName ) - this.setState({ - containerStyle: layoutStyles, - }) - } - } + // https://developers.google.com/maps/documentation/javascript/3.exp/reference#MapPanes + if (instance !== null) { + const mapPanes: google.maps.MapPanes = instance.getPanes() - draw = (): void => { - this.onPositionElement() - } + if (!mapPanes) { + return + } - onRemove = (): void => { - this.mapPaneEl = null - } - - constructor(props: OverlayViewProps) { - super(props) + mapPanelRef.current = mapPanes[mapPaneName] + } + }, + [instance, mapPaneName] + ) - this.containerRef = React.createRef() - } + React.useEffect( + function effect(): () => void { + const instance = new google.maps.OverlayView() - componentDidMount(): void { - const overlayView = new google.maps.OverlayView() + // You must implement three methods: onAdd(), draw(), and onRemove(). + instance.onAdd = onAdd + instance.draw = draw + instance.onRemove = onRemove - // You must implement three methods: onAdd(), draw(), and onRemove(). - overlayView.onAdd = this.onAdd - overlayView.draw = this.draw - overlayView.onRemove = this.onRemove + // the onAdd() method and setMap(null) in order to trigger the onRemove() method. + // You must call setMap() with a valid Map object to trigger the call to + instance.setMap(map) - overlayView.setMap(this.context) + setInstance(instance) - // You must call setMap() with a valid Map object to trigger the call to - // the onAdd() method and setMap(null) in order to trigger the onRemove() method. + return function cleanup(): void { + if (instance !== null) { + if (onUnmount) { + onUnmount(instance) + } - this.setState(function setOverlayView() { - return { - overlayView, + instance.setMap(null) + } } - }) - } - - componentDidUpdate(prevProps: OverlayViewProps): void { - const prevPositionString = convertToLatLngString(prevProps.position) - const positionString = convertToLatLngString(this.props.position) - const prevBoundsString = convertToLatLngBoundsString(prevProps.bounds) - const boundsString = convertToLatLngBoundsString(this.props.bounds) - - if (prevPositionString !== positionString || prevBoundsString !== boundsString) { - setTimeout(() => { - this.state.overlayView !== null && this.state.overlayView.draw() - }, 0) - } - } - - componentWillUnmount(): void { - if (this.state.overlayView !== null) { - if (this.props.onUnmount) { - this.props.onUnmount(this.state.overlayView) + }, + [draw, map, onAdd, onRemove, onUnmount] + ) + + React.useEffect( + function effect(): () => void { + const prevPositionString = convertToLatLngString(prevProps.position) + const positionString = convertToLatLngString(position) + const prevBoundsString = convertToLatLngBoundsString(prevProps.bounds) + const boundsString = convertToLatLngBoundsString(bounds) + + let timeout = 0 + if ( + prevPositionString !== positionString || + prevBoundsString !== boundsString + ) { + timeout = window.setTimeout(() => { + instance !== null && instance.draw() + }, 0) } - this.state.overlayView.setMap(null) - } - } - - render(): React.ReactPortal | React.ReactNode { - return this.mapPaneEl ? ( - ReactDOM.createPortal( -
- - {React.Children.only(this.props.children)} - -
, - this.mapPaneEl, - ) - ) : ( - <> + return function cleanup(): void { + window.clearTimeout(timeout) + } + }, + [bounds, instance, position, prevProps.bounds, prevProps.position] + ) + + const containerStyleMemo: React.CSSProperties = React.useMemo( + function memo() { + return { ...containerStyle, position: 'absolute' } + }, + [containerStyle] + ) + + return mapPanelRef.current !== null ? ( + ReactDOM.createPortal( +
+ + {React.Children.only(children)} + +
, + mapPanelRef.current ) - } + ) : ( + <> + ) } -export default OverlayView +export default React.memo(OverlayView) diff --git a/packages/react-google-maps-api/src/components/dom/count-mount-handler.tsx b/packages/react-google-maps-api/src/components/dom/count-mount-handler.tsx new file mode 100644 index 000000000..f73dd2907 --- /dev/null +++ b/packages/react-google-maps-api/src/components/dom/count-mount-handler.tsx @@ -0,0 +1,24 @@ +import * as React from 'react' + +interface ContentMountHandlerProps { + children: React.ReactNode + onLoad?: () => void +} + +function ContentMountHandler({ + children, + onLoad, +}: ContentMountHandlerProps): JSX.Element { + React.useEffect( + function effect(): void { + if (onLoad) { + onLoad() + } + }, + [onLoad] + ) + + return <>{children} +} + +export default React.memo(ContentMountHandler) diff --git a/packages/react-google-maps-api/src/components/dom/dom-helper.ts b/packages/react-google-maps-api/src/components/dom/dom-helper.ts index d2b227e74..37695f3e7 100644 --- a/packages/react-google-maps-api/src/components/dom/dom-helper.ts +++ b/packages/react-google-maps-api/src/components/dom/dom-helper.ts @@ -1,25 +1,43 @@ -/* eslint-disable filenames/match-regex */ export function getOffsetOverride( containerElement: HTMLElement, - getPixelPositionOffset?: (offsetWidth: number, offsetHeight: number) => { x: number; y: number } -): { x: number; y: number } | {} { + getPixelPositionOffset?: ( + offsetWidth: number, + offsetHeight: number + ) => { x: number; y: number } +): { x: number; y: number } | Record { return typeof getPixelPositionOffset === 'function' - ? getPixelPositionOffset(containerElement.offsetWidth, containerElement.offsetHeight) + ? getPixelPositionOffset( + containerElement.offsetWidth, + containerElement.offsetHeight + ) : {} } // eslint-disable-next-line @typescript-eslint/no-explicit-any -const createLatLng = (inst: any, Type: any): any => new Type(inst.lat, inst.lng) +function createLatLng(inst: any, Type: any): any { + return new Type(inst.lat, inst.lng) +} // eslint-disable-next-line @typescript-eslint/no-explicit-any -const createLatLngBounds = (inst: any, Type: any): any => - new Type( +function createLatLngBounds(inst: any, Type: any): any { + return new Type( new google.maps.LatLng(inst.ne.lat, inst.ne.lng), new google.maps.LatLng(inst.sw.lat, inst.sw.lng) ) +} -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const ensureOfType = (inst: any, type: any, factory: any): any => { +function ensureOfType( + inst: + | google.maps.LatLngBounds + | google.maps.LatLngBoundsLiteral + | google.maps.LatLng + | google.maps.LatLngLiteral, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + type: any, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + factory: any + // eslint-disable-next-line @typescript-eslint/no-explicit-any +): any { return inst instanceof type ? inst : factory(inst, type) } @@ -27,7 +45,7 @@ const getLayoutStylesByBounds = ( mapCanvasProjection: google.maps.MapCanvasProjection, offset: { x: number; y: number }, bounds: google.maps.LatLngBounds -): { left: string; top: string; width?: string; height?: string } => { +): React.CSSProperties => { const ne = mapCanvasProjection.fromLatLngToDivPixel(bounds.getNorthEast()) const sw = mapCanvasProjection.fromLatLngToDivPixel(bounds.getSouthWest()) @@ -47,11 +65,11 @@ const getLayoutStylesByBounds = ( } } -const getLayoutStylesByPosition = ( +function getLayoutStylesByPosition( mapCanvasProjection: google.maps.MapCanvasProjection, offset: { x: number; y: number }, position: google.maps.LatLng -): { left: string; top: string } => { +): React.CSSProperties { const point = mapCanvasProjection.fromLatLngToDivPixel(position) if (point) { @@ -69,21 +87,27 @@ const getLayoutStylesByPosition = ( } } -export const getLayoutStyles = ( +export function getLayoutStyles( mapCanvasProjection: google.maps.MapCanvasProjection, offset: { x: number; y: number }, bounds?: google.maps.LatLngBounds | google.maps.LatLngBoundsLiteral, position?: google.maps.LatLng | google.maps.LatLngLiteral -): { left: string; top: string; width?: string; height?: string } => { - return bounds !== undefined - ? getLayoutStylesByBounds( - mapCanvasProjection, - offset, - ensureOfType(bounds, google.maps.LatLngBounds, createLatLngBounds) - ) - : getLayoutStylesByPosition( - mapCanvasProjection, - offset, - ensureOfType(position, google.maps.LatLng, createLatLng) - ) +): React.CSSProperties | null { + if (bounds !== undefined) { + return getLayoutStylesByBounds( + mapCanvasProjection, + offset, + ensureOfType(bounds, google.maps.LatLngBounds, createLatLngBounds) + ) + } + + if (position !== undefined) { + return getLayoutStylesByPosition( + mapCanvasProjection, + offset, + ensureOfType(position, google.maps.LatLng, createLatLng) + ) + } + + return null } diff --git a/packages/react-google-maps-api/src/components/drawing/Circle.tsx b/packages/react-google-maps-api/src/components/drawing/Circle.tsx index d71827163..2a68e2a56 100644 --- a/packages/react-google-maps-api/src/components/drawing/Circle.tsx +++ b/packages/react-google-maps-api/src/components/drawing/Circle.tsx @@ -1,8 +1,11 @@ import * as React from 'react' -import { unregisterEvents, applyUpdatersToPropsAndRegisterEvents } from '../../utils/helper' - import MapContext from '../../map-context' +import { + unregisterEvents, + applyUpdatersToPropsAndRegisterEvents, +} from '../../utils/helper' +import { usePrevious } from '../../utils/use-previous' const eventMap = { onCenterChanged: 'center_changed', @@ -33,7 +36,10 @@ const updaterMap = { map(instance: google.maps.Circle, map: google.maps.Map): void { instance.setMap(map) }, - options(instance: google.maps.Circle, options: google.maps.CircleOptions): void { + options( + instance: google.maps.Circle, + options: google.maps.CircleOptions + ): void { instance.setOptions(options) }, radius(instance: google.maps.Circle, radius: number): void { @@ -44,10 +50,6 @@ const updaterMap = { }, } -interface CircleState { - circle: google.maps.Circle | null -} - export interface CircleProps { options?: google.maps.CircleOptions @@ -96,71 +98,69 @@ export interface CircleProps { onUnmount?: (circle: google.maps.Circle) => void } -export class Circle extends React.PureComponent { - static contextType = MapContext - - registeredEvents: google.maps.MapsEventListener[] = [] - - state: CircleState = { - circle: null, - } - - setCircleCallback = (): void => { - if (this.state.circle !== null && this.props.onLoad) { - this.props.onLoad(this.state.circle) - } - } - - componentDidMount(): void { - const circle = new google.maps.Circle({ - ...(this.props.options || {}), - map: this.context, - }) - - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps: {}, - nextProps: this.props, - instance: circle, - }) - - this.setState(function setCircle() { - return { - circle, - } - }, this.setCircleCallback) - } - - componentDidUpdate(prevProps: CircleProps): void { - if (this.state.circle !== null) { - unregisterEvents(this.registeredEvents) - - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps, - nextProps: this.props, - instance: this.state.circle, - }) - } - } - - componentWillUnmount(): void { - if (this.state.circle !== null) { - if (this.props.onUnmount) { - this.props.onUnmount(this.state.circle) +function Circle(props: CircleProps): JSX.Element { + const { options, onLoad, onUnmount } = props + const map = React.useContext(MapContext) + const prevProps: CircleProps = usePrevious(props) + + const [instance, setInstance] = React.useState( + null + ) + + React.useEffect( + function effect() { + if (map !== null) { + if (instance === null) { + setInstance( + new google.maps.Circle({ + ...(options || {}), + map, + }) + ) + } + + if (instance !== null) { + instance.setMap(map) + + if (onLoad) { + onLoad(instance) + } + } } - unregisterEvents(this.registeredEvents) + return function cleanup() { + if (instance !== null) { + if (onUnmount) { + onUnmount(instance) + } - this.state.circle && this.state.circle.setMap(null) - } - } + instance.setMap(null) + } + } + }, + [instance, map, options, onLoad, onUnmount] + ) + + React.useEffect( + function effect(): () => void { + const registeredEvents: google.maps.MapsEventListener[] = applyUpdatersToPropsAndRegisterEvents( + { + updaterMap, + eventMap, + prevProps, + nextProps: props, + instance, + } + ) + + return function cleanup(): void { + unregisterEvents(registeredEvents) + } + }, + [props, instance, prevProps] + ) - render(): JSX.Element { - return <> - } + return <> } -export default Circle +export default React.memo(Circle) diff --git a/packages/react-google-maps-api/src/components/drawing/Data.md b/packages/react-google-maps-api/src/components/drawing/Data.md index 88ee3ae26..96f8a0a10 100644 --- a/packages/react-google-maps-api/src/components/drawing/Data.md +++ b/packages/react-google-maps-api/src/components/drawing/Data.md @@ -7,15 +7,79 @@ const ScriptLoaded = require("../../docs/ScriptLoaded").default; const mapContainerStyle = { height: "400px", width: "800px" -} +}; const center = { lat: 38.685, lng: -115.234 -} +}; const onLoad = data => { console.log('data: ', data) +}; + +const options = { + controlPosition: window.google ? window.google.maps.ControlPosition.TOP_LEFT : undefined, + controls: ["Point"], + drawingMode: "Point", // "LineString" or "Polygon". + featureFactory: geometry => { + console.log("geometry: ", geometry); + }, + // Type: boolean + // If true, the marker receives mouse and touch events. Default value is true. + clickable: true, + + // Type: string + // Mouse cursor to show on hover. Only applies to point geometries. + // cursor: 'cursor', + + // Type: boolean + // If true, the object can be dragged across the map and the underlying feature will have its geometry updated. Default value is false. + draggable: true, + + // Type: boolean + // If true, the object can be edited by dragging control points and the underlying feature will have its geometry updated. Only applies to LineString and Polygon geometries. Default value is false. + editable: false, + + // Type: string + // The fill color. All CSS3 colors are supported except for extended named colors. Only applies to polygon geometries. + fillColor: "#FF0055", + + // Type: number + // The fill opacity between 0.0 and 1.0. Only applies to polygon geometries. + fillOpacity: 1, + + // Type: string|Icon|Symbol + // Icon for the foreground. If a string is provided, it is treated as though it were an Icon with the string as url. Only applies to point geometries. + // icon: 'icon', + + // Type: MarkerShape + // Defines the image map used for hit detection. Only applies to point geometries. + // shape: 'shape', + + // Type: string + // The stroke color. All CSS3 colors are supported except for extended named colors. Only applies to line and polygon geometries. + strokeColor: "#00FF55", + + // Type: number + // The stroke opacity between 0.0 and 1.0. Only applies to line and polygon geometries. + strokeOpacity: 1, + + // Type: number + // The stroke width in pixels. Only applies to line and polygon geometries. + strokeWeight: 2, + + // Type: string + // Rollover text. Only applies to point geometries. + title: "Title", + + // Type: boolean + // Whether the feature is visible. Defaults to true. + visible: true, + + // Type: number + // All features are displayed on the map in order of their zIndex, with higher values displaying in front of features with lower values. Markers are always displayed in front of line-strings and polygons. + zIndex: 2 } @@ -27,69 +91,7 @@ const onLoad = data => { > { - console.log("geometry: ", geometry); - }, - // Type: boolean - // If true, the marker receives mouse and touch events. Default value is true. - clickable: true, - - // Type: string - // Mouse cursor to show on hover. Only applies to point geometries. - // cursor: 'cursor', - - // Type: boolean - // If true, the object can be dragged across the map and the underlying feature will have its geometry updated. Default value is false. - draggable: true, - - // Type: boolean - // If true, the object can be edited by dragging control points and the underlying feature will have its geometry updated. Only applies to LineString and Polygon geometries. Default value is false. - editable: false, - - // Type: string - // The fill color. All CSS3 colors are supported except for extended named colors. Only applies to polygon geometries. - fillColor: "#FF0055", - - // Type: number - // The fill opacity between 0.0 and 1.0. Only applies to polygon geometries. - fillOpacity: 1, - - // Type: string|Icon|Symbol - // Icon for the foreground. If a string is provided, it is treated as though it were an Icon with the string as url. Only applies to point geometries. - // icon: 'icon', - - // Type: MarkerShape - // Defines the image map used for hit detection. Only applies to point geometries. - // shape: 'shape', - - // Type: string - // The stroke color. All CSS3 colors are supported except for extended named colors. Only applies to line and polygon geometries. - strokeColor: "#00FF55", - - // Type: number - // The stroke opacity between 0.0 and 1.0. Only applies to line and polygon geometries. - strokeOpacity: 1, - - // Type: number - // The stroke width in pixels. Only applies to line and polygon geometries. - strokeWeight: 2, - - // Type: string - // Rollover text. Only applies to point geometries. - title: "Title", - - // Type: boolean - // Whether the feature is visible. Defaults to true. - visible: true, - - // Type: number - // All features are displayed on the map in order of their zIndex, with higher values displaying in front of features with lower values. Markers are always displayed in front of line-strings and polygons. - zIndex: 2 - }} + options={options} /> ; diff --git a/packages/react-google-maps-api/src/components/drawing/Data.tsx b/packages/react-google-maps-api/src/components/drawing/Data.tsx index 624fa3d89..66c0b540d 100644 --- a/packages/react-google-maps-api/src/components/drawing/Data.tsx +++ b/packages/react-google-maps-api/src/components/drawing/Data.tsx @@ -1,8 +1,11 @@ import * as React from 'react' -import { unregisterEvents, applyUpdatersToPropsAndRegisterEvents } from '../../utils/helper' - import MapContext from '../../map-context' +import { + unregisterEvents, + applyUpdatersToPropsAndRegisterEvents, +} from '../../utils/helper' +import { usePrevious } from '../../utils/use-previous' const eventMap = { onAddFeature: 'addfeature', @@ -28,15 +31,21 @@ const updaterMap = { }, addgeojson( instance: google.maps.Data, - geojson: object, + geojson: Record, options?: google.maps.Data.GeoJsonOptions ): void { instance.addGeoJson(geojson, options) }, - contains(instance: google.maps.Data, feature: google.maps.Data.Feature): void { + contains( + instance: google.maps.Data, + feature: google.maps.Data.Feature + ): void { instance.contains(feature) }, - foreach(instance: google.maps.Data, callback: (feature: google.maps.Data.Feature) => void): void { + foreach( + instance: google.maps.Data, + callback: (feature: google.maps.Data.Feature) => void + ): void { instance.forEach(callback) }, loadgeojson( @@ -57,13 +66,22 @@ const updaterMap = { remove(instance: google.maps.Data, feature: google.maps.Data.Feature): void { instance.remove(feature) }, - revertstyle(instance: google.maps.Data, feature: google.maps.Data.Feature): void { + revertstyle( + instance: google.maps.Data, + feature: google.maps.Data.Feature + ): void { instance.revertStyle(feature) }, - controlposition(instance: google.maps.Data, controlPosition: google.maps.ControlPosition): void { + controlposition( + instance: google.maps.Data, + controlPosition: google.maps.ControlPosition + ): void { instance.setControlPosition(controlPosition) }, - controls(instance: google.maps.Data, controls: google.maps.DrawingMode[] | null): void { + controls( + instance: google.maps.Data, + controls: google.maps.DrawingMode[] | null + ): void { instance.setControls(controls) }, drawingmode(instance: google.maps.Data, mode: google.maps.DrawingMode): void { @@ -78,14 +96,16 @@ const updaterMap = { ): void { instance.setStyle(style) }, - togeojson(instance: google.maps.Data, callback: (feature: object) => void): void { + togeojson( + instance: google.maps.Data, + // wait till @types/googlemapsapi support typescript 3.9.5 + // eslint-disable-next-line @typescript-eslint/ban-types + callback: (feature: object) => void + ): void { instance.toGeoJson(callback) }, } -interface DataState { - data: google.maps.Data | null -} export interface DataProps { options?: google.maps.Data.DataOptions /** This event is fired when a feature is added to the collection. */ @@ -118,73 +138,67 @@ export interface DataProps { onUnmount?: (data: google.maps.Data) => void } -export class Data extends React.PureComponent { - static contextType = MapContext - - registeredEvents: google.maps.MapsEventListener[] = [] - - state: DataState = { - data: null, - } - - setDataCallback = (): void => { - if (this.state.data !== null && this.props.onLoad) { - this.props.onLoad(this.state.data) - } - } - - componentDidMount(): void { - const data = new google.maps.Data({ - ...(this.props.options || {}), - map: this.context, - }) - - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps: {}, - nextProps: this.props, - instance: data, - }) - - this.setState(function setData() { - return { - data, +function Data(props: DataProps): JSX.Element { + const { options, onLoad, onUnmount } = props + const map = React.useContext(MapContext) + const prevProps: DataProps = usePrevious(props) + + const [instance, setInstance] = React.useState(null) + + React.useEffect( + function effect() { + if (map !== null) { + if (instance === null) { + setInstance( + new google.maps.Data({ + ...(options || {}), + map, + }) + ) + } + + if (instance !== null) { + instance.setMap(map) + + if (onLoad) { + onLoad(instance) + } + } } - }, this.setDataCallback) - } - - componentDidUpdate(prevProps: DataProps): void { - if (this.state.data !== null) { - unregisterEvents(this.registeredEvents) - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps, - nextProps: this.props, - instance: this.state.data, - }) - } - } + return function cleanup() { + if (instance !== null) { + if (onUnmount) { + onUnmount(instance) + } - componentWillUnmount(): void { - if (this.state.data !== null) { - if (this.props.onUnmount) { - this.props.onUnmount(this.state.data) + instance.setMap(null) + } } - - unregisterEvents(this.registeredEvents) - - if (this.state.data) { - this.state.data.setMap(null) + }, + [instance, map, options, onLoad, onUnmount] + ) + + React.useEffect( + function effect(): () => void { + const registeredEvents: google.maps.MapsEventListener[] = applyUpdatersToPropsAndRegisterEvents( + { + updaterMap, + eventMap, + prevProps, + nextProps: props, + instance, + } + ) + + return function cleanup(): void { + unregisterEvents(registeredEvents) } - } - } + }, + [props, instance, prevProps] + ) - render(): null { - return null - } + return <> } -export default Data +export default React.memo(Data) diff --git a/packages/react-google-maps-api/src/components/drawing/DrawingManager.tsx b/packages/react-google-maps-api/src/components/drawing/DrawingManager.tsx index 99dd6ef29..1b5a1f1ce 100644 --- a/packages/react-google-maps-api/src/components/drawing/DrawingManager.tsx +++ b/packages/react-google-maps-api/src/components/drawing/DrawingManager.tsx @@ -3,9 +3,12 @@ import * as React from 'react' import invariant from 'invariant' -import { unregisterEvents, applyUpdatersToPropsAndRegisterEvents } from '../../utils/helper' - import MapContext from '../../map-context' +import { + unregisterEvents, + applyUpdatersToPropsAndRegisterEvents, +} from '../../utils/helper' +import { usePrevious } from '../../utils/use-previous' const eventMap = { onCircleComplete: 'circlecomplete', @@ -31,10 +34,6 @@ const updaterMap = { }, } -interface DrawingManagerState { - drawingManager: google.maps.drawing.DrawingManager | null -} - export interface DrawingManagerProps { options?: google.maps.drawing.DrawingManagerOptions /** Changes the DrawingManager's drawing mode, which defines the type of overlay to be added on the map. Accepted values are 'marker', 'polygon', 'polyline', 'rectangle', 'circle', or null. A drawing mode of null means that the user can interact with the map as normal, and clicks do not draw anything. */ @@ -57,81 +56,76 @@ export interface DrawingManagerProps { onUnmount?: (drawingManager: google.maps.drawing.DrawingManager) => void } -export class DrawingManager extends React.PureComponent { - static contextType = MapContext - - registeredEvents: google.maps.MapsEventListener[] = [] - - state: DrawingManagerState = { - drawingManager: null, - } - - constructor(props: DrawingManagerProps) { - super(props) - - invariant( - !!google.maps.drawing, - `Did you include prop libraries={['drawing']} in the URL? %s`, - google.maps.drawing - ) - } - - setDrawingManagerCallback = (): void => { - if (this.state.drawingManager !== null && this.props.onLoad) { - this.props.onLoad(this.state.drawingManager) - } - } - - componentDidMount(): void { - const drawingManager = new google.maps.drawing.DrawingManager({ - ...(this.props.options || {}), - map: this.context, - }) - - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps: {}, - nextProps: this.props, - instance: drawingManager, - }) - - this.setState(function setDrawingManager() { - return { - drawingManager, - } - }, this.setDrawingManagerCallback) - } - - componentDidUpdate(prevProps: DrawingManagerProps): void { - if (this.state.drawingManager !== null) { - unregisterEvents(this.registeredEvents) - - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps, - nextProps: this.props, - instance: this.state.drawingManager, - }) - } - } - - componentWillUnmount(): void { - if (this.state.drawingManager !== null) { - if (this.props.onUnmount) { - this.props.onUnmount(this.state.drawingManager) +function DrawingManager(props: DrawingManagerProps): JSX.Element { + const { options, onLoad, onUnmount } = props + const map = React.useContext(MapContext) + const prevProps: DrawingManagerProps = usePrevious(props) + + const [ + instance, + setInstance, + ] = React.useState(null) + + React.useEffect( + function effect() { + invariant( + !!google.maps.drawing, + `Did you include prop libraries={['drawing']} in the URL? %s`, + google.maps.drawing + ) + + if (map !== null) { + if (instance === null) { + setInstance( + new google.maps.drawing.DrawingManager({ + ...(options || {}), + map, + }) + ) + } + + if (instance !== null) { + instance.setMap(map) + + if (onLoad) { + onLoad(instance) + } + } } - unregisterEvents(this.registeredEvents) + return function cleanup() { + if (instance !== null) { + if (onUnmount) { + onUnmount(instance) + } - this.state.drawingManager.setMap(null) - } - } + instance.setMap(null) + } + } + }, + [instance, map, options, onLoad, onUnmount] + ) + + React.useEffect( + function effect(): () => void { + const registeredEvents: google.maps.MapsEventListener[] = applyUpdatersToPropsAndRegisterEvents( + { + updaterMap, + eventMap, + prevProps, + nextProps: props, + instance, + } + ) + + return function cleanup(): void { + unregisterEvents(registeredEvents) + } + }, + [props, instance, prevProps] + ) - render(): JSX.Element { - return <> - } + return <> } -export default DrawingManager +export default React.memo(DrawingManager) diff --git a/packages/react-google-maps-api/src/components/drawing/InfoWindow.tsx b/packages/react-google-maps-api/src/components/drawing/InfoWindow.tsx index c069e05a7..834ff6d26 100644 --- a/packages/react-google-maps-api/src/components/drawing/InfoWindow.tsx +++ b/packages/react-google-maps-api/src/components/drawing/InfoWindow.tsx @@ -1,10 +1,14 @@ /* global google */ import * as React from 'react' import * as ReactDOM from 'react-dom' -import { unregisterEvents, applyUpdatersToPropsAndRegisterEvents } from '../../utils/helper' +import invariant from 'invariant' import MapContext from '../../map-context' -import invariant from 'invariant' +import { + unregisterEvents, + applyUpdatersToPropsAndRegisterEvents, +} from '../../utils/helper' +import { usePrevious } from '../../utils/use-previous' const eventMap = { onCloseClick: 'closeclick', @@ -15,7 +19,10 @@ const eventMap = { } const updaterMap = { - options(instance: google.maps.InfoWindow, options: google.maps.InfoWindowOptions): void { + options( + instance: google.maps.InfoWindow, + options: google.maps.InfoWindowOptions + ): void { instance.setOptions(options) }, position( @@ -29,11 +36,8 @@ const updaterMap = { }, } -interface InfoWindowState { - infoWindow: google.maps.InfoWindow | null -} - export interface InfoWindowProps { + children: React.ReactNode /** Can be any MVCObject that exposes a LatLng position property and optionally a Point anchorPoint property for calculating the pixelOffset. The anchorPoint is the offset from the anchor's position to the tip of the InfoWindow. */ anchor?: google.maps.MVCObject options?: google.maps.InfoWindowOptions @@ -57,92 +61,91 @@ export interface InfoWindowProps { onUnmount?: (infoWindow: google.maps.InfoWindow) => void } -export class InfoWindow extends React.PureComponent { - static contextType = MapContext - - registeredEvents: google.maps.MapsEventListener[] = [] - containerElement: HTMLElement | null = null - - state: InfoWindowState = { - infoWindow: null, - } - - open = (infoWindow: google.maps.InfoWindow, anchor?: google.maps.MVCObject): void => { - if (anchor) { - infoWindow.open(this.context, anchor) - } else if (infoWindow.getPosition()) { - infoWindow.open(this.context) - } else { - invariant( - false, - `You must provide either an anchor (typically render it inside a ) or a position props for .` - ) - } - } - - setInfoWindowCallback = (): void => { - if (this.state.infoWindow !== null && this.containerElement !== null) { - this.state.infoWindow.setContent(this.containerElement) +function InfoWindow(props: InfoWindowProps): JSX.Element { + const { children, anchor, options, onLoad, onUnmount } = props + const map = React.useContext(MapContext) + const prevProps: InfoWindowProps = usePrevious(props) + const [ + containerElement, + setContainerElement, + ] = React.useState(null) + + const [instance, setInstance] = React.useState( + null + ) + + React.useEffect( + function effect() { + if (map !== null) { + if (instance === null) { + setInstance( + new google.maps.InfoWindow({ + ...(options || {}), + }) + ) + + setContainerElement(document.createElement('div')) + } + + if (instance !== null && containerElement !== null) { + instance.setContent(containerElement) + + if (anchor) { + instance.open(map, anchor) + } else if (instance.getPosition()) { + instance.open(map) + } else { + invariant( + false, + `You must provide either an anchor (typically render it inside a ) or a position props for .` + ) + } + + if (onLoad) { + onLoad(instance) + } + } + } - this.open(this.state.infoWindow, this.props.anchor) + return function cleanup() { + if (instance !== null) { + if (onUnmount) { + onUnmount(instance) + } - if (this.props.onLoad) { - this.props.onLoad(this.state.infoWindow) + instance.close() + } } - } - } - - componentDidMount(): void { - const infoWindow = new google.maps.InfoWindow({ - ...(this.props.options || {}), - }) - - this.containerElement = document.createElement('div') - - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps: {}, - nextProps: this.props, - instance: infoWindow, - }) - - this.setState(function setInfoWindow() { - return { - infoWindow, + }, + [instance, anchor, containerElement, map, options, onLoad, onUnmount] + ) + + React.useEffect( + function effect(): () => void { + const registeredEvents: google.maps.MapsEventListener[] = applyUpdatersToPropsAndRegisterEvents( + { + updaterMap, + eventMap, + prevProps, + nextProps: props, + instance, + } + ) + + return function cleanup(): void { + unregisterEvents(registeredEvents) } - }, this.setInfoWindowCallback) - } - - componentDidUpdate(prevProps: InfoWindowProps): void { - if (this.state.infoWindow !== null) { - unregisterEvents(this.registeredEvents) - - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps, - nextProps: this.props, - instance: this.state.infoWindow, - }) - } - } - - componentWillUnmount(): void { - if (this.state.infoWindow !== null) { - unregisterEvents(this.registeredEvents) - - this.state.infoWindow.close() - } - } - - render(): React.ReactPortal | React.ReactNode { - return this.containerElement ? ( - ReactDOM.createPortal(React.Children.only(this.props.children), this.containerElement) - ) : ( - <> - ) - } + }, + [props, instance, prevProps] + ) + + return containerElement ? ( + <> + {ReactDOM.createPortal(React.Children.only(children), containerElement)} + + ) : ( + <> + ) } -export default InfoWindow +export default React.memo(InfoWindow) diff --git a/packages/react-google-maps-api/src/components/drawing/Marker.tsx b/packages/react-google-maps-api/src/components/drawing/Marker.tsx index 15f243fd4..39c980569 100644 --- a/packages/react-google-maps-api/src/components/drawing/Marker.tsx +++ b/packages/react-google-maps-api/src/components/drawing/Marker.tsx @@ -1,14 +1,18 @@ import * as React from 'react' -import { unregisterEvents, applyUpdatersToPropsAndRegisterEvents } from '../../utils/helper' - import MapContext from '../../map-context' -import { HasMarkerAnchor } from '../../types' +import { + unregisterEvents, + applyUpdatersToPropsAndRegisterEvents, +} from '../../utils/helper' +import { usePrevious } from '../../utils/use-previous' import { Clusterer } from '@react-google-maps/marker-clusterer' -import { ReactNode } from 'react' -const eventMap = { +import { HasMarkerAnchor } from '../../types' +import MarkerOptions = google.maps.MarkerOptions + +export const eventMap = { onAnimationChanged: 'animation_changed', onClick: 'click', onClickableChanged: 'clickable_changed', @@ -32,8 +36,11 @@ const eventMap = { onZindexChanged: 'zindex_changed', } -const updaterMap = { - animation(instance: google.maps.Marker, animation: google.maps.Animation): void { +export const updaterMap = { + animation( + instance: google.maps.Marker, + animation: google.maps.Animation + ): void { instance.setAnimation(animation) }, clickable(instance: google.maps.Marker, clickable: boolean): void { @@ -45,10 +52,16 @@ const updaterMap = { draggable(instance: google.maps.Marker, draggable: boolean): void { instance.setDraggable(draggable) }, - icon(instance: google.maps.Marker, icon: string | google.maps.Icon | google.maps.Symbol): void { + icon( + instance: google.maps.Marker, + icon: string | google.maps.Icon | google.maps.Symbol + ): void { instance.setIcon(icon) }, - label(instance: google.maps.Marker, label: string | google.maps.MarkerLabel): void { + label( + instance: google.maps.Marker, + label: string | google.maps.MarkerLabel + ): void { instance.setLabel(label) }, map(instance: google.maps.Marker, map: google.maps.Map): void { @@ -57,7 +70,10 @@ const updaterMap = { opacity(instance: google.maps.Marker, opacity: number): void { instance.setOpacity(opacity) }, - options(instance: google.maps.Marker, options: google.maps.MarkerOptions): void { + options( + instance: google.maps.Marker, + options: google.maps.MarkerOptions + ): void { instance.setOptions(options) }, position( @@ -80,11 +96,8 @@ const updaterMap = { }, } -interface MarkerState { - marker: google.maps.Marker | null -} - export interface MarkerProps { + children?: React.ReactNode options?: google.maps.MarkerOptions /** Start an animation. Any ongoing animation will be cancelled. Currently supported animations are: BOUNCE, DROP. Passing in null will cause any animation to stop. */ animation?: google.maps.Animation @@ -104,6 +117,13 @@ export interface MarkerProps { // required /** Marker position. */ position: google.maps.LatLng | google.maps.LatLngLiteral + /** customizable marker factory for extensions */ + markerFactory?: (options: MarkerOptions) => google.maps.Marker + /** customizable updaters for extensions */ + defaultUpdaterMap?: Record< + string, + (instance: google.maps.Marker, ...options: any[]) => void + > /** Image map region definition used for drag/click. */ shape?: google.maps.MarkerShape /** Rollover text */ @@ -118,7 +138,7 @@ export interface MarkerProps { noClustererRedraw?: boolean /** This event is fired when the marker icon was clicked. */ onClick?: (e: google.maps.MouseEvent) => void - /** This event is fired when the marker's clickable property changes. */ + /** This event is fired when the marker's clickable property changes. */ onClickableChanged?: () => void /** This event is fired when the marker's cursor property changes. */ onCursorChanged?: () => void @@ -164,105 +184,118 @@ export interface MarkerProps { onUnmount?: (marker: google.maps.Marker) => void } -export class Marker extends React.PureComponent { - static contextType = MapContext +const createMarker = (options: MarkerOptions) => new google.maps.Marker(options) - registeredEvents: google.maps.MapsEventListener[] = [] +function Marker(props: MarkerProps): JSX.Element { + const { + children, + options, + position, + clusterer, + noClustererRedraw, + onLoad, + onUnmount, + defaultUpdaterMap = updaterMap, + markerFactory = createMarker, + } = props + const map = React.useContext(MapContext) + const prevProps: MarkerProps = usePrevious(props) - state: MarkerState = { - marker: null, - } + const [instance, setInstance] = React.useState( + null + ) - setMarkerCallback = (): void => { - if (this.state.marker !== null && this.props.onLoad) { - this.props.onLoad(this.state.marker) - } - } - - componentDidMount(): void { - const markerOptions = { - ...(this.props.options || {}), - ...(this.props.clusterer ? {} : { map: this.context }), - position: this.props.position, - } + React.useEffect( + function effect() { + if (map !== null) { + if (instance === null) { + const marker = markerFactory({ + ...(options || {}), + ...(clusterer ? {} : { map }), + position, + }) - const marker = new google.maps.Marker(markerOptions) + if (clusterer) { + clusterer.addMarker(marker, !!noClustererRedraw) + } else { + marker.setMap(map) + } - if (this.props.clusterer) { - this.props.clusterer.addMarker( - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore - // @ts-ignore - marker, - !!this.props.noClustererRedraw - ) - } else { - marker.setMap(this.context) - } + setInstance(marker) + } - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps: {}, - nextProps: this.props, - instance: marker, - }) + if (instance !== null) { + instance.setMap(map) - this.setState(function setMarker() { - return { - marker, + if (onLoad) { + onLoad(instance) + } + } } - }, this.setMarkerCallback) - } - - componentDidUpdate(prevProps: MarkerProps): void { - if (this.state.marker !== null) { - unregisterEvents(this.registeredEvents) - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps, - nextProps: this.props, - instance: this.state.marker, - }) - } - } + return function cleanup() { + if (instance !== null) { + if (onUnmount) { + onUnmount(instance) + } - componentWillUnmount(): void { - if (this.state.marker !== null) { - if (this.props.onUnmount) { - this.props.onUnmount(this.state.marker) + if (clusterer) { + clusterer.removeMarker(instance, !!noClustererRedraw) + } else { + instance && instance.setMap(null) + } + } } + }, + [ + instance, + map, + options, + clusterer, + noClustererRedraw, + position, + onLoad, + onUnmount, + markerFactory, + ] + ) - unregisterEvents(this.registeredEvents) + React.useEffect( + function effect(): () => void { + const registeredEvents: google.maps.MapsEventListener[] = applyUpdatersToPropsAndRegisterEvents( + { + updaterMap: defaultUpdaterMap, + eventMap, + prevProps, + nextProps: props, + instance, + } + ) - if (this.props.clusterer) { - this.props.clusterer.removeMarker( - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore - // @ts-ignore - this.state.marker, - !!this.props.noClustererRedraw - ) - } else { - this.state.marker && this.state.marker.setMap(null) + return function cleanup(): void { + unregisterEvents(registeredEvents) } - } - } + }, + [props, instance, prevProps, defaultUpdaterMap] + ) - render(): React.ReactNode { - let children: ReactNode | null = null - if(this.props.children) { - children = React.Children.map(this.props.children, child => { - if(!React.isValidElement(child)) { - return child; - } + if (children) { + return ( + <> + {React.Children.map(children, function mapper(child) { + if (!React.isValidElement(child)) { + return child + } + + const elementChild: React.ReactElement = child - let elementChild: React.ReactElement = child; - return React.cloneElement(elementChild, {anchor: this.state.marker}); - }) - } - return children || null + return React.cloneElement(elementChild, { anchor: instance }) + })} + + ) + } else { + return <> } } -export default Marker +export default React.memo(Marker) diff --git a/packages/react-google-maps-api/src/components/drawing/MarkerWithLabel.md b/packages/react-google-maps-api/src/components/drawing/MarkerWithLabel.md new file mode 100644 index 000000000..47490969c --- /dev/null +++ b/packages/react-google-maps-api/src/components/drawing/MarkerWithLabel.md @@ -0,0 +1,57 @@ +# MarkerWithLabel example + +```jsx +const { GoogleMap, LoadScript } = require("../../"); +const ScriptLoaded = require("../../docs/ScriptLoaded").default; + +const mapContainerStyle = { + height: "400px", + width: "800px" +} + +const center = { + lat: 0, + lng: -180 +} + +const position = { + lat: 37.772, + lng: -122.214 +} +const labelStyle = { + textAlign: "center", + width: "auto", + backgroundColor: "purple", + fontSize: "14px", + borderRadius: '3px', + color: '#fff', + transform: "translateX(-50%) translateY(-50%)", + padding: '5px' +} +const icon= { + size: { width: 1, height: 1 }, + url: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQYV2Pg9VD6DwACVAF3tB1M7gAAAABJRU5ErkJggg==' +} + +const onLoad = marker => { + console.log('marker: ', marker) +} + + + + Custom Marker + + +``` diff --git a/packages/react-google-maps-api/src/components/drawing/MarkerWithLabel.tsx b/packages/react-google-maps-api/src/components/drawing/MarkerWithLabel.tsx new file mode 100644 index 000000000..31680c820 --- /dev/null +++ b/packages/react-google-maps-api/src/components/drawing/MarkerWithLabel.tsx @@ -0,0 +1,83 @@ +import React, { + FC, + CSSProperties, + useEffect, + memo, + useCallback, + useState, +} from 'react' +import ReactDOM from 'react-dom' +import Marker, { MarkerProps, updaterMap } from './Marker' +import markerWithLabelFactory from 'markerwithlabel' + +export interface MarkerWithLabelProps extends MarkerProps { + labelAnchor?: google.maps.Point + labelClass?: string + labelStyle?: CSSProperties + labelVisible?: boolean +} + +const markerWithLabelUpdaterMap = { + labelAnchor(instance: google.maps.Marker, labelAnchor: google.maps.Point) { + instance.set(`labelAnchor`, labelAnchor) + }, + labelClass(instance: google.maps.Marker, labelClass: string) { + instance.set(`labelClass`, labelClass) + }, + labelStyle(instance: google.maps.Marker, labelStyle: CSSProperties) { + instance.set(`labelStyle`, labelStyle) + }, + labelVisible(instance: google.maps.Marker, labelVisible: boolean) { + instance.set(`labelVisible`, labelVisible) + }, + ...updaterMap, +} + +const MarkerWithLabel: FC = ({ + labelAnchor, + labelClass, + labelStyle, + labelVisible, + ...rest +}) => { + const [ + containerElement, + setContainerElement, + ] = useState(null) + + useEffect(() => { + setContainerElement(document.createElement('div')) + }, [setContainerElement]) + + const createMarker = useCallback( + (markerOptions: google.maps.MarkerOptions) => { + const MarkerWithLabel = markerWithLabelFactory(google.maps) + const marker = new MarkerWithLabel({ + ...markerOptions, + labelAnchor, + labelClass, + labelStyle, + labelVisible, + }) + marker.set('labelContent', containerElement) + return marker + }, + [containerElement, labelAnchor, labelClass, labelStyle, labelVisible] + ) + + return ( + <> + {containerElement && + ReactDOM.createPortal( + , + containerElement + )} + + ) +} + +export default memo(MarkerWithLabel) diff --git a/packages/react-google-maps-api/src/components/drawing/Polygon.tsx b/packages/react-google-maps-api/src/components/drawing/Polygon.tsx index 705e1c54d..895832d40 100644 --- a/packages/react-google-maps-api/src/components/drawing/Polygon.tsx +++ b/packages/react-google-maps-api/src/components/drawing/Polygon.tsx @@ -1,9 +1,12 @@ /* global google */ import * as React from 'react' -import { unregisterEvents, applyUpdatersToPropsAndRegisterEvents } from '../../utils/helper' - import MapContext from '../../map-context' +import { + unregisterEvents, + applyUpdatersToPropsAndRegisterEvents, +} from '../../utils/helper' +import { usePrevious } from '../../utils/use-previous' const eventMap = { onClick: 'click', @@ -29,7 +32,10 @@ const updaterMap = { map(instance: google.maps.Polygon, map: google.maps.Map): void { instance.setMap(map) }, - options(instance: google.maps.Polygon, options: google.maps.PolygonOptions): void { + options( + instance: google.maps.Polygon, + options: google.maps.PolygonOptions + ): void { instance.setOptions(options) }, path( @@ -60,10 +66,6 @@ const updaterMap = { }, } -interface PolygonState { - polygon: google.maps.Polygon | null -} - export interface PolygonProps { options?: google.maps.PolygonOptions /** If set to true, the user can drag this shape over the map. The geodesic property defines the mode of dragging. */ @@ -113,71 +115,69 @@ export interface PolygonProps { onUnmount?: (polygon: google.maps.Polygon) => void } -export class Polygon extends React.PureComponent { - static contextType = MapContext - - registeredEvents: google.maps.MapsEventListener[] = [] - - state: PolygonState = { - polygon: null, - } - - setPolygonCallback = (): void => { - if (this.state.polygon !== null && this.props.onLoad) { - this.props.onLoad(this.state.polygon) - } - } - - componentDidMount(): void { - const polygon = new google.maps.Polygon({ - ...(this.props.options || {}), - map: this.context, - }) - - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps: {}, - nextProps: this.props, - instance: polygon, - }) - - this.setState(function setPolygon() { - return { - polygon, - } - }, this.setPolygonCallback) - } - - componentDidUpdate(prevProps: PolygonProps): void { - if (this.state.polygon !== null) { - unregisterEvents(this.registeredEvents) - - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps, - nextProps: this.props, - instance: this.state.polygon, - }) - } - } - - componentWillUnmount(): void { - if (this.state.polygon !== null) { - if (this.props.onUnmount) { - this.props.onUnmount(this.state.polygon) +function Polygon(props: PolygonProps): JSX.Element { + const { options, onLoad, onUnmount } = props + const map = React.useContext(MapContext) + const prevProps: PolygonProps = usePrevious(props) + + const [instance, setInstance] = React.useState( + null + ) + + React.useEffect( + function effect() { + if (map !== null) { + if (instance === null) { + setInstance( + new google.maps.Polygon({ + ...(options || {}), + map, + }) + ) + } + + if (instance !== null) { + instance.setMap(map) + + if (onLoad) { + onLoad(instance) + } + } } - unregisterEvents(this.registeredEvents) + return function cleanup() { + if (instance !== null) { + if (onUnmount) { + onUnmount(instance) + } - this.state.polygon && this.state.polygon.setMap(null) - } - } + instance.setMap(null) + } + } + }, + [instance, map, options, onLoad, onUnmount] + ) + + React.useEffect( + function effect(): () => void { + const registeredEvents: google.maps.MapsEventListener[] = applyUpdatersToPropsAndRegisterEvents( + { + updaterMap, + eventMap, + prevProps, + nextProps: props, + instance, + } + ) + + return function cleanup(): void { + unregisterEvents(registeredEvents) + } + }, + [props, instance, prevProps] + ) - render(): React.ReactNode { - return null - } + return <> } -export default Polygon +export default React.memo(Polygon) diff --git a/packages/react-google-maps-api/src/components/drawing/Polyline.tsx b/packages/react-google-maps-api/src/components/drawing/Polyline.tsx index 3737de075..13cba7783 100644 --- a/packages/react-google-maps-api/src/components/drawing/Polyline.tsx +++ b/packages/react-google-maps-api/src/components/drawing/Polyline.tsx @@ -1,8 +1,11 @@ import * as React from 'react' -import { unregisterEvents, applyUpdatersToPropsAndRegisterEvents } from '../../utils/helper' - import MapContext from '../../map-context' +import { + unregisterEvents, + applyUpdatersToPropsAndRegisterEvents, +} from '../../utils/helper' +import { usePrevious } from '../../utils/use-previous' const eventMap = { onClick: 'click', @@ -28,7 +31,10 @@ const updaterMap = { map(instance: google.maps.Polyline, map: google.maps.Map): void { instance.setMap(map) }, - options(instance: google.maps.Polyline, options: google.maps.PolylineOptions): void { + options( + instance: google.maps.Polyline, + options: google.maps.PolylineOptions + ): void { instance.setOptions(options) }, path( @@ -45,10 +51,6 @@ const updaterMap = { }, } -interface PolylineState { - polyline: google.maps.Polyline | null -} - export interface PolylineProps { options?: google.maps.PolylineOptions /** If set to true, the user can drag this shape over the map. The geodesic property defines the mode of dragging. */ @@ -90,71 +92,69 @@ export interface PolylineProps { onUnmount?: (polyline: google.maps.Polyline) => void } -export class Polyline extends React.PureComponent { - static contextType = MapContext - - registeredEvents: google.maps.MapsEventListener[] = [] - - state: PolylineState = { - polyline: null, - } - - setPolylineCallback = (): void => { - if (this.state.polyline !== null && this.props.onLoad) { - this.props.onLoad(this.state.polyline) - } - } - - componentDidMount(): void { - const polyline = new google.maps.Polyline({ - ...(this.props.options || {}), - map: this.context, - }) - - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps: {}, - nextProps: this.props, - instance: polyline, - }) - - this.setState(function setPolyline() { - return { - polyline, +function Polyline(props: PolylineProps): JSX.Element { + const { options, onLoad, onUnmount } = props + const map = React.useContext(MapContext) + const prevProps: PolylineProps = usePrevious(props) + + const [instance, setInstance] = React.useState( + null + ) + + React.useEffect( + function effect() { + if (map !== null) { + if (instance === null) { + setInstance( + new google.maps.Polyline({ + ...(options || {}), + map, + }) + ) + } + + if (instance !== null) { + instance.setMap(map) + + if (onLoad) { + onLoad(instance) + } + } } - }, this.setPolylineCallback) - } - - componentDidUpdate(prevProps: PolylineProps): void { - if (this.state.polyline !== null) { - unregisterEvents(this.registeredEvents) - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps, - nextProps: this.props, - instance: this.state.polyline, - }) - } - } + return function cleanup() { + if (instance !== null) { + if (onUnmount) { + onUnmount(instance) + } - componentWillUnmount(): void { - if (this.state.polyline !== null) { - if (this.props.onUnmount) { - this.props.onUnmount(this.state.polyline) + instance.setMap(null) + } } + }, + [instance, map, options, onLoad, onUnmount] + ) + + React.useEffect( + function effect(): () => void { + const registeredEvents: google.maps.MapsEventListener[] = applyUpdatersToPropsAndRegisterEvents( + { + updaterMap, + eventMap, + prevProps, + nextProps: props, + instance, + } + ) + + return function cleanup(): void { + unregisterEvents(registeredEvents) + } + }, + [props, instance, prevProps] + ) - unregisterEvents(this.registeredEvents) - - this.state.polyline.setMap(null) - } - } - - render(): React.ReactNode { - return <> - } + return <> } -export default Polyline +export default React.memo(Polyline) diff --git a/packages/react-google-maps-api/src/components/drawing/Rectangle.tsx b/packages/react-google-maps-api/src/components/drawing/Rectangle.tsx index b172b7ca7..182f1bd50 100644 --- a/packages/react-google-maps-api/src/components/drawing/Rectangle.tsx +++ b/packages/react-google-maps-api/src/components/drawing/Rectangle.tsx @@ -1,7 +1,11 @@ import * as React from 'react' -import { unregisterEvents, applyUpdatersToPropsAndRegisterEvents } from '../../utils/helper' import MapContext from '../../map-context' +import { + unregisterEvents, + applyUpdatersToPropsAndRegisterEvents, +} from '../../utils/helper' +import { usePrevious } from '../../utils/use-previous' const eventMap = { onBoundsChanged: 'bounds_changed', @@ -34,7 +38,10 @@ const updaterMap = { map(instance: google.maps.Rectangle, map: google.maps.Map): void { instance.setMap(map) }, - options(instance: google.maps.Rectangle, options: google.maps.RectangleOptions): void { + options( + instance: google.maps.Rectangle, + options: google.maps.RectangleOptions + ): void { instance.setOptions(options) }, visible(instance: google.maps.Rectangle, visible: boolean): void { @@ -42,10 +49,6 @@ const updaterMap = { }, } -interface RectangleState { - rectangle: google.maps.Rectangle | null -} - export interface RectangleProps { options?: google.maps.RectangleOptions /** Sets the bounds of this rectangle. */ @@ -88,71 +91,69 @@ export interface RectangleProps { onUnmount?: (rectangle: google.maps.Rectangle) => void } -export class Rectangle extends React.PureComponent { - static contextType = MapContext - - registeredEvents: google.maps.MapsEventListener[] = [] - - state: RectangleState = { - rectangle: null, - } - - setRectangleCallback = (): void => { - if (this.state.rectangle !== null && this.props.onLoad) { - this.props.onLoad(this.state.rectangle) - } - } - - componentDidMount(): void { - const rectangle = new google.maps.Rectangle({ - ...(this.props.options || {}), - map: this.context, - }) - - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps: {}, - nextProps: this.props, - instance: rectangle, - }) - - this.setState(function setRectangle() { - return { - rectangle, +function Rectangle(props: RectangleProps): JSX.Element { + const { options, onLoad, onUnmount } = props + const map = React.useContext(MapContext) + const prevProps: RectangleProps = usePrevious(props) + + const [instance, setInstance] = React.useState( + null + ) + + React.useEffect( + function effect() { + if (map !== null) { + if (instance === null) { + setInstance( + new google.maps.Rectangle({ + ...(options || {}), + map, + }) + ) + } + + if (instance !== null) { + instance.setMap(map) + + if (onLoad) { + onLoad(instance) + } + } } - }, this.setRectangleCallback) - } - - componentDidUpdate(prevProps: RectangleProps): void { - if (this.state.rectangle !== null) { - unregisterEvents(this.registeredEvents) - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps, - nextProps: this.props, - instance: this.state.rectangle, - }) - } - } + return function cleanup() { + if (instance !== null) { + if (onUnmount) { + onUnmount(instance) + } - componentWillUnmount(): void { - if (this.state.rectangle !== null) { - if (this.props.onUnmount) { - this.props.onUnmount(this.state.rectangle) + instance.setMap(null) + } } + }, + [instance, map, options, onLoad, onUnmount] + ) + + React.useEffect( + function effect(): () => void { + const registeredEvents: google.maps.MapsEventListener[] = applyUpdatersToPropsAndRegisterEvents( + { + updaterMap, + eventMap, + prevProps, + nextProps: props, + instance, + } + ) + + return function cleanup(): void { + unregisterEvents(registeredEvents) + } + }, + [props, instance, prevProps] + ) - unregisterEvents(this.registeredEvents) - - this.state.rectangle.setMap(null) - } - } - - render(): React.ReactNode { - return <> - } + return <> } -export default Rectangle +export default React.memo(Rectangle) diff --git a/packages/react-google-maps-api/src/components/heatmap/HeatmapLayer.tsx b/packages/react-google-maps-api/src/components/heatmap/HeatmapLayer.tsx index ebb021d62..d2dd19bc8 100644 --- a/packages/react-google-maps-api/src/components/heatmap/HeatmapLayer.tsx +++ b/packages/react-google-maps-api/src/components/heatmap/HeatmapLayer.tsx @@ -1,9 +1,12 @@ import * as React from 'react' import invariant from 'invariant' -import { unregisterEvents, applyUpdatersToPropsAndRegisterEvents } from '../../utils/helper' - import MapContext from '../../map-context' +import { + unregisterEvents, + applyUpdatersToPropsAndRegisterEvents, +} from '../../utils/helper' +import { usePrevious } from '../../utils/use-previous' const eventMap = {} @@ -11,13 +14,18 @@ const updaterMap = { data( instance: google.maps.visualization.HeatmapLayer, data: - | google.maps.MVCArray + | google.maps.MVCArray< + google.maps.LatLng | google.maps.visualization.WeightedLocation + > | google.maps.LatLng[] | google.maps.visualization.WeightedLocation[] ): void { instance.setData(data) }, - map(instance: google.maps.visualization.HeatmapLayer, map: google.maps.Map): void { + map( + instance: google.maps.visualization.HeatmapLayer, + map: google.maps.Map + ): void { instance.setMap(map) }, options( @@ -28,15 +36,13 @@ const updaterMap = { }, } -interface HeatmapLayerState { - heatmapLayer: google.maps.visualization.HeatmapLayer | null -} - export interface HeatmapLayerProps { // required /** The data points to display. Required. */ data: - | google.maps.MVCArray + | google.maps.MVCArray< + google.maps.LatLng | google.maps.visualization.WeightedLocation + > | google.maps.LatLng[] | google.maps.visualization.WeightedLocation[] options?: google.maps.visualization.HeatmapLayerOptions @@ -46,78 +52,78 @@ export interface HeatmapLayerProps { onUnmount?: (heatmapLayer: google.maps.visualization.HeatmapLayer) => void } -export class HeatmapLayer extends React.PureComponent { - static contextType = MapContext - - registeredEvents: google.maps.MapsEventListener[] = [] - - state: HeatmapLayerState = { - heatmapLayer: null, - } - - setHeatmapLayerCallback = (): void => { - if (this.state.heatmapLayer !== null && this.props.onLoad) { - this.props.onLoad(this.state.heatmapLayer) - } - } - - componentDidMount(): void { - invariant( - !!google.maps.visualization, - 'Did you include prop libraries={["visualization"]} to ? %s', - google.maps.visualization - ) - - invariant(!!this.props.data, 'data property is required in HeatmapLayer %s', this.props.data) - - const heatmapLayer = new google.maps.visualization.HeatmapLayer({ - ...(this.props.options || {}), - data: this.props.data, - map: this.context, - }) - - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps: {}, - nextProps: this.props, - instance: heatmapLayer, - }) - - this.setState(function setHeatmapLayer() { - return { - heatmapLayer, - } - }, this.setHeatmapLayerCallback) - } - - componentDidUpdate(prevProps: HeatmapLayerProps): void { - unregisterEvents(this.registeredEvents) - - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps, - nextProps: this.props, - instance: this.state.heatmapLayer, - }) - } - - componentWillUnmount(): void { - if (this.state.heatmapLayer !== null) { - if (this.props.onUnmount) { - this.props.onUnmount(this.state.heatmapLayer) +function HeatmapLayer(props: HeatmapLayerProps): JSX.Element { + const { data, options, onLoad, onUnmount } = props + const map = React.useContext(MapContext) + const prevProps: HeatmapLayerProps = usePrevious(props) + const [ + instance, + setInstance, + ] = React.useState(null) + + React.useEffect( + function effect() { + invariant( + !!google.maps.visualization, + 'Did you include prop libraries={["visualization"]} to ? %s', + google.maps.visualization + ) + + invariant(!!data, 'data property is required in HeatmapLayer %s', data) + + if (map !== null) { + if (instance === null) { + setInstance( + new google.maps.visualization.HeatmapLayer({ + ...(options || {}), + data, + map, + }) + ) + } + + if (instance !== null) { + instance.setMap(map) + + if (onLoad) { + onLoad(instance) + } + } } - unregisterEvents(this.registeredEvents) + return function cleanup() { + if (instance !== null) { + if (onUnmount) { + onUnmount(instance) + } - this.state.heatmapLayer.setMap(null) - } - } + instance.setMap(null) + } + } + }, + [instance, data, map, options, onLoad, onUnmount] + ) + + React.useEffect( + function effect(): () => void { + const registeredEvents: google.maps.MapsEventListener[] = applyUpdatersToPropsAndRegisterEvents( + { + updaterMap, + eventMap, + prevProps, + nextProps: props, + instance, + } + ) + + return function cleanup(): void { + unregisterEvents(registeredEvents) + } + }, + [props, instance, prevProps] + ) - render(): React.ReactNode { - return null - } + return <> } -export default HeatmapLayer +export default React.memo(HeatmapLayer) diff --git a/packages/react-google-maps-api/src/components/kml/KmlLayer.tsx b/packages/react-google-maps-api/src/components/kml/KmlLayer.tsx index aa45ab9ce..70bbaa4ee 100644 --- a/packages/react-google-maps-api/src/components/kml/KmlLayer.tsx +++ b/packages/react-google-maps-api/src/components/kml/KmlLayer.tsx @@ -1,7 +1,11 @@ -import { PureComponent } from 'react' +import * as React from 'react' -import { unregisterEvents, applyUpdatersToPropsAndRegisterEvents } from '../../utils/helper' +import { + unregisterEvents, + applyUpdatersToPropsAndRegisterEvents, +} from '../../utils/helper' import MapContext from '../../map-context' +import { usePrevious } from '../../utils/use-previous' const eventMap = { onClick: 'click', @@ -10,7 +14,10 @@ const eventMap = { } const updaterMap = { - options(instance: google.maps.KmlLayer, options: google.maps.KmlLayerOptions): void { + options( + instance: google.maps.KmlLayer, + options: google.maps.KmlLayerOptions + ): void { instance.setOptions(options) }, url(instance: google.maps.KmlLayer, url: string): void { @@ -21,10 +28,6 @@ const updaterMap = { }, } -interface KmlLayerState { - kmlLayer: google.maps.KmlLayer | null -} - export interface KmlLayerProps { options?: google.maps.KmlLayerOptions /** The URL of the KML document to display. */ @@ -43,71 +46,69 @@ export interface KmlLayerProps { onUnmount: (kmlLayer: google.maps.KmlLayer) => void } -export class KmlLayer extends PureComponent { - static contextType = MapContext - - registeredEvents: google.maps.MapsEventListener[] = [] - - state: KmlLayerState = { - kmlLayer: null, - } - - setKmlLayerCallback = (): void => { - if (this.state.kmlLayer !== null && this.props.onLoad) { - this.props.onLoad(this.state.kmlLayer) - } - } - - componentDidMount(): void { - const kmlLayer = new google.maps.KmlLayer({ - ...this.props.options, - map: this.context, - }) - - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps: {}, - nextProps: this.props, - instance: kmlLayer, - }) - - this.setState(function setLmlLayer() { - return { - kmlLayer, +function KmlLayer(props: KmlLayerProps): JSX.Element { + const { options, onLoad, onUnmount } = props + const map = React.useContext(MapContext) + const prevProps: KmlLayerProps = usePrevious(props) + + const [instance, setInstance] = React.useState( + null + ) + + React.useEffect( + function effect() { + if (map !== null) { + if (instance === null) { + setInstance( + new google.maps.KmlLayer({ + ...(options || {}), + map, + }) + ) + } + + if (instance !== null) { + instance.setMap(map) + + if (onLoad) { + onLoad(instance) + } + } } - }, this.setKmlLayerCallback) - } - - componentDidUpdate(prevProps: KmlLayerProps): void { - if (this.state.kmlLayer !== null) { - unregisterEvents(this.registeredEvents) - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps, - nextProps: this.props, - instance: this.state.kmlLayer, - }) - } - } + return function cleanup() { + if (instance !== null) { + if (onUnmount) { + onUnmount(instance) + } - componentWillUnmount(): void { - if (this.state.kmlLayer !== null) { - if (this.props.onUnmount) { - this.props.onUnmount(this.state.kmlLayer) + instance.setMap(null) + } } + }, + [instance, map, options, onLoad, onUnmount] + ) + + React.useEffect( + function effect(): () => void { + const registeredEvents: google.maps.MapsEventListener[] = applyUpdatersToPropsAndRegisterEvents( + { + updaterMap, + eventMap, + prevProps, + nextProps: props, + instance, + } + ) + + return function cleanup(): void { + unregisterEvents(registeredEvents) + } + }, + [props, instance, prevProps] + ) - unregisterEvents(this.registeredEvents) - - this.state.kmlLayer.setMap(null) - } - } - - render(): React.ReactNode { - return null - } + return <> } -export default KmlLayer +export default React.memo(KmlLayer) diff --git a/packages/react-google-maps-api/src/components/maps/BicyclingLayer.tsx b/packages/react-google-maps-api/src/components/maps/BicyclingLayer.tsx index 3a3bb830e..b8ac348fb 100644 --- a/packages/react-google-maps-api/src/components/maps/BicyclingLayer.tsx +++ b/packages/react-google-maps-api/src/components/maps/BicyclingLayer.tsx @@ -2,10 +2,6 @@ import * as React from 'react' import MapContext from '../../map-context' -interface BicyclingLayerState { - bicyclingLayer: google.maps.BicyclingLayer | null -} - export interface BicyclingLayerProps { /** This callback is called when the bicyclingLayer instance has loaded. It is called with the bicyclingLayer instance. */ onLoad?: (bicyclingLayer: google.maps.BicyclingLayer) => void @@ -13,55 +9,47 @@ export interface BicyclingLayerProps { onUnmount?: (bicyclingLayer: google.maps.BicyclingLayer) => void } -export class BicyclingLayer extends React.PureComponent { - static contextType = MapContext - - state = { - bicyclingLayer: null, - } - - setBicyclingLayerCallback = (): void => { - if (this.state.bicyclingLayer !== null) { - // TODO: how is this possibly null if we're doing a null check - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore - // @ts-ignore - this.state.bicyclingLayer.setMap(this.context) - - if (this.props.onLoad) { - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore - // @ts-ignore - this.props.onLoad(this.state.bicyclingLayer) +function BicyclingLayer({ + onLoad, + onUnmount, +}: BicyclingLayerProps): JSX.Element { + const map = React.useContext(MapContext) + + const [ + instance, + setInstance, + ] = React.useState(null) + + React.useEffect( + function effect() { + if (map !== null) { + if (instance === null) { + setInstance(new google.maps.BicyclingLayer()) + } + + if (instance !== null) { + instance.setMap(map) + + if (onLoad) { + onLoad(instance) + } + } } - } - } - - componentDidMount(): void { - const bicyclingLayer = new google.maps.BicyclingLayer() - this.setState(function setBicyclingLayer() { - return { - bicyclingLayer, - } - }, this.setBicyclingLayerCallback) - } + return function cleanup() { + if (instance !== null) { + if (onUnmount) { + onUnmount(instance) + } - componentWillUnmount(): void { - if (this.state.bicyclingLayer !== null) { - if (this.props.onUnmount) { - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore - // @ts-ignore - this.props.onUnmount(this.state.bicyclingLayer) + instance.setMap(null) + } } + }, + [instance, map, onLoad, onUnmount] + ) - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore - // @ts-ignore - this.state.bicyclingLayer.setMap(null) - } - } - - render(): React.ReactNode { - return null - } + return <> } -export default BicyclingLayer +export default React.memo(BicyclingLayer) diff --git a/packages/react-google-maps-api/src/components/maps/TrafficLayer.tsx b/packages/react-google-maps-api/src/components/maps/TrafficLayer.tsx index 913ffc080..b66995764 100644 --- a/packages/react-google-maps-api/src/components/maps/TrafficLayer.tsx +++ b/packages/react-google-maps-api/src/components/maps/TrafficLayer.tsx @@ -1,20 +1,23 @@ -import { PureComponent } from 'react' +import * as React from 'react' -import { unregisterEvents, applyUpdatersToPropsAndRegisterEvents } from '../../utils/helper' import MapContext from '../../map-context' +import { + unregisterEvents, + applyUpdatersToPropsAndRegisterEvents, +} from '../../utils/helper' +import { usePrevious } from '../../utils/use-previous' const eventMap = {} const updaterMap = { - options(instance: google.maps.TrafficLayer, options: google.maps.TrafficLayerOptions): void { + options( + instance: google.maps.TrafficLayer, + options: google.maps.TrafficLayerOptions + ): void { instance.setOptions(options) }, } -interface TrafficLayerState { - trafficLayer: google.maps.TrafficLayer | null -} - export interface TrafficLayerProps { options?: google.maps.TrafficLayerOptions /** This callback is called when the trafficLayer instance has loaded. It is called with the trafficLayer instance. */ @@ -23,79 +26,70 @@ export interface TrafficLayerProps { onUnmount?: (trafficLayer: google.maps.TrafficLayer) => void } -export class TrafficLayer extends PureComponent { - static contextType = MapContext - - state = { - trafficLayer: null, - } - - setTrafficLayerCallback = () => { - if (this.state.trafficLayer !== null) { - if (this.props.onLoad) { - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore - // @ts-ignore - this.props.onLoad(this.state.trafficLayer) +function TrafficLayer(props: TrafficLayerProps): JSX.Element { + const { options, onLoad, onUnmount } = props + const map = React.useContext(MapContext) + const prevProps: TrafficLayerProps = usePrevious(props) + + const [ + instance, + setInstance, + ] = React.useState(null) + + React.useEffect( + function effect() { + if (map !== null) { + if (instance === null) { + setInstance( + new google.maps.TrafficLayer({ + ...(options || {}), + map, + }) + ) + } + + if (instance !== null) { + instance.setMap(map) + + if (onLoad) { + onLoad(instance) + } + } } - } - } - - registeredEvents: google.maps.MapsEventListener[] = [] - - componentDidMount(): void { - const trafficLayer = new google.maps.TrafficLayer({ - ...(this.props.options || {}), - map: this.context, - }) - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps: {}, - nextProps: this.props, - instance: trafficLayer, - }) + return function cleanup() { + if (instance !== null) { + if (onUnmount) { + onUnmount(instance) + } - this.setState(function setTrafficLayer() { - return { - trafficLayer, + instance.setMap(null) + } } - }, this.setTrafficLayerCallback) - } - - componentDidUpdate(prevProps: TrafficLayerProps): void { - if (this.state.trafficLayer !== null) { - unregisterEvents(this.registeredEvents) - - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps, - nextProps: this.props, - instance: this.state.trafficLayer, - }) - } - } - - componentWillUnmount(): void { - if (this.state.trafficLayer !== null) { - if (this.props.onUnmount) { - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore - // @ts-ignore - this.props.onUnmount(this.state.trafficLayer) + }, + [instance, map, options, onLoad, onUnmount] + ) + + React.useEffect( + function effect(): () => void { + const registeredEvents: google.maps.MapsEventListener[] = applyUpdatersToPropsAndRegisterEvents( + { + updaterMap, + eventMap, + prevProps, + nextProps: props, + instance, + } + ) + + return function cleanup(): void { + unregisterEvents(registeredEvents) } + }, + [props, instance, prevProps] + ) - unregisterEvents(this.registeredEvents) - - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore - // @ts-ignore - this.state.trafficLayer.setMap(null) - } - } - - render() { - return null - } + return <> } -export default TrafficLayer +export default React.memo(TrafficLayer) diff --git a/packages/react-google-maps-api/src/components/maps/TransitLayer.tsx b/packages/react-google-maps-api/src/components/maps/TransitLayer.tsx index 3b12f472b..526296819 100644 --- a/packages/react-google-maps-api/src/components/maps/TransitLayer.tsx +++ b/packages/react-google-maps-api/src/components/maps/TransitLayer.tsx @@ -2,10 +2,6 @@ import * as React from 'react' import MapContext from '../../map-context' -interface TransitLayerState { - transitLayer: google.maps.TransitLayer | null -} - export interface TransitLayerProps { /** This callback is called when the transitLayer instance has loaded. It is called with the transitLayer instance. */ onLoad?: (transitLayer: google.maps.TransitLayer) => void @@ -13,55 +9,40 @@ export interface TransitLayerProps { onUnmount?: (transitLayer: google.maps.TransitLayer) => void } -export class TransitLayer extends React.PureComponent { - static contextType = MapContext - - state = { - transitLayer: null, - } +function TransitLayer(props: TransitLayerProps): JSX.Element { + const { onLoad, onUnmount } = props + const map = React.useContext(MapContext) - setTransitLayerCallback = (): void => { - if (this.state.transitLayer !== null) { - // TODO: how is this possibly null if we're doing a null check - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore - // @ts-ignore - this.state.transitLayer.setMap(this.context) + const [ + instance, + setInstance, + ] = React.useState(null) - if (this.props.onLoad) { - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore - // @ts-ignore - this.props.onLoad(this.state.transitLayer) - } - } - } + React.useEffect( + function effect(): () => void { + const newInstance: google.maps.TransitLayer = new google.maps.TransitLayer() + setInstance(newInstance) - componentDidMount(): void { - const transitLayer = new google.maps.TransitLayer() + newInstance.setMap(map) - this.setState(function setTransitLayer() { - return { - transitLayer, + if (onLoad) { + onLoad(newInstance) } - }, this.setTransitLayerCallback) - } - componentWillUnmount(): void { - if (this.state.transitLayer !== null) { - if (this.props.onUnmount) { - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore - // @ts-ignore - this.props.onUnmount(this.state.transitLayer) - } + return function cleanup(): void { + if (instance !== null) { + if (onUnmount) { + onUnmount(instance) + } - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore - // @ts-ignore - this.state.transitLayer.setMap(null) - } - } + instance.setMap(null) + } + } + }, + [instance, map, onLoad, onUnmount] + ) - render(): React.ReactNode { - return null - } + return <> } -export default TransitLayer +export default React.memo(TransitLayer) diff --git a/packages/react-google-maps-api/src/components/overlays/GroundOverlay.tsx b/packages/react-google-maps-api/src/components/overlays/GroundOverlay.tsx index 62db1a561..a4e416ffc 100644 --- a/packages/react-google-maps-api/src/components/overlays/GroundOverlay.tsx +++ b/packages/react-google-maps-api/src/components/overlays/GroundOverlay.tsx @@ -2,10 +2,13 @@ import * as React from 'react' import invariant from 'invariant' -import { unregisterEvents, applyUpdatersToPropsAndRegisterEvents } from '../../utils/helper' - +import { + unregisterEvents, + applyUpdatersToPropsAndRegisterEvents, +} from '../../utils/helper' import MapContext from '../../map-context' import { noop } from '../../utils/noop' +import { usePrevious } from '../../utils/use-previous' const eventMap = { onDblClick: 'dblclick', @@ -18,10 +21,6 @@ const updaterMap = { }, } -interface GroundOverlayState { - groundOverlay: google.maps.GroundOverlay | null -} - export interface GroundOverlayProps { options?: google.maps.GroundOverlayOptions /** The opacity of the overlay, expressed as a number between 0 and 1. Optional. Defaults to 1. */ @@ -40,78 +39,84 @@ export interface GroundOverlayProps { onUnmount?: (groundOverlay: google.maps.GroundOverlay) => void } -export class GroundOverlay extends React.PureComponent { - public static defaultProps = { - onLoad: noop, - } - - static contextType = MapContext - - registeredEvents: google.maps.MapsEventListener[] = [] - - state: GroundOverlayState = { - groundOverlay: null, - } - - setGroundOverlayCallback = (): void => { - if (this.state.groundOverlay !== null && this.props.onLoad) { - this.props.onLoad(this.state.groundOverlay) - } - } - - componentDidMount(): void { - invariant( - !!this.props.url || !!this.props.bounds, - `For GroundOverlay, url and bounds are passed in to constructor and are immutable after instantiated. This is the behavior of Google Maps JavaScript API v3 ( See https://developers.google.com/maps/documentation/javascript/reference#GroundOverlay) Hence, use the corresponding two props provided by \`react-google-maps-api\`, url and bounds. In some cases, you'll need the GroundOverlay component to reflect the changes of url and bounds. You can leverage the React's key property to remount the component. Typically, just \`key={url}\` would serve your need. See https://github.com/tomchentw/react-google-maps/issues/655` - ) - - const groundOverlay = new google.maps.GroundOverlay(this.props.url, this.props.bounds, { - ...this.props.options, - map: this.context, - }) - - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps: {}, - nextProps: this.props, - instance: groundOverlay, - }) - - this.setState(function setGroundOverlay() { - return { - groundOverlay, - } - }, this.setGroundOverlayCallback) - } - - componentDidUpdate(prevProps: GroundOverlayProps): void { - if (this.state.groundOverlay !== null) { - unregisterEvents(this.registeredEvents) - - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps, - nextProps: this.props, - instance: this.state.groundOverlay, - }) - } - } - - componentWillUnmount(): void { - if (this.state.groundOverlay) { - if (this.props.onUnmount) { - this.props.onUnmount(this.state.groundOverlay) +function GroundOverlay(props: GroundOverlayProps): JSX.Element { + const { + options, + // opacity, + // onDblClick, + // onClick, + url, + bounds, + onLoad = noop, + onUnmount, + } = props + const map = React.useContext(MapContext) + const prevProps: GroundOverlayProps = usePrevious(props) + + const [ + instance, + setInstance, + ] = React.useState(null) + + React.useEffect( + function effect() { + invariant( + !!url || !!bounds, + `For GroundOverlay, url and bounds are passed in to constructor and are immutable after instantiated. This is the behavior of Google Maps JavaScript API v3 ( See https://developers.google.com/maps/documentation/javascript/reference#GroundOverlay) Hence, use the corresponding two props provided by \`react-google-maps-api\`, url and bounds. In some cases, you'll need the GroundOverlay component to reflect the changes of url and bounds. You can leverage the React's key property to remount the component. Typically, just \`key={url}\` would serve your need. See https://github.com/tomchentw/react-google-maps/issues/655` + ) + + if (map !== null) { + if (instance === null) { + setInstance( + new google.maps.GroundOverlay(url, bounds, { + ...(options || {}), + map, + }) + ) + } + + if (instance !== null) { + instance.setMap(map) + + if (onLoad) { + onLoad(instance) + } + } } - this.state.groundOverlay.setMap(null) - } - } + return function cleanup() { + if (instance !== null) { + if (onUnmount) { + onUnmount(instance) + } + + instance.setMap(null) + } + } + }, + [instance, map, bounds, url, options, onLoad, onUnmount] + ) + + React.useEffect( + function effect(): () => void { + const registeredEvents: google.maps.MapsEventListener[] = applyUpdatersToPropsAndRegisterEvents( + { + updaterMap, + eventMap, + prevProps, + nextProps: props, + instance, + } + ) + + return function cleanup(): void { + unregisterEvents(registeredEvents) + } + }, + [props, instance, prevProps] + ) - render(): React.ReactNode { - return null - } + return <> } -export default GroundOverlay +export default React.memo(GroundOverlay) diff --git a/packages/react-google-maps-api/src/components/places/Autocomplete.tsx b/packages/react-google-maps-api/src/components/places/Autocomplete.tsx index 3fbd53cbd..d119eccfc 100644 --- a/packages/react-google-maps-api/src/components/places/Autocomplete.tsx +++ b/packages/react-google-maps-api/src/components/places/Autocomplete.tsx @@ -1,10 +1,12 @@ import * as React from 'react' - -import { unregisterEvents, applyUpdatersToPropsAndRegisterEvents } from '../../utils/helper' +import invariant from 'invariant' import MapContext from '../../map-context' - -import invariant from 'invariant' +import { + unregisterEvents, + applyUpdatersToPropsAndRegisterEvents, +} from '../../utils/helper' +import { usePrevious } from '../../utils/use-previous' const eventMap = { onPlaceChanged: 'place_changed', @@ -37,10 +39,6 @@ const updaterMap = { }, } -interface AutocompleteState { - autocomplete: google.maps.places.Autocomplete | null -} - export interface AutocompleteProps { // required children: React.ReactChild @@ -61,74 +59,73 @@ export interface AutocompleteProps { onUnmount?: (autocomplete: google.maps.places.Autocomplete) => void } -export class Autocomplete extends React.PureComponent { - static contextType = MapContext - - registeredEvents: google.maps.MapsEventListener[] = [] - containerElement: React.RefObject = React.createRef() - - state: AutocompleteState = { - autocomplete: null, - } - - setAutocompleteCallback = (): void => { - if (this.state.autocomplete !== null && this.props.onLoad) { - this.props.onLoad(this.state.autocomplete) - } - } - - componentDidMount(): void { - invariant( - !!google.maps.places, - 'You need to provide libraries={["places"]} prop to component %s', - google.maps.places - ) - - // TODO: why current could be equal null? - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore - // @ts-ignore - const input = this.containerElement.current.querySelector('input') - - if (input) { - const autocomplete = new google.maps.places.Autocomplete(input, this.props.options) - - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps: {}, - nextProps: this.props, - instance: autocomplete, - }) - - this.setState(function setAutocomplete() { - return { - autocomplete, +function Autocomplete(props: AutocompleteProps): JSX.Element { + const { children, options, onLoad, onUnmount } = props + const map = React.useContext(MapContext) + const prevProps: AutocompleteProps = usePrevious(props) + const containerElementRef = React.useRef(null) + + const [ + instance, + setInstance, + ] = React.useState(null) + + React.useEffect( + function effect() { + invariant( + !!google.maps.places, + 'You need to provide libraries={["places"]} prop to component %s', + google.maps.places + ) + + if (containerElementRef.current !== null) { + const input = containerElementRef.current.querySelector('input') + + if (input) { + const autocomplete = new google.maps.places.Autocomplete( + input, + options + ) + + setInstance(autocomplete) + + if (onLoad) { + onLoad(autocomplete) + } } - }, this.setAutocompleteCallback) - } - } - - componentDidUpdate(prevProps: AutocompleteProps): void { - unregisterEvents(this.registeredEvents) - - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps, - nextProps: this.props, - instance: this.state.autocomplete, - }) - } - - componentWillUnmount(): void { - if (this.state.autocomplete !== null) { - unregisterEvents(this.registeredEvents) - } - } - - render(): React.ReactNode { - return
{React.Children.only(this.props.children)}
- } + } + + return function cleanup() { + if (instance !== null) { + if (onUnmount) { + onUnmount(instance) + } + } + } + }, + [instance, map, options, onLoad, onUnmount] + ) + + React.useEffect( + function effect(): () => void { + const registeredEvents: google.maps.MapsEventListener[] = applyUpdatersToPropsAndRegisterEvents( + { + updaterMap, + eventMap, + prevProps, + nextProps: props, + instance, + } + ) + + return function cleanup(): void { + unregisterEvents(registeredEvents) + } + }, + [props, instance, prevProps] + ) + + return
{React.Children.only(children)}
} -export default Autocomplete +export default React.memo(Autocomplete) diff --git a/packages/react-google-maps-api/src/components/places/StandaloneSearchBox.tsx b/packages/react-google-maps-api/src/components/places/StandaloneSearchBox.tsx index ea5dc33ba..6d2199c7d 100644 --- a/packages/react-google-maps-api/src/components/places/StandaloneSearchBox.tsx +++ b/packages/react-google-maps-api/src/components/places/StandaloneSearchBox.tsx @@ -1,10 +1,12 @@ import * as React from 'react' - import invariant from 'invariant' -import { unregisterEvents, applyUpdatersToPropsAndRegisterEvents } from '../../utils/helper' - import MapContext from '../../map-context' +import { + unregisterEvents, + applyUpdatersToPropsAndRegisterEvents, +} from '../../utils/helper' +import { usePrevious } from '../../utils/use-previous' const eventMap = { onPlacesChanged: 'places_changed', @@ -19,11 +21,8 @@ const updaterMap = { }, } -interface StandaloneSearchBoxState { - searchBox: google.maps.places.SearchBox | null -} - export interface StandaloneSearchBoxProps { + children: React.ReactNode /** The area towards which to bias query predictions. Predictions are biased towards, but not restricted to, queries targeting these bounds. */ bounds?: google.maps.LatLngBounds | google.maps.LatLngBoundsLiteral options?: google.maps.places.SearchBoxOptions @@ -35,83 +34,74 @@ export interface StandaloneSearchBoxProps { onUnmount?: (searchBox: google.maps.places.SearchBox) => void } -class StandaloneSearchBox extends React.PureComponent< - StandaloneSearchBoxProps, - StandaloneSearchBoxState -> { - static contextType = MapContext - - registeredEvents: google.maps.MapsEventListener[] = [] - - containerElement: React.RefObject = React.createRef() - - state: StandaloneSearchBoxState = { - searchBox: null, - } - - setSearchBoxCallback = (): void => { - if (this.state.searchBox !== null && this.props.onLoad) { - this.props.onLoad(this.state.searchBox) - } - } - - componentDidMount(): void { - invariant( - !!google.maps.places, - 'You need to provide libraries={["places"]} prop to component %s', - google.maps.places - ) - - if (this.containerElement !== null && this.containerElement.current !== null) { - const input = this.containerElement.current.querySelector('input') - - if (input !== null) { - const searchBox = new google.maps.places.SearchBox(input, this.props.options) +function StandaloneSearchBox(props: StandaloneSearchBoxProps): JSX.Element { + const { children, options, onLoad, onUnmount } = props + const map = React.useContext(MapContext) + const prevProps: StandaloneSearchBoxProps = usePrevious< + StandaloneSearchBoxProps + >(props) + const containerElementRef = React.useRef(null) + + const [ + instance, + setInstance, + ] = React.useState(null) + + React.useEffect( + function effect() { + invariant( + !!google.maps.places, + 'You need to provide libraries={["places"]} prop to component %s', + google.maps.places + ) + + if (map !== null) { + if (containerElementRef.current !== null) { + const input = containerElementRef.current.querySelector('input') + + if (input !== null) { + const searchBox = new google.maps.places.SearchBox(input, options) + + setInstance(searchBox) + + if (searchBox !== null && onLoad) { + onLoad(searchBox) + } + } + } + } - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps: {}, - nextProps: this.props, - instance: searchBox, - }) - - this.setState(function setSearchBox() { - return { - searchBox, + return function cleanup() { + if (instance !== null) { + if (onUnmount) { + onUnmount(instance) } - }, this.setSearchBoxCallback) + } } - } - } - - componentDidUpdate(prevProps: StandaloneSearchBoxProps): void { - if (this.state.searchBox !== null) { - unregisterEvents(this.registeredEvents) - - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps, - nextProps: this.props, - instance: this.state.searchBox, - }) - } - } - - componentWillUnmount(): void { - if (this.state.searchBox !== null) { - if (this.props.onUnmount) { - this.props.onUnmount(this.state.searchBox) + }, + [instance, map, options, onLoad, onUnmount] + ) + + React.useEffect( + function effect(): () => void { + const registeredEvents: google.maps.MapsEventListener[] = applyUpdatersToPropsAndRegisterEvents( + { + updaterMap, + eventMap, + prevProps, + nextProps: props, + instance, + } + ) + + return function cleanup(): void { + unregisterEvents(registeredEvents) } + }, + [props, instance, prevProps] + ) - unregisterEvents(this.registeredEvents) - } - } - - render(): React.ReactNode { - return
{React.Children.only(this.props.children)}
- } + return
{React.Children.only(children)}
} -export default StandaloneSearchBox +export default React.memo(StandaloneSearchBox) diff --git a/packages/react-google-maps-api/src/components/streetview/StreetViewPanorama.tsx b/packages/react-google-maps-api/src/components/streetview/StreetViewPanorama.tsx index c089ef76b..ea685f070 100644 --- a/packages/react-google-maps-api/src/components/streetview/StreetViewPanorama.tsx +++ b/packages/react-google-maps-api/src/components/streetview/StreetViewPanorama.tsx @@ -1,8 +1,11 @@ import * as React from 'react' -import { unregisterEvents, applyUpdatersToPropsAndRegisterEvents } from '../../utils/helper' - import MapContext from '../../map-context' +import { + unregisterEvents, + applyUpdatersToPropsAndRegisterEvents, +} from '../../utils/helper' +import { usePrevious } from '../../utils/use-previous' const eventMap = { onCloseClick: 'closeclick', @@ -23,10 +26,16 @@ const updaterMap = { ): void { instance.registerPanoProvider(provider, options) }, - links(instance: google.maps.StreetViewPanorama, links: google.maps.StreetViewLink[]): void { + links( + instance: google.maps.StreetViewPanorama, + links: google.maps.StreetViewLink[] + ): void { instance.setLinks(links) }, - motionTracking(instance: google.maps.StreetViewPanorama, motionTracking: boolean): void { + motionTracking( + instance: google.maps.StreetViewPanorama, + motionTracking: boolean + ): void { instance.setMotionTracking(motionTracking) }, options( @@ -44,7 +53,10 @@ const updaterMap = { ): void { instance.setPosition(position) }, - pov(instance: google.maps.StreetViewPanorama, pov: google.maps.StreetViewPov): void { + pov( + instance: google.maps.StreetViewPanorama, + pov: google.maps.StreetViewPov + ): void { instance.setPov(pov) }, visible(instance: google.maps.StreetViewPanorama, visible: boolean): void { @@ -55,10 +67,6 @@ const updaterMap = { }, } -interface StreetViewPanoramaState { - streetViewPanorama: google.maps.StreetViewPanorama | null -} - export interface StreetViewPanoramaProps { options?: google.maps.StreetViewPanoramaOptions /** This event is fired when the close button is clicked. */ @@ -83,71 +91,65 @@ export interface StreetViewPanoramaProps { onUnmount?: (streetViewPanorama: google.maps.StreetViewPanorama) => void } -export class StreetViewPanorama extends React.PureComponent< - StreetViewPanoramaProps, - StreetViewPanoramaState -> { - static contextType = MapContext - - registeredEvents: google.maps.MapsEventListener[] = [] - - state: StreetViewPanoramaState = { - streetViewPanorama: null, - } - - setStreetViewPanoramaCallback = (): void => { - if (this.state.streetViewPanorama !== null && this.props.onLoad) { - this.props.onLoad(this.state.streetViewPanorama) - } - } - - componentDidMount(): void { - const streetViewPanorama = this.context.getStreetView() - - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps: {}, - nextProps: this.props, - instance: streetViewPanorama, - }) - - this.setState(function setStreetViewPanorama() { - return { - streetViewPanorama, +function StreetViewPanorama(props: StreetViewPanoramaProps): JSX.Element { + const { options, onLoad, onUnmount } = props + const map = React.useContext(MapContext) + const prevProps: StreetViewPanoramaProps = usePrevious< + StreetViewPanoramaProps + >(props) + + const [ + instance, + setInstance, + ] = React.useState(null) + + React.useEffect( + function effect() { + if (map !== null) { + if (instance === null) { + setInstance(map.getStreetView()) + } + + if (instance !== null) { + if (onLoad) { + onLoad(instance) + } + } } - }, this.setStreetViewPanoramaCallback) - } - componentDidUpdate(prevProps: StreetViewPanoramaProps): void { - if (this.state.streetViewPanorama !== null) { - unregisterEvents(this.registeredEvents) + return function cleanup() { + if (instance !== null) { + if (onUnmount) { + onUnmount(instance) + } - this.registeredEvents = applyUpdatersToPropsAndRegisterEvents({ - updaterMap, - eventMap, - prevProps, - nextProps: this.props, - instance: this.state.streetViewPanorama, - }) - } - } - - componentWillUnmount(): void { - if (this.state.streetViewPanorama !== null) { - if (this.props.onUnmount) { - this.props.onUnmount(this.state.streetViewPanorama) + instance.setVisible(false) + } } + }, + [instance, map, options, onLoad, onUnmount] + ) + + React.useEffect( + function effect(): () => void { + const registeredEvents: google.maps.MapsEventListener[] = applyUpdatersToPropsAndRegisterEvents( + { + updaterMap, + eventMap, + prevProps, + nextProps: props, + instance, + } + ) + + return function cleanup(): void { + unregisterEvents(registeredEvents) + } + }, + [props, instance, prevProps] + ) - unregisterEvents(this.registeredEvents) - - this.state.streetViewPanorama.setVisible(false) - } - } - - render(): React.ReactNode { - return null - } + return <> } export default StreetViewPanorama diff --git a/packages/react-google-maps-api/src/components/streetview/StreetViewService.tsx b/packages/react-google-maps-api/src/components/streetview/StreetViewService.tsx index b4b768adc..9dece1c2c 100644 --- a/packages/react-google-maps-api/src/components/streetview/StreetViewService.tsx +++ b/packages/react-google-maps-api/src/components/streetview/StreetViewService.tsx @@ -1,7 +1,5 @@ import * as React from 'react' -import MapContext from '../../map-context' - export interface StreetViewServiceProps { /** This callback is called when the streetViewService instance has loaded. It is called with the streetViewService instance. */ onLoad?: (streetViewService: google.maps.StreetViewService | null) => void @@ -9,47 +7,36 @@ export interface StreetViewServiceProps { onUnmount?: (streetViewService: google.maps.StreetViewService | null) => void } -interface StreetViewServiceState { - streetViewService: google.maps.StreetViewService | null -} - -export class StreetViewService extends React.PureComponent< - StreetViewServiceProps, - StreetViewServiceState -> { - static contextType = MapContext +function StreetViewService(props: StreetViewServiceProps): JSX.Element { + const { onLoad, onUnmount } = props - state = { - streetViewService: null, - } + const [ + instance, + setInstance, + ] = React.useState(null) - setStreetViewServiceCallback = (): void => { - if (this.state.streetViewService !== null && this.props.onLoad) { - this.props.onLoad(this.state.streetViewService) - } - } + React.useEffect( + function effect(): () => void { + const streetViewService = new google.maps.StreetViewService() - componentDidMount(): void { - const streetViewService = new google.maps.StreetViewService() + setInstance(streetViewService) - this.setState(function setStreetViewService() { - return { - streetViewService, + if (instance !== null && onLoad) { + onLoad(instance) } - }, this.setStreetViewServiceCallback) - } - componentWillUnmount(): void { - if (this.state.streetViewService !== null) { - if (this.props.onUnmount) { - this.props.onUnmount(this.state.streetViewService) + return function callback(): void { + if (instance !== null) { + if (onUnmount) { + onUnmount(instance) + } + } } - } - } + }, + [instance, onLoad, onUnmount] + ) - render(): React.ReactNode { - return null - } + return <> } -export default StreetViewService +export default React.memo(StreetViewService) diff --git a/packages/react-google-maps-api/src/docs/DocsApiKeyInput.tsx b/packages/react-google-maps-api/src/docs/DocsApiKeyInput.tsx index 45e8e7173..3dc04c63e 100644 --- a/packages/react-google-maps-api/src/docs/DocsApiKeyInput.tsx +++ b/packages/react-google-maps-api/src/docs/DocsApiKeyInput.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { setKey, getKey } from './docs-api-key' +import * as storage from './docs-api-key' import LoadScript from '../LoadScript' @@ -18,73 +18,80 @@ const buttonStyle = { const loadingElement: JSX.Element =
Loading...
-interface DocsApiKeyInputState { - key: string - loadScript: boolean +interface DocsApiKeyInputProps { + children: React.ReactChild } -class DocsApiKeyInput extends React.Component<{}, DocsApiKeyInputState> { - constructor(props: {}) { - super(props) +function DocsApiKeyInput({ children }: DocsApiKeyInputProps): JSX.Element { + const [key, setKey] = React.useState(null) + const [inputKey, setInputKey] = React.useState('') - const key = getKey() + React.useEffect( + function effect() { + const k = key === null ? storage.getKey() : inputKey - this.state = key ? { key, loadScript: true } : { key: '', loadScript: false } - } - - onInputChange = ({ target: { value } }: React.ChangeEvent): void => { - this.setState(function setKey() { - return { - key: value, + if (k !== null) { + storage.setKey(k) } - }) - } - - onFormSubmit = (event: React.FormEvent): void => { - event.preventDefault() - - setKey(this.state.key) - - this.setState(function setLoadScript() { - return { - loadScript: true, + }, + [key, inputKey] + ) + + const onInputChange = React.useCallback(function callback({ + target: { value }, + }: React.ChangeEvent): void { + setInputKey(value) + }, + []) + + const onFormSubmit = React.useCallback( + function callback(event: React.FormEvent): void { + event.preventDefault() + + if (inputKey === '') { + setKey(null) + storage.removeKey() } - }) - } - - render(): React.ReactNode { - return ( - <> -
- - - -
- - {this.state.loadScript ? ( - - ) : ( - <> - )} - - ) - } + + setKey(inputKey) + storage.setKey(inputKey) + }, + [inputKey] + ) + + return ( + <> +
+ + + +
+ + {key !== null ? ( + + {children} + + ) : ( + <> + )} + + ) } -export default DocsApiKeyInput +export default React.memo(DocsApiKeyInput) diff --git a/packages/react-google-maps-api/src/docs/ScriptLoaded.tsx b/packages/react-google-maps-api/src/docs/ScriptLoaded.tsx index 2ecaf8b3a..ad7aa719b 100644 --- a/packages/react-google-maps-api/src/docs/ScriptLoaded.tsx +++ b/packages/react-google-maps-api/src/docs/ScriptLoaded.tsx @@ -1,10 +1,7 @@ import * as React from 'react' -interface ScriptLoadedState { - scriptLoaded: boolean -} - interface ScriptLoadedProps { + // eslint-disable-next-line @typescript-eslint/ban-types children: React.ReactChild | React.ReactChildren | Function } @@ -16,46 +13,36 @@ function SpanIntro(): JSX.Element { ) } -class ScriptLoaded extends React.Component { - interval: number | undefined - - constructor(props: ScriptLoadedProps) { - super(props) - - this.state = { - scriptLoaded: !!window.google, - } - - this.interval = window.setInterval(this.checkIfScriptLoaded, 200) - } +const SpanIntroMemo = React.memo(SpanIntro) - setScriptLoadedCallback = (): void => { - if (this.state.scriptLoaded) { - window.clearInterval(this.interval) - } - } +function ScriptLoaded(props: ScriptLoadedProps): JSX.Element { + const { children } = props + const [scriptLoaded, setScriptLoaded] = React.useState(!!window.google) + const [intervalState, setIntervalState] = React.useState(0) - checkIfScriptLoaded = (): void => { + const checkIfScriptLoaded = React.useCallback(function callback(): void { if (window.google) { - this.setState(function serScriptLoaded() { - return { - scriptLoaded: true, - } - }, this.setScriptLoadedCallback) + setScriptLoaded(true) + window.clearInterval(intervalState) } - } + }, []) - componentWillUnmount(): void { - window.clearInterval(this.interval) - } + React.useEffect( + function effect() { + setIntervalState(window.setInterval(checkIfScriptLoaded, 200)) - render(): JSX.Element { - if (!this.state.scriptLoaded) { - return - } + return function callback() { + window.clearInterval(intervalState) + } + }, + [checkIfScriptLoaded, intervalState] + ) - return this.props.children instanceof Function ? this.props.children() : this.props.children + if (!scriptLoaded) { + return } + + return children instanceof Function ? children() : children } -export default ScriptLoaded +export default React.memo(ScriptLoaded) diff --git a/packages/react-google-maps-api/src/docs/docs-api-key.ts b/packages/react-google-maps-api/src/docs/docs-api-key.ts index d667a81f1..134aadff1 100644 --- a/packages/react-google-maps-api/src/docs/docs-api-key.ts +++ b/packages/react-google-maps-api/src/docs/docs-api-key.ts @@ -8,3 +8,7 @@ export function setKey(key: string): void { export function getKey(): string | null { return localDevKey || window.sessionStorage.getItem(KEY_NAME) } + +export function removeKey(): void { + window.sessionStorage.removeItem(KEY_NAME) +} diff --git a/packages/react-google-maps-api/src/index.ts b/packages/react-google-maps-api/src/index.ts index fd0475183..8a65d806c 100644 --- a/packages/react-google-maps-api/src/index.ts +++ b/packages/react-google-maps-api/src/index.ts @@ -2,20 +2,40 @@ export { default as GoogleMap, GoogleMapProps } from './GoogleMap' export { default as LoadScript, LoadScriptProps } from './LoadScript' -export { default as LoadScriptNext, LoadScriptNextProps } from './LoadScriptNext' +export { + default as LoadScriptNext, + LoadScriptNextProps, +} from './LoadScriptNext' export { useLoadScript } from './useLoadScript' -export { default as TrafficLayer, TrafficLayerProps } from './components/maps/TrafficLayer' +export { + default as TrafficLayer, + TrafficLayerProps, +} from './components/maps/TrafficLayer' -export { default as BicyclingLayer, BicyclingLayerProps } from './components/maps/BicyclingLayer' +export { + default as BicyclingLayer, + BicyclingLayerProps, +} from './components/maps/BicyclingLayer' -export { default as TransitLayer, TransitLayerProps } from './components/maps/TransitLayer' +export { + default as TransitLayer, + TransitLayerProps, +} from './components/maps/TransitLayer' -export { default as DrawingManager, DrawingManagerProps } from './components/drawing/DrawingManager' +export { + default as DrawingManager, + DrawingManagerProps, +} from './components/drawing/DrawingManager' export { default as Marker, MarkerProps } from './components/drawing/Marker' +export { + default as MarkerWithLabel, + MarkerWithLabelProps +} from './components/drawing/MarkerWithLabel' + export { default as MarkerClusterer, ClustererProps as MarkerClustererProps, @@ -23,13 +43,22 @@ export { export { default as InfoBox, InfoBoxProps } from './components/addons/InfoBox' -export { default as InfoWindow, InfoWindowProps } from './components/drawing/InfoWindow' +export { + default as InfoWindow, + InfoWindowProps, +} from './components/drawing/InfoWindow' -export { default as Polyline, PolylineProps } from './components/drawing/Polyline' +export { + default as Polyline, + PolylineProps, +} from './components/drawing/Polyline' export { default as Polygon, PolygonProps } from './components/drawing/Polygon' -export { default as Rectangle, RectangleProps } from './components/drawing/Rectangle' +export { + default as Rectangle, + RectangleProps, +} from './components/drawing/Rectangle' export { default as Circle, CircleProps } from './components/drawing/Circle' @@ -37,11 +66,20 @@ export { default as Data, DataProps } from './components/drawing/Data' export { default as KmlLayer, KmlLayerProps } from './components/kml/KmlLayer' -export { default as OverlayView, OverlayViewProps } from './components/dom/OverlayView' +export { + default as OverlayView, + OverlayViewProps, +} from './components/dom/OverlayView' -export { default as GroundOverlay, GroundOverlayProps } from './components/overlays/GroundOverlay' +export { + default as GroundOverlay, + GroundOverlayProps, +} from './components/overlays/GroundOverlay' -export { default as HeatmapLayer, HeatmapLayerProps } from './components/heatmap/HeatmapLayer' +export { + default as HeatmapLayer, + HeatmapLayerProps, +} from './components/heatmap/HeatmapLayer' export { default as StreetViewPanorama, @@ -73,6 +111,9 @@ export { StandaloneSearchBoxProps, } from './components/places/StandaloneSearchBox' -export { default as Autocomplete, AutocompleteProps } from './components/places/Autocomplete' +export { + default as Autocomplete, + AutocompleteProps, +} from './components/places/Autocomplete' export { default as MapContext, useGoogleMap } from './map-context' diff --git a/packages/react-google-maps-api/src/map-context.ts b/packages/react-google-maps-api/src/map-context.ts index f70f2a557..5a8e6cfea 100644 --- a/packages/react-google-maps-api/src/map-context.ts +++ b/packages/react-google-maps-api/src/map-context.ts @@ -4,7 +4,10 @@ import invariant from 'invariant' const MapContext = createContext(null) export function useGoogleMap(): google.maps.Map | null { - invariant(!!useContext, 'useGoogleMap is React hook and requires React version 16.8+') + invariant( + !!useContext, + 'useGoogleMap is React hook and requires React version 16.8+' + ) const map = useContext(MapContext) diff --git a/packages/react-google-maps-api/src/setup-tests.js b/packages/react-google-maps-api/src/setup-tests.js index b8e8d58ea..7e0bee4bc 100644 --- a/packages/react-google-maps-api/src/setup-tests.js +++ b/packages/react-google-maps-api/src/setup-tests.js @@ -43,15 +43,15 @@ const createGoogleMapsMock = (libraries = []) => { Lo: 3, Go: 4, }, - BicyclingLayer: jest.fn().mockImplementation(function() { + BicyclingLayer: jest.fn().mockImplementation(function BicyclingLayer() { createMVCObject(this) createMockFuncsFromArray(this, ['setMap']) }), - TransitLayer: jest.fn().mockImplementation(function() { + TransitLayer: jest.fn().mockImplementation(function TransitLayer() { createMVCObject(this) createMockFuncsFromArray(this, ['setMap']) }), - Circle: jest.fn().mockImplementation(function(opts) { + Circle: jest.fn().mockImplementation(function Circle(opts) { this.opts = opts createMVCObject(this) createMockFuncsFromArray(this, [ @@ -82,7 +82,7 @@ const createGoogleMapsMock = (libraries = []) => { BOTTOM_RIGHT: 12, CENTER: 13, }, - Data: jest.fn().mockImplementation(function(options) { + Data: jest.fn().mockImplementation(function Data(options) { this.options = options createMVCObject(this) createMockFuncsFromArray(this, [ @@ -93,18 +93,22 @@ const createGoogleMapsMock = (libraries = []) => { 'setStyle', ]) }), - DirectionsRenderer: jest.fn().mockImplementation(function(opts) { - this.opts = opts - createMVCObject(this) - createMockFuncsFromArray(this, [ - 'setDirections', - 'setMap', - 'setOptions', - 'setPanel', - 'setRouteIndex', - ]) - }), - DirectionsService: function() {}, + DirectionsRenderer: jest + .fn() + .mockImplementation(function DirectionsRenderer(opts) { + this.opts = opts + createMVCObject(this) + createMockFuncsFromArray(this, [ + 'setDirections', + 'setMap', + 'setOptions', + 'setPanel', + 'setRouteIndex', + ]) + }), + DirectionsService: function DirectionsService() { + return + }, DirectionsStatus: { INVALID_REQUEST: 'INVALID_REQUEST', MAX_WAYPOINTS_EXCEEDED: 'MAX_WAYPOINTS_EXCEEDED', @@ -130,7 +134,9 @@ const createGoogleMapsMock = (libraries = []) => { OK: 'OK', ZERO_RESULTS: 'ZERO_RESULTS', }, - DistanceMatrixService: function() {}, + DistanceMatrixService: function DistanceMatrixService() { + return + }, DistanceMatrixStatus: { INVALID_REQUEST: 'INVALID_REQUEST', MAX_DIMENSIONS_EXCEEDED: 'MAX_DIMENSIONS_EXCEEDED', @@ -140,7 +146,9 @@ const createGoogleMapsMock = (libraries = []) => { REQUEST_DENIED: 'REQUEST_DENIED', UNKNOWN_ERROR: 'UNKNOWN_ERROR', }, - ElevationService: function() {}, + ElevationService: function ElevationService() { + return + }, ElevationStatus: { Co: 'DATA_NOT_AVAILABLE', INVALID_REQUEST: 'INVALID_REQUEST', @@ -149,12 +157,16 @@ const createGoogleMapsMock = (libraries = []) => { REQUEST_DENIED: 'REQUEST_DENIED', UNKNOWN_ERROR: 'UNKNOWN_ERROR', }, - FusionTablesLayer: jest.fn().mockImplementation(function(options) { - this.options = options - createMVCObject(this) - createMockFuncsFromArray(this, ['setMap', 'setOptions']) - }), - Geocoder: function() {}, + FusionTablesLayer: jest + .fn() + .mockImplementation(function FusionTablesLayer(options) { + this.options = options + createMVCObject(this) + createMockFuncsFromArray(this, ['setMap', 'setOptions']) + }), + Geocoder: function Geocoder() { + return + }, GeocoderLocationType: { APPROXIMATE: 'APPROXIMATE', GEOMETRIC_CENTER: 'GEOMETRIC_CENTER', @@ -170,10 +182,18 @@ const createGoogleMapsMock = (libraries = []) => { UNKNOWN_ERROR: 'UNKNOWN_ERROR', ZERO_RESULTS: 'ZERO_RESULTS', }, - GroundOverlay: function() {}, - ImageMapType: function() {}, - InfoWindow: function() {}, - KmlLayer: function() {}, + GroundOverlay: function GroundOverlay() { + return + }, + ImageMapType: function ImageMapType() { + return + }, + InfoWindow: function InfoWindow() { + return + }, + KmlLayer: function KmlLayer() { + return + }, KmlLayerStatus: { DOCUMENT_NOT_FOUND: 'DOCUMENT_NOT_FOUND', DOCUMENT_TOO_LARGE: 'DOCUMENT_TOO_LARGE', @@ -185,13 +205,19 @@ const createGoogleMapsMock = (libraries = []) => { TIMED_OUT: 'TIMED_OUT', UNKNOWN: 'UNKNOWN', }, - LatLng: function() {}, - LatLngBounds: function() {}, - MVCArray: function() {}, - MVCObject: jest.fn().mockImplementation(function() { + LatLng: function LatLng() { + return + }, + LatLngBounds: function LatLngBounds() { + return + }, + MVCArray: function MVCArray() { + return + }, + MVCObject: jest.fn().mockImplementation(function MVCObject() { createMVCObject(this) }), - Map: jest.fn().mockImplementation(function(mapDiv, opts) { + Map: jest.fn().mockImplementation(function Map(mapDiv, opts) { this.mapDiv = mapDiv this.opts = opts createMVCObject(this) @@ -222,8 +248,10 @@ const createGoogleMapsMock = (libraries = []) => { SATELLITE: 'satellite', TERRAIN: 'terrain', }, - MapTypeRegistry: function() {}, - Marker: jest.fn().mockImplementation(function(opts) { + MapTypeRegistry: function MapTypeRegistry() { + return + }, + Marker: jest.fn().mockImplementation(function Marker(opts) { this.opts = opts createMVCObject(this) createMockFuncsFromArray(this, [ @@ -237,10 +265,14 @@ const createGoogleMapsMock = (libraries = []) => { 'setZIndex', ]) }), - MarkerImage: function() {}, - MaxZoomService: function() { + MarkerImage: function MarkerImage() { + return + }, + MaxZoomService: function MaxZoomService() { return { - getMaxZoomAtLatLng: function() {}, + getMaxZoomAtLatLng: function getMaxZoomAtLatLng() { + return + }, } }, MaxZoomStatus: { @@ -255,23 +287,43 @@ const createGoogleMapsMock = (libraries = []) => { ZOOM_PAN: 3, ik: 5, }, - OverlayView: function() {}, - Point: function() {}, - Polygon: function() {}, - Polyline: function() {}, - Rectangle: function() {}, - SaveWidget: function() {}, + OverlayView: function OverlayView() { + return + }, + Point: function Point() { + return + }, + Polygon: function Polygon() { + return + }, + Polyline: function Polyline() { + return + }, + Rectangle: function Rectangle() { + return + }, + SaveWidget: function SaveWidget() { + return + }, ScaleControlStyle: { DEFAULT: 0, }, - Size: function() {}, - StreetViewCoverageLayer: function() {}, - StreetViewPanorama: function() {}, + Size: function Size() { + return + }, + StreetViewCoverageLayer: function StreetViewCoverageLayer() { + return + }, + StreetViewPanorama: function StreetViewPanorama() { + return + }, StreetViewPreference: { BEST: 'best', NEAREST: 'nearest', }, - StreetViewService: function() {}, + StreetViewService: function StreetViewService() { + return + }, StreetViewSource: { DEFAULT: 'default', OUTDOOR: 'outdoor', @@ -286,7 +338,9 @@ const createGoogleMapsMock = (libraries = []) => { INSIDE: 1, OUTSIDE: 2, }, - StyledMapType: function() {}, + StyledMapType: function StyledMapType() { + return + }, SymbolPath: { BACKWARD_CLOSED_ARROW: 3, BACKWARD_OPEN_ARROW: 4, @@ -294,7 +348,7 @@ const createGoogleMapsMock = (libraries = []) => { FORWARD_CLOSED_ARROW: 1, FORWARD_OPEN_ARROW: 2, }, - TrafficLayer: jest.fn().mockImplementation(function(opts) { + TrafficLayer: jest.fn().mockImplementation(function TrafficLayer(opts) { this.opts = opts createMVCObject(this) createMockFuncsFromArray(this, ['setMap', 'setOptions']) @@ -331,7 +385,9 @@ const createGoogleMapsMock = (libraries = []) => { SMALL: 1, ik: 3, }, - __gjsload__: function() {}, + __gjsload__: function __gjsload__() { + return + }, event: { clearInstanceListeners: jest.fn().mockName('clearInstanceListeners'), }, diff --git a/packages/react-google-maps-api/src/useLoadScript.tsx b/packages/react-google-maps-api/src/useLoadScript.tsx index 514e8332c..eb58c4418 100644 --- a/packages/react-google-maps-api/src/useLoadScript.tsx +++ b/packages/react-google-maps-api/src/useLoadScript.tsx @@ -1,11 +1,13 @@ -/* eslint-disable filenames/match-regex */ import * as React from 'react' import invariant from 'invariant' import { isBrowser } from './utils/isbrowser' import { injectScript } from './utils/injectscript' import { preventGoogleFonts } from './utils/prevent-google-fonts' -import { makeLoadScriptUrl, LoadScriptUrlOptions } from './utils/make-load-script-url' +import { + makeLoadScriptUrl, + LoadScriptUrlOptions, +} from './utils/make-load-script-url' import { defaultLoadScriptProps } from './LoadScript' @@ -105,7 +107,7 @@ export function useLoadScript({ console.error(err) }) }, - [id, url] + [id, url, googleMapsApiKey, googleMapsClientId] ) const prevLibraries = React.useRef() diff --git a/packages/react-google-maps-api/src/utils/foreach.ts b/packages/react-google-maps-api/src/utils/foreach.ts index 38ef41333..e0ebea3fb 100644 --- a/packages/react-google-maps-api/src/utils/foreach.ts +++ b/packages/react-google-maps-api/src/utils/foreach.ts @@ -1,6 +1,6 @@ -// eslint-disable-next-line @typescript-eslint/no-explicit-any +// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any export function forEach(obj: any, fn: any): any { - Object.keys(obj).forEach(function iterator(key) { + Object.keys(obj).forEach(function callbackfn(key) { return fn(obj[key], key) }) } diff --git a/packages/react-google-maps-api/src/utils/helper.ts b/packages/react-google-maps-api/src/utils/helper.ts index 7cb617ff5..ce5ee8adf 100644 --- a/packages/react-google-maps-api/src/utils/helper.ts +++ b/packages/react-google-maps-api/src/utils/helper.ts @@ -1,24 +1,16 @@ /* global google */ -/* eslint-disable filenames/match-regex */ import { reduce } from './reduce' import { forEach } from './foreach' -export const applyUpdaterToNextProps = ( - // eslint-disable-next-line @typescript-eslint/no-explicit-any +export function applyUpdaterToNextProps( updaterMap: any, - // eslint-disable-next-line @typescript-eslint/no-explicit-any prevProps: any, - // eslint-disable-next-line @typescript-eslint/no-explicit-any nextProps: any, - // eslint-disable-next-line @typescript-eslint/no-explicit-any instance: any - // eslint-disable-next-line @typescript-eslint/no-explicit-any -): any => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any +): any { const map: any = {} - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const iter = (fn: any, key: string): void => { + function iter(fn: any, key: string): void { const nextValue = nextProps[key] if (nextValue !== prevProps[key]) { @@ -33,9 +25,8 @@ export const applyUpdaterToNextProps = ( } export function registerEvents( - // eslint-disable-next-line @typescript-eslint/no-explicit-any props: any, - // eslint-disable-next-line @typescript-eslint/no-explicit-any + instance: any, eventMap: Record ): google.maps.MapsEventListener[] { @@ -44,11 +35,17 @@ export function registerEvents( function reducer( acc: google.maps.MapsEventListener[], googleEventName: string, - // eslint-disable-next-line @typescript-eslint/no-explicit-any + onEventName: any ): google.maps.MapsEventListener[] { if (typeof props[onEventName] === 'function') { - acc.push(google.maps.event.addListener(instance, googleEventName, props[onEventName])) + acc.push( + google.maps.event.addListener( + instance, + googleEventName, + props[onEventName] + ) + ) } return acc @@ -62,7 +59,9 @@ function unregisterEvent(registered: google.maps.MapsEventListener): void { google.maps.event.removeListener(registered) } -export function unregisterEvents(events: google.maps.MapsEventListener[] = []): void { +export function unregisterEvents( + events: google.maps.MapsEventListener[] = [] +): void { events.forEach(unregisterEvent) } @@ -73,14 +72,10 @@ export function applyUpdatersToPropsAndRegisterEvents({ nextProps, instance, }: { - // eslint-disable-next-line @typescript-eslint/no-explicit-any updaterMap: any eventMap: Record - // eslint-disable-next-line @typescript-eslint/no-explicit-any prevProps: any - // eslint-disable-next-line @typescript-eslint/no-explicit-any nextProps: any - // eslint-disable-next-line @typescript-eslint/no-explicit-any instance: any }): google.maps.MapsEventListener[] { const registeredEvents = registerEvents(nextProps, instance, eventMap) diff --git a/packages/react-google-maps-api/src/utils/injectscript.ts b/packages/react-google-maps-api/src/utils/injectscript.ts index 2c5d79eba..1ecf3a1f8 100644 --- a/packages/react-google-maps-api/src/utils/injectscript.ts +++ b/packages/react-google-maps-api/src/utils/injectscript.ts @@ -9,17 +9,24 @@ interface InjectScriptArg { id: string } -export const injectScript = ({ url, id }: InjectScriptArg): Promise => { +export function injectScript({ url, id }: InjectScriptArg): Promise { if (!isBrowser) { return Promise.reject(new Error('document is undefined')) } - return new Promise(function injectScriptCallback(resolve, reject) { - const existingScript = document.getElementById(id) as HTMLScriptElement | undefined + return new Promise(function injectScriptCallback( + resolve: (value?: unknown) => void, + reject: (reason?: unknown) => void + ): void { + const existingScript = document.getElementById(id) as + | HTMLScriptElement + | undefined const windowWithGoogleMap: WindowWithGoogleMap = window + if (existingScript) { // Same script id/url: keep same script const dataStateAttribute = existingScript.getAttribute('data-state') + if (existingScript.src === url && dataStateAttribute !== 'error') { if (dataStateAttribute === 'ready') { return resolve(id) @@ -34,14 +41,12 @@ export const injectScript = ({ url, id }: InjectScriptArg): Promise => { resolve(id) } - existingScript.onerror = function(err): void { + existingScript.onerror = function onerror(err): void { if (originalErrorCallback) { originalErrorCallback(err) } reject(err) } - - return } } // Same script id, but either diff --git a/packages/react-google-maps-api/src/utils/noop.ts b/packages/react-google-maps-api/src/utils/noop.ts index 89966dd3d..5feb46280 100644 --- a/packages/react-google-maps-api/src/utils/noop.ts +++ b/packages/react-google-maps-api/src/utils/noop.ts @@ -1 +1,3 @@ -export function noop(): void {} +export function noop(): void { + return +} diff --git a/packages/react-google-maps-api/src/utils/prevent-google-fonts.ts b/packages/react-google-maps-api/src/utils/prevent-google-fonts.ts index 601191e9b..b72d76874 100644 --- a/packages/react-google-maps-api/src/utils/prevent-google-fonts.ts +++ b/packages/react-google-maps-api/src/utils/prevent-google-fonts.ts @@ -2,25 +2,26 @@ const isRobotoStyle = (element: HTMLElement): boolean => { // roboto font download if ( (element as HTMLLinkElement).href && - (element as HTMLLinkElement).href.indexOf('https://fonts.googleapis.com/css?family=Roboto') === - 0 + (element as HTMLLinkElement).href.indexOf( + 'https://fonts.googleapis.com/css?family=Roboto' + ) === 0 ) { return true } // roboto style elements if ( element.tagName.toLowerCase() === 'style' && - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore element.styleSheet && - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore element.styleSheet.cssText && - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore element.styleSheet.cssText.replace('\r\n', '').indexOf('.gm-style') === 0 ) { - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore element.styleSheet.cssText = '' return true @@ -37,7 +38,7 @@ const isRobotoStyle = (element: HTMLElement): boolean => { // when google tries to add empty style if ( element.tagName.toLowerCase() === 'style' && - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore !element.styleSheet && !element.innerHTML @@ -57,7 +58,7 @@ export const preventGoogleFonts = (): void => { const trueInsertBefore = head.insertBefore.bind(head) // TODO: adding return before reflect solves the TS issue - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore head.insertBefore = function insertBefore( newElement: HTMLElement, @@ -71,7 +72,7 @@ export const preventGoogleFonts = (): void => { const trueAppend = head.appendChild.bind(head) // TODO: adding return before reflect solves the TS issue - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore head.appendChild = function appendChild(textNode: HTMLElement): void { if (!isRobotoStyle(textNode)) { diff --git a/packages/react-google-maps-api/src/utils/reduce.ts b/packages/react-google-maps-api/src/utils/reduce.ts index 081c7c478..164efc7f1 100644 --- a/packages/react-google-maps-api/src/utils/reduce.ts +++ b/packages/react-google-maps-api/src/utils/reduce.ts @@ -1,4 +1,4 @@ -// eslint-disable-next-line @typescript-eslint/no-explicit-any +// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any export const reduce = (obj: any, fn: any, acc: any): any => { return Object.keys(obj).reduce(function reducer(newAcc, key) { return fn(newAcc, obj[key], key) diff --git a/packages/react-google-maps-api/src/utils/use-map-component.ts b/packages/react-google-maps-api/src/utils/use-map-component.ts deleted file mode 100644 index 73895eef1..000000000 --- a/packages/react-google-maps-api/src/utils/use-map-component.ts +++ /dev/null @@ -1,43 +0,0 @@ -// import { useState, useEffect, useContext } from "react" - -// import MapContext from "../map-context" - -// import { -// unregisterEvents, -// applyUpdatersToPropsAndRegisterEvents -// } from "./helper" - -// export default function useMapComponent(props) { -// const [instance, setInstance] = useState(null) -// const context = useContext(MapContext) - -// let tempInstance - -// console.log({ context }) - -// if (!instance) { -// console.log(props.className, new google.maps[props.className]()) - -// tempInstance = new google.maps[props.className]() - -// setInstance(tempInstance) - -// tempInstance.setMap(context) -// } - -// console.log({ tempInstance }) - -// useEffect(() => { -// console.log(props, tempInstance) -// const registeredEvents = applyUpdatersToPropsAndRegisterEvents({ -// ...props, -// instance: tempInstance -// }) - -// return () => { -// unregisterEvents(registeredEvents) -// } -// }) - -// return "was here" -// } diff --git a/packages/react-google-maps-api/src/utils/use-previous.tsx b/packages/react-google-maps-api/src/utils/use-previous.tsx new file mode 100644 index 000000000..a0d48a53c --- /dev/null +++ b/packages/react-google-maps-api/src/utils/use-previous.tsx @@ -0,0 +1,14 @@ +import * as React from 'react' + +export function usePrevious(props: T): T { + const ref = React.useRef(props) + + React.useEffect( + function effect(): void { + ref.current = props + }, + [props] + ) + + return ref.current +} diff --git a/packages/react-google-maps-api/tsconfig.json b/packages/react-google-maps-api/tsconfig.json index 2ea111ee3..7780425b7 100644 --- a/packages/react-google-maps-api/tsconfig.json +++ b/packages/react-google-maps-api/tsconfig.json @@ -1,12 +1,13 @@ { "include": ["src/**/*"], - "exclude": ["node_modules"], + "exclude": ["node_modules", "types"], "compilerOptions": { "module": "esnext", "moduleResolution": "node", "target": "es5", "jsx": "react", "lib": ["dom", "es2017"], + "typeRoots": ["node_modules/@types", "types"], "rootDir": "src", "strict": true, "allowJs": false, diff --git a/packages/react-google-maps-api/types/markerwithlabel/index.d.ts b/packages/react-google-maps-api/types/markerwithlabel/index.d.ts new file mode 100644 index 000000000..6983a330d --- /dev/null +++ b/packages/react-google-maps-api/types/markerwithlabel/index.d.ts @@ -0,0 +1,18 @@ +declare module 'markerwithlabel' { + import Point = google.maps.Point; + + interface MarkerWithLabelOptions extends google.maps.MarkerOptions { + labelAnchor?: Point + labelClass?: string + labelStyle?: React.CSSProperties + labelVisible?: boolean + } + + class MarkerWithLabel extends google.maps.Marker { + constructor(args: MarkerWithLabelOptions); + } + + function factory (maps: {}): typeof MarkerWithLabel + export = factory +} + diff --git a/packages/react-google-maps-api/yarn.lock b/packages/react-google-maps-api/yarn.lock index 54d662b21..bf1ab4f7f 100644 --- a/packages/react-google-maps-api/yarn.lock +++ b/packages/react-google-maps-api/yarn.lock @@ -1176,16 +1176,6 @@ "@types/istanbul-reports" "^1.1.1" "@types/yargs" "^13.0.0" -"@jest/types@^25.1.0": - version "25.1.0" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-25.1.0.tgz#b26831916f0d7c381e11dbb5e103a72aed1b4395" - integrity sha512-VpOtt7tCrgvamWZh1reVsGADujKigBUFTi19mlRjqEGsE8qH4r3s+skY33dNdXOwyZIvuftZ5tqdF1IgsMejMA== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^1.1.1" - "@types/yargs" "^15.0.0" - chalk "^3.0.0" - "@jest/types@^25.3.0": version "25.3.0" resolved "https://registry.yarnpkg.com/@jest/types/-/types-25.3.0.tgz#88f94b277a1d028fd7117bc1f74451e0fc2131e7" @@ -1229,15 +1219,15 @@ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b" integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw== -"@react-google-maps/infobox@1.9.3": - version "1.9.3" - resolved "https://registry.yarnpkg.com/@react-google-maps/infobox/-/infobox-1.9.3.tgz#90a32d57527f5f0476f2fcb41556016b650cc4a3" - integrity sha512-e2EoeS+VSBsU4Gol3m3eaj9n1UGmp4Sz1ORpYHq0TJI2zRNwS7C2rGLe4aT0tHMXcaPSfkPR811IKtmc54ItUQ== +"@react-google-maps/infobox@2.0.0-alpha": + version "2.0.0-alpha" + resolved "https://registry.yarnpkg.com/@react-google-maps/infobox/-/infobox-2.0.0-alpha.tgz#d9fb7b1f091466460e5cc7a3a2c9de4c4b831a3c" + integrity sha512-QOHyH1OfFvubpNB8/U4VSUcOVizIdo4R9jfQBN3klzV8T2h0JA3SQ9bi4isBHSINssvBc7rhAdz0PKe19fkc/w== -"@react-google-maps/marker-clusterer@1.9.3": - version "1.9.3" - resolved "https://registry.yarnpkg.com/@react-google-maps/marker-clusterer/-/marker-clusterer-1.9.3.tgz#6acb6a12cffeef04f11549aaf0a43e6135578116" - integrity sha512-fJoNmtHewep2wM4PnCtpPn3wImUPHBhCyz0YqOx1AxRg8zOwCOauPSMon3xKtGP7m5AmrAZpiYY51vBkubH/aA== +"@react-google-maps/marker-clusterer@2.0.0-alpha": + version "2.0.0-alpha" + resolved "https://registry.yarnpkg.com/@react-google-maps/marker-clusterer/-/marker-clusterer-2.0.0-alpha.tgz#4e55f1ab664a12a227104dc17b999c1cca5d99a3" + integrity sha512-SiDkSBQp5YPcbWGnLMNEzqJuhKP1u455o4h1MnqDLNsuEMjCT/Z8BdgpV+tuFFf4fDOpd5PeD3gEVwtPkcoH8A== "@rollup/plugin-commonjs@^11.0.0": version "11.0.1" @@ -1314,14 +1304,13 @@ dom-accessibility-api "^0.4.4" pretty-format "^25.5.0" -"@testing-library/react@10.0.6": - version "10.0.6" - resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-10.0.6.tgz#e1e569135badb7367cc6ac9823e376eccb0280e0" - integrity sha512-7cZ2sHN6zTW1b/pNKzA0icZozshOOuiEQq/zCcf4LUCNGKAOnGCxZDQI7qjpO6lMITmi4Qs0VU1j9Cd4Z36e+w== +"@testing-library/react@10.2.1": + version "10.2.1" + resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-10.2.1.tgz#f0c5ac9072ad54c29672150943f35d6617263f26" + integrity sha512-pv2jZhiZgN1/alz1aImhSasZAOPg3er2Kgcfg9fzuw7aKPLxVengqqR1n0CJANeErR1DqORauQaod+gGUgAJOQ== dependencies: "@babel/runtime" "^7.10.2" "@testing-library/dom" "^7.9.0" - "@types/testing-library__react" "^10.0.1" "@types/anymatch@*": version "1.3.1" @@ -1503,13 +1492,6 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7" integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw== -"@types/react-dom@*": - version "16.9.5" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.5.tgz#5de610b04a35d07ffd8f44edad93a71032d9aaa7" - integrity sha512-BX6RQ8s9D+2/gDhxrj8OW+YD4R+8hj7FEM/OJHGNR0KipE1h1mSsf39YeyC81qafkq+N3rU3h3RFbLSwE5VqUg== - dependencies: - "@types/react" "*" - "@types/react-dom@16.9.8": version "16.9.8" resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.8.tgz#fe4c1e11dfc67155733dfa6aa65108b4971cb423" @@ -1547,22 +1529,6 @@ resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.5.tgz#9adbc12950582aa65ead76bffdf39fe0c27a3c02" integrity sha512-/gG2M/Imw7cQFp8PGvz/SwocNrmKFjFsm5Pb8HdbHkZ1K8pmuPzOX4VeVoiEecFCVf4CsN1r3/BRvx+6sNqwtQ== -"@types/testing-library__dom@*": - version "6.11.1" - resolved "https://registry.yarnpkg.com/@types/testing-library__dom/-/testing-library__dom-6.11.1.tgz#6058a6ac391db679f7c60dbb27b81f0620de2dd9" - integrity sha512-ImChHtQqmjwraRLqBC2sgSQFtczeFvBmBcfhTYZn/3KwXbyD07LQykEQ0xJo7QHc1GbVvf7pRyGaIe6PkCdxEw== - dependencies: - pretty-format "^24.3.0" - -"@types/testing-library__react@^10.0.1": - version "10.0.1" - resolved "https://registry.yarnpkg.com/@types/testing-library__react/-/testing-library__react-10.0.1.tgz#92bb4a02394bf44428e35f1da2970ed77f803593" - integrity sha512-RbDwmActAckbujLZeVO/daSfdL1pnjVqas25UueOkAY5r7vriavWf0Zqg7ghXMHa8ycD/kLkv8QOj31LmSYwww== - dependencies: - "@types/react-dom" "*" - "@types/testing-library__dom" "*" - pretty-format "^25.1.0" - "@types/uglify-js@*": version "3.0.4" resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.0.4.tgz#96beae23df6f561862a830b4288a49e86baac082" @@ -1656,6 +1622,16 @@ eslint-scope "^5.0.0" eslint-utils "^2.0.0" +"@typescript-eslint/experimental-utils@^2.5.0": + version "2.34.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.34.0.tgz#d3524b644cdb40eebceca67f8cf3e4cc9c8f980f" + integrity sha512-eS6FTkq+wuMJ+sgtuNTtcqavWXqsflWcfBnlYhg/nS4aZ1leewkXGbvBhaapn1q6qf4M71bsR1tez5JTRMuqwA== + dependencies: + "@types/json-schema" "^7.0.3" + "@typescript-eslint/typescript-estree" "2.34.0" + eslint-scope "^5.0.0" + eslint-utils "^2.0.0" + "@typescript-eslint/parser@3.1.0": version "3.1.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-3.1.0.tgz#9c02ba5d88ad2355672f39e6cd4176f172dd47f8" @@ -1689,6 +1665,19 @@ semver "^6.3.0" tsutils "^3.17.1" +"@typescript-eslint/typescript-estree@2.34.0": + version "2.34.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz#14aeb6353b39ef0732cc7f1b8285294937cf37d5" + integrity sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg== + dependencies: + debug "^4.1.1" + eslint-visitor-keys "^1.1.0" + glob "^7.1.6" + is-glob "^4.0.1" + lodash "^4.17.15" + semver "^7.3.2" + tsutils "^3.17.1" + "@typescript-eslint/typescript-estree@3.1.0": version "3.1.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-3.1.0.tgz#eaff52d31e615e05b894f8b9d2c3d8af152a5dd2" @@ -1898,16 +1887,16 @@ acorn-globals@^6.0.0: acorn "^7.1.1" acorn-walk "^7.1.1" +acorn-jsx@5.2.0, acorn-jsx@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.2.0.tgz#4c66069173d6fdd68ed85239fc256226182b2ebe" + integrity sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ== + acorn-jsx@^5.0.1, acorn-jsx@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.1.0.tgz#294adb71b57398b0680015f0a38c563ee1db5384" integrity sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw== -acorn-jsx@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.2.0.tgz#4c66069173d6fdd68ed85239fc256226182b2ebe" - integrity sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ== - acorn-walk@^6.0.1: version "6.2.0" resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-6.2.0.tgz#123cb8f3b84c2171f1f7fb252615b1c78a6b1a8c" @@ -1918,6 +1907,11 @@ acorn-walk@^7.1.1: resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.1.1.tgz#345f0dffad5c735e7373d2fec9a1023e6a44b83e" integrity sha512-wdlPY2tm/9XBr7QkKlq0WQVgiuGTX6YWPyRyBviSoScBuLfTVQhvwg6wJ369GJ/1nPfTLMfnrFIfjqVg6d+jQQ== +acorn@7.2.0, acorn@^7.1.1, acorn@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.2.0.tgz#17ea7e40d7c8640ff54a694c889c26f31704effe" + integrity sha512-apwXVmYVpQ34m/i71vrApRrRKCWQnZZF1+npOD0WV5xZFfwWOmKGQ2RWlfdy9vWITsenisM8M0Qeq8agcFHNiQ== + acorn@^5.5.3: version "5.7.4" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.4.tgz#3e8d8a9947d0599a1796d10225d7432f4a4acf5e" @@ -1933,11 +1927,6 @@ acorn@^7.1.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.0.tgz#949d36f2c292535da602283586c2477c57eb2d6c" integrity sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ== -acorn@^7.1.1, acorn@^7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.2.0.tgz#17ea7e40d7c8640ff54a694c889c26f31704effe" - integrity sha512-apwXVmYVpQ34m/i71vrApRrRKCWQnZZF1+npOD0WV5xZFfwWOmKGQ2RWlfdy9vWITsenisM8M0Qeq8agcFHNiQ== - address@1.1.2, address@^1.0.1: version "1.1.2" resolved "https://registry.yarnpkg.com/address/-/address-1.1.2.tgz#bf1116c9c758c51b7a933d296b72c221ed9428b6" @@ -4044,6 +4033,13 @@ escodegen@^1.14.1: optionalDependencies: source-map "~0.6.1" +eslint-config-prettier@6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.11.0.tgz#f6d2238c1290d01c859a8b5c1f7d352a0b0da8b1" + integrity sha512-oB8cpLWSAjOVFEJhhyMZh6NOEOtBVziaqdDQ86+qhDHFbZXoRTM7pNSvFRfW/W/L/LrQ38C99J5CGuRBBzBsdA== + dependencies: + get-stdin "^6.0.0" + eslint-config-prettier@^6.0.0: version "6.9.0" resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.9.0.tgz#430d24822e82f7deb1e22a435bfa3999fae4ad64" @@ -4114,6 +4110,18 @@ eslint-plugin-babel@5.3.0: dependencies: eslint-rule-composer "^0.3.0" +eslint-plugin-chai-expect@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-chai-expect/-/eslint-plugin-chai-expect-2.1.0.tgz#9dd1d8e5a80543fdec956f6aef7f83f2241ca92b" + integrity sha512-rd0/4mjMV6c3i0o4DKkWI4uaFN9DK707kW+/fDphaDI6HVgxXnhML9Xgt5vHnTXmSSnDhupuCFBgsEAEpchXmQ== + +eslint-plugin-cypress@2.11.1: + version "2.11.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-cypress/-/eslint-plugin-cypress-2.11.1.tgz#a945e2774b88211e2c706a059d431e262b5c2862" + integrity sha512-MxMYoReSO5+IZMGgpBZHHSx64zYPSPTpXDwsgW7ChlJTF/sA+obqRbHplxD6sBStE+g4Mi0LCLkG4t9liu//mQ== + dependencies: + globals "^11.12.0" + eslint-plugin-es@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-3.0.0.tgz#98cb1bc8ab0aa807977855e11ad9d1c9422d014b" @@ -4182,6 +4190,13 @@ eslint-plugin-import@^2.18.2: read-pkg-up "^2.0.0" resolve "^1.12.0" +eslint-plugin-jest@23.13.2: + version "23.13.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-23.13.2.tgz#7b7993b4e09be708c696b02555083ddefd7e4cc7" + integrity sha512-qZit+moTXTyZFNDqSIR88/L3rdBlTU7CuW6XmyErD2FfHEkdoLgThkRbiQjzgYnX6rfgLx3Ci4eJmF4Ui5v1Cw== + dependencies: + "@typescript-eslint/experimental-utils" "^2.5.0" + eslint-plugin-json@2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/eslint-plugin-json/-/eslint-plugin-json-2.1.1.tgz#7b9c4da2121f6f48d44efceb9a99ac0d4d12b299" @@ -4205,6 +4220,15 @@ eslint-plugin-jsx-a11y@6.2.3, eslint-plugin-jsx-a11y@^6.2.3: has "^1.0.3" jsx-ast-utils "^2.2.1" +eslint-plugin-markdown@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-markdown/-/eslint-plugin-markdown-1.0.2.tgz#79274bf17ce3ead48e4a55cbcb6d7ce735754280" + integrity sha512-BfvXKsO0K+zvdarNc801jsE/NTLmig4oKhZ1U3aSUgTf2dB/US5+CrfGxMsCK2Ki1vS1R3HPok+uYpufFndhzw== + dependencies: + object-assign "^4.0.1" + remark-parse "^5.0.0" + unified "^6.1.2" + eslint-plugin-no-inferred-method-name@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/eslint-plugin-no-inferred-method-name/-/eslint-plugin-no-inferred-method-name-2.0.0.tgz#99e2c9c921dfcb98c3874b427e26f8889f516c8e" @@ -4229,6 +4253,18 @@ eslint-plugin-optimize-regex@1.2.0: dependencies: regexp-tree "^0.1.20" +eslint-plugin-perf-standard@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-perf-standard/-/eslint-plugin-perf-standard-1.0.3.tgz#f2477073b40f7ae8c42093b9a08d84835d146b69" + integrity sha1-8kdwc7QPeujEIJO5oI2Eg10Ua2k= + +eslint-plugin-prettier@3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.3.tgz#ae116a0fc0e598fdae48743a4430903de5b4e6ca" + integrity sha512-+HG5jmu/dN3ZV3T6eCD7a4BlAySdN7mLIbJYo0z1cFQuI+r2DiTJEFeF68ots93PsnrMxbzIZ2S/ieX+mkrBeQ== + dependencies: + prettier-linter-helpers "^1.0.0" + eslint-plugin-prettier@^3.1.0: version "3.1.2" resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.2.tgz#432e5a667666ab84ce72f945c72f77d996a5c9ba" @@ -4306,6 +4342,18 @@ eslint-plugin-standard@4.0.1: resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-4.0.1.tgz#ff0519f7ffaff114f76d1bd7c3996eef0f6e20b4" integrity sha512-v/KBnfyaOMPmZc/dmc6ozOdWqekGp7bBGq4jLAecEfPGmfKiWS4sA8sC0LqiV9w5qmXAtXVn4M3p1jSyhY85SQ== +eslint-plugin-tree-shaking@1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-tree-shaking/-/eslint-plugin-tree-shaking-1.8.0.tgz#6ac08485481a5406142d0652bf894e45c46f3d5d" + integrity sha512-5jrqlyka6MCaV8efwAIIo/3cvmhurA4gUaFoTWoWw6wLhmHUS0/42NDKubKOMlQJXm5Z7/i4hbzyIcDXbHAnVw== + +eslint-plugin-xss@^0.1.10: + version "0.1.10" + resolved "https://registry.yarnpkg.com/eslint-plugin-xss/-/eslint-plugin-xss-0.1.10.tgz#4d2dd121475cfd73c0062883f33e330c0c3db5ee" + integrity sha512-Wm2QIokqBq/IYi529xDXf9EOmVoQdAclaTEw1PNk+iyzyTiWssc1dqFz00PuB6nh01vA4phw0dnseY9b3Tsg1w== + dependencies: + requireindex "~1.1.0" + eslint-plugin-you-dont-need-lodash-underscore@6.10.0: version "6.10.0" resolved "https://registry.yarnpkg.com/eslint-plugin-you-dont-need-lodash-underscore/-/eslint-plugin-you-dont-need-lodash-underscore-6.10.0.tgz#63df0785ee1a07365ef77db907692f1ac928e000" @@ -4334,6 +4382,14 @@ eslint-scope@^5.0.0: esrecurse "^4.1.0" estraverse "^4.1.1" +eslint-scope@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.0.tgz#d0f971dfe59c69e0cada684b23d49dbf82600ce5" + integrity sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + eslint-utils@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" @@ -4353,10 +4409,15 @@ eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== -eslint@7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.1.0.tgz#d9a1df25e5b7859b0a3d86bb05f0940ab676a851" - integrity sha512-DfS3b8iHMK5z/YLSme8K5cge168I8j8o1uiVmFCgnnjxZQbCGyraF8bMl7Ju4yfBmCuxD7shOF7eqGkcuIHfsA== +eslint-visitor-keys@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.2.0.tgz#74415ac884874495f78ec2a97349525344c981fa" + integrity sha512-WFb4ihckKil6hu3Dp798xdzSfddwKKU3+nGniKF6HfeW6OLd2OUDEPP7TcHtB5+QXOKg2s6B2DaMPE1Nn/kxKQ== + +eslint@7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.2.0.tgz#d41b2e47804b30dbabb093a967fb283d560082e6" + integrity sha512-B3BtEyaDKC5MlfDa2Ha8/D6DsS4fju95zs0hjS3HdGazw+LNayai38A25qMppK37wWGWNYSPOR6oYzlz5MHsRQ== dependencies: "@babel/code-frame" "^7.0.0" ajv "^6.10.0" @@ -4364,10 +4425,10 @@ eslint@7.1.0: cross-spawn "^7.0.2" debug "^4.0.1" doctrine "^3.0.0" - eslint-scope "^5.0.0" + eslint-scope "^5.1.0" eslint-utils "^2.0.0" - eslint-visitor-keys "^1.1.0" - espree "^7.0.0" + eslint-visitor-keys "^1.2.0" + espree "^7.1.0" esquery "^1.2.0" esutils "^2.0.2" file-entry-cache "^5.0.1" @@ -4447,14 +4508,14 @@ espree@^6.1.2: acorn-jsx "^5.1.0" eslint-visitor-keys "^1.1.0" -espree@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-7.0.0.tgz#8a7a60f218e69f120a842dc24c5a88aa7748a74e" - integrity sha512-/r2XEx5Mw4pgKdyb7GNLQNsu++asx/dltf/CI8RFi9oGHxmQFgvLbc5Op4U6i8Oaj+kdslhJtVlEZeAqH5qOTw== +espree@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-7.1.0.tgz#a9c7f18a752056735bf1ba14cb1b70adc3a5ce1c" + integrity sha512-dcorZSyfmm4WTuTnE5Y7MEN1DyoPYy1ZR783QW1FJoenn7RailyWFsq/UL6ZAAA7uXurN9FIpYyUs3OfiIW+Qw== dependencies: - acorn "^7.1.1" + acorn "^7.2.0" acorn-jsx "^5.2.0" - eslint-visitor-keys "^1.1.0" + eslint-visitor-keys "^1.2.0" esprima@^2.1.0: version "2.7.3" @@ -5165,7 +5226,7 @@ global-prefix@^3.0.0: kind-of "^6.0.2" which "^1.3.1" -globals@^11.1.0: +globals@^11.1.0, globals@^11.12.0: version "11.12.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== @@ -5769,7 +5830,7 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" -is-buffer@^1.1.5: +is-buffer@^1.1.4, is-buffer@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== @@ -5947,6 +6008,11 @@ is-path-inside@^2.1.0: dependencies: path-is-inside "^1.0.2" +is-plain-obj@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= + is-plain-obj@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.0.0.tgz#7fd1a7f1b69e160cde9181d2313f445c68aa2679" @@ -7479,6 +7545,11 @@ markdown-to-jsx@^6.11.4: prop-types "^15.6.2" unquote "^1.1.0" +markerwithlabel@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/markerwithlabel/-/markerwithlabel-2.0.2.tgz#fa6aee4abb0ee553e24e2b708226858f58b8729e" + integrity sha512-C/cbm1A0h/u54gwHk5ZJNdUU3V3+1BbCpRPMsMyFA7vF4yL+aB4rWpxACz29TpQ+cTg6/iQroExh0PMSRGtQFg== + md5.js@^1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" @@ -8594,7 +8665,7 @@ prettier@^1.19.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== -pretty-format@^24.3.0, pretty-format@^24.9.0: +pretty-format@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.9.0.tgz#12fac31b37019a4eea3c11aa9a959eb7628aa7c9" integrity sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA== @@ -8604,16 +8675,6 @@ pretty-format@^24.3.0, pretty-format@^24.9.0: ansi-styles "^3.2.0" react-is "^16.8.4" -pretty-format@^25.1.0: - version "25.1.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-25.1.0.tgz#ed869bdaec1356fc5ae45de045e2c8ec7b07b0c8" - integrity sha512-46zLRSGLd02Rp+Lhad9zzuNZ+swunitn8zIpfD2B4OPCRLXbM87RJT2aBLBWYOznNUML/2l/ReMyWNC80PJBUQ== - dependencies: - "@jest/types" "^25.1.0" - ansi-regex "^5.0.0" - ansi-styles "^4.0.0" - react-is "^16.12.0" - pretty-format@^25.2.1, pretty-format@^25.3.0: version "25.3.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-25.3.0.tgz#d0a4f988ff4a6cd350342fdabbb809aeb4d49ad5" @@ -9235,6 +9296,27 @@ regjsparser@^0.6.0: dependencies: jsesc "~0.5.0" +remark-parse@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-5.0.0.tgz#4c077f9e499044d1d5c13f80d7a98cf7b9285d95" + integrity sha512-b3iXszZLH1TLoyUzrATcTQUZrwNl1rE70rVdSruJFlDaJ9z5aMkhrG43Pp68OgfHndL/ADz6V69Zow8cTQu+JA== + dependencies: + collapse-white-space "^1.0.2" + is-alphabetical "^1.0.0" + is-decimal "^1.0.0" + is-whitespace-character "^1.0.0" + is-word-character "^1.0.0" + markdown-escapes "^1.0.0" + parse-entities "^1.1.0" + repeat-string "^1.5.4" + state-toggle "^1.0.0" + trim "0.0.1" + trim-trailing-lines "^1.0.0" + unherit "^1.0.4" + unist-util-remove-position "^1.0.0" + vfile-location "^2.0.0" + xtend "^4.0.1" + remark-parse@^7.0.0: version "7.0.2" resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-7.0.2.tgz#41e7170d9c1d96c3d32cf1109600a9ed50dba7cf" @@ -10841,10 +10923,10 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@3.9.3: - version "3.9.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.3.tgz#d3ac8883a97c26139e42df5e93eeece33d610b8a" - integrity sha512-D/wqnB2xzNFIcoBG9FG8cXRDjiqSTbG2wd8DMZeQyJlP1vfTkIxH4GKveWaEBYySKIg+USu+E+EDIR47SqnaMQ== +typescript@3.9.5: + version "3.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.5.tgz#586f0dba300cde8be52dd1ac4f7e1009c1b13f36" + integrity sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ== typescript@^3.7.3: version "3.7.5" @@ -10882,6 +10964,18 @@ unicode-property-aliases-ecmascript@^1.0.4: resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz#a9cc6cc7ce63a0a3023fc99e341b94431d405a57" integrity sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw== +unified@^6.1.2: + version "6.2.0" + resolved "https://registry.yarnpkg.com/unified/-/unified-6.2.0.tgz#7fbd630f719126d67d40c644b7e3f617035f6dba" + integrity sha512-1k+KPhlVtqmG99RaTbAv/usu85fcSRu3wY8X+vnsEhIxNP5VbVIDiXnLqyKIG+UMdyTg0ZX9EI6k2AfjJkHPtA== + dependencies: + bail "^1.0.0" + extend "^3.0.0" + is-plain-obj "^1.1.0" + trough "^1.0.0" + vfile "^2.0.0" + x-is-string "^0.1.0" + unified@^8.2.0: version "8.4.2" resolved "https://registry.yarnpkg.com/unified/-/unified-8.4.2.tgz#13ad58b4a437faa2751a4a4c6a16f680c500fff1" @@ -10934,6 +11028,11 @@ unist-util-remove-position@^1.0.0: dependencies: unist-util-visit "^1.1.0" +unist-util-stringify-position@^1.0.0, unist-util-stringify-position@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-1.1.2.tgz#3f37fcf351279dcbca7480ab5889bb8a832ee1c6" + integrity sha512-pNCVrk64LZv1kElr0N1wPiHEUoXNVFERp+mlTg/s9R5Lwg87f9bM/3sQB99w+N9D/qnM9ar3+AKDBwo/gm/iQQ== + unist-util-stringify-position@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-2.0.2.tgz#5a3866e7138d55974b640ec69a94bc19e0f3fa12" @@ -11130,6 +11229,13 @@ vfile-location@^2.0.0: resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-2.0.6.tgz#8a274f39411b8719ea5728802e10d9e0dff1519e" integrity sha512-sSFdyCP3G6Ka0CEmN83A2YCMKIieHx0EDaj5IDP4g1pa5ZJ4FJDvpO0WODLxo4LUX4oe52gmSCK7Jw4SBghqxA== +vfile-message@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-1.1.1.tgz#5833ae078a1dfa2d96e9647886cd32993ab313e1" + integrity sha512-1WmsopSGhWt5laNir+633LszXvZ+Z/lxveBf6yhGsqnQIhlhzooZae7zV6YVM1Sdkw68dtAW3ow0pOdPANugvA== + dependencies: + unist-util-stringify-position "^1.1.1" + vfile-message@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-2.0.2.tgz#75ba05090ec758fa8420f2c11ce049bcddd8cf3e" @@ -11138,6 +11244,16 @@ vfile-message@^2.0.0: "@types/unist" "^2.0.0" unist-util-stringify-position "^2.0.0" +vfile@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/vfile/-/vfile-2.3.0.tgz#e62d8e72b20e83c324bc6c67278ee272488bf84a" + integrity sha512-ASt4mBUHcTpMKD/l5Q+WJXNtshlWxOogYyGYYrg4lt/vuRjC1EFQtlAofL5VmtVNIZJzWYFJjzGWZ0Gw8pzW1w== + dependencies: + is-buffer "^1.1.4" + replace-ext "1.0.0" + unist-util-stringify-position "^1.0.0" + vfile-message "^1.0.0" + vfile@^4.0.0: version "4.0.2" resolved "https://registry.yarnpkg.com/vfile/-/vfile-4.0.2.tgz#71af004d4a710b0e6be99c894655bc56126d5d56" @@ -11547,6 +11663,11 @@ ws@^7.2.3: resolved "https://registry.yarnpkg.com/ws/-/ws-7.3.0.tgz#4b2f7f219b3d3737bc1a2fbf145d825b94d38ffd" integrity sha512-iFtXzngZVXPGgpTlP1rBqsUK82p9tKqsWRPg5L56egiljujJT3vGAYnHANvFxBieXrTFavhzhxW52jnaWV+w2w== +x-is-string@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/x-is-string/-/x-is-string-0.1.0.tgz#474b50865af3a49a9c4657f05acd145458f77d82" + integrity sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI= + xml-name-validator@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" diff --git a/yarn.lock b/yarn.lock index bbfb653e1..7eb102d48 100644 --- a/yarn.lock +++ b/yarn.lock @@ -25,13 +25,6 @@ dependencies: regenerator-runtime "^0.13.2" -"@samverschueren/stream-to-observable@^0.3.0": - version "0.3.0" - resolved "https://registry.yarnpkg.com/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz#ecdf48d532c58ea477acfcab80348424f8d0662f" - integrity sha512-MI4Xx6LHs4Webyvi6EbspgyAb4D2Q2VtnCQ1blOJcoLS6mVa8lNN2rkIy1CVxfTUpoyIbCTkXES1rLXztFD1lg== - dependencies: - any-observable "^0.3.0" - "@types/color-name@^1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" @@ -82,11 +75,6 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: "@types/color-name" "^1.1.1" color-convert "^2.0.1" -any-observable@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.3.0.tgz#af933475e5806a67d0d7df090dd5e8bef65d119b" - integrity sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog== - astral-regex@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" @@ -146,11 +134,6 @@ cli-truncate@2.1.0, cli-truncate@^2.1.0: slice-ansi "^3.0.0" string-width "^4.2.0" -clone@^1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" - integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= - color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -217,18 +200,6 @@ dedent@^0.7.0: resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= -defaults@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" - integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= - dependencies: - clone "^1.0.2" - -elegant-spinner@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/elegant-spinner/-/elegant-spinner-2.0.0.tgz#f236378985ecd16da75488d166be4b688fd5af94" - integrity sha512-5YRYHhvhYzV/FC4AiMdeSIg3jAYGq9xFvbhZMpPlJoBsfYgrw2DSCYeXfat6tYBu45PWiyRr3+flaCPPmviPaA== - emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" @@ -415,10 +386,10 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= -lint-staged@10.2.7: - version "10.2.7" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-10.2.7.tgz#6e47860af3d86a6a01849cbf8ba80f7754aae6eb" - integrity sha512-srod2bTpF8riaLz+Bgr6v0mI/nSntE8M9jbh4WwAhoosx0G7RKEUIG7mI5Nu5SMbTF9o8GROPgK0Lhf5cDnUUw== +lint-staged@10.2.9: + version "10.2.9" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-10.2.9.tgz#6013ecfa80829cd422446b545fd30a96bca3098c" + integrity sha512-ziRAuXEqvJLSXg43ezBpHxRW8FOJCXISaXU//BWrxRrp5cBdRkIx7g5IsB3OI45xYGE0S6cOacfekSjDyDKF2g== dependencies: chalk "^4.0.0" cli-truncate "2.1.0" @@ -426,8 +397,9 @@ lint-staged@10.2.7: cosmiconfig "^6.0.0" debug "^4.1.1" dedent "^0.7.0" + enquirer "^2.3.5" execa "^4.0.1" - listr2 "^2.0.2" + listr2 "^2.1.0" log-symbols "^4.0.0" micromatch "^4.0.2" normalize-path "^3.0.0" @@ -435,25 +407,19 @@ lint-staged@10.2.7: string-argv "0.3.1" stringify-object "^3.3.0" -listr2@^2.0.2: - version "2.0.4" - resolved "https://registry.yarnpkg.com/listr2/-/listr2-2.0.4.tgz#b39100b0a227ec5659dcf76ddc516211fc168d61" - integrity sha512-oJaAcplPsa72rKW0eg4P4LbEJjhH+UO2I8uqR/I2wzHrVg16ohSfUy0SlcHS21zfYXxtsUpL8YXGHjyfWMR0cg== +listr2@^2.1.0: + version "2.1.3" + resolved "https://registry.yarnpkg.com/listr2/-/listr2-2.1.3.tgz#f527e197de12ad8c488c566921fa2da34cbc67f6" + integrity sha512-6oy3QhrZAlJGrG8oPcRp1hix1zUpb5AvyvZ5je979HCyf48tIj3Hn1TG5+rfyhz30t7HfySH/OIaVbwrI2kruA== dependencies: - "@samverschueren/stream-to-observable" "^0.3.0" chalk "^4.0.0" - cli-cursor "^3.1.0" cli-truncate "^2.1.0" - elegant-spinner "^2.0.0" - enquirer "^2.3.5" figures "^3.2.0" indent-string "^4.0.0" log-update "^4.0.0" p-map "^4.0.0" - pad "^3.2.0" rxjs "^6.5.5" through "^2.3.8" - uuid "^7.0.2" locate-path@^5.0.0: version "5.0.0" @@ -559,13 +525,6 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== -pad@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/pad/-/pad-3.2.0.tgz#be7a1d1cb6757049b4ad5b70e71977158fea95d1" - integrity sha512-2u0TrjcGbOjBTJpyewEl4hBO3OeX5wWue7eIFPzQTg6wFSvoaHcBTTUY5m+n0hd04gmTCPuY0kCpVIVuw5etwg== - dependencies: - wcwidth "^1.0.1" - parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -771,18 +730,6 @@ type-fest@^0.11.0: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1" integrity sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ== -uuid@^7.0.2: - version "7.0.3" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b" - integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg== - -wcwidth@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" - integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= - dependencies: - defaults "^1.0.3" - which-pm-runs@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb"