notes on the future namespace-based API
See original GitHub issueIn light of https://github.com/ianstormtaylor/slate/issues/2495 and switching to using an interface-based API with plain JavaScript objects and arrays, the core API will change. Using plain JavaScript data means that we can eliminate a decent amount of code I think, and it means we’ll move to mimicking native namespaced utils like Object.entries(object)
.
This issue is just note to keep track of the “ideal” future interface-and-namespace-based API, as I think of improvements. We’ll work towards it over a series of versions, since we want to keep things incremental and deprecation-friendly whenever possible.
But here’s a sketch…
const Slate = {
// Creators
createAnnotation(props, root = null) {},
createDecoration(props, root = null) {},
createMark(props) {},
createNode(props) {},
createRange(props, root = null) {},
createPath(array, root = null) {},
createPoint(props, root = null) {},
createSelection(props, root = null) {},
createValue(props) {},
// Producers
produce() {}, // for producing new immutable values, delegates to immer
apply(value, operation) {},
}
const Node = {
// Getters
get(root, path) {}, // lookup by path in a `root`
path(root, node) {}, // lookup a path by `node` instance
slice(root, range) {}, // slice out a fragment by range
offset(root, path) {}, // compute the text offset by path
text(root) {}, // get the concatenated text content of a node
// Testers
has(root, path) {}, // test if a path exists
hasBlocks(root) {},
hasInlines(root) {},
isInVoid(root, path) {}, // test if a path is in a void
isLeafBlock(root) {},
isLeafInline(root) {},
// Iterables
ancestors(root, path) {},
blocks(root) {},
descendants(root) {},
inlines(root) {},
marks(root) {},
siblings(root, path) {},
texts(root) {},
// Searching
closest(root, path, predicate = identity) {},
furthest(root, path, predicate = identity) {},
// Convenience
firstBlock(root) {},
lastBlock(root) {},
nextBlock(root, path) {},
previousBlock(root, path) {},
closestBlock(root, path) {},
furthestBlock(root, path) {},
firstInline(root) {},
lastInline(root) {},
nextInline(root, path) {},
previousInline(root, path) {},
closestInline(root, path) {},
furthestInline(root, path) {},
nextSibling(root, path) {},
previousSibling(root, path) {},
firstText(root) {},
lastText(root) {},
nextText(root, path) {},
previousText(root, path) {},
closestVoid(root, path) {},
furthestVoid(root, path) {},
// Producers
addMark(root, path, mark) {},
removeMark(root, path, mark) {},
setMark(root, path, mark, newProperties) {},
insertNode(root, path, node) {},
removeNode(root, path) {},
insertText(root, path, offset, text) {},
removeText(root, path, offset, length) {},
splitNode(root, path, position) {},
mergeNode(root, path) {},
setNode(root, path, newProperties) {},
setData(node, data) {},
setObject(node, object) {},
setType(node, type) {},
setNodes(node, nodes) {},
}
const Point = {
// Testers
isAfter(point, pointOrRange) {},
isBefore(point, pointOrRange) {},
isAtEndOf(point, range) {},
isAtStartOf(point, range) {},
isIn(point, range) {},
// Producers
moveBackward(point, n, root, options) {}, // can specify `options.unit` (char, word, …)
moveForward(point, n, root, options) {}, // can specify `options.unit` (char, word, …)
moveTo(point, path, offset, root) {},
setPath(point, path) {},
setOffset(point, offset) {},
}
const Range = {
// Testers
isBackward(range) {},
isCollapsed(range) {},
isExpanded(range) {},
isForward(range) {},
isSet(range) {},
isUnset(range) {},
// Getters
start(range) {},
end(range) {},
// Iterables
points(range) {}, // returns `[start, end]` for convenience
// Producers
flip(range) {},
unset(range) {},
moveBackward(range, n, root, options) {}, // can specify `options.unit` (char, word, …)
moveForward(range, n, root, options) {}, // can specify `options.unit` (char, word, …)
moveTo(range, path, offset) {},
setAnchor(range, fn) {},
setFocus(range, fn) {},
setStart(range, fn) {},
setEnd(range, fn) {},
setPoints(range, fn) {},
}
// TODO: the other interfaces...
It’s funny, I thought it was going to make things more verbose, but in reality the before and after is pretty similar (and in some cases more clear) for many of them:
// Before...
const node = document.getNode(path)
// After...
const node = Node.get(document, path)
And the iterators are similar to how Object.entries()
works:
for (const [block, path] of Node.blocks(document)) {
// ...
}
Overall pretty excited for how it’s shaking out. If you want to help make this happen, anything to further https://github.com/ianstormtaylor/slate/issues/2495 is the best way to do that! Thanks.
Issue Analytics
- State:
- Created 4 years ago
- Reactions:3
- Comments:5 (3 by maintainers)
Top GitHub Comments
@steida that’s a good point, we could consider exporting both and just seeing which one is most useful over time if only one ends up being used.
Fixed by https://github.com/ianstormtaylor/slate/pull/3093.