Slate properties props and feature Attributes
In Slate’s documentation, there’s a reminder, “Make sure to mix the attributes of props into the custom component and render props. Children in the custom component.”
The props refer generally to the parameters passed by the parent to the child, the Attributes refer to the built-in features Slate needs during rendering, and the children refer to the text components Slate takes over and is responsible for rendering.
So why is this “attributes” so important? This article will take this question into consideration.
Slate’s custom built-in features
In the process of Slate development, we often see some custom built-in attributes starting with data-, such as data-slate-node. These built-in features are listed below:
Editable
data-slate-editor
Used to identify the editor component.
Element
-
Data – SLATE -node: must have values’ element ‘|’ value ‘|’ text ‘, representing elements, document the whole quantity (applicable to the Editable), text node (applicable to isInline elements).
-
Data-slate-void: the value is true if the element is empty; otherwise, it does not exist.
-
Data-slate-inline: The value is true if the element is inline; otherwise, it does not exist.
Additionally, there are the following built-in features in the Attributes for Element:
-
ContentEditable: The value is false if it cannot be edited; otherwise, it does not exist.
-
Dir: The value is’ RTL ‘if the editing direction is from right to left; otherwise, it does not exist.
-
Ref: Mandatory, the ref reference of the current element. Slate adds the mapping between an Element and its corresponding DOM node to the WeakMap of ELEMENT_TO_NODE each time it renders. A lack of ref will result in rendering failures and errors in toSlateNode due to missing mappings in ELEMENT_TO_NODE.
Leaf
data-slate-leaf
: Yes, the value istrue
, indicating that the corresponding DOM element is Leaf node.
String
-
Data-slate-string: The value is true if it is a text node; otherwise, it does not exist.
-
Data – SLATE – zero – width: if zero width of the text node values’ n ‘|’ z ‘, respectively to refer to a newline, not line, otherwise does not exist.
-
Data-slate-length: indicates the actual width of a zero-width text node, in characters. Defaults to 0 or, if not, to the width of the text character of the element with isVoid set.
other
data-slate-spacer
: set upisVoid
的Element
A layer of elements is wrapped around it that contains the custom properties to distinguish normal elements and to manage the behavior associated with the empty element (copy, cursor focus, cursor out-of-focus, and so on).
Slate’s onion model
The component hierarchy in Slate can be represented as follows:
Slate is essentially an onion model, from the outside to the inside, respectively:
Slate
An editor component wrapper used to take overEditable
的onChange
Events.Editable
Is essentially a superset of Textarea elements, which is also reflected in itsThe parameter typesOn. Is a mutable singleton instance.Children
Child component for take overEditable
的children
Property and is responsible for rendering downElement
.Element
Element from the root nodeeditor
The next-level nodes represent element instances, one for each elementtype
Attribute to identify its type. userenderElement
Method to add custom properties and styles. Update in this layerElement node hierarchyThe mapping relation of.Text
Text component used to take overElement
的children
Property and is responsible for rendering downLeaf
. Update in this layerLeaf node hierarchyThe mapping relation of.Leaf
Leaves, from the root nodeeditor
The secondary nodes down here, one for each leaftext
Attribute toString
Render text. userenderLeaf
Method to add custom properties and styles.String
The lowest level text element, text input and browserDOM
Where the real interaction is, there is no view-data binding with the virtual DOM layer, because this locationcontentEditable
的DOM
Natively supports text input. For example, if you type a character, it will fire once hereonChange
Event and bubble toSlate
Take over processing.
Due to Slate’s Onion model, all elements’ features are directly mounted to the corresponding DOM node, and each corresponding level will have the corresponding attributes built-in features to mark the information of that level node (such as inline elements, This will correspond to data-slate-inline=”true”), such as Element’s built-in feature data-slate-node= “Element”, and Leaf’s built-in feature data-slate-leaf.
Develop a custom component
When a custom component or a custom text node attribute is involved in Slate, the renderLeaf and renderElement of Slate react are used.
Let’s simply develop a custom component to deepen our understanding of the Onion model:
function App() {
const editor = useMemo(() = > withReact(createEditor()), []);
const [value, setValue] = useState([
{
type: "paragraph".children: [{text: "This is editable ",},],}, {type: "block-quote".children: [{text: "This is block quote ",},],},]);const renderElement = ({ children, element, attributes }) = > {
return <DefaultElement {.{ children.element.attributes}} / >;
};
const DefaultElement = ({ children, element, attributes }) = > {
if (element.type === "block-quote") {
return (
<blockquote style={{ fontFamily: "fantasy}} ">{children}</blockquote>
);
}
return (<div {. attributes} >{children}</div>);
};
return (
<div className="App">
<Slate editor={editor} value={value} onChange={(val)= > setValue(val)}>
<Editable renderElement={renderElement} />
</Slate>
</div>
);
}
export default App;
Copy the code
Adding a custom block-Quote component is common, but it is possible to remove the mask from the Onion model and directly return the complete rendering of the block-Quote component as DefaultElement.
We rewrite DefaultElement above as:
const DefaultElement = ({ children, element, attributes }) = > {
if (element.type === "block-quote") {
return (
<blockquote
data-slate-node="text"
ref={attributes.ref}
style={{ fontFamily: "fantasy}} ">
<span data-slate-leaf="true" contenteditable="true">
<span data-slate-string="true">{children[0].props.text.text}</span>
</span>
</blockquote>
);
}
return <div {. attributes} >{children}</div>;
};
Copy the code
The rewritten block-quote component is virtually identical to the DOM structure rendered, returning the component’s rendering directly. The hierarchy fits Slate’s onion model.
Note: This is not recommended in practice, as it would lose the information contained in the leaf node as part of a custom component, and the render results of the leaf node are unpredictable, so doing so may result in inconsistent render results.
In Slate, the weak map ELEMENT_TO_NODE is updated at both the Element and Text levels. The weak map ELEMENT_TO_NODE is not updated at the Element and Text levels. Cannot get the leaf node at path [1] because it refers to a non-leaf node: [object Object]
ToSlateNode error
When using Slate’s React rendering engine, this error is often encountered because of the design limitations of the React layer itself.
Uncaught Error: Cannot resolve a Slate node from DOM node: [object HTMLDivElement]
at Object.toSlateNode (react-editor.ts:391:1)
at editable.tsx:761:1
Copy the code
This is because DOM nodes obtained through events do not have corresponding key-value pairs in the ELEMENT_TO_NODE weak mapping, and thus cannot be mapped from DOM elements to corresponding Slate nodes.
In practice, we add a custom data-ignore-slate attribute for a particular node so that nodes with this attribute can be filtered when toSlateNode() is called to avoid errors.
if(domNode? .hasAttribute? . ("data-ignore-slate")) return
Copy the code
conclusion
Starting with Slate attributes, we learned what these built-in features do and how Slate carries information into rendered DOM nodes.
And see how Slate-React wraps data layer by layer, like an onion model, from top to bottom. The data of Slate nodes is managed by hierarchical mapping, which translates layer by layer into DOM nodes on corresponding pages.