@astrojs/starlight 0.41.7 → 0.41.8

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 CHANGED
@@ -1,5 +1,15 @@
1
1
  # @astrojs/starlight
2
2
 
3
+ ## 0.41.8
4
+
5
+ ### Patch Changes
6
+
7
+ - [#4142](https://github.com/withastro/starlight/pull/4142) [`cacbc9f`](https://github.com/withastro/starlight/commit/cacbc9ff45c551c2f20c6b307800f7ff7ee07db2) Thanks [@alebelcor](https://github.com/alebelcor)! - Adds 1 new icon: `whatsApp`
8
+
9
+ - [#4133](https://github.com/withastro/starlight/pull/4133) [`3944311`](https://github.com/withastro/starlight/commit/3944311bed46f956e12e79a8eb0c32084eeeaea6) Thanks [@delucis](https://github.com/delucis)! - Internal refactor: numbered `id` attributes in the `<Tabs>` component are now page-specific instead of using a global counter
10
+
11
+ - [#4138](https://github.com/withastro/starlight/pull/4138) [`cd4b665`](https://github.com/withastro/starlight/commit/cd4b6655f3235220cded12f0567e0dad1bf5adac) Thanks [@delucis](https://github.com/delucis)! - Fixes localisation of code block UI elements when using the Sätteri Markdown processor
12
+
3
13
  ## 0.41.7
4
14
 
5
15
  ### Patch Changes
@@ -141,6 +141,8 @@ export const BuiltInIcons = {
141
141
  '<path d="M15.72 0 14 1.28l6.4 8.58 1.7-1.26L15.73 0zm-3.94 3.42-1.36 1.64 8.22 6.85 1.37-1.64-8.23-6.85zM8.64 7.88l-.91 1.94 9.7 4.52.9-1.94-9.7-4.52zm-1.86 4.86-.44 2.1 10.48 2.2.44-2.1-10.47-2.2zM1.9 15.47V24h19.19v-8.53h-2.13v6.4H4.02v-6.4H1.9zm4.26 2.13v2.13h10.66V17.6H6.15Z"/>',
142
142
  telegram:
143
143
  '<path d="M22.265 2.428a2.048 2.048 0 0 0-2.078-.324L2.266 9.339a2.043 2.043 0 0 0 .104 3.818l3.625 1.261 2.02 6.682a.998.998 0 0 0 .119.252c.008.012.019.02.027.033a.988.988 0 0 0 .211.215.972.972 0 0 0 .07.05.986.986 0 0 0 .31.136l.013.001.006.003a1.022 1.022 0 0 0 .203.02l.018-.003a.993.993 0 0 0 .301-.052c.023-.008.042-.02.064-.03a.993.993 0 0 0 .205-.114 250.76 250.76 0 0 1 .152-.129l2.702-2.983 4.03 3.122a2.023 2.023 0 0 0 1.241.427 2.054 2.054 0 0 0 2.008-1.633l3.263-16.017a2.03 2.03 0 0 0-.693-1.97ZM9.37 14.736a.994.994 0 0 0-.272.506l-.31 1.504-.784-2.593 4.065-2.117Zm8.302 5.304-4.763-3.69a1.001 1.001 0 0 0-1.353.12l-.866.955.306-1.487 7.083-7.083a1 1 0 0 0-1.169-1.593L6.745 12.554 3.02 11.191 20.999 4Z"/>',
144
+ whatsApp:
145
+ '<path d="M11.96 0a11.78 11.78 0 0 1 8.387 3.477 11.8 11.8 0 0 1 3.47 8.389c-.003 6.472-5.216 11.75-11.661 11.855l-.196.002h-.005a11.85 11.85 0 0 1-5.586-1.4l-.08-.043-6.286 1.649 1.682-6.145a11.84 11.84 0 0 1-1.583-5.928C.105 5.32 5.424 0 11.96 0m.004 2.003c-5.436 0-9.857 4.42-9.86 9.854 0 1.834.505 3.62 1.463 5.174l.044.071.235.373-.996 3.636 3.73-.978.36.214a9.84 9.84 0 0 0 4.932 1.373h.088c5.432 0 9.853-4.42 9.855-9.855a9.8 9.8 0 0 0-2.884-6.972 9.8 9.8 0 0 0-6.967-2.89M7.762 6.38c.197 0 .395.002.568.01.182.01.426-.069.666.509.092.221.233.563.376.913l.031.075A51 51 0 0 0 9.91 9.1c.074.148.123.32.024.519-.098.197-.148.32-.296.494-.148.173-.31.386-.444.519l-.022.022-.022.022c-.132.136-.242.293-.086.56.173.297.767 1.268 1.648 2.053 1.132 1.01 2.086 1.322 2.383 1.47.296.149.469.124.641-.074.173-.197.741-.865.939-1.161s.394-.247.666-.149c.13.047.526.234.939.433l.128.062c.414.2.817.399.957.47.297.148.494.222.568.345.074.124.074.717-.172 1.409-.247.692-1.431 1.324-2 1.409-.51.076-1.156.108-1.866-.117a17 17 0 0 1-1.69-.625c-2.971-1.283-4.912-4.275-5.06-4.473l-.01-.014c-.18-.24-1.2-1.622-1.2-3.051 0-1.458.765-2.175 1.037-2.472a1.1 1.1 0 0 1 .79-.37"/>',
144
146
  rss: '<path d="M2.88 16.88a3 3 0 0 0 0 4.24 3 3 0 0 0 4.24 0 3 3 0 0 0-4.24-4.24Zm2.83 2.83a1 1 0 0 1-1.42-1.42 1 1 0 0 1 1.42 0 1 1 0 0 1 0 1.42ZM5 12a1 1 0 0 0 0 2 5 5 0 0 1 5 5 1 1 0 0 0 2 0 7 7 0 0 0-7-7Zm0-4a1 1 0 0 0 0 2 9 9 0 0 1 9 9 1 1 0 0 0 2 0 11.08 11.08 0 0 0-3.22-7.78A11.08 11.08 0 0 0 5 8Zm10.61.39A15.11 15.11 0 0 0 5 4a1 1 0 0 0 0 2 13 13 0 0 1 13 13 1 1 0 0 0 2 0 15.11 15.11 0 0 0-4.39-10.61Z"/>',
145
147
  facebook:
146
148
  '<path d="M20.9 2H3.1A1.1 1.1 0 0 0 2 3.1v17.8A1.1 1.1 0 0 0 3.1 22h9.58v-7.75h-2.6v-3h2.6V9a3.64 3.64 0 0 1 3.88-4 20.26 20.26 0 0 1 2.33.12v2.7H17.3c-1.26 0-1.5.6-1.5 1.47v1.93h3l-.39 3H15.8V22h5.1a1.1 1.1 0 0 0 1.1-1.1V3.1A1.1 1.1 0 0 0 20.9 2Z"/>',
@@ -106,7 +106,12 @@ export function getStarlightEcConfigPreprocessor({
106
106
  ...otherStyleOverrides,
107
107
  },
108
108
  getBlockLocale: ({ file }) => {
109
- if (file.url) {
109
+ // When Expressive Code runs inside the `<Code>` component, it uses `Astro.url` to provide
110
+ // the file URL, so we can deduce the locale from that slug. This is different from the URL
111
+ // provided by Sätteri, which is a `file://` URL for the full absolute file path, so we
112
+ // ignore the `file.url` field for `file://` protocols so this branch only processes the
113
+ // `<Code>` component case.
114
+ if (file.url && file.url.protocol !== 'file:') {
110
115
  const locale = slugToLocale(file.url.pathname.slice(1), starlightConfig);
111
116
  return localeToLang(starlightConfig, locale);
112
117
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrojs/starlight",
3
- "version": "0.41.7",
3
+ "version": "0.41.8",
4
4
  "description": "Build beautiful, high-performance documentation websites with Astro",
5
5
  "keywords": [
6
6
  "docs",
@@ -94,8 +94,8 @@
94
94
  "provenance": true
95
95
  },
96
96
  "scripts": {
97
- "test": "vitest",
98
- "test:coverage": "vitest run --coverage",
97
+ "test": "VITE_CONFIG_NATIVE_IGNORE_WARNING=true vitest",
98
+ "test:coverage": "VITE_CONFIG_NATIVE_IGNORE_WARNING=true vitest run --coverage",
99
99
  "test:e2e": "playwright install --with-deps chromium && playwright test",
100
100
  "test:e2e:ci": "playwright test"
101
101
  }
@@ -7,36 +7,49 @@ interface Props {
7
7
  }
8
8
 
9
9
  const { syncKey } = Astro.props;
10
- const panelHtml = await Astro.slots.render('default');
11
- const { html, panels } = processPanels(panelHtml);
12
-
13
- /**
14
- * Synced tabs are persisted across page using `localStorage`. The script used to restore the
15
- * active tab for a given sync key has a few requirements:
16
- *
17
- * - The script should only be included when at least one set of synced tabs is present on the page.
18
- * - The script should be inlined to avoid a flash of invalid active tab.
19
- * - The script should only be included once per page.
20
- *
21
- * To do so, we keep track of whether the script has been rendered using a variable stored using
22
- * `Astro.locals` which will be reset for each new page. The value is tracked using an untyped
23
- * symbol on purpose to avoid Starlight users to get autocomplete for it and avoid potential
24
- * clashes with user-defined variables.
25
- *
26
- * The restore script defines a custom element `starlight-tabs-restore` that will be included in
27
- * each set of synced tabs to restore the active tab based on the persisted value using the
28
- * `connectedCallback` lifecycle method. To ensure this callback can access all tabs and panels for
29
- * the current set of tabs, the script should be rendered before the tabs themselves.
30
- */
31
- const isSynced = syncKey !== undefined;
10
+
11
+ // Some tab functionality has to be co-ordinated across multiple instances for each page. To do
12
+ // this, we keep track of page-level state in symbol-keyed variables in `Astro.locals`, which is a
13
+ // fresh object for each new page. The keys are not typed globally to avoid Starlight users
14
+ // getting autocomplete for them and using symbols reduces the risk of potential clashes with
15
+ // user-defined variables.
16
+ //
17
+ // We store data for:
18
+ //
19
+ // - The number of tabs rendered on the current page, so that each set can have unique IDs.
20
+ //
21
+ // - Synced tabs, which are persisted across pages using `localStorage`. The script used to restore
22
+ // the active tab for a given sync key has a few requirements:
23
+ // - The script should only be included when at least one set of synced tabs is present on the page.
24
+ // - The script should be inlined to avoid a flash of invalid active tab.
25
+ // - The script should only be included once per page.
26
+ //
27
+ // The restore script defines a custom element `starlight-tabs-restore` that will be included in
28
+ // each set of synced tabs to restore the active tab based on the persisted value using the
29
+ // `connectedCallback` lifecycle method. To ensure this callback can access all tabs and panels for
30
+ // the current set of tabs, the script should be rendered before the tabs themselves.
31
+
32
32
  const didRenderSyncedTabsRestoreScriptSymbol = Symbol.for('starlight:did-render-synced-tabs-restore-script');
33
- // @ts-expect-error - See above
34
- const shouldRenderSyncedTabsRestoreScript = isSynced && Astro.locals[didRenderSyncedTabsRestoreScriptSymbol] !== true;
33
+ const tabInstanceCountSymbol = Symbol.for('starlight:tab-instance-count');
34
+
35
+ const locals = Astro.locals as App.Locals & {
36
+ [didRenderSyncedTabsRestoreScriptSymbol]?: boolean;
37
+ [tabInstanceCountSymbol]?: number;
38
+ };
39
+
40
+ const isSynced = syncKey !== undefined;
41
+ const shouldRenderSyncedTabsRestoreScript =
42
+ isSynced && locals[didRenderSyncedTabsRestoreScriptSymbol] !== true;
35
43
 
36
44
  if (isSynced) {
37
- // @ts-expect-error - See above
38
- Astro.locals[didRenderSyncedTabsRestoreScriptSymbol] = true
45
+ locals[didRenderSyncedTabsRestoreScriptSymbol] = true;
39
46
  }
47
+
48
+ locals[tabInstanceCountSymbol] ??= 0;
49
+ const tabInstanceCount = locals[tabInstanceCountSymbol]++;
50
+
51
+ const panelHtml = await Astro.slots.render('default');
52
+ const { html, panels } = processPanels(panelHtml, tabInstanceCount);
40
53
  ---
41
54
 
42
55
  {/* Inlined to avoid a flash of invalid active tab. */}
@@ -2,6 +2,7 @@ import type { Element } from 'hast';
2
2
  import { select } from 'hast-util-select';
3
3
  import { rehype } from 'rehype';
4
4
  import { CONTINUE, SKIP, visit } from 'unist-util-visit';
5
+ import { VFile } from 'vfile';
5
6
  import type { StarlightIcon } from '../components-internals/Icons';
6
7
 
7
8
  interface Panel {
@@ -14,6 +15,7 @@ interface Panel {
14
15
  declare module 'vfile' {
15
16
  interface DataMap {
16
17
  panels: Panel[];
18
+ index: number;
17
19
  }
18
20
  }
19
21
 
@@ -39,12 +41,6 @@ const focusableElementSelectors = [
39
41
  .map((selector) => `${selector}:not([hidden]):not([tabindex="-1"])`)
40
42
  .join(',');
41
43
 
42
- let count = 0;
43
- const getIDs = () => {
44
- const id = count++;
45
- return { panelId: 'tab-panel-' + id, tabId: 'tab-' + id };
46
- };
47
-
48
44
  /**
49
45
  * Rehype processor to extract tab panel data and turn each
50
46
  * `<starlight-tab-item>` into a `<div>` with the necessary
@@ -56,6 +52,14 @@ const tabsProcessor = rehype()
56
52
  return (tree: Element, file) => {
57
53
  file.data.panels = [];
58
54
  let isFirst = true;
55
+ let count = 0;
56
+ const getIDs = () => {
57
+ const id = count++;
58
+ return {
59
+ panelId: `tab-panel-${file.data.index}-${id}`,
60
+ tabId: `tab-${file.data.index}-${id}`,
61
+ };
62
+ };
59
63
  visit(tree, 'element', (node) => {
60
64
  if (node.tagName !== TabItemTagname || !node.properties) {
61
65
  return CONTINUE;
@@ -104,9 +108,10 @@ const tabsProcessor = rehype()
104
108
  * Process tab panel items to extract data for the tab links and format
105
109
  * each tab panel correctly.
106
110
  * @param html Inner HTML passed to the `<Tabs>` component.
111
+ * @param index The index of the `<Tabs>` component on the page.
107
112
  */
108
- export const processPanels = (html: string) => {
109
- const file = tabsProcessor.processSync({ value: html });
113
+ export const processPanels = (html: string, index: number) => {
114
+ const file = tabsProcessor.processSync(new VFile({ value: html, data: { index } }));
110
115
  return {
111
116
  /** Data for each tab panel. */
112
117
  panels: file.data.panels,