Compare commits
15 commits
@cartamd/p
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
2177545454 | ||
|
a303834127 | ||
|
3fd18a6796 | ||
|
486a885704 | ||
|
8e5803a1c4 | ||
|
0ff9e5b124 | ||
|
eb114a7311 | ||
|
34d4f400e6 | ||
|
cc79b25288 | ||
|
a44b8e971d | ||
|
bafc86d8d3 | ||
|
a086ece088 | ||
|
dddaad1f1b | ||
|
7261d295e2 | ||
|
482fd4b8af |
13 changed files with 322 additions and 57 deletions
|
@ -45,6 +45,12 @@
|
||||||
<span class="text-[0.95rem]">Community Plugins</span>
|
<span class="text-[0.95rem]">Community Plugins</span>
|
||||||
</SidebarLink>
|
</SidebarLink>
|
||||||
|
|
||||||
|
<!-- Using Svelte Components -->
|
||||||
|
<SidebarLink href="/using-components">
|
||||||
|
<iconify-icon icon="ri:svelte-fill" class="text-xl"></iconify-icon>
|
||||||
|
<span class="text-[0.95rem]">Using Components</span>
|
||||||
|
</SidebarLink>
|
||||||
|
|
||||||
<h3 class="mb-3 ml-4 mt-6 text-sm font-medium first:mt-0 last:mb-0">Plugins</h3>
|
<h3 class="mb-3 ml-4 mt-6 text-sm font-medium first:mt-0 last:mb-0">Plugins</h3>
|
||||||
|
|
||||||
<!-- Math -->
|
<!-- Math -->
|
||||||
|
|
|
@ -46,8 +46,18 @@
|
||||||
@apply rounded bg-neutral-800 px-1 text-neutral-50;
|
@apply rounded bg-neutral-800 px-1 text-neutral-50;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p,
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3 {
|
||||||
|
code {
|
||||||
|
@apply px-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.carta-editor code {
|
.carta-editor code {
|
||||||
font-family: 'Fira Code', monospace;
|
font-family: 'Fira Code', monospace;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
|
padding: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,11 +43,39 @@ While the core styles are embedded in the Svelte components, the others can be s
|
||||||
|
|
||||||
### Using multiple themes
|
### Using multiple themes
|
||||||
|
|
||||||
By using the `theme` property in the editor you can differentiate the themes of multiple editors.
|
By using the `theme` property in `<MarkdownEditor>` you can differentiate the themes of multiple editors.
|
||||||
|
|
||||||
## Changing Markdown color theme
|
## Dark mode
|
||||||
|
|
||||||
Carta uses [Shiki](https://shiki.matsu.io/) for syntax highlighting. Two default themes are included in the core package, which are as a [dual theme](https://shiki.matsu.io/guide/dual-themes) used for light and dark mode.
|
When using dark mode, there are two different themes that have to be changed: the editor theme and the one used for syntax highlighting:
|
||||||
|
|
||||||
|
<Code>
|
||||||
|
|
||||||
|
```css
|
||||||
|
/* Editor dark mode */
|
||||||
|
/* Only if you are using the default theme */
|
||||||
|
html.dark .carta-theme__default {
|
||||||
|
--border-color: var(--border-color-dark);
|
||||||
|
--selection-color: var(--selection-color-dark);
|
||||||
|
--focus-outline: var(--focus-outline-dark);
|
||||||
|
--hover-color: var(--hover-color-dark);
|
||||||
|
--caret-color: var(--caret-color-dark);
|
||||||
|
--text-color: var(--text-color-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Code dark mode */
|
||||||
|
/* Only if you didn't specify a custom code theme */
|
||||||
|
html.dark .shiki,
|
||||||
|
html.dark .shiki span {
|
||||||
|
color: var(--shiki-dark) !important;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
</Code>
|
||||||
|
|
||||||
|
## Changing Markdown input color theme
|
||||||
|
|
||||||
|
Carta uses [Shiki](https://shiki.matsu.io/) for syntax highlighting. Two default themes are included in the core package, which are set as a [dual theme](https://shiki.matsu.io/guide/dual-themes) to support light and dark mode. If you plan to use a custom one with light/dark modes, make sure to use a dual theme as well.
|
||||||
|
|
||||||
You can change theme in the options:
|
You can change theme in the options:
|
||||||
|
|
||||||
|
@ -62,7 +90,7 @@ const carta = new Carta({
|
||||||
|
|
||||||
</Code>
|
</Code>
|
||||||
|
|
||||||
If you use a [custom theme](https://shiki.matsu.io/guide/load-theme)(or also a custom language), you need to specify it, so that it gets loaded into the highlighter:
|
If you use a [custom theme](https://shiki.matsu.io/guide/load-theme)(or a custom language), you need to provide it inside the options, so that it gets loaded into the highlighter:
|
||||||
|
|
||||||
<Code>
|
<Code>
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,8 @@ import 'carta-md/light.css'; // 👈 To be removed!
|
||||||
And also update the default theme. Previous based selectors should be removed:
|
And also update the default theme. Previous based selectors should be removed:
|
||||||
|
|
||||||
```css
|
```css
|
||||||
|
/* 👇 To be removed! */
|
||||||
[class*='shj-lang-'] {
|
[class*='shj-lang-'] {
|
||||||
/* 👈 To be removed! */
|
|
||||||
/* ... */
|
/* ... */
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -38,7 +38,7 @@ Many exports have been renamed to make them less verbose:
|
||||||
- `CartaRenderer` -> `Markdown` (old one still supported);
|
- `CartaRenderer` -> `Markdown` (old one still supported);
|
||||||
- `CartaEvent` -> `Event`;
|
- `CartaEvent` -> `Event`;
|
||||||
- `CartaEventType` -> `EventType`;
|
- `CartaEventType` -> `EventType`;
|
||||||
- `CartaExtension` -> `Extension`;
|
- `CartaExtension` -> `Plugin`;
|
||||||
- `CartaExtensionComponent` -> `ExtensionComponent`;
|
- `CartaExtensionComponent` -> `ExtensionComponent`;
|
||||||
- `CartaOptions` -> `Options`;
|
- `CartaOptions` -> `Options`;
|
||||||
- `CartaHistory` -> `TextAreaHistory`;
|
- `CartaHistory` -> `TextAreaHistory`;
|
||||||
|
|
217
docs/src/pages/using-components.svelte.md
Normal file
217
docs/src/pages/using-components.svelte.md
Normal file
|
@ -0,0 +1,217 @@
|
||||||
|
---
|
||||||
|
title: Using Svelte Components
|
||||||
|
section: Overview
|
||||||
|
---
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Code from '$lib/components/code/Code.svelte';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
Svelte components can be embedded into the rendered HTML to make certain elements interactive. However, they require a bit more work, as Remark is configured to only render static HTML. To get around this, the idea is to do the following:
|
||||||
|
|
||||||
|
1. Create a Unified plugin to isolate the targeted element;
|
||||||
|
2. Replace all the elements with the component, after every render.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
Let's say we want to replace all hashtags, such as `#something`, with a custom component. Here is as example of how that could be achieved.
|
||||||
|
|
||||||
|
### Parsing the hashtags
|
||||||
|
|
||||||
|
First things first: we need to tell the parser that we want to parse hashtags as custom elements. To do this, it's useful to first install the following packages:
|
||||||
|
|
||||||
|
<Code>
|
||||||
|
|
||||||
|
```shell
|
||||||
|
npm i unist-util-visit
|
||||||
|
# Types
|
||||||
|
npm i -D unified hast
|
||||||
|
```
|
||||||
|
|
||||||
|
</Code>
|
||||||
|
|
||||||
|
Let's create a Unified plugin. The basic structure of a plugin is the following:
|
||||||
|
|
||||||
|
<Code>
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import type { Plugin as UnifiedPlugin } from 'unified'
|
||||||
|
import { SKIP, visit } from 'unist-util-visit'
|
||||||
|
|
||||||
|
const unifiedPlugin: UnifiedPlugin<[], hast.Root> = () => {
|
||||||
|
return function (tree) {
|
||||||
|
// Visit every node in the syntax tree
|
||||||
|
visit(tree, (node, index, parent) => {
|
||||||
|
// Do something with the node
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
</Code>
|
||||||
|
|
||||||
|
We now want to parse text nodes, so that words such as `#pizza` and `#123` are separated from the rest. This is a possible implementation:
|
||||||
|
|
||||||
|
<Code>
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const unifiedPlugin: UnifiedPlugin<[], hast.Root> = () => {
|
||||||
|
return function (tree) {
|
||||||
|
visit(tree, (node, index, parent) => {
|
||||||
|
// Skip code blocks and their children
|
||||||
|
if (node.type === 'element' && node.tagName === 'pre') return [SKIP];
|
||||||
|
// Skip non-text nodes
|
||||||
|
if (node.type !== 'text') return;
|
||||||
|
const text = node as hast.Text;
|
||||||
|
|
||||||
|
// Parse the text node and replace hashtags with spans
|
||||||
|
const regex = /#(\w+)/g;
|
||||||
|
const children: (hast.Element | hast.Text)[] = [];
|
||||||
|
let lastIndex = 0;
|
||||||
|
let match;
|
||||||
|
while ((match = regex.exec(text.value))) {
|
||||||
|
const before = text.value.slice(lastIndex, match.index);
|
||||||
|
if (before) {
|
||||||
|
children.push({ type: 'text', value: before });
|
||||||
|
}
|
||||||
|
children.push({
|
||||||
|
type: 'element',
|
||||||
|
tagName: 'span',
|
||||||
|
properties: { type: 'hashtag', value: match[1] },
|
||||||
|
children: [{ type: 'text', value: match[0] }]
|
||||||
|
});
|
||||||
|
lastIndex = regex.lastIndex;
|
||||||
|
}
|
||||||
|
if (lastIndex < text.value.length) {
|
||||||
|
children.push({ type: 'text', value: text.value.slice(lastIndex) });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace the text node with all the children
|
||||||
|
parent!.children.splice(index!, 1, ...children);
|
||||||
|
|
||||||
|
// Skip the children
|
||||||
|
return [SKIP, index! + children.length];
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
</Code>
|
||||||
|
|
||||||
|
If you want a more in-depth guide on writing Unified plugins, you can check out the official [documentation](https://unifiedjs.com/learn/guide/create-a-plugin/).
|
||||||
|
|
||||||
|
Notice that hashtags are now replaced with the following:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<span type="hashtag" value="pizza"> #pizza </span>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuring the transformer
|
||||||
|
|
||||||
|
Unified plugins need to be wrapped inside a `UnifiedTransformer` type, to be able to be used in Carta.
|
||||||
|
|
||||||
|
<Code>
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import type { UnifiedTransformer } from 'carta-md';
|
||||||
|
|
||||||
|
const hashtagTransformer: UnifiedTransformer<'sync'> = {
|
||||||
|
execution: 'sync', // Sync, since the plugin is synchronous
|
||||||
|
type: 'rehype', // Rehype, since it operates on HTML
|
||||||
|
transform({ processor }) {
|
||||||
|
processor.use(unifiedPlugin);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
</Code>
|
||||||
|
|
||||||
|
### Mounting the components
|
||||||
|
|
||||||
|
We now want to replace the generated hashtag placeholders with the following element:
|
||||||
|
|
||||||
|
<Code>
|
||||||
|
|
||||||
|
```svelte
|
||||||
|
<!-- Hashtag.svelte -->
|
||||||
|
<script>
|
||||||
|
export let value;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button
|
||||||
|
on:click={() => {
|
||||||
|
console.log('Hashtag clicked!');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
#{value}
|
||||||
|
</button>
|
||||||
|
```
|
||||||
|
|
||||||
|
</Code>
|
||||||
|
|
||||||
|
To do that, we create a listener that:
|
||||||
|
|
||||||
|
1. Finds all the previous placeholders;
|
||||||
|
2. Mounts the component next to them;
|
||||||
|
3. Removes the placeholders.
|
||||||
|
|
||||||
|
<Code>
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import type { Listener } from 'carta-md';
|
||||||
|
import Hashtag from './Hashtag.svelte';
|
||||||
|
|
||||||
|
const convertHashtags: Listener<'carta-render'> = [
|
||||||
|
'carta-render',
|
||||||
|
function onRender({ detail: { carta } }) {
|
||||||
|
const rendererContainer = carta.renderer?.container;
|
||||||
|
if (!rendererContainer) return;
|
||||||
|
|
||||||
|
// Find all hashtag spans and replace them with Svelte components
|
||||||
|
const hashtagSpans = rendererContainer.querySelectorAll('span[type="hashtag"]');
|
||||||
|
for (const span of hashtagSpans) {
|
||||||
|
const hashtag = span.getAttribute('value') ?? '';
|
||||||
|
|
||||||
|
new Hashtag({
|
||||||
|
target: span.parentElement!,
|
||||||
|
anchor: span,
|
||||||
|
props: { value: hashtag }
|
||||||
|
});
|
||||||
|
|
||||||
|
span.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
```
|
||||||
|
|
||||||
|
</Code>
|
||||||
|
|
||||||
|
### Using the plugin
|
||||||
|
|
||||||
|
Let's now create a Plugin with the transformer and the listener:
|
||||||
|
|
||||||
|
<Code>
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import type { Plugin } from 'carta-md';
|
||||||
|
|
||||||
|
export const hashtag = (): Plugin => ({
|
||||||
|
transformers: [hashtagTransformer],
|
||||||
|
listeners: [convertHashtags]
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
</Code>
|
||||||
|
|
||||||
|
We can now use the plugin with the following:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { Carta } from 'carta-md';
|
||||||
|
|
||||||
|
const carta = new Carta({
|
||||||
|
// ...
|
||||||
|
extensions: [hashtag()]
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
You can find the example source code [here](https://github.com/BearToCode/svelte-in-carta-example).
|
|
@ -39,7 +39,7 @@
|
||||||
"remark-gfm": "^4.0.0",
|
"remark-gfm": "^4.0.0",
|
||||||
"remark-parse": "^11.0.0",
|
"remark-parse": "^11.0.0",
|
||||||
"remark-rehype": "^11.1.0",
|
"remark-rehype": "^11.1.0",
|
||||||
"shiki": "^1.3.0",
|
"shiki": "^1.4.0",
|
||||||
"unified": "^11.0.4"
|
"unified": "^11.0.4"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
|
|
@ -63,18 +63,14 @@
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const normalize = (text: string) => {
|
|
||||||
return text.replaceAll('\r\n', '\n');
|
|
||||||
};
|
|
||||||
|
|
||||||
const highlightNestedLanguages = debounce(async (text: string) => {
|
const highlightNestedLanguages = debounce(async (text: string) => {
|
||||||
const highlighter = await carta.highlighter();
|
const highlighter = await carta.highlighter();
|
||||||
const { updated } = await loadNestedLanguages(highlighter, text);
|
const { updated } = await loadNestedLanguages(highlighter, text);
|
||||||
if (updated) highlight(text);
|
if (updated) highlight(text);
|
||||||
}, 300);
|
}, 300);
|
||||||
|
|
||||||
$: highlight(normalize(value)).then(resize);
|
$: highlight(value).then(resize);
|
||||||
$: highlightNestedLanguages(normalize(value));
|
$: highlightNestedLanguages(value);
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
mounted = true;
|
mounted = true;
|
||||||
|
|
|
@ -249,6 +249,8 @@ const findNestedLanguages = (text: string) => {
|
||||||
* @returns Whether the highlighter was updated with new languages.
|
* @returns Whether the highlighter was updated with new languages.
|
||||||
*/
|
*/
|
||||||
export const loadNestedLanguages = async (highlighter: Highlighter, text: string) => {
|
export const loadNestedLanguages = async (highlighter: Highlighter, text: string) => {
|
||||||
|
text = text.replaceAll('\r\n', '\n'); // Normalize line endings
|
||||||
|
|
||||||
const languages = findNestedLanguages(text);
|
const languages = findNestedLanguages(text);
|
||||||
const loadedLanguages = highlighter.getLoadedLanguages();
|
const loadedLanguages = highlighter.getLoadedLanguages();
|
||||||
let updated = false;
|
let updated = false;
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
.carta-renderer h1,
|
.carta-viewer h1,
|
||||||
.carta-renderer h2,
|
.carta-viewer h2,
|
||||||
.carta-renderer h3,
|
.carta-viewer h3,
|
||||||
.carta-renderer h4,
|
.carta-viewer h4,
|
||||||
.carta-renderer h5,
|
.carta-viewer h5,
|
||||||
.carta-renderer h6 {
|
.carta-viewer h6 {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.carta-renderer h1 .icon.icon-link,
|
.carta-viewer h1 .icon.icon-link,
|
||||||
.carta-renderer h2 .icon.icon-link,
|
.carta-viewer h2 .icon.icon-link,
|
||||||
.carta-renderer h3 .icon.icon-link,
|
.carta-viewer h3 .icon.icon-link,
|
||||||
.carta-renderer h4 .icon.icon-link,
|
.carta-viewer h4 .icon.icon-link,
|
||||||
.carta-renderer h5 .icon.icon-link,
|
.carta-viewer h5 .icon.icon-link,
|
||||||
.carta-renderer h6 .icon.icon-link {
|
.carta-viewer h6 .icon.icon-link {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
content: url('./link.svg');
|
content: url('./link.svg');
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -22,11 +22,11 @@
|
||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.carta-renderer h1:hover .icon-link,
|
.carta-viewer h1:hover .icon-link,
|
||||||
.carta-renderer h2:hover .icon-link,
|
.carta-viewer h2:hover .icon-link,
|
||||||
.carta-renderer h3:hover .icon-link,
|
.carta-viewer h3:hover .icon-link,
|
||||||
.carta-renderer h4:hover .icon-link,
|
.carta-viewer h4:hover .icon-link,
|
||||||
.carta-renderer h5:hover .icon-link,
|
.carta-viewer h5:hover .icon-link,
|
||||||
.carta-renderer h6:hover .icon-link {
|
.carta-viewer h6:hover .icon-link {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
# Carta Code Plugin
|
# Carta Code Plugin
|
||||||
|
|
||||||
This plugin adds support for code blocks **syntax highlighting**. Install it using:
|
This plugin adds support for code blocks **syntax highlighting**. It uses the same highlighter from the core package(Shiki).
|
||||||
|
|
||||||
```
|
```
|
||||||
npm i @cartamd/plugin-code
|
npm i @cartamd/plugin-code
|
||||||
```
|
```
|
||||||
|
|
||||||
This is done using [Speed-highlight JS](https://github.com/speed-highlight/core), which supports dynamic imports. This way, languages definitions are only imported at the moment of need.
|
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
### Styles
|
### Styles
|
||||||
|
@ -20,7 +18,7 @@ import '@cartamd/plugin-code/default.css';
|
||||||
|
|
||||||
### Using the default highlighter
|
### Using the default highlighter
|
||||||
|
|
||||||
Carta comes with a default highlighter that matches the one used to highlight markdown in the editor and is used by default (Shiki). If you want to use a theme different from the one used to highlight Markdown, you can specify it in the options.
|
Carta comes with a default highlighter that matches the one used to highlight markdown in the editor and is used by default (Shiki). If you want to use a theme different from the one used to highlight Markdown, you can specify it in the options. Remember to also have it loaded into the highlighter, by specifying it in `shikiOptions`.
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
const carta = new Carta({
|
const carta = new Carta({
|
||||||
|
@ -29,7 +27,10 @@ const carta = new Carta({
|
||||||
code({
|
code({
|
||||||
theme: 'ayu-light'
|
theme: 'ayu-light'
|
||||||
})
|
})
|
||||||
]
|
],
|
||||||
|
shikiOptions: {
|
||||||
|
themes: ['ayu-light']
|
||||||
|
}
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
"build": "tsc && tscp"
|
"build": "tsc && tscp"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@shikijs/rehype": "^1.3.0",
|
"@shikijs/rehype": "^1.4.0",
|
||||||
"@types/node": "^18.16.3",
|
"@types/node": "^18.16.3",
|
||||||
"carta-md": "workspace:*",
|
"carta-md": "workspace:*",
|
||||||
"typescript": "^5.0.4",
|
"typescript": "^5.0.4",
|
||||||
|
@ -30,7 +30,7 @@
|
||||||
],
|
],
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@shikijs/rehype": "^1.3.0",
|
"@shikijs/rehype": "^1.4.0",
|
||||||
"unified": "^11.0.4"
|
"unified": "^11.0.4"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
|
|
@ -86,14 +86,18 @@ const tikzTransformer: UnifiedPlugin<
|
||||||
hast.Root
|
hast.Root
|
||||||
> = ({ carta, options }) => {
|
> = ({ carta, options }) => {
|
||||||
return async function (tree) {
|
return async function (tree) {
|
||||||
visit(tree, (node, index, parent) => {
|
visit(tree, (pre, index, parent) => {
|
||||||
if (typeof document === 'undefined') {
|
if (typeof document === 'undefined') {
|
||||||
// Cannot run outside the browser
|
// Cannot run outside the browser
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node.type !== 'element') return;
|
if (pre.type !== 'element') return;
|
||||||
const element = node as hast.Element;
|
const preElement = pre as hast.Element;
|
||||||
|
if (preElement.tagName !== 'pre') return;
|
||||||
|
const element = pre.children.at(0) as hast.Element | undefined;
|
||||||
|
if (!element) return;
|
||||||
|
|
||||||
if (element.tagName !== 'code') return;
|
if (element.tagName !== 'code') return;
|
||||||
if (!element.properties['className']) return;
|
if (!element.properties['className']) return;
|
||||||
if (!(element.properties['className'] as string[]).includes('language-tikz')) return;
|
if (!(element.properties['className'] as string[]).includes('language-tikz')) return;
|
||||||
|
@ -130,6 +134,7 @@ const tikzTransformer: UnifiedPlugin<
|
||||||
}
|
}
|
||||||
|
|
||||||
const hastNode = fromDom(container) as hast.Element;
|
const hastNode = fromDom(container) as hast.Element;
|
||||||
|
|
||||||
parent?.children.splice(index!, 1, hastNode);
|
parent?.children.splice(index!, 1, hastNode);
|
||||||
|
|
||||||
return [SKIP, index!];
|
return [SKIP, index!];
|
||||||
|
|
32
pnpm-lock.yaml
generated
32
pnpm-lock.yaml
generated
|
@ -172,8 +172,8 @@ importers:
|
||||||
specifier: ^11.1.0
|
specifier: ^11.1.0
|
||||||
version: 11.1.0
|
version: 11.1.0
|
||||||
shiki:
|
shiki:
|
||||||
specifier: ^1.3.0
|
specifier: ^1.4.0
|
||||||
version: 1.3.0
|
version: 1.4.0
|
||||||
svelte:
|
svelte:
|
||||||
specifier: ^3.54.0 || ^4.0.0
|
specifier: ^3.54.0 || ^4.0.0
|
||||||
version: 4.2.2
|
version: 4.2.2
|
||||||
|
@ -297,8 +297,8 @@ importers:
|
||||||
packages/plugin-code:
|
packages/plugin-code:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@shikijs/rehype':
|
'@shikijs/rehype':
|
||||||
specifier: ^1.3.0
|
specifier: ^1.4.0
|
||||||
version: 1.3.0
|
version: 1.4.0
|
||||||
unified:
|
unified:
|
||||||
specifier: ^11.0.4
|
specifier: ^11.0.4
|
||||||
version: 11.0.4
|
version: 11.0.4
|
||||||
|
@ -1422,25 +1422,25 @@ packages:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@shikijs/core@1.3.0:
|
/@shikijs/core@1.4.0:
|
||||||
resolution: {integrity: sha512-7fedsBfuILDTBmrYZNFI8B6ATTxhQAasUHllHmjvSZPnoq4bULWoTpHwmuQvZ8Aq03/tAa2IGo6RXqWtHdWaCA==}
|
resolution: {integrity: sha512-CxpKLntAi64h3j+TwWqVIQObPTED0FyXLHTTh3MKXtqiQNn2JGcMQQ362LftDbc9kYbDtrksNMNoVmVXzKFYUQ==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@shikijs/rehype@1.3.0:
|
/@shikijs/rehype@1.4.0:
|
||||||
resolution: {integrity: sha512-CknEidx0ZTg3TeYAPU4ah8cr31a16neBbMyQ5kwAVdkloCe65uhQp+C/FEFs8NRir4eU5XCDA/+w2v5wnN6zgQ==}
|
resolution: {integrity: sha512-Ba6QHYx+EIEvmqyNy/B49KAz3rXsTfAqYRY3KTZjPWonytokGOiJ1q/FV9l13D/ad6Qv+eWKhkAz6ITxx6ziFA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@shikijs/transformers': 1.3.0
|
'@shikijs/transformers': 1.4.0
|
||||||
'@types/hast': 3.0.4
|
'@types/hast': 3.0.4
|
||||||
hast-util-to-string: 3.0.0
|
hast-util-to-string: 3.0.0
|
||||||
shiki: 1.3.0
|
shiki: 1.4.0
|
||||||
unified: 11.0.4
|
unified: 11.0.4
|
||||||
unist-util-visit: 5.0.0
|
unist-util-visit: 5.0.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@shikijs/transformers@1.3.0:
|
/@shikijs/transformers@1.4.0:
|
||||||
resolution: {integrity: sha512-3mlpg2I9CjhjE96dEWQOGeCWoPcyTov3s4aAsHmgvnTHa8MBknEnCQy8/xivJPSpD+olqOqIEoHnLfbNJK29AA==}
|
resolution: {integrity: sha512-kzvlWmWYYSeaLKRce/kgmFFORUtBtFahfXRKndor0b60ocYiXufBQM6d6w1PlMuUkdk55aor9xLvy9wy7hTEJg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
shiki: 1.3.0
|
shiki: 1.4.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@sveltejs/adapter-auto@3.1.1(@sveltejs/kit@2.5.4):
|
/@sveltejs/adapter-auto@3.1.1(@sveltejs/kit@2.5.4):
|
||||||
|
@ -6435,10 +6435,10 @@ packages:
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/shiki@1.3.0:
|
/shiki@1.4.0:
|
||||||
resolution: {integrity: sha512-9aNdQy/etMXctnPzsje1h1XIGm9YfRcSksKOGqZWXA/qP9G18/8fpz5Bjpma8bOgz3tqIpjERAd6/lLjFyzoww==}
|
resolution: {integrity: sha512-5WIn0OL8PWm7JhnTwRWXniy6eEDY234mRrERVlFa646V2ErQqwIFd2UML7e0Pq9eqSKLoMa3Ke+xbsF+DAuy+Q==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@shikijs/core': 1.3.0
|
'@shikijs/core': 1.4.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/signal-exit@3.0.7:
|
/signal-exit@3.0.7:
|
||||||
|
|
Loading…
Add table
Reference in a new issue