prosemirror-flat-list
Version:
Powerful list support for ProseMirror
57 lines (48 loc) • 1.87 kB
text/typescript
import type { ResolvedPos } from 'prosemirror-model'
import { type Command, TextSelection } from 'prosemirror-state'
import type { ListAttributes } from '../types'
import { atTextblockStart } from '../utils/at-textblock-start'
import { isListNode } from '../utils/is-list-node'
import { joinTextblocksAround } from './join-textblocks-around'
/**
* If the selection is empty and at the start of a block, and there is a
* collapsed list node right before the cursor, move current block and append it
* to the first child of the collapsed list node (i.e. skip the hidden content).
*
* @public @group Commands
*/
export const joinCollapsedListBackward: Command = (state, dispatch, view) => {
const $cursor = atTextblockStart(state, view)
if (!$cursor) return false
const $cut = findCutBefore($cursor)
if (!$cut) return false
const { nodeBefore, nodeAfter } = $cut
if (
nodeBefore &&
nodeAfter &&
isListNode(nodeBefore) &&
(nodeBefore.attrs as ListAttributes).collapsed &&
nodeAfter.isBlock
) {
const tr = state.tr
const listPos = $cut.pos - nodeBefore.nodeSize
tr.delete($cut.pos, $cut.pos + nodeAfter.nodeSize)
const insert = listPos + 1 + nodeBefore.child(0).nodeSize
tr.insert(insert, nodeAfter)
const $insert = tr.doc.resolve(insert)
tr.setSelection(TextSelection.near($insert))
if (joinTextblocksAround(tr, $insert, dispatch)) {
return true
}
}
return false
}
// https://github.com/prosemirror/prosemirror-commands/blob/e607d5abda0fcc399462e6452a82450f4118702d/src/commands.ts#L150
function findCutBefore($pos: ResolvedPos): ResolvedPos | null {
if (!$pos.parent.type.spec.isolating)
for (let i = $pos.depth - 1; i >= 0; i--) {
if ($pos.index(i) > 0) return $pos.doc.resolve($pos.before(i + 1))
if ($pos.node(i).type.spec.isolating) break
}
return null
}