I am experiencing an unexpected behavior with a custom block-level element, custom-title
, in my ProseMirror setup. This element is intended to mirror the behavior of standard HTML block elements like h1
and p
.
// :: Object
// [Specs](#model.NodeSpec) for the nodes defined in this schema.
export const nodes: any = {
// :: NodeSpec The top level document node.
doc: {
content: "customTitle block+",
},
// :: NodeSpec A title textblock, with a `level` attribute that
// should hold the number 1. Parsed and serialized as `<custom-title>` elements.
customTitle: {
attrs: {
level: { default: 1 },
ychange: { default: null },
id: { default: null },
"data-toc-id": { default: null },
},
content: "inline*",
group: "customTitleBlock",
defining: true,
parseDOM: [
{
tag: "custom-title",
getAttrs: (dom: any) => ({
level: dom.getAttribute("level") || 1,
id: dom.getAttribute("id"),
"data-toc-id": dom.getAttribute("data-toc-id"),
}),
},
],
toDOM(node: any) {
const ychangeAttrs = calcYchangeDomAttrs(node.attrs);
const domAttrs: any = {
...ychangeAttrs,
};
if (node.attrs.id) {
domAttrs.id = node.attrs.id;
}
if (node.attrs["data-toc-id"]) {
domAttrs["data-toc-id"] = node.attrs["data-toc-id"];
}
return ["custom-title", domAttrs, 0];
},
},
// :: NodeSpec A plain paragraph textblock. Represented in the DOM
// as a `<p>` element.
paragraph: {
attrs: {
ychange: { default: null },
align: { default: null },
},
content: "inline*",
group: "block",
parseDOM: [
{
tag: "p",
getAttrs: (node: any) => ({
align: node.style.textAlign || null,
}),
},
],
toDOM(node: any) {
const ychangeAttrs = calcYchangeDomAttrs(node.attrs.ychange);
const alignStyle = node.attrs.align
? { style: `text-align: ${node.attrs.align}` }
: {};
return ["p", { ...ychangeAttrs, ...alignStyle }, 0];
},
},
// :: NodeSpec A heading textblock, with a `level` attribute that
// should hold the number 1 to 6. Parsed and serialized as `<h1>` to
// `<h6>` elements.
heading: {
attrs: {
level: { default: 1 },
ychange: { default: null },
id: { default: null },
"data-toc-id": { default: null },
},
content: "inline*",
group: "block",
defining: true,
parseDOM: [
{ tag: "h1", attrs: { level: 1 } },
{ tag: "h2", attrs: { level: 2 } },
{ tag: "h3", attrs: { level: 3 } },
{ tag: "h4", attrs: { level: 4 } },
{ tag: "h5", attrs: { level: 5 } },
{ tag: "h6", attrs: { level: 6 } },
],
toDOM(node: any) {
const ychangeAttrs = calcYchangeDomAttrs(node.attrs);
const domAttrs: any = {
...ychangeAttrs,
};
if (node.attrs.id) {
domAttrs.id = node.attrs.id;
}
if (node.attrs["data-toc-id"]) {
domAttrs["data-toc-id"] = node.attrs["data-toc-id"];
}
return ["h" + node.attrs.level, domAttrs, 0];
},
},
Issue Description:
- The specific issue arises when the content within
custom-title
is deleted. Unlike standard elements such ash1
, where the subsequentp
element remains in its place, in the case ofcustom-title
, the followingp
element content unexpectedly shifts or moves in a way that is inconsistent with the behavior of standard HTML elements.
-
Before delete
-
After delete
- Changing the tag from
custom-title
toh1
seems to resolve this issue, highlighting a discrepancy in how ProseMirror handles custom versus standard elements.
customTitle: {
attrs: {
level: { default: 1 },
ychange: { default: null },
id: { default: null },
"data-toc-id": { default: null },
},
content: "inline*",
group: "customTitleBlock",
defining: true,
parseDOM: [
{
tag: "h1",
getAttrs: (dom: any) => ({
level: dom.getAttribute("level") || 1,
id: dom.getAttribute("id"),
"data-toc-id": dom.getAttribute("data-toc-id"),
}),
},
],
toDOM(node: any) {
const ychangeAttrs = calcYchangeDomAttrs(node.attrs);
const domAttrs: any = {
...ychangeAttrs,
};
if (node.attrs.id) {
domAttrs.id = node.attrs.id;
}
if (node.attrs["data-toc-id"]) {
domAttrs["data-toc-id"] = node.attrs["data-toc-id"];
}
return ["h1", domAttrs, 0];
},
},
- Before delete
- After delete
Attempts Made:
- Ensured
custom-title
is set as a block-level element (display: block;
).
custom-title {
display: block;
font-size: 22pt;
font-weight: bold;
line-height: 2.5;
}
Questions:
- What might be causing the
custom-title
element to behave differently from standard elements likeh1
in terms of post-deletion content reflow? - Are there any recommended practices in ProseMirror for ensuring custom elements behave similarly to standard HTML block elements?