This commit is contained in:
parent
b48e346001
commit
f50e7e9b71
4 changed files with 48 additions and 35 deletions
34
README.md
34
README.md
|
|
@ -3,37 +3,3 @@
|
||||||
```sh
|
```sh
|
||||||
pnpm install https://git.methanium.net/methanium/ui/releases/download/latest/methanium-ui.tgz
|
pnpm install https://git.methanium.net/methanium/ui/releases/download/latest/methanium-ui.tgz
|
||||||
```
|
```
|
||||||
|
|
||||||
## Markdown
|
|
||||||
|
|
||||||
The renderer is available from the package root. The live editor, compact text
|
|
||||||
renderer, and emoji APIs use the `@methanium/ui/markdown` entry point.
|
|
||||||
|
|
||||||
```tsx
|
|
||||||
import { Markdown } from "@methanium/ui";
|
|
||||||
import {
|
|
||||||
EmojiProvider,
|
|
||||||
Input,
|
|
||||||
createEmojiRegistry,
|
|
||||||
} from "@methanium/ui/markdown";
|
|
||||||
|
|
||||||
const registry = createEmojiRegistry({
|
|
||||||
customEmojis: [
|
|
||||||
{
|
|
||||||
shortcode: ":party_parrot:",
|
|
||||||
aliases: [":parrot_party:"],
|
|
||||||
src: "/emoji/party-parrot.webp",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
<EmojiProvider registry={registry}>
|
|
||||||
<Input value={value} setValue={setValue} />
|
|
||||||
<Markdown content={value} />
|
|
||||||
</EmojiProvider>;
|
|
||||||
```
|
|
||||||
|
|
||||||
Custom shortcodes and aliases must be unique and may not collide with built-in
|
|
||||||
Twemoji names. Twemoji graphics are bundled locally and do not use a CDN. The
|
|
||||||
graphics are provided by the [Twemoji project](https://github.com/jdecked/twemoji)
|
|
||||||
under CC-BY 4.0; code is licensed under MIT.
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@methanium/ui",
|
"name": "@methanium/ui",
|
||||||
"version": "0.0.25",
|
"version": "0.0.26",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ import { EmojiProvider, useEmojiRegistry } from "./emoji-context";
|
||||||
import type { EmojiRegistry } from "./emoji-data";
|
import type { EmojiRegistry } from "./emoji-data";
|
||||||
import { parseCodeMeta, remarkCodeMeta } from "./markdown-meta";
|
import { parseCodeMeta, remarkCodeMeta } from "./markdown-meta";
|
||||||
import { remarkEmoji } from "./remark-emoji";
|
import { remarkEmoji } from "./remark-emoji";
|
||||||
|
import { remarkSmallMuted } from "./remark-small-muted";
|
||||||
|
|
||||||
export type MarkdownTheme = "light" | "dark";
|
export type MarkdownTheme = "light" | "dark";
|
||||||
export type MarkdownVariant = "article" | "compact";
|
export type MarkdownVariant = "article" | "compact";
|
||||||
|
|
@ -147,6 +148,7 @@ function Markdown({
|
||||||
remarkMath,
|
remarkMath,
|
||||||
remarkBreaks,
|
remarkBreaks,
|
||||||
remarkCodeMeta,
|
remarkCodeMeta,
|
||||||
|
remarkSmallMuted,
|
||||||
[remarkEmoji, { registry }],
|
[remarkEmoji, { registry }],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
||||||
45
src/markdown/remark-small-muted.ts
Normal file
45
src/markdown/remark-small-muted.ts
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
import type { Emphasis, Parent, Root, Text } from "mdast";
|
||||||
|
import { SKIP, visit } from "unist-util-visit";
|
||||||
|
|
||||||
|
const delimiter = "??++";
|
||||||
|
|
||||||
|
export function remarkSmallMuted() {
|
||||||
|
return (tree: Root) => {
|
||||||
|
visit(tree, "text", (node: Text, index, parent: Parent | undefined) => {
|
||||||
|
if (index === undefined || !parent) return;
|
||||||
|
|
||||||
|
const children: Parent["children"] = [];
|
||||||
|
let cursor = 0;
|
||||||
|
let opening = node.value.indexOf(delimiter);
|
||||||
|
|
||||||
|
while (opening !== -1) {
|
||||||
|
const contentStart = opening + delimiter.length;
|
||||||
|
const closing = node.value.indexOf(delimiter, contentStart);
|
||||||
|
if (closing === -1) break;
|
||||||
|
|
||||||
|
if (opening > cursor) {
|
||||||
|
children.push({ type: "text", value: node.value.slice(cursor, opening) });
|
||||||
|
}
|
||||||
|
children.push({
|
||||||
|
type: "emphasis",
|
||||||
|
children: [{ type: "text", value: node.value.slice(contentStart, closing) }],
|
||||||
|
data: {
|
||||||
|
hName: "span",
|
||||||
|
hProperties: { className: ["text-xs", "text-muted-foreground"] },
|
||||||
|
},
|
||||||
|
} satisfies Emphasis);
|
||||||
|
|
||||||
|
cursor = closing + delimiter.length;
|
||||||
|
opening = node.value.indexOf(delimiter, cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (children.length === 0) return;
|
||||||
|
if (cursor < node.value.length) {
|
||||||
|
children.push({ type: "text", value: node.value.slice(cursor) });
|
||||||
|
}
|
||||||
|
|
||||||
|
parent.children.splice(index, 1, ...children);
|
||||||
|
return [SKIP, index + children.length];
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue