Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Cover image for SLATE Code editor with highlight
priolo
priolo

Posted on

     

SLATE Code editor with highlight

INTRODUCTION

SLATE is an excellent library for creating WYSIWYG editors in REACT, I find it superior toQUILL.

However, I had difficulties inserting editable BLOCKS with syntax highlighting for code.

Yes, there is an officialexample, but at least for me, it's not very clear.

Let's cut to the chase! Let's see the CODE!!!

Let's say you have an empty React project with typescript.

Install the dependencies:

npm install slate slate-react slate-history prismjs

inApp.tsx

functionApp(){consteditor=useMemo(()=>withHistory(withReact(createEditor())),[]);return(<Slateeditor={editor}initialValue={[{children:[{text:''}]}]}><Editablestyle={{backgroundColor:"lightgray"}}renderElement={({attributes,element,children})=><div{...attributes}>{children}</div>}renderLeaf={({attributes,children,leaf})=><span{...attributes}>{children}</span>}/></Slate>)}
Enter fullscreen modeExit fullscreen mode

On initialization of the "App" component

I create theeditor controller

and apply it to theSlate component.

Let's create the tokens for highlighting withPRISMJS

inApp.tsx

...typeBaseRangeCustom=BaseRange&{className:string}functiondecorateCode([node,path]:NodeEntry){constranges:BaseRangeCustom[]=[]// make sure it is an Slate Elementif(!Element.isElement(node))returnranges// transform the Element into a stringconsttext=Node.string(node)// create "tokens" with "prismjs" and put them in "ranges"consttokens=Prism.tokenize(text,Prism.languages.javascript);letstart=0;for(consttokenoftokens){constlength=token.length;constend=start+length;if(typeoftoken!=='string'){ranges.push({anchor:{path,offset:start},focus:{path,offset:end},className:`token${token.type}`,});}start=end;}// these will be found in "renderLeaf" in "leaf" and their "className" will be appliedreturnranges;}
Enter fullscreen modeExit fullscreen mode

This function receives a SLATENode.

I get the text of the "Node"

With the text, I create the "tokens" withPRISMJS.

I transform the "tokens" intoRange.

The "Ranges" have theclassName property with the information for the highlight.

Finally, I apply the "Ranges" to the Slate component

I assign the function to thedecorate property which is rendered withrenderLeaf

still inApp.tsx

...<Editablestyle={{backgroundColor:"lightgray"}}decorate={decorateCode}renderElement={({attributes,element,children})=><div{...attributes}>{children}</div>}renderLeaf={({attributes,children,leaf})=>// here I apply the className that I calculated in "decorateCode"<span{...attributes}className={leaf.className}>{children}</span>}/>...
Enter fullscreen modeExit fullscreen mode

The code ishere!

End.

Optimize the code

You will notice that the "decorateCode" function is called with every interaction.

Every time you press a key, it creates the tokens for all the lines!

To optimize, we use a cache.

Let's move the "decorateCode" function inside the "App" component

functionApp(){...constcacheMem=useRef<{text:string,ranges:BaseRange[]}[]>([])functiondecorateCode([node,path]:NodeEntry){// CACHE **************constranges:BaseRangeCustom[]=[]// make sure it is an Slate Elementif(!Element.isElement(node))returnranges// transform the Element into a stringconsttext=Node.string(node)// CACHE **************constindex=path[0]constcache=cacheMem.current[index]if(!!cache&&cache.text==text)returncache.ranges// CACHE **************// create "tokens" with "prismjs" and put them in "ranges"consttokens=Prism.tokenize(text,Prism.languages.javascript);letstart=0;for(consttokenoftokens){constlength=token.length;constend=start+length;if(typeoftoken!=='string'){ranges.push({anchor:{path,offset:start},focus:{path,offset:end},className:`token${token.type}`,});}start=end;}// CACHE **************cacheMem.current[index]={text,ranges}// CACHE **************// these will be found in "renderLeaf" in "leaf" and their "className" will be appliedreturnranges;}}
Enter fullscreen modeExit fullscreen mode

You can find the codehere!

Basically, if thePath of the Node (which is an index)

is present in the cache and the text is the same

it immediately returns the "ranges" from the cache without creating the "tokens".

Top comments(3)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss
CollapseExpand
 
priolo profile image
priolo
  • Location
    Italy
  • Joined

It is interesting to note that dev.to does not use WYSIWYG.
It could be a good choice (like visual studio code)
But in my opinion it should put a preview always visible

CollapseExpand
 
programmerraja profile image
Boopathi
Programmer with curious to learn different technologies and develop cool product from that
  • Location
    India
  • Work
    Full stack dev
  • Joined

This is a really helpful breakdown of how to implement syntax highlighting in a SLATE editor. The caching optimization is particularly valuable, as it prevents unnecessary re-calculations. 👍

CollapseExpand
 
priolo profile image
priolo
  • Location
    Italy
  • Joined

Thanks!
It was something I needed for a project of mine and I found it very difficult. Instead in the end it is quite simple.
Yes, optimization, for a very long text is necessary!

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

  • Location
    Italy
  • Joined

More frompriolo

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp