mirror of
https://gitlab.com/ArkHost/HelixNotes.git
synced 2026-07-23 23:35:57 +02:00
Fix typing stutter in large notes by debouncing per-keystroke document scans
This commit is contained in:
@@ -180,6 +180,8 @@
|
|||||||
outlineHeadings = headings;
|
outlineHeadings = headings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const scheduleOutline = debounce(updateOutline, 250);
|
||||||
|
|
||||||
function handleOutlineResize(delta: number) {
|
function handleOutlineResize(delta: number) {
|
||||||
$outlineWidth = Math.max(160, Math.min(500, $outlineWidth - delta));
|
$outlineWidth = Math.max(160, Math.min(500, $outlineWidth - delta));
|
||||||
}
|
}
|
||||||
@@ -1038,6 +1040,38 @@
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Remap decorations while typing; full rebuild 300ms after it settles, so large notes don't rescan the whole doc per keystroke.
|
||||||
|
function lazyDecorationPlugin(key: PluginKey, build: (doc: any) => DecorationSet) {
|
||||||
|
return new Plugin({
|
||||||
|
key,
|
||||||
|
state: {
|
||||||
|
init: (_config: any, state: any) => build(state.doc),
|
||||||
|
apply: (tr: any, old: DecorationSet, _oldState: any, newState: any) => {
|
||||||
|
if (tr.getMeta(key) === 'rebuildDecos') return build(newState.doc);
|
||||||
|
if (!tr.docChanged) return old;
|
||||||
|
return old.map(tr.mapping, tr.doc);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
decorations(state: any) { return key.getState(state); },
|
||||||
|
},
|
||||||
|
view() {
|
||||||
|
let timer: ReturnType<typeof setTimeout> | null = null;
|
||||||
|
return {
|
||||||
|
update(view: any, prev: any) {
|
||||||
|
if (view.state.doc === prev.doc) return;
|
||||||
|
if (timer) clearTimeout(timer);
|
||||||
|
timer = setTimeout(() => {
|
||||||
|
timer = null;
|
||||||
|
if (!view.isDestroyed) view.dispatch(view.state.tr.setMeta(key, 'rebuildDecos'));
|
||||||
|
}, 300);
|
||||||
|
},
|
||||||
|
destroy() { if (timer) clearTimeout(timer); },
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const MermaidRenderer = Extension.create({
|
const MermaidRenderer = Extension.create({
|
||||||
name: 'mermaidRendererOptIn',
|
name: 'mermaidRendererOptIn',
|
||||||
addProseMirrorPlugins() {
|
addProseMirrorPlugins() {
|
||||||
@@ -1297,21 +1331,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const pluginKey = new PluginKey('mermaidRendererOptIn');
|
const pluginKey = new PluginKey('mermaidRendererOptIn');
|
||||||
return [
|
return [lazyDecorationPlugin(pluginKey, buildDecorations)];
|
||||||
new Plugin({
|
|
||||||
key: pluginKey,
|
|
||||||
state: {
|
|
||||||
init: (_, state) => buildDecorations(state.doc),
|
|
||||||
apply: (tr, old, _oldState, newState) => {
|
|
||||||
if (!tr.docChanged) return old;
|
|
||||||
return buildDecorations(newState.doc);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
decorations(state) { return pluginKey.getState(state); },
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
];
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1347,18 +1367,7 @@
|
|||||||
return DecorationSet.create(doc, decos);
|
return DecorationSet.create(doc, decos);
|
||||||
}
|
}
|
||||||
const pluginKey = new PluginKey('codeBlockCopyButton');
|
const pluginKey = new PluginKey('codeBlockCopyButton');
|
||||||
return [
|
return [lazyDecorationPlugin(pluginKey, buildDecorations)];
|
||||||
new Plugin({
|
|
||||||
key: pluginKey,
|
|
||||||
state: {
|
|
||||||
init: (_, state) => buildDecorations(state.doc),
|
|
||||||
apply: (tr, old) => { if (!tr.docChanged) return old; return buildDecorations(tr.doc); },
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
decorations(state) { return pluginKey.getState(state); },
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
];
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1456,21 +1465,7 @@
|
|||||||
const ColorSwatch = Extension.create({
|
const ColorSwatch = Extension.create({
|
||||||
name: 'colorSwatch',
|
name: 'colorSwatch',
|
||||||
addProseMirrorPlugins() {
|
addProseMirrorPlugins() {
|
||||||
return [
|
return [lazyDecorationPlugin(colorSwatchPluginKey, buildColorSwatchDecorations)];
|
||||||
new Plugin({
|
|
||||||
key: colorSwatchPluginKey,
|
|
||||||
state: {
|
|
||||||
init: (_, state) => buildColorSwatchDecorations(state.doc),
|
|
||||||
apply: (tr, old, _oldState, newState) => {
|
|
||||||
if (!tr.docChanged) return old;
|
|
||||||
return buildColorSwatchDecorations(newState.doc);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
decorations(state) { return colorSwatchPluginKey.getState(state); },
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
];
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1510,21 +1505,7 @@
|
|||||||
const TaskMetaDim = Extension.create({
|
const TaskMetaDim = Extension.create({
|
||||||
name: 'taskMetaDim',
|
name: 'taskMetaDim',
|
||||||
addProseMirrorPlugins() {
|
addProseMirrorPlugins() {
|
||||||
return [
|
return [lazyDecorationPlugin(taskMetaPluginKey, buildTaskMetaDecorations)];
|
||||||
new Plugin({
|
|
||||||
key: taskMetaPluginKey,
|
|
||||||
state: {
|
|
||||||
init: (_, state) => buildTaskMetaDecorations(state.doc),
|
|
||||||
apply: (tr, old, _oldState, newState) => {
|
|
||||||
if (!tr.docChanged) return old;
|
|
||||||
return buildTaskMetaDecorations(newState.doc);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
decorations(state) { return taskMetaPluginKey.getState(state); },
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
];
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -2638,6 +2619,8 @@
|
|||||||
charCount = text.replace(/\s/g, '').length;
|
charCount = text.replace(/\s/g, '').length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const scheduleCounts = debounce(updateCounts, 250);
|
||||||
|
|
||||||
async function toggleInfo() {
|
async function toggleInfo() {
|
||||||
if (!showInfo && $activeNote) {
|
if (!showInfo && $activeNote) {
|
||||||
historyLoading = true;
|
historyLoading = true;
|
||||||
@@ -4148,12 +4131,8 @@
|
|||||||
}
|
}
|
||||||
$editorDirty = true;
|
$editorDirty = true;
|
||||||
autoSave();
|
autoSave();
|
||||||
if (!isMobile && showOutline) updateOutline();
|
if (!isMobile && showOutline) scheduleOutline();
|
||||||
if (editor) {
|
if (showInfo) scheduleCounts();
|
||||||
const text = editor.state.doc.textContent;
|
|
||||||
wordCount = countWords(text);
|
|
||||||
charCount = text.replace(/\s/g, '').length;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
editorReady = true;
|
editorReady = true;
|
||||||
@@ -8984,11 +8963,7 @@
|
|||||||
list-style-type: square;
|
list-style-type: square;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ordered lists render their number via a counter in normal content flow
|
/* Counter-based numbering: WebKitGTK clips the native ol marker (overflow:hidden), so 11 rendered as 1. list-item respects <ol start> + nesting. */
|
||||||
instead of the native outside marker. WebKitGTK (Linux) clips the native
|
|
||||||
marker against the editor's overflow:hidden box, so two-digit numbers
|
|
||||||
showed only the last digit (11 -> 1). The built-in `list-item` counter
|
|
||||||
still respects the <ol start> attribute and per-level nesting. */
|
|
||||||
:global(.tiptap-wrapper .tiptap ol) {
|
:global(.tiptap-wrapper .tiptap ol) {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user