Skip to main content

Module spec

Module spec 

Source
Expand description

NodeSpec and TextStyle: everything a node and a text declare, as plain data with a builder.

A NodeSpec is the contract every frontend lowers into, whether a Rust builder chain, a Lua table or a JSX element. It groups the layout (LayoutSpec: sizing, direction, padding, gap, alignment, overflow), the look (VisualStyle: background, border, radius, shadow, opacity) and, boxed because most nodes declare none of it, the events, animation, accessibility and interaction styling. Every builder method sets one of those fields; the field docs below say what each means.

use kui_core::{Align, Color, NodeSpec, Sizing, TextStyle, TextWrap};

// A card: grows across its parent, fits its content down, 12 px padding
// and gap, rounded, with a hover background and a click payload.
let card = NodeSpec::column()
    .width(Sizing::GROW)
    .pad(12.0)
    .gap(8.0)
    .bg(Color::hex(0x1e2230ff))
    .hover_bg(Color::hex(0x262b3aff))
    .radius(8.0)
    .on_click("open-card");

// A toolbar row: fixed height, children centred across it.
let toolbar = NodeSpec::row().size(Sizing::GROW, 36.0).cross_align(Align::Center);

// A one-line title, cut with an ellipsis when it does not fit.
let title = TextStyle::new(16.0).ellipsis().color(Color::WHITE);
let code = TextStyle::new(13.0).mono().wrap(TextWrap::Glyph);

assert_eq!(card.layout.padding.l, 12.0);
assert!(card.events().on_click.is_some());
assert_eq!(toolbar.layout.height, Sizing::Fixed(36.0));
assert_eq!(title.max_lines, 0); // `ellipsis` alone means one line
assert!(title.ellipsis && code.wrap == TextWrap::Glyph);

Modules§

corner
Corner indices into VisualStyle::radius / Quad::radius.

Structs§

AccessSpec
Accessibility properties a view states outright, as opposed to the ones the core derives (see crate::access). Boxed on NodeSpec: read only while an access tree is being built, and unset on nearly every node.
AnimSpec
Per-node animation declarations. Boxed on NodeSpec: enter and exit are 60 bytes each and almost every node has neither.
EventSpec
Event payloads a node declares. Boxed on NodeSpec because most nodes declare none.
FloatConfig
Takes a node out of flex flow: it does not consume space in its parent, sizes Grow/Percent against its anchor, is positioned by attach points, and escapes ancestor clips unless FloatConfig::clip keeps it in its parent’s. It paints as a layer of its own, above the in-flow tree and every float that opened before it and under every one that opened after, and takes input in the same order.
FontFeatures
The OpenType features a style asks the shaper for: up to FontFeatures::MAX four-letter tags with a value each. liga 0 keeps a coding font from joining ->, tnum 1 gives tabular figures, ss01 1 turns on a stylistic set. Plain data and Copy, since a TextStyle is; the spelling every binding shares is FontFeatures::parse’s.
InteractSpec
Hover / pressed / focus styling and the sounds that go with them. Boxed on NodeSpec so the common node — which declares none of it — costs one null check in resolve_hover_style instead of reading several Options spread across the struct.
LayoutSpec
The layout half of a NodeSpec: sizing, clamps, direction, padding, gap, alignment, overflow and floating. Set through the NodeSpec builders; read by the solver.
Min
A lower clamp on one axis: a number of logical px, or the node’s own fit size on that axis (Min::FIT, minWidth: "fit" in the bindings). FIT is what lets a Grow child keep a content floor, like CSS’s flex: 1 0 auto: tabs split a bar evenly while they fit and sit at their label’s width, scrolling, once they do not. Layout resolves it to a number in the fit pass of its axis, so every later clamp reads one; until then it clamps like no floor at all.
NodeSpec
Everything one node declares. This, not any Rust trait, is the contract every frontend (Rust builders, Lua, JSX, C) lowers into. Start from NodeSpec::row, NodeSpec::column or NodeSpec::table and chain builders; see the module docs for an example.
PadShorthand
The pad shorthand family as declared — any subset of the seven names, each None when the frontend did not see it. PadShorthand::resolve decides what a missing edge falls back to; a binding only reports what it found.
Scrollbar
A scrolling node’s bars, per node. Every field’s default is the stock bar — the theme’s scrollbar / scrollbar_active colours, 4 px at rest and 6 px under the pointer, always drawn while the content overflows — so a binding that sets none of the four rows gets exactly what it always had. The bars are overlays and take no layout space whatever their width; the grabbable track is at least as wide as the active thumb plus its inset.
Shadow
One outer drop shadow: the node’s rounded rect, moved by dx/dy, grown by spread and its edge blurred over blur, painted in color behind the node. CSS’s box-shadow without the inset and multi-shadow forms.
TextStyle
How a run of text is shaped and painted: size, line height, colour, family, wrapping, line limits, OpenType features and decorations.
Vec2Offset
Plain offset pair (kept separate from geometry to stay Copy + FFI-flat).
VisualStyle
The paint half of a NodeSpec: background, border, corner radii, opacity, shadow and pixel snapping.

Enums§

Align
Where children sit along an axis, and where a float attaches.
Bound
What a min_width / max_width / min_height / max_height declares: px, the node’s own fit size (a min only), or a size expression that layout resolves against the parent’s content box when it sizes the node. Until then a calc bound clamps like none, as a percentage clamp does in CSS’s intrinsic sizing.
Dir
Which way a container stacks its children.
FloatAnchor
What a floating node is positioned against.
FontFamily
Which face a text shapes with: one of the three stock families, or a font registered with the core.
Live
How urgently a reader should read a change it was not asked to read: ARIA’s aria-live, AccessKit’s Live. Declared on the node holding the text (live prop) and, for a one-off with no node behind it, the politeness of an Announcement.
Overscroll
What a scroll gesture that starts over a scroller already at its limit does: CSS’s overscroll-behavior, spelled by the overscroll row.
Role
What a node is to assistive technology. Most of these a view declares (role prop; schema::ROLES is that list, and the wire order); the ones the core derives from a node’s content and behaviour instead are schema::DERIVED_ONLY, which says what derives each. Every variant is on one list or the other — schema’s every_role_is_declarable_or_derived fails when a new one is on neither.
ScrollAxes
Which axes an on_scroll node takes, spelled by the scrollAxes row.
ScrollbarMode
When a scrolling node’s bars are drawn. Spelled by the scrollbar row (crate::schema::SCROLLBARS, in this order).
Sizing
How a node sizes one axis. A plain number converts to Fixed, so .width(120.0) and .width(Sizing::Fixed(120.0)) are the same.
TextWrap
How a text node breaks lines at its width.
UnderlineStyle
The shape of an underline: the face’s line, a wave under a diagnostic, dots. Where it goes and how thick it is are the face’s recommendation either way; a wave is three strokes tall around the line’s centre with a six-stroke period, dots two strokes across and four apart (crate::deco).

Constants§

FLOAT_PRESETS
The float preset names, in wire order: the index of a name here is what the binary protocol writes for it and what KUI_FLOAT_* counts from.
OVERFLOW_CLIP
overflow as bits: the C struct’s field, the binary wire’s payload and what the clip / scrollX / scrollY booleans OR together. One set of values so a binding cannot invent its own numbering.
OVERFLOW_SCROLL_X
OVERFLOW_SCROLL_Y

Functions§

max_calc
The size expression a max_w / max_h waits on, if it is one.
max_of_calc
A ceiling that is a size expression, as max_w / max_h hold it until layout resolves it: -1 minus its number.
px_ceiling
A px ceiling as max_w / max_h hold it: never below zero, so a negative there is only ever max_of_calc’s. A negative or NaN ceiling is a ceiling of 0. Every binding’s max clamp reaches the field through NodeSpec::max_width / NodeSpec::max_height, which call this.

Type Aliases§

Label
The label type on NodeSpec: shared, so cloning a spec is a refcount bump and a Rust view can keep one Arc<str> across frames.