Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

prosemirror-commands

Package Overview
Dependencies
Maintainers
1
Versions
51
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

prosemirror-commands - npm Package Compare versions

Comparing version 1.3.1 to 1.4.0

10

CHANGELOG.md

@@ -0,1 +1,11 @@

## 1.4.0 (2022-12-01)
### Bug fixes
Make `setBlockType` act on all selection ranges in selections that have them.
### New features
The new `joinTextblockForward` and `joinTextblockBackward` commands provide a more primitive command for delete/backspace behavior when you don't want the extra strategies implemented by `joinForward`/`joinBackward`.
## 1.3.1 (2022-09-08)

@@ -2,0 +12,0 @@

14

dist/index.d.ts

@@ -19,2 +19,14 @@ import { NodeType, Attrs, MarkType, Node } from 'prosemirror-model';

/**
A more limited form of [`joinBackward`]($commands.joinBackward)
that only tries to join the current textblock to the one before
it, if the cursor is at the start of a textblock.
*/
declare const joinTextblockBackward: Command;
/**
A more limited form of [`joinForward`]($commands.joinForward)
that only tries to join the current textblock to the one after
it, if the cursor is at the end of a textblock.
*/
declare const joinTextblockForward: Command;
/**
When the selection is empty and at the start of a textblock, select

@@ -177,2 +189,2 @@ the node before that textblock, if possible. This is intended to be

export { autoJoin, baseKeymap, chainCommands, createParagraphNear, deleteSelection, exitCode, joinBackward, joinDown, joinForward, joinUp, lift, liftEmptyBlock, macBaseKeymap, newlineInCode, pcBaseKeymap, selectAll, selectNodeBackward, selectNodeForward, selectParentNode, selectTextblockEnd, selectTextblockStart, setBlockType, splitBlock, splitBlockKeepMarks, toggleMark, wrapIn };
export { autoJoin, baseKeymap, chainCommands, createParagraphNear, deleteSelection, exitCode, joinBackward, joinDown, joinForward, joinTextblockBackward, joinTextblockForward, joinUp, lift, liftEmptyBlock, macBaseKeymap, newlineInCode, pcBaseKeymap, selectAll, selectNodeBackward, selectNodeForward, selectParentNode, selectTextblockEnd, selectTextblockStart, setBlockType, splitBlock, splitBlockKeepMarks, toggleMark, wrapIn };
import { liftTarget, replaceStep, canJoin, joinPoint, canSplit, ReplaceAroundStep, findWrapping } from 'prosemirror-transform';
import { Slice, Fragment } from 'prosemirror-model';
import { NodeSelection, Selection, AllSelection, TextSelection } from 'prosemirror-state';
import { NodeSelection, Selection, TextSelection, AllSelection } from 'prosemirror-state';

@@ -15,2 +15,9 @@ /**

};
function atBlockStart(state, view) {
let { $cursor } = state.selection;
if (!$cursor || (view ? !view.endOfTextblock("backward", state)
: $cursor.parentOffset > 0))
return null;
return $cursor;
}
/**

@@ -26,5 +33,4 @@ If the selection is empty and at the start of a textblock, try to

const joinBackward = (state, dispatch, view) => {
let { $cursor } = state.selection;
if (!$cursor || (view ? !view.endOfTextblock("backward", state)
: $cursor.parentOffset > 0))
let $cursor = atBlockStart(state, view);
if (!$cursor)
return false;

@@ -68,2 +74,55 @@ let $cut = findCutBefore($cursor);

};
/**
A more limited form of [`joinBackward`]($commands.joinBackward)
that only tries to join the current textblock to the one before
it, if the cursor is at the start of a textblock.
*/
const joinTextblockBackward = (state, dispatch, view) => {
let $cursor = atBlockStart(state, view);
if (!$cursor)
return false;
let $cut = findCutBefore($cursor);
return $cut ? joinTextblocksAround(state, $cut, dispatch) : false;
};
/**
A more limited form of [`joinForward`]($commands.joinForward)
that only tries to join the current textblock to the one after
it, if the cursor is at the end of a textblock.
*/
const joinTextblockForward = (state, dispatch, view) => {
let $cursor = atBlockEnd(state, view);
if (!$cursor)
return false;
let $cut = findCutAfter($cursor);
return $cut ? joinTextblocksAround(state, $cut, dispatch) : false;
};
function joinTextblocksAround(state, $cut, dispatch) {
let before = $cut.nodeBefore, beforeText = before, beforePos = $cut.pos - 1;
for (; !beforeText.isTextblock; beforePos--) {
if (beforeText.type.spec.isolating)
return false;
let child = beforeText.lastChild;
if (!child)
return false;
beforeText = child;
}
let after = $cut.nodeAfter, afterText = after, afterPos = $cut.pos + 1;
for (; !afterText.isTextblock; afterPos++) {
if (afterText.type.spec.isolating)
return false;
let child = afterText.firstChild;
if (!child)
return false;
afterText = child;
}
let step = replaceStep(state.doc, beforePos, afterPos, Slice.empty);
if (!step || step.from != beforePos || step.slice.size >= afterPos - beforePos)
return false;
if (dispatch) {
let tr = state.tr.step(step);
tr.setSelection(TextSelection.create(tr.doc, beforePos));
dispatch(tr.scrollIntoView());
}
return true;
}
function textblockAt(node, side, only = false) {

@@ -112,2 +171,9 @@ for (let scan = node; scan; scan = (side == "start" ? scan.firstChild : scan.lastChild)) {

}
function atBlockEnd(state, view) {
let { $cursor } = state.selection;
if (!$cursor || (view ? !view.endOfTextblock("forward", state)
: $cursor.parentOffset < $cursor.parent.content.size))
return null;
return $cursor;
}
/**

@@ -121,5 +187,4 @@ If the selection is empty and the cursor is at the end of a

const joinForward = (state, dispatch, view) => {
let { $cursor } = state.selection;
if (!$cursor || (view ? !view.endOfTextblock("forward", state)
: $cursor.parentOffset < $cursor.parent.content.size))
let $cursor = atBlockEnd(state, view);
if (!$cursor)
return false;

@@ -524,21 +589,29 @@ let $cut = findCutAfter($cursor);

return function (state, dispatch) {
let { from, to } = state.selection;
let applicable = false;
state.doc.nodesBetween(from, to, (node, pos) => {
if (applicable)
return false;
if (!node.isTextblock || node.hasMarkup(nodeType, attrs))
return;
if (node.type == nodeType) {
applicable = true;
}
else {
let $pos = state.doc.resolve(pos), index = $pos.index();
applicable = $pos.parent.canReplaceWith(index, index + 1, nodeType);
}
});
for (let i = 0; i < state.selection.ranges.length && !applicable; i++) {
let { $from: { pos: from }, $to: { pos: to } } = state.selection.ranges[i];
state.doc.nodesBetween(from, to, (node, pos) => {
if (applicable)
return false;
if (!node.isTextblock || node.hasMarkup(nodeType, attrs))
return;
if (node.type == nodeType) {
applicable = true;
}
else {
let $pos = state.doc.resolve(pos), index = $pos.index();
applicable = $pos.parent.canReplaceWith(index, index + 1, nodeType);
}
});
}
if (!applicable)
return false;
if (dispatch)
dispatch(state.tr.setBlockType(from, to, nodeType, attrs).scrollIntoView());
if (dispatch) {
let tr = state.tr;
for (let i = 0; i < state.selection.ranges.length; i++) {
let { $from: { pos: from }, $to: { pos: to } } = state.selection.ranges[i];
tr.setBlockType(from, to, nodeType, attrs);
}
dispatch(tr.scrollIntoView());
}
return true;

@@ -725,2 +798,2 @@ };

export { autoJoin, baseKeymap, chainCommands, createParagraphNear, deleteSelection, exitCode, joinBackward, joinDown, joinForward, joinUp, lift, liftEmptyBlock, macBaseKeymap, newlineInCode, pcBaseKeymap, selectAll, selectNodeBackward, selectNodeForward, selectParentNode, selectTextblockEnd, selectTextblockStart, setBlockType, splitBlock, splitBlockKeepMarks, toggleMark, wrapIn };
export { autoJoin, baseKeymap, chainCommands, createParagraphNear, deleteSelection, exitCode, joinBackward, joinDown, joinForward, joinTextblockBackward, joinTextblockForward, joinUp, lift, liftEmptyBlock, macBaseKeymap, newlineInCode, pcBaseKeymap, selectAll, selectNodeBackward, selectNodeForward, selectParentNode, selectTextblockEnd, selectTextblockStart, setBlockType, splitBlock, splitBlockKeepMarks, toggleMark, wrapIn };

2

package.json
{
"name": "prosemirror-commands",
"version": "1.3.1",
"version": "1.4.0",
"description": "Editing commands for ProseMirror",

@@ -5,0 +5,0 @@ "type": "module",

# prosemirror-commands
[ [**WEBSITE**](https://prosemirror.net) | [**ISSUES**](https://github.com/prosemirror/prosemirror/issues) | [**FORUM**](https://discuss.prosemirror.net) | [**GITTER**](https://gitter.im/ProseMirror/prosemirror) | [**CHANGELOG**](https://github.com/ProseMirror/prosemirror-commands/blob/master/CHANGELOG.md) ]
[ [**WEBSITE**](https://prosemirror.net) | [**ISSUES**](https://github.com/prosemirror/prosemirror/issues) | [**FORUM**](https://discuss.prosemirror.net) | [**CHANGELOG**](https://github.com/ProseMirror/prosemirror-commands/blob/master/CHANGELOG.md) ]

@@ -5,0 +5,0 @@ This is a [core module](https://prosemirror.net/docs/ref/#commands) of [ProseMirror](https://prosemirror.net).

@@ -6,2 +6,3 @@ import {joinPoint, canJoin, findWrapping, liftTarget, canSplit,

SelectionRange, AllSelection, Command} from "prosemirror-state"
import {EditorView} from "prosemirror-view"

@@ -15,2 +16,10 @@ /// Delete the selection, if there is one.

function atBlockStart(state: EditorState, view?: EditorView): ResolvedPos | null {
let {$cursor} = state.selection as TextSelection
if (!$cursor || (view ? !view.endOfTextblock("backward", state)
: $cursor.parentOffset > 0))
return null
return $cursor
}
/// If the selection is empty and at the start of a textblock, try to

@@ -24,6 +33,4 @@ /// reduce the distance between that block and the one before it—if

export const joinBackward: Command = (state, dispatch, view) => {
let {$cursor} = state.selection as TextSelection
if (!$cursor || (view ? !view.endOfTextblock("backward", state)
: $cursor.parentOffset > 0))
return false
let $cursor = atBlockStart(state, view)
if (!$cursor) return false

@@ -70,2 +77,48 @@ let $cut = findCutBefore($cursor)

/// A more limited form of [`joinBackward`]($commands.joinBackward)
/// that only tries to join the current textblock to the one before
/// it, if the cursor is at the start of a textblock.
export const joinTextblockBackward: Command = (state, dispatch, view) => {
let $cursor = atBlockStart(state, view)
if (!$cursor) return false
let $cut = findCutBefore($cursor)
return $cut ? joinTextblocksAround(state, $cut, dispatch) : false
}
/// A more limited form of [`joinForward`]($commands.joinForward)
/// that only tries to join the current textblock to the one after
/// it, if the cursor is at the end of a textblock.
export const joinTextblockForward: Command = (state, dispatch, view) => {
let $cursor = atBlockEnd(state, view)
if (!$cursor) return false
let $cut = findCutAfter($cursor)
return $cut ? joinTextblocksAround(state, $cut, dispatch) : false
}
function joinTextblocksAround(state: EditorState, $cut: ResolvedPos, dispatch?: (tr: Transaction) => void) {
let before = $cut.nodeBefore!, beforeText = before, beforePos = $cut.pos - 1
for (; !beforeText.isTextblock; beforePos--) {
if (beforeText.type.spec.isolating) return false
let child = beforeText.lastChild
if (!child) return false
beforeText = child
}
let after = $cut.nodeAfter!, afterText = after, afterPos = $cut.pos + 1
for (; !afterText.isTextblock; afterPos++) {
if (afterText.type.spec.isolating) return false
let child = afterText.firstChild
if (!child) return false
afterText = child
}
let step = replaceStep(state.doc, beforePos, afterPos, Slice.empty) as ReplaceStep | null
if (!step || step.from != beforePos || step.slice.size >= afterPos - beforePos) return false
if (dispatch) {
let tr = state.tr.step(step)
tr.setSelection(TextSelection.create(tr.doc, beforePos))
dispatch(tr.scrollIntoView())
}
return true
}
function textblockAt(node: Node, side: "start" | "end", only = false) {

@@ -108,2 +161,10 @@ for (let scan: Node | null = node; scan; scan = (side == "start" ? scan.firstChild : scan.lastChild)) {

function atBlockEnd(state: EditorState, view?: EditorView): ResolvedPos | null {
let {$cursor} = state.selection as TextSelection
if (!$cursor || (view ? !view.endOfTextblock("forward", state)
: $cursor.parentOffset < $cursor.parent.content.size))
return null
return $cursor
}
/// If the selection is empty and the cursor is at the end of a

@@ -115,9 +176,6 @@ /// textblock, try to reduce or remove the boundary between that block

export const joinForward: Command = (state, dispatch, view) => {
let {$cursor} = state.selection as TextSelection
if (!$cursor || (view ? !view.endOfTextblock("forward", state)
: $cursor.parentOffset < $cursor.parent.content.size))
return false
let $cursor = atBlockEnd(state, view)
if (!$cursor) return false
let $cut = findCutAfter($cursor)
// If there is no node after this, there's nothing to do

@@ -473,16 +531,25 @@ if (!$cut) return false

return function(state, dispatch) {
let {from, to} = state.selection
let applicable = false
state.doc.nodesBetween(from, to, (node, pos) => {
if (applicable) return false
if (!node.isTextblock || node.hasMarkup(nodeType, attrs)) return
if (node.type == nodeType) {
applicable = true
} else {
let $pos = state.doc.resolve(pos), index = $pos.index()
applicable = $pos.parent.canReplaceWith(index, index + 1, nodeType)
for (let i = 0; i < state.selection.ranges.length && !applicable; i++) {
let {$from: {pos: from}, $to: {pos: to}} = state.selection.ranges[i]
state.doc.nodesBetween(from, to, (node, pos) => {
if (applicable) return false
if (!node.isTextblock || node.hasMarkup(nodeType, attrs)) return
if (node.type == nodeType) {
applicable = true
} else {
let $pos = state.doc.resolve(pos), index = $pos.index()
applicable = $pos.parent.canReplaceWith(index, index + 1, nodeType)
}
})
}
if (!applicable) return false
if (dispatch) {
let tr = state.tr
for (let i = 0; i < state.selection.ranges.length; i++) {
let {$from: {pos: from}, $to: {pos: to}} = state.selection.ranges[i]
tr.setBlockType(from, to, nodeType, attrs)
}
})
if (!applicable) return false
if (dispatch) dispatch(state.tr.setBlockType(from, to, nodeType, attrs).scrollIntoView())
dispatch(tr.scrollIntoView())
}
return true

@@ -489,0 +556,0 @@ }

@@ -16,4 +16,6 @@ This module exports a number of _commands_, which are building block

@selectNodeBackward
@joinTextblockBackward
@joinForward
@selectNodeForward
@joinTextblockForward
@joinUp

@@ -20,0 +22,0 @@ @joinDown

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc