summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Swithinbank2023-08-21 13:16:11 +0200
committerGitHub2023-08-21 13:16:11 +0200
commit87caf21adaac98cf8342dac4db97ace327849616 (patch)
tree3a55ac3e2b8a5220035314f8cd634cd951944ba0
parente287d6fe158ac6d590d0371fa9cf6ffe83cc02e2 (diff)
downloadIT.starlight-87caf21adaac98cf8342dac4db97ace327849616.tar.gz
IT.starlight-87caf21adaac98cf8342dac4db97ace327849616.tar.bz2
IT.starlight-87caf21adaac98cf8342dac4db97ace327849616.zip
Improve inline code and code block support in RTL languages (#525)
Co-authored-by: Kevin Zuniga Cuellar <46791833+kevinzunigacuellar@users.noreply.github.com>
-rw-r--r--.changeset/long-parrots-give.md5
-rw-r--r--packages/starlight/__tests__/remark-rehype/code-rtl-support.test.ts25
-rw-r--r--packages/starlight/__tests__/remark-rehype/vitest.config.ts3
-rw-r--r--packages/starlight/index.ts2
-rw-r--r--packages/starlight/integrations/code-rtl-support.ts31
5 files changed, 66 insertions, 0 deletions
diff --git a/.changeset/long-parrots-give.md b/.changeset/long-parrots-give.md
new file mode 100644
index 00000000..269c5130
--- /dev/null
+++ b/.changeset/long-parrots-give.md
@@ -0,0 +1,5 @@
+---
+'@astrojs/starlight': patch
+---
+
+Improve inline code and code block support in RTL languages
diff --git a/packages/starlight/__tests__/remark-rehype/code-rtl-support.test.ts b/packages/starlight/__tests__/remark-rehype/code-rtl-support.test.ts
new file mode 100644
index 00000000..69aa85ad
--- /dev/null
+++ b/packages/starlight/__tests__/remark-rehype/code-rtl-support.test.ts
@@ -0,0 +1,25 @@
+import { rehype } from 'rehype';
+import { expect, test } from 'vitest';
+import { rehypeRtlCodeSupport } from '../../integrations/code-rtl-support';
+
+const processor = rehype().data('settings', { fragment: true }).use(rehypeRtlCodeSupport());
+
+test('applies `dir="auto"` to inline code', async () => {
+ const input = `<p>Some text with <code>inline code</code>.</p>`;
+ const output = String(await processor.process(input));
+ expect(output).not.toEqual(input);
+ expect(output).includes('dir="auto"');
+ expect(output).toMatchInlineSnapshot(
+ '"<p>Some text with <code dir=\\"auto\\">inline code</code>.</p>"'
+ );
+});
+
+test('applies `dir="ltr"` to code blocks', async () => {
+ const input = `<p>Some text in a paragraph:</p><pre><code>console.log('test')</code></pre>`;
+ const output = String(await processor.process(input));
+ expect(output).not.toEqual(input);
+ expect(output).includes('dir="ltr"');
+ expect(output).toMatchInlineSnapshot(
+ '"<p>Some text in a paragraph:</p><pre dir=\\"ltr\\"><code>console.log(\'test\')</code></pre>"'
+ );
+});
diff --git a/packages/starlight/__tests__/remark-rehype/vitest.config.ts b/packages/starlight/__tests__/remark-rehype/vitest.config.ts
new file mode 100644
index 00000000..0b12dc3a
--- /dev/null
+++ b/packages/starlight/__tests__/remark-rehype/vitest.config.ts
@@ -0,0 +1,3 @@
+import { defineVitestConfig } from '../test-config';
+
+export default defineVitestConfig({ title: 'Remark-Rehype' });
diff --git a/packages/starlight/index.ts b/packages/starlight/index.ts
index dbd487bd..5909777e 100644
--- a/packages/starlight/index.ts
+++ b/packages/starlight/index.ts
@@ -8,6 +8,7 @@ import { starlightSitemap } from './integrations/sitemap';
import { vitePluginStarlightUserConfig } from './integrations/virtual-user-config';
import { errorMap } from './utils/error-map';
import { StarlightConfigSchema, StarlightUserConfig } from './utils/user-config';
+import { rehypeRtlCodeSupport } from './integrations/code-rtl-support';
export default function StarlightIntegration(opts: StarlightUserConfig): AstroIntegration[] {
const parsedConfig = StarlightConfigSchema.safeParse(opts, { errorMap });
@@ -39,6 +40,7 @@ export default function StarlightIntegration(opts: StarlightUserConfig): AstroIn
},
markdown: {
remarkPlugins: [...starlightAsides()],
+ rehypePlugins: [rehypeRtlCodeSupport()],
shikiConfig:
// Configure Shiki theme if the user is using the default github-dark theme.
config.markdown.shikiConfig.theme !== 'github-dark' ? {} : { theme: 'css-variables' },
diff --git a/packages/starlight/integrations/code-rtl-support.ts b/packages/starlight/integrations/code-rtl-support.ts
new file mode 100644
index 00000000..b8f7c3a6
--- /dev/null
+++ b/packages/starlight/integrations/code-rtl-support.ts
@@ -0,0 +1,31 @@
+import type { Root } from 'hastscript/lib/core';
+import { CONTINUE, SKIP, visit } from 'unist-util-visit';
+
+/**
+ * rehype plugin that adds `dir` attributes to `<code>` and `<pre>`
+ * elements that don’t already have them.
+ *
+ * `<code>` will become `<code dir="auto">`
+ * `<pre>` will become `<pre dir="ltr">`
+ *
+ * `<code>` _inside_ `<pre>` is skipped, so respects the `ltr` on its parent.
+ *
+ * Reasoning:
+ * - `<pre>` is usually a code block and code should be LTR even in an RTL document
+ * - `<code>` is often LTR, but could also be RTL. `dir="auto"` ensures the bidirectional
+ * algorithm treats the contents of `<code>` in isolation and gives its best guess.
+ */
+export function rehypeRtlCodeSupport() {
+ return () => (root: Root) => {
+ visit(root, 'element', (el) => {
+ if (el.tagName === 'pre' || el.tagName === 'code') {
+ el.properties ||= {};
+ if (!('dir' in el.properties)) {
+ el.properties.dir = { pre: 'ltr', code: 'auto' }[el.tagName];
+ }
+ return SKIP;
+ }
+ return CONTINUE;
+ });
+ };
+}