README
slate-bind-copy-paste
This plugin generates and helps to generate wiser range operations of deleteAtRange
, insertFragmentAtRange
, getFragmentAtRange
Usage
yarn add --save slate-bind-copy-paste
import { getFragmentAtRange as getPlugin, insertFragmentAtRange as insertPlugin, deleteAtRange as deletePlugin} from 'slate-bind-copy-paste';
const getFragmentAtRange = getPlugin.generate(getRules)
const insertFragmentAtRange = insertPlugin.generate(insertRules)
const deleteAtRange = deletePlugin.generate(deleteRules)
API
Because getFragmentAtRange
, deleteAtRange
, insertFragmentAtRange
are often configured in different files, I think it is better not to export default
.
Then you can load them with alias.
getFragmentAtRange
import { getFragmentAtRange as plugin} from 'slate-bind-copy-paste'
const getFragmentAtRange : (Node, Range) => Document = plugin.generate(rules: Array<GetRule>)
If no rules are specified, the function will behave like the slate's getFragmentAtRange
.
rules
are a set of the rule explained as below:
type GetRule = (
rootGet: (Node, Range, Options) => Document,
node: Node,
range: Range,
option: Options,
next: (Options) => Document
) => Document;
Options: Immutable.Record({startText: Text, endText: Text, startAncestors: List<Node>, endAncestors: List<Node>})
Argument:
rootGet
: Transfer the control to the first rule ofrules
, used when reset thenode
orrange
.node
: The root node forgetFragmentAtRange
range
: The range of getting fragmentoption
: a set of convinient variables to simplify the code; Do not worry aboutoption
, the option will be normalized with the corrent{Edge}Text
and{Edge}Ancestors
in each call ofnext
androotGet
next
: Transfer the control to the next rule ofrules
, keepingnode
andrange
For exmample, this is a rule not copying the void Block at the start;
function noVoidStart(rootGet, node, range, option, next) {
const {startAncestors} = option;
if (startAncestors.find(n => n.isVoid)) {
if (range.startKey === range.endKey) {
return Document.create({nodes:[]})
}
const nextText = node.getNextText(range.startKey);
range = range.moveAnchorToStartOf(nextText)
return rootGet(node, range, option)
}
return next(option)
}
For more example usage, see zhujinxuan/slate-bad-table
in lib/rules/getFragmentAtRange
deleteAtRange
import { deleteAtRange as plugin} from 'slate-bind-copy-paste'
const deleteAtRange = plugin.generate(rules: Array<DeleteRule>)
If no rules are specified, the function will behave like the slate's deleteAtRange
.
rules
are a set of the rule explained as below:
type DeleteRule = (
rootDelete: (Change, Range, Options) => Change,
change: Change,
range: Range,
option: Options,
next: (Options) => Change
) => Change;
Options: Immutable.Record({startText: Text, endText: Text, startAncestors: List<Node>, endAncestors: List<Node>, deleteStartText: boolean, deleteEndText: boolean})
Argument:
rootDelete
: Transfer the control to the first rule ofrules
, used when reset thenode
,range
oroption.delete{Edge}Text
change
: changerange
: range for deleteoption
:
deleteStartText
: whether to remove Text node if the range is at the start of the TextdeleteEndText
: whether to remove Text node if the range is at the end of the Text{Edge}Text
and{Edge}Ancestors
convenient variables, automatically normalized inrootGet
andnext
next
: Transfer control to the next rule. You can resetoption.delete{Edge}Text
in calling this rule
The generated deleteAtRange
is called with
deleteAtRange : (change: Change, range: Range, {normalize, snapshot, deleteStartText, deleteEndText})
normalize
: by defaulttrue
snapshot
is whether to snapshot the selection, incaseof avoiding undo bugs, by defaulttrue
deleteStartText
: whether to remove Text node if the range is at the start of the Text, by defaultfalse
for the first ruledeleteEndText
: whether to remove Text node if the range is at the end of the Text, by defaulttrue
for the first rule
For more example usage, see lib/deleteAtRange/rules
or zhujinxuan/slate-bad-table
in lib/rules/deleteAtRange
insertFragmentAtRange
import { insertFragmentAtRange as plugin} from 'slate-bind-copy-paste'
const insertFragmentAtRange = plugin.generate(rules: Array<InsertRule>)
If no rules are specified, the function will behave like the insertFragmentAtRange in Slate's PR 1553.
rules
are a set of the rule explained as below:
type InsertRule = (
rootDelete: (Change, Range, Document, Options) => Change,
change: Change,
range: Range,
fragment: Document,
option: Options,
(Options) => Change
) => Change;
Options: Immutable.Record({`Edge`Text: Text, `Edge`Ancestors: List<Node>, firstNodeAsText: boolean, lastNodeAsText: boolean})
Argument:
rootDelete
: transfer the control to the first rule. used when resetnode
,range
,fragment
,option.{Where}AsText
change
: changerange
: range for insertFragmentAtRange, you can takerange.startKey
andrange.startOffset
if you like. However, this is not automatically collapsed because someone may want to implement a featuregetFragmentAtRange + insertFragmentAtRange
do not change significantly.fragment
fragment for insertoption
firstNodeAsText
: whether tries to concat first fragment node as TextdeleteEndText
: whethere tries to concat last fragment node as Text{Edge}Text
and{Edge}Ancestors
convenient variables, automatically normalized inrootGet
andnext
next
: Transfer control to the next rule. You can resetoption.{Where}AsText
in calling this rule
The generated function is called with
insertFragmentAtRange : (change: Change, range: Range, fragment: Document, {normalize, snapshot, firstNodeAsText, lastNodeAsText, deleteAtRange})
normalize
: by defaulttrue
snapshot
is whether to snapshot the selection, incaseof avoiding undo bugs, by defaulttrue
firstNodeAsText
: whether to concat texts in the first fragment node, by defaulttrue
for the first rulelastNodeAsText
: whether to concat texts in the last fragment node, by defaulttrue
for the first ruledeleteAtRange: (Change, Range, {snapshot: false, deleteStartText: false, deleteEndText: false, normalize: false})
, by default use slate'schange.deleteAtRange
. Delete content in the range before insert.
For more exmple usage, see lib/insertFragmentAtRange/rules
or zhujinxuan/slate-bad-table
in lib/rules/insertFragmentAtRange
pre-defined rules:
deleteAtRange
import { deleteAtRange as plugin} from 'slate-bind-copy-paste'
const {atDifferentText, atSameText} = plugin.rules;
atDifferentText
called whenstartKey
andendKey
are different. Behavior are alike:
- if same Text at both edges, transfer control to next rule
- if
deleteStartText: false
orstartOffset !== 0
, delete the text content in , transfer control to the first rule - delete all nodes from startText to the
commonAncestor.child
which is not an ancestor ofendText
, transfer control to the first rule
atSameText
called when whenstartKey
andendKey
are same. If the edges are different Texts, then transfer control to the next rule
insertFragmentAtRange
import { insertFragmentAtRange as plugin} from 'slate-bind-copy-paste'
const {firstParagraphAsText, lastParagraphAsText, nodesAsBlocks} = plugin.rules
firstParagraphAsText
: Tries to concat the first fragment node as TextlastParagraphAsText
: Tries to concat the last fragment node as TextnodesAsBlocks
: Insert fragment nodes as blocks in the range withsplitBlock
For Flow users
You can import the type of rules like
// @flow
import {type typeDeleteAtRangeRule as typeRule } from 'slate-bind-copy-paste'
// @flow
import {type typeInsertFragmentAtRangeRule as typeRule } from 'slate-bind-copy-paste'
// @flow
import {type typeGetFragmentAtRangeRule as typeRule } from 'slate-bind-copy-paste'