diff --git a/app/components/ConnectorModal.vue b/app/components/ConnectorModal.vue
index 7807110c22..22add06365 100644
--- a/app/components/ConnectorModal.vue
+++ b/app/components/ConnectorModal.vue
@@ -125,21 +125,25 @@ watch(open, isOpen => {
>
$
{{ executeNpmxConnectorCommand }}
-
+
{{ $t('connector.modal.paste_token') }}
diff --git a/app/components/PackageManagerSelect.vue b/app/components/PackageManagerSelect.vue
new file mode 100644
index 0000000000..8a9bc4df7f
--- /dev/null
+++ b/app/components/PackageManagerSelect.vue
@@ -0,0 +1,192 @@
+
+
+
+
+
+
+
+
+
+ -
+
+ {{ pm.label }}
+
+
+
+
+
+
+
+
diff --git a/app/components/PackageManagerTabs.vue b/app/components/PackageManagerTabs.vue
deleted file mode 100644
index 57812bec0e..0000000000
--- a/app/components/PackageManagerTabs.vue
+++ /dev/null
@@ -1,97 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/app/pages/[...package].vue b/app/pages/[...package].vue
index 0be1584031..7c1d95f4cb 100644
--- a/app/pages/[...package].vue
+++ b/app/pages/[...package].vue
@@ -798,8 +798,8 @@ function handleClick(event: MouseEvent) {
{{ $t('package.run.title') }}
-
-
+
+
-
-
+
+
{
describe('DateTime', () => {
@@ -1293,4 +1294,12 @@ describe('component accessibility audits', () => {
expect(results.violations).toEqual([])
})
})
+
+ describe('PackageManagerSelect', () => {
+ it('should have no accessibility violations', async () => {
+ const component = await mountSuspended(PackageManagerSelect)
+ const results = await runAxe(component)
+ expect(results.violations).toEqual([])
+ })
+ })
})
diff --git a/tests/package-manager-select.spec.ts b/tests/package-manager-select.spec.ts
new file mode 100644
index 0000000000..e26d61eb75
--- /dev/null
+++ b/tests/package-manager-select.spec.ts
@@ -0,0 +1,33 @@
+import { expect, test } from '@nuxt/test-utils/playwright'
+
+test.describe('Package Page', () => {
+ test('/vue → package manager select dropdown works', async ({ page, goto }) => {
+ await goto('/vue', { waitUntil: 'domcontentloaded' })
+
+ const packageManagerButton = page.locator('button[aria-haspopup="listbox"]').first()
+ await expect(packageManagerButton).toBeVisible()
+
+ // Open dropdown
+ await packageManagerButton.click()
+ const packageManagerDropdown = page.locator('[role="listbox"]')
+ await expect(packageManagerDropdown).toBeVisible()
+
+ // Arrow keys navigate the listbox
+ await packageManagerButton.press('ArrowDown')
+ const firstDescendant = await packageManagerDropdown.getAttribute('aria-activedescendant')
+ await packageManagerButton.press('ArrowDown')
+ const secondDescendant = await packageManagerDropdown.getAttribute('aria-activedescendant')
+ expect(secondDescendant).not.toBe(firstDescendant)
+
+ // Escape closes dropdown and returns focus
+ await packageManagerButton.press('Escape')
+ await expect(packageManagerDropdown).not.toBeVisible()
+ await expect(packageManagerButton).toBeFocused()
+
+ // Enter selects option and closes dropdown
+ await packageManagerButton.click()
+ await packageManagerButton.press('ArrowDown')
+ await packageManagerButton.press('Enter')
+ await expect(packageManagerDropdown).not.toBeVisible()
+ })
+})
diff --git a/tests/package-manager-tabs.spec.ts b/tests/package-manager-tabs.spec.ts
deleted file mode 100644
index ab25880bc6..0000000000
--- a/tests/package-manager-tabs.spec.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import { expect, test } from '@nuxt/test-utils/playwright'
-
-test.describe('Package Page', () => {
- test('/vue → package manager tabs use roving tabindex', async ({ page, goto }) => {
- await goto('/vue', { waitUntil: 'domcontentloaded' })
-
- const tablist = page.locator('[role="tablist"]').first()
- await expect(tablist).toBeVisible()
-
- const tabs = tablist.locator('[role="tab"]')
- const tabCount = await tabs.count()
- expect(tabCount).toBeGreaterThan(1)
-
- const firstTab = tabs.first()
- await firstTab.focus()
- await expect(firstTab).toBeFocused()
-
- await page.keyboard.press('ArrowRight')
-
- const secondTab = tabs.nth(1)
- await expect(secondTab).toBeFocused()
- await expect(secondTab).toHaveAttribute('aria-selected', 'true')
- await expect(secondTab).toHaveAttribute('tabindex', '0')
- await expect(firstTab).toHaveAttribute('tabindex', '-1')
-
- const tabpanel = page.locator('[role="tabpanel"]').first()
- const controls = await secondTab.getAttribute('aria-controls')
- const panelId = await tabpanel.getAttribute('id')
- expect(controls).toBe(panelId)
-
- const labelledBy = await tabpanel.getAttribute('aria-labelledby')
- const tabId = await secondTab.getAttribute('id')
- expect(labelledBy).toBe(tabId)
- })
-})