Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wordWrap and (at least) readOnly properties don't seem to work #43

Open
mperreir opened this issue Mar 20, 2021 · 4 comments
Open

wordWrap and (at least) readOnly properties don't seem to work #43

mperreir opened this issue Mar 20, 2021 · 4 comments
Labels
bug Something isn't working

Comments

@mperreir
Copy link
Contributor

When trying this code:

<script lang="ts">
    import { onMount } from "svelte";
    import type { NSVElement, RNWindow } from "@nodegui/svelte-nodegui";
    import { Direction } from "@nodegui/nodegui";
    import fetch from "node-fetch";

    /**
     * The exact type for this is: NSVElement<RNWindow>
     * ... However, the Svelte language tools erroneously expect all bind:this values to extend HTMLElement, so
     * for now, we have to rely on reasserting the type.
     */
    let win;
    let urlWidget;
    let dataWidget;
    let jsonData="";

    async function loadPressed(){
        let dataPromise = await loadData(urlWidget.textContent);
        jsonData = JSON.stringify(dataPromise);
    }

    async function loadData(url){
        try{
            let response = await fetch(url);
            let jsonResponse = await response.json();
            return jsonResponse;
        }
        catch(error){
            console.error(error);
        }
    }

    onMount(() => {
        (window as any).win = win; // Prevent garbage collection, otherwise the window quickly disappears!
        (win as NSVElement<RNWindow>).nativeView.show();

        urlWidget.textContent = "https://reqres.in/api/products/3";

        return () => {
            delete (window as any).win;
        };
    });
</script>

<window
    bind:this={win}
    windowTitle="Seafile Share link DL">
    <view class="vertical">
        <view class="horizontal">
            <text>Share link url:</text>
            <lineEdit id="lineEdit" bind:this={urlWidget}/>
            <button text="Load" on:clicked={loadPressed}/>
        </view>
        <view>
            <text id="dataWidget" wordWrap={true} bind:this={dataWidget}>{jsonData}</text>
            <plainTextEdit readOnly={true} text={jsonData}></plainTextEdit>
        </view>
    </view>
</window>

<style>
    /* 
     * CSS has a few gotchas for now.
     * 1) Some values need to be enclosed with quotes (e.g. `width: '100%';` rather than `width: 100%;`).
     *    See: https://github.com/nodegui/svelte-nodegui/issues/4
     * 2) Classes are not supported yet; they're a bit weird in Qt5.
          See: https://github.com/nodegui/svelte-nodegui/issues/6
     * 3) You can't write element-level rules like `text { color: 'red'; }`, unless they're global (not scoped).
     *    For scoped rules, you have to refer to the underlying native element, e.g. `QLabel { color: 'red'; }`.
     *    See: https://github.com/nodegui/svelte-nodegui/issues/7
     */
    .vertical{
        flex-direction: column;
    }

    .horizontal{
        flex-direction: row;
    }

    #lineEdit{
        flex: 1;
    }
</style>

the text widget does not wrap and the plainTextEdit is not readonly.

@shirakaba
Copy link
Collaborator

shirakaba commented Mar 27, 2021

I've found the reason for the issue. Svelte is compiling the attributes from camel-case to lower-case before passing them to Svelte NodeGUI. This is something I'd thought we'd solved once and for all with the PRs to Svelte from @halfnelson and @mrsauravsahu to support foreign namespaces. The Svelte NodeGUI preprocessor (and Svelte Native preprocessor from which it is forked) implicitly inserts <svelte:options namespace="foreign" /> to indicate that our host is foreign and so should not be treated as HTML. But it appears there are still some further cases where it is mistreated.

<window windowTitle="abc"/> correctly preserves casing, i.e. it results in a correct call to widget.setProps({ windowTitle: "abc" }, {}).

However, <text wordWrap={true}>abc</text> strips casing, resulting in an incorrect call to widget.setProps({ wordwrap: true }, {}).

Incidentally, <text wordWrap>abc</text> also strips casing, resulting in an incorrect call to widget.setProps({ wordwrap: "" }, {}).

I also tried <text wordWrap="abc">abc</text>, which also strips casing, resulting in an incorrect call to widget.setProps({ wordwrap: "abc" }, {}).

So it has nothing to do with the values being booleans or strings. I guess Svelte must be special-casing certain attributes from the HTML5 spec, as wordwrap and readonly.

I can't find any mentions of wordwrap in the Svelte repo, but there are some indications that readonly may be treated as a special case in some manner:

I'm just surprised that this is biting us when we're in a foreign namespace. Does this analysis seem plausible @halfnelson, @mrsauravsahu?

Mentioned PRs:

@shirakaba
Copy link
Collaborator

A horrible workaround for now if it's blocking you:

// BetterText.svelte
<script lang="ts">
    import type { NSVElement, RNText } from "@nodegui/svelte-nodegui";

    let ref: any;
    export let wordwrap: boolean = false;
    // Find some way to map out the other attributes you need.
    // There is probably a clever Svelte way to extend all those of RNTextProps, but I don't know how!
    $: {
        if(ref){
            /** With reference to the setTextProps() method in: src/dom/react-nodegui/src/components/Text/RNText.ts */
            (ref as NSVElement<RNText>).nativeView.setWordWrap(wordwrap);
        }
    }
</script>
<text bind:this={ref}><slot></slot></text>

And use like this:

<script lang="ts">
    import BetterText from BetterText.svelte
</script>

<BetterText wordwrap={true}>abc</BetterText>

@shirakaba shirakaba added the bug Something isn't working label Mar 27, 2021
@mperreir
Copy link
Contributor Author

Far from perfect, but at least it allows to set wordWrap and readOnly on components that need it :-).

@halfnelson
Copy link

Looking at the Svelte JS output of the same code in the repl (https://svelte.dev/repl/a64f21f99f3d48de992a731a76818c32?version=3.37.0) gives us a clue

c() {
	window_1 = document.createElementNS("https://svelte.dev/docs#svelte_options", "window");
	view2 = svg_element("view");
	view0 = svg_element("view");
	text0 = svg_element("text");
//snip
        attr(text1, "wordwrap", text1_wordwrap_value = true);

The elements are being detected as and forced to SVG. There must be some code in svelte that does this which we need to skip for namespace foreign

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants