slate-bind-copy-paste
v0.2.3
Published
A Slate plugin to handle deleteAtRange, insertFragmentAtRange and getFragmentAtRange
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 thenodeorrange.node: The root node forgetFragmentAtRangerange: 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}Textand{Edge}Ancestorsin each call ofnextandrootGetnext: Transfer the control to the next rule ofrules, keepingnodeandrange
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,rangeoroption.delete{Edge}Textchange: 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}Textand{Edge}Ancestorsconvenient variables, automatically normalized inrootGetandnext
next: Transfer control to the next rule. You can resetoption.delete{Edge}Textin calling this rule
The generated deleteAtRange is called with
deleteAtRange : (change: Change, range: Range, {normalize, snapshot, deleteStartText, deleteEndText})normalize: by defaulttruesnapshotis whether to snapshot the selection, incaseof avoiding undo bugs, by defaulttruedeleteStartText: whether to remove Text node if the range is at the start of the Text, by defaultfalsefor the first ruledeleteEndText: whether to remove Text node if the range is at the end of the Text, by defaulttruefor 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}AsTextchange: changerange: range for insertFragmentAtRange, you can takerange.startKeyandrange.startOffsetif you like. However, this is not automatically collapsed because someone may want to implement a featuregetFragmentAtRange + insertFragmentAtRangedo not change significantly.fragmentfragment for insertoption
firstNodeAsText: whether tries to concat first fragment node as TextdeleteEndText: whethere tries to concat last fragment node as Text{Edge}Textand{Edge}Ancestorsconvenient variables, automatically normalized inrootGetandnext
next: Transfer control to the next rule. You can resetoption.{Where}AsTextin calling this rule
The generated function is called with
insertFragmentAtRange : (change: Change, range: Range, fragment: Document, {normalize, snapshot, firstNodeAsText, lastNodeAsText, deleteAtRange})normalize: by defaulttruesnapshotis whether to snapshot the selection, incaseof avoiding undo bugs, by defaulttruefirstNodeAsText: whether to concat texts in the first fragment node, by defaulttruefor the first rulelastNodeAsText: whether to concat texts in the last fragment node, by defaulttruefor 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;atDifferentTextcalled whenstartKeyandendKeyare different. Behavior are alike:
- if same Text at both edges, transfer control to next rule
- if
deleteStartText: falseorstartOffset !== 0, delete the text content in , transfer control to the first rule - delete all nodes from startText to the
commonAncestor.childwhich is not an ancestor ofendText, transfer control to the first rule
atSameTextcalled when whenstartKeyandendKeyare 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.rulesfirstParagraphAsText: 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'