diff --git a/.changeset/few-deers-work.md b/.changeset/few-deers-work.md new file mode 100644 index 00000000000..4f0cb60d3b5 --- /dev/null +++ b/.changeset/few-deers-work.md @@ -0,0 +1,5 @@ +--- +"@primer/react": patch +--- + +TreeView: When moving focus to TreeView, the current item will be focused by default. diff --git a/.changeset/tidy-rice-hammer.md b/.changeset/tidy-rice-hammer.md new file mode 100644 index 00000000000..254d19a2d0a --- /dev/null +++ b/.changeset/tidy-rice-hammer.md @@ -0,0 +1,5 @@ +--- +"@primer/react": patch +--- + +TabNav: Re-focusing a TabNav will focus the selected tab diff --git a/package-lock.json b/package-lock.json index d3cbb9c0ec8..37aab23844e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "@github/paste-markdown": "^1.4.0", "@github/relative-time-element": "^4.1.2", "@lit-labs/react": "1.1.1", - "@primer/behaviors": "1.3.2", + "@primer/behaviors": "1.3.3", "@primer/octicons-react": "^17.7.0", "@primer/primitives": "7.10.0", "@react-aria/ssr": "^3.1.0", @@ -3044,9 +3044,9 @@ "dev": true }, "node_modules/@github/combobox-nav": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@github/combobox-nav/-/combobox-nav-2.1.7.tgz", - "integrity": "sha512-Webx0W5iTpkk5Chy9dB/1BEUORQ0qrwui8HaaVBiy75W2VOJg96WTuKj1rXENAJ3XTMhdEF53bn0LYfvP0EKvg==" + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@github/combobox-nav/-/combobox-nav-2.1.5.tgz", + "integrity": "sha512-dmG1PuppNKHnBBEcfylWDwj9SSxd/E/qd8mC1G/klQC3s7ps5q6JZ034mwkkG0LKfI+Y+UgEua/ROD776N400w==" }, "node_modules/@github/markdown-toolbar-element": { "version": "2.1.1", @@ -6243,9 +6243,9 @@ } }, "node_modules/@primer/behaviors": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@primer/behaviors/-/behaviors-1.3.2.tgz", - "integrity": "sha512-xKXNmkuu+ydU9ygdW+IYs6M4GBaQgs181XPlUvmyqjQbhQC7n/OyrZjPNTHuyLvEV3OKWbT31BSDQbYO4yHzVg==" + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@primer/behaviors/-/behaviors-1.3.3.tgz", + "integrity": "sha512-iHMRuu8YWDJIdqCi1krx0cyFNeqszNKTOb0dXFu2wQ5BeIqxqPJLD7rjZ2Vjf/+YaPSbWuIQE1H6TaGMMsDfdA==" }, "node_modules/@primer/octicons-react": { "version": "17.7.0", @@ -31080,38 +31080,6 @@ "esbuild-windows-arm64": "0.14.39" } }, - "node_modules/esbuild-android-64": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.39.tgz", - "integrity": "sha512-EJOu04p9WgZk0UoKTqLId9VnIsotmI/Z98EXrKURGb3LPNunkeffqQIkjS2cAvidh+OK5uVrXaIP229zK6GvhQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-android-arm64": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.39.tgz", - "integrity": "sha512-+twajJqO7n3MrCz9e+2lVOnFplRsaGRwsq1KL/uOy7xK7QdRSprRQcObGDeDZUZsacD5gUkk6OiHiYp6RzU3CA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/esbuild-darwin-64": { "version": "0.14.39", "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.39.tgz", @@ -31128,182 +31096,6 @@ "node": ">=12" } }, - "node_modules/esbuild-darwin-arm64": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.39.tgz", - "integrity": "sha512-/fcQ5UhE05OiT+bW5v7/up1bDsnvaRZPJxXwzXsMRrr7rZqPa85vayrD723oWMT64dhrgWeA3FIneF8yER0XTw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-freebsd-64": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.39.tgz", - "integrity": "sha512-oMNH8lJI4wtgN5oxuFP7BQ22vgB/e3Tl5Woehcd6i2r6F3TszpCnNl8wo2d/KvyQ4zvLvCWAlRciumhQg88+kQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-freebsd-arm64": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.39.tgz", - "integrity": "sha512-1GHK7kwk57ukY2yI4ILWKJXaxfr+8HcM/r/JKCGCPziIVlL+Wi7RbJ2OzMcTKZ1HpvEqCTBT/J6cO4ZEwW4Ypg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-32": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.39.tgz", - "integrity": "sha512-g97Sbb6g4zfRLIxHgW2pc393DjnkTRMeq3N1rmjDUABxpx8SjocK4jLen+/mq55G46eE2TA0MkJ4R3SpKMu7dg==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-64": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.39.tgz", - "integrity": "sha512-4tcgFDYWdI+UbNMGlua9u1Zhu0N5R6u9tl5WOM8aVnNX143JZoBZLpCuUr5lCKhnD0SCO+5gUyMfupGrHtfggQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-arm": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.39.tgz", - "integrity": "sha512-t0Hn1kWVx5UpCzAJkKRfHeYOLyFnXwYynIkK54/h3tbMweGI7dj400D1k0Vvtj2u1P+JTRT9tx3AjtLEMmfVBQ==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-arm64": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.39.tgz", - "integrity": "sha512-23pc8MlD2D6Px1mV8GMglZlKgwgNKAO8gsgsLLcXWSs9lQsCYkIlMo/2Ycfo5JrDIbLdwgP8D2vpfH2KcBqrDQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-mips64le": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.39.tgz", - "integrity": "sha512-epwlYgVdbmkuRr5n4es3B+yDI0I2e/nxhKejT9H0OLxFAlMkeQZxSpxATpDc9m8NqRci6Kwyb/SfmD1koG2Zuw==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-ppc64le": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.39.tgz", - "integrity": "sha512-W/5ezaq+rQiQBThIjLMNjsuhPHg+ApVAdTz2LvcuesZFMsJoQAW2hutoyg47XxpWi7aEjJGrkS26qCJKhRn3QQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-riscv64": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.39.tgz", - "integrity": "sha512-IS48xeokcCTKeQIOke2O0t9t14HPvwnZcy+5baG13Z1wxs9ZrC5ig5ypEQQh4QMKxURD5TpCLHw2W42CLuVZaA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-s390x": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.39.tgz", - "integrity": "sha512-zEfunpqR8sMomqXhNTFEKDs+ik7HC01m3M60MsEjZOqaywHu5e5682fMsqOlZbesEAAaO9aAtRBsU7CHnSZWyA==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/esbuild-loader": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/esbuild-loader/-/esbuild-loader-2.19.0.tgz", @@ -31369,102 +31161,6 @@ "node": ">=10.13.0" } }, - "node_modules/esbuild-netbsd-64": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.39.tgz", - "integrity": "sha512-Uo2suJBSIlrZCe4E0k75VDIFJWfZy+bOV6ih3T4MVMRJh1lHJ2UyGoaX4bOxomYN3t+IakHPyEoln1+qJ1qYaA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-openbsd-64": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.39.tgz", - "integrity": "sha512-secQU+EpgUPpYjJe3OecoeGKVvRMLeKUxSMGHnK+aK5uQM3n1FPXNJzyz1LHFOo0WOyw+uoCxBYdM4O10oaCAA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-sunos-64": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.39.tgz", - "integrity": "sha512-qHq0t5gePEDm2nqZLb+35p/qkaXVS7oIe32R0ECh2HOdiXXkj/1uQI9IRogGqKkK+QjDG+DhwiUw7QoHur/Rwg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-32": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.39.tgz", - "integrity": "sha512-XPjwp2OgtEX0JnOlTgT6E5txbRp6Uw54Isorm3CwOtloJazeIWXuiwK0ONJBVb/CGbiCpS7iP2UahGgd2p1x+Q==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-64": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.39.tgz", - "integrity": "sha512-E2wm+5FwCcLpKsBHRw28bSYQw0Ikxb7zIMxw3OPAkiaQhLVr3dnVO8DofmbWhhf6b97bWzg37iSZ45ZDpLw7Ow==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-arm64": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.39.tgz", - "integrity": "sha512-sBZQz5D+Gd0EQ09tZRnz/PpVdLwvp/ufMtJ1iDFYddDaPpZXKqPyaxfYBLs3ueiaksQ26GGa7sci0OqFzNs7KA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -56415,9 +56111,9 @@ "dev": true }, "@github/combobox-nav": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@github/combobox-nav/-/combobox-nav-2.1.7.tgz", - "integrity": "sha512-Webx0W5iTpkk5Chy9dB/1BEUORQ0qrwui8HaaVBiy75W2VOJg96WTuKj1rXENAJ3XTMhdEF53bn0LYfvP0EKvg==" + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@github/combobox-nav/-/combobox-nav-2.1.5.tgz", + "integrity": "sha512-dmG1PuppNKHnBBEcfylWDwj9SSxd/E/qd8mC1G/klQC3s7ps5q6JZ034mwkkG0LKfI+Y+UgEua/ROD776N400w==" }, "@github/markdown-toolbar-element": { "version": "2.1.1", @@ -58905,9 +58601,9 @@ } }, "@primer/behaviors": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@primer/behaviors/-/behaviors-1.3.2.tgz", - "integrity": "sha512-xKXNmkuu+ydU9ygdW+IYs6M4GBaQgs181XPlUvmyqjQbhQC7n/OyrZjPNTHuyLvEV3OKWbT31BSDQbYO4yHzVg==" + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@primer/behaviors/-/behaviors-1.3.3.tgz", + "integrity": "sha512-iHMRuu8YWDJIdqCi1krx0cyFNeqszNKTOb0dXFu2wQ5BeIqxqPJLD7rjZ2Vjf/+YaPSbWuIQE1H6TaGMMsDfdA==" }, "@primer/octicons-react": { "version": "17.7.0", @@ -77684,20 +77380,6 @@ "esbuild-windows-arm64": "0.14.39" } }, - "esbuild-android-64": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.39.tgz", - "integrity": "sha512-EJOu04p9WgZk0UoKTqLId9VnIsotmI/Z98EXrKURGb3LPNunkeffqQIkjS2cAvidh+OK5uVrXaIP229zK6GvhQ==", - "dev": true, - "optional": true - }, - "esbuild-android-arm64": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.39.tgz", - "integrity": "sha512-+twajJqO7n3MrCz9e+2lVOnFplRsaGRwsq1KL/uOy7xK7QdRSprRQcObGDeDZUZsacD5gUkk6OiHiYp6RzU3CA==", - "dev": true, - "optional": true - }, "esbuild-darwin-64": { "version": "0.14.39", "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.39.tgz", @@ -77705,83 +77387,6 @@ "dev": true, "optional": true }, - "esbuild-darwin-arm64": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.39.tgz", - "integrity": "sha512-/fcQ5UhE05OiT+bW5v7/up1bDsnvaRZPJxXwzXsMRrr7rZqPa85vayrD723oWMT64dhrgWeA3FIneF8yER0XTw==", - "dev": true, - "optional": true - }, - "esbuild-freebsd-64": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.39.tgz", - "integrity": "sha512-oMNH8lJI4wtgN5oxuFP7BQ22vgB/e3Tl5Woehcd6i2r6F3TszpCnNl8wo2d/KvyQ4zvLvCWAlRciumhQg88+kQ==", - "dev": true, - "optional": true - }, - "esbuild-freebsd-arm64": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.39.tgz", - "integrity": "sha512-1GHK7kwk57ukY2yI4ILWKJXaxfr+8HcM/r/JKCGCPziIVlL+Wi7RbJ2OzMcTKZ1HpvEqCTBT/J6cO4ZEwW4Ypg==", - "dev": true, - "optional": true - }, - "esbuild-linux-32": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.39.tgz", - "integrity": "sha512-g97Sbb6g4zfRLIxHgW2pc393DjnkTRMeq3N1rmjDUABxpx8SjocK4jLen+/mq55G46eE2TA0MkJ4R3SpKMu7dg==", - "dev": true, - "optional": true - }, - "esbuild-linux-64": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.39.tgz", - "integrity": "sha512-4tcgFDYWdI+UbNMGlua9u1Zhu0N5R6u9tl5WOM8aVnNX143JZoBZLpCuUr5lCKhnD0SCO+5gUyMfupGrHtfggQ==", - "dev": true, - "optional": true - }, - "esbuild-linux-arm": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.39.tgz", - "integrity": "sha512-t0Hn1kWVx5UpCzAJkKRfHeYOLyFnXwYynIkK54/h3tbMweGI7dj400D1k0Vvtj2u1P+JTRT9tx3AjtLEMmfVBQ==", - "dev": true, - "optional": true - }, - "esbuild-linux-arm64": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.39.tgz", - "integrity": "sha512-23pc8MlD2D6Px1mV8GMglZlKgwgNKAO8gsgsLLcXWSs9lQsCYkIlMo/2Ycfo5JrDIbLdwgP8D2vpfH2KcBqrDQ==", - "dev": true, - "optional": true - }, - "esbuild-linux-mips64le": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.39.tgz", - "integrity": "sha512-epwlYgVdbmkuRr5n4es3B+yDI0I2e/nxhKejT9H0OLxFAlMkeQZxSpxATpDc9m8NqRci6Kwyb/SfmD1koG2Zuw==", - "dev": true, - "optional": true - }, - "esbuild-linux-ppc64le": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.39.tgz", - "integrity": "sha512-W/5ezaq+rQiQBThIjLMNjsuhPHg+ApVAdTz2LvcuesZFMsJoQAW2hutoyg47XxpWi7aEjJGrkS26qCJKhRn3QQ==", - "dev": true, - "optional": true - }, - "esbuild-linux-riscv64": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.39.tgz", - "integrity": "sha512-IS48xeokcCTKeQIOke2O0t9t14HPvwnZcy+5baG13Z1wxs9ZrC5ig5ypEQQh4QMKxURD5TpCLHw2W42CLuVZaA==", - "dev": true, - "optional": true - }, - "esbuild-linux-s390x": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.39.tgz", - "integrity": "sha512-zEfunpqR8sMomqXhNTFEKDs+ik7HC01m3M60MsEjZOqaywHu5e5682fMsqOlZbesEAAaO9aAtRBsU7CHnSZWyA==", - "dev": true, - "optional": true - }, "esbuild-loader": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/esbuild-loader/-/esbuild-loader-2.19.0.tgz", @@ -77831,48 +77436,6 @@ } } }, - "esbuild-netbsd-64": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.39.tgz", - "integrity": "sha512-Uo2suJBSIlrZCe4E0k75VDIFJWfZy+bOV6ih3T4MVMRJh1lHJ2UyGoaX4bOxomYN3t+IakHPyEoln1+qJ1qYaA==", - "dev": true, - "optional": true - }, - "esbuild-openbsd-64": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.39.tgz", - "integrity": "sha512-secQU+EpgUPpYjJe3OecoeGKVvRMLeKUxSMGHnK+aK5uQM3n1FPXNJzyz1LHFOo0WOyw+uoCxBYdM4O10oaCAA==", - "dev": true, - "optional": true - }, - "esbuild-sunos-64": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.39.tgz", - "integrity": "sha512-qHq0t5gePEDm2nqZLb+35p/qkaXVS7oIe32R0ECh2HOdiXXkj/1uQI9IRogGqKkK+QjDG+DhwiUw7QoHur/Rwg==", - "dev": true, - "optional": true - }, - "esbuild-windows-32": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.39.tgz", - "integrity": "sha512-XPjwp2OgtEX0JnOlTgT6E5txbRp6Uw54Isorm3CwOtloJazeIWXuiwK0ONJBVb/CGbiCpS7iP2UahGgd2p1x+Q==", - "dev": true, - "optional": true - }, - "esbuild-windows-64": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.39.tgz", - "integrity": "sha512-E2wm+5FwCcLpKsBHRw28bSYQw0Ikxb7zIMxw3OPAkiaQhLVr3dnVO8DofmbWhhf6b97bWzg37iSZ45ZDpLw7Ow==", - "dev": true, - "optional": true - }, - "esbuild-windows-arm64": { - "version": "0.14.39", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.39.tgz", - "integrity": "sha512-sBZQz5D+Gd0EQ09tZRnz/PpVdLwvp/ufMtJ1iDFYddDaPpZXKqPyaxfYBLs3ueiaksQ26GGa7sci0OqFzNs7KA==", - "dev": true, - "optional": true - }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", diff --git a/package.json b/package.json index 059fd7b3ec9..aa4e6cd8cb6 100644 --- a/package.json +++ b/package.json @@ -92,7 +92,7 @@ "@github/paste-markdown": "^1.4.0", "@github/relative-time-element": "^4.1.2", "@lit-labs/react": "1.1.1", - "@primer/behaviors": "1.3.2", + "@primer/behaviors": "1.3.3", "@primer/octicons-react": "^17.7.0", "@primer/primitives": "7.10.0", "@react-aria/ssr": "^3.1.0", diff --git a/src/TabNav/TabNav.tsx b/src/TabNav/TabNav.tsx index 17c7646bc82..b0fa7373da1 100644 --- a/src/TabNav/TabNav.tsx +++ b/src/TabNav/TabNav.tsx @@ -31,34 +31,40 @@ export type TabNavProps = ComponentProps function TabNav({children, 'aria-label': ariaLabel, ...rest}: TabNavProps) { const customContainerRef = useRef(null) - // TODO: revert tracking when `initialFocus` is set. This is a fix when TabNav - // is nested within another focus zone. This flag is used to indicate when - // focus has been initially set, this is useful for including the - // `aria-selected="true"` tab as the first interactive item. - // - // When set to `true`, this changes the behavior in `useFocusZone` to use - // the `'previous'` strategy which allows the tab to participate in nested - // focus zones without conflict - const [initialFocus, setInitialFocus] = useState(false) - const customStrategy = React.useCallback(() => { + + // Detect if the TabNav is inside an ActionMenu. + const [isInsideMenu, setIsInsideMenu] = useState(false) + React.useEffect(() => { if (customContainerRef.current) { - const tabs = Array.from( - customContainerRef.current.querySelectorAll('[role=tab][aria-selected=true]'), - ) - setInitialFocus(true) - return tabs[0] + const menu = customContainerRef.current.closest('[role=menu]') + if (menu) { + setIsInsideMenu(true) + } } }, [customContainerRef]) + + const customStrategy = React.useCallback(() => { + const selectedTab = customContainerRef.current?.querySelector('[role=tab][aria-selected=true]') + const firstTab = customContainerRef.current?.querySelector('[role=tab]') + return selectedTab ?? firstTab ?? undefined + }, [customContainerRef]) + const {containerRef: navRef} = useFocusZone( { containerRef: customContainerRef, bindKeys: FocusKeys.ArrowHorizontal | FocusKeys.HomeAndEnd, focusOutBehavior: 'wrap', - focusInStrategy: initialFocus ? 'previous' : customStrategy, + // Use 'previous' strategy when inside an ActionMenu to avoid + // conflicting with the ActionMenu's focus zone. + // + // WARNING: We don't recommend using TabNav inside an ActionMenu. + // This is a workaround to avoid breaking existing code. + focusInStrategy: isInsideMenu ? 'previous' : customStrategy, focusableElementFilter: element => element.getAttribute('role') === 'tab', }, - [initialFocus], + [isInsideMenu], ) + return ( }> diff --git a/src/TreeView/TreeView.features.stories.tsx b/src/TreeView/TreeView.features.stories.tsx index bf19cdd7b0f..4f037bc508a 100644 --- a/src/TreeView/TreeView.features.stories.tsx +++ b/src/TreeView/TreeView.features.stories.tsx @@ -773,6 +773,20 @@ export const ContainIntrinsicSize: Story = () => { ) } +export const InitialFocus: Story = () => ( +
+ + + Item 1 + + Item 2 + + Item 3 + + +
+) + ContainIntrinsicSize.parameters = { chromatic: {disableSnapshot: true}, } diff --git a/src/TreeView/TreeView.test.tsx b/src/TreeView/TreeView.test.tsx index ca45a641491..8f14689e586 100644 --- a/src/TreeView/TreeView.test.tsx +++ b/src/TreeView/TreeView.test.tsx @@ -219,6 +219,34 @@ describe('Markup', () => { const parentItem = getByLabelText(/Parent/) expect(parentItem).toBeInTheDocument() }) + + it('should move focus to current treeitem by default', async () => { + const user = userEvent.setup({delay: null}) + const {getByRole} = renderWithTheme( +
+ + + Item 1 + + Item 2 + + Item 3 + +
, + ) + + // Focus button + const button = getByRole('button', {name: /Focusable element/}) + await user.click(button) + expect(button).toHaveFocus() + + // Move focus to tree + await user.tab() + + // Focus should be on current treeitem + const item2 = getByRole('treeitem', {name: /Item 2/}) + expect(item2).toHaveFocus() + }) }) describe('Keyboard interactions', () => { diff --git a/src/TreeView/useRovingTabIndex.ts b/src/TreeView/useRovingTabIndex.ts index ac1998a3b4c..6959e037b41 100644 --- a/src/TreeView/useRovingTabIndex.ts +++ b/src/TreeView/useRovingTabIndex.ts @@ -18,6 +18,23 @@ export function useRovingTabIndex({containerRef}: {containerRef: React.RefObject return getNextFocusableElement(from, event) ?? from }, + focusInStrategy: () => { + const currentItem = containerRef.current?.querySelector('[aria-current]') + const firstItem = containerRef.current?.querySelector('[role="treeitem"]') + + // Focus the aria-current item if it exists + if (currentItem instanceof HTMLElement) { + return currentItem + } + + // Otherwise, focus the activeElement if it's a treeitem + if (document.activeElement instanceof HTMLElement && containerRef.current?.contains(document.activeElement)) { + return document.activeElement + } + + // Otherwise, focus the first treeitem + return firstItem instanceof HTMLElement ? firstItem : undefined + }, }) }