List Type Toggle

I found a solution that requires very little code based on a few discussions on these forums. I hope this will help someone:

function chainTransactions(...commands: EditorCommand[]): EditorCommand {
    return (state, dispatch): boolean => {
        const dispatcher = (tr: Transaction) => {
            state = state.apply(tr);
            dispatch(tr);
        };
        const last = commands.pop();
        const reduced = commands.reduce((result, command) => {
            return result || command(state, dispatcher);
        }, false);
        return reduced && last !== undefined && last(state, dispatch);
    };
}

function toggleList(listType: NodeType, schema: Schema, attrs: any): EditorCommand {
    return function (state: EditorState, dispatch?: (tr: Transaction) => void): boolean {
        if (!dispatch) return true;
        const currentNode = getSelectedNodeType(state);
        const oppositeListOf: { [key: string]: string } = {
            bullet_list: 'ordered_list',
            ordered_list: 'bullet_list',
        };

        let transactions: EditorCommand;
        if (currentNode.name === listType.name) transactions = liftListItem(schema.nodes.list_item);
        else if (oppositeListOf[currentNode.name] === listType.name)
            transactions = chainTransactions(liftListItem(schema.nodes.list_item), wrapInList(listType, attrs));
        else transactions = wrapInList(listType, attrs);

        return transactions(state, dispatch);
    };
}

export function toggleListItem(nodeType: NodeType, schema: Schema, options: any): MenuItem {
    return cmdItem(toggleList(nodeType, schema, options.attrs), { ...options, active: isListActive(nodeType) });
}
2 Likes