@tinacms/mdx 2.2.3 → 2.4.0
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/dist/index.browser.js +1316 -14802
- package/dist/index.js +1320 -14806
- package/dist/next/parse/color-marks.d.ts +10 -0
- package/dist/next/tests/markdown-basic-marks-text-color/field.d.ts +2 -0
- package/dist/next/tests/markdown-basic-marks-text-color/index.test.d.ts +1 -0
- package/dist/next/tests/markdown-basic-marks-text-color-html/field.d.ts +2 -0
- package/dist/next/tests/markdown-basic-marks-text-color-html/index.test.d.ts +1 -0
- package/dist/parse/index.d.ts +3 -3
- package/dist/parse/mark.d.ts +15 -1
- package/dist/parse/mdx.d.ts +4 -4
- package/dist/parse/plate.d.ts +2 -0
- package/dist/parse/remarkToPlate.d.ts +2 -2
- package/dist/sanitize-css-color.d.ts +17 -0
- package/dist/sanitize-css-color.js +43 -0
- package/dist/sanitize-css-color.test.d.ts +1 -0
- package/dist/stringify/index.d.ts +5 -5
- package/dist/stringify/marks.d.ts +2 -2
- package/dist/stringify/print-object-literal.corpus.d.ts +12 -0
- package/dist/stringify/print-object-literal.d.ts +1 -0
- package/dist/stringify/print-object-literal.snapshot.d.ts +12 -0
- package/dist/stringify/print-object-literal.test.d.ts +1 -0
- package/dist/stringify/text-color.d.ts +19 -0
- package/dist/stringify/text-color.test.d.ts +1 -0
- package/package.json +12 -5
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Node } from 'unist';
|
|
2
|
+
/**
|
|
3
|
+
* Markdown has no JSX, so text colour is written as HTML
|
|
4
|
+
* (`<span style="color: …">…</span>`) and arrives here as separate
|
|
5
|
+
* opening/closing `html` nodes. Folds each matched
|
|
6
|
+
* pair (siblings inside the same inline parent) into a JSX element so it
|
|
7
|
+
* parses into marks just like the MDX form. Tags at block level, and tags we
|
|
8
|
+
* wouldn't claim, are left as raw HTML.
|
|
9
|
+
*/
|
|
10
|
+
export declare const foldColorMarkHtml: <T extends Node>(node: T) => T;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/parse/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
*/
|
|
6
|
-
import type {
|
|
6
|
+
import type { RichTextField } from '@tinacms/schema-tools';
|
|
7
7
|
import type * as Plate from './plate';
|
|
8
8
|
import { RichTextParseError } from './remarkToPlate';
|
|
9
9
|
/**
|
|
@@ -55,10 +55,10 @@ import { RichTextParseError } from './remarkToPlate';
|
|
|
55
55
|
* 2. We don't need to do any client-side parsing. Since TinaMarkdown and the slate editor work with the same
|
|
56
56
|
* format we can just allow Tina to do it's thing and update the form value with no additional work.
|
|
57
57
|
*/
|
|
58
|
-
export declare const markdownToAst: (value: string, field:
|
|
58
|
+
export declare const markdownToAst: (value: string, field: RichTextField) => import("mdast").Root;
|
|
59
59
|
export declare const mdxToAst: (value: string) => import("mdast").Root;
|
|
60
60
|
export declare const MDX_PARSE_ERROR_MSG = "TinaCMS supports a stricter version of markdown and a subset of MDX. https://tina.io/docs/r/what-is-markdown";
|
|
61
61
|
export declare const MDX_PARSE_ERROR_MSG_HTML = "TinaCMS supports a stricter version of markdown and a subset of MDX. <a href=\"https://tina.io/docs/r/what-is-markdown\" target=\"_blank\" rel=\"noopener noreferrer\">Learn More</a>";
|
|
62
|
-
export declare const parseMDX: (value: string, field:
|
|
62
|
+
export declare const parseMDX: (value: string, field: RichTextField, imageCallback: (s: string) => string) => Plate.RootElement;
|
|
63
63
|
export declare const invalidMarkdown: (e: RichTextParseError, value: string) => Plate.RootElement;
|
|
64
64
|
export declare const replaceAll: (string: string, target: string, value: string) => string;
|
package/dist/parse/mark.d.ts
CHANGED
|
@@ -1,7 +1,21 @@
|
|
|
1
1
|
import type { PhrasingContent } from 'mdast';
|
|
2
2
|
import type { MdxJsxAttribute, MdxJsxExpressionAttribute, MdxJsxTextElement } from 'mdast-util-mdx-jsx';
|
|
3
3
|
import type * as Plate from './plate';
|
|
4
|
+
type ColorMarks = Pick<Plate.TextElement, 'highlight' | 'highlightColor' | 'textColor'>;
|
|
4
5
|
export declare const getHighlightColorFromAttributes: (attributes?: (MdxJsxAttribute | MdxJsxExpressionAttribute)[]) => string | undefined;
|
|
6
|
+
/**
|
|
7
|
+
* The Plate marks a `<mark>` or text colour `<span>` stands for, or null when
|
|
8
|
+
* the element isn't one of ours. A `<span>` is only claimed when its sole
|
|
9
|
+
* attribute is a style holding just a safe `color`, so spans carrying
|
|
10
|
+
* anything else keep round-tripping as raw HTML.
|
|
11
|
+
*/
|
|
12
|
+
export declare const getColorMarks: (content: MdxJsxTextElement) => ColorMarks | null;
|
|
13
|
+
/**
|
|
14
|
+
* Converts `<mark>` (highlight) and `<span style={{ color }}>` (text colour)
|
|
15
|
+
* into marked text nodes. Children are parsed with `parseChild`, so nested
|
|
16
|
+
* bold/italic/etc. keep their marks. Returns null for any other element.
|
|
17
|
+
*/
|
|
5
18
|
export declare const parseMarkMdxText: <TChild extends PhrasingContent = PhrasingContent>(content: MdxJsxTextElement & {
|
|
6
19
|
children?: TChild[];
|
|
7
|
-
}, extraMarks?: Record<string, boolean
|
|
20
|
+
}, extraMarks?: Record<string, boolean>, parseChild?: (child: TChild) => Plate.InlineElement | Plate.InlineElement[]) => Plate.InlineElement[] | null;
|
|
21
|
+
export {};
|
package/dist/parse/mdx.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { RichTextField } from '@tinacms/schema-tools';
|
|
2
2
|
import { ContainerDirective } from 'mdast-util-directive';
|
|
3
3
|
import { LeafDirective } from 'mdast-util-directive/lib';
|
|
4
4
|
/**
|
|
@@ -8,6 +8,6 @@ import { LeafDirective } from 'mdast-util-directive/lib';
|
|
|
8
8
|
*/
|
|
9
9
|
import type { MdxJsxFlowElement, MdxJsxTextElement } from 'mdast-util-mdx-jsx';
|
|
10
10
|
import type * as Plate from './plate';
|
|
11
|
-
export declare function mdxJsxElement(node: MdxJsxTextElement, field:
|
|
12
|
-
export declare function mdxJsxElement(node: MdxJsxFlowElement, field:
|
|
13
|
-
export declare const directiveElement: (node: ContainerDirective | LeafDirective, field:
|
|
11
|
+
export declare function mdxJsxElement(node: MdxJsxTextElement, field: RichTextField, imageCallback: (url: string) => string): Plate.MdxInlineElement;
|
|
12
|
+
export declare function mdxJsxElement(node: MdxJsxFlowElement, field: RichTextField, imageCallback: (url: string) => string): Plate.MdxBlockElement;
|
|
13
|
+
export declare const directiveElement: (node: ContainerDirective | LeafDirective, field: RichTextField, imageCallback: (url: string) => string, raw?: string) => Plate.BlockElement | Plate.ParagraphElement;
|
package/dist/parse/plate.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
*/
|
|
6
|
-
import type {
|
|
6
|
+
import type { RichTextField } from '@tinacms/schema-tools';
|
|
7
7
|
import type * as Md from 'mdast';
|
|
8
8
|
import type { ContainerDirective } from 'mdast-util-directive';
|
|
9
9
|
import type { MdxJsxFlowElement, MdxJsxTextElement } from 'mdast-util-mdx-jsx';
|
|
@@ -24,7 +24,7 @@ declare module 'mdast' {
|
|
|
24
24
|
mdxJsxFlowElement: MdxJsxFlowElement;
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
-
export declare const remarkToSlate: (root: Md.Root | MdxJsxFlowElement | MdxJsxTextElement | ContainerDirective, field:
|
|
27
|
+
export declare const remarkToSlate: (root: Md.Root | MdxJsxFlowElement | MdxJsxTextElement | ContainerDirective, field: RichTextField, imageCallback: (url: string) => string, raw?: string, skipMDXProcess?: boolean) => Plate.RootElement;
|
|
28
28
|
export declare class RichTextParseError extends Error {
|
|
29
29
|
position?: Plate.Position;
|
|
30
30
|
constructor(message: string, position?: Plate.Position);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validates CSS colours from rich-text colour marks.
|
|
3
|
+
*
|
|
4
|
+
* This file is intentionally dependency-free — it's built as its own entry point
|
|
5
|
+
* (`@tinacms/mdx/sanitize-css-color`) so renderers and editors that only need
|
|
6
|
+
* colour validation (eg. `tinacms`'s rich-text renderer) don't pull in the
|
|
7
|
+
* markdown-parsing toolchain the rest of `@tinacms/mdx` bundles.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Whether `value` is a plain CSS colour that's safe to drop into a `style`:
|
|
11
|
+
* hex, a named colour, or colour functions (`rgb()`, `hsl()`, `lab()`,
|
|
12
|
+
* `oklch()`, `color-mix()`, `var(--name, fallback)` and the like) nested only
|
|
13
|
+
* in each other. Anything else (`;`, braces, quotes, comments, `url(`) is
|
|
14
|
+
* rejected so a colour can't smuggle in extra CSS. Used when parsing and
|
|
15
|
+
* rendering rich-text text colour and highlight colour.
|
|
16
|
+
*/
|
|
17
|
+
export declare const isSafeCssColor: (value: string) => boolean;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
const COLOR_FUNCTIONS = /* @__PURE__ */ new Set([
|
|
2
|
+
"rgb",
|
|
3
|
+
"rgba",
|
|
4
|
+
"hsl",
|
|
5
|
+
"hsla",
|
|
6
|
+
"hwb",
|
|
7
|
+
"lab",
|
|
8
|
+
"lch",
|
|
9
|
+
"oklab",
|
|
10
|
+
"oklch",
|
|
11
|
+
"color",
|
|
12
|
+
"color-mix",
|
|
13
|
+
"light-dark",
|
|
14
|
+
"calc",
|
|
15
|
+
"var"
|
|
16
|
+
]);
|
|
17
|
+
const isSafeColorFunction = (value) => {
|
|
18
|
+
if (!/^[a-z-]+\([a-z0-9_.,%/#() +-]*\)$/i.test(value)) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
let depth = 0;
|
|
22
|
+
for (const [token, name = ""] of value.matchAll(/([a-z-]*)\(|\)/gi)) {
|
|
23
|
+
if (token === ")") {
|
|
24
|
+
depth--;
|
|
25
|
+
} else if (COLOR_FUNCTIONS.has(name.toLowerCase())) {
|
|
26
|
+
depth++;
|
|
27
|
+
} else {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
if (depth < 0) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return depth === 0;
|
|
35
|
+
};
|
|
36
|
+
const isSafeCssColor = (value) => {
|
|
37
|
+
const trimmed = value.trim();
|
|
38
|
+
const color = trimmed.toLowerCase().endsWith("!important") ? trimmed.slice(0, -"!important".length).trimEnd() : trimmed;
|
|
39
|
+
return /^#(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i.test(color) || /^[a-z]+$/i.test(color) || isSafeColorFunction(color);
|
|
40
|
+
};
|
|
41
|
+
export {
|
|
42
|
+
isSafeCssColor
|
|
43
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { RichTextField } from '@tinacms/schema-tools';
|
|
2
2
|
import type * as Md from 'mdast';
|
|
3
3
|
import { MdxJsxFlowElement, MdxJsxTextElement } from 'mdast-util-mdx-jsx';
|
|
4
4
|
import type * as Plate from '../parse/plate';
|
|
@@ -16,7 +16,7 @@ declare module 'mdast' {
|
|
|
16
16
|
mdxJsxFlowElement: MdxJsxFlowElement;
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
|
-
export declare const serializeMDX: (value: Plate.RootElement, field:
|
|
19
|
+
export declare const serializeMDX: (value: Plate.RootElement, field: RichTextField, imageCallback: (url: string) => string) => string | Plate.RootElement | undefined;
|
|
20
20
|
export type Pattern = {
|
|
21
21
|
start: string;
|
|
22
22
|
end: string;
|
|
@@ -24,9 +24,9 @@ export type Pattern = {
|
|
|
24
24
|
templateName: string;
|
|
25
25
|
type: 'block' | 'leaf';
|
|
26
26
|
};
|
|
27
|
-
export declare const toTinaMarkdown: (tree: Md.Root, field:
|
|
28
|
-
export declare const rootElement: (content: Plate.RootElement, field:
|
|
27
|
+
export declare const toTinaMarkdown: (tree: Md.Root, field: RichTextField) => string;
|
|
28
|
+
export declare const rootElement: (content: Plate.RootElement, field: RichTextField, imageCallback: (url: string) => string) => Md.Root;
|
|
29
29
|
export declare function codeLinesToString(content: Plate.CodeBlockElement): string;
|
|
30
|
-
export declare const blockElement: (content: Plate.BlockElement, field:
|
|
30
|
+
export declare const blockElement: (content: Plate.BlockElement, field: RichTextField, imageCallback: (url: string) => string) => Md.Content | null;
|
|
31
31
|
export type Marks = 'strong' | 'emphasis' | 'inlineCode' | 'delete' | 'highlight';
|
|
32
32
|
export declare const getMarks: (content: Plate.InlineElement) => Marks[];
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
*/
|
|
6
|
-
import type {
|
|
6
|
+
import type { RichTextField } from '@tinacms/schema-tools';
|
|
7
7
|
import type * as Md from 'mdast';
|
|
8
8
|
import type * as Plate from '../parse/plate';
|
|
9
9
|
type InlineElementWithCallback = Plate.InlineElement & {
|
|
10
10
|
linkifyTextNode?: (arg: Md.Text) => Md.Link;
|
|
11
11
|
};
|
|
12
|
-
export declare const eat: (c: InlineElementWithCallback[], field:
|
|
12
|
+
export declare const eat: (c: InlineElementWithCallback[], field: RichTextField, imageCallback: (url: string) => string) => Md.PhrasingContent[];
|
|
13
13
|
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The differential corpus for `printObjectLiteral`. Every case is
|
|
3
|
+
* deterministic, so the expected output of each one is recorded in
|
|
4
|
+
* `__snapshots__/print-object-literal.txt` by `pnpm snapshot:print-object-literal`.
|
|
5
|
+
* Append new cases; never reorder or rename existing ones.
|
|
6
|
+
*/
|
|
7
|
+
export type Case = {
|
|
8
|
+
name: string;
|
|
9
|
+
value: unknown;
|
|
10
|
+
};
|
|
11
|
+
export declare const corpus: Case[];
|
|
12
|
+
export declare const MINIMUM_CORPUS = 5000;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const printObjectLiteral: (value: unknown) => string;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One record per corpus case, in corpus order. Blank lines separate records;
|
|
3
|
+
* neither a `JSON.stringify` input nor a printed object literal contains one.
|
|
4
|
+
*/
|
|
5
|
+
export type SnapshotRecord = {
|
|
6
|
+
index: number;
|
|
7
|
+
name: string;
|
|
8
|
+
input: string;
|
|
9
|
+
expected: string;
|
|
10
|
+
};
|
|
11
|
+
export declare const formatSnapshot: (records: SnapshotRecord[]) => string;
|
|
12
|
+
export declare const parseSnapshot: (text: string) => SnapshotRecord[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type * as Md from 'mdast';
|
|
2
|
+
import type * as Plate from '../parse/plate';
|
|
3
|
+
import { type Marks } from './index';
|
|
4
|
+
/**
|
|
5
|
+
* MDX form of a text colour, always the innermost element:
|
|
6
|
+
* `<span style={{ color: "#CC4141" }}>text</span>`.
|
|
7
|
+
*/
|
|
8
|
+
export declare const textColorElement: (content: Plate.TextElement, node: Md.PhrasingContent) => Md.PhrasingContent[];
|
|
9
|
+
/** Markdown form, as raw HTML: `<span style="color: #CC4141">text</span>`. */
|
|
10
|
+
export declare const textColorHtml: (content: Plate.TextElement, node: Md.PhrasingContent) => Md.PhrasingContent[];
|
|
11
|
+
/**
|
|
12
|
+
* Picks the mark to write outermost: the one shared by the longest run of
|
|
13
|
+
* leading nodes, ties going to the earliest in `getMarks` order. Only that
|
|
14
|
+
* run is wrapped, so neighbours without the mark never gain it.
|
|
15
|
+
*/
|
|
16
|
+
export declare const longestMarkRun: <M extends Marks>(content: Plate.InlineElement[], marks: M[]) => {
|
|
17
|
+
markToProcess: M | undefined;
|
|
18
|
+
runLength: number;
|
|
19
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tinacms/mdx",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -18,6 +18,10 @@
|
|
|
18
18
|
"./sanitize-url": {
|
|
19
19
|
"types": "./dist/sanitize-url.d.ts",
|
|
20
20
|
"default": "./dist/sanitize-url.js"
|
|
21
|
+
},
|
|
22
|
+
"./sanitize-css-color": {
|
|
23
|
+
"types": "./dist/sanitize-css-color.d.ts",
|
|
24
|
+
"default": "./dist/sanitize-css-color.js"
|
|
21
25
|
}
|
|
22
26
|
},
|
|
23
27
|
"license": "Apache-2.0",
|
|
@@ -28,13 +32,16 @@
|
|
|
28
32
|
"target": "node",
|
|
29
33
|
"bundleDeps": true
|
|
30
34
|
},
|
|
31
|
-
"src/sanitize-url.ts"
|
|
35
|
+
"src/sanitize-url.ts",
|
|
36
|
+
"src/sanitize-css-color.ts"
|
|
32
37
|
]
|
|
33
38
|
},
|
|
34
39
|
"dependencies": {
|
|
35
40
|
"acorn": "^8.16.0",
|
|
36
41
|
"ccount": "2.0.1",
|
|
42
|
+
"emoji-regex": "9.2.2",
|
|
37
43
|
"estree-util-is-identifier-name": "2.1.0",
|
|
44
|
+
"esutils": "2.0.3",
|
|
38
45
|
"mdast-util-compact": "4.1.1",
|
|
39
46
|
"mdast-util-directive": "2.2.4",
|
|
40
47
|
"mdast-util-from-markdown": "1.3.0",
|
|
@@ -49,7 +56,6 @@
|
|
|
49
56
|
"micromark-util-symbol": "1.0.1",
|
|
50
57
|
"micromark-util-types": "1.1.0",
|
|
51
58
|
"parse-entities": "4.0.1",
|
|
52
|
-
"prettier": "^2.8.8",
|
|
53
59
|
"remark": "14.0.2",
|
|
54
60
|
"remark-gfm": "^2.0.0",
|
|
55
61
|
"remark-mdx": "2.3.0",
|
|
@@ -58,7 +64,7 @@
|
|
|
58
64
|
"unist-util-stringify-position": "3.0.3",
|
|
59
65
|
"unist-util-visit": "4.1.2",
|
|
60
66
|
"vfile-message": "3.1.4",
|
|
61
|
-
"@tinacms/schema-tools": "^2.
|
|
67
|
+
"@tinacms/schema-tools": "^2.11.0"
|
|
62
68
|
},
|
|
63
69
|
"publishConfig": {
|
|
64
70
|
"registry": "https://registry.npmjs.org"
|
|
@@ -69,9 +75,9 @@
|
|
|
69
75
|
},
|
|
70
76
|
"devDependencies": {
|
|
71
77
|
"@types/estree": "1.0.0",
|
|
78
|
+
"@types/esutils": "^2.0.2",
|
|
72
79
|
"@types/mdast": "^3.0.15",
|
|
73
80
|
"@types/node": "^22.13.1",
|
|
74
|
-
"@types/prettier": "^2.7.3",
|
|
75
81
|
"@types/unist": "^2.0.11",
|
|
76
82
|
"c8": "^7.14.0",
|
|
77
83
|
"jest-file-snapshot": "^0.5.0",
|
|
@@ -86,6 +92,7 @@
|
|
|
86
92
|
"build": "tinacms-scripts build",
|
|
87
93
|
"serve": "nodemon dist/server.js",
|
|
88
94
|
"test": "vitest run",
|
|
95
|
+
"snapshot:print-object-literal": "node --experimental-strip-types scripts/generate-print-object-literal-snapshot.mjs",
|
|
89
96
|
"coverage": "vitest run --coverage",
|
|
90
97
|
"test-watch": "vitest"
|
|
91
98
|
}
|