tiptap-markdown-react 1.6.0 → 1.7.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.
@@ -16,4 +16,6 @@ export interface LocaleBundle {
16
16
  codeBlock: CodeBlockLabels;
17
17
  find: FindLabels;
18
18
  imageUpload: ImageUploadLabels;
19
+ /** 正文顶部文档标题的占位。 */
20
+ titlePlaceholder: string;
19
21
  }
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { Markdown, MarkdownManager } from "@tiptap/markdown";
3
- import { g as getLocaleBundle, S as SearchIcon, d as ChevronUpIcon, e as ChevronDownIcon, X as XIcon, h as ReplaceIcon, i as ReplaceAllIcon, j as renderOrUpdateChart, k as destroyChart, l as CheckIcon, T as TrashIcon, n as CopyIcon, o as ChevronsUpDownIcon, G as GripIcon, E as EraserIcon, D as DownloadIcon, u as useIsMobile, K as KeyboardIcon, p as EditorToc, I as ImagePreviewHost, q as sameTocItems$1, A as AlignRightIcon, t as AlignCenterIcon, v as AlignLeftIcon, w as CropIcon, x as CaptionsIcon, y as ExpandIcon, z as requestImagePreview, B as RotateCcwIcon, F as ExternalLinkIcon, H as TableDeleteIcon, J as ColumnBeforeIcon, L as ColumnAfterIcon, M as ColumnDeleteIcon, N as RowBeforeIcon, O as RowAfterIcon, P as RowDeleteIcon, U as UndoIcon, Q as RedoIcon, V as PaintbrushIcon, W as BoldIcon, Y as ItalicIcon, Z as UnderlineIcon, _ as StrikethroughIcon, $ as CodeIcon, a0 as LinkIcon, a1 as ImageIcon, a2 as DetailsIcon, a3 as AlignJustifyIcon, a4 as IndentIncreaseIcon, a5 as IndentDecreaseIcon, a6 as LineHeightIcon, a7 as ListUnorderedIcon, a8 as ListOrderedIcon, a9 as ListChecksIcon, aa as MinimizeIcon } from "./ReportContentWithCharts-BaBitkZX.js";
4
- import { C, ab, ac, a, ad, ae, af, ag, b, c, ah, ai, aj, f, m, r, s } from "./ReportContentWithCharts-BaBitkZX.js";
3
+ import { g as getLocaleBundle, S as SearchIcon, d as ChevronUpIcon, e as ChevronDownIcon, X as XIcon, h as ReplaceIcon, i as ReplaceAllIcon, j as renderOrUpdateChart, k as destroyChart, l as CheckIcon, T as TrashIcon, n as CopyIcon, o as ChevronsUpDownIcon, G as GripIcon, E as EraserIcon, D as DownloadIcon, u as useIsMobile, K as KeyboardIcon, p as EditorToc, I as ImagePreviewHost, q as sameTocItems$1, A as AlignRightIcon, t as AlignCenterIcon, v as AlignLeftIcon, w as CropIcon, x as CaptionsIcon, y as ExpandIcon, z as requestImagePreview, B as RotateCcwIcon, F as ExternalLinkIcon, H as TableDeleteIcon, J as ColumnBeforeIcon, L as ColumnAfterIcon, M as ColumnDeleteIcon, N as RowBeforeIcon, O as RowAfterIcon, P as RowDeleteIcon, U as UndoIcon, Q as RedoIcon, V as PaintbrushIcon, W as BoldIcon, Y as ItalicIcon, Z as UnderlineIcon, _ as StrikethroughIcon, $ as CodeIcon, a0 as LinkIcon, a1 as ImageIcon, a2 as DetailsIcon, a3 as AlignJustifyIcon, a4 as IndentIncreaseIcon, a5 as IndentDecreaseIcon, a6 as LineHeightIcon, a7 as ListUnorderedIcon, a8 as ListOrderedIcon, a9 as ListChecksIcon, aa as MinimizeIcon } from "./ReportContentWithCharts-DeuBXydb.js";
4
+ import { C, ab, ac, a, ad, ae, af, ag, b, c, ah, ai, aj, f, m, r, s } from "./ReportContentWithCharts-DeuBXydb.js";
5
5
  import { jsx, jsxs, Fragment as Fragment$2 } from "react/jsx-runtime";
6
6
  import CodeBlockLowlight from "@tiptap/extension-code-block-lowlight";
7
7
  import FindAndReplace, { FindAndReplacePluginKey, createSearchRegex } from "@tiptap/extension-find-and-replace";
@@ -14,10 +14,10 @@ import { NodeViewWrapper, ReactNodeViewRenderer, useEditorState, ReactRenderer,
14
14
  import { Extension, Node as Node$1, mergeAttributes } from "@tiptap/core";
15
15
  import { createPortal } from "react-dom";
16
16
  import { useState, useEffect, useCallback, useRef, useMemo, useSyncExternalStore, useLayoutEffect, forwardRef, useId, useImperativeHandle, Fragment as Fragment$1, useContext, createContext } from "react";
17
- import { q as normalizeImageAlign, l as normalizeImageCrop, m as cropImageBox, e as enrichMarkdownCitations, o as styles$e, i as imageMarkdownTokenizer, c as imageParseMarkdown, d as imageRenderMarkdown, f as imageNodeHtml, g as imageFigureParseRule, h as imageCropAttribute, j as imageCaptionAttribute, k as imageAlignAttribute, r as normalizeImageCaption } from "./ReportContent-DUvhic0o.js";
18
- import { R, a as a2, b as b2, s as s2 } from "./ReportContent-DUvhic0o.js";
19
- import { C as CitationRef, i as mergeCommentIntervals, h as mapCommentAnchors, p as prepareChartMarkdown, j as reportChart, f as CommentMark, b as baseExtensions, l as lowlight, m as makeTocGetId, k as parseCodeTokenAsChartOrCodeBlock, a as pureCodeBlock, c as pureImage, n as renderMathInto, o as readCurrentNumberingFormat, q as subscribeMathClick, t as applyNumberingFormat, N as NUMBERING_FORMAT_IDS, u as NUMBERING_FORMAT_LABELS, v as NUMBERING_FORMAT_PREVIEWS, d as pureChart } from "./extractToc-B-hg0XuH.js";
20
- import { P, g, e, s as s3 } from "./extractToc-B-hg0XuH.js";
17
+ import { q as normalizeImageAlign, l as normalizeImageCrop, m as cropImageBox, e as enrichMarkdownCitations, o as styles$e, i as imageMarkdownTokenizer, c as imageParseMarkdown, d as imageRenderMarkdown, f as imageNodeHtml, g as imageFigureParseRule, h as imageCropAttribute, j as imageCaptionAttribute, k as imageAlignAttribute, r as normalizeImageCaption } from "./ReportContent-BlGb1jJw.js";
18
+ import { R, a as a2, b as b2, s as s2 } from "./ReportContent-BlGb1jJw.js";
19
+ import { C as CitationRef, i as mergeCommentIntervals, h as mapCommentAnchors, p as prepareChartMarkdown, j as reportChart, f as CommentMark, b as baseExtensions, l as lowlight, m as makeTocGetId, k as parseCodeTokenAsChartOrCodeBlock, a as pureCodeBlock, c as pureImage, n as renderMathInto, o as readCurrentNumberingFormat, q as subscribeMathClick, t as applyNumberingFormat, N as NUMBERING_FORMAT_IDS, u as NUMBERING_FORMAT_LABELS, v as NUMBERING_FORMAT_PREVIEWS, d as pureChart } from "./extractToc-DNrkCXJc.js";
20
+ import { P, g, e, s as s3 } from "./extractToc-DNrkCXJc.js";
21
21
  import { Slice, Fragment } from "@tiptap/pm/model";
22
22
  import { PluginKey, Plugin, Selection, TextSelection, NodeSelection } from "@tiptap/pm/state";
23
23
  import { DecorationSet, Decoration } from "@tiptap/pm/view";
@@ -3738,6 +3738,62 @@ function sameTocItems(a3, b3) {
3738
3738
  (item2, index) => item2.id === b3[index].id && item2.level === b3[index].level && item2.text === b3[index].text
3739
3739
  );
3740
3740
  }
