limn
    ↑↓ ChooseEnter OpenEsc Close
    GitHub

    Components/Layout

    PeekPanelNew

    What is left of a side panel the user has closed: a strip at the window's edge through which the panel's content can barely be seen, that reaches out under the pointer and opens the panel when it is clicked.

    Native componentGuide source

    Preview

    CodeSource
    fn view(state: &State, palette: ComponentPalette) -> Element {
        let side = if state.queue_open {
            queue(state, palette).size(Some(state.queue_width), None)
        } else {
            PeekPanel::new("queue-peek", queue(state, palette), palette)
                .content_width(state.queue_width)
                .accessibility_label("Show the queue")
                .render()
        };
        Element::row(vec![main_view(state, palette).flex(1.0), side]).gap(8.0)
    }
    
    fn update(state: &mut State, action: &UiAction) {
        if matches!(action, UiAction::Clicked { id } if id == "queue-peek") {
            state.queue_open = true;
        }
    }

    Examples

    Each one is the library drawing it. Press, type and hover.

    Peek at the left edge
    CodeSource
    window(cx, vec![
        PeekPanel::new("side-peek-left", queue(cx, "side-queue-left", Vec::new()), cx.palette)
            .side(Side::Left)
            .content_width(280.0)
            .accessibility_label("Show the library")
            .render(),
        main_area(cx, "Main view"),
    ])

    PeekPanel

    What is left of a side panel the user has closed: a strip at the window’s edge through which the panel’s content can barely be seen, that reaches out under the pointer and opens the panel when it is clicked.

    Import

    use limn::{Component, PeekPanel, Side};

    Usage

    Render the strip where the panel was while it is closed, with the panel’s content. The host owns the window’s layout and whether the panel is open: a click on the strip reports its ID, and the host opens the panel.

    fn view(state: &State, palette: ComponentPalette) -> Element {
        let side = if state.queue_open {
            queue(state, palette).size(Some(state.queue_width), None)
        } else {
            PeekPanel::new("queue-peek", queue(state, palette), palette)
                .content_width(state.queue_width)
                .accessibility_label("Show the queue")
                .render()
        };
        Element::row(vec![main_view(state, palette).flex(1.0), side]).gap(8.0)
    }
    
    fn update(state: &mut State, action: &UiAction) {
        if matches!(action, UiAction::Clicked { id } if id == "queue-peek") {
            state.queue_open = true;
        }
    }

    The strip

    It is 40 px wide unless width(px) says otherwise, on the palette’s surface. The corners that face the window are rounded to the panel radius and the others are square, so it runs to the window’s edge.

    The content is laid out at content_width(px), the open panel’s width (320 unless set), from the strip’s left edge and clipped to the strip, so what shows is how the panel begins. A veil of the surface at 0.9 opacity covers it. The content is only painted there: its controls take no pointer, no focus and no reader until the panel is open.

    Side

    side(Side::Right) is the default. side(Side::Left) puts the rounded corners on the right and reaches out to the right.

    Under the pointer

    While the pointer is over the strip, or it has keyboard focus, it reaches 12 px further into the window on a spring that overshoots a little, the veil lifts to 0.8 and a small chevron, muted at rest, turns to full ink. The pointer over the part it reached keeps it out. Leaving reverses it.

    The strip takes the room it reaches into, as a music app’s does: what is beside it in a row gives way, a flexible main area narrowing by the 12 px and keeping its gap from the strip, instead of being covered. Put it in a row beside the main area, on either side:

    Element::row(vec![main_view.flex(1.0), peek.render()]).gap(8.0)

    Keyboard

    KeyEffect
    TabFocuses the strip, which reaches out as under the pointer.
    Enter, SpaceReport the strip’s ID.

    Motion

    The reach is the tree’s: an Element::push_on_hover spring with a damping ratio of 0.6, which overshoots by about a tenth and settles within three move_ms. The veil and the chevron fade over enter_ms and exit_ms. With reduced motion the strip reaches out and back at once.

    Actions

    ActionWhen
    UiAction::Clicked { id } with the strip’s IDThe strip is clicked, or Enter or Space is pressed on it.

    Accessibility

    The strip is a button with no text: name it with accessibility_label, such as “Show the queue”.

    API reference

    The guide covers composition, options and actions. Generate the complete Rust type and builder reference from the checkout:

    cargo doc -p limn --open

    Component API overview · State and actions

    The example is drawn by crates/limn-gallery/src/pages/side_panels.rs.