@lofcz/platejs-markdown 52.3.9 → 53.0.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.js +137 -71
- package/package.json +8 -5
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ElementApi, KEYS, TextApi, bindFirst, createTSlatePlugin, getPluginKey, getPluginType, isUrl } from "platejs";
|
|
2
2
|
import "mdast-util-mdx";
|
|
3
|
+
import { normalizeDateValue } from "@platejs/date";
|
|
3
4
|
import kebabCase from "lodash/kebabCase.js";
|
|
4
5
|
import { defaultHandlers, toMarkdown } from "mdast-util-to-markdown";
|
|
5
6
|
import { unified } from "unified";
|
|
@@ -131,7 +132,7 @@ function propsToAttributes(props) {
|
|
|
131
132
|
return Object.entries(props).map(([name, value]) => ({
|
|
132
133
|
name,
|
|
133
134
|
type: "mdxJsxAttribute",
|
|
134
|
-
value: typeof value === "string" ? value : JSON.stringify(value)
|
|
135
|
+
value: typeof value === "string" || value?.type === "mdxJsxAttributeValueExpression" ? value : JSON.stringify(value)
|
|
135
136
|
}));
|
|
136
137
|
}
|
|
137
138
|
|
|
@@ -239,7 +240,7 @@ function createMediaRule() {
|
|
|
239
240
|
};
|
|
240
241
|
},
|
|
241
242
|
serialize: (node, options) => {
|
|
242
|
-
const {
|
|
243
|
+
const { children, type, url, ...rest } = node;
|
|
243
244
|
return {
|
|
244
245
|
attributes: propsToAttributes({
|
|
245
246
|
...rest,
|
|
@@ -255,6 +256,7 @@ function createMediaRule() {
|
|
|
255
256
|
const mediaRules = {
|
|
256
257
|
audio: createMediaRule(),
|
|
257
258
|
file: createMediaRule(),
|
|
259
|
+
media_embed: createMediaRule(),
|
|
258
260
|
video: createMediaRule()
|
|
259
261
|
};
|
|
260
262
|
|
|
@@ -1296,6 +1298,7 @@ const serializeMd = (editor, options) => {
|
|
|
1296
1298
|
const { remarkPlugins, value } = mergedOptions;
|
|
1297
1299
|
const toRemarkProcessor = unified().use(remarkPlugins ?? []).use(remarkStringify, {
|
|
1298
1300
|
emphasis: "_",
|
|
1301
|
+
resourceLink: false,
|
|
1299
1302
|
...mergedOptions?.remarkStringifyOptions
|
|
1300
1303
|
});
|
|
1301
1304
|
const mdast = slateToMdast({
|
|
@@ -1313,6 +1316,7 @@ const slateToMdast = ({ children, options }) => {
|
|
|
1313
1316
|
|
|
1314
1317
|
//#endregion
|
|
1315
1318
|
//#region src/lib/rules/defaultRules.ts
|
|
1319
|
+
const BARE_AUTOLINK_PROTOCOL_REGEX = /^https?:\/\//i;
|
|
1316
1320
|
const LEADING_NEWLINE_REGEX = /^\n/;
|
|
1317
1321
|
function isBoolean(value) {
|
|
1318
1322
|
return value === true || value === false || !!value && typeof value === "object" && Object.prototype.toString.call(value) === "[object Boolean]";
|
|
@@ -1330,6 +1334,33 @@ const deserializeClassicListItemChildren = (mdastChildren, deco, options) => {
|
|
|
1330
1334
|
if (!children.some((child) => child.type === licType)) children.unshift(createClassicListItemContent(options.editor));
|
|
1331
1335
|
return children;
|
|
1332
1336
|
};
|
|
1337
|
+
const groupInlineChildrenIntoParagraphs = (editor, children = []) => {
|
|
1338
|
+
const paragraphType = getPluginType(editor, KEYS.p);
|
|
1339
|
+
const elements = [];
|
|
1340
|
+
let inlineNodes = [];
|
|
1341
|
+
const flushInlineNodes = () => {
|
|
1342
|
+
if (inlineNodes.length === 0) return;
|
|
1343
|
+
elements.push({
|
|
1344
|
+
children: inlineNodes,
|
|
1345
|
+
type: paragraphType
|
|
1346
|
+
});
|
|
1347
|
+
inlineNodes = [];
|
|
1348
|
+
};
|
|
1349
|
+
children.forEach((child) => {
|
|
1350
|
+
if (ElementApi.isElement(child) && !editor.api.isInline(child) && editor.api.isBlock(child)) {
|
|
1351
|
+
flushInlineNodes();
|
|
1352
|
+
elements.push(child);
|
|
1353
|
+
return;
|
|
1354
|
+
}
|
|
1355
|
+
inlineNodes.push(child);
|
|
1356
|
+
});
|
|
1357
|
+
flushInlineNodes();
|
|
1358
|
+
if (elements.length > 0) return elements;
|
|
1359
|
+
return [{
|
|
1360
|
+
children: [{ text: "" }],
|
|
1361
|
+
type: paragraphType
|
|
1362
|
+
}];
|
|
1363
|
+
};
|
|
1333
1364
|
const defaultRules = {
|
|
1334
1365
|
a: {
|
|
1335
1366
|
deserialize: (mdastNode, deco, options) => ({
|
|
@@ -1337,48 +1368,29 @@ const defaultRules = {
|
|
|
1337
1368
|
type: getPluginType(options.editor, KEYS.a),
|
|
1338
1369
|
url: mdastNode.url
|
|
1339
1370
|
}),
|
|
1340
|
-
serialize: (node, options) => ({
|
|
1341
|
-
children: convertNodesSerialize(node.children, options),
|
|
1342
|
-
type: "link",
|
|
1343
|
-
url: node.url
|
|
1344
|
-
})
|
|
1345
|
-
},
|
|
1346
|
-
blockquote: {
|
|
1347
|
-
deserialize: (mdastNode, deco, options) => {
|
|
1348
|
-
return {
|
|
1349
|
-
children: (mdastNode.children.length > 0 ? mdastNode.children.flatMap((paragraph, index, children) => {
|
|
1350
|
-
if (paragraph.type === "paragraph") {
|
|
1351
|
-
if (children.length > 1 && children.length - 1 !== index) {
|
|
1352
|
-
const paragraphChildren = convertChildrenDeserialize(paragraph.children, deco, options);
|
|
1353
|
-
paragraphChildren.push({ text: "\n" }, { text: "\n" });
|
|
1354
|
-
return paragraphChildren;
|
|
1355
|
-
}
|
|
1356
|
-
return convertChildrenDeserialize(paragraph.children, deco, options);
|
|
1357
|
-
}
|
|
1358
|
-
if ("children" in paragraph) return convertChildrenDeserialize(paragraph.children, deco, options);
|
|
1359
|
-
return [{ text: "" }];
|
|
1360
|
-
}) : [{ text: "" }]).flatMap((child) => child.type === "blockquote" ? child.children : [child]),
|
|
1361
|
-
type: getPluginType(options.editor, KEYS.blockquote)
|
|
1362
|
-
};
|
|
1363
|
-
},
|
|
1364
1371
|
serialize: (node, options) => {
|
|
1365
|
-
const
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
paragraphChildren.at(-1).type = "html";
|
|
1371
|
-
paragraphChildren.at(-1).value = "\n<br />";
|
|
1372
|
-
}
|
|
1372
|
+
const children = convertNodesSerialize(node.children, options);
|
|
1373
|
+
if (children.length === 1 && children[0]?.type === "text" && children[0].value === node.url && BARE_AUTOLINK_PROTOCOL_REGEX.test(node.url ?? "")) return {
|
|
1374
|
+
type: "html",
|
|
1375
|
+
value: node.url
|
|
1376
|
+
};
|
|
1373
1377
|
return {
|
|
1374
|
-
children
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
}],
|
|
1378
|
-
type: "blockquote"
|
|
1378
|
+
children,
|
|
1379
|
+
type: "link",
|
|
1380
|
+
url: node.url
|
|
1379
1381
|
};
|
|
1380
1382
|
}
|
|
1381
1383
|
},
|
|
1384
|
+
blockquote: {
|
|
1385
|
+
deserialize: (mdastNode, deco, options) => ({
|
|
1386
|
+
children: groupInlineChildrenIntoParagraphs(options.editor, convertNodesDeserialize(mdastNode.children, deco, options)),
|
|
1387
|
+
type: getPluginType(options.editor, KEYS.blockquote)
|
|
1388
|
+
}),
|
|
1389
|
+
serialize: (node, options) => ({
|
|
1390
|
+
children: convertNodesSerialize(groupInlineChildrenIntoParagraphs(options.editor, node.children), options),
|
|
1391
|
+
type: "blockquote"
|
|
1392
|
+
})
|
|
1393
|
+
},
|
|
1382
1394
|
bold: {
|
|
1383
1395
|
mark: true,
|
|
1384
1396
|
deserialize: (mdastNode, deco, options) => convertTextsDeserialize(mdastNode, deco, options)
|
|
@@ -1454,18 +1466,25 @@ const defaultRules = {
|
|
|
1454
1466
|
},
|
|
1455
1467
|
date: {
|
|
1456
1468
|
deserialize(mdastNode, _deco, options) {
|
|
1469
|
+
const props = parseAttributes(mdastNode.attributes);
|
|
1457
1470
|
return {
|
|
1458
1471
|
children: [{ text: "" }],
|
|
1459
|
-
|
|
1472
|
+
...normalizeDateValue(typeof props.value === "string" ? props.value : (mdastNode.children?.[0])?.value || ""),
|
|
1460
1473
|
type: getPluginType(options.editor, KEYS.date)
|
|
1461
1474
|
};
|
|
1462
1475
|
},
|
|
1463
|
-
serialize({ date }) {
|
|
1476
|
+
serialize({ date, rawDate }) {
|
|
1477
|
+
if (date && !rawDate) return {
|
|
1478
|
+
attributes: propsToAttributes({ value: date }),
|
|
1479
|
+
children: [],
|
|
1480
|
+
name: "date",
|
|
1481
|
+
type: "mdxJsxTextElement"
|
|
1482
|
+
};
|
|
1464
1483
|
return {
|
|
1465
1484
|
attributes: [],
|
|
1466
1485
|
children: [{
|
|
1467
1486
|
type: "text",
|
|
1468
|
-
value: date ?? ""
|
|
1487
|
+
value: rawDate ?? date ?? ""
|
|
1469
1488
|
}],
|
|
1470
1489
|
name: "date",
|
|
1471
1490
|
type: "mdxJsxTextElement"
|
|
@@ -1490,13 +1509,47 @@ const defaultRules = {
|
|
|
1490
1509
|
value: node.texExpression
|
|
1491
1510
|
})
|
|
1492
1511
|
},
|
|
1493
|
-
footnoteDefinition: {
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1512
|
+
footnoteDefinition: {
|
|
1513
|
+
deserialize: (mdastNode, deco, options) => {
|
|
1514
|
+
const paragraphType = getPluginType(options.editor, KEYS.p);
|
|
1515
|
+
const blocks = convertNodesDeserialize(mdastNode.children, deco, options).map((child) => child.type === paragraphType ? child : {
|
|
1516
|
+
children: [child],
|
|
1517
|
+
type: paragraphType
|
|
1518
|
+
});
|
|
1519
|
+
const identifier = mdastNode.identifier;
|
|
1520
|
+
if (blocks.length === 0) return {
|
|
1521
|
+
children: [{
|
|
1522
|
+
children: [{ text: "" }],
|
|
1523
|
+
type: paragraphType
|
|
1524
|
+
}],
|
|
1525
|
+
identifier,
|
|
1526
|
+
type: getPluginType(options.editor, "footnoteDefinition")
|
|
1527
|
+
};
|
|
1528
|
+
return {
|
|
1529
|
+
children: blocks,
|
|
1530
|
+
identifier,
|
|
1531
|
+
type: getPluginType(options.editor, "footnoteDefinition")
|
|
1532
|
+
};
|
|
1533
|
+
},
|
|
1534
|
+
serialize: (node, options) => ({
|
|
1535
|
+
children: convertNodesSerialize(node.children, options),
|
|
1536
|
+
identifier: node.identifier,
|
|
1537
|
+
type: "footnoteDefinition"
|
|
1538
|
+
})
|
|
1539
|
+
},
|
|
1540
|
+
footnoteReference: {
|
|
1541
|
+
deserialize: (mdastNode, _deco, options) => {
|
|
1542
|
+
return {
|
|
1543
|
+
children: [{ text: "" }],
|
|
1544
|
+
identifier: mdastNode.identifier ?? "",
|
|
1545
|
+
type: getPluginType(options.editor, "footnoteReference")
|
|
1546
|
+
};
|
|
1547
|
+
},
|
|
1548
|
+
serialize: (node) => ({
|
|
1549
|
+
identifier: node.identifier ?? node.children?.map((child) => child.text ?? "").join("") ?? "",
|
|
1550
|
+
type: "footnoteReference"
|
|
1551
|
+
})
|
|
1552
|
+
},
|
|
1500
1553
|
heading: {
|
|
1501
1554
|
deserialize: (mdastNode, deco, options) => {
|
|
1502
1555
|
const defaultType = {
|
|
@@ -1568,11 +1621,11 @@ const defaultRules = {
|
|
|
1568
1621
|
...rest
|
|
1569
1622
|
};
|
|
1570
1623
|
},
|
|
1571
|
-
serialize: ({ caption, url }) => {
|
|
1624
|
+
serialize: ({ caption, title, url }) => {
|
|
1572
1625
|
return {
|
|
1573
1626
|
children: [{
|
|
1574
1627
|
alt: caption ? caption.map((c) => c.text).join("") : void 0,
|
|
1575
|
-
title:
|
|
1628
|
+
title: typeof title === "string" ? title : void 0,
|
|
1576
1629
|
type: "image",
|
|
1577
1630
|
url
|
|
1578
1631
|
}],
|
|
@@ -2018,6 +2071,34 @@ const getDeserializerByKey = (key, options) => {
|
|
|
2018
2071
|
|
|
2019
2072
|
//#endregion
|
|
2020
2073
|
//#region src/lib/deserializer/utils/customMdxDeserialize.ts
|
|
2074
|
+
const MDX_ATTR_NAME_TO_HTML_ATTR = {
|
|
2075
|
+
className: "class",
|
|
2076
|
+
htmlFor: "for"
|
|
2077
|
+
};
|
|
2078
|
+
const serializeUnknownMdxChild = (child) => {
|
|
2079
|
+
if (child?.type === "mdxJsxTextElement" || child?.type === "mdxJsxFlowElement") return serializeUnknownMdxNode(child);
|
|
2080
|
+
if ("value" in (child ?? {})) return child.value ?? "";
|
|
2081
|
+
if (Array.isArray(child?.children)) return child.children.map(serializeUnknownMdxChild).join("");
|
|
2082
|
+
return "";
|
|
2083
|
+
};
|
|
2084
|
+
const serializeUnknownMdxAttributes = (attributes) => {
|
|
2085
|
+
if (!attributes?.length) return "";
|
|
2086
|
+
const serialized = attributes.map((attribute) => {
|
|
2087
|
+
const name = MDX_ATTR_NAME_TO_HTML_ATTR[attribute.name] ?? attribute.name;
|
|
2088
|
+
if (attribute.value === void 0 || attribute.value === null) return name;
|
|
2089
|
+
if (typeof attribute.value === "object" && attribute.value?.type === "mdxJsxAttributeValueExpression") return `${name}={${attribute.value.value}}`;
|
|
2090
|
+
return `${name}="${String(attribute.value)}"`;
|
|
2091
|
+
});
|
|
2092
|
+
return serialized.length > 0 ? ` ${serialized.join(" ")}` : "";
|
|
2093
|
+
};
|
|
2094
|
+
const serializeUnknownMdxNode = (mdastNode) => {
|
|
2095
|
+
const attrs = serializeUnknownMdxAttributes(mdastNode.attributes);
|
|
2096
|
+
const openTag = `<${mdastNode.name}${attrs}`;
|
|
2097
|
+
if (!mdastNode.children?.length) return `${openTag} />`;
|
|
2098
|
+
const inner = mdastNode.children.map(serializeUnknownMdxChild).join(mdastNode.type === "mdxJsxFlowElement" ? "\n" : "");
|
|
2099
|
+
if (mdastNode.type === "mdxJsxFlowElement") return `${openTag}>\n${inner}\n</${mdastNode.name}>`;
|
|
2100
|
+
return `${openTag}>${inner}</${mdastNode.name}>`;
|
|
2101
|
+
};
|
|
2021
2102
|
const customMdxDeserialize = (mdastNode, deco, options) => {
|
|
2022
2103
|
const customJsxElementKey = mdastNode.name;
|
|
2023
2104
|
const key = getPluginKey(options.editor, customJsxElementKey) ?? mdastNode.name;
|
|
@@ -2025,26 +2106,11 @@ const customMdxDeserialize = (mdastNode, deco, options) => {
|
|
|
2025
2106
|
const nodeParserDeserialize = getDeserializerByKey(mdastToPlate(options.editor, key), options);
|
|
2026
2107
|
if (nodeParserDeserialize) return nodeParserDeserialize(mdastNode, deco, options);
|
|
2027
2108
|
} else console.warn("This MDX node does not have a parser for deserialization", mdastNode);
|
|
2028
|
-
if (mdastNode.type === "mdxJsxTextElement") {
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
return "";
|
|
2034
|
-
}).join("");
|
|
2035
|
-
return [{ text: `<${tagName}>${textContent}</${tagName}>` }];
|
|
2036
|
-
}
|
|
2037
|
-
if (mdastNode.type === "mdxJsxFlowElement") {
|
|
2038
|
-
const tagName = mdastNode.name;
|
|
2039
|
-
return [{
|
|
2040
|
-
children: [
|
|
2041
|
-
{ text: `<${tagName}>\n` },
|
|
2042
|
-
...convertChildrenDeserialize(mdastNode.children, deco, options),
|
|
2043
|
-
{ text: `\n</${tagName}>` }
|
|
2044
|
-
],
|
|
2045
|
-
type: getPluginType(options.editor, KEYS.p)
|
|
2046
|
-
}];
|
|
2047
|
-
}
|
|
2109
|
+
if (mdastNode.type === "mdxJsxTextElement") return [{ text: serializeUnknownMdxNode(mdastNode) }];
|
|
2110
|
+
if (mdastNode.type === "mdxJsxFlowElement") return [{
|
|
2111
|
+
children: [{ text: serializeUnknownMdxNode(mdastNode) }],
|
|
2112
|
+
type: getPluginType(options.editor, KEYS.p)
|
|
2113
|
+
}];
|
|
2048
2114
|
};
|
|
2049
2115
|
|
|
2050
2116
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lofcz/platejs-markdown",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "53.0.0",
|
|
4
4
|
"description": "Markdown serializer plugin for Plate",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"markdown",
|
|
@@ -42,18 +42,21 @@
|
|
|
42
42
|
"remark-stringify": "^11.0.0",
|
|
43
43
|
"ts-essentials": "10.1.0",
|
|
44
44
|
"unified": "^11.0.5",
|
|
45
|
-
"unist-util-visit": "5.0.0"
|
|
45
|
+
"unist-util-visit": "5.0.0",
|
|
46
|
+
"@platejs/date": "npm:@lofcz/platejs-date@53.0.0"
|
|
46
47
|
},
|
|
47
48
|
"devDependencies": {
|
|
48
49
|
"@types/mdast": "^4.0.4",
|
|
49
50
|
"@types/unist": "^3.0.3",
|
|
51
|
+
"remark-emoji": "5.0.1",
|
|
50
52
|
"remark-gfm": "4.0.1",
|
|
51
53
|
"remark-math": "6.0.0",
|
|
52
|
-
"
|
|
53
|
-
"@
|
|
54
|
+
"@plate/scripts": "1.0.0",
|
|
55
|
+
"@platejs/footnote": "npm:@lofcz/platejs-footnote@53.0.0",
|
|
56
|
+
"platejs": "npm:@lofcz/platejs@53.0.0"
|
|
54
57
|
},
|
|
55
58
|
"peerDependencies": {
|
|
56
|
-
"platejs": ">=
|
|
59
|
+
"platejs": ">=53.0.0",
|
|
57
60
|
"react": ">=18.0.0",
|
|
58
61
|
"react-dom": ">=18.0.0"
|
|
59
62
|
},
|