slint-ui / slint

Slint is a declarative GUI toolkit to build native user interfaces for Rust, C++, or JavaScript apps.
https://slint.dev
Other
17.67k stars 611 forks source link

Support for teleportation of elements #6730

Open Enyium opened 2 weeks ago

Enyium commented 2 weeks ago

Vue.js has <Teleport>:

<Teleport> is a built-in component that allows us to "teleport" a part of a component's template into a DOM node that exists outside the DOM hierarchy of that component.

...

Sometimes we may run into the following scenario: a part of a component's template belongs to it logically, but from a visual standpoint, it should be displayed somewhere else in the DOM

The following SlintPad example demonstrates how such functionality would be useful to prevent undesired overlaps of spacial component extensions (sometimes also seen in the form of a glow effect to indicate focus):

component HoverHighlightText {
    in property <string> text;
    //in property <component-ref> teleport-highlight-to: parent;

    Rectangle {
        // Every element gets this new property, which only
        // affects the z-order and possible clipping.
        // Teleported elements should probably be placed on top of
        // regular elements inside their container.
        // It could also be named `teleportation-target`, which
        // would be quite verbose, though.
        //teleport-to: root.teleport-highlight-to;

        property <length> extension: 6px;
        x: t.x - self.extension;
        y: t.y - self.extension;
        width: t.width + 2 * self.extension;
        height: t.height + 2 * self.extension;
        border-radius: self.extension / 1.6;

        background: ta.has-hover ? lightgray : transparent;
    }

    ta := TouchArea {
        t := Text {
            text: root.text;
        }
    }
}

export component Demo {
    width: 200px;
    height: 200px;

    VerticalLayout {
        alignment: start;

        HoverHighlightText {
            text: "Foo";
            //teleport-highlight-to: root;
        }

        HoverHighlightText {
            text: "Bar";
            //teleport-highlight-to: root;
        }

        HoverHighlightText {
            text: "Baz";
            //teleport-highlight-to: root;
        }

        HoverHighlightText {
            text: "Qux";
            //teleport-highlight-to: root;
        }
    }
}

This video demonstrates the problem. Pay attention to the highlight overlapping some text, although these highlights should always be in the background surface:

https://github.com/user-attachments/assets/da343caf-46a9-4b28-bec5-130a7c2f8e05

Of course, you can flatten your component hierarchy to work around this. But good encapsulation and separation of concerns should be possible.


I had to use the non-existent type component-ref. Related issues regarding this: #5082, #2390.