@astrojs/starlight 0.26.0 → 0.26.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/components/Hero.astro +8 -6
- package/components/Icons.ts +3 -0
- package/components/SidebarPersistState.ts +5 -3
- package/package.json +1 -1
- package/schemas/social.ts +2 -0
- package/utils/i18n.ts +3 -0
- package/__e2e__/collection-config.test.ts +0 -14
- package/__e2e__/fixtures/basics/astro.config.mjs +0 -11
- package/__e2e__/fixtures/basics/node_modules/.bin/astro +0 -17
- package/__e2e__/fixtures/basics/package.json +0 -9
- package/__e2e__/fixtures/basics/src/content/config.ts +0 -6
- package/__e2e__/fixtures/basics/src/content/docs/tabs-unsynced.mdx +0 -21
- package/__e2e__/fixtures/basics/src/content/docs/tabs-variable-height.mdx +0 -151
- package/__e2e__/fixtures/basics/src/content/docs/tabs.mdx +0 -70
- package/__e2e__/fixtures/basics/src/env.d.ts +0 -2
- package/__e2e__/fixtures/custom src-dir/astro.config.mjs +0 -12
- package/__e2e__/fixtures/custom src-dir/node_modules/.bin/astro +0 -17
- package/__e2e__/fixtures/custom src-dir/package.json +0 -9
- package/__e2e__/fixtures/custom src-dir/www/content/config.ts +0 -6
- package/__e2e__/fixtures/custom src-dir/www/env.d.ts +0 -2
- package/__e2e__/fixtures/custom src-dir/www/pages/custom.astro +0 -7
- package/__e2e__/tabs.test.ts +0 -299
- package/__e2e__/test-utils.ts +0 -56
- package/playwright.config.ts +0 -17
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @astrojs/starlight
|
|
2
2
|
|
|
3
|
+
## 0.26.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#2273](https://github.com/withastro/starlight/pull/2273) [`746e0cd`](https://github.com/withastro/starlight/commit/746e0cd301f4ac4a182e8c45b36865c61d208b77) Thanks [@delucis](https://github.com/delucis)! - Fixes type error when using Starlight with Astro v4.15
|
|
8
|
+
|
|
9
|
+
- [#2265](https://github.com/withastro/starlight/pull/2265) [`25b661e`](https://github.com/withastro/starlight/commit/25b661e238cdc6c08ef79504fa5507d879c0f62d) Thanks [@SeraphicRav](https://github.com/SeraphicRav)! - Adds TikTok social icon
|
|
10
|
+
|
|
11
|
+
- [#2272](https://github.com/withastro/starlight/pull/2272) [`d1969dd`](https://github.com/withastro/starlight/commit/d1969dde2ea8ece6ce9d439eae12d9c63c2201d7) Thanks [@o-az](https://github.com/o-az)! - Adds new icon: `jsr`
|
|
12
|
+
|
|
13
|
+
- [#2250](https://github.com/withastro/starlight/pull/2250) [`c0a6166`](https://github.com/withastro/starlight/commit/c0a6166bb280e2d70060b68cdf6ee166812c82d2) Thanks [@HiDeoo](https://github.com/HiDeoo)! - Removes internal E2E tests from the package published to the npm registry.
|
|
14
|
+
|
|
15
|
+
- [#2253](https://github.com/withastro/starlight/pull/2253) [`72bc76a`](https://github.com/withastro/starlight/commit/72bc76a28f5c1b050d8125d80c6146526b699600) Thanks [@HiDeoo](https://github.com/HiDeoo)! - Fixes an issue preventing to use the `class` attribute in hero action link buttons.
|
|
16
|
+
|
|
17
|
+
## 0.26.1
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- [#2219](https://github.com/withastro/starlight/pull/2219) [`74d4716`](https://github.com/withastro/starlight/commit/74d4716f6a70fbef486e1057b81d2280c40251df) Thanks [@HiDeoo](https://github.com/HiDeoo)! - Fixes a sidebar persistence issue when navigating between pages with different sidebar content.
|
|
22
|
+
|
|
3
23
|
## 0.26.0
|
|
4
24
|
|
|
5
25
|
### Minor Changes
|
package/components/Hero.astro
CHANGED
|
@@ -50,12 +50,14 @@ if (image) {
|
|
|
50
50
|
{
|
|
51
51
|
actions.length > 0 && (
|
|
52
52
|
<div class="sl-flex actions">
|
|
53
|
-
{actions.map(
|
|
54
|
-
|
|
55
|
-
{
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
53
|
+
{actions.map(
|
|
54
|
+
({ attrs: { class: className, ...attrs } = {}, icon, link: href, text, variant }) => (
|
|
55
|
+
<LinkButton {href} {variant} icon={icon?.name} class:list={[className]} {...attrs}>
|
|
56
|
+
{text}
|
|
57
|
+
{icon?.html && <Fragment set:html={icon.html} />}
|
|
58
|
+
</LinkButton>
|
|
59
|
+
)
|
|
60
|
+
)}
|
|
59
61
|
</div>
|
|
60
62
|
)
|
|
61
63
|
}
|
package/components/Icons.ts
CHANGED
|
@@ -130,6 +130,8 @@ export const BuiltInIcons = {
|
|
|
130
130
|
'<path d="M21 19c0 1.7-1.2 3-2.7 3H5.7C4.2 22 3 20.7 3 19a3 3 0 0 1 1.2-2.4l6.7-6c0-.1.3 0 .2.2l-2.5 5s0 .2.2.2h9.5c1.5 0 2.7 1.4 2.7 3Zm0-14a3 3 0 0 1-1.2 2.4l-6.7 6c0 .1-.2 0-.2-.2l2.5-5s0-.2-.2-.2H5.7C4.2 8 3 6.6 3 5c0-1.7 1.2-3 2.7-3h12.6C19.8 2 21 3.3 21 5Z"/>',
|
|
131
131
|
pinterest:
|
|
132
132
|
'<path d="M12 0a12 12 0 0 0-4.4 23.1c0-.9-.2-2.4 0-3.4l1.5-6s-.4-.7-.4-1.7c0-1.7 1-3 2.2-3 1 0 1.5.8 1.5 1.7 0 1-.6 2.6-1 4-.3 1.2.6 2.2 1.8 2.2 2.1 0 3.8-2.2 3.8-5.5 0-2.8-2-4.9-5-4.9a5.2 5.2 0 0 0-5.4 5.2c0 1 .3 2.2.8 2.8.1.1.2.2.1.3l-.3 1.4c0 .2-.2.3-.4.2-1.5-.7-2.4-3-2.4-4.7C4.4 8 7 4.5 12.3 4.5c4.1 0 7.4 3 7.4 6.9 0 4.1-2.6 7.4-6.3 7.4-1.2 0-2.3-.6-2.7-1.3l-.8 2.8c-.2 1-1 2.4-1.5 3.2A12 12 0 1 0 12 0z"/>',
|
|
133
|
+
tiktok:
|
|
134
|
+
'<path d="M12.525.02c1.31-.02 2.61-.01 3.91-.02.08 1.53.63 3.09 1.75 4.17 1.12 1.11 2.7 1.62 4.24 1.79v4.03c-1.44-.05-2.89-.35-4.2-.97-.57-.26-1.1-.59-1.62-.93-.01 2.92.01 5.84-.02 8.75-.08 1.4-.54 2.79-1.35 3.94-1.31 1.92-3.58 3.17-5.91 3.21-1.43.08-2.86-.31-4.08-1.03-2.02-1.19-3.44-3.37-3.65-5.71-.02-.5-.03-1-.01-1.49.18-1.9 1.12-3.72 2.58-4.96 1.66-1.44 3.98-2.13 6.15-1.72.02 1.48-.04 2.96-.04 4.44-.99-.32-2.15-.23-3.02.37-.63.41-1.11 1.04-1.36 1.75-.21.51-.15 1.07-.14 1.61.24 1.64 1.82 3.02 3.5 2.87 1.12-.01 2.19-.66 2.77-1.61.19-.33.4-.67.41-1.06.1-1.79.06-3.57.07-5.36.01-4.03-.01-8.05.02-12.07z"/>',
|
|
133
135
|
astro:
|
|
134
136
|
'<path d="M7.233 15.856c-.456 1.5-.132 3.586.948 4.57v-.036l.036-.096c.132-.636.648-1.032 1.309-1.008.612.012.96.336 1.044 1.044.036.264.036.528.048.803v.084c0 .6.168 1.176.504 1.68.3.48.72.851 1.284 1.103l-.024-.048-.024-.096c-.42-1.26-.12-2.135.984-2.879l.336-.227.745-.492a3.647 3.647 0 0 0 1.536-2.603c.06-.456 0-.9-.132-1.331l-.18.12c-1.668.887-3.577 1.2-5.425.84-1.117-.169-2.197-.48-3-1.416l.011-.012ZM2 15.592s3.205-1.559 6.421-1.559l2.437-7.508c.084-.36.348-.6.648-.6.3 0 .552.24.648.612l2.425 7.496c3.816 0 6.421 1.56 6.421 1.56L15.539.72c-.144-.444-.42-.72-.768-.72H8.24c-.348 0-.6.276-.768.72L2 15.592Z"/>',
|
|
135
137
|
alpine: '<path d="m18.7 6 5.3 5.3-5.3 5.3-5.4-5.3L18.7 6zM5.3 6l11 11H5.8L0 11.2 5.3 6z"/>',
|
|
@@ -155,6 +157,7 @@ export const BuiltInIcons = {
|
|
|
155
157
|
netlify:
|
|
156
158
|
'<path d="M6.49 19.04h-.23L5.13 17.9v-.23l1.73-1.71h1.2l.15.15v1.2L6.5 19.04ZM5.13 6.31V6.1l1.13-1.13h.23L8.2 6.68v1.2l-.15.15h-1.2zm9.96 9.09h-1.65l-.14-.13v-3.83c0-.68-.27-1.2-1.1-1.23c-.42 0-.9 0-1.43.02l-.07.08v4.96l-.14.14H8.9l-.13-.14V8.73l.13-.14h3.7a2.6 2.6 0 0 1 2.61 2.6v4.08l-.13.14Zm-8.37-2.44H.14L0 12.82v-1.64l.14-.14h6.58l.14.14v1.64zm17.14 0h-6.58l-.14-.14v-1.64l.14-.14h6.58l.14.14v1.64zM11.05 6.55V1.64l.14-.14h1.65l.14.14v4.9l-.14.14h-1.65zm0 15.81v-4.9l.14-.14h1.65l.14.13v4.91l-.14.14h-1.65z"/>',
|
|
157
159
|
deno: '<path d="M12 0a12 12 0 1 1 0 24 12 12 0 0 1 0-24m-.47 6.8c-3.49 0-6.2 2.19-6.2 4.92 0 2.58 2.5 4.23 6.37 4.15h.12l.42-.02-.1.28v.03l.09.22v.03l.02.04.02.07.02.04.01.05.02.05.02.07.02.08.02.06.02.08.02.09.02.09.03.1.01.06.03.1.02.1.03.15.02.07.02.11.03.12.02.12.04.17.02.15.04.2.02.1.03.15.03.15.04.22.04.23.04.23.04.24.04.24.04.26.04.26.04.2.05.34.02.14.06.36.04.3.04.22.04.31.03.16a10.76 10.76 0 0 0 6.53-3.41l.05-.06-.24-.89-.64-2.37-.39-1.47-.35-1.3-.21-.78-.14-.5-.08-.3-.07-.26-.03-.11-.02-.07-.01-.03v-.03a6.04 6.04 0 0 0-2.05-2.97 6.75 6.75 0 0 0-4.25-1.35M8.47 19.3a.59.59 0 0 0-.72.4v.01l-.53 1.96q.5.24 1.01.43l.08.03.57-2.11V20a.59.59 0 0 0-.41-.7m3.26-1.43a.59.59 0 0 0-.71.4v.01l-.8 2.96v.01a.59.59 0 0 0 1.12.3l.8-2.96v-.02l.02-.06v-.02l-.02-.1-.02-.14-.02-.08a.58.58 0 0 0-.37-.3Zm-5.55-3.04a1 1 0 0 0-.04.09v.02l-.8 2.95v.02a.59.59 0 0 0 1.13.3v-.01l.72-2.68a5.3 5.3 0 0 1-1.01-.7Zm-1.9-3.4a.59.59 0 0 0-.72.4v.02l-.8 2.95v.01a.59.59 0 0 0 1.13.3l.8-2.96v-.01a.59.59 0 0 0-.41-.7m17.87-.68a.59.59 0 0 0-.72.4v.02l-.8 2.95v.01a.59.59 0 0 0 1.13.3l.8-2.96v-.01a.59.59 0 0 0-.41-.7M2.55 6.81a10.7 10.7 0 0 0-1.26 3.93.59.59 0 0 0 1-.22v-.02l.8-2.95v-.01a.59.59 0 0 0-.55-.73m17.59.02a.59.59 0 0 0-.72.4v.01l-.8 2.96v.01a.59.59 0 0 0 1.13.3l.8-2.96v-.01a.59.59 0 0 0-.41-.7Zm-7.85 1.93a.75.75 0 1 1 0 1.5.75.75 0 0 1 0-1.5M6.01 4.03a.59.59 0 0 0-.71.4v.02L4.5 7.4v.01a.59.59 0 0 0 1.12.3l.8-2.96v-.01a.59.59 0 0 0-.41-.7Zm10.24.56a.59.59 0 0 0-.71.4V5L15 7q.52.26.99.6l.05.04.62-2.32V5.3a.59.59 0 0 0-.41-.7m-5.21-3.34a11 11 0 0 0-1.12.16l-.07.01L9.1 4.2v.01a.59.59 0 0 0 1.13.3l.8-2.96v-.01a.6.6 0 0 0 0-.27m7.34 2.04-.16.58v.02a.59.59 0 0 0 1.13.3V4.2l.02-.07a11 11 0 0 0-.92-.77zm-4.64-1.94-.28 1.05a.59.59 0 0 0 1.13.31v-.01l.3-1.1q-.52-.15-1.06-.24z"/>',
|
|
160
|
+
jsr: '<path d="M3.7 5.54v3.7H0v7.38h7.38v1.84h12.93v-3.7H24V7.39h-7.38V5.54Zm1.84 1.85h1.85v7.38H1.84v-3.7h1.84v1.85h1.85zm3.7 0h5.53v1.84h-3.7v1.85h3.7v5.53H9.23v-1.84h3.7v-1.85h-3.7Zm7.38 1.84h5.53v3.7h-1.84v-1.85h-1.85v5.54h-1.84z"/>',
|
|
158
161
|
};
|
|
159
162
|
|
|
160
163
|
export const Icons = {
|
|
@@ -16,17 +16,19 @@ interface SidebarState {
|
|
|
16
16
|
/**
|
|
17
17
|
* Get the current sidebar state.
|
|
18
18
|
*
|
|
19
|
-
* The `open` state is loaded from session storage, while `scroll`
|
|
19
|
+
* The `open` state is loaded from session storage when the sidebar hashes match, while `scroll`
|
|
20
|
+
* and `hash` are read from the current page.
|
|
20
21
|
*/
|
|
21
22
|
const getState = (): SidebarState => {
|
|
22
23
|
let open = [];
|
|
24
|
+
const hash = target?.dataset.hash || '';
|
|
23
25
|
try {
|
|
24
26
|
const rawStoredState = sessionStorage.getItem(storageKey);
|
|
25
27
|
const storedState = JSON.parse(rawStoredState || '{}');
|
|
26
|
-
if (Array.isArray(storedState.open)) open = storedState.open;
|
|
28
|
+
if (Array.isArray(storedState.open) && storedState.hash === hash) open = storedState.open;
|
|
27
29
|
} catch {}
|
|
28
30
|
return {
|
|
29
|
-
hash
|
|
31
|
+
hash,
|
|
30
32
|
open,
|
|
31
33
|
scroll: scroller?.scrollTop || 0,
|
|
32
34
|
};
|
package/package.json
CHANGED
package/schemas/social.ts
CHANGED
|
@@ -34,6 +34,7 @@ export const socialLinks = [
|
|
|
34
34
|
'discourse',
|
|
35
35
|
'zulip',
|
|
36
36
|
'pinterest',
|
|
37
|
+
'tiktok',
|
|
37
38
|
] as const;
|
|
38
39
|
|
|
39
40
|
export const SocialLinksSchema = () =>
|
|
@@ -83,6 +84,7 @@ export const SocialLinksSchema = () =>
|
|
|
83
84
|
discourse: 'Discourse',
|
|
84
85
|
zulip: 'Zulip',
|
|
85
86
|
pinterest: 'Pinterest',
|
|
87
|
+
tiktok: 'TikTok',
|
|
86
88
|
}[key];
|
|
87
89
|
labelledLinks[key] = { label, url };
|
|
88
90
|
}
|
package/utils/i18n.ts
CHANGED
|
@@ -70,6 +70,9 @@ function getAstroI18nConfig(config: StarlightConfig): NonNullable<AstroConfig['i
|
|
|
70
70
|
// Sites with a single non-root language different from the built-in default locale.
|
|
71
71
|
(!config.isMultilingual && config.locales !== undefined),
|
|
72
72
|
redirectToDefaultLocale: false,
|
|
73
|
+
// TODO: remove this ignore comment for Astro v5
|
|
74
|
+
// @ts-ignore — Only used in Astro >=4.15.0, but Starlight supports ^4.8.6
|
|
75
|
+
fallbackType: 'redirect',
|
|
73
76
|
},
|
|
74
77
|
};
|
|
75
78
|
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { expect, testFactory } from './test-utils';
|
|
2
|
-
|
|
3
|
-
// This fixture contains a space in the directory so that we have a smoke test for building
|
|
4
|
-
// Starlight projects with pathnames like this, which are a common source of bugs.
|
|
5
|
-
const test = await testFactory('./fixtures/custom src-dir/');
|
|
6
|
-
|
|
7
|
-
test('builds a custom page using the `<StarlightPage>` component and a custom `srcDir`', async ({
|
|
8
|
-
page,
|
|
9
|
-
starlight,
|
|
10
|
-
}) => {
|
|
11
|
-
await starlight.goto('/custom');
|
|
12
|
-
|
|
13
|
-
await expect(page.getByText('Hello')).toBeVisible();
|
|
14
|
-
});
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
#!/bin/sh
|
|
2
|
-
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
-
|
|
4
|
-
case `uname` in
|
|
5
|
-
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
|
|
6
|
-
esac
|
|
7
|
-
|
|
8
|
-
if [ -z "$NODE_PATH" ]; then
|
|
9
|
-
export NODE_PATH="/home/runner/work/starlight/starlight/node_modules/.pnpm/astro@4.10.2_@types+node@18.16.19_typescript@5.4.5/node_modules/astro/node_modules:/home/runner/work/starlight/starlight/node_modules/.pnpm/astro@4.10.2_@types+node@18.16.19_typescript@5.4.5/node_modules:/home/runner/work/starlight/starlight/node_modules/.pnpm/node_modules"
|
|
10
|
-
else
|
|
11
|
-
export NODE_PATH="/home/runner/work/starlight/starlight/node_modules/.pnpm/astro@4.10.2_@types+node@18.16.19_typescript@5.4.5/node_modules/astro/node_modules:/home/runner/work/starlight/starlight/node_modules/.pnpm/astro@4.10.2_@types+node@18.16.19_typescript@5.4.5/node_modules:/home/runner/work/starlight/starlight/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
12
|
-
fi
|
|
13
|
-
if [ -x "$basedir/node" ]; then
|
|
14
|
-
exec "$basedir/node" "$basedir/../astro/astro.js" "$@"
|
|
15
|
-
else
|
|
16
|
-
exec node "$basedir/../astro/astro.js" "$@"
|
|
17
|
-
fi
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Tabs unsynced
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
import { Tabs, TabItem } from '@astrojs/starlight/components';
|
|
6
|
-
|
|
7
|
-
A basic set of tabs.
|
|
8
|
-
|
|
9
|
-
<Tabs>
|
|
10
|
-
<TabItem label="npm">npm command</TabItem>
|
|
11
|
-
<TabItem label="pnpm">pnpm command</TabItem>
|
|
12
|
-
<TabItem label="yarn">yarn command</TabItem>
|
|
13
|
-
</Tabs>
|
|
14
|
-
|
|
15
|
-
Another basic set of tabs.
|
|
16
|
-
|
|
17
|
-
<Tabs>
|
|
18
|
-
<TabItem label="one">tab 1</TabItem>
|
|
19
|
-
<TabItem label="two">tab 2</TabItem>
|
|
20
|
-
<TabItem label="three">tab 3</TabItem>
|
|
21
|
-
</Tabs>
|
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Tabs with varying content heights
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
import { Tabs, TabItem } from '@astrojs/starlight/components';
|
|
6
|
-
|
|
7
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
8
|
-
|
|
9
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
10
|
-
|
|
11
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
12
|
-
|
|
13
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
14
|
-
|
|
15
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
16
|
-
|
|
17
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
18
|
-
|
|
19
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
20
|
-
|
|
21
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
22
|
-
|
|
23
|
-
**A set of tabs using a sync key with content of different heights between tabs.**
|
|
24
|
-
|
|
25
|
-
<Tabs syncKey="things">
|
|
26
|
-
<TabItem label="A">
|
|
27
|
-
|
|
28
|
-
A little bit of text.
|
|
29
|
-
|
|
30
|
-
</TabItem>
|
|
31
|
-
<TabItem label="B">
|
|
32
|
-
|
|
33
|
-
A lot more text.
|
|
34
|
-
|
|
35
|
-
A lot more text.
|
|
36
|
-
|
|
37
|
-
A lot more text.
|
|
38
|
-
|
|
39
|
-
A lot more text.
|
|
40
|
-
|
|
41
|
-
A lot more text.
|
|
42
|
-
|
|
43
|
-
A lot more text.
|
|
44
|
-
|
|
45
|
-
A lot more text.
|
|
46
|
-
|
|
47
|
-
A lot more text.
|
|
48
|
-
|
|
49
|
-
A lot more text.
|
|
50
|
-
|
|
51
|
-
A lot more text.
|
|
52
|
-
|
|
53
|
-
</TabItem>
|
|
54
|
-
</Tabs>
|
|
55
|
-
|
|
56
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
57
|
-
|
|
58
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
59
|
-
|
|
60
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
61
|
-
|
|
62
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
63
|
-
|
|
64
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
65
|
-
|
|
66
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
67
|
-
|
|
68
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
69
|
-
|
|
70
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
71
|
-
|
|
72
|
-
**Another set of tabs using the same sync key with content of different heights between tabs.**
|
|
73
|
-
|
|
74
|
-
<Tabs syncKey="things">
|
|
75
|
-
<TabItem label="A">
|
|
76
|
-
|
|
77
|
-
A little bit of text.
|
|
78
|
-
|
|
79
|
-
</TabItem>
|
|
80
|
-
<TabItem label="B">
|
|
81
|
-
|
|
82
|
-
A lot more text.
|
|
83
|
-
|
|
84
|
-
A lot more text.
|
|
85
|
-
|
|
86
|
-
A lot more text.
|
|
87
|
-
|
|
88
|
-
A lot more text.
|
|
89
|
-
|
|
90
|
-
A lot more text.
|
|
91
|
-
|
|
92
|
-
A lot more text.
|
|
93
|
-
|
|
94
|
-
A lot more text.
|
|
95
|
-
|
|
96
|
-
A lot more text.
|
|
97
|
-
|
|
98
|
-
A lot more text.
|
|
99
|
-
|
|
100
|
-
A lot more text.
|
|
101
|
-
|
|
102
|
-
</TabItem>
|
|
103
|
-
</Tabs>
|
|
104
|
-
|
|
105
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
106
|
-
|
|
107
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
108
|
-
|
|
109
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
110
|
-
|
|
111
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
112
|
-
|
|
113
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
114
|
-
|
|
115
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
116
|
-
|
|
117
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
118
|
-
|
|
119
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
120
|
-
|
|
121
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
122
|
-
|
|
123
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
124
|
-
|
|
125
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
126
|
-
|
|
127
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
128
|
-
|
|
129
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
130
|
-
|
|
131
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
132
|
-
|
|
133
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
134
|
-
|
|
135
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
136
|
-
|
|
137
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
138
|
-
|
|
139
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
140
|
-
|
|
141
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
142
|
-
|
|
143
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
144
|
-
|
|
145
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
146
|
-
|
|
147
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
148
|
-
|
|
149
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
150
|
-
|
|
151
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Tabs
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
import { Tabs, TabItem } from '@astrojs/starlight/components';
|
|
6
|
-
|
|
7
|
-
A set of tabs using the `pkg` sync key.
|
|
8
|
-
|
|
9
|
-
<Tabs syncKey="pkg">
|
|
10
|
-
<TabItem label="npm">npm command</TabItem>
|
|
11
|
-
<TabItem label="pnpm">pnpm command</TabItem>
|
|
12
|
-
<TabItem label="yarn">yarn command</TabItem>
|
|
13
|
-
</Tabs>
|
|
14
|
-
|
|
15
|
-
A basic set of tabs.
|
|
16
|
-
|
|
17
|
-
<Tabs>
|
|
18
|
-
<TabItem label="one">tab 1</TabItem>
|
|
19
|
-
<TabItem label="two">tab 2</TabItem>
|
|
20
|
-
<TabItem label="three">tab 3</TabItem>
|
|
21
|
-
</Tabs>
|
|
22
|
-
|
|
23
|
-
Another set of tabs using the `pkg` sync key and an extra tab.
|
|
24
|
-
|
|
25
|
-
<Tabs syncKey="pkg">
|
|
26
|
-
<TabItem label="npm">another npm command</TabItem>
|
|
27
|
-
<TabItem label="pnpm">another pnpm command</TabItem>
|
|
28
|
-
<TabItem label="bun">another bun command</TabItem>
|
|
29
|
-
<TabItem label="yarn">another yarn command</TabItem>
|
|
30
|
-
</Tabs>
|
|
31
|
-
|
|
32
|
-
A set of tabs using the `style` sync key.
|
|
33
|
-
|
|
34
|
-
<Tabs syncKey="style">
|
|
35
|
-
<TabItem label="css">css code</TabItem>
|
|
36
|
-
<TabItem label="tailwind">tailwind code</TabItem>
|
|
37
|
-
</Tabs>
|
|
38
|
-
|
|
39
|
-
Another set of tabs using the `pkg` sync key and using icons.
|
|
40
|
-
|
|
41
|
-
<Tabs syncKey="pkg">
|
|
42
|
-
<TabItem label="npm" icon="seti:npm">
|
|
43
|
-
another npm command
|
|
44
|
-
</TabItem>
|
|
45
|
-
<TabItem label="pnpm" icon="pnpm">
|
|
46
|
-
another pnpm command
|
|
47
|
-
</TabItem>
|
|
48
|
-
<TabItem label="bun" icon="bun">
|
|
49
|
-
another bun command
|
|
50
|
-
</TabItem>
|
|
51
|
-
<TabItem label="yarn" icon="seti:yarn">
|
|
52
|
-
another yarn command
|
|
53
|
-
</TabItem>
|
|
54
|
-
</Tabs>
|
|
55
|
-
|
|
56
|
-
A set of tabs using the `os` sync key.
|
|
57
|
-
|
|
58
|
-
<Tabs syncKey="os">
|
|
59
|
-
<TabItem label="macos">macOS</TabItem>
|
|
60
|
-
<TabItem label="windows">Windows</TabItem>
|
|
61
|
-
<TabItem label="linux">GNU/Linux</TabItem>
|
|
62
|
-
</Tabs>
|
|
63
|
-
|
|
64
|
-
Another set of tabs using the `os` sync key.
|
|
65
|
-
|
|
66
|
-
<Tabs syncKey="os">
|
|
67
|
-
<TabItem label="macos">ls</TabItem>
|
|
68
|
-
<TabItem label="windows">Get-ChildItem</TabItem>
|
|
69
|
-
<TabItem label="linux">ls</TabItem>
|
|
70
|
-
</Tabs>
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
#!/bin/sh
|
|
2
|
-
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
-
|
|
4
|
-
case `uname` in
|
|
5
|
-
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
|
|
6
|
-
esac
|
|
7
|
-
|
|
8
|
-
if [ -z "$NODE_PATH" ]; then
|
|
9
|
-
export NODE_PATH="/home/runner/work/starlight/starlight/node_modules/.pnpm/astro@4.10.2_@types+node@18.16.19_typescript@5.4.5/node_modules/astro/node_modules:/home/runner/work/starlight/starlight/node_modules/.pnpm/astro@4.10.2_@types+node@18.16.19_typescript@5.4.5/node_modules:/home/runner/work/starlight/starlight/node_modules/.pnpm/node_modules"
|
|
10
|
-
else
|
|
11
|
-
export NODE_PATH="/home/runner/work/starlight/starlight/node_modules/.pnpm/astro@4.10.2_@types+node@18.16.19_typescript@5.4.5/node_modules/astro/node_modules:/home/runner/work/starlight/starlight/node_modules/.pnpm/astro@4.10.2_@types+node@18.16.19_typescript@5.4.5/node_modules:/home/runner/work/starlight/starlight/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
12
|
-
fi
|
|
13
|
-
if [ -x "$basedir/node" ]; then
|
|
14
|
-
exec "$basedir/node" "$basedir/../astro/astro.js" "$@"
|
|
15
|
-
else
|
|
16
|
-
exec node "$basedir/../astro/astro.js" "$@"
|
|
17
|
-
fi
|
package/__e2e__/tabs.test.ts
DELETED
|
@@ -1,299 +0,0 @@
|
|
|
1
|
-
import { expect, testFactory, type Locator } from './test-utils';
|
|
2
|
-
|
|
3
|
-
const test = await testFactory('./fixtures/basics/');
|
|
4
|
-
|
|
5
|
-
test('syncs tabs with a click event', async ({ page, starlight }) => {
|
|
6
|
-
await starlight.goto('/tabs');
|
|
7
|
-
|
|
8
|
-
const tabs = page.locator('starlight-tabs');
|
|
9
|
-
const pkgTabsA = tabs.nth(0);
|
|
10
|
-
const pkgTabsB = tabs.nth(2);
|
|
11
|
-
|
|
12
|
-
// Select the pnpm tab in the first set of synced tabs.
|
|
13
|
-
await pkgTabsA.getByRole('tab').filter({ hasText: 'pnpm' }).click();
|
|
14
|
-
|
|
15
|
-
await expectSelectedTab(pkgTabsA, 'pnpm', 'pnpm command');
|
|
16
|
-
await expectSelectedTab(pkgTabsB, 'pnpm', 'another pnpm command');
|
|
17
|
-
|
|
18
|
-
// Select the yarn tab in the second set of synced tabs.
|
|
19
|
-
await pkgTabsB.getByRole('tab').filter({ hasText: 'yarn' }).click();
|
|
20
|
-
|
|
21
|
-
await expectSelectedTab(pkgTabsB, 'yarn', 'another yarn command');
|
|
22
|
-
await expectSelectedTab(pkgTabsA, 'yarn', 'yarn command');
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
test('syncs tabs with a keyboard event', async ({ page, starlight }) => {
|
|
26
|
-
await starlight.goto('/tabs');
|
|
27
|
-
|
|
28
|
-
const tabs = page.locator('starlight-tabs');
|
|
29
|
-
const pkgTabsA = tabs.nth(0);
|
|
30
|
-
const pkgTabsB = tabs.nth(2);
|
|
31
|
-
|
|
32
|
-
// Select the pnpm tab in the first set of synced tabs with the keyboard.
|
|
33
|
-
await pkgTabsA.getByRole('tab', { selected: true }).press('ArrowRight');
|
|
34
|
-
|
|
35
|
-
await expectSelectedTab(pkgTabsA, 'pnpm', 'pnpm command');
|
|
36
|
-
await expectSelectedTab(pkgTabsB, 'pnpm', 'another pnpm command');
|
|
37
|
-
|
|
38
|
-
// Select back the npm tab in the second set of synced tabs with the keyboard.
|
|
39
|
-
const selectedTabB = pkgTabsB.getByRole('tab', { selected: true });
|
|
40
|
-
await selectedTabB.press('ArrowRight');
|
|
41
|
-
await selectedTabB.press('ArrowLeft');
|
|
42
|
-
await selectedTabB.press('ArrowLeft');
|
|
43
|
-
|
|
44
|
-
await expectSelectedTab(pkgTabsA, 'npm', 'npm command');
|
|
45
|
-
await expectSelectedTab(pkgTabsB, 'npm', 'another npm command');
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
test('syncs only tabs using the same sync key', async ({ page, starlight }) => {
|
|
49
|
-
await starlight.goto('/tabs');
|
|
50
|
-
|
|
51
|
-
const tabs = page.locator('starlight-tabs');
|
|
52
|
-
const pkgTabsA = tabs.nth(0);
|
|
53
|
-
const unsyncedTabs = tabs.nth(1);
|
|
54
|
-
const styleTabs = tabs.nth(3);
|
|
55
|
-
const osTabsA = tabs.nth(5);
|
|
56
|
-
const osTabsB = tabs.nth(6);
|
|
57
|
-
|
|
58
|
-
// Select the pnpm tab in the set of tabs synced with the 'pkg' key.
|
|
59
|
-
await pkgTabsA.getByRole('tab').filter({ hasText: 'pnpm' }).click();
|
|
60
|
-
|
|
61
|
-
await expectSelectedTab(unsyncedTabs, 'one', 'tab 1');
|
|
62
|
-
await expectSelectedTab(styleTabs, 'css', 'css code');
|
|
63
|
-
await expectSelectedTab(osTabsA, 'macos', 'macOS');
|
|
64
|
-
await expectSelectedTab(osTabsB, 'macos', 'ls');
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
test('supports synced tabs with different tab items', async ({ page, starlight }) => {
|
|
68
|
-
await starlight.goto('/tabs');
|
|
69
|
-
|
|
70
|
-
const tabs = page.locator('starlight-tabs');
|
|
71
|
-
const pkgTabsA = tabs.nth(0);
|
|
72
|
-
const pkgTabsB = tabs.nth(2); // This set contains an extra tab item.
|
|
73
|
-
|
|
74
|
-
// Select the bun tab in the second set of synced tabs.
|
|
75
|
-
await pkgTabsB.getByRole('tab').filter({ hasText: 'bun' }).click();
|
|
76
|
-
|
|
77
|
-
await expectSelectedTab(pkgTabsA, 'npm', 'npm command');
|
|
78
|
-
await expectSelectedTab(pkgTabsB, 'bun', 'another bun command');
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
test('persists the focus when syncing tabs', async ({ page, starlight }) => {
|
|
82
|
-
await starlight.goto('/tabs');
|
|
83
|
-
|
|
84
|
-
const pkgTabsA = page.locator('starlight-tabs').nth(0);
|
|
85
|
-
|
|
86
|
-
// Focus the selected tab in the set of tabs synced with the 'pkg' key.
|
|
87
|
-
await pkgTabsA.getByRole('tab', { selected: true }).focus();
|
|
88
|
-
// Select the pnpm tab in the set of tabs synced with the 'pkg' key using the keyboard.
|
|
89
|
-
await page.keyboard.press('ArrowRight');
|
|
90
|
-
|
|
91
|
-
expect(
|
|
92
|
-
await pkgTabsA
|
|
93
|
-
.getByRole('tab', { selected: true })
|
|
94
|
-
.evaluate((node) => document.activeElement === node)
|
|
95
|
-
).toBe(true);
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
test('preserves tabs position when alternating between tabs with different content heights', async ({
|
|
99
|
-
page,
|
|
100
|
-
starlight,
|
|
101
|
-
}) => {
|
|
102
|
-
await starlight.goto('/tabs-variable-height');
|
|
103
|
-
|
|
104
|
-
const tabs = page.locator('starlight-tabs').nth(1);
|
|
105
|
-
const selectedTab = tabs.getByRole('tab', { selected: true });
|
|
106
|
-
|
|
107
|
-
// Scroll to the second set of synced tabs and focus the selected tab.
|
|
108
|
-
await tabs.scrollIntoViewIfNeeded();
|
|
109
|
-
await selectedTab.focus();
|
|
110
|
-
|
|
111
|
-
// Get the bounding box of the tabs.
|
|
112
|
-
const initialBoundingBox = await tabs.boundingBox();
|
|
113
|
-
|
|
114
|
-
// Select the second tab which has a different height.
|
|
115
|
-
await selectedTab.press('ArrowRight');
|
|
116
|
-
|
|
117
|
-
// Ensure the tabs vertical position is exactly the same after selecting the second tab.
|
|
118
|
-
// Note that a small difference could be the result of the base line-height having a fractional part which can cause a
|
|
119
|
-
// sub-pixel difference in some browsers like Chrome or Firefox.
|
|
120
|
-
expect((await tabs.boundingBox())?.y).toBe(initialBoundingBox?.y);
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
test('syncs tabs with the same sync key if they do not consistenly use icons', async ({
|
|
124
|
-
page,
|
|
125
|
-
starlight,
|
|
126
|
-
}) => {
|
|
127
|
-
await starlight.goto('/tabs');
|
|
128
|
-
|
|
129
|
-
const tabs = page.locator('starlight-tabs');
|
|
130
|
-
const pkgTabsA = tabs.nth(0); // This set does not use icons for tab items.
|
|
131
|
-
const pkgTabsB = tabs.nth(4); // This set uses icons for tab items.
|
|
132
|
-
|
|
133
|
-
// Select the pnpm tab in the first set of synced tabs.
|
|
134
|
-
await pkgTabsA.getByRole('tab').filter({ hasText: 'pnpm' }).click();
|
|
135
|
-
|
|
136
|
-
await expectSelectedTab(pkgTabsA, 'pnpm', 'pnpm command');
|
|
137
|
-
await expectSelectedTab(pkgTabsB, 'pnpm', 'another pnpm command');
|
|
138
|
-
|
|
139
|
-
// Select the yarn tab in the second set of synced tabs.
|
|
140
|
-
await pkgTabsB.getByRole('tab').filter({ hasText: 'yarn' }).click();
|
|
141
|
-
|
|
142
|
-
await expectSelectedTab(pkgTabsB, 'yarn', 'another yarn command');
|
|
143
|
-
await expectSelectedTab(pkgTabsA, 'yarn', 'yarn command');
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
test('restores tabs only for synced tabs with a persisted state', async ({ page, starlight }) => {
|
|
147
|
-
await starlight.goto('/tabs');
|
|
148
|
-
|
|
149
|
-
const tabs = page.locator('starlight-tabs');
|
|
150
|
-
const pkgTabsA = tabs.nth(0);
|
|
151
|
-
const pkgTabsB = tabs.nth(2);
|
|
152
|
-
const pkgTabsC = tabs.nth(4);
|
|
153
|
-
const unsyncedTabs = tabs.nth(1);
|
|
154
|
-
const styleTabs = tabs.nth(3);
|
|
155
|
-
const osTabsA = tabs.nth(5);
|
|
156
|
-
const osTabsB = tabs.nth(6);
|
|
157
|
-
|
|
158
|
-
// Select the pnpm tab in the set of tabs synced with the 'pkg' key.
|
|
159
|
-
await pkgTabsA.getByRole('tab').filter({ hasText: 'pnpm' }).click();
|
|
160
|
-
|
|
161
|
-
await expectSelectedTab(pkgTabsA, 'pnpm', 'pnpm command');
|
|
162
|
-
await expectSelectedTab(pkgTabsB, 'pnpm', 'another pnpm command');
|
|
163
|
-
await expectSelectedTab(pkgTabsC, 'pnpm', 'another pnpm command');
|
|
164
|
-
|
|
165
|
-
page.reload();
|
|
166
|
-
|
|
167
|
-
// The synced tabs with a persisted state should be restored.
|
|
168
|
-
await expectSelectedTab(pkgTabsA, 'pnpm', 'pnpm command');
|
|
169
|
-
await expectSelectedTab(pkgTabsB, 'pnpm', 'another pnpm command');
|
|
170
|
-
await expectSelectedTab(pkgTabsC, 'pnpm', 'another pnpm command');
|
|
171
|
-
|
|
172
|
-
// Other tabs should not be affected.
|
|
173
|
-
await expectSelectedTab(unsyncedTabs, 'one', 'tab 1');
|
|
174
|
-
await expectSelectedTab(styleTabs, 'css', 'css code');
|
|
175
|
-
await expectSelectedTab(osTabsA, 'macos', 'macOS');
|
|
176
|
-
await expectSelectedTab(osTabsB, 'macos', 'ls');
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
test('restores tabs for a single set of synced tabs with a persisted state', async ({
|
|
180
|
-
page,
|
|
181
|
-
starlight,
|
|
182
|
-
}) => {
|
|
183
|
-
await starlight.goto('/tabs');
|
|
184
|
-
|
|
185
|
-
const tabs = page.locator('starlight-tabs');
|
|
186
|
-
const styleTabs = tabs.nth(3);
|
|
187
|
-
|
|
188
|
-
// Select the tailwind tab in the set of tabs synced with the 'style' key.
|
|
189
|
-
await styleTabs.getByRole('tab').filter({ hasText: 'tailwind' }).click();
|
|
190
|
-
|
|
191
|
-
await expectSelectedTab(styleTabs, 'tailwind', 'tailwind code');
|
|
192
|
-
|
|
193
|
-
page.reload();
|
|
194
|
-
|
|
195
|
-
// The synced tabs with a persisted state should be restored.
|
|
196
|
-
await expectSelectedTab(styleTabs, 'tailwind', 'tailwind code');
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
test('restores tabs for multiple synced tabs with different sync keys', async ({
|
|
200
|
-
page,
|
|
201
|
-
starlight,
|
|
202
|
-
}) => {
|
|
203
|
-
await starlight.goto('/tabs');
|
|
204
|
-
|
|
205
|
-
const tabs = page.locator('starlight-tabs');
|
|
206
|
-
const pkgTabsA = tabs.nth(0);
|
|
207
|
-
const pkgTabsB = tabs.nth(2);
|
|
208
|
-
const pkgTabsC = tabs.nth(4);
|
|
209
|
-
const osTabsA = tabs.nth(5);
|
|
210
|
-
const osTabsB = tabs.nth(6);
|
|
211
|
-
|
|
212
|
-
// Select the pnpm tab in the set of tabs synced with the 'pkg' key.
|
|
213
|
-
await pkgTabsA.getByRole('tab').filter({ hasText: 'pnpm' }).click();
|
|
214
|
-
|
|
215
|
-
await expectSelectedTab(pkgTabsA, 'pnpm', 'pnpm command');
|
|
216
|
-
await expectSelectedTab(pkgTabsB, 'pnpm', 'another pnpm command');
|
|
217
|
-
await expectSelectedTab(pkgTabsC, 'pnpm', 'another pnpm command');
|
|
218
|
-
|
|
219
|
-
// Select the windows tab in the set of tabs synced with the 'os' key.
|
|
220
|
-
await osTabsB.getByRole('tab').filter({ hasText: 'windows' }).click();
|
|
221
|
-
|
|
222
|
-
page.reload();
|
|
223
|
-
|
|
224
|
-
// The synced tabs with a persisted state for the `pkg` sync key should be restored.
|
|
225
|
-
await expectSelectedTab(pkgTabsA, 'pnpm', 'pnpm command');
|
|
226
|
-
await expectSelectedTab(pkgTabsB, 'pnpm', 'another pnpm command');
|
|
227
|
-
await expectSelectedTab(pkgTabsC, 'pnpm', 'another pnpm command');
|
|
228
|
-
|
|
229
|
-
// The synced tabs with a persisted state for the `os` sync key should be restored.
|
|
230
|
-
await expectSelectedTab(osTabsA, 'windows', 'Windows');
|
|
231
|
-
await expectSelectedTab(osTabsB, 'windows', 'Get-ChildItem');
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
test('includes the `<starlight-tabs-restore>` element only for synced tabs', async ({
|
|
235
|
-
page,
|
|
236
|
-
starlight,
|
|
237
|
-
}) => {
|
|
238
|
-
await starlight.goto('/tabs');
|
|
239
|
-
|
|
240
|
-
// The page includes 7 sets of tabs.
|
|
241
|
-
await expect(page.locator('starlight-tabs')).toHaveCount(7);
|
|
242
|
-
// Only 6 sets of tabs are synced.
|
|
243
|
-
await expect(page.locator('starlight-tabs-restore')).toHaveCount(6);
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
test('includes the synced tabs restore script only when needed and at most once', async ({
|
|
247
|
-
page,
|
|
248
|
-
starlight,
|
|
249
|
-
}) => {
|
|
250
|
-
const syncedTabsRestoreScriptRegex = /customElements\.define\('starlight-tabs-restore',/g;
|
|
251
|
-
|
|
252
|
-
await starlight.goto('/tabs');
|
|
253
|
-
|
|
254
|
-
// The page includes at least one set of synced tabs.
|
|
255
|
-
expect((await page.content()).match(syncedTabsRestoreScriptRegex)?.length).toBe(1);
|
|
256
|
-
|
|
257
|
-
await starlight.goto('/tabs-unsynced');
|
|
258
|
-
|
|
259
|
-
// The page includes no set of synced tabs.
|
|
260
|
-
expect((await page.content()).match(syncedTabsRestoreScriptRegex)).toBeNull();
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
test('gracefully handles invalid persisted state for synced tabs', async ({ page, starlight }) => {
|
|
264
|
-
await starlight.goto('/tabs');
|
|
265
|
-
|
|
266
|
-
const tabs = page.locator('starlight-tabs');
|
|
267
|
-
const pkgTabsA = tabs.nth(0);
|
|
268
|
-
|
|
269
|
-
// Select the pnpm tab in the set of tabs synced with the 'pkg' key.
|
|
270
|
-
await pkgTabsA.getByRole('tab').filter({ hasText: 'pnpm' }).click();
|
|
271
|
-
|
|
272
|
-
await expectSelectedTab(pkgTabsA, 'pnpm', 'pnpm command');
|
|
273
|
-
|
|
274
|
-
// Replace the persisted state with a new invalid value.
|
|
275
|
-
await page.evaluate(
|
|
276
|
-
(value) => localStorage.setItem('starlight-synced-tabs__pkg', value),
|
|
277
|
-
'invalid-value'
|
|
278
|
-
);
|
|
279
|
-
|
|
280
|
-
page.reload();
|
|
281
|
-
|
|
282
|
-
// The synced tabs should not be restored due to the invalid persisted state.
|
|
283
|
-
await expectSelectedTab(pkgTabsA, 'npm', 'npm command');
|
|
284
|
-
|
|
285
|
-
// Select the pnpm tab in the set of tabs synced with the 'pkg' key.
|
|
286
|
-
await pkgTabsA.getByRole('tab').filter({ hasText: 'pnpm' }).click();
|
|
287
|
-
|
|
288
|
-
await expectSelectedTab(pkgTabsA, 'pnpm', 'pnpm command');
|
|
289
|
-
|
|
290
|
-
// The synced tabs should be restored with the new valid persisted state.
|
|
291
|
-
expect(await page.evaluate(() => localStorage.getItem('starlight-synced-tabs__pkg'))).toBe(
|
|
292
|
-
'pnpm'
|
|
293
|
-
);
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
async function expectSelectedTab(tabs: Locator, label: string, panel: string) {
|
|
297
|
-
expect((await tabs.getByRole('tab', { selected: true }).textContent())?.trim()).toBe(label);
|
|
298
|
-
expect((await tabs.getByRole('tabpanel').textContent())?.trim()).toBe(panel);
|
|
299
|
-
}
|
package/__e2e__/test-utils.ts
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { fileURLToPath } from 'node:url';
|
|
2
|
-
import { test as baseTest, type Page } from '@playwright/test';
|
|
3
|
-
import { build, preview } from 'astro';
|
|
4
|
-
|
|
5
|
-
export { expect, type Locator } from '@playwright/test';
|
|
6
|
-
|
|
7
|
-
process.env.ASTRO_TELEMETRY_DISABLED = 'true';
|
|
8
|
-
process.env.ASTRO_DISABLE_UPDATE_CHECK = 'true';
|
|
9
|
-
|
|
10
|
-
// Setup a test environment that will build and start a preview server for a given fixture path and
|
|
11
|
-
// provide a Starlight Playwright fixture accessible from within all tests.
|
|
12
|
-
export async function testFactory(fixturePath: string) {
|
|
13
|
-
let previewServer: PreviewServer | undefined;
|
|
14
|
-
|
|
15
|
-
const test = baseTest.extend<{ starlight: StarlightPage }>({
|
|
16
|
-
starlight: async ({ page }, use) => {
|
|
17
|
-
if (!previewServer) {
|
|
18
|
-
throw new Error('Could not find a preview server to run tests against.');
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
await use(new StarlightPage(previewServer, page));
|
|
22
|
-
},
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
test.beforeAll(async () => {
|
|
26
|
-
const root = fileURLToPath(new URL(fixturePath, import.meta.url));
|
|
27
|
-
await build({ logLevel: 'error', root });
|
|
28
|
-
previewServer = await preview({ logLevel: 'error', root });
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
test.afterAll(async () => {
|
|
32
|
-
await previewServer?.stop();
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
return test;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// A Playwright test fixture accessible from within all tests.
|
|
39
|
-
class StarlightPage {
|
|
40
|
-
constructor(
|
|
41
|
-
private readonly previewServer: PreviewServer,
|
|
42
|
-
private readonly page: Page
|
|
43
|
-
) {}
|
|
44
|
-
|
|
45
|
-
// Navigate to a URL relative to the server used during a test run and return the resource response.
|
|
46
|
-
goto(url: string) {
|
|
47
|
-
return this.page.goto(this.resolveUrl(url));
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Resolve a URL relative to the server used during a test run.
|
|
51
|
-
resolveUrl(url: string) {
|
|
52
|
-
return `http://localhost:${this.previewServer.port}${url.replace(/^\/?/, '/')}`;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
type PreviewServer = Awaited<ReturnType<typeof preview>>;
|
package/playwright.config.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { defineConfig, devices } from '@playwright/test';
|
|
2
|
-
|
|
3
|
-
export default defineConfig({
|
|
4
|
-
forbidOnly: !!process.env['CI'],
|
|
5
|
-
projects: [
|
|
6
|
-
{
|
|
7
|
-
name: 'Chrome Stable',
|
|
8
|
-
use: {
|
|
9
|
-
...devices['Desktop Chrome'],
|
|
10
|
-
headless: true,
|
|
11
|
-
},
|
|
12
|
-
},
|
|
13
|
-
],
|
|
14
|
-
testMatch: '__e2e__/*.test.ts',
|
|
15
|
-
timeout: 40 * 1_000,
|
|
16
|
-
workers: 1,
|
|
17
|
-
});
|