3741
+ function isAtDocumentStart(selection) {
3742
+ if (!selection.empty) return selection.from === 0;
3743
+ const $from = selection.$from;
3744
+ if ($from.parentOffset !== 0) return false;
3745
+ for (let depth = $from.depth; depth > 0; depth -= 1) {
3746
+ if ($from.index(depth - 1) !== 0) return false;
3747
+ }
3748
+ return true;
3749
+ }
3750
+ function DocumentTitleField({
3751
+ value,
3752
+ placeholder,
3753
+ maxLength,
3754
+ readOnly: readOnly2,
3755
+ inputRef,
3756
+ onChange,
3757
+ onMoveToBody
3758
+ }) {
3759
+ useLayoutEffect(() => {
3760
+ const el = inputRef.current;
3761
+ if (!el) return;
3762
+ el.style.height = "auto";
3763
+ if (el.scrollHeight > 0) el.style.height = `${el.scrollHeight}px`;
3764
+ }, [inputRef, value]);
3765
+ return /* @__PURE__ */ jsx(
3766
+ "textarea",
3767
+ {
3768
+ ref: inputRef,
3769
+ className: styles$e.documentTitle,
3770
+ "data-document-title": "",
3771
+ value,
3772
+ placeholder,
3773
+ maxLength,
3774
+ rows: 1,
3775
+ "aria-label": placeholder,
3776
+ readOnly: readOnly2,
3777
+ onChange: (event) => onChange(event.target.value),
3778
+ onKeyDown: (event) => {
3779
+ if (readOnly2 || isComposingKeyEvent(event.nativeEvent)) return;
3780
+ if (event.key === "Enter" && !event.shiftKey) {
3781
+ event.preventDefault();
3782
+ onMoveToBody();
3783
+ return;
3784
+ }
3785
+ if (event.key !== "ArrowDown" || event.shiftKey || event.altKey || event.metaKey || event.ctrlKey) {
3786
+ return;
3787
+ }
3788
+ const el = event.currentTarget;
3789
+ if (el.selectionStart === el.value.length && el.selectionEnd === el.value.length) {
3790
+ event.preventDefault();
3791
+ onMoveToBody();
3792
+ }
3793
+ }
3794
+ }
3795
+ );
3796
+ }
3741
3797
  const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
3742
3798
  initialMarkdown = "",
3743
3799
  editable = true,
@@ -3745,6 +3801,11 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
3745
3801
  sources,
3746
3802
  renderCitation,
3747
3803
  placeholder,
3804
+ documentTitle,
3805
+ defaultDocumentTitle = "",
3806
+ onDocumentTitleChange,
3807
+ documentTitlePlaceholder,
3808
+ documentTitleMaxLength = 200,
3748
3809
  onEditorReady,
3749
3810
  onTocChange,
3750
3811
  toc = false,
@@ -3785,7 +3846,25 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
3785
3846
  const [findOpen, setFindOpen] = useState(false);
3786
3847
  const [shortcutsOpen, setShortcutsOpen] = useState(false);
3787
3848
  const [tocItems, setTocItems] = useState([]);
3849
+ const [uncontrolledTitle, setUncontrolledTitle] = useState(defaultDocumentTitle);
3788
3850
  const findInputRef = useRef(null);
