blixify-ui-web 1.2.126 → 1.2.128
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/lib/components/input/markdown/headings.d.ts +98 -0
- package/lib/components/input/markdown/headings.d.ts.map +1 -0
- package/lib/components/input/markdown/headings.js +216 -0
- package/lib/components/input/markdown/headings.js.map +1 -0
- package/lib/components/input/markdown/index.d.ts +17 -1
- package/lib/components/input/markdown/index.d.ts.map +1 -1
- package/lib/components/input/markdown/index.js +287 -5
- package/lib/components/input/markdown/index.js.map +1 -1
- package/lib/tail.css +2 -2
- package/package.json +1 -1
|
@@ -90,6 +90,7 @@ var TableCellsIcon_1 = __importDefault(require("@heroicons/react/24/solid/TableC
|
|
|
90
90
|
var core_1 = require("@tiptap/core");
|
|
91
91
|
var filePreview_1 = require("../../display/filePreview");
|
|
92
92
|
var state_1 = require("@tiptap/pm/state");
|
|
93
|
+
var view_1 = require("@tiptap/pm/view");
|
|
93
94
|
var extension_image_1 = __importDefault(require("@tiptap/extension-image"));
|
|
94
95
|
var extensions_1 = require("@tiptap/extensions");
|
|
95
96
|
var extension_subscript_1 = __importDefault(require("@tiptap/extension-subscript"));
|
|
@@ -108,6 +109,7 @@ var turndown_1 = __importDefault(require("turndown"));
|
|
|
108
109
|
var infoWindow_1 = require("../../advanced/infoWindow");
|
|
109
110
|
var loading_1 = require("../../display/loading");
|
|
110
111
|
var mermaid_1 = require("./mermaid");
|
|
112
|
+
var headings_1 = require("./headings");
|
|
111
113
|
var md = new markdown_it_1.default({
|
|
112
114
|
html: true,
|
|
113
115
|
breaks: true,
|
|
@@ -222,6 +224,17 @@ turndownService.addRule("image", {
|
|
|
222
224
|
var alt = img.getAttribute("alt") || "";
|
|
223
225
|
var src = img.getAttribute("src") || "";
|
|
224
226
|
var title = img.getAttribute("title") || "";
|
|
227
|
+
var width = img.getAttribute("width") || "";
|
|
228
|
+
// INFO: markdown has no syntax for a size, so a resized image is written as
|
|
229
|
+
// html — the same route <video>, the file attachment and the space embed
|
|
230
|
+
// take, and markdown-it runs with html:true so it parses back on load.
|
|
231
|
+
// Written ONLY when a width was actually set: an image nobody has resized
|
|
232
|
+
// still serialises as , so every document saved before resizing
|
|
233
|
+
// existed round-trips byte-for-byte.
|
|
234
|
+
if (width) {
|
|
235
|
+
var titleAttr = title ? " title=\"".concat(title, "\"") : "";
|
|
236
|
+
return "<img src=\"".concat(src, "\" alt=\"").concat(alt, "\"").concat(titleAttr, " width=\"").concat(width, "\" />");
|
|
237
|
+
}
|
|
225
238
|
if (title) {
|
|
226
239
|
return ".concat(src, " \"").concat(title, "\")");
|
|
227
240
|
}
|
|
@@ -771,6 +784,40 @@ var TrailingParagraph = core_1.Extension.create({
|
|
|
771
784
|
];
|
|
772
785
|
},
|
|
773
786
|
});
|
|
787
|
+
/**
|
|
788
|
+
* Gives every h1-h3 in the editor the id its outline entry scrolls to.
|
|
789
|
+
*
|
|
790
|
+
* INFO: a view decoration, so it is recomputed from the document on every redraw
|
|
791
|
+
* and never enters the document itself. The two alternatives both fail: a node
|
|
792
|
+
* attribute reaches `getHTML()` and would be written into the saved markdown,
|
|
793
|
+
* and a DOM write is undone the next time ProseMirror redraws the heading.
|
|
794
|
+
*/
|
|
795
|
+
var HeadingAnchors = core_1.Extension.create({
|
|
796
|
+
name: "headingAnchors",
|
|
797
|
+
addProseMirrorPlugins: function () {
|
|
798
|
+
return [
|
|
799
|
+
new state_1.Plugin({
|
|
800
|
+
key: new state_1.PluginKey("headingAnchors"),
|
|
801
|
+
props: {
|
|
802
|
+
// INFO: cast because the tree carries two copies of prosemirror-view —
|
|
803
|
+
// one hoisted, one under @tiptap/pm — so the DecorationSet built from
|
|
804
|
+
// `@tiptap/pm/view` is a different nominal type to the one tiptap's own
|
|
805
|
+
// Plugin signature was compiled against, despite being the same class
|
|
806
|
+
// at runtime. Importing the hoisted copy directly would fix the types
|
|
807
|
+
// by adding an undeclared dependency, which is the worse trade.
|
|
808
|
+
decorations: function (state) {
|
|
809
|
+
return view_1.DecorationSet.create(state.doc, (0, headings_1.handleBuildHeadingAnchors)(state.doc).map(function (eachAnchor) {
|
|
810
|
+
return view_1.Decoration.node(eachAnchor.from, eachAnchor.to, {
|
|
811
|
+
id: eachAnchor.id,
|
|
812
|
+
"data-heading-id": eachAnchor.id,
|
|
813
|
+
});
|
|
814
|
+
}));
|
|
815
|
+
},
|
|
816
|
+
},
|
|
817
|
+
}),
|
|
818
|
+
];
|
|
819
|
+
},
|
|
820
|
+
});
|
|
774
821
|
var SpaceEmbed = core_1.Node.create({
|
|
775
822
|
name: "spaceEmbed",
|
|
776
823
|
group: "block",
|
|
@@ -944,6 +991,206 @@ var DiagramCodeBlock = extension_code_block_1.default.extend({
|
|
|
944
991
|
return (0, react_1.ReactNodeViewRenderer)(CodeBlockComponent);
|
|
945
992
|
},
|
|
946
993
|
});
|
|
994
|
+
// INFO: below this an image is a thumbnail nobody can see the content of, and
|
|
995
|
+
// dragging past it is almost always an accident
|
|
996
|
+
var MIN_IMAGE_WIDTH = 80;
|
|
997
|
+
/**
|
|
998
|
+
* An image with drag handles on its left and right edges.
|
|
999
|
+
*
|
|
1000
|
+
* INFO: the width is previewed in local state while dragging and only committed
|
|
1001
|
+
* to the node on release. Writing it on every pointermove would put one
|
|
1002
|
+
* transaction per mouse move into the history — undo would take fifty presses to
|
|
1003
|
+
* get back — and each one fires onUpdate, which in a host with autosave is fifty
|
|
1004
|
+
* saves for one resize.
|
|
1005
|
+
*/
|
|
1006
|
+
var ResizableImageComponent = function (_a) {
|
|
1007
|
+
var _b;
|
|
1008
|
+
var node = _a.node, updateAttributes = _a.updateAttributes, editor = _a.editor, selected = _a.selected;
|
|
1009
|
+
var _c = (0, react_2.useState)(null), preview = _c[0], setPreview = _c[1];
|
|
1010
|
+
var _d = (0, react_2.useState)(false), hovered = _d[0], setHovered = _d[1];
|
|
1011
|
+
var _e = (0, react_2.useState)(null), dragging = _e[0], setDragging = _e[1];
|
|
1012
|
+
var imageRef = (0, react_2.useRef)(null);
|
|
1013
|
+
var startRef = (0, react_2.useRef)({ x: 0, width: 0 });
|
|
1014
|
+
// INFO: the pointerup handler needs the width the last move produced, and it
|
|
1015
|
+
// is registered once — reading it from state would read the value from the
|
|
1016
|
+
// render that registered it, which is the width before the drag started
|
|
1017
|
+
var previewRef = (0, react_2.useRef)(null);
|
|
1018
|
+
var _f = node.attrs, src = _f.src, alt = _f.alt, title = _f.title, width = _f.width;
|
|
1019
|
+
var editable = !!(editor === null || editor === void 0 ? void 0 : editor.isEditable);
|
|
1020
|
+
// INFO: the preview wins while dragging so the image tracks the pointer
|
|
1021
|
+
// without the document being edited on the way
|
|
1022
|
+
var shownWidth = (_b = preview !== null && preview !== void 0 ? preview : width) !== null && _b !== void 0 ? _b : null;
|
|
1023
|
+
(0, react_2.useEffect)(function () {
|
|
1024
|
+
if (!dragging)
|
|
1025
|
+
return;
|
|
1026
|
+
return handleObserveDrag();
|
|
1027
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1028
|
+
}, [dragging]);
|
|
1029
|
+
var handleObserveDrag = function () {
|
|
1030
|
+
var edge = dragging;
|
|
1031
|
+
var handleMove = function (event) {
|
|
1032
|
+
var _a, _b, _c;
|
|
1033
|
+
var delta = event.clientX - startRef.current.x;
|
|
1034
|
+
// INFO: dragging the left handle outward is dragging left, so the sign
|
|
1035
|
+
// flips — the alternative is a handle that shrinks when pulled away
|
|
1036
|
+
var next = startRef.current.width + (edge === "left" ? -delta : delta);
|
|
1037
|
+
// INFO: an event that carries no coordinate makes this NaN, and NaN is
|
|
1038
|
+
// truthy enough to be stored and falsy enough to render as no width at
|
|
1039
|
+
// all — so the image would silently lose the size it already had. There is
|
|
1040
|
+
// nothing to resize to without a coordinate, so the move is ignored.
|
|
1041
|
+
if (!Number.isFinite(next))
|
|
1042
|
+
return;
|
|
1043
|
+
// INFO: capped at the width of the COLUMN the image sits in, because a
|
|
1044
|
+
// wider image would be clipped by the page with no handle left to drag it
|
|
1045
|
+
// back. Measured from the editor element, not from the node view wrapper:
|
|
1046
|
+
// the wrapper is `fit-content` so the selection outline hugs the image,
|
|
1047
|
+
// which means measuring it caps the image at its own current width — an
|
|
1048
|
+
// image could then be shrunk but never grown again. A container that
|
|
1049
|
+
// cannot be measured is no reason to refuse the resize.
|
|
1050
|
+
var column = (_c = (_b = (_a = imageRef.current) === null || _a === void 0 ? void 0 : _a.closest(".ProseMirror")) === null || _b === void 0 ? void 0 : _b.clientWidth) !== null && _c !== void 0 ? _c : 0;
|
|
1051
|
+
var max = column > 0 ? column : Number.MAX_SAFE_INTEGER;
|
|
1052
|
+
var resolved = Math.round(Math.max(MIN_IMAGE_WIDTH, Math.min(next, max)));
|
|
1053
|
+
previewRef.current = resolved;
|
|
1054
|
+
setPreview(resolved);
|
|
1055
|
+
};
|
|
1056
|
+
/**
|
|
1057
|
+
* INFO: the single point where the document is edited. Committing here
|
|
1058
|
+
* rather than from the effect's cleanup keeps it out of a state updater —
|
|
1059
|
+
* React may run an updater more than once, and a write to the document is
|
|
1060
|
+
* not something that may happen twice.
|
|
1061
|
+
*/
|
|
1062
|
+
var handleUp = function () {
|
|
1063
|
+
var resolved = previewRef.current;
|
|
1064
|
+
previewRef.current = null;
|
|
1065
|
+
setDragging(null);
|
|
1066
|
+
setPreview(null);
|
|
1067
|
+
if (resolved !== null && resolved !== width)
|
|
1068
|
+
updateAttributes({ width: resolved });
|
|
1069
|
+
};
|
|
1070
|
+
window.addEventListener("pointermove", handleMove);
|
|
1071
|
+
window.addEventListener("pointerup", handleUp);
|
|
1072
|
+
window.addEventListener("pointercancel", handleUp);
|
|
1073
|
+
return function () {
|
|
1074
|
+
window.removeEventListener("pointermove", handleMove);
|
|
1075
|
+
window.removeEventListener("pointerup", handleUp);
|
|
1076
|
+
window.removeEventListener("pointercancel", handleUp);
|
|
1077
|
+
};
|
|
1078
|
+
};
|
|
1079
|
+
var handleStartDrag = function (edge) { return function (event) {
|
|
1080
|
+
var _a, _b, _c, _d;
|
|
1081
|
+
if (!editable)
|
|
1082
|
+
return;
|
|
1083
|
+
// INFO: capture phase, and propagation stopped. ProseMirror handles pointer
|
|
1084
|
+
// events on the editor element to move the selection and to drag a node
|
|
1085
|
+
// around the document — an image IS draggable — and its listener sits on an
|
|
1086
|
+
// ancestor of this handle, so a bubble-phase handler never runs: the drag
|
|
1087
|
+
// silently did nothing in a real browser while passing in jsdom, where no
|
|
1088
|
+
// editor view competes for the event.
|
|
1089
|
+
event.preventDefault();
|
|
1090
|
+
event.stopPropagation();
|
|
1091
|
+
// INFO: on a touch screen the finger leaves the 6px handle almost at once,
|
|
1092
|
+
// and without capture every later move goes to whatever is underneath — the
|
|
1093
|
+
// drag appeared to stick after a few pixels. Capture keeps the whole stream
|
|
1094
|
+
// coming here until release.
|
|
1095
|
+
try {
|
|
1096
|
+
(_b = (_a = event.currentTarget) === null || _a === void 0 ? void 0 : _a.setPointerCapture) === null || _b === void 0 ? void 0 : _b.call(_a, event.pointerId);
|
|
1097
|
+
}
|
|
1098
|
+
catch (err) {
|
|
1099
|
+
// INFO: a mouse event carries no pointerId in every browser; the drag
|
|
1100
|
+
// works from the window listeners regardless
|
|
1101
|
+
}
|
|
1102
|
+
startRef.current = {
|
|
1103
|
+
x: event.clientX,
|
|
1104
|
+
width: (_d = (_c = imageRef.current) === null || _c === void 0 ? void 0 : _c.getBoundingClientRect().width) !== null && _d !== void 0 ? _d : 0,
|
|
1105
|
+
};
|
|
1106
|
+
setDragging(edge);
|
|
1107
|
+
}; };
|
|
1108
|
+
var renderHandle = function (edge) { return (react_2.default.createElement("div", { role: "presentation", "data-testid": "image-resize-".concat(edge), onPointerDownCapture: handleStartDrag(edge),
|
|
1109
|
+
// INFO: the editor must not treat a grab of the handle as a text selection
|
|
1110
|
+
// or a node drag either, and it listens for mousedown as well
|
|
1111
|
+
onMouseDownCapture: function (event) {
|
|
1112
|
+
event.preventDefault();
|
|
1113
|
+
event.stopPropagation();
|
|
1114
|
+
}, draggable: false,
|
|
1115
|
+
// INFO: the hit area is far larger than the bar it draws. A 6px target is
|
|
1116
|
+
// reachable with a mouse and not with a thumb, which is most of why
|
|
1117
|
+
// resizing felt unresponsive on a phone rather than anything in the maths.
|
|
1118
|
+
className: "absolute ".concat(edge === "left" ? "-left-1" : "-right-1", " top-1/2 flex h-16 w-8 -translate-y-1/2 cursor-ew-resize items-center justify-center"),
|
|
1119
|
+
// INFO: touch-action none is what makes a touch drag possible at all —
|
|
1120
|
+
// otherwise the browser claims the gesture as a scroll and cancels the
|
|
1121
|
+
// pointer stream after the first few pixels, which reads as the handle
|
|
1122
|
+
// being unresponsive
|
|
1123
|
+
style: { touchAction: "none" } },
|
|
1124
|
+
react_2.default.createElement("div", { className: "h-10 w-1.5 rounded-full bg-white/90 shadow ring-1 ring-gray-900/20" }))); };
|
|
1125
|
+
/**
|
|
1126
|
+
* INFO: a double click returns the image to its natural width by clearing the
|
|
1127
|
+
* attribute rather than measuring one — so it goes back to serialising as
|
|
1128
|
+
* plain ``, exactly as it did before it was ever resized.
|
|
1129
|
+
*/
|
|
1130
|
+
var handleResetWidth = function () {
|
|
1131
|
+
if (!editable || !width)
|
|
1132
|
+
return;
|
|
1133
|
+
updateAttributes({ width: null });
|
|
1134
|
+
};
|
|
1135
|
+
var showHandles = editable && (hovered || selected || !!dragging);
|
|
1136
|
+
return (react_2.default.createElement(react_1.NodeViewWrapper, { className: "my-4",
|
|
1137
|
+
// INFO: the selection outline and the handles sit on a box the size of the
|
|
1138
|
+
// image, not the width of the line, so they do not float away from it
|
|
1139
|
+
style: { width: "fit-content", maxWidth: "100%" }, onMouseEnter: function () { return setHovered(true); }, onMouseLeave: function () { return setHovered(false); },
|
|
1140
|
+
// INFO: a touch screen has no hover, so a tap has to be what reveals the
|
|
1141
|
+
// handles. ProseMirror also selects the node on tap, but only once the
|
|
1142
|
+
// editor has focus — relying on that alone left an image on a phone with
|
|
1143
|
+
// no handles at all on first touch.
|
|
1144
|
+
onPointerDown: function (event) {
|
|
1145
|
+
if (event.pointerType !== "mouse")
|
|
1146
|
+
setHovered(true);
|
|
1147
|
+
} },
|
|
1148
|
+
react_2.default.createElement("div", { className: "relative inline-block max-w-full leading-none" },
|
|
1149
|
+
react_2.default.createElement("img", { ref: imageRef, src: src, alt: alt !== null && alt !== void 0 ? alt : "", title: title !== null && title !== void 0 ? title : undefined, draggable: false, onDoubleClick: handleResetWidth, className: "block h-auto max-w-full rounded ".concat(selected ? "ring-2 ring-primary-500" : ""), style: {
|
|
1150
|
+
// INFO: no width attribute means the image draws at its own size,
|
|
1151
|
+
// capped the way it always was
|
|
1152
|
+
width: shownWidth ? "".concat(shownWidth, "px") : undefined,
|
|
1153
|
+
maxWidth: shownWidth ? "100%" : "600px",
|
|
1154
|
+
// INFO: the browser would otherwise keep showing the resize cursor
|
|
1155
|
+
// and the pointer could slip onto the image mid-drag
|
|
1156
|
+
pointerEvents: dragging ? "none" : undefined,
|
|
1157
|
+
} }),
|
|
1158
|
+
showHandles && renderHandle("left"),
|
|
1159
|
+
showHandles && renderHandle("right"))));
|
|
1160
|
+
};
|
|
1161
|
+
/**
|
|
1162
|
+
* INFO: only a width is stored, never a height — the image keeps its own aspect
|
|
1163
|
+
* ratio, which is what makes a one-axis handle enough and makes it impossible to
|
|
1164
|
+
* save a distorted image.
|
|
1165
|
+
*/
|
|
1166
|
+
var ResizableImage = extension_image_1.default.extend({
|
|
1167
|
+
addAttributes: function () {
|
|
1168
|
+
var _a;
|
|
1169
|
+
return __assign(__assign({}, (_a = this.parent) === null || _a === void 0 ? void 0 : _a.call(this)), { width: {
|
|
1170
|
+
default: null,
|
|
1171
|
+
parseHTML: function (element) {
|
|
1172
|
+
var _a, _b;
|
|
1173
|
+
var attr = element.getAttribute("width");
|
|
1174
|
+
if (attr && !Number.isNaN(Number(attr)))
|
|
1175
|
+
return Number(attr);
|
|
1176
|
+
// INFO: a document written by an older editor carries the size in the
|
|
1177
|
+
// inline style instead, so it is read back rather than being lost
|
|
1178
|
+
var style = (_b = (_a = element.style) === null || _a === void 0 ? void 0 : _a.width) !== null && _b !== void 0 ? _b : "";
|
|
1179
|
+
var match = style.match(/^(\d+(?:\.\d+)?)px$/);
|
|
1180
|
+
return match ? Math.round(Number(match[1])) : null;
|
|
1181
|
+
},
|
|
1182
|
+
// INFO: the attribute, not a style — this is what turndown reads to
|
|
1183
|
+
// decide between html and ``, and what a browser honours when
|
|
1184
|
+
// the published page sets the html raw
|
|
1185
|
+
renderHTML: function (attributes) {
|
|
1186
|
+
return attributes.width ? { width: attributes.width } : {};
|
|
1187
|
+
},
|
|
1188
|
+
} });
|
|
1189
|
+
},
|
|
1190
|
+
addNodeView: function () {
|
|
1191
|
+
return (0, react_1.ReactNodeViewRenderer)(ResizableImageComponent);
|
|
1192
|
+
},
|
|
1193
|
+
});
|
|
947
1194
|
// Slash command items
|
|
948
1195
|
var slashCommands = [
|
|
949
1196
|
{
|
|
@@ -1061,7 +1308,7 @@ var SlashMenuList = function (_a) {
|
|
|
1061
1308
|
react_2.default.createElement("span", { className: "text-sm ".concat(darkMode ? "text-gray-200" : "text-gray-700") }, item.label))); })) : (react_2.default.createElement("div", { className: "px-4 py-2 text-sm text-gray-500" }, "No results"))));
|
|
1062
1309
|
};
|
|
1063
1310
|
var MarkdownInputContent = function (_a) {
|
|
1064
|
-
var innerRef = _a.innerRef, id = _a.id, value = _a.value, label = _a.label, subLabel = _a.subLabel, labelExtra = _a.labelExtra, infoElement = _a.infoElement, placeholder = _a.placeholder, optional = _a.optional, disabled = _a.disabled, containerClassName = _a.containerClassName, heightClassName = _a.heightClassName, borderless = _a.borderless, onChange = _a.onChange, compress = _a.compress, lib = _a.lib, uploadEndpoint = _a.uploadEndpoint, enableImageUpload = _a.enableImageUpload, enableVideoUpload = _a.enableVideoUpload, enableFileUpload = _a.enableFileUpload, darkMode = _a.darkMode, readOnly = _a.readOnly, customElement = _a.customElement, renderEmbed = _a.renderEmbed, onRequestRemove = _a.onRequestRemove, customCommands = _a.customCommands;
|
|
1311
|
+
var innerRef = _a.innerRef, id = _a.id, value = _a.value, label = _a.label, subLabel = _a.subLabel, labelExtra = _a.labelExtra, infoElement = _a.infoElement, placeholder = _a.placeholder, optional = _a.optional, disabled = _a.disabled, containerClassName = _a.containerClassName, heightClassName = _a.heightClassName, borderless = _a.borderless, onChange = _a.onChange, compress = _a.compress, lib = _a.lib, uploadEndpoint = _a.uploadEndpoint, enableImageUpload = _a.enableImageUpload, enableVideoUpload = _a.enableVideoUpload, enableFileUpload = _a.enableFileUpload, darkMode = _a.darkMode, readOnly = _a.readOnly, customElement = _a.customElement, renderEmbed = _a.renderEmbed, onRequestRemove = _a.onRequestRemove, onHeadingsChange = _a.onHeadingsChange, customCommands = _a.customCommands;
|
|
1065
1312
|
var _b = (0, react_2.useState)(""), error = _b[0], setError = _b[1];
|
|
1066
1313
|
var _c = (0, react_2.useState)(false), showTableMenu = _c[0], setShowTableMenu = _c[1];
|
|
1067
1314
|
var _d = (0, react_2.useState)(3), tableCols = _d[0], setTableCols = _d[1];
|
|
@@ -1228,6 +1475,7 @@ var MarkdownInputContent = function (_a) {
|
|
|
1228
1475
|
extension_list_1.TaskItem.configure({
|
|
1229
1476
|
nested: true,
|
|
1230
1477
|
}),
|
|
1478
|
+
HeadingAnchors,
|
|
1231
1479
|
SpaceEmbed.configure({
|
|
1232
1480
|
getRenderEmbed: function () { return renderEmbedRef.current; },
|
|
1233
1481
|
getOnRequestRemove: function () { return onRequestRemoveRef.current; },
|
|
@@ -1240,7 +1488,10 @@ var MarkdownInputContent = function (_a) {
|
|
|
1240
1488
|
extension_table_1.TableRow,
|
|
1241
1489
|
extension_table_1.TableHeader,
|
|
1242
1490
|
extension_table_1.TableCell,
|
|
1243
|
-
|
|
1491
|
+
// INFO: the same image node with drag handles. The style stays for the
|
|
1492
|
+
// html path — getHTML() is turndown's input, and a document opened by
|
|
1493
|
+
// anything that renders that html directly still gets the 600px cap.
|
|
1494
|
+
ResizableImage.configure({
|
|
1244
1495
|
inline: false,
|
|
1245
1496
|
allowBase64: true,
|
|
1246
1497
|
HTMLAttributes: {
|
|
@@ -1763,6 +2014,18 @@ var MarkdownInputContent = function (_a) {
|
|
|
1763
2014
|
}
|
|
1764
2015
|
}
|
|
1765
2016
|
}, [value, editor, pendingImagesCount]);
|
|
2017
|
+
/**
|
|
2018
|
+
* INFO: the outline of the document being edited. The ids the headings carry
|
|
2019
|
+
* in the view are produced by the HeadingAnchors plugin from the same slug
|
|
2020
|
+
* function, so an entry here and the anchor it scrolls to cannot disagree.
|
|
2021
|
+
*/
|
|
2022
|
+
var headings = (0, react_2.useMemo)(function () { return (0, headings_1.handleParseMarkdownHeadings)(value); }, [value]);
|
|
2023
|
+
var onHeadingsChangeRef = (0, react_2.useRef)(onHeadingsChange);
|
|
2024
|
+
onHeadingsChangeRef.current = onHeadingsChange;
|
|
2025
|
+
(0, react_2.useEffect)(function () {
|
|
2026
|
+
var _a;
|
|
2027
|
+
(_a = onHeadingsChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onHeadingsChangeRef, headings);
|
|
2028
|
+
}, [headings]);
|
|
1766
2029
|
(0, react_2.useImperativeHandle)(innerRef, function () {
|
|
1767
2030
|
var methods = {
|
|
1768
2031
|
handleSubmit: function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
@@ -2152,7 +2415,7 @@ var MarkdownInputContent = function (_a) {
|
|
|
2152
2415
|
* instances or a heavy re-parse.
|
|
2153
2416
|
*/
|
|
2154
2417
|
var MarkdownStatic = function (_a) {
|
|
2155
|
-
var id = _a.id, label = _a.label, labelExtra = _a.labelExtra, subLabel = _a.subLabel, value = _a.value, darkMode = _a.darkMode, containerClassName = _a.containerClassName, lib = _a.lib;
|
|
2418
|
+
var id = _a.id, label = _a.label, labelExtra = _a.labelExtra, subLabel = _a.subLabel, value = _a.value, darkMode = _a.darkMode, containerClassName = _a.containerClassName, onHeadingsChange = _a.onHeadingsChange, lib = _a.lib;
|
|
2156
2419
|
var contentRef = (0, react_2.useRef)(null);
|
|
2157
2420
|
var labelColor = darkMode ? "text-white" : "text-gray-700";
|
|
2158
2421
|
var subColor = darkMode ? "text-gray-300" : "text-gray-500";
|
|
@@ -2178,9 +2441,17 @@ var MarkdownStatic = function (_a) {
|
|
|
2178
2441
|
};
|
|
2179
2442
|
// INFO: markdown-it is fast (~ms/field); memoize on value so a read view with
|
|
2180
2443
|
// many fields never re-parses on re-render — the source of the repeated freeze.
|
|
2181
|
-
var
|
|
2444
|
+
var headings = (0, react_2.useMemo)(function () { return (0, headings_1.handleParseMarkdownHeadings)(value); }, [value]);
|
|
2445
|
+
var html = (0, react_2.useMemo)(function () {
|
|
2446
|
+
return value
|
|
2447
|
+
? // INFO: the ids go into the html here, not onto the DOM afterwards —
|
|
2448
|
+
// React re-commits this string on re-render and would wipe anything
|
|
2449
|
+
// added to the mounted nodes
|
|
2450
|
+
(0, headings_1.handleInjectHeadingIds)((0, headings_1.handleCapImages)(handleRenderAttachments(md.render(value))), headings)
|
|
2451
|
+
: "";
|
|
2452
|
+
},
|
|
2182
2453
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2183
|
-
[value]);
|
|
2454
|
+
[value, headings]);
|
|
2184
2455
|
// INFO: the html is set raw, so diagrams are drawn over the mounted DOM once
|
|
2185
2456
|
// it matches this value. A document with no mermaid block never loads mermaid.
|
|
2186
2457
|
var mermaidLoader = lib === null || lib === void 0 ? void 0 : lib.mermaid;
|
|
@@ -2189,6 +2460,17 @@ var MarkdownStatic = function (_a) {
|
|
|
2189
2460
|
return;
|
|
2190
2461
|
(0, mermaid_1.handleRenderMermaidBlocks)(contentRef.current, mermaidLoader);
|
|
2191
2462
|
}, [html, mermaidLoader]);
|
|
2463
|
+
/**
|
|
2464
|
+
* INFO: the same outline the editor reports, from the same function — a
|
|
2465
|
+
* published page and the note it was published from cannot list different
|
|
2466
|
+
* sections.
|
|
2467
|
+
*/
|
|
2468
|
+
var onHeadingsChangeRef = (0, react_2.useRef)(onHeadingsChange);
|
|
2469
|
+
onHeadingsChangeRef.current = onHeadingsChange;
|
|
2470
|
+
(0, react_2.useEffect)(function () {
|
|
2471
|
+
var _a;
|
|
2472
|
+
(_a = onHeadingsChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onHeadingsChangeRef, headings);
|
|
2473
|
+
}, [headings]);
|
|
2192
2474
|
return (react_2.default.createElement("div", { className: defaultClassName },
|
|
2193
2475
|
react_2.default.createElement("div", { className: "flex flex-col" },
|
|
2194
2476
|
react_2.default.createElement("label", { className: "block text-sm font-medium ".concat(labelColor) },
|