craft.js icon indicating copy to clipboard operation
craft.js copied to clipboard

Rich Text Editor - Is there an example?

Open saas-developer opened this issue 4 years ago • 11 comments

Is your feature request related to a problem? Please describe. A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

Is it possible to use a Rich Text Editor for editing the text content. Is there an example on how this can be done?

Describe the solution you'd like A clear and concise description of what you want to happen.

I would like to see Rich Text Editor added to examples and documentation.

saas-developer avatar Jun 21 '20 05:06 saas-developer

I guess it would be pretty easy to integrate some external solution like CKE5, the problem is that it won't feel really seamless with Craft's UI. E.g. imagine you have a block of text inside an RTE and editors would want to insert a heading in the middle of it. They'd have to first break it apart into two Craft blocks, insert one more node in-between, doesn't feel like a great UX to me.

dimaip avatar Feb 09 '21 18:02 dimaip

Actually @prevwong had released a package for v2 of craft that can integrate slate-js: https://www.npmjs.com/package/@craftjs/slate . It's still quite fresh and not everything works perfectly, but UX is somewhat decent. I'm going to work on example that shows how it can be used together when i have a moment 🤞

matdru avatar Feb 09 '21 18:02 matdru

@matdru @prevwong Awesome! Could you give me a hint where the source of that package is located? I wanted to get some insights to figure out in the meantime how to use it but found nothing so far.

janus-reith avatar Feb 17 '21 09:02 janus-reith

@janus-reith The slate code is located here, and you can use it by installing one of the v.0.2.0-alpha.x versions of the @craftjs/core and @craftjs/slate packages on NPM.

A word of caution though - the slate package is far from perfect and it's not very performant with larger documents. This is due to the current approach of synching Craft and Slate states together which requires the use of deep equals and other transformations.

The good news is that I'm trying to work on introducing an Operations system to Craft (similar to Slate) that would allow us to translate Slate operations to Craft (and vice versa) directly, so this should technically help us achieve much better performance (and flexibility)!

Edit: A demo project using the slate package: https://github.com/prevwong/craft-rte if you wanna try it out (The APIs will definitely change in the future)

prevwong avatar Feb 17 '21 09:02 prevwong

@prevwong Awesome, will try right away, thanks for these details! Right now, my primary use case would only involve some very basic styled text passages which probably won't be nested heavily.

Although for some different future use case I also had that other approach in mind that Notion and Gutenberg Editor take, where the main element is editable text itself, performance would certainly become important there - I wonder how far craftjs and slate could blend for that purpose or if it would even make sense, I guess that outer element could just be handled by craft and spawn Slate-based components when starting to type or something like that. Edit: I just tried out your example and realized that this is exactly what it does, amazing!

janus-reith avatar Feb 17 '21 11:02 janus-reith

I investigated few solutions and at the time I found that implementing it directly on a Text component and then just use it across the different elements was the best course of action.

Here is a video https://youtu.be/AFYcSMYjd3o

The hover function looks something like this

function HoverButton(fontSize, textAlign, weight, tag, color) { return ( <div> <ButtonGroup size="sm" color="red" isAttached variant="outline"> <EditButton cmd="italic" name="I" border="3px 0 0 0" /> </ButtonGroup> </div> ); }

and this is an example of how to modify the selection using execCommand

function EditButton(props) { return ( <Button key={props.cmd} onMouseDown={(evt) => { evt.preventDefault(); document.execCommand(props.cmd, false, evt.target.value); }} > {props.name} </Button> ); }

hugominas avatar Feb 17 '21 11:02 hugominas

function EditButton(props) { return ( <Button key={props.cmd} onMouseDown={(evt) => { evt.preventDefault(); document.execCommand(props.cmd, false, evt.target.value); }} > {props.name} </Button> ); }

Looks really nice what you showcase in your video! I refrained from using document.execCommand so far because I was unclear about the spec.

janus-reith avatar Feb 18 '21 07:02 janus-reith

Your right, even though its deprecated it is still usable, with a few font-size hacks to be honest. However I think it will be a quick port to use https://w3c.github.io/input-events/

hugominas avatar Feb 18 '21 10:02 hugominas

Has there been any progress on this? I don't see the slate package in the repo anymore, is it still supported?

mozzius avatar Sep 13 '21 12:09 mozzius

@Mozzius i believe it lives in next branch with experimental flag since it iss way too early to guarantee a stable API at this point.

matdru avatar Sep 13 '21 12:09 matdru

My mistake, I looked at next but not in experimental

mozzius avatar Sep 13 '21 13:09 mozzius