tiptap-markdown-react 0.8.0 → 0.8.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 CHANGED
@@ -161,7 +161,7 @@ const comments: CommentRef[] = [
161
161
 
162
162
  ### 5. Equations (KaTeX)
163
163
 
164
- Insert from the toolbar **More** menu (`Inline equation` / `Block equation`). Click an existing formula to edit LaTeX with a live preview. There is no keyboard shortcut and typing `$` / `$$` does **not** convert to math.
164
+ Insert from the toolbar **More** menu (`Inline equation` / `Block equation`). Click an existing formula to edit. The editor is an anchored chip + live KaTeX preview + pill input with **Done**; inline confirms with Enter, block with ⌘/Ctrl+Enter. There is no typing shortcut and `$` / `$$` does **not** convert to math.
165
165
 
166
166
  Markdown on disk:
167
167
 
@@ -235,6 +235,8 @@ The underlying extensions `MarkdownPaste` / `MarkdownFileDrop` (and the `looksLi
235
235
  | `onError` | `(err: unknown) => void` | Side-effect error callback (e.g. failed upload). |
236
236
  | `labels` | `Partial<ToolbarLabels>` | i18n labels. |
237
237
  | `extraToolbarItems` | `ExtraToolbarItem[]` | Custom items appended to the "More" menu. |
238
+ | `labels.inlineMath` / `blockMath` | `string` | More-menu equation items. |
239
+ | `labels.mathPlaceholder` / `mathDone` / `mathNewInline` / `mathNewBlock` | `string` | Equation editor (chip, preview, Done). |
238
240
 
239
241
  ### `<MarkdownPreview>` (client)
240
242
 
@@ -1,12 +1,15 @@
1
+ import { Editor } from '@tiptap/react';
1
2
  import { MathKind } from '../math';
2
3
  export interface MathEditorPopoverProps {
4
+ editor: Editor;
3
5
  kind: MathKind;
6
+ mode: 'insert' | 'edit';
7
+ pos?: number;
4
8
  latex: string;
5
- title: string;
9
+ newLabel: string;
6
10
  placeholder: string;
7
11
  doneLabel: string;
8
- cancelLabel: string;
9
12
  onConfirm: (latex: string) => void;
10
13
  onCancel: () => void;
11
14
  }
12
- export declare function MathEditorPopover({ kind, latex, title, placeholder, doneLabel, cancelLabel, onConfirm, onCancel, }: MathEditorPopoverProps): import('react').ReactPortal;
15
+ export declare function MathEditorPopover({ editor, kind, mode, pos, latex, newLabel, placeholder, doneLabel, onConfirm, onCancel, }: MathEditorPopoverProps): import("react").JSX.Element;
package/dist/index.js CHANGED
@@ -590,7 +590,9 @@ const defaultToolbarLabels = {
590
590
  blockMath: "Block equation",
591
591
  mathPlaceholder: "E = mc^2",
592
592
  mathDone: "Done",
593
- mathCancel: "Cancel"
593
+ mathCancel: "Cancel",
594
+ mathNewInline: "New equation",
595
+ mathNewBlock: "Add a TeX equation"
594
596
  };
595
597
  const defaultColorPaletteLabels = {
596
598
  none: "None",
@@ -979,36 +981,42 @@ function insertMarkdown(editor, markdown, sources = []) {
979
981
  const prepared = enrichMarkdownCitations(markdown, sources);
980
982
  editor.chain().focus().insertContent(prepared, { contentType: "markdown" }).run();
981
983
  }
982
- const toolbar = "_toolbar_8cpy8_2";
983
- const inner = "_inner_8cpy8_15";
984
- const btn = "_btn_8cpy8_27";
985
- const btnActive = "_btnActive_8cpy8_50";
986
- const tableBubble = "_tableBubble_8cpy8_66";
987
- const txtIcon = "_txtIcon_8cpy8_78";
988
- const colorIcon = "_colorIcon_8cpy8_86";
989
- const colorIconGlyph = "_colorIconGlyph_8cpy8_94";
990
- const colorIconBar = "_colorIconBar_8cpy8_100";
991
- const scriptTrigger = "_scriptTrigger_8cpy8_107";
992
- const scriptTriggerGlyph = "_scriptTriggerGlyph_8cpy8_127";
993
- const divider = "_divider_8cpy8_135";
994
- const styleTrigger = "_styleTrigger_8cpy8_144";
995
- const styleTriggerLabel = "_styleTriggerLabel_8cpy8_173";
996
- const styleTriggerCaret = "_styleTriggerCaret_8cpy8_181";
997
- const styleItem = "_styleItem_8cpy8_187";
998
- const styleIcon = "_styleIcon_8cpy8_193";
999
- const scriptGlyph = "_scriptGlyph_8cpy8_203";
1000
- const menu = "_menu_8cpy8_215";
1001
- const menuItem = "_menuItem_8cpy8_226";
1002
- const menuItemSelected = "_menuItemSelected_8cpy8_252";
1003
- const popoverContent$1 = "_popoverContent_8cpy8_266";
1004
- const mathOverlay = "_mathOverlay_8cpy8_270";
1005
- const mathPopover = "_mathPopover_8cpy8_280";
1006
- const mathTitle = "_mathTitle_8cpy8_290";
1007
- const mathTextarea = "_mathTextarea_8cpy8_297";
1008
- const mathPreview = "_mathPreview_8cpy8_316";
1009
- const mathActions = "_mathActions_8cpy8_326";
1010
- const mathBtn = "_mathBtn_8cpy8_333";
1011
- const mathBtnPrimary = "_mathBtnPrimary_8cpy8_348";
984
+ const toolbar = "_toolbar_z6tes_2";
985
+ const inner = "_inner_z6tes_15";
986
+ const btn = "_btn_z6tes_27";
987
+ const btnActive = "_btnActive_z6tes_50";
988
+ const tableBubble = "_tableBubble_z6tes_66";
989
+ const txtIcon = "_txtIcon_z6tes_78";
990
+ const colorIcon = "_colorIcon_z6tes_86";
991
+ const colorIconGlyph = "_colorIconGlyph_z6tes_94";
992
+ const colorIconBar = "_colorIconBar_z6tes_100";
993
+ const scriptTrigger = "_scriptTrigger_z6tes_107";
994
+ const scriptTriggerGlyph = "_scriptTriggerGlyph_z6tes_127";
995
+ const divider = "_divider_z6tes_135";
996
+ const styleTrigger = "_styleTrigger_z6tes_144";
997
+ const styleTriggerLabel = "_styleTriggerLabel_z6tes_173";
998
+ const styleTriggerCaret = "_styleTriggerCaret_z6tes_181";
999
+ const styleItem = "_styleItem_z6tes_187";
1000
+ const styleIcon = "_styleIcon_z6tes_193";
1001
+ const scriptGlyph = "_scriptGlyph_z6tes_203";
1002
+ const menu = "_menu_z6tes_215";
1003
+ const menuItem = "_menuItem_z6tes_226";
1004
+ const menuItemSelected = "_menuItemSelected_z6tes_252";
1005
+ const popoverContent$1 = "_popoverContent_z6tes_266";
1006
+ const mathAnchor = "_mathAnchor_z6tes_270";
1007
+ const mathContent = "_mathContent_z6tes_277";
1008
+ const mathStack = "_mathStack_z6tes_286";
1009
+ const mathStackBlock = "_mathStackBlock_z6tes_293";
1010
+ const mathHint = "_mathHint_z6tes_298";
1011
+ const mathHintBlock = "_mathHintBlock_z6tes_310";
1012
+ const mathHintIcon = "_mathHintIcon_z6tes_316";
1013
+ const mathPreviewInline = "_mathPreviewInline_z6tes_322";
1014
+ const mathPreviewBlock = "_mathPreviewBlock_z6tes_332";
1015
+ const mathField = "_mathField_z6tes_347";
1016
+ const mathFieldBlock = "_mathFieldBlock_z6tes_359";
1017
+ const mathInput = "_mathInput_z6tes_366";
1018
+ const mathDone = "_mathDone_z6tes_384";
1019
+ const mathDoneKbd = "_mathDoneKbd_z6tes_409";
1012
1020
  const styles$3 = {
1013
1021
  toolbar,
1014
1022
  inner,
@@ -1032,14 +1040,20 @@ const styles$3 = {
1032
1040
  menuItem,
1033
1041
  menuItemSelected,
1034
1042
  popoverContent: popoverContent$1,
1035
- mathOverlay,
1036
- mathPopover,
1037
- mathTitle,
1038
- mathTextarea,
1039
- mathPreview,
1040
- mathActions,
1041
- mathBtn,
1042
- mathBtnPrimary
1043
+ mathAnchor,
1044
+ mathContent,
1045
+ mathStack,
1046
+ mathStackBlock,
1047
+ mathHint,
1048
+ mathHintBlock,
1049
+ mathHintIcon,
1050
+ mathPreviewInline,
1051
+ mathPreviewBlock,
1052
+ mathField,
1053
+ mathFieldBlock,
1054
+ mathInput,
1055
+ mathDone,
1056
+ mathDoneKbd
1043
1057
  };
1044
1058
  const palette = "_palette_x5lrq_2";
1045
1059
  const noneRow = "_noneRow_x5lrq_11";
@@ -1116,93 +1130,198 @@ function ColorPalette({ value, onPick, labels }) {
1116
1130
  )) })
1117
1131
  ] });
1118
1132
  }
1133
+ function getMathAnchorRect(editor, kind, pos) {
1134
+ const editorRect = editor.view.dom.getBoundingClientRect();
1135
+ if (pos != null) {
1136
+ const dom = editor.view.nodeDOM(pos);
1137
+ const el = dom instanceof HTMLElement ? dom : dom instanceof Node ? dom.parentElement : null;
1138
+ if (el) {
1139
+ const r = el.getBoundingClientRect();
1140
+ if (kind === "block") {
1141
+ return new DOMRect(editorRect.left, r.top, editorRect.width, r.height);
1142
+ }
1143
+ return r;
1144
+ }
1145
+ }
1146
+ const coords = editor.view.coordsAtPos(editor.state.selection.from);
1147
+ if (kind === "block") {
1148
+ return new DOMRect(editorRect.left, coords.bottom, editorRect.width, 0);
1149
+ }
1150
+ return new DOMRect(coords.left, coords.bottom, 0, 0);
1151
+ }
1119
1152
  function MathEditorPopover({
1153
+ editor,
1120
1154
  kind,
1155
+ mode,
1156
+ pos,
1121
1157
  latex,
1122
- title,
1158
+ newLabel,
1123
1159
  placeholder,
1124
1160
  doneLabel,
1125
- cancelLabel,
1126
1161
  onConfirm,
1127
1162
  onCancel
1128
1163
  }) {
1129
1164
  const [draft, setDraft] = useState(latex);
1165
+ const [rect, setRect] = useState(() => getMathAnchorRect(editor, kind, pos));
1130
1166
  const titleId = useId();
1167
+ const inputRef = useRef(null);
1168
+ const confirmedRef = useRef(false);
1169
+ const isBlock = kind === "block";
1131
1170
  useEffect(() => {
1132
1171
  setDraft(latex);
1133
1172
  }, [latex]);
1134
1173
  useEffect(() => {
1135
- const onKey = (e) => {
1136
- if (e.key === "Escape") onCancel();
1174
+ const update = () => setRect(getMathAnchorRect(editor, kind, pos));
1175
+ update();
1176
+ window.addEventListener("resize", update);
1177
+ window.addEventListener("scroll", update, true);
1178
+ return () => {
1179
+ window.removeEventListener("resize", update);
1180
+ window.removeEventListener("scroll", update, true);
1137
1181
  };
1138
- document.addEventListener("keydown", onKey, true);
1139
- return () => document.removeEventListener("keydown", onKey, true);
1140
- }, [onCancel]);
1141
- const preview = renderMathHtml(draft.trim(), kind === "block");
1182
+ }, [editor, kind, pos]);
1183
+ useEffect(() => {
1184
+ var _a;
1185
+ (_a = inputRef.current) == null ? void 0 : _a.focus();
1186
+ }, []);
1187
+ useEffect(() => {
1188
+ if (pos == null) return;
1189
+ const dom = editor.view.nodeDOM(pos);
1190
+ const el = dom instanceof HTMLElement ? dom : dom instanceof Node ? dom.parentElement : null;
1191
+ if (!el) return;
1192
+ el.classList.add("tmr-math-editing");
1193
+ return () => {
1194
+ el.classList.remove("tmr-math-editing");
1195
+ };
1196
+ }, [editor, pos]);
1197
+ const preview = useMemo(
1198
+ () => renderMathHtml(draft.trim(), isBlock),
1199
+ [draft, isBlock]
1200
+ );
1142
1201
  const canSubmit = draft.trim().length > 0;
1143
- return createPortal(
1144
- /* @__PURE__ */ jsx(
1145
- "div",
1146
- {
1147
- className: styles$3.mathOverlay,
1148
- onMouseDown: (e) => {
1149
- if (e.target === e.currentTarget) onCancel();
1150
- },
1151
- children: /* @__PURE__ */ jsxs(
1152
- "div",
1202
+ const showHint = !canSubmit && mode === "insert";
1203
+ const submit = () => {
1204
+ if (!canSubmit) return;
1205
+ confirmedRef.current = true;
1206
+ onConfirm(draft.trim());
1207
+ };
1208
+ const onKeyDown = (e) => {
1209
+ if (e.key === "Escape") {
1210
+ e.preventDefault();
1211
+ onCancel();
1212
+ return;
1213
+ }
1214
+ if (e.key !== "Enter") return;
1215
+ if (isBlock && !(e.metaKey || e.ctrlKey)) return;
1216
+ e.preventDefault();
1217
+ submit();
1218
+ };
1219
+ const field = isBlock ? /* @__PURE__ */ jsx(
1220
+ "textarea",
1221
+ {
1222
+ ref: inputRef,
1223
+ className: styles$3.mathInput,
1224
+ value: draft,
1225
+ placeholder,
1226
+ rows: Math.max(3, draft.split("\n").length),
1227
+ "aria-labelledby": titleId,
1228
+ onChange: (e) => setDraft(e.target.value),
1229
+ onKeyDown
1230
+ }
1231
+ ) : /* @__PURE__ */ jsx(
1232
+ "input",
1233
+ {
1234
+ ref: inputRef,
1235
+ className: styles$3.mathInput,
1236
+ value: draft,
1237
+ placeholder,
1238
+ "aria-labelledby": titleId,
1239
+ onChange: (e) => setDraft(e.target.value),
1240
+ onKeyDown
1241
+ }
1242
+ );
1243
+ return /* @__PURE__ */ jsxs(
1244
+ Popover.Root,
1245
+ {
1246
+ open: true,
1247
+ onOpenChange: (open) => {
1248
+ if (!open && !confirmedRef.current) onCancel();
1249
+ },
1250
+ children: [
1251
+ /* @__PURE__ */ jsx(Popover.Anchor, { asChild: true, children: /* @__PURE__ */ jsx(
1252
+ "span",
1153
1253
  {
1154
- className: styles$3.mathPopover,
1155
- role: "dialog",
1156
- "aria-modal": "true",
1157
- "aria-labelledby": titleId,
1158
- onMouseDown: (e) => e.stopPropagation(),
1159
- children: [
1160
- /* @__PURE__ */ jsx("div", { id: titleId, className: styles$3.mathTitle, children: title }),
1161
- /* @__PURE__ */ jsx(
1162
- "textarea",
1163
- {
1164
- className: styles$3.mathTextarea,
1165
- value: draft,
1166
- placeholder,
1167
- autoFocus: true,
1168
- rows: kind === "block" ? 5 : 3,
1169
- onChange: (e) => setDraft(e.target.value)
1170
- }
1171
- ),
1172
- /* @__PURE__ */ jsx(
1173
- "div",
1174
- {
1175
- className: styles$3.mathPreview,
1176
- dangerouslySetInnerHTML: { __html: preview }
1177
- }
1178
- ),
1179
- /* @__PURE__ */ jsxs("div", { className: styles$3.mathActions, children: [
1180
- /* @__PURE__ */ jsx(
1181
- "button",
1182
- {
1183
- type: "button",
1184
- className: styles$3.mathBtn,
1185
- onClick: onCancel,
1186
- children: cancelLabel
1187
- }
1188
- ),
1189
- /* @__PURE__ */ jsx(
1190
- "button",
1191
- {
1192
- type: "button",
1193
- className: `${styles$3.mathBtn} ${styles$3.mathBtnPrimary}`,
1194
- disabled: !canSubmit,
1195
- onClick: () => onConfirm(draft.trim()),
1196
- children: doneLabel
1197
- }
1198
- )
1199
- ] })
1200
- ]
1254
+ className: styles$3.mathAnchor,
1255
+ style: { left: rect.left, top: rect.top }
1201
1256
  }
1202
- )
1203
- }
1204
- ),
1205
- document.body
1257
+ ) }),
1258
+ /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsx(
1259
+ Popover.Content,
1260
+ {
1261
+ className: styles$3.mathContent,
1262
+ side: "bottom",
1263
+ align: "start",
1264
+ sideOffset: mode === "edit" ? 0 : 6,
1265
+ collisionPadding: 12,
1266
+ style: isBlock ? { width: Math.max(rect.width, 280) } : void 0,
1267
+ onOpenAutoFocus: (e) => e.preventDefault(),
1268
+ onCloseAutoFocus: (e) => e.preventDefault(),
1269
+ children: /* @__PURE__ */ jsxs(
1270
+ "div",
1271
+ {
1272
+ className: isBlock ? `${styles$3.mathStack} ${styles$3.mathStackBlock}` : styles$3.mathStack,
1273
+ role: "dialog",
1274
+ "aria-modal": "false",
1275
+ "aria-labelledby": titleId,
1276
+ children: [
1277
+ showHint ? /* @__PURE__ */ jsxs(
1278
+ "div",
1279
+ {
1280
+ id: titleId,
1281
+ className: isBlock ? `${styles$3.mathHint} ${styles$3.mathHintBlock}` : styles$3.mathHint,
1282
+ children: [
1283
+ /* @__PURE__ */ jsx("span", { className: styles$3.mathHintIcon, "aria-hidden": true, children: isBlock ? "TeX" : "√x" }),
1284
+ newLabel
1285
+ ]
1286
+ }
1287
+ ) : /* @__PURE__ */ jsx(
1288
+ "div",
1289
+ {
1290
+ id: titleId,
1291
+ className: isBlock ? styles$3.mathPreviewBlock : styles$3.mathPreviewInline,
1292
+ dangerouslySetInnerHTML: { __html: preview }
1293
+ }
1294
+ ),
1295
+ /* @__PURE__ */ jsxs(
1296
+ "div",
1297
+ {
1298
+ className: isBlock ? `${styles$3.mathField} ${styles$3.mathFieldBlock}` : styles$3.mathField,
1299
+ children: [
1300
+ field,
1301
+ /* @__PURE__ */ jsxs(
1302
+ "button",
1303
+ {
1304
+ type: "button",
1305
+ className: styles$3.mathDone,
1306
+ disabled: !canSubmit,
1307
+ title: isBlock ? `${doneLabel} (⌘/Ctrl+Enter)` : `${doneLabel} (Enter)`,
1308
+ onClick: submit,
1309
+ children: [
1310
+ doneLabel,
1311
+ /* @__PURE__ */ jsx("span", { className: styles$3.mathDoneKbd, "aria-hidden": true, children: "↵" })
1312
+ ]
1313
+ }
1314
+ )
1315
+ ]
1316
+ }
1317
+ )
1318
+ ]
1319
+ }
1320
+ )
1321
+ }
1322
+ ) })
1323
+ ]
1324
+ }
1206
1325
  );
1207
1326
  }
1208
1327
  function ToolbarButton({
@@ -1888,12 +2007,14 @@ function EditorToolbar({
1888
2007
  mathEdit ? /* @__PURE__ */ jsx(
1889
2008
  MathEditorPopover,
1890
2009
  {
2010
+ editor,
1891
2011
  kind: mathEdit.kind,
2012
+ mode: mathEdit.mode,
2013
+ pos: mathEdit.pos,
1892
2014
  latex: mathEdit.latex,
1893
- title: mathEdit.kind === "inline" ? t.inlineMath : t.blockMath,
2015
+ newLabel: mathEdit.kind === "inline" ? t.mathNewInline : t.mathNewBlock,
1894
2016
  placeholder: t.mathPlaceholder,
1895
2017
  doneLabel: t.mathDone,
1896
- cancelLabel: t.mathCancel,
1897
2018
  onConfirm: applyMath,
1898
2019
  onCancel: () => setMathEdit(null)
1899
2020
  }