import Quickshell import Quickshell.Wayland import Quickshell.Hyprland import QtQuick import qs.Components import qs.Config Item { id: root property list animCurve: Appearance.anim.curves.expressiveDefaultSpatial property int animLength: Appearance.anim.durations.expressiveDefaultSpatial readonly property alias content: content readonly property Item current: (content.item as Content)?.current ?? null property real currentCenter property alias currentName: popoutState.currentName property string detachedMode property alias hasCurrent: popoutState.hasCurrent readonly property real nonAnimHeight: content.implicitHeight || 150 readonly property real nonAnimWidth: children.find(c => c.shouldBeActive)?.implicitWidth ?? content.implicitWidth required property real offsetScale property string queuedMode required property ShellScreen screen function close(): void { hasCurrent = false; detachedMode = ""; } focus: hasCurrent implicitHeight: nonAnimHeight implicitWidth: nonAnimWidth Behavior on implicitHeight { enabled: root.offsetScale < 1 Anim { duration: root.animLength easing.bezierCurve: root.animCurve } } Behavior on implicitWidth { enabled: root.offsetScale < 1 Anim { duration: root.animLength easing.bezierCurve: root.animCurve } } PopoutState { id: popoutState } Comp { id: content anchors.centerIn: parent shouldBeActive: root.hasCurrent sourceComponent: Content { popouts: popoutState } } component Comp: Loader { id: comp property bool shouldBeActive active: false opacity: 0 // Makes the loader load on the same frame shouldBeActive becomes true, which ensures size is set states: State { name: "active" when: comp.shouldBeActive PropertyChanges { comp.active: true comp.opacity: 1 } } transitions: [ Transition { from: "" to: "active" SequentialAnimation { PropertyAction { property: "active" } Anim { property: "opacity" } } }, Transition { from: "active" to: "" SequentialAnimation { Anim { property: "opacity" } PropertyAction { property: "active" } } } ] } }