3851
+ const titleInputRef = useRef(null);
3852
+ const showDocumentTitleRef = useRef(false);
3853
+ const titleValueRef = useRef("");
3854
+ const onDocumentTitleChangeRef = useRef(onDocumentTitleChange);
3855
+ onDocumentTitleChangeRef.current = onDocumentTitleChange;
3856
+ const titleControlled = typeof documentTitle === "string";
3857
+ const titleControlledRef = useRef(titleControlled);
3858
+ titleControlledRef.current = titleControlled;
3859
+ const titleValue = titleControlled ? documentTitle : uncontrolledTitle;
3860
+ const showDocumentTitle = documentTitle !== false && (editable || titleValue.trim().length > 0);
3861
+ showDocumentTitleRef.current = showDocumentTitle;
3862
+ titleValueRef.current = titleValue;
3863
+ const setDocumentTitle = useCallback((next) => {
3864
+ var _a;
3865
+ if (!titleControlledRef.current) setUncontrolledTitle(next);
3866
+ (_a = onDocumentTitleChangeRef.current) == null ? void 0 : _a.call(onDocumentTitleChangeRef, next);
3867
+ }, []);
3789
3868
  const onTocChangeRef = useRef(onTocChange);
3790
3869
  onTocChangeRef.current = onTocChange;
3791
3870
  const tocItemsRef = useRef([]);
@@ -3875,6 +3954,20 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
3875
3954
  editorProps: {
3876
3955
  attributes: {
3877
3956
  class: styles$e.editorContent
3957
+ },
3958
+ handleKeyDown: (_view, event) => {
3959
+ if (!showDocumentTitleRef.current) return false;
3960
+ if (event.key !== "ArrowUp" || event.shiftKey || event.altKey || event.metaKey || event.ctrlKey || isComposingKeyEvent(event)) {
3961
+ return false;
3962
+ }
3963
+ if (!isAtDocumentStart(_view.state.selection)) return false;
3964
+ const title = titleInputRef.current;
3965
+ if (!title) return false;
3966
+ event.preventDefault();
3967
+ title.focus();
3968
+ const end = title.value.length;
3969
+ title.setSelectionRange(end, end);
3970
+ return true;
3878
3971
  }
3879
3972
  }
3880
3973
  });
@@ -4042,6 +4135,7 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
4042
4135
  var _a;
4043
4136
  return ((_a = editor == null ? void 0 : editor.getMarkdown) == null ? void 0 : _a.call(editor)) ?? "";
4044
4137
  },
4138
+ getDocumentTitle: () => showDocumentTitleRef.current ? titleValueRef.current : "",
4045
4139
  getHTML: () => {
4046
4140
  var _a;
4047
4141
  return ((_a = editor == null ? void 0 : editor.getHTML) == null ? void 0 : _a.call(editor)) ?? "";
@@ -4099,6 +4193,20 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
4099
4193
  children: /* @__PURE__ */ jsx(KeyboardIcon, { size: 18 })
4100
4194
  }
4101
4195
  ) : null;
4196
+ const padDrag = showBlockDrag ? styles$e.withBlockDrag : "";
4197
+ const padToc = toc && !blockDragMobile && tocItems.length > 0 ? styles$e.withToc : "";
4198
+ const editorSurface = /* @__PURE__ */ jsx(ImagePreviewHost, { locale, activate: editable ? "dblclick" : "click", children: /* @__PURE__ */ jsx(
4199
+ EditorContent,
4200
+ {
4201
+ editor,
4202
+ className: [
4203
+ styles$e.editorScroll,
4204
+ showDocumentTitle ? "" : padDrag,
4205
+ showDocumentTitle ? "" : padToc,
4206
+ className ?? ""
4207
+ ].filter(Boolean).join(" ")
4208
+ }
4209
+ ) });
4102
4210
  return /* @__PURE__ */ jsxs(
4103
4211
  "div",
4104
4212
  {
@@ -4115,18 +4223,21 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
4115
4223
  locale
4116
4224
  }
4117
4225
  ) : null,
4118
- /* @__PURE__ */ jsx(ImagePreviewHost, { locale, activate: editable ? "dblclick" : "click", children: /* @__PURE__ */ jsx(
4119
- EditorContent,
4120
- {
4121
- editor,
4122
- className: [
4123
- styles$e.editorScroll,
4124
- showBlockDrag ? styles$e.withBlockDrag : "",
4125
- toc && !blockDragMobile && tocItems.length > 0 ? styles$e.withToc : "",
4126
- className ?? ""
4127
- ].filter(Boolean).join(" ")
4128
- }
4129
- ) }),
4226
+ showDocumentTitle ? /* @__PURE__ */ jsxs("div", { className: [styles$e.titleStack, padDrag, padToc].filter(Boolean).join(" "), children: [
4227
+ /* @__PURE__ */ jsx(
4228
+ DocumentTitleField,
4229
+ {
4230
+ value: titleValue,
4231
+ placeholder: documentTitlePlaceholder ?? getLocaleBundle(locale).titlePlaceholder,
4232
+ maxLength: documentTitleMaxLength,
4233
+ readOnly: !editable,
4234
+ inputRef: titleInputRef,
4235
+ onChange: setDocumentTitle,
4236
+ onMoveToBody: () => editor == null ? void 0 : editor.commands.focus("start")
4237
+ }
4238
+ ),
4239
+ editorSurface
4240
+ ] }) : editorSurface,
4130
4241
  editor && showBlockDrag ? /* @__PURE__ */ jsx(BlockDragHandle, { editor }) : null,
4131
4242
  editor && characterCount ? /* @__PURE__ */ jsxs("div", { className: styles$e.editorStatus, children: [
4132
4243
  /* @__PURE__ */ jsx(CharacterCountStatus, { editor, locale }),
@@ -4237,6 +4348,30 @@ const ESCAPE_GUARDS = [
4237
4348
  '[role="listbox"]',
4238
4349
  '[role="menu"]'
4239
4350
  ].join(",");
4351
+ const POPUP_MENU_ROOT = "[data-radix-popper-content-wrapper], .ant-menu-submenu-popup, .ant-dropdown, .ant-select-dropdown, .ant-cascader-menus, .ant-picker-dropdown, .ant-popover";
4352
+ function isShown(el) {
4353
+ let current = el;
4354
+ while (current && current !== document.documentElement) {
4355
+ if (!(current instanceof HTMLElement)) return false;
4356
+ if (current.hidden || current.getAttribute("aria-hidden") === "true") return false;
4357
+ const style = window.getComputedStyle(current);
4358
+ if (style.display === "none" || style.visibility === "hidden") return false;
4359
+ current = current.parentElement;
4360
+ }
4361
+ return true;
4362
+ }
4363
+ function isEscapeLayer(node) {
4364
+ if (!isShown(node)) return false;
4365
+ if (node.getAttribute("role") !== "menu") return true;
4366
+ if (node.closest(POPUP_MENU_ROOT)) return true;
4367
+ if (node.classList.contains("ant-menu-root") || node.closest('nav, [role="navigation"], aside, .ant-layout-sider')) {
4368
+ return false;
4369
+ }
4370
+ return true;
4371
+ }
4372
+ function escapeLayerOpen() {
4373
+ return [...document.querySelectorAll(ESCAPE_GUARDS)].some(isEscapeLayer);
4374
+ }
4240
4375
  let savedBodyOverflow = null;
4241
4376
  function readExplicitTarget(target) {
4242
4377
  if (typeof target === "function") return target();
@@ -4318,7 +4453,7 @@ function useToolbarFullscreen({
4318
4453
  if (!fullscreen) return;
4319
4454
  const onKey = (event) => {
4320
4455
  if (event.key !== "Escape" || isComposingKeyEvent(event)) return;
4321
- if (document.querySelector(ESCAPE_GUARDS)) return;
4456
+ if (escapeLayerOpen()) return;
4322
4457
  if (!editor.isDestroyed && editor.view.dom.classList.contains("tmr-format-painter")) {
4323
4458
  return;
4324
4459
  }