[lexical][lexical-utils][lexical-selection][lexical-table] Feature: NodeCaret abstraction for traversals and ranges#7046
Conversation
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
This comment was marked as outdated.
This comment was marked as outdated.
zurfyx
left a comment
There was a problem hiding this comment.
Overall, I like the concept and the direction, thank you for putting this masterpiece together with such detailed documentation and test plan!
A couple high-level thoughts:
While most of the LexicalCaret methods are simple, this adds a major of piece of opinionated API that (will) touch on most of Lexical core methods, I'm curious how complicated it will for contributors to familiarize with it. Before that, selection and LexicalNode were mostly independent. However, it does make some of the core implementation easier to read when the verbose iteration logic is abstracted away, and your LexicalSelection fixes prove this.
Naming wise, @fantactuka proposes the use of cursor instead of caret. Previously, we introduced block "cursor" selection, I wonder why we decided to name this one caret instead.
I'll have it a second pass this week but I wonder what others think in the meantime.
Selection and Even in situations like TableSelection, NodeSelection, etc. you still need to do document tree navigation and in those cases it will be very useful to have these abstractions at hand. In some cases RangeSelection could be used for that but it's awfully hard to work with them without setting the editor's selection which is counter-productive when you are working with another selection type.
The words have very similar meaning, and I think it will be hard to avoid some confusion no matter which name is chosen. I settled on caret specifically because it is used more commonly for text, where cursor is the more general term. Cursor is used in other contexts in lexical already which is why I avoided that (blockCursor, css cursor for the mouse pointer, etc.). See also: |
|
I think a more accurate way to think of it is that NodeCaret/PointCaret are a way to bring something like PointType (but more fit for purpose) to everywhere in Lexical in a way that does not depend on RangeSelection. Right now RangeSelection is too intertwined with LexicalNode and document navigation in general. For example there's probably been a hundred times where I want to programmatically create a selection that spans multiple nodes but the APIs to do that are just miserable because calling .select(...) on a node sets the EditorState's selection as a side-effect and always sets both points when you're really just trying to get an anchor or a focus. In order to get an anchor or focus from a node with NodeCaret you just create one with one function call. |
|
Will merge this after v0.24.0 so there's some nightly releases before it goes live |
|
Latest couple commits:
Should be good to merge once re-approved |
Description
A fair amount of bugs and complexity in our code results from ambiguity and awkwardness around traversing the node tree, as well as issues around coordinates becoming stale after mutations. This is a proposal for a new set of abstractions that can be used in place of the typical
PointTypeandRangeSelectionto work through these sorts of traversal use cases with hopefully fewer bugs.There are three major deficiencies that the design of
NodeCarethopes to address:Docs:
I can write up some flow types when/if we move forward with the proposal to reduce the maintenance burden if anything changes before acceptance.
Cost
The current estimate looks like it's currently at
31.55 KB (+8.56% 🔺)which is +~2.5kB for the production cjs build. There will be some follow-up PRs to reduce this further with additional refactoring to use this API more internally.Other changes
I didn't refactor everything with NodeCaret but chose a few places that would be straightforward and/or make it easier to fix a few bugs. More will come later which should reduce code size.
lexicalRangeSelection.removeTextwith new algorithm based on CaretRangeTextNode.splitTextalgorithm@lexical/selection$forEachSelectedTextNodeto work with types other than RangeSelection$patchStylefor updating the style of an individual TextNode or collapsed RangeSelection$ensureForwardRangeSelectionfunction to flip anchor/focus when backwards$setBlocksType: Add new$afterCreateElementargument to allow user to specify how properties propagate to the new block (e.g. format and indent by default - fixes an indent related bug)$copyBlockFormatIndentused as new$setBlocksTypeoptional argument default@lexical/table$createTableSelectionFrom@lexical/utils$dfsand related functions with NodeCaret implementationsCloses #7076
Closes #7081