Merge pull request #8882 from 01zulfi/editor/fix-collapsible-hidden-under

editor: fix disappearing nodes under collapsed headings if heading is edited
This commit is contained in:
Abdullah Atta
2025-10-30 13:29:05 +05:00
committed by GitHub
6 changed files with 50 additions and 38 deletions

View File

@@ -258,10 +258,10 @@ export const Callout = Node.create({
container.onmousedown = onClick; container.onmousedown = onClick;
container.ontouchstart = onClick; container.ontouchstart = onClick;
if (node.attrs.hiddenUnder) { if (node.attrs.hidden) {
container.dataset.hiddenUnder = node.attrs.hiddenUnder; container.dataset.hidden = node.attrs.hidden;
} else { } else {
delete container.dataset.hiddenUnder; delete container.dataset.hidden;
} }
return { return {
@@ -275,9 +275,9 @@ export const Callout = Node.create({
if (updatedNode.attrs.collapsed) container.classList.add("collapsed"); if (updatedNode.attrs.collapsed) container.classList.add("collapsed");
else container.classList.remove("collapsed"); else container.classList.remove("collapsed");
if (updatedNode.attrs.hiddenUnder) if (updatedNode.attrs.hidden)
container.dataset.hiddenUnder = updatedNode.attrs.hiddenUnder; container.dataset.hidden = updatedNode.attrs.hidden;
else delete container.dataset.hiddenUnder; else delete container.dataset.hidden;
return true; return true;
} }

View File

@@ -555,7 +555,7 @@ export const CodeBlock = Node.create<CodeBlockOptions>({
compareCaretPosition(prev.caretPosition, next.caretPosition) || compareCaretPosition(prev.caretPosition, next.caretPosition) ||
prev.language !== next.language || prev.language !== next.language ||
prev.indentType !== next.indentType || prev.indentType !== next.indentType ||
prev.hiddenUnder !== next.hiddenUnder prev.hidden !== next.hidden
); );
} }
}); });

View File

@@ -89,14 +89,14 @@ export const Heading = TiptapHeading.extend({
{ {
types: COLLAPSIBLE_BLOCK_TYPES, types: COLLAPSIBLE_BLOCK_TYPES,
attributes: { attributes: {
hiddenUnder: { hidden: {
default: null, default: false,
keepOnSplit: false, keepOnSplit: false,
parseHTML: (element) => element.dataset.hiddenUnder || null, parseHTML: (element) => element.dataset.hidden === "true",
renderHTML: (attributes) => { renderHTML: (attributes) => {
if (!attributes.hiddenUnder) return {}; if (!attributes.hidden) return {};
return { return {
"data-hidden-under": attributes.hiddenUnder "data-hidden": attributes.hidden === true
}; };
} }
} }
@@ -200,16 +200,9 @@ export const Heading = TiptapHeading.extend({
if (currentNode && currentNode.type.name === "heading") { if (currentNode && currentNode.type.name === "heading") {
const shouldCollapse = !currentNode.attrs.collapsed; const shouldCollapse = !currentNode.attrs.collapsed;
const headingLevel = currentNode.attrs.level; const headingLevel = currentNode.attrs.level;
const headingId = currentNode.attrs.blockId;
tr.setNodeAttribute(pos, "collapsed", shouldCollapse); tr.setNodeAttribute(pos, "collapsed", shouldCollapse);
toggleNodesUnderHeading( toggleNodesUnderHeading(tr, pos, headingLevel, shouldCollapse);
tr,
pos,
headingLevel,
shouldCollapse,
headingId
);
} }
return true; return true;
}); });
@@ -234,9 +227,9 @@ export const Heading = TiptapHeading.extend({
if (updatedNode.attrs.collapsed) heading.dataset.collapsed = "true"; if (updatedNode.attrs.collapsed) heading.dataset.collapsed = "true";
else delete heading.dataset.collapsed; else delete heading.dataset.collapsed;
if (updatedNode.attrs.hiddenUnder) if (updatedNode.attrs.hidden)
heading.dataset.hiddenUnder = updatedNode.attrs.hiddenUnder; heading.dataset.hidden = updatedNode.attrs.hidden;
else delete heading.dataset.hiddenUnder; else delete heading.dataset.hidden;
if (updatedNode.attrs.textAlign) if (updatedNode.attrs.textAlign)
heading.style.textAlign = heading.style.textAlign =
@@ -259,8 +252,7 @@ function toggleNodesUnderHeading(
tr: Transaction, tr: Transaction,
headingPos: number, headingPos: number,
headingLevel: number, headingLevel: number,
isCollapsing: boolean, isCollapsing: boolean
headingId: string
) { ) {
const { doc } = tr; const { doc } = tr;
const headingNode = doc.nodeAt(headingPos); const headingNode = doc.nodeAt(headingPos);
@@ -269,6 +261,8 @@ function toggleNodesUnderHeading(
let nextPos = headingPos + headingNode.nodeSize; let nextPos = headingPos + headingNode.nodeSize;
const cursorPos = tr.selection.from; const cursorPos = tr.selection.from;
let shouldMoveCursor = false; let shouldMoveCursor = false;
let insideCollapsedHeading = false;
let nestedHeadingLevel: number | null = null;
while (nextPos < doc.content.size) { while (nextPos < doc.content.size) {
const nextNode = doc.nodeAt(nextPos); const nextNode = doc.nodeAt(nextPos);
@@ -289,15 +283,33 @@ function toggleNodesUnderHeading(
shouldMoveCursor = true; shouldMoveCursor = true;
} }
const currentPos = nextPos;
nextPos += nextNode.nodeSize;
if (COLLAPSIBLE_BLOCK_TYPES.includes(nextNode.type.name)) { if (COLLAPSIBLE_BLOCK_TYPES.includes(nextNode.type.name)) {
if (isCollapsing && typeof nextNode.attrs.hiddenUnder !== "string") { if (isCollapsing) {
tr.setNodeAttribute(nextPos, "hiddenUnder", headingId); tr.setNodeAttribute(currentPos, "hidden", true);
} else if (!isCollapsing && nextNode.attrs.hiddenUnder === headingId) { } else {
tr.setNodeAttribute(nextPos, "hiddenUnder", null); if (insideCollapsedHeading) {
if (
nextNode.type.name === "heading" &&
nestedHeadingLevel !== null &&
nextNode.attrs.level <= nestedHeadingLevel
) {
insideCollapsedHeading = false;
nestedHeadingLevel = null;
} else {
continue;
}
}
tr.setNodeAttribute(currentPos, "hidden", false);
if (nextNode.type.name === "heading" && nextNode.attrs.collapsed) {
insideCollapsedHeading = true;
nestedHeadingLevel = nextNode.attrs.level;
}
} }
} }
nextPos += nextNode.nodeSize;
} }
if (shouldMoveCursor) { if (shouldMoveCursor) {

View File

@@ -125,10 +125,10 @@ export class MathView implements NodeView, ICursorPosObserver {
if (options.className) this.dom.classList.add(options.className); if (options.className) this.dom.classList.add(options.className);
this.dom.classList.add("math-node"); this.dom.classList.add("math-node");
if (node.attrs.hiddenUnder) { if (node.attrs.hidden) {
this.dom.dataset.hiddenUnder = node.attrs.hiddenUnder; this.dom.dataset.hidden = node.attrs.hidden;
} else { } else {
delete this.dom.dataset.hiddenUnder; delete this.dom.dataset.hidden;
} }
this._mathRenderElt = document.createElement("span"); this._mathRenderElt = document.createElement("span");

View File

@@ -112,10 +112,10 @@ export class ReactNodeView<P extends ReactNodeViewProps> implements NodeView {
return; return;
} }
if (this.node.attrs.hiddenUnder) { if (this.node.attrs.hidden) {
this.domRef.dataset.hiddenUnder = this.node.attrs.hiddenUnder; this.domRef.dataset.hidden = this.node.attrs.hidden;
} else { } else {
delete this.domRef.dataset.hiddenUnder; delete this.domRef.dataset.hidden;
} }
portalProviderAPI.render(this.Component, this.domRef); portalProviderAPI.render(this.Component, this.domRef);

View File

@@ -978,7 +978,7 @@ del.diffdel {
display: none; display: none;
} }
[data-hidden-under] { [data-hidden="true"] {
display: none !important; display: none !important;
} }