ryanseddon / react-frame-component

Render your React app to an iFrame
http://ryanseddon.github.io/react-frame-component/
MIT License
1.75k stars 156 forks source link

Iframe and Quill-React, events are lost #133

Closed entiendoNull closed 5 years ago

entiendoNull commented 5 years ago

I am trying to wrap my head around an issue regarding react-frame-component and React-Quill.

I am building a small template editor that will have areas (normal divs) that my hope is to convert into editable areas using Quill.

This is what I do:

I have a simple piece of html markup that includes a div that looks like this: <div data-cms-text="true"></div>

All my markup is stored into a constant called iframeContent.

I then include my mark up into the iframe, but through ReactHtmlParser

<Iframe initialContent={page.html.initial} head={<link rel="stylesheet" href="//cdn.quilljs.com/1.2.6/quill.snow.css"/>} mountTarget="#mount">
    <FrameContextConsumer>
        {
            frameContext => {
                return (
                    <StyleSheetManager target={frameContext.document.head}>
                        <>
                            {ReactHtmlParser(iframeContent, { transform: transformer })}
                        </>
                    </StyleSheetManager>
                );
            }

        }
    </FrameContextConsumer>
</Iframe>

With ReactHtmlParser I loop through each node and I look for divs (at the moment only one) with the cms-text data attribute.

ReactHtmlParser provides us with a transformer method. I am using that to convert <div data-cms-text="true"></div> to a Quill component:

<Quill
    onChange={contentUpdated}
    placeholder="Type something... :-)"
    theme={"snow"}
    key="some-uniqiue-key" />

That works!

screen shot 2019-02-12 at 13 12 51

This is what's going wrong The Quill tool bar doesn't respond to anything I do. It's as those events are never registered within the iframe.

What am I missing here?

I have tried this in order to localize the issue 1). Tried to add React-Quill directly into the iframe, without using ReactHtmlParser (no luck there). 2). Tried React-Quill outside of an iframe, and that obviously works flawless. 3). Quill also provides provides me to declare an onChange callback. That callback is successfully triggered everytime I type something into the editor. But, does not respond to anything I do in the tool bar either.

To clarify, sending references to functions that I declare outside the iframe into the iframe can successfully be triggered. But, I assume Quill registers eventHandlers that seems to fail within the iframe - while being used outside of an iframe it does.

What else am I using? styled-components (and they seem to render fine within the iframe, and references such as <Button onClick={clickedReference}>Some button</Button> work flawless).

Any help or advice is much appriciated.

dominiczaq commented 5 years ago

Do you have a minimal repo where this can be reproduced?

entiendoNull commented 5 years ago

Sure! Added it here: https://github.com/entiendoNull/react-iframe-test

Please let me know if something is unclear. In the meantime I'll continue working on this myself too. Thanks for your effort :)

dominiczaq commented 5 years ago

Hey, I've run your code and I'm almost certain that this issue is related to https://github.com/quilljs/quill/issues/1042 or https://github.com/quilljs/quill/issues/1386. As you probably know from documentation you can access the iframe's window and document object like this - https://github.com/ryanseddon/react-frame-component#accessing-the-iframes-window-and-document. But quill's implementation uses global window and document.

I had similar problem in my project as well - different package though. https://github.com/ryanseddon/react-frame-component/issues/132#issuecomment-459721310

entiendoNull commented 5 years ago

Heey :) Really, thanks for having a look at this! Yeah, I forgot to mention, but I did play around with the iframe window and document object. But still, I had not much luck with it either in this case.

I do have a plan B... and possibly even a plan C, but I would have preferred to get this approach to work as that would've been the cleanest one. But according to the links you provided it seems there is little hope for an official "fix" to this at the moment.

I did however get inspired on your fix for that other project. Will something similar work here as well?

dominiczaq commented 5 years ago

For my usecase it was easy because targeted package (emoji-mart) used window object only in one component. I don't think that's the case with quilljs. For a fix to work quilljs would need to accept window in conifg and pass it to every usage. I believe quilljs can also be extended / modularized, and I don't know how it's designed there, but maybe the exposed api would also need to change (expose that passed window object if it's not the default one).

These are of course only my guesses which maybe could be confirmed on quills github issues :)

atirip commented 5 years ago

I think I got this sorted out. I too run editable content in clean iframe. What you need to do is:

There is few more places, like in Quill constructor, you'll find them. I work right now with webpacked distribution of quill-core.js, just searched and replaced, have no time right now to do it properly.

Also you probably need to proxy up these ['selectionchange', 'mousedown', 'mouseup', 'click'] events from iframe to top. Pay attentio to proxied up custom events targets, as quill needs them and you can't modify target property in event, so you need to hack original target in and then use it in Emitters handleDOM and addEventListener

ryanseddon commented 5 years ago

Closing this as it seems to be an issue with Quill and not this component.

marcustran98 commented 5 months ago

hi @entiendoNull i am also experiencing a similar issue. have you found a solution yet? thanks. ref: https://github.com/zenoamaro/react-quill/issues/982