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.ontouchstart = onClick;
if (node.attrs.hiddenUnder) {
container.dataset.hiddenUnder = node.attrs.hiddenUnder;
if (node.attrs.hidden) {
container.dataset.hidden = node.attrs.hidden;
} else {
delete container.dataset.hiddenUnder;
delete container.dataset.hidden;
}
return {
@@ -275,9 +275,9 @@ export const Callout = Node.create({
if (updatedNode.attrs.collapsed) container.classList.add("collapsed");
else container.classList.remove("collapsed");
if (updatedNode.attrs.hiddenUnder)
container.dataset.hiddenUnder = updatedNode.attrs.hiddenUnder;
else delete container.dataset.hiddenUnder;
if (updatedNode.attrs.hidden)
container.dataset.hidden = updatedNode.attrs.hidden;
else delete container.dataset.hidden;
return true;
}

View File

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

View File

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

View File

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

View File

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