craft.js
craft.js copied to clipboard
Support for Frame inside iframe / react-frame-component / react-styled-frame
I'd like to use Craft for a drag-and-drop React editor, where the preview is resizable to show responsive behavior.
I tried using react-styled-frame like this:
<Editor resolver={allComponents}>
<StyledFrame>
<Frame>
<Canvas>
<TextComponent text="Hello world" />
</Canvas>
</Frame>
</StyledFrame>
</Editor>
...but the drag-and-drop indicators show up in the wrong space, probably using the global window coordinates instead of the coordinates within the iframe.
@hdaggett It's an iframe-canvas interplay transition bug. More details can be found here: https://stackoverflow.com/questions/10514081/how-to-put-iframe-in-to-canvas
i.e. you will face performance issues; https://stackoverflow.com/questions/4020910/html5-multiple-canvas-on-a-single-page
@prateekrastogi The links you've shared are discussing the html <canvas>
. Care to elaborate how that relates to this ?
I've not yet investigated this bug in details, but it's most likely caused by the drop indicator not being placed in the <Frame />
.
<iframe/>
creates an isolated context. The iframe doesn't share scripts or stylesheets with the main document. This might actually be trickier than you might think.
If you just want to create a resizable preview, can't you just change the width of the container where craft.js renders your content? (You could even use some smart mouse-resizable container that 100% exists as a npm package already.)
And if you wanted to stick to iframes exactly for their isolation to better simulate the rendering in production. Wouldn't it be better to pass in just the serialized JSON and let an isolated rendering script handle it? I am talking about a new React instance within the iframe that would grab the JSON and construct a static page. I believe that's the usecase anyway, to have a page designed using craft.js, store the JSON in database and then use that JSON in different, totally unrelated place just to render the content.
PS: Anyway thanks for the brain exercise. I was actually looking for a solution to render a Real preview without the additional markup and html attributes craft.js might introduce for those various Canvas, Frame and other control/overhead components. And the actual solution (for my usecase) might just be the craft.js -> JSON -> render.
@ackvf resizing the container doesn't show responsive behavior (i.e. any css @media
query selectors won't be applied because it uses the window size, not the container size)
I got around the "share scripts or stylesheets" problem with this hack inside the StyledFrame
:
<div dangerouslySetInnerHTML={{__html: document.head.innerHTML}}></div>
It actually appears that Craft is working inside StyledFrame
, but the indicators just aren't appearing in the right place. I can still drag and drop and move things around, but the indicator coordinates are off. I had this working with SlateJS so I feel it should be possible to also work with Craft.
@ackvf Craft.js does not introduce additional markup/attributes (only the draggable
attribute is added to the elements with the drag
connector). You can still pass the json
prop to preview the result and also set the enabled
prop to false
in the <Editor />
and that will disable all editing features, and remove the draggable
attribute as well.
Hi, not sure if this could help, but I'm working to make it support iframes
https://github.com/prevwong/craft.js/pull/125
hi @nicoladefranceschi could you post an example on how to use craft.js with an iframe? Thank you!
For those who want to render craft.js contents into an iframe, here are my thoughts and learnings:
When you use native html
Ideally you should be using react-frame-component as advised by the Author, because what this library does is, it waits until your iframe is loaded and then renders your children inside a React portal . This React portal allows the contents rendered inside your iframe content to be part of your parent's React-tree.
Even if the iframe contents are part of React context, your external resources cannot be. So if your parent has an external .css file it would not work inside the react-frame-component's iframe but you may have to inject it seperately on the head of the iframe.
Here is an extended example of the Author's old example where you can see the contents rendered inside an iframe using react-frame-component but not styles isolated.
https://codesandbox.io/p/devbox/9tsc5r