mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
[WEB-1526] feat: add auto merge behaviour to task lists and fix infinite backspace case (#4703)
* feat: add auto merge behaviour to task lists * fix: unhandled cases for taskItem and taskList * fix: css task list such that toggling task list doesn't shift things * fix: task list jumps around while trying create/delete things in between two task lists * fix: remove filtering for generic transactions i.e. transactions with some meta data while tying to join things
This commit is contained in:
parent
f5656111ee
commit
b1c7e6ae20
@ -110,6 +110,11 @@ ul[data-type="taskList"] li > label input[type="checkbox"]:checked:hover {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* the p tag just after the ul tag */
|
||||||
|
ul[data-type="taskList"] + p {
|
||||||
|
margin-top: 0.4rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
ul[data-type="taskList"] li > label input[type="checkbox"] {
|
ul[data-type="taskList"] li > label input[type="checkbox"] {
|
||||||
position: relative;
|
position: relative;
|
||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
@ -152,6 +157,10 @@ ul[data-type="taskList"] li > label input[type="checkbox"] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ul[data-type="taskList"] li > div > p {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
ul[data-type="taskList"] li[data-checked="true"] > div > p {
|
ul[data-type="taskList"] li[data-checked="true"] > div > p {
|
||||||
color: rgb(var(--color-text-400));
|
color: rgb(var(--color-text-400));
|
||||||
text-decoration: line-through;
|
text-decoration: line-through;
|
||||||
|
@ -72,7 +72,7 @@ const getPrevListDepth = (typeOrName: string, state: EditorState) => {
|
|||||||
// Traverse up the document structure from the adjusted position
|
// Traverse up the document structure from the adjusted position
|
||||||
for (let d = resolvedPos.depth; d > 0; d--) {
|
for (let d = resolvedPos.depth; d > 0; d--) {
|
||||||
const node = resolvedPos.node(d);
|
const node = resolvedPos.node(d);
|
||||||
if (node.type.name === "bulletList" || node.type.name === "orderedList") {
|
if (node.type.name === "bulletList" || node.type.name === "orderedList" || node.type.name === "taskList") {
|
||||||
// Increment depth for each list ancestor found
|
// Increment depth for each list ancestor found
|
||||||
depth++;
|
depth++;
|
||||||
}
|
}
|
||||||
@ -146,6 +146,8 @@ export const handleBackspace = (editor: Editor, name: string, parentListTypes: s
|
|||||||
if (!isAtStartOfNode(editor.state)) {
|
if (!isAtStartOfNode(editor.state)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// is the paragraph node inside of the current list item (maybe with a hard break)
|
||||||
const isParaSibling = isCurrentParagraphASibling(editor.state);
|
const isParaSibling = isCurrentParagraphASibling(editor.state);
|
||||||
const isCurrentListItemSublist = prevListIsHigher(name, editor.state);
|
const isCurrentListItemSublist = prevListIsHigher(name, editor.state);
|
||||||
const listItemPos = findListItemPos(name, editor.state);
|
const listItemPos = findListItemPos(name, editor.state);
|
||||||
@ -306,7 +308,10 @@ const isCurrentParagraphASibling = (state: EditorState): boolean => {
|
|||||||
const currentParagraphNode = $from.parent; // Get the current node where the selection is.
|
const currentParagraphNode = $from.parent; // Get the current node where the selection is.
|
||||||
|
|
||||||
// Ensure we're in a paragraph and the parent is a list item.
|
// Ensure we're in a paragraph and the parent is a list item.
|
||||||
if (currentParagraphNode.type.name === "paragraph" && listItemNode.type.name === "listItem") {
|
if (
|
||||||
|
currentParagraphNode.type.name === "paragraph" &&
|
||||||
|
(listItemNode.type.name === "listItem" || listItemNode.type.name === "taskItem")
|
||||||
|
) {
|
||||||
let paragraphNodesCount = 0;
|
let paragraphNodesCount = 0;
|
||||||
listItemNode.forEach((child) => {
|
listItemNode.forEach((child) => {
|
||||||
if (child.type.name === "paragraph") {
|
if (child.type.name === "paragraph") {
|
||||||
@ -327,16 +332,19 @@ export function isCursorInSubList(editor: Editor) {
|
|||||||
|
|
||||||
// Check if the current node is a list item
|
// Check if the current node is a list item
|
||||||
const listItem = editor.schema.nodes.listItem;
|
const listItem = editor.schema.nodes.listItem;
|
||||||
|
const taskItem = editor.schema.nodes.taskItem;
|
||||||
|
|
||||||
// Traverse up the document tree from the current position
|
// Traverse up the document tree from the current position
|
||||||
for (let depth = $from.depth; depth > 0; depth--) {
|
for (let depth = $from.depth; depth > 0; depth--) {
|
||||||
const node = $from.node(depth);
|
const node = $from.node(depth);
|
||||||
if (node.type === listItem) {
|
if (node.type === listItem || node.type === taskItem) {
|
||||||
// If the parent of the list item is also a list, it's a sub-list
|
// If the parent of the list item is also a list, it's a sub-list
|
||||||
const parent = $from.node(depth - 1);
|
const parent = $from.node(depth - 1);
|
||||||
if (
|
if (
|
||||||
parent &&
|
parent &&
|
||||||
(parent.type === editor.schema.nodes.bulletList || parent.type === editor.schema.nodes.orderedList)
|
(parent.type === editor.schema.nodes.bulletList ||
|
||||||
|
parent.type === editor.schema.nodes.orderedList ||
|
||||||
|
parent.type === editor.schema.nodes.taskList)
|
||||||
) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -15,9 +15,7 @@ declare module "@tiptap/core" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function autoJoin(tr: Transaction, newTr: Transaction, nodeType: NodeType) {
|
function autoJoin(tr: Transaction, newTr: Transaction, nodeTypes: NodeType[]) {
|
||||||
if (!tr.isGeneric) return false;
|
|
||||||
|
|
||||||
// Find all ranges where we might want to join.
|
// Find all ranges where we might want to join.
|
||||||
const ranges: Array<number> = [];
|
const ranges: Array<number> = [];
|
||||||
for (let i = 0; i < tr.mapping.maps.length; i++) {
|
for (let i = 0; i < tr.mapping.maps.length; i++) {
|
||||||
@ -28,7 +26,7 @@ function autoJoin(tr: Transaction, newTr: Transaction, nodeType: NodeType) {
|
|||||||
|
|
||||||
// Figure out which joinable points exist inside those ranges,
|
// Figure out which joinable points exist inside those ranges,
|
||||||
// by checking all node boundaries in their parent nodes.
|
// by checking all node boundaries in their parent nodes.
|
||||||
const joinable = [];
|
const joinable: number[] = [];
|
||||||
for (let i = 0; i < ranges.length; i += 2) {
|
for (let i = 0; i < ranges.length; i += 2) {
|
||||||
const from = ranges[i],
|
const from = ranges[i],
|
||||||
to = ranges[i + 1];
|
to = ranges[i + 1];
|
||||||
@ -40,7 +38,7 @@ function autoJoin(tr: Transaction, newTr: Transaction, nodeType: NodeType) {
|
|||||||
if (!after) break;
|
if (!after) break;
|
||||||
if (index && joinable.indexOf(pos) == -1) {
|
if (index && joinable.indexOf(pos) == -1) {
|
||||||
const before = parent.child(index - 1);
|
const before = parent.child(index - 1);
|
||||||
if (before.type == after.type && before.type === nodeType) joinable.push(pos);
|
if (before.type == after.type && nodeTypes.includes(before.type)) joinable.push(pos);
|
||||||
}
|
}
|
||||||
pos += after.nodeSize;
|
pos += after.nodeSize;
|
||||||
}
|
}
|
||||||
@ -88,25 +86,15 @@ export const CustomKeymap = Extension.create({
|
|||||||
// Create a new transaction.
|
// Create a new transaction.
|
||||||
const newTr = newState.tr;
|
const newTr = newState.tr;
|
||||||
|
|
||||||
let joined = false;
|
const joinableNodes = [
|
||||||
for (const transaction of transactions) {
|
newState.schema.nodes["orderedList"],
|
||||||
const anotherJoin = autoJoin(transaction, newTr, newState.schema.nodes["orderedList"]);
|
newState.schema.nodes["taskList"],
|
||||||
joined = anotherJoin || joined;
|
newState.schema.nodes["bulletList"],
|
||||||
}
|
];
|
||||||
if (joined) {
|
|
||||||
return newTr;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
new Plugin({
|
|
||||||
key: new PluginKey("unordered-list-merging"),
|
|
||||||
appendTransaction(transactions, oldState, newState) {
|
|
||||||
// Create a new transaction.
|
|
||||||
const newTr = newState.tr;
|
|
||||||
|
|
||||||
let joined = false;
|
let joined = false;
|
||||||
for (const transaction of transactions) {
|
for (const transaction of transactions) {
|
||||||
const anotherJoin = autoJoin(transaction, newTr, newState.schema.nodes["bulletList"]);
|
const anotherJoin = autoJoin(transaction, newTr, joinableNodes);
|
||||||
joined = anotherJoin || joined;
|
joined = anotherJoin || joined;
|
||||||
}
|
}
|
||||||
if (joined) {
|
if (joined) {
|
||||||
|
Loading…
Reference in New Issue
Block a user