This work is ongoing and not ready yet.
Differences (incomplete)
There are lots of changes in this branch. But here's an overview of the big differences from an architectural point of view.
More coming, still in progress…
JSON
The data model is now comprised of simple JSON objects. Previously, it used Immutable.js data structures. This is a huge change, and one that unlocks many other things. Hopefully it will also increase the average performance when using Slate. It also makes it much easier to get started for newcomers. This will be a large change to migrate from, but it will be worth it.
Interfaces & Namespaces
The data model is interface-based. Previously each model was an instance of a class. Now, not only is the data plain objects, but Slate only expects that the objects implement an interface. So custom properties that used to live in node.data
can now live at the top-level of the nodes. Helpers are exposed as a collection of helper functions on a namespace. For example, Node.get(root, path)
or Range.isCollapsed(range)
. This ends up making code much clearer because you can always quickly see what interface you're working with.
TypeScript
The codebase now uses TypeScript. Working with pure JSON as a data model, and using an interface-based API are two things that have been made easier by migrating to TypeScript. You don't need to use it yourself, but if you do you'll get a lot more security when using the APIs. (And if you use VS Code you'll get nice autocompletion regardless!)
Fewer Concepts
The number of interfaces and commands has been reduced. Previously Selection
, Annotation
, Decoration
used to all be separate classes. Now they are simply objects that implement the Range
interface. Previously Block
and Inline
were separate, now they are objects that implement the Element
interface. Previously there was a Document
and Value
, but now the top-level Editor
contains the children nodes of the document itself.
The number of commands has been reduced too. Previously we had commands for every type of input, like insertText
, insertTextAtRange
, insertTextAtPath
. These have been merged into a smaller set of more customizable commands, eg. insertText
which can take at: Path | Range | Point
.
Fewer Packages
In attempt to decrease the maintenance burden, and because the new abstraction and APIs in Slate's core packages make things much easier, the total number of packages has been reduced. Things like slate-plain-serializer
, slate-base64-serializer
, etc. have been removed and can be implemented in userland easily if needed. Even the slate-html-deserializer
can now be implemented in userland (in ~10 LOC leveraging slate-hyperscript
). And internal packages like slate-dev-environment
, slate-dev-test-utils
, etc. are no longer exposed because they are implementation details.
Plugins
Plugins are now plain functions that augment the Editor
object they receive and return it again. For example can augment the command execution by composing the editor.exec
function. Or listen to operations by composing editor.apply
. Previously they relied on a custom middleware stack, and they were just bags of handlers that got merged onto an editor. Now we're using plain old function composition (aka wrapping) instead.
Elements
Block-ness and inline-ness is now a runtime choice. Previously it was baked into the data model with the object: 'block'
or object: 'inline'
attributes. Now, it checks whether an "element" is inline or not at runtime. For example, you might check to see that element.type === 'link'
and treat it as inline.
beforeinput
We now use the beforeinput
event almost exclusively. Instead of having relying on a series of shims and the quirks of React synthetic events, we're now using the standardized beforeinput
event as our baseline. It is fully supported in Safari and Chrome, will soon be supported in the new Chromium-based Edge, and is currently being worked on in Firefox. In the meantime there are a few patches to make Firefox work. Internet Explorer is no longer supported in core out of the box.
More React-ish
Rendering and event-handling is no longer a plugin's concern. Previously plugins had full control over the rendering logic, and event-handling logic in the editor. This creates a bad incentive to start putting all rendering logic in plugins, which puts Slate in a position of being a wrapper around all of React, which is very hard to do well. Instead, the new architecture has plugins focused purely on the rich-text aspects, and leaves the rendering and event handling aspects to React.
Context
Previously the <Editor>
component was doing double duty as a sort of "controller" object and also the contenteditable
DOM element. This led to a lot of awkwardness in how other components worked with Slate. In the new version, there is a new <Slate>
context provider and a simpler <Editable>
contenteditable
-like component. By putting the <Slate>
provider higher up in your component tree, you can share the editor directly with toolbars, buttons, etc. using the useSlate
hook.
Hooks
In addition to the useSlate
hook, there are a handful of other hooks. For example the useSelected
and useFocused
hooks help with knowing when to render selected states (often for void nodes). And since the use React's Content API they will automatically re-render when their state changes.
Reductions
One of the goals was to dramatically simplify a lot of the logic in Slate to make it easier to maintain and iterate on. This was done by refactoring to better base abstractions that can be built on, by leveraging modern DOM APIs, and by migrating to simpler React patterns.
To give you a sense for the change in total lines of code:
slate 8,436 -> 4,038 (48%)
slate-react 3,905 -> 715 (18%)
slate-base64-serializer 38 -> 0
slate-dev-benchmark 340 -> 0
slate-dev-environment 102 -> 0
slate-dev-test-utils 44 -> 0
slate-history 0 -> 201
slate-hotkeys 62 -> 0
slate-html-serializer 253 -> 0
slate-hyperscript 447 -> 410
slate-plain-serializer 56 -> 0
slate-prop-types 62 -> 0
slate-react-placeholder 62 -> 0
slate-schema 0 -> 504
total 13,807 -> 5,868 (43%)
It's quite a big difference, although it's not done so the final sizes will likely grow a bit before it's ready. But that doesn't even include the dependencies that were shed in the process too.
Fixes
This is an estimate of which issues are fixed by this pull request. There are a lot of them, because it changes a lot of things. There might be a few incorrectly "fixed" ones here, so if one of them is your issue and you don't think it's fixed feel free to reopen a new issue.
Fixes https://github.com/ianstormtaylor/slate/issues/3087
Fixes https://github.com/ianstormtaylor/slate/issues/3056
Fixes https://github.com/ianstormtaylor/slate/issues/3090
Fixes https://github.com/ianstormtaylor/slate/issues/3075
Fixes https://github.com/ianstormtaylor/slate/issues/2890
Fixes https://github.com/ianstormtaylor/slate/issues/2325
Fixes https://github.com/ianstormtaylor/slate/issues/3007
Fixes https://github.com/ianstormtaylor/slate/issues/3061
Fixes https://github.com/ianstormtaylor/slate/issues/560
Fixes https://github.com/ianstormtaylor/slate/issues/2869
Fixes https://github.com/ianstormtaylor/slate/issues/3028
Fixes https://github.com/ianstormtaylor/slate/issues/3027
Fixes https://github.com/ianstormtaylor/slate/issues/1762
Fixes https://github.com/ianstormtaylor/slate/issues/1022
Fixes https://github.com/ianstormtaylor/slate/issues/3020
Fixes https://github.com/ianstormtaylor/slate/issues/2746
Fixes https://github.com/ianstormtaylor/slate/issues/2991
Fixes https://github.com/ianstormtaylor/slate/issues/2333
Fixes https://github.com/ianstormtaylor/slate/issues/2711
Fixes https://github.com/ianstormtaylor/slate/issues/2413
Fixes https://github.com/ianstormtaylor/slate/issues/2345
Fixes https://github.com/ianstormtaylor/slate/issues/2812
Fixes https://github.com/ianstormtaylor/slate/issues/2859
Fixes https://github.com/ianstormtaylor/slate/issues/2862
Fixes https://github.com/ianstormtaylor/slate/issues/2863
Fixes https://github.com/ianstormtaylor/slate/issues/2495
Fixes https://github.com/ianstormtaylor/slate/issues/2864
Fixes https://github.com/ianstormtaylor/slate/issues/2860
Fixes https://github.com/ianstormtaylor/slate/issues/2878
Fixes https://github.com/ianstormtaylor/slate/issues/2858
Fixes https://github.com/ianstormtaylor/slate/issues/2861
Fixes https://github.com/ianstormtaylor/slate/issues/2985
Fixes https://github.com/ianstormtaylor/slate/issues/2987
Fixes https://github.com/ianstormtaylor/slate/issues/1883
Fixes https://github.com/ianstormtaylor/slate/issues/2002
Fixes https://github.com/ianstormtaylor/slate/issues/2022
Fixes https://github.com/ianstormtaylor/slate/issues/2989
Fixes https://github.com/ianstormtaylor/slate/issues/2990
Fixes https://github.com/ianstormtaylor/slate/issues/2876
Fixes https://github.com/ianstormtaylor/slate/issues/2983
Fixes https://github.com/ianstormtaylor/slate/issues/2945
Fixes https://github.com/ianstormtaylor/slate/issues/2986
Fixes https://github.com/ianstormtaylor/slate/issues/2939
Fixes https://github.com/ianstormtaylor/slate/issues/2968
Fixes https://github.com/ianstormtaylor/slate/issues/2895
Fixes https://github.com/ianstormtaylor/slate/issues/2900
Fixes https://github.com/ianstormtaylor/slate/issues/2873
Fixes https://github.com/ianstormtaylor/slate/issues/2567
Fixes https://github.com/ianstormtaylor/slate/issues/2868
Fixes https://github.com/ianstormtaylor/slate/issues/2867
Fixes https://github.com/ianstormtaylor/slate/issues/2668
Fixes https://github.com/ianstormtaylor/slate/issues/2029
Fixes https://github.com/ianstormtaylor/slate/issues/2759
Fixes https://github.com/ianstormtaylor/slate/issues/2701
Fixes https://github.com/ianstormtaylor/slate/issues/1884
Fixes https://github.com/ianstormtaylor/slate/issues/2503
Fixes https://github.com/ianstormtaylor/slate/issues/2620
Fixes https://github.com/ianstormtaylor/slate/issues/2420
Fixes https://github.com/ianstormtaylor/slate/issues/2708
Fixes https://github.com/ianstormtaylor/slate/issues/2538
Fixes https://github.com/ianstormtaylor/slate/issues/1247
Fixes https://github.com/ianstormtaylor/slate/issues/2466
Fixes https://github.com/ianstormtaylor/slate/issues/2111
Fixes https://github.com/ianstormtaylor/slate/issues/2297
Fixes https://github.com/ianstormtaylor/slate/issues/2321
Fixes https://github.com/ianstormtaylor/slate/issues/2329
Fixes https://github.com/ianstormtaylor/slate/issues/2060
Fixes https://github.com/ianstormtaylor/slate/issues/2274
Fixes https://github.com/ianstormtaylor/slate/issues/2108
Fixes https://github.com/ianstormtaylor/slate/issues/1466
Fixes https://github.com/ianstormtaylor/slate/issues/1759
Fixes https://github.com/ianstormtaylor/slate/issues/2043
Fixes https://github.com/ianstormtaylor/slate/issues/1128
Fixes https://github.com/ianstormtaylor/slate/issues/1464
Fixes https://github.com/ianstormtaylor/slate/issues/721
Fixes https://github.com/ianstormtaylor/slate/issues/674
Fixes https://github.com/ianstormtaylor/slate/issues/2977
Fixes https://github.com/ianstormtaylor/slate/issues/2336
Fixes https://github.com/ianstormtaylor/slate/issues/2361
Fixes https://github.com/ianstormtaylor/slate/issues/2093
Fixes https://github.com/ianstormtaylor/slate/issues/802
Fixes https://github.com/ianstormtaylor/slate/pull/2871
Fixes https://github.com/ianstormtaylor/slate/pull/3113
Fixes https://github.com/ianstormtaylor/slate/pull/2734
Fixes https://github.com/ianstormtaylor/slate/pull/3077
Fixes https://github.com/ianstormtaylor/slate/pull/3040
Fixes https://github.com/ianstormtaylor/slate/pull/2144
Fixes https://github.com/ianstormtaylor/slate/pull/3041
Fixes https://github.com/ianstormtaylor/slate/pull/2743
Fixes https://github.com/ianstormtaylor/slate/pull/2680
Fixes https://github.com/ianstormtaylor/slate/pull/2937
Fixes https://github.com/ianstormtaylor/slate/pull/2907
Fixes https://github.com/ianstormtaylor/slate/pull/2931
Fixes https://github.com/ianstormtaylor/slate/pull/2871
Fixes https://github.com/ianstormtaylor/slate/pull/2850
Fixes https://github.com/ianstormtaylor/slate/pull/2436
Fixes https://github.com/ianstormtaylor/slate/pull/1823
Fixes https://github.com/ianstormtaylor/slate/pull/2073
Fixes https://github.com/ianstormtaylor/slate/pull/1576
Fixes https://github.com/ianstormtaylor/slate/pull/1490
Fixes https://github.com/ianstormtaylor/slate/pull/1202
Fixes https://github.com/ianstormtaylor/slate/pull/1027
Eliminates
In addition to fixing a lot of things, the significant changes to the architecture mean that a lot of open issues are no longer relevant because they are talking about concepts that no longer exist.
https://github.com/ianstormtaylor/slate/issues/3022
https://github.com/ianstormtaylor/slate/issues/3050
https://github.com/ianstormtaylor/slate/issues/3061
https://github.com/ianstormtaylor/slate/issues/3013
https://github.com/ianstormtaylor/slate/issues/3012
https://github.com/ianstormtaylor/slate/issues/3006
https://github.com/ianstormtaylor/slate/issues/2886
https://github.com/ianstormtaylor/slate/issues/2932
https://github.com/ianstormtaylor/slate/issues/2829
https://github.com/ianstormtaylor/slate/issues/2328
https://github.com/ianstormtaylor/slate/issues/2856
https://github.com/ianstormtaylor/slate/issues/2634
https://github.com/ianstormtaylor/slate/issues/2472
https://github.com/ianstormtaylor/slate/issues/2742
https://github.com/ianstormtaylor/slate/issues/2744
https://github.com/ianstormtaylor/slate/issues/2549
https://github.com/ianstormtaylor/slate/issues/2672
https://github.com/ianstormtaylor/slate/issues/2673
https://github.com/ianstormtaylor/slate/issues/2640
https://github.com/ianstormtaylor/slate/issues/2296
https://github.com/ianstormtaylor/slate/issues/826
https://github.com/ianstormtaylor/slate/issues/2330
https://github.com/ianstormtaylor/slate/issues/1915
https://github.com/ianstormtaylor/slate/issues/2331
https://github.com/ianstormtaylor/slate/issues/1749
https://github.com/ianstormtaylor/slate/issues/2289
https://github.com/ianstormtaylor/slate/issues/2082
https://github.com/ianstormtaylor/slate/issues/2078
https://github.com/ianstormtaylor/slate/issues/1843
https://github.com/ianstormtaylor/slate/issues/1703
https://github.com/ianstormtaylor/slate/issues/1794
https://github.com/ianstormtaylor/slate/issues/1821
https://github.com/ianstormtaylor/slate/issues/1652
https://github.com/ianstormtaylor/slate/issues/1464
https://github.com/ianstormtaylor/slate/issues/803
https://github.com/ianstormtaylor/slate/issues/1367
https://github.com/ianstormtaylor/slate/issues/651
https://github.com/ianstormtaylor/slate/issues/873
https://github.com/ianstormtaylor/slate/pull/1023
https://github.com/ianstormtaylor/slate/pull/784
https://github.com/ianstormtaylor/slate/pull/1756
https://github.com/ianstormtaylor/slate/pull/1626
https://github.com/ianstormtaylor/slate/pull/1827
https://github.com/ianstormtaylor/slate/pull/2280
https://github.com/ianstormtaylor/slate/pull/2410
https://github.com/ianstormtaylor/slate/pull/2448
https://github.com/ianstormtaylor/slate/pull/2660
https://github.com/ianstormtaylor/slate/pull/2602
https://github.com/ianstormtaylor/slate/pull/2505
https://github.com/ianstormtaylor/slate/pull/2674
https://github.com/ianstormtaylor/slate/pull/2928
https://github.com/ianstormtaylor/slate/pull/3003
https://github.com/ianstormtaylor/slate/pull/3092
improvement debt ✶ breaking