ResolvedStyle Struct
Public Members
| std::string | fill |
| bool | fillIsGradient { false } |
| std::string | borderFill |
| bool | borderIsGradient { false } |
| double | borderThickness { 0 } |
| double | radiusTL { 0 } |
| double | radiusTR { 0 } |
| double | radiusBL { 0 } |
| double | radiusBR { 0 } |
| std::string | textColor |
| double | marginL { 0 } |
| double | marginT { 0 } |
| double | marginR { 0 } |
| double | marginB { 0 } |
| double | paddingL { 0 } |
| double | paddingT { 0 } |
| double | paddingR { 0 } |
| double | paddingB { 0 } |
| std::string | fontFamily |
| double | fontSize { 0 } |
| double | fontWeight { 0 } |
| std::string | direction |
| std::string | crossAlign |
| std::string | justify |
| std::string | scroll |
| double | spacing { 0 } |
| double | grow { 0 } |
| double | shrink { -1 } |
| double | width { 0 } |
| double | height { 0 } |
| double | maxWidth { 0 } |
| double | aspectRatio { 0 } |
| double | opacity { 1.0 } |
| bool | visible { true } |
| bool | collapsed { false } |
| double | translateX { 0 } |
| double | translateY { 0 } |
| double | rotation { 0 } |
| std::string | intent |
| std::string | overlay |
| bool | secret = false |
| bool | multiline = false |
| bool | readOnly = false |
| bool | wrap = true |
| std::string | fit |
| bool | autoplay = false |
| bool | loop = false |
| bool | muted = false |
| bool | controls = false |
| std::string | text |
| std::string | placeholder |
| std::string | iconSource |
| std::string | mediaSource |
| std::string | qrData |
| std::string | href |
| std::string | tag |
| std::string | anchor |
| std::string | bind |
| double | heightVp = 0 |
| std::string | codeBg |
Detailed Description
Fully-resolved styling for a single box/text node. Colors are hex strings ("#rrggbb" / "#aarrggbb"). Gradients are stored as comma-joined stops ("0:#3a3c42,1:#42454d") with the matching *IsGradient flag set.
Note: Content inset = borderThickness + padding.
Member Variable Documentation
std::string fill
Color or gradient that fills the widget
bool fillIsGradient { false }
True when fill is a gradient
std::string borderFill
Color or gradient that fills the widget's border
bool borderIsGradient { false }
True when borderFill is a gradient
double borderThickness { 0 }
The widget's border thickness (px)
double radiusTL { 0 }
Top-left corner radius of the widget (px)
double radiusTR { 0 }
Top-right corner radius of the widget (px)
double radiusBL { 0 }
Bottom-left corner radius of the widget (px)
double radiusBR { 0 }
Bottom-right corner radius of the widget (px)
std::string textColor
Color of text and icons
double marginL { 0 }
Left space outside the widget (handled by parent layout)
double marginT { 0 }
Top space outside the widget (handled by parent layout)
double marginR { 0 }
Right space outside the widget (handled by parent layout)
double marginB { 0 }
Bottom space outside the widget (handled by parent layout)
double paddingL { 0 }
Left space between the widget's border and its content
double paddingT { 0 }
Top space between the widget's border and its content
double paddingR { 0 }
Right space between the widget's border and its content
double paddingB { 0 }
Bottom space between the widget's border and its content
std::string fontFamily
Font family name for text. The generic "monospace" maps to the platform's default. "" is the reconciler default.
double fontSize { 0 }
Pixel size for text; 0 is reconciler default
double fontWeight { 0 }
Numeric text weight (100-900); 0 is reconciler default
std::string direction
Direction that children are laid out.
| Option | Default | Orients children... |
|---|---|---|
| "Column" | ☑ | vertically |
| "Column-Reverse" | vertically in reversed order | |
| "Row" | horizontally | |
| "Row-Reverse" | horizontally in reversed order |
std::string crossAlign
Cross-axis alignment of children. If direction == "Row", then this
controls the vertical alignment, whereas direction == "Column" means
this controls the horizontal alignment.
The associated margins of the children are factored into each result.
For example, if direction == "Row" and this == "Start", the children
are aligned to the top-side offset by their individual marginT distances.
| Option | Default | Aligns children... |
|---|---|---|
| "Start" | along the top ("Row") or left ("Column") edge | |
| "Center" | ☑ | centered between the top & bottom ("Row") or left & right ("Column") edges |
| "End" | along the bottom ("Row") or right ("Column") edge | |
| "Stretch" | filling the available height ("Row") or width ("Column") |
std::string justify
Main-axis placement of the child block, when there's leftover space.
Unlike the cross-axis where children are aligned within their own lanes,
on the main-axis, children sit one after another, and justify shifts
the whole group. If direction == "Row" and there is free space available:
Start: [A][B][C]·········
Center: ····[A][B][C]·····
End: ·········[A][B][C]
If any of the children in the block are set to grow, the justify field is irrelevant because a growing child leaves no free space.
Start: [A][B][C·········] // Since `C` grows, justify is irrelevant
Center: [A][B][C·········]
End: [A][B][C·········]
| Option | Default | Shifts child block... |
|---|---|---|
| "Start" | to the left ("Row") or top ("Column") edge | |
| "Center" | ☑ | centered between the left & right ("Row") or top & bottom ("Column") edges |
| "End" | to the right ("Row") or bottom ("Column") edge |
std::string scroll
Enabled scrolling directions.
| Option | Default | Scrolling is... |
|---|---|---|
| "" (empty) | ☑ | disabled |
| "Vertical" | enabled for vertically overflowing content | |
| "Horizontal" | enabled for horizontally overflowing content | |
| "Both" | enabled for both vertically & horizontally overflowing content |
double spacing { 0 }
Gap between children (px)
double grow { 0 }
Growth factor of this child along the parent's main-axis. When applied,
the parent's leftover space is split between this child and any other
growing siblings. No factor (the default value of 0) means the node
keeps its content size.
The leftover space consumed by this child is calculated using a ratio of its factor divided by the factor total of all the parent's growing children:
ratio = factor / total
consume = ratio * leftover
Two Grow: 1 children divide the space evenly (both get 1/2). If
they are Grow: 1 and Grow: 2, then the space is divided into thirds
(1/3 and 2/3). A single growing child takes all of the leftover
space regardless of its growth factor (a lone Grow: 3 produces 3/3).
[A......][B......] // `A/Grow: 1` & `B/Grow: 1`
[A....][B........] // `A/Grow: 1` & `B/Grow: 2`
[A...............] // `A/Grow: 3`
If any of the children are set to grow, justify is
irrelevant because a growing child leaves no free space, unless the
growing children have their sizes capped.
double shrink { -1 }
Static-web only: Prevents shrinking below the content size when set
to a value of 0.
double width { 0 }
double height { 0 }
double maxWidth { 0 }
Fills the width up to the set value (px), or up to the available space if it's narrower.
A value of 0 means no constraint is applied. If a fixed
width is set, then this field is ignored.
double aspectRatio { 0 }
Image/Video nodes only Ratio of horizontal-to-vertical pixels used to derive a height value by dividing the width by the ratio.
If an aspect ratio is set, then height is ignored. A value
of 0 means no ratio is applied.
ratio = horizontal pixels / vertical pixels
height = width / ratio
// For example: a width of `1920` & a desired 16:9 aspect ratio
ratio = 16 / 9 // 1.7778; This is what you set `aspectRatio` to
height = 1920 / ratio // 1080
The aspect ratio frames the rendering of an Image/Video node, whereas
fit controls how the actual image/video fits within that frame.
double opacity { 1.0 }
Render-time opacity; value in the range [0,1]
bool visible { true }
When false, the node is dropped from the render tree
bool collapsed { false }
When true, the reconciler animates the node's height to 0, and then
back to the natural content height when false (un-collapsed).
Unlike visible which removes the node from the tree, a
collapsed node stays in the tree to permit the collapsing/expanding
animation.
double translateX { 0 }
Sliding overlays only: Render-time horizontal offset
expressed as a fraction of the node's width (a value of 0 keeps the
node in place, while a value of 1 fully shifts it by its own width).
double translateY { 0 }
Sliding overlays only: Render-time vertical offset
expressed as a fraction of the node's height (a value of 0 keeps the
node in place, while a value of 1 fully shifts it by its own height).
double rotation { 0 }
Icon nodes only: Render-time clockwise rotation in degrees.
std::string intent
Optional semantic action for binding a platform behavior, like
"window:close" on an exit button or "window:drag" on a titlebar box.
Platforms ignore intents that they don't handle.
std::string overlay
Overlay mode. "" == this node lays out normally in its parent's flow.
"Modal" == the reconciler lifts this node out of the flow and presents it
as a dialog centered over a darkening backdrop covering the rest of the UI
(desktop = a movable, modal frameless window; web/Android = a fixed,
centered element). The node is shown/hidden via the normal visibility
overlay (bind_visible), so opening/closing the dialog rides the diff as a
single Insert / Remove.
"PinnedBottom" == the reconciler floats this node over the content, anchored
to the bottom edge (rather than occupying a slot in the flow), so it can
slide off-screen via translateY without reflowing content. Used by the
titlebar in @Narrow (where the bar sits at the bottom) to drive hide-away-
on-scroll. Empty for most nodes.
"BottomSheet" == like PinnedBottom (floated at the anchor's bottom edge,
centered up to Size.Max Width), but reserves NO bottom space: the node
OVERLAYS the content instead of pushing it. Used by the dashboard drawers,
which peek as just a header (their body carries a Visible "@Expanded"
variant) and grow upward over the list when expanded; the list reserves the
collapsed peek with its own bottom padding.
"SideSheet" == a modal detail panel floated at the anchor's RIGHT edge, full
anchor height, right-aligned and capped at Size.Max Width (0 == fill, i.e.
edge-to-edge in @Narrow). The reconciler draws a darkening scrim over the
rest of the anchor (click-to-dismiss; dispatches a "click" to THIS node's
path) and slides the panel in/out horizontally via translateX (rest at 1
off-screen; an @Open variant pulls it to 0), the scrim's opacity tracking
the slide. Stays in the tree across open/close (state-driven, like the
titlebar's translateY hide-away) so the slide animates both ways. Used by
the profile post-detail.
bool secret = false
Editor nodes: mask the typed value (password field) when true. Defaults false (a normal visible field).
bool multiline = false
Editor nodes: a multi-line text box (wrapping, top-aligned) instead of the single-line field. The floating placeholder is a single-line affordance, so multi-line fields show a STATIC placeholder that fills the box while empty. Height comes from the style's Size.Height (no auto-grow). Defaults false.
bool readOnly = false
Editor nodes: a display surface the user can select/copy from but not type into (Docuriser's streamed build log). The value still moves via app rebinds (bind_text); a read-only multi-line editor additionally pins its scroll to the bottom on each rebind — log semantics. Defaults false.
bool wrap = true
Text nodes wrap long lines to the available width by default (like web +
Android); "Wrap": 0 keeps them single-line. Editor nodes (multi-line):
wrap long lines to the box width (the default).
"Wrap": 0 disables wrapping and scrolls horizontally instead — the
log/code look (long paths stay on one line). Single-line fields ignore it.
std::string fit
Image / Video nodes: how the media fills its box when its aspect ratio differs from the box's — "Cover" (fill + crop) or "Contain" (fit whole, letterbox). Maps to CSS object-fit. Empty == the reconciler's default (Cover). Ignored by non-media nodes.
bool autoplay = false
Video nodes only: playback flags. autoplay starts on load (browsers require muted to honor it), loop restarts at the end, muted starts silent, controls shows the native scrubber/volume UI. All default false. Ignored elsewhere.
std::string text
Text nodes: static, design-owned literal copy authored directly in the style (mirrors iconSource for icons). The base value for node.text; a runtime bind_text() value or a dynamic "Bind" override takes precedence. Empty when the style supplies no literal (text then comes from code/bind). NOTE: literal copy here is not localizable — when i18n lands this should become a string-table key (e.g. "@app.title") resolved against app data.
std::string placeholder
Editor nodes: the floating placeholder copy — shown filling the field while
it is empty and unfocused, animating up + smaller to a label once the user
focuses or types (the legacy desktop line-editor behavior, now portable to
every reconciler). The editor's INITIAL/default value rides the normal
text field (the style's literal Text, overridable via bind_text); the
user's typed value is owned by the reconciler and read back via
VApp::editor_text(). Empty for non-editor nodes.
std::string iconSource
Icon nodes: the .svg asset name (no extension) the reconciler loads and recolors (to textColor). Empty for non-icon nodes.
std::string mediaSource
Image / Video nodes: the media file path or URL the reconciler loads and displays (a photo, an mp4, an SVG logo). Raster/video render verbatim; an SVG Image renders as a live vector and — unlike a photo, but like an icon — recolors to textColor when the style sets Text Color (else full color is preserved). Resolves the same "Source" attribute icons use; the reconciler reads whichever of iconSource/mediaSource matches the node type. Empty otherwise.
std::string qrData
QR nodes: the payload string encoded into the QR matrix (a node URL, a key blob, …). Resolves the "Data" attribute (a separate attribute from Source, so a QR and an icon/image can't be confused). The matrix is derived from this on demand — by the core when serializing for web/Android, by the desktop reconciler directly — so only the payload rides the resolved style. Empty for non-QR nodes (an empty payload paints just the box fill).
std::string href
Link nodes: the target URL (the "Href" attribute; overridable at runtime
via bind_href and per-row via a "Href:
std::string tag
Document tag hint (the "Tag" attribute): the semantic HTML element the static-web emitter uses instead of div/span — "h1".."h6", "nav", "main", "header", "footer", "section", "article", "ul", "li", … Authored per style for crawlable, reader-mode-friendly generated pages. Runtime reconcilers ignore it. Empty = the emitter's default element.
std::string anchor
Fragment anchor (the "Anchor" attribute): the emitted element's id, the target of "#anchor" deep links in generated documentation. Runtime reconcilers ignore it. Empty = no id.
std::string bind
Data binding handled in the core during tree-build (consumed there, never
sent to reconcilers): "ThemeList" makes a container generate one button
per loaded theme (from its first child as a template); "ActiveThemeName" /
"ActiveThemePublisher" set a text node to the active theme's
name/publisher; "ThemeName" / "ThemePublisher" do the same for the theme of
the enclosing generated theme button (its primary label + publisher
subtext), so each button reads its own theme rather than the active one.
Row-data forms (inside a "List:
double heightVp = 0
Height as a FRACTION of the VIEWPORT height ("Size.Height Viewport",
0 == unset) — the viewport cousin of translateY's self-fraction. Folded
into height at build time against the platform-reported viewport
(VApp::set_viewport_height), so reconcilers only ever see the concrete
px value; an authored Size.Height doubles as the fallback when no
viewport height has been reported. A fraction (not a px length), so the
mobile metric scale leaves it alone. Sizes the scan drawer's camera to
the legacy "70% of the screen" drawer proportions.
std::string codeBg
Markdown nodes only: the resolved Theme/Secondary hex used as the surface color behind inline + fenced code (so code reads as a tinted pill/block over the body). Resolved in core from the active theme — not an author-facing attribute — so all three reconcilers theme code identically. Empty for every non-Markdown node.