diff --git a/configs/eslint-config-compass/index.js b/configs/eslint-config-compass/index.js index 2cb05106087..752f4daaaa1 100644 --- a/configs/eslint-config-compass/index.js +++ b/configs/eslint-config-compass/index.js @@ -44,7 +44,8 @@ const tsxRules = { 'react-hooks/exhaustive-deps': [ 'warn', { - additionalHooks: 'useTrackOnChange', + additionalHooks: + '(useTrackOnChange|useContextMenuItems|useContextMenuGroups)', }, ], }; diff --git a/package-lock.json b/package-lock.json index bf330c39573..bb4990b12bf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6071,9 +6071,9 @@ } }, "node_modules/@leafygreen-ui/icon": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/icon/-/icon-13.3.0.tgz", - "integrity": "sha512-//vun0KJrtMAN6pTCmQGT3brTFEpSE2LbNnwlJ+l8klG6bwEmcPF9xPCS+XU98/b3UhMhtXHpwbzYN29UteAYg==", + "version": "13.4.0", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/icon/-/icon-13.4.0.tgz", + "integrity": "sha512-GtvdkjPPERf8g0+uXGqBRw7Zgzhj1PH4moGQxNqyOc3IHeVkurAxjF1Oq64pKMLeMwuqFGhVGEVfXi3pixTPFg==", "license": "Apache-2.0", "dependencies": { "@leafygreen-ui/emotion": "^4.1.1", @@ -6287,32 +6287,33 @@ } }, "node_modules/@leafygreen-ui/popover": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/popover/-/popover-13.0.3.tgz", - "integrity": "sha512-5dmqbfwO2m5hYcgtlQr58JVK1oYdOIqGOQBtx0R9fjxrObuX2XpGa7g0ej9HuqVI+LrKD/BxsbVozlaVz4WmIQ==", + "version": "13.0.11", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/popover/-/popover-13.0.11.tgz", + "integrity": "sha512-A9LbihqeYlGmdvfj6KDAtVc89yvNqd/B1WeXyZBbxErQ4mm17NKqA8x4M1RstTazz9MP45HV6gsnz/fZ3Wml+g==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react": "^0.26.28", - "@leafygreen-ui/emotion": "^4.0.9", - "@leafygreen-ui/hooks": "^8.3.4", - "@leafygreen-ui/lib": "^14.0.2", - "@leafygreen-ui/portal": "^6.0.2", - "@leafygreen-ui/tokens": "^2.11.3", + "@leafygreen-ui/emotion": "^4.1.1", + "@leafygreen-ui/hooks": "^8.4.1", + "@leafygreen-ui/lib": "^14.2.0", + "@leafygreen-ui/portal": "^6.0.6", + "@leafygreen-ui/tokens": "^2.12.2", "@types/react-transition-group": "^4.4.5", + "lodash": "^4.17.21", "react-transition-group": "^4.4.5" }, "peerDependencies": { - "@leafygreen-ui/leafygreen-provider": "^4.0.2" + "@leafygreen-ui/leafygreen-provider": "^4.0.7" } }, "node_modules/@leafygreen-ui/portal": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/portal/-/portal-6.0.2.tgz", - "integrity": "sha512-RTGJdAScV6OicrLQv2CHU02CiELPYmrPOfOuuAC2YxqkLiOJCsNS4mE5TWaAYp+yMMFh5nC8cQWjXxNoYbdmNA==", + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/portal/-/portal-6.0.6.tgz", + "integrity": "sha512-kersWbwRpHGrqOKHhT6sBonsxXtkhowoAfxRPlbNRQBC7pgiZ/WWlfd3iE1vavqYliZAwImRG1qNZOz3D7SRcw==", "license": "Apache-2.0", "dependencies": { - "@leafygreen-ui/hooks": "^8.3.4", - "@leafygreen-ui/lib": "^14.0.2" + "@leafygreen-ui/hooks": "^8.4.1", + "@leafygreen-ui/lib": "^14.2.0" }, "peerDependencies": { "react-dom": "^17.0.0 || ^18.0.0" @@ -6611,34 +6612,34 @@ } }, "node_modules/@leafygreen-ui/tooltip": { - "version": "13.0.2", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/tooltip/-/tooltip-13.0.2.tgz", - "integrity": "sha512-dEfH4VmhvtOnTWGZZ62SkqGkaxNp2VEvuwbMrK3TKq5WqvCRdw7FDkEH7fKO2If284qWVKiJwIWCqPrIK0397g==", + "version": "13.0.13", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/tooltip/-/tooltip-13.0.13.tgz", + "integrity": "sha512-h9+/XGbzgy94lxREd/54cB9ryu6SVB7kcdUjjrR8klqRapfqrdrFEfJFOfltr7K3vfMoYo7F8XMOu7ctpJ8ylw==", "license": "Apache-2.0", "dependencies": { - "@leafygreen-ui/emotion": "^4.0.9", - "@leafygreen-ui/hooks": "^8.3.4", - "@leafygreen-ui/icon": "^13.1.2", - "@leafygreen-ui/lib": "^14.0.2", - "@leafygreen-ui/palette": "^4.1.3", - "@leafygreen-ui/popover": "^13.0.2", - "@leafygreen-ui/tokens": "^2.11.3", - "@leafygreen-ui/typography": "^20.0.2", + "@leafygreen-ui/emotion": "^4.1.1", + "@leafygreen-ui/hooks": "^8.4.1", + "@leafygreen-ui/icon": "^13.4.0", + "@leafygreen-ui/lib": "^14.2.0", + "@leafygreen-ui/palette": "^4.1.4", + "@leafygreen-ui/popover": "^13.0.11", + "@leafygreen-ui/tokens": "^2.12.2", + "@leafygreen-ui/typography": "^20.1.9", "lodash": "^4.17.21", "polished": "^4.2.2" }, "peerDependencies": { - "@leafygreen-ui/leafygreen-provider": "^4.0.2" + "@leafygreen-ui/leafygreen-provider": "^4.0.7" } }, "node_modules/@leafygreen-ui/typography": { - "version": "20.1.8", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/typography/-/typography-20.1.8.tgz", - "integrity": "sha512-roZz/Dopv/5A2TAvc5ysvi+s+R9SXkvPeIfJEcz9s9ZTi4RO5y7B8D81w3px0h1Fj8WnZDl8+bEPms4oak0EUw==", + "version": "20.1.9", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/typography/-/typography-20.1.9.tgz", + "integrity": "sha512-TPnzIRSgu8X/sZY4ASt4a03vVUKrGxLhpBAs//N+kDaf080Z/sMJqfWGaq/zjt3WQx4pVf+ThssHI+ZMOYdHvg==", "license": "Apache-2.0", "dependencies": { "@leafygreen-ui/emotion": "^4.1.1", - "@leafygreen-ui/icon": "^13.3.0", + "@leafygreen-ui/icon": "^13.4.0", "@leafygreen-ui/lib": "^14.2.0", "@leafygreen-ui/palette": "^4.1.4", "@leafygreen-ui/polymorphic": "^2.0.9", @@ -43619,12 +43620,12 @@ "@leafygreen-ui/leafygreen-provider": "^4.0.2", "@leafygreen-ui/logo": "^10.0.2", "@leafygreen-ui/marketing-modal": "^5.0.2", - "@leafygreen-ui/menu": "^28.0.2", + "@leafygreen-ui/menu": "^29.0.5", "@leafygreen-ui/modal": "^17.0.2", "@leafygreen-ui/palette": "^4.1.3", "@leafygreen-ui/pipeline": "^7.0.2", "@leafygreen-ui/polymorphic": "^2.0.5", - "@leafygreen-ui/popover": "^13.0.2", + "@leafygreen-ui/popover": "^13.0.11", "@leafygreen-ui/portal": "^6.0.2", "@leafygreen-ui/radio-box-group": "^14.0.2", "@leafygreen-ui/radio-group": "^12.0.2", @@ -43640,8 +43641,9 @@ "@leafygreen-ui/toast": "^7.0.2", "@leafygreen-ui/toggle": "^11.0.2", "@leafygreen-ui/tokens": "^2.11.3", - "@leafygreen-ui/tooltip": "^13.0.2", + "@leafygreen-ui/tooltip": "^13.0.13", "@leafygreen-ui/typography": "^20.0.2", + "@mongodb-js/compass-context-menu": "^0.0.1", "@react-aria/interactions": "^3.9.1", "@react-aria/utils": "^3.13.1", "@react-aria/visually-hidden": "^3.3.1", @@ -43678,6 +43680,17 @@ "typescript": "^5.0.4" } }, + "packages/compass-components/node_modules/@leafygreen-ui/a11y": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/a11y/-/a11y-2.0.7.tgz", + "integrity": "sha512-eIKWOs75WfmobMv1W7tk7nyZzD/NXgC/EnG0PnOYr2PBwtf4MDRyOQnctq/cVy7o6lg6SK0n/P4SbdftWqIDng==", + "license": "Apache-2.0", + "dependencies": { + "@leafygreen-ui/emotion": "^4.1.1", + "@leafygreen-ui/hooks": "^8.4.1", + "@leafygreen-ui/lib": "^14.2.0" + } + }, "packages/compass-components/node_modules/@leafygreen-ui/chip": { "version": "3.0.12", "resolved": "https://registry.npmjs.org/@leafygreen-ui/chip/-/chip-3.0.12.tgz", @@ -43695,6 +43708,20 @@ "@leafygreen-ui/leafygreen-provider": "^4.0.7" } }, + "packages/compass-components/node_modules/@leafygreen-ui/descendants": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/descendants/-/descendants-2.1.5.tgz", + "integrity": "sha512-1HT2spOnpULZb03wt95vbPOxOKEJKA9tdZDxH9KmWg+yYEMwEjxa+SNuHDZ/zxncJQe7NSDu1p1TQsHgjT5VpA==", + "license": "Apache-2.0", + "dependencies": { + "@leafygreen-ui/hooks": "^8.4.1", + "@leafygreen-ui/lib": "^14.2.0", + "lodash": "^4.17.21" + }, + "peerDependencies": { + "@leafygreen-ui/leafygreen-provider": "^4.0.7" + } + }, "packages/compass-components/node_modules/@leafygreen-ui/icon-button": { "version": "16.0.2", "resolved": "https://registry.npmjs.org/@leafygreen-ui/icon-button/-/icon-button-16.0.2.tgz", @@ -43730,37 +43757,67 @@ "@leafygreen-ui/leafygreen-provider": "^4.0.7" } }, - "packages/compass-components/node_modules/@leafygreen-ui/popover": { - "version": "13.0.11", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/popover/-/popover-13.0.11.tgz", - "integrity": "sha512-A9LbihqeYlGmdvfj6KDAtVc89yvNqd/B1WeXyZBbxErQ4mm17NKqA8x4M1RstTazz9MP45HV6gsnz/fZ3Wml+g==", + "packages/compass-components/node_modules/@leafygreen-ui/input-option": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/input-option/-/input-option-3.0.12.tgz", + "integrity": "sha512-p4mC9xZiyTapz2Z7vlgb9c839g2fcpi5ssRogn/Ix7uPaBpg6SAwQU1cqve6/55P1ekXVt0cHBTY1S/n+MtMQA==", "license": "Apache-2.0", "dependencies": { - "@floating-ui/react": "^0.26.28", + "@leafygreen-ui/a11y": "^2.0.7", + "@leafygreen-ui/emotion": "^4.1.1", + "@leafygreen-ui/lib": "^14.2.0", + "@leafygreen-ui/palette": "^4.1.4", + "@leafygreen-ui/polymorphic": "^2.0.9", + "@leafygreen-ui/tokens": "^2.12.2", + "@leafygreen-ui/typography": "^20.1.9" + }, + "peerDependencies": { + "@leafygreen-ui/leafygreen-provider": "^4.0.7" + } + }, + "packages/compass-components/node_modules/@leafygreen-ui/menu": { + "version": "29.0.5", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/menu/-/menu-29.0.5.tgz", + "integrity": "sha512-QVe4YoNaYEuJnSc9Cd+IJQG2vUykv9g4Az8TcVib4Axb5E0RsLt3EOwGr2WPPCCGktMEpVOT0OwrsbLtDCwopA==", + "license": "Apache-2.0", + "dependencies": { + "@leafygreen-ui/descendants": "^2.1.5", "@leafygreen-ui/emotion": "^4.1.1", "@leafygreen-ui/hooks": "^8.4.1", + "@leafygreen-ui/icon": "^13.4.0", + "@leafygreen-ui/icon-button": "^16.0.12", + "@leafygreen-ui/input-option": "^3.0.12", "@leafygreen-ui/lib": "^14.2.0", - "@leafygreen-ui/portal": "^6.0.6", + "@leafygreen-ui/palette": "^4.1.4", + "@leafygreen-ui/polymorphic": "^2.0.9", + "@leafygreen-ui/popover": "^13.0.11", "@leafygreen-ui/tokens": "^2.12.2", - "@types/react-transition-group": "^4.4.5", + "@leafygreen-ui/typography": "^20.1.9", "lodash": "^4.17.21", + "polished": "^4.3.1", "react-transition-group": "^4.4.5" }, "peerDependencies": { "@leafygreen-ui/leafygreen-provider": "^4.0.7" } }, - "packages/compass-components/node_modules/@leafygreen-ui/popover/node_modules/@leafygreen-ui/portal": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/portal/-/portal-6.0.6.tgz", - "integrity": "sha512-kersWbwRpHGrqOKHhT6sBonsxXtkhowoAfxRPlbNRQBC7pgiZ/WWlfd3iE1vavqYliZAwImRG1qNZOz3D7SRcw==", + "packages/compass-components/node_modules/@leafygreen-ui/menu/node_modules/@leafygreen-ui/icon-button": { + "version": "16.0.12", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/icon-button/-/icon-button-16.0.12.tgz", + "integrity": "sha512-EkuAfWe4J14/VEx0BDRNRXbN6QwaLqAnAYPtf/RUOwEqHzgkQQYkVStpEkAqp50k2OSR1FzopznmWxyPnrW55w==", "license": "Apache-2.0", "dependencies": { - "@leafygreen-ui/hooks": "^8.4.1", - "@leafygreen-ui/lib": "^14.2.0" + "@leafygreen-ui/a11y": "^2.0.7", + "@leafygreen-ui/emotion": "^4.1.1", + "@leafygreen-ui/icon": "^13.4.0", + "@leafygreen-ui/lib": "^14.2.0", + "@leafygreen-ui/palette": "^4.1.4", + "@leafygreen-ui/polymorphic": "^2.0.9", + "@leafygreen-ui/tokens": "^2.12.2", + "polished": "^4.2.2" }, "peerDependencies": { - "react-dom": "^17.0.0 || ^18.0.0" + "@leafygreen-ui/leafygreen-provider": "^4.0.7" } }, "packages/compass-components/node_modules/@leafygreen-ui/table": { @@ -43791,27 +43848,6 @@ "@leafygreen-ui/leafygreen-provider": "^4.0.2" } }, - "packages/compass-components/node_modules/@leafygreen-ui/tooltip": { - "version": "13.0.12", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/tooltip/-/tooltip-13.0.12.tgz", - "integrity": "sha512-ShFusJLnNw16tQ1c+24n0BpHu1DwbpmFeOQGEpoKud7zQlS5j75kCk2jq0S8ctKQi7K5la2QymiLy69u53/uwQ==", - "license": "Apache-2.0", - "dependencies": { - "@leafygreen-ui/emotion": "^4.1.1", - "@leafygreen-ui/hooks": "^8.4.1", - "@leafygreen-ui/icon": "^13.3.0", - "@leafygreen-ui/lib": "^14.2.0", - "@leafygreen-ui/palette": "^4.1.4", - "@leafygreen-ui/popover": "^13.0.11", - "@leafygreen-ui/tokens": "^2.12.2", - "@leafygreen-ui/typography": "^20.1.8", - "lodash": "^4.17.21", - "polished": "^4.2.2" - }, - "peerDependencies": { - "@leafygreen-ui/leafygreen-provider": "^4.0.7" - } - }, "packages/compass-components/node_modules/sinon": { "version": "9.2.4", "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.2.4.tgz", @@ -54062,9 +54098,9 @@ } }, "@leafygreen-ui/icon": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/icon/-/icon-13.3.0.tgz", - "integrity": "sha512-//vun0KJrtMAN6pTCmQGT3brTFEpSE2LbNnwlJ+l8klG6bwEmcPF9xPCS+XU98/b3UhMhtXHpwbzYN29UteAYg==", + "version": "13.4.0", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/icon/-/icon-13.4.0.tgz", + "integrity": "sha512-GtvdkjPPERf8g0+uXGqBRw7Zgzhj1PH4moGQxNqyOc3IHeVkurAxjF1Oq64pKMLeMwuqFGhVGEVfXi3pixTPFg==", "requires": { "@leafygreen-ui/emotion": "^4.1.1", "lodash": "^4.17.21" @@ -54237,27 +54273,28 @@ } }, "@leafygreen-ui/popover": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/popover/-/popover-13.0.3.tgz", - "integrity": "sha512-5dmqbfwO2m5hYcgtlQr58JVK1oYdOIqGOQBtx0R9fjxrObuX2XpGa7g0ej9HuqVI+LrKD/BxsbVozlaVz4WmIQ==", + "version": "13.0.11", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/popover/-/popover-13.0.11.tgz", + "integrity": "sha512-A9LbihqeYlGmdvfj6KDAtVc89yvNqd/B1WeXyZBbxErQ4mm17NKqA8x4M1RstTazz9MP45HV6gsnz/fZ3Wml+g==", "requires": { "@floating-ui/react": "^0.26.28", - "@leafygreen-ui/emotion": "^4.0.9", - "@leafygreen-ui/hooks": "^8.3.4", - "@leafygreen-ui/lib": "^14.0.2", - "@leafygreen-ui/portal": "^6.0.2", - "@leafygreen-ui/tokens": "^2.11.3", + "@leafygreen-ui/emotion": "^4.1.1", + "@leafygreen-ui/hooks": "^8.4.1", + "@leafygreen-ui/lib": "^14.2.0", + "@leafygreen-ui/portal": "^6.0.6", + "@leafygreen-ui/tokens": "^2.12.2", "@types/react-transition-group": "^4.4.5", + "lodash": "^4.17.21", "react-transition-group": "^4.4.5" } }, "@leafygreen-ui/portal": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/portal/-/portal-6.0.2.tgz", - "integrity": "sha512-RTGJdAScV6OicrLQv2CHU02CiELPYmrPOfOuuAC2YxqkLiOJCsNS4mE5TWaAYp+yMMFh5nC8cQWjXxNoYbdmNA==", + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/portal/-/portal-6.0.6.tgz", + "integrity": "sha512-kersWbwRpHGrqOKHhT6sBonsxXtkhowoAfxRPlbNRQBC7pgiZ/WWlfd3iE1vavqYliZAwImRG1qNZOz3D7SRcw==", "requires": { - "@leafygreen-ui/hooks": "^8.3.4", - "@leafygreen-ui/lib": "^14.0.2" + "@leafygreen-ui/hooks": "^8.4.1", + "@leafygreen-ui/lib": "^14.2.0" } }, "@leafygreen-ui/radio-box-group": { @@ -54502,29 +54539,29 @@ } }, "@leafygreen-ui/tooltip": { - "version": "13.0.2", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/tooltip/-/tooltip-13.0.2.tgz", - "integrity": "sha512-dEfH4VmhvtOnTWGZZ62SkqGkaxNp2VEvuwbMrK3TKq5WqvCRdw7FDkEH7fKO2If284qWVKiJwIWCqPrIK0397g==", + "version": "13.0.13", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/tooltip/-/tooltip-13.0.13.tgz", + "integrity": "sha512-h9+/XGbzgy94lxREd/54cB9ryu6SVB7kcdUjjrR8klqRapfqrdrFEfJFOfltr7K3vfMoYo7F8XMOu7ctpJ8ylw==", "requires": { - "@leafygreen-ui/emotion": "^4.0.9", - "@leafygreen-ui/hooks": "^8.3.4", - "@leafygreen-ui/icon": "^13.1.2", - "@leafygreen-ui/lib": "^14.0.2", - "@leafygreen-ui/palette": "^4.1.3", - "@leafygreen-ui/popover": "^13.0.2", - "@leafygreen-ui/tokens": "^2.11.3", - "@leafygreen-ui/typography": "^20.0.2", + "@leafygreen-ui/emotion": "^4.1.1", + "@leafygreen-ui/hooks": "^8.4.1", + "@leafygreen-ui/icon": "^13.4.0", + "@leafygreen-ui/lib": "^14.2.0", + "@leafygreen-ui/palette": "^4.1.4", + "@leafygreen-ui/popover": "^13.0.11", + "@leafygreen-ui/tokens": "^2.12.2", + "@leafygreen-ui/typography": "^20.1.9", "lodash": "^4.17.21", "polished": "^4.2.2" } }, "@leafygreen-ui/typography": { - "version": "20.1.8", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/typography/-/typography-20.1.8.tgz", - "integrity": "sha512-roZz/Dopv/5A2TAvc5ysvi+s+R9SXkvPeIfJEcz9s9ZTi4RO5y7B8D81w3px0h1Fj8WnZDl8+bEPms4oak0EUw==", + "version": "20.1.9", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/typography/-/typography-20.1.9.tgz", + "integrity": "sha512-TPnzIRSgu8X/sZY4ASt4a03vVUKrGxLhpBAs//N+kDaf080Z/sMJqfWGaq/zjt3WQx4pVf+ThssHI+ZMOYdHvg==", "requires": { "@leafygreen-ui/emotion": "^4.1.1", - "@leafygreen-ui/icon": "^13.3.0", + "@leafygreen-ui/icon": "^13.4.0", "@leafygreen-ui/lib": "^14.2.0", "@leafygreen-ui/palette": "^4.1.4", "@leafygreen-ui/polymorphic": "^2.0.9", @@ -56218,12 +56255,12 @@ "@leafygreen-ui/leafygreen-provider": "^4.0.2", "@leafygreen-ui/logo": "^10.0.2", "@leafygreen-ui/marketing-modal": "^5.0.2", - "@leafygreen-ui/menu": "^28.0.2", + "@leafygreen-ui/menu": "^29.0.5", "@leafygreen-ui/modal": "^17.0.2", "@leafygreen-ui/palette": "^4.1.3", "@leafygreen-ui/pipeline": "^7.0.2", "@leafygreen-ui/polymorphic": "^2.0.5", - "@leafygreen-ui/popover": "^13.0.2", + "@leafygreen-ui/popover": "^13.0.11", "@leafygreen-ui/portal": "^6.0.2", "@leafygreen-ui/radio-box-group": "^14.0.2", "@leafygreen-ui/radio-group": "^12.0.2", @@ -56239,8 +56276,9 @@ "@leafygreen-ui/toast": "^7.0.2", "@leafygreen-ui/toggle": "^11.0.2", "@leafygreen-ui/tokens": "^2.11.3", - "@leafygreen-ui/tooltip": "^13.0.2", + "@leafygreen-ui/tooltip": "^13.0.13", "@leafygreen-ui/typography": "^20.0.2", + "@mongodb-js/compass-context-menu": "^0.0.1", "@mongodb-js/eslint-config-compass": "^1.3.10", "@mongodb-js/mocha-config-compass": "^1.6.8", "@mongodb-js/prettier-config-compass": "^1.2.8", @@ -56274,6 +56312,16 @@ "typescript": "^5.0.4" }, "dependencies": { + "@leafygreen-ui/a11y": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/a11y/-/a11y-2.0.7.tgz", + "integrity": "sha512-eIKWOs75WfmobMv1W7tk7nyZzD/NXgC/EnG0PnOYr2PBwtf4MDRyOQnctq/cVy7o6lg6SK0n/P4SbdftWqIDng==", + "requires": { + "@leafygreen-ui/emotion": "^4.1.1", + "@leafygreen-ui/hooks": "^8.4.1", + "@leafygreen-ui/lib": "^14.2.0" + } + }, "@leafygreen-ui/chip": { "version": "3.0.12", "resolved": "https://registry.npmjs.org/@leafygreen-ui/chip/-/chip-3.0.12.tgz", @@ -56287,6 +56335,16 @@ "@leafygreen-ui/tokens": "^2.12.2" } }, + "@leafygreen-ui/descendants": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/descendants/-/descendants-2.1.5.tgz", + "integrity": "sha512-1HT2spOnpULZb03wt95vbPOxOKEJKA9tdZDxH9KmWg+yYEMwEjxa+SNuHDZ/zxncJQe7NSDu1p1TQsHgjT5VpA==", + "requires": { + "@leafygreen-ui/hooks": "^8.4.1", + "@leafygreen-ui/lib": "^14.2.0", + "lodash": "^4.17.21" + } + }, "@leafygreen-ui/icon-button": { "version": "16.0.2", "resolved": "https://registry.npmjs.org/@leafygreen-ui/icon-button/-/icon-button-16.0.2.tgz", @@ -56314,29 +56372,55 @@ "@leafygreen-ui/tooltip": "^13.0.12" } }, - "@leafygreen-ui/popover": { - "version": "13.0.11", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/popover/-/popover-13.0.11.tgz", - "integrity": "sha512-A9LbihqeYlGmdvfj6KDAtVc89yvNqd/B1WeXyZBbxErQ4mm17NKqA8x4M1RstTazz9MP45HV6gsnz/fZ3Wml+g==", + "@leafygreen-ui/input-option": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/input-option/-/input-option-3.0.12.tgz", + "integrity": "sha512-p4mC9xZiyTapz2Z7vlgb9c839g2fcpi5ssRogn/Ix7uPaBpg6SAwQU1cqve6/55P1ekXVt0cHBTY1S/n+MtMQA==", + "requires": { + "@leafygreen-ui/a11y": "^2.0.7", + "@leafygreen-ui/emotion": "^4.1.1", + "@leafygreen-ui/lib": "^14.2.0", + "@leafygreen-ui/palette": "^4.1.4", + "@leafygreen-ui/polymorphic": "^2.0.9", + "@leafygreen-ui/tokens": "^2.12.2", + "@leafygreen-ui/typography": "^20.1.9" + } + }, + "@leafygreen-ui/menu": { + "version": "29.0.5", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/menu/-/menu-29.0.5.tgz", + "integrity": "sha512-QVe4YoNaYEuJnSc9Cd+IJQG2vUykv9g4Az8TcVib4Axb5E0RsLt3EOwGr2WPPCCGktMEpVOT0OwrsbLtDCwopA==", "requires": { - "@floating-ui/react": "^0.26.28", + "@leafygreen-ui/descendants": "^2.1.5", "@leafygreen-ui/emotion": "^4.1.1", "@leafygreen-ui/hooks": "^8.4.1", + "@leafygreen-ui/icon": "^13.4.0", + "@leafygreen-ui/icon-button": "^16.0.12", + "@leafygreen-ui/input-option": "^3.0.12", "@leafygreen-ui/lib": "^14.2.0", - "@leafygreen-ui/portal": "^6.0.6", + "@leafygreen-ui/palette": "^4.1.4", + "@leafygreen-ui/polymorphic": "^2.0.9", + "@leafygreen-ui/popover": "^13.0.11", "@leafygreen-ui/tokens": "^2.12.2", - "@types/react-transition-group": "^4.4.5", + "@leafygreen-ui/typography": "^20.1.9", "lodash": "^4.17.21", + "polished": "^4.3.1", "react-transition-group": "^4.4.5" }, "dependencies": { - "@leafygreen-ui/portal": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/portal/-/portal-6.0.6.tgz", - "integrity": "sha512-kersWbwRpHGrqOKHhT6sBonsxXtkhowoAfxRPlbNRQBC7pgiZ/WWlfd3iE1vavqYliZAwImRG1qNZOz3D7SRcw==", + "@leafygreen-ui/icon-button": { + "version": "16.0.12", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/icon-button/-/icon-button-16.0.12.tgz", + "integrity": "sha512-EkuAfWe4J14/VEx0BDRNRXbN6QwaLqAnAYPtf/RUOwEqHzgkQQYkVStpEkAqp50k2OSR1FzopznmWxyPnrW55w==", "requires": { - "@leafygreen-ui/hooks": "^8.4.1", - "@leafygreen-ui/lib": "^14.2.0" + "@leafygreen-ui/a11y": "^2.0.7", + "@leafygreen-ui/emotion": "^4.1.1", + "@leafygreen-ui/icon": "^13.4.0", + "@leafygreen-ui/lib": "^14.2.0", + "@leafygreen-ui/palette": "^4.1.4", + "@leafygreen-ui/polymorphic": "^2.0.9", + "@leafygreen-ui/tokens": "^2.12.2", + "polished": "^4.2.2" } } } @@ -56365,23 +56449,6 @@ "react-intersection-observer": "^8.25.1" } }, - "@leafygreen-ui/tooltip": { - "version": "13.0.12", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/tooltip/-/tooltip-13.0.12.tgz", - "integrity": "sha512-ShFusJLnNw16tQ1c+24n0BpHu1DwbpmFeOQGEpoKud7zQlS5j75kCk2jq0S8ctKQi7K5la2QymiLy69u53/uwQ==", - "requires": { - "@leafygreen-ui/emotion": "^4.1.1", - "@leafygreen-ui/hooks": "^8.4.1", - "@leafygreen-ui/icon": "^13.3.0", - "@leafygreen-ui/lib": "^14.2.0", - "@leafygreen-ui/palette": "^4.1.4", - "@leafygreen-ui/popover": "^13.0.11", - "@leafygreen-ui/tokens": "^2.12.2", - "@leafygreen-ui/typography": "^20.1.8", - "lodash": "^4.17.21", - "polished": "^4.2.2" - } - }, "sinon": { "version": "9.2.4", "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.2.4.tgz", diff --git a/packages/compass-components/package.json b/packages/compass-components/package.json index 14af3a7b98b..f17ec4608b5 100644 --- a/packages/compass-components/package.json +++ b/packages/compass-components/package.json @@ -52,12 +52,12 @@ "@leafygreen-ui/leafygreen-provider": "^4.0.2", "@leafygreen-ui/logo": "^10.0.2", "@leafygreen-ui/marketing-modal": "^5.0.2", - "@leafygreen-ui/menu": "^28.0.2", + "@leafygreen-ui/menu": "^29.0.5", "@leafygreen-ui/modal": "^17.0.2", "@leafygreen-ui/palette": "^4.1.3", "@leafygreen-ui/pipeline": "^7.0.2", "@leafygreen-ui/polymorphic": "^2.0.5", - "@leafygreen-ui/popover": "^13.0.2", + "@leafygreen-ui/popover": "^13.0.11", "@leafygreen-ui/portal": "^6.0.2", "@leafygreen-ui/radio-box-group": "^14.0.2", "@leafygreen-ui/radio-group": "^12.0.2", @@ -73,8 +73,9 @@ "@leafygreen-ui/toast": "^7.0.2", "@leafygreen-ui/toggle": "^11.0.2", "@leafygreen-ui/tokens": "^2.11.3", - "@leafygreen-ui/tooltip": "^13.0.2", + "@leafygreen-ui/tooltip": "^13.0.13", "@leafygreen-ui/typography": "^20.0.2", + "@mongodb-js/compass-context-menu": "^0.0.1", "@react-aria/interactions": "^3.9.1", "@react-aria/utils": "^3.13.1", "@react-aria/visually-hidden": "^3.3.1", diff --git a/packages/compass-components/src/components/compass-components-provider.tsx b/packages/compass-components/src/components/compass-components-provider.tsx index 18bac239d30..7a2fdf20117 100644 --- a/packages/compass-components/src/components/compass-components-provider.tsx +++ b/packages/compass-components/src/components/compass-components-provider.tsx @@ -6,6 +6,7 @@ import { GuideCueProvider } from './guide-cue/guide-cue'; import { SignalHooksProvider } from './signal-popover'; import { RequiredURLSearchParamsProvider } from './links/link'; import { StackedComponentProvider } from '../hooks/use-stacked-component'; +import { ContextMenuProvider } from './context-menu'; type GuideCueProviderProps = React.ComponentProps; @@ -135,15 +136,17 @@ export const CompassComponentsProvider = ({ > - - {typeof children === 'function' - ? children({ - darkMode, - portalContainerRef: setPortalContainer, - scrollContainerRef: setScrollContainer, - }) - : children} - + + + {typeof children === 'function' + ? children({ + darkMode, + portalContainerRef: setPortalContainer, + scrollContainerRef: setScrollContainer, + }) + : children} + + diff --git a/packages/compass-components/src/components/content-with-fallback.spec.tsx b/packages/compass-components/src/components/content-with-fallback.spec.tsx index bd4daa3861c..ac2f8a40910 100644 --- a/packages/compass-components/src/components/content-with-fallback.spec.tsx +++ b/packages/compass-components/src/components/content-with-fallback.spec.tsx @@ -58,7 +58,9 @@ describe('ContentWithFallback', function () { { container } ); - expect(container).to.be.empty; + expect(container.children.length).to.equal(1); + const [anchorElement] = container.children; + expect(anchorElement.getAttribute('data-testid')).to.equal('context-menu'); }); it('should render fallback when the timeout passes', async function () { diff --git a/packages/compass-components/src/components/context-menu.spec.tsx b/packages/compass-components/src/components/context-menu.spec.tsx new file mode 100644 index 00000000000..13fd851ec0c --- /dev/null +++ b/packages/compass-components/src/components/context-menu.spec.tsx @@ -0,0 +1,166 @@ +import React from 'react'; +import { render, screen, userEvent } from '@mongodb-js/testing-library-compass'; +import { expect } from 'chai'; +import sinon from 'sinon'; +import { ContextMenuProvider } from '@mongodb-js/compass-context-menu'; +import { useContextMenuItems, ContextMenu } from './context-menu'; +import type { ContextMenuItem } from '@mongodb-js/compass-context-menu'; + +describe('useContextMenuItems', function () { + const menuTestTriggerId = 'test-trigger'; + + const TestComponent = ({ + items, + children, + 'data-testid': dataTestId = menuTestTriggerId, + }: { + items: ContextMenuItem[]; + children?: React.ReactNode; + 'data-testid'?: string; + }) => { + const ref = useContextMenuItems(() => items, [items]); + + return ( +
+ Test Component + {children} +
+ ); + }; + + it('works with nested providers, using the parent provider', function () { + const items = [ + { + label: 'Test Item', + onAction: () => {}, + }, + ]; + + const { container } = render( + + + + + + ); + + // Should only find one context menu (from the parent provider) + expect( + container.querySelectorAll('[data-testid="context-menu"]') + ).to.have.length(1); + // Should still render the trigger + expect(screen.getByTestId(menuTestTriggerId)).to.exist; + }); + + it('renders without error', function () { + const items = [ + { + label: 'Test Item', + onAction: () => {}, + }, + ]; + + render(); + + expect(screen.getByTestId(menuTestTriggerId)).to.exist; + }); + + it('shows context menu with items on right click', function () { + const items = [ + { + label: 'Test Item 1', + onAction: () => {}, + }, + { + label: 'Test Item 2', + onAction: () => {}, + }, + ]; + + render(); + + const trigger = screen.getByTestId(menuTestTriggerId); + userEvent.click(trigger, { button: 2 }); + + // The menu items should be rendered + expect(screen.getByTestId('menu-group-0-item-0')).to.exist; + expect(screen.getByTestId('menu-group-0-item-1')).to.exist; + }); + + it('triggers the correct action when menu item is clicked', function () { + const onAction = sinon.spy(); + const items = [ + { + label: 'Test Item 1', + onAction: () => onAction(1), + }, + { + label: 'Test Item 2', + onAction: () => onAction(2), + }, + ]; + + render(); + + const trigger = screen.getByTestId(menuTestTriggerId); + userEvent.click(trigger, { button: 2 }); + + const menuItem = screen.getByTestId('menu-group-0-item-1'); + userEvent.click(menuItem); + + expect(onAction).to.have.been.calledOnceWithExactly(2); + }); + + describe('with nested components', function () { + const childTriggerId = 'child-trigger'; + + beforeEach(function () { + const items = [ + { + label: 'Test Item 1', + onAction: () => {}, + }, + { + label: 'Test Item 2', + onAction: () => {}, + }, + ]; + + const childItems = [ + { + label: 'Child Item 1', + onAction: () => {}, + }, + ]; + + render( + + + + ); + }); + + it('renders menu items with separators', function () { + const trigger = screen.getByTestId(childTriggerId); + userEvent.click(trigger, { button: 2 }); + + // Should find the menu item and the separator + expect(screen.getByTestId('menu-group-0').children.length).to.equal(2); + expect( + screen.getByTestId('menu-group-0').children.item(0)?.textContent + ).to.equal('Child Item 1'); + + expect(screen.getByTestId('menu-group-0-separator')).to.exist; + + expect(screen.getByTestId('menu-group-1').children.length).to.equal(2); + expect( + screen.getByTestId('menu-group-1').children.item(0)?.textContent + ).to.equal('Test Item 1'); + expect( + screen.getByTestId('menu-group-1').children.item(1)?.textContent + ).to.equal('Test Item 2'); + + expect(screen.queryByTestId('menu-group-1-separator')).not.to.exist; + }); + }); +}); diff --git a/packages/compass-components/src/components/context-menu.tsx b/packages/compass-components/src/components/context-menu.tsx new file mode 100644 index 00000000000..8941cbab1da --- /dev/null +++ b/packages/compass-components/src/components/context-menu.tsx @@ -0,0 +1,110 @@ +import React, { useEffect, useMemo, useRef } from 'react'; +import { Menu, MenuItem, MenuSeparator } from './leafygreen'; + +import { + ContextMenuProvider as ContextMenuProviderBase, + useContextMenu, + type ContextMenuItem, + type ContextMenuItemGroup, + type ContextMenuWrapperProps, +} from '@mongodb-js/compass-context-menu'; + +export type { ContextMenuItem } from '@mongodb-js/compass-context-menu'; + +export function ContextMenuProvider({ + children, +}: { + children: React.ReactNode; +}) { + return ( + + {children} + + ); +} + +export function ContextMenu({ menu }: ContextMenuWrapperProps) { + const menuRef = useRef(null); + + const { position, itemGroups } = menu; + + useEffect(() => { + if (!menu.isOpen) { + menu.close(); + } + }, [menu.isOpen]); + + return ( +
+ + {itemGroups.map((items: ContextMenuItemGroup, groupIndex: number) => { + return ( +
+ {items.map((item: ContextMenuItem, itemIndex: number) => { + return ( + { + item.onAction?.(evt); + menu.close(); + }} + > + {item.label} + + ); + })} + {groupIndex < itemGroups.length - 1 && ( +
+ +
+ )} +
+ ); + })} +
+
+ ); +} + +export function useContextMenuItems( + getItems: () => ContextMenuItem[], + dependencies: React.DependencyList | undefined +): React.RefCallback { + // eslint-disable-next-line react-hooks/exhaustive-deps + const memoizedItems = useMemo(getItems, dependencies); + const contextMenu = useContextMenu(); + return contextMenu.registerItems(memoizedItems); +} + +export function useContextMenuGroups( + getGroups: () => ContextMenuItemGroup[], + dependencies: React.DependencyList | undefined +): React.RefCallback { + // eslint-disable-next-line react-hooks/exhaustive-deps + const memoizedGroups = useMemo(getGroups, dependencies); + const contextMenu = useContextMenu(); + return contextMenu.registerItems(...memoizedGroups); +} diff --git a/packages/compass-components/src/components/leafygreen.tsx b/packages/compass-components/src/components/leafygreen.tsx index fce04e6affd..1563d00d02e 100644 --- a/packages/compass-components/src/components/leafygreen.tsx +++ b/packages/compass-components/src/components/leafygreen.tsx @@ -72,7 +72,7 @@ import LeafyGreenTextInput from '@leafygreen-ui/text-input'; import { SearchInput } from '@leafygreen-ui/search-input'; export type { ToastProps } from '@leafygreen-ui/toast'; export { ToastProvider, useToast } from '@leafygreen-ui/toast'; -export { usePrevious } from '@leafygreen-ui/hooks'; +export { usePrevious, useMergeRefs } from '@leafygreen-ui/hooks'; import Toggle from '@leafygreen-ui/toggle'; import Tooltip from '@leafygreen-ui/tooltip'; import { diff --git a/packages/compass-components/src/index.ts b/packages/compass-components/src/index.ts index 56f02757634..6be7d8102eb 100644 --- a/packages/compass-components/src/index.ts +++ b/packages/compass-components/src/index.ts @@ -100,6 +100,12 @@ export { ModalHeader } from './components/modals/modal-header'; export { FormModal } from './components/modals/form-modal'; export { InfoModal } from './components/modals/info-modal'; +export { + useContextMenuItems, + useContextMenuGroups, + type ContextMenuItem, +} from './components/context-menu'; + export type { FileInputBackend, ItemAction, diff --git a/packages/compass-context-menu/src/context-menu-content.ts b/packages/compass-context-menu/src/context-menu-content.ts index c301983a679..bbfd53ccea9 100644 --- a/packages/compass-context-menu/src/context-menu-content.ts +++ b/packages/compass-context-menu/src/context-menu-content.ts @@ -14,11 +14,11 @@ export function getContextMenuContent( export function appendContextMenuContent( event: EnhancedMouseEvent, - content: ContextMenuItemGroup + ...groups: ContextMenuItemGroup[] ) { // Initialize if not already patched if (!event[CONTEXT_MENUS_SYMBOL]) { event[CONTEXT_MENUS_SYMBOL] = []; } - event[CONTEXT_MENUS_SYMBOL].push(content); + event[CONTEXT_MENUS_SYMBOL].push(...groups); } diff --git a/packages/compass-context-menu/src/context-menu-provider.spec.tsx b/packages/compass-context-menu/src/context-menu-provider.spec.tsx index 0cd6f23e492..88d85c1fbcf 100644 --- a/packages/compass-context-menu/src/context-menu-provider.spec.tsx +++ b/packages/compass-context-menu/src/context-menu-provider.spec.tsx @@ -1,9 +1,12 @@ import React from 'react'; -import { render } from '@mongodb-js/testing-library-compass'; +import { testingLibrary } from '@mongodb-js/testing-library-compass'; import { expect } from 'chai'; import { ContextMenuProvider } from './context-menu-provider'; import type { ContextMenuWrapperProps } from './types'; +// We need to import from testing-library-compass directly to avoid the extra wrapping. +const { render } = testingLibrary; + describe('ContextMenuProvider', function () { const TestMenu: React.FC = () => (
Test Menu
@@ -14,20 +17,23 @@ describe('ContextMenuProvider', function () { ); describe('when nested', function () { - it('throws an error when providers are nested', function () { - expect(() => { - render( - -
- - - -
-
- ); - }).to.throw( - 'Duplicated ContextMenuProvider found. Please remove the nested provider.' + it('uses parent provider and does not render duplicate menu wrapper', function () { + const { container } = render( + +
+ + + +
+
); + + // Should only find one test-menu element (from the parent provider) + expect( + container.querySelectorAll('[data-testid="test-menu"]') + ).to.have.length(1); + // Should still render the content + expect(container.querySelector('[data-testid="test-content"]')).to.exist; }); }); diff --git a/packages/compass-context-menu/src/context-menu-provider.tsx b/packages/compass-context-menu/src/context-menu-provider.tsx index aac3cd92494..d88280d976f 100644 --- a/packages/compass-context-menu/src/context-menu-provider.tsx +++ b/packages/compass-context-menu/src/context-menu-provider.tsx @@ -26,30 +26,29 @@ export function ContextMenuProvider({ // Check if there's already a parent context menu provider const parentContext = useContext(ContextMenuContext); - // Prevent accidental nested providers - if (parentContext) { - throw new Error( - 'Duplicated ContextMenuProvider found. Please remove the nested provider.' - ); - } - const [menu, setMenu] = useState({ isOpen: false, itemGroups: [], position: { x: 0, y: 0 }, }); - const close = useCallback(() => setMenu({ ...menu, isOpen: false }), [menu]); + const close = useCallback( + () => setMenu((prev) => ({ ...prev, isOpen: false })), + [setMenu] + ); const handleClosingEvent = useCallback( (event: Event) => { if (!event.defaultPrevented) { - setMenu({ ...menu, isOpen: false }); + close(); } }, - [menu] + [close] ); useEffect(() => { + // Don't set up event listeners if we have a parent context + if (parentContext) return; + function handleContextMenu(event: MouseEvent) { event.preventDefault(); @@ -77,7 +76,7 @@ export function ContextMenuProvider({ document.removeEventListener('contextmenu', handleContextMenu); window.removeEventListener('resize', handleClosingEvent); }; - }, [handleClosingEvent]); + }, [handleClosingEvent, parentContext]); const value = useMemo( () => ({ @@ -86,6 +85,11 @@ export function ContextMenuProvider({ [close] ); + // If we have a parent context, just render children without the wrapper + if (parentContext) { + return <>{children}; + } + const Wrapper = menuWrapper ?? React.Fragment; return ( diff --git a/packages/compass-context-menu/src/types.ts b/packages/compass-context-menu/src/types.ts index 163abe56132..1b342f9a3da 100644 --- a/packages/compass-context-menu/src/types.ts +++ b/packages/compass-context-menu/src/types.ts @@ -1,7 +1,4 @@ -export interface ContextMenuItemGroup { - items: ContextMenuItem[]; - originListener: (event: MouseEvent) => void; -} +export type ContextMenuItemGroup = ContextMenuItem[]; export type ContextMenuState = { isOpen: boolean; diff --git a/packages/compass-context-menu/src/use-context-menu.spec.tsx b/packages/compass-context-menu/src/use-context-menu.spec.tsx index fb17fa0e66a..e6cde2deae7 100644 --- a/packages/compass-context-menu/src/use-context-menu.spec.tsx +++ b/packages/compass-context-menu/src/use-context-menu.spec.tsx @@ -1,16 +1,23 @@ import React from 'react'; -import { render, screen, userEvent } from '@mongodb-js/testing-library-compass'; +import { + screen, + userEvent, + testingLibrary, +} from '@mongodb-js/testing-library-compass'; import { expect } from 'chai'; import sinon from 'sinon'; import { useContextMenu } from './use-context-menu'; import { ContextMenuProvider } from './context-menu-provider'; import type { ContextMenuItem, ContextMenuWrapperProps } from './types'; +// We need to import from testing-library-compass directly to avoid the extra wrapping. +const { render } = testingLibrary; + describe('useContextMenu', function () { const TestMenu: React.FC = ({ menu }) => (
- {menu.itemGroups.flatMap((group, groupIdx) => - group.items.map((item, idx) => ( + {menu.itemGroups.flatMap((items, groupIdx) => + items.map((item, idx) => (
void; + onRegister?: (ref: unknown) => void; onAction?: (id: number) => void; }) => { const contextMenu = useContextMenu(); diff --git a/packages/compass-context-menu/src/use-context-menu.tsx b/packages/compass-context-menu/src/use-context-menu.tsx index a0b874b656c..56754933c33 100644 --- a/packages/compass-context-menu/src/use-context-menu.tsx +++ b/packages/compass-context-menu/src/use-context-menu.tsx @@ -8,12 +8,12 @@ export type ContextMenuMethods = { /** * Close the context menu. */ - close: () => void; + close(): void; /** * Register the menu items for the context menu. * @returns a callback ref to be passed onto the element responsible for triggering the menu. */ - registerItems: (items: T[]) => RefCallback; + registerItems(...groups: T[][]): RefCallback; }; export function useContextMenu< @@ -34,12 +34,9 @@ export function useContextMenu< /** * @returns a callback ref, passed onto the element responsible for triggering the menu. */ - registerItems(items: ContextMenuItem[]) { + registerItems(...groups: ContextMenuItem[][]) { function listener(event: MouseEvent): void { - appendContextMenuContent(event, { - items, - originListener: listener, - }); + appendContextMenuContent(event, ...groups); } return (trigger: HTMLElement | null) => { diff --git a/packages/compass-crud/src/components/document-list-view.spec.tsx b/packages/compass-crud/src/components/document-list-view.spec.tsx index 536f48e66c2..ed257306567 100644 --- a/packages/compass-crud/src/components/document-list-view.spec.tsx +++ b/packages/compass-crud/src/components/document-list-view.spec.tsx @@ -1,28 +1,32 @@ import React from 'react'; import { mount } from 'enzyme'; +import type { ReactWrapper } from 'enzyme'; import HadronDocument from 'hadron-document'; import { expect } from 'chai'; -import sinon from 'sinon'; import DocumentListView from './document-list-view'; +import { ContextMenuProvider } from '@mongodb-js/compass-components'; describe('', function () { describe('#render', function () { context('when the documents have objects for ids', function () { const docs = [{ _id: { name: 'test-1' } }, { _id: { name: 'test-2' } }]; const hadronDocs = docs.map((doc) => new HadronDocument(doc)); - const component = mount( - - ); + let component: ReactWrapper; + beforeEach(function () { + component = mount( + , + { wrappingComponent: ContextMenuProvider } + ); + }); + + afterEach(function () { + component?.unmount(); + }); it('renders all the documents', function () { const wrapper = component.find('[data-testid="readonly-document"]');