-
Notifications
You must be signed in to change notification settings - Fork 9
Design Layout Rules
The headless layer is layout-agnostic — every factory hands a styled
Div back to the caller, and the caller decides the surrounding
flex / grid / positioning. These are the rules the demos converge on
to keep things predictable.
ListItem (in yororen-ui-core/src/headless/list_item.rs) is a row
content container. Its default behaviour:
- Do not stretch children horizontally.
- Only opt into flexible growth when the caller explicitly wants it.
This prevents inputs / buttons / selects from unexpectedly expanding
to full width when placed in a row container. If a row needs to fill
its container, the caller opts in with .w_full() on the row itself.
use gpui::div;
use yororen_ui::headless::button::button;
use yororen_ui::headless::list_item::list_item;
use yororen_ui::headless::text_input::text_input;
let row = list_item("row-1", "Alice", cx)
.content(
div()
.flex()
.items_center()
.gap_2()
.child(text_input("name").placeholder("Name"))
.child(button("save", cx).caption("Save")),
);When stacking buttons in a toolbar, use a flex_row with an explicit
gap. The default gap is 0, so buttons will butt against each other
unless you say otherwise.
use gpui::{div, px};
let toolbar = div()
.flex()
.flex_row()
.gap(px(8.))
.child(button("new", cx).caption("New"))
.child(button("open", cx).caption("Open"))
.child(button("save", cx).caption("Save"));A modal must be rendered at the scroll-root level — sibling to
your main content, not inside it — and wrapped in
gpui::deferred(...).with_priority(2) so it paints above the page
content but below the toast host. The gallery_demo shows the
exact placement.
use gpui::deferred;
let content = div()
.child(/* your main app content */);
let modal_host = modal("settings", app.modal_state.clone())
.child(/* ... */)
.render(cx);
// (your app's custom notification host, see
// gallery_demo/src/notifications_host.rs::deferred_host for the
// canonical v0.3 pattern; the `notification_host()` factory in
// yororen-ui-default-renderer is dead code and not a public API)
let toast_host = /* your deferred host, priority 3 */;
deferred(content.with_priority(0))
.with_priority(0)
// deferred priority wraps in the same way — see gallery_demoThe notification host goes on top of modals via
gpui::deferred(...).with_priority(3). The priority ladder is:
| Layer | Priority |
|---|---|
| App content | 0 |
| Modal scrim + body | 2 |
| Toast / notification host | 3 |
If your custom layout uses .left_* / .right_* directly instead
of the start / end helpers, it will render wrong in RTL locales. Use
the rtl module — see
Design-Internationalization.
headless::*::render(cx) returns a Stateful<Div> that does not
impose a default width. The caller's parent decides. Common patterns:
use gpui::div;
let full_width = div().w_full().child(button("save", cx).caption("Save"));
let auto_width = div().child(button("save", cx).caption("Save")); // shrink-to-fit
let fixed = div().w(px(120.)).child(button("save", cx).caption("Save"));- Design-Three-Layer-Architecture — layout is the caller's job.
-
Design-Virtualization — sizing of
virtual lists (
ListSizingBehavior). - Design-Internationalization — RTL-aware flex.
Yororen UI v0.3.0 · repository · Apache-2.0 · This wiki documents Yororen UI v0.3.0.
This wiki documents Yororen UI v0.3.0 — the headless-core, swappable-renderer build.