Lists with single paragraph per list item

As already mentioned in another topic (here) there is a problem to get lists with a single paragraph per list_item just by using

nodes: addListNodes(schema.spec.nodes, "paragraph", "block")

Aside from the problem with the Backspace key there is also a problem with the wrapInList function:

when nodes: addListNodes(schema.spec.nodes, "paragraph*", "block") is used

if one selects several paragraphs from the document and then executes wrapInList - the formatting works and the result is a list with a single paragraph per list_item.

when nodes: addListNodes(schema.spec.nodes, "paragraph", "block") is used

if one selects several paragraphs and then executes wrapInList nothing happens - why is it so? The definition with single paragraph allows in theory the same result as with "paragraph*" but it does not work. There is a

var wrap = findWrapping(outerRange, listType, attrs, range);

      if (!wrap) {
        return false;
      }

in the wrapInList and it is always null when single paragraph is used (instead of paragraph*).

2 Likes

I am suffering from the same issue. wrapInList seems not to function well when the schema of listItem is set to paragraph.

@sunsande Did you solve the problem later?

2 Likes

I have the same problem!

What do you think about this solution?

export function customWrapInList(listType: NodeType, attrs: Attrs | null = null): Command {
    return function (state: EditorState, dispatch?: (tr: Transaction) => void) {
        const { tr } = state;
        const { from, to } = tr.selection;
        let startPos: number | undefined;
        let endPos: number | undefined;
        const items = [];

        // Collect list items and track start/end positions
        tr.doc.nodesBetween(from, to, (node, pos) => {
            if (node.type === state.schema.nodes.paragraph) {
                startPos = startPos ?? pos;
                endPos = pos + node.nodeSize;
                const listItem = state.schema.nodes.list_item.createAndFill(attrs, node);
                if (listItem) {
                    items.push(listItem);
                }
            }
        });

        if (items.length && startPos !== undefined && endPos !== undefined) {
            const list = listType.createAndFill(attrs, items);
            if (list) {
                tr.replaceRangeWith(startPos, endPos, list);
                if (dispatch) dispatch(tr);
                return true;
            }
        }

        return false;
    };
}