summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHiDeoo2024-09-19 20:55:48 +0200
committerGitHub2024-09-19 20:55:48 +0200
commita257b83f1e5704ff41bcbe85482ac81a1a61ce1f (patch)
treebe1ba93533d4716b6c8d809b6ab7b2ebba0649b2
parentb02b935513819cd8634e3f656831ff184e713e91 (diff)
downloadIT.starlight-a257b83f1e5704ff41bcbe85482ac81a1a61ce1f.tar.gz
IT.starlight-a257b83f1e5704ff41bcbe85482ac81a1a61ce1f.tar.bz2
IT.starlight-a257b83f1e5704ff41bcbe85482ac81a1a61ce1f.zip
Fix synced nested `<Tabs>` restoration issue (#2377)
-rw-r--r--.changeset/beige-knives-visit.md5
-rw-r--r--packages/starlight/__e2e__/fixtures/basics/src/content/docs/tabs-nested.mdx47
-rw-r--r--packages/starlight/__e2e__/tabs.test.ts40
-rw-r--r--packages/starlight/user-components/Tabs.astro2
4 files changed, 90 insertions, 4 deletions
diff --git a/.changeset/beige-knives-visit.md b/.changeset/beige-knives-visit.md
new file mode 100644
index 00000000..443bbf07
--- /dev/null
+++ b/.changeset/beige-knives-visit.md
@@ -0,0 +1,5 @@
+---
+'@astrojs/starlight': patch
+---
+
+Fixes an issue with synced `<Tabs>` components containing nested `<Tabs>` causing tab panels to not render correctly.
diff --git a/packages/starlight/__e2e__/fixtures/basics/src/content/docs/tabs-nested.mdx b/packages/starlight/__e2e__/fixtures/basics/src/content/docs/tabs-nested.mdx
new file mode 100644
index 00000000..1be29663
--- /dev/null
+++ b/packages/starlight/__e2e__/fixtures/basics/src/content/docs/tabs-nested.mdx
@@ -0,0 +1,47 @@
+---
+title: Tabs
+---
+
+import { Tabs, TabItem } from '@astrojs/starlight/components';
+
+A set of tabs using the `pkg` sync key with some nested tabs using an `os` sync key.
+
+<Tabs syncKey="pkg">
+
+ <TabItem label="npm">
+
+ npm content
+
+ <Tabs syncKey="os">
+ <TabItem label="macos">npm macOS</TabItem>
+ <TabItem label="windows">npm Windows</TabItem>
+ <TabItem label="linux">npm GNU/Linux</TabItem>
+ </Tabs>
+
+ </TabItem>
+
+ <TabItem label="pnpm">
+
+ pnpm content
+
+ <Tabs syncKey="os">
+ <TabItem label="macos">pnpm macOS</TabItem>
+ <TabItem label="windows">pnpm Windows</TabItem>
+ <TabItem label="linux">pnpm GNU/Linux</TabItem>
+ </Tabs>
+
+ </TabItem>
+
+ <TabItem label="yarn">
+
+ yarn content
+
+ <Tabs syncKey="os">
+ <TabItem label="macos">yarn macOS</TabItem>
+ <TabItem label="windows">yarn Windows</TabItem>
+ <TabItem label="linux">yarn GNU/Linux</TabItem>
+ </Tabs>
+
+ </TabItem>
+
+</Tabs>
diff --git a/packages/starlight/__e2e__/tabs.test.ts b/packages/starlight/__e2e__/tabs.test.ts
index 45e96c84..2812494f 100644
--- a/packages/starlight/__e2e__/tabs.test.ts
+++ b/packages/starlight/__e2e__/tabs.test.ts
@@ -312,7 +312,41 @@ test('gracefully handles invalid persisted state for synced tabs', async ({
);
});
-async function expectSelectedTab(tabs: Locator, label: string, panel: string) {
- expect((await tabs.getByRole('tab', { selected: true }).textContent())?.trim()).toBe(label);
- expect((await tabs.getByRole('tabpanel').textContent())?.trim()).toBe(panel);
+test('syncs and restores nested tabs', async ({ page, getProdServer }) => {
+ const starlight = await getProdServer();
+ await starlight.goto('/tabs-nested');
+
+ const tabs = page.locator('starlight-tabs');
+ const pkgTabs = tabs.nth(0);
+ const osTabsA = tabs.nth(1);
+ const osTabsB = tabs.nth(2);
+
+ // Select the linux tab in the npm tab.
+ await osTabsA.getByRole('tab').filter({ hasText: 'linux' }).click();
+
+ await expectSelectedTab(osTabsA, 'linux', 'npm GNU/Linux');
+
+ // Select the pnpm tab.
+ await pkgTabs.getByRole('tab').filter({ hasText: 'pnpm' }).click();
+
+ await expectSelectedTab(pkgTabs, 'pnpm');
+ await expectSelectedTab(osTabsB, 'linux', 'pnpm GNU/Linux');
+
+ page.reload();
+
+ // The synced tabs should be restored.
+ await expectSelectedTab(pkgTabs, 'pnpm');
+ await expectSelectedTab(osTabsB, 'linux', 'pnpm GNU/Linux');
+});
+
+async function expectSelectedTab(tabs: Locator, label: string, panel?: string) {
+ expect(
+ (await tabs.locator(':scope > div [role=tab][aria-selected=true]').textContent())?.trim()
+ ).toBe(label);
+
+ if (panel) {
+ const tabPanel = tabs.locator(':scope > [role=tabpanel]:not([hidden])');
+ await expect(tabPanel).toBeVisible();
+ expect((await tabPanel.textContent())?.trim()).toBe(panel);
+ }
}
diff --git a/packages/starlight/user-components/Tabs.astro b/packages/starlight/user-components/Tabs.astro
index f3108806..4234eb01 100644
--- a/packages/starlight/user-components/Tabs.astro
+++ b/packages/starlight/user-components/Tabs.astro
@@ -54,7 +54,7 @@ if (isSynced) {
const tabIndexToRestore = tabs.findIndex(
(tab) => tab instanceof HTMLAnchorElement && tab.textContent?.trim() === label
);
- const panels = starlightTabs?.querySelectorAll('[role="tabpanel"]');
+ const panels = starlightTabs?.querySelectorAll(':scope > [role="tabpanel"]');
const newTab = tabs[tabIndexToRestore];
const newPanel = panels[tabIndexToRestore];
if (tabIndexToRestore < 1 || !newTab || !newPanel) return;