tiptap-markdown-react 0.13.0 → 0.14.1
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/README.md +1 -0
- package/dist/components/CodeBlockView.d.ts +5 -0
- package/dist/components/codeBlockReadonly.dom.test.d.ts +1 -0
- package/dist/icons/index.d.ts +2 -0
- package/dist/index.js +154 -23
- package/dist/index.js.map +1 -1
- package/dist/labels.d.ts +6 -0
- package/dist/style.css +120 -42
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -258,6 +258,7 @@ Override any of these CSS variables on an ancestor (e.g. `:root` or the editor c
|
|
|
258
258
|
| `--tmr-line-height` | `1.7` | Content line height |
|
|
259
259
|
| `--tmr-min-height` | `420px` | Editor min height |
|
|
260
260
|
| `--tmr-code-bg` | `#f4f4f4` | Inline code background |
|
|
261
|
+
| `--tmr-code-max-height` | `480px` | Readonly code block max height (long blocks scroll internally; the header toggle expands to full height; `none` disables the cap). Editable code blocks are never capped |
|
|
261
262
|
| `--tmr-table-header-bg` | `#f7f7f7` | Table header background |
|
|
262
263
|
| `--tmr-comment-ring` | `rgba(219, 171, 10, 0.55)` | Active mark / block outline ring |
|
|
263
264
|
| `--tmr-comment-gutter-bg` | `#f4b400` | Gutter bubble background |
|
|
@@ -2,5 +2,10 @@ import { NodeViewProps } from '@tiptap/react';
|
|
|
2
2
|
/**
|
|
3
3
|
* 代码块自定义 NodeView:右上角语言选择器(Radix DropdownMenu,支持方向键导航)+ 删除。
|
|
4
4
|
* 文案(Auto-detect / 删除标题)从扩展 options.codeBlockLabels 读取,缺省用英文默认。
|
|
5
|
+
*
|
|
6
|
+
* 只读态(预览 / 只读编辑器)走另一套头部:左侧语言标签,右侧复制 + 展开收起;
|
|
7
|
+
* 超出 `--tmr-code-max-height`(缺省 480px)的代码块默认限高块内滚动,行号槽
|
|
8
|
+
* 用 MutationObserver 跟踪 PM 管理的 code 内容保持同步(纯文本变化不触发 React
|
|
9
|
+
* 重渲染,gutter 行数靠观察器自刷新)。
|
|
5
10
|
*/
|
|
6
11
|
export declare function CodeBlockView({ node, updateAttributes, deleteNode, extension, editor, }: NodeViewProps): import("react").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/icons/index.d.ts
CHANGED
|
@@ -40,3 +40,5 @@ export declare const RowBeforeIcon: (p: IconProps) => import("react").JSX.Elemen
|
|
|
40
40
|
export declare const RowAfterIcon: (p: IconProps) => import("react").JSX.Element;
|
|
41
41
|
export declare const RowDeleteIcon: (p: IconProps) => import("react").JSX.Element;
|
|
42
42
|
export declare const TableDeleteIcon: (p: IconProps) => import("react").JSX.Element;
|
|
43
|
+
export declare const CopyIcon: (p: IconProps) => import("react").JSX.Element;
|
|
44
|
+
export declare const ChevronsUpDownIcon: (p: IconProps) => import("react").JSX.Element;
|
package/dist/index.js
CHANGED
|
@@ -525,6 +525,14 @@ const TableDeleteIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
|
|
|
525
525
|
/* @__PURE__ */ jsx("path", { d: "M15 5v14" }),
|
|
526
526
|
/* @__PURE__ */ jsx("path", { d: "m7 2 10 20" })
|
|
527
527
|
] });
|
|
528
|
+
const CopyIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
|
|
529
|
+
/* @__PURE__ */ jsx("rect", { width: "14", height: "14", x: "8", y: "8", rx: "2", ry: "2" }),
|
|
530
|
+
/* @__PURE__ */ jsx("path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" })
|
|
531
|
+
] });
|
|
532
|
+
const ChevronsUpDownIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
|
|
533
|
+
/* @__PURE__ */ jsx("path", { d: "m7 15 5 5 5-5" }),
|
|
534
|
+
/* @__PURE__ */ jsx("path", { d: "m7 9 5-5 5 5" })
|
|
535
|
+
] });
|
|
528
536
|
const defaultChartLabels = {
|
|
529
537
|
tabLabel: (chartType, index) => `${chartType} ${index + 1}`,
|
|
530
538
|
done: "Done",
|
|
@@ -608,7 +616,10 @@ const defaultTocLabels = {
|
|
|
608
616
|
};
|
|
609
617
|
const defaultCodeBlockLabels = {
|
|
610
618
|
autoDetect: "Auto-detect",
|
|
611
|
-
delete: "Delete code block"
|
|
619
|
+
delete: "Delete code block",
|
|
620
|
+
copy: "Copy code",
|
|
621
|
+
expand: "Expand code",
|
|
622
|
+
collapse: "Collapse code"
|
|
612
623
|
};
|
|
613
624
|
const defaultCommentLabels = {
|
|
614
625
|
open: "Open",
|
|
@@ -1281,29 +1292,45 @@ function createChart(options = {}) {
|
|
|
1281
1292
|
}
|
|
1282
1293
|
});
|
|
1283
1294
|
}
|
|
1284
|
-
const wrapper = "
|
|
1285
|
-
const header$1 = "
|
|
1286
|
-
const langTrigger = "
|
|
1287
|
-
const langChevron = "
|
|
1288
|
-
const
|
|
1289
|
-
const
|
|
1290
|
-
const
|
|
1291
|
-
const
|
|
1292
|
-
const
|
|
1293
|
-
const
|
|
1294
|
-
const
|
|
1295
|
+
const wrapper = "_wrapper_16490_2";
|
|
1296
|
+
const header$1 = "_header_16490_18";
|
|
1297
|
+
const langTrigger = "_langTrigger_16490_28";
|
|
1298
|
+
const langChevron = "_langChevron_16490_50";
|
|
1299
|
+
const readonlyHeader = "_readonlyHeader_16490_56";
|
|
1300
|
+
const langBadge = "_langBadge_16490_64";
|
|
1301
|
+
const langMenu = "_langMenu_16490_78";
|
|
1302
|
+
const langItem = "_langItem_16490_91";
|
|
1303
|
+
const langItemSelected = "_langItemSelected_16490_110";
|
|
1304
|
+
const langItemCheck = "_langItemCheck_16490_115";
|
|
1305
|
+
const deleteBtn = "_deleteBtn_16490_123";
|
|
1306
|
+
const pre = "_pre_16490_143";
|
|
1307
|
+
const readonly = "_readonly_16490_56";
|
|
1308
|
+
const expanded = "_expanded_16490_162";
|
|
1309
|
+
const gutter = "_gutter_16490_168";
|
|
1310
|
+
const gutterLine = "_gutterLine_16490_185";
|
|
1311
|
+
const readonlyActions = "_readonlyActions_16490_189";
|
|
1312
|
+
const actionBtn = "_actionBtn_16490_195";
|
|
1313
|
+
const langBraces = "_langBraces_16490_214";
|
|
1295
1314
|
const styles$4 = {
|
|
1296
1315
|
wrapper,
|
|
1297
1316
|
header: header$1,
|
|
1298
1317
|
langTrigger,
|
|
1299
1318
|
langChevron,
|
|
1319
|
+
readonlyHeader,
|
|
1300
1320
|
langBadge,
|
|
1301
1321
|
langMenu,
|
|
1302
1322
|
langItem,
|
|
1303
1323
|
langItemSelected,
|
|
1304
1324
|
langItemCheck,
|
|
1305
1325
|
deleteBtn,
|
|
1306
|
-
pre
|
|
1326
|
+
pre,
|
|
1327
|
+
readonly,
|
|
1328
|
+
expanded,
|
|
1329
|
+
gutter,
|
|
1330
|
+
gutterLine,
|
|
1331
|
+
readonlyActions,
|
|
1332
|
+
actionBtn,
|
|
1333
|
+
langBraces
|
|
1307
1334
|
};
|
|
1308
1335
|
const LANGUAGES = [
|
|
1309
1336
|
{ value: "", label: "Auto-detect" },
|
|
@@ -1341,7 +1368,60 @@ function CodeBlockView({
|
|
|
1341
1368
|
const current = LANGUAGES.find((l) => l.value === language);
|
|
1342
1369
|
const currentLabel = current ? current.value === "" ? labels.autoDetect : current.label : labels.autoDetect;
|
|
1343
1370
|
const editable = editor.isEditable;
|
|
1344
|
-
|
|
1371
|
+
const readonly2 = !editable;
|
|
1372
|
+
const [copied, setCopied] = useState(false);
|
|
1373
|
+
const [expanded2, setExpanded] = useState(false);
|
|
1374
|
+
const [scrollable, setScrollable] = useState(false);
|
|
1375
|
+
const [lineCount, setLineCount] = useState(
|
|
1376
|
+
() => Math.max((node.textContent ?? "").split("\n").length, 1)
|
|
1377
|
+
);
|
|
1378
|
+
const preRef = useRef(null);
|
|
1379
|
+
useEffect(() => {
|
|
1380
|
+
if (!readonly2) return;
|
|
1381
|
+
const pre2 = preRef.current;
|
|
1382
|
+
if (!pre2) return;
|
|
1383
|
+
const update = () => {
|
|
1384
|
+
setLineCount(Math.max((pre2.textContent ?? "").split("\n").length, 1));
|
|
1385
|
+
setScrollable(pre2.scrollHeight > pre2.clientHeight + 2);
|
|
1386
|
+
};
|
|
1387
|
+
update();
|
|
1388
|
+
const mo = new MutationObserver(update);
|
|
1389
|
+
mo.observe(pre2, { childList: true, subtree: true, characterData: true });
|
|
1390
|
+
window.addEventListener("resize", update);
|
|
1391
|
+
return () => {
|
|
1392
|
+
mo.disconnect();
|
|
1393
|
+
window.removeEventListener("resize", update);
|
|
1394
|
+
};
|
|
1395
|
+
}, [readonly2, expanded2]);
|
|
1396
|
+
const handleCopy = () => {
|
|
1397
|
+
var _a2;
|
|
1398
|
+
const text = node.textContent ?? "";
|
|
1399
|
+
const done = () => {
|
|
1400
|
+
setCopied(true);
|
|
1401
|
+
window.setTimeout(() => setCopied(false), 1500);
|
|
1402
|
+
};
|
|
1403
|
+
if ((_a2 = navigator.clipboard) == null ? void 0 : _a2.writeText) {
|
|
1404
|
+
navigator.clipboard.writeText(text).then(done, () => {
|
|
1405
|
+
});
|
|
1406
|
+
return;
|
|
1407
|
+
}
|
|
1408
|
+
const ta = document.createElement("textarea");
|
|
1409
|
+
ta.value = text;
|
|
1410
|
+
document.body.appendChild(ta);
|
|
1411
|
+
ta.select();
|
|
1412
|
+
try {
|
|
1413
|
+
document.execCommand("copy");
|
|
1414
|
+
done();
|
|
1415
|
+
} catch {
|
|
1416
|
+
}
|
|
1417
|
+
ta.remove();
|
|
1418
|
+
};
|
|
1419
|
+
const wrapperClass = [
|
|
1420
|
+
styles$4.wrapper,
|
|
1421
|
+
readonly2 ? styles$4.readonly : "",
|
|
1422
|
+
expanded2 ? styles$4.expanded : ""
|
|
1423
|
+
].filter(Boolean).join(" ");
|
|
1424
|
+
return /* @__PURE__ */ jsxs(NodeViewWrapper, { className: wrapperClass, children: [
|
|
1345
1425
|
editable ? /* @__PURE__ */ jsxs("div", { className: styles$4.header, contentEditable: false, children: [
|
|
1346
1426
|
/* @__PURE__ */ jsxs(DropdownMenu.Root, { children: [
|
|
1347
1427
|
/* @__PURE__ */ jsx(DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
@@ -1393,10 +1473,51 @@ function CodeBlockView({
|
|
|
1393
1473
|
}
|
|
1394
1474
|
)
|
|
1395
1475
|
] }) : (
|
|
1396
|
-
//
|
|
1397
|
-
/* @__PURE__ */
|
|
1476
|
+
// 只读头部:左侧语言标签,右侧复制 + 展开收起(展开后按钮保留,供收回)
|
|
1477
|
+
/* @__PURE__ */ jsxs("div", { className: styles$4.readonlyHeader, contentEditable: false, children: [
|
|
1478
|
+
/* @__PURE__ */ jsxs("span", { className: styles$4.langBadge, children: [
|
|
1479
|
+
/* @__PURE__ */ jsx("span", { className: styles$4.langBraces, children: "{}" }),
|
|
1480
|
+
currentLabel
|
|
1481
|
+
] }),
|
|
1482
|
+
/* @__PURE__ */ jsxs("span", { className: styles$4.readonlyActions, children: [
|
|
1483
|
+
/* @__PURE__ */ jsx(
|
|
1484
|
+
"button",
|
|
1485
|
+
{
|
|
1486
|
+
type: "button",
|
|
1487
|
+
className: styles$4.actionBtn,
|
|
1488
|
+
onClick: handleCopy,
|
|
1489
|
+
"aria-label": labels.copy,
|
|
1490
|
+
title: labels.copy,
|
|
1491
|
+
children: copied ? /* @__PURE__ */ jsx(CheckIcon, { size: 14 }) : /* @__PURE__ */ jsx(CopyIcon, { size: 14 })
|
|
1492
|
+
}
|
|
1493
|
+
),
|
|
1494
|
+
scrollable || expanded2 ? /* @__PURE__ */ jsx(
|
|
1495
|
+
"button",
|
|
1496
|
+
{
|
|
1497
|
+
type: "button",
|
|
1498
|
+
className: styles$4.actionBtn,
|
|
1499
|
+
onClick: () => setExpanded((v) => !v),
|
|
1500
|
+
"aria-label": expanded2 ? labels.collapse : labels.expand,
|
|
1501
|
+
title: expanded2 ? labels.collapse : labels.expand,
|
|
1502
|
+
"aria-expanded": expanded2,
|
|
1503
|
+
children: /* @__PURE__ */ jsx(ChevronsUpDownIcon, { size: 14 })
|
|
1504
|
+
}
|
|
1505
|
+
) : null
|
|
1506
|
+
] })
|
|
1507
|
+
] })
|
|
1398
1508
|
),
|
|
1399
|
-
/* @__PURE__ */
|
|
1509
|
+
/* @__PURE__ */ jsxs("pre", { ref: preRef, className: styles$4.pre, children: [
|
|
1510
|
+
readonly2 ? /* @__PURE__ */ jsx(
|
|
1511
|
+
"span",
|
|
1512
|
+
{
|
|
1513
|
+
className: styles$4.gutter,
|
|
1514
|
+
contentEditable: false,
|
|
1515
|
+
"aria-hidden": "true",
|
|
1516
|
+
children: Array.from({ length: lineCount }, (_, i) => /* @__PURE__ */ jsx("span", { className: styles$4.gutterLine, children: i + 1 }, i))
|
|
1517
|
+
}
|
|
1518
|
+
) : null,
|
|
1519
|
+
/* @__PURE__ */ jsx(NodeViewContent, { as: "code" })
|
|
1520
|
+
] })
|
|
1400
1521
|
] });
|
|
1401
1522
|
}
|
|
1402
1523
|
const CodeBlock = CodeBlockLowlight.extend({
|
|
@@ -1654,14 +1775,14 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
|
|
|
1654
1775
|
(_a = onCommentClickRef.current) == null ? void 0 : _a.call(onCommentClickRef, click);
|
|
1655
1776
|
(_b = onActiveCommentChangeRef.current) == null ? void 0 : _b.call(onActiveCommentChangeRef, click.commentIds[0] ?? null);
|
|
1656
1777
|
}
|
|
1657
|
-
const
|
|
1658
|
-
if (
|
|
1778
|
+
const gutter2 = transaction.getMeta(COMMENT_GUTTER_META);
|
|
1779
|
+
if (gutter2) {
|
|
1659
1780
|
(_c = onCommentClickRef.current) == null ? void 0 : _c.call(onCommentClickRef, {
|
|
1660
|
-
commentIds:
|
|
1781
|
+
commentIds: gutter2.commentIds,
|
|
1661
1782
|
anchorEl: null,
|
|
1662
|
-
pos:
|
|
1783
|
+
pos: gutter2.pos
|
|
1663
1784
|
});
|
|
1664
|
-
(_d = onActiveCommentChangeRef.current) == null ? void 0 : _d.call(onActiveCommentChangeRef,
|
|
1785
|
+
(_d = onActiveCommentChangeRef.current) == null ? void 0 : _d.call(onActiveCommentChangeRef, gutter2.commentIds[0] ?? null);
|
|
1665
1786
|
}
|
|
1666
1787
|
};
|
|
1667
1788
|
editor.on("transaction", onTransaction);
|
|
@@ -1735,10 +1856,18 @@ function MarkdownPreview({
|
|
|
1735
1856
|
),
|
|
1736
1857
|
[markdown, sources]
|
|
1737
1858
|
);
|
|
1859
|
+
const previewCodeBlock = useMemo(
|
|
1860
|
+
() => pureCodeBlock.extend({
|
|
1861
|
+
addNodeView() {
|
|
1862
|
+
return ReactNodeViewRenderer(CodeBlockView);
|
|
1863
|
+
}
|
|
1864
|
+
}),
|
|
1865
|
+
[]
|
|
1866
|
+
);
|
|
1738
1867
|
const extensions = useMemo(
|
|
1739
1868
|
() => [
|
|
1740
1869
|
...baseExtensions,
|
|
1741
|
-
|
|
1870
|
+
previewCodeBlock,
|
|
1742
1871
|
pureImage,
|
|
1743
1872
|
createChart({ editable: false }),
|
|
1744
1873
|
createCitationRef({ renderCitation }),
|
|
@@ -3650,6 +3779,7 @@ export {
|
|
|
3650
3779
|
CheckIcon,
|
|
3651
3780
|
ChevronDownIcon,
|
|
3652
3781
|
ChevronUpIcon,
|
|
3782
|
+
ChevronsUpDownIcon,
|
|
3653
3783
|
a as CitationInteractive,
|
|
3654
3784
|
CitationRef,
|
|
3655
3785
|
CodeBlockView,
|
|
@@ -3660,6 +3790,7 @@ export {
|
|
|
3660
3790
|
ColumnDeleteIcon,
|
|
3661
3791
|
CommentMark,
|
|
3662
3792
|
CommentPopover,
|
|
3793
|
+
CopyIcon,
|
|
3663
3794
|
EditorToolbar,
|
|
3664
3795
|
FIND_DEBOUNCE_MS,
|
|
3665
3796
|
default2 as FindAndReplace,
|