Conversation
Coverage Report
File Coverage |
|
At the moment, this PR solves the top-down selection issue, but it creates a flickering problem. Screen.Recording.2025-08-11.102618.mp4For selection from bottom to top, the previous bug + flickering remains Screen.Recording.2025-08-11.102648.mp4 |
|
I think the problem happens when we start moving the cursor. After all, according to the new logic added to |
|
This PR may not be the ideal solution for #291.
CleanShot.2025-08-11.at.18.25.19.mp4
CleanShot.2025-08-11.at.18.28.53.mp4I'll think more about it... |
|
|
I noticed another strange behavior, which is probably related to our problem. When we select and drag the table, the empty cell remains in the same position. Screen.Recording.2025-08-11.124105.mp4 |
I have solution for this case. It need's some changed in return $anchor.pos < $head.pos
? TextSelection.between($anchor, doc.resolve(headTableEnd), 1)
: TextSelection.between($anchor, doc.resolve(Math.max(headTableStart - 2, 0)), -1);This Screen.Recording.2025-08-11.133538.mp4But if table at the start of the document, only this fix won't work. Screen.Recording.2025-08-11.133837.mp4For that keys, I also have solution. In const check = (node: Node, pos: number) => {
if (node.type.spec.tableRole == 'table') {
if (isNodeEmpty(state.doc) && node.content.content.length === 1) {
tr = (tr || state.tr).replaceRangeWith(0, state.doc.content.size, state.schema.node("paragraph"))
} else {
tr = fixTable(state, node, pos, tr);
}
}
};/**
* Returns true if the given prosemirror node is empty.
*/
export function isNodeEmpty(
node: Node,
{
checkChildren = true,
ignoreWhitespace = false,
}: {
/**
* When true (default), it will also check if all children are empty.
*/
checkChildren?: boolean
/**
* When true, it will ignore whitespace when checking for emptiness.
*/
ignoreWhitespace?: boolean
} = {},
): boolean {
if (ignoreWhitespace) {
// Hard breaks are considered empty
if (node.type.name === 'hardBreak') return true
if (node.isText) return /^\s*$/m.test(node.text ?? '')
}
if (node.isText) return !node.text
if (node.isAtom || node.isLeaf) return false
if (node.content.childCount === 0) return true
if (checkChildren) {
let isContentEmpty = true
node.content.forEach(childNode => {
// Exit early for perf
if (isContentEmpty === false) return
if (!isNodeEmpty(childNode, { ignoreWhitespace, checkChildren })) isContentEmpty = false
})
return isContentEmpty
}
return false
}Screen.Recording.2025-08-11.134402.mp4Also, in this method, we need to check, if table contains only one row, otherwise, this method will be delete the whole table, but it shouldn't. Screen.Recording.2025-08-11.143628.mp4 |
This bug was solved, after this fix: Magically, the empty table disappears, but an empty line appears before the insertion. Screen.Recording.2025-08-11.150245.mp4EDITED: I think it's happening because of the pre-capture previous block |
FIXEDWith this changes, this bug is fixed: export function fixTables(
transactions: readonly Transaction[],
state: EditorState,
oldState?: EditorState,
): Transaction | undefined {
if (!state) return;
let tr: Transaction | undefined;
if (Array.isArray(transactions)) {
const drop = transactions.filter(t => t.getMeta("uiEvent") === "drop")
if (drop.length > 0) {
const maybeEmptyParagraph = state.selection.$anchor.parent
const maybeTable = state.doc.resolve(Math.min(state.selection.anchor + 2, state.doc.content.size)).parent
if (
(maybeEmptyParagraph && isNodeEmpty(maybeEmptyParagraph)) && (maybeTable && maybeTable.type.name === "table")
) {
tr = (tr || state.tr).delete(state.selection.anchor - 1, state.selection.anchor + 2)
}
}
}
// Other code..
}appendTransaction(transactions, oldState, state) {
return normalizeSelection(
state,
fixTables(transactions, state, oldState),
allowTableNodeSelection,
);
}Screen.Recording.2025-08-11.152329.mp4 |
|
@ocavue Please check my solutions for these problems. Hot to fix selection flashing issue I don't know. In Google Docs always fine, because they use canvas for editor. In Chrome this doesn't work at all :) Screen.Recording.2025-08-11.155603.mp4 |
|
I suggest to use Screen.Recording.2025-08-12.002303.mp4 |
|
I like how Notion. I'm not quite sure how to implement it just yet, but I'll revisit this when I have more free time. |
I try to get the same behavior and get it but with little bug (I have no ideas why this happens). mouseup: (view) => {
if (!isInTable(view.state)) return false;
let headTableStart = -1;
let headTableEnd = -1;
for (let i = view.state.selection.$head.depth; i > 0; i--) {
const node = view.state.selection.$head.node(i);
if (node.type.spec.tableRole === 'table') {
headTableStart = view.state.selection.$head.start(i);
headTableEnd = view.state.selection.$head.end(i);
break;
}
}
// head is not in a table
if (headTableStart === headTableEnd) return;
// anchor is inside this table
if (headTableStart <= view.state.selection.$anchor.pos && view.state.selection.$anchor.pos <= headTableEnd) return;
const selection = view.state.selection.$anchor.pos < view.state.selection.$head.pos
? TextSelection.between(view.state.selection.$anchor, view.state.doc.resolve(headTableStart), 1)
: TextSelection.between(view.state.doc.resolve(headTableEnd), view.state.selection.$anchor, -1)
console.log(selection);
view.dispatch(view.state.tr.setSelection(selection))
return false;
}And we need to remove these part: // else if (sel instanceof TextSelection) {
// normalize ||= expandTextSelectionAcrossTable(sel);
// }Screen.Recording.2025-08-12.171057.mp4 |
|
I'm tried several places for this logic (also in |
|
It;s a mystic with upper selection. I create method to deal with this in And, It's crazy.. If i change TextSelection.between(selection.$anchor, state.doc.resolve(headTableStart), 1)to 22 (it's TextSelection.between(state.doc.resolve(22), state.doc.resolve(headTableStart), 1)But, on new Screen.Recording.2025-08-12.192124.mp4 |
|
It's a bug works only on Firefox. Blue selection stays on table, but the actual selection stands on text and it;s correct (if press backspace, only the desired content before the table will be removed). If a new transaction occurs, the blue selection return to its correct place. Screen.Recording.2025-08-12.194817.mp4I tested Google Chrome and its work correct. Screen.Recording.2025-08-12.194843.mp4 |
No description provided.