import { Plugin, PluginKey } from "prosemirror-state";
import { Decoration, DecorationSet } from "prosemirror-view";
import TableCell from "@tiptap/extension-table-cell";
import { findParentNode } from "@tiptap/core";
export default TableCell.extend({
addNodeView() {
return ({ editor, node, getPos }) => {
const { view } = editor;
const cell = document.createElement("td");
cell.style.color = "black";
cell.style.position = "relative";
const cellContent = document.createElement("div");
cellContent.style.display = "flex";
cellContent.style.position = "relative";
cellContent.style.marginLeft = "8px";
cellContent.style.marginRight = "8px";
cell.append(cellContent);
// Set the background color from attributes
if (node.attrs.backgroundColor) {
cell.style.backgroundColor = node.attrs.backgroundColor;
}
return {
dom: cell,
contentDOM: cellContent,
};
};
},
addProseMirrorPlugins() {
const pluginKey = new PluginKey("table");
return [
new Plugin({
key: pluginKey,
state: {
init: () => ({ selectedCellPos: null }),
apply(tr, value, oldState, newState) {
const editorFocused = tr.getMeta("EDITOR_FOCUSED");
if (editorFocused === false) return value;
const { schema, selection } = newState;
const {
tableCell: schemaTableCell,
tableHeader: schemaTableHeader,
} = schema.nodes;
const tableCell = findParentNode(
({ type }) =>
type === schemaTableCell || type === schemaTableHeader
)(selection);
if (tableCell) {
return { selectedCellPos: tableCell.start };
}
return { selectedCellPos: null };
},
},
props: {
decorations(state) {
const { selectedCellPos } = this.getState(state);
const decorations = [];
if (selectedCellPos !== null) {
const $pos = state.doc.resolve(selectedCellPos);
const node = $pos.nodeAfter;
const nodeParent = $pos.parent;
if (node && nodeParent.type.name === "tableCell") {
const cellEnd = $pos.end();
const cellDecor = Decoration.widget(
cellEnd,
() => {
const btn = document.createElement("button"); // Note: lowercase 'button'
btn.textContent = "Click Me";
btn.setAttribute("contentEditable", "false");
btn.setAttribute("data-pos", selectedCellPos);
btn.style.position = "absolute"; // Absolute positioning
btn.style.right = "10px"; // Position from the right edge
btn.style.bottom = "10px"; // Position from the bottom edge
btn.style.zIndex = "10"; // Ensure it's on top
btn.style.backgroundColor = "#007bff"; // Optional: make the button visually distinct
btn.style.color = "#fff"; // Optional: text color
btn.style.border = "none"; // Optional: remove default button border
btn.style.padding = "5px 10px"; // Optional: add some padding
btn.style.borderRadius = "3px"; // Optional: rounded corners
btn.addEventListener("click", () => {
alert("Button clicked!");
});
return btn;
},
{ key: "button-decoration" }
); // Add a key for unique identification
decorations.push(cellDecor);
}
}
return DecorationSet.create(state.doc, decorations);
},
},
}),
];
},
});
I am making a plugin for tiptap editor, So I want to show cell options whenever the cell is selected. But somehow not sure using this plugin in some cases (not always) the cursor get updated to the next cell. Please help I am new to all these. Thanks in advance. Please let me also know if there is any alternative for this, Also would appreciate if could tell me how can I fire the event so that a popper from outside can be triggered with options.