slint-ui-templates 0.1.0

Composable Slint UI building blocks — mother-child pattern, token-driven
Documentation
import { Colors, Spacing, Type, FluentIcons } from "../tokens/theme.slint";
import { Sizes } from "../tokens/sizes.slint";

// TreeViewNode — a single tree node row with expand toggle, icon, and label.
/// T re ev ie wn od e component.
export component TreeViewNode inherits Rectangle {
    /// Input property "node-id".
    in property <string> node-id;
    /// Input property "label".
    in property <string> label;
    /// Input property "icon".
    in property <string> icon;
    /// Input property "level".
    in property <int>    level;
    /// Input property "expanded".
    in property <bool>   expanded;
    /// Input property "leaf".
    in property <bool>   leaf;
    /// Input property "is-selected".
    in property <bool>   is-selected: false;
    /// Callback fired for s el ec te d.
    callback selected();
    /// Callback fired for t og gl e e xp an de d.
    callback toggle-expanded();

    height: Spacing.xl;
    background: root.is-selected ? Colors.accent :
                node-ta.has-hover ? Colors.bg-elevated : transparent;

    HorizontalLayout {
        padding-left: root.level * Spacing.lg;
        spacing: Spacing.xs;
        alignment: start;

        // Expand/collapse toggle
        if !root.leaf: Rectangle {
            width: Spacing.md;
            height: Spacing.md;
            background: transparent;

            Text {
                text: root.expanded ? "\u{25BC}" : "\u{25B6}";
                font-size: Type.caption-size;
                color: root.is-selected
                    ? Colors.accent-text : Colors.text-secondary;
                horizontal-alignment: center;
                vertical-alignment: center;
            }

            expand-ta := TouchArea {
                clicked => { root.toggle-expanded(); }
            }
        }

        // Spacer for leaf nodes (alignment)
        if root.leaf: Rectangle {
            width: Spacing.md;
            background: transparent;
        }

        // Icon
        if root.icon != "": Text {
            text: root.icon;
            font-family: FluentIcons.icon-font;
            font-size: Type.body-size;
            color: root.is-selected
                ? Colors.accent-text : Colors.text-secondary;
            vertical-alignment: center;
        }

        // Label
        Text {
            text: root.label;
            font-size: Type.body-size;
            color: root.is-selected
                ? Colors.accent-text : Colors.text-primary;
            vertical-alignment: center;
            horizontal-stretch: Sizes.one;
        }
    }

    node-ta := TouchArea {
        clicked => { root.selected(); }
    }
}