Modifier and indication API
Declared by <huxerui/modifier.h> and <huxerui/indication.h>.
Modifier model
Section titled “Modifier model”ViewModifier accepts built-in property modifiers and retained modifier values whose nested extension derives from NodeExtension. View::With applies modifiers left to right.
Descriptor and erased storage types live in huxerui::detail; custom retained behavior uses the typed modifier and NodeExtension contract instead of depending on that storage.
Built-in property modifiers
Section titled “Built-in property modifiers”Enabled{value}andFocusable{value}.Padding(float|EdgeInsets).Background{VisualFill},Foreground{Color},Border{color, width},Shadow{color, offset, blur_radius, spread}.FontSize{value}.Frame{width, height, min_width, max_width, min_height, max_height}.CornerRadius{CornerRadii}and markerClipChildren.Spacing{value},MainAlign{MainAxisAlignment},CrossAlign{CrossAxisAlignment}, andAlign{HorizontalAlignment, VerticalAlignment}.Grow{factor}.ScrollPhysics{fling_enabled, deceleration_rate, minimum_fling_velocity, maximum_fling_velocity}.ScrollBar{optional<ScrollBarStyle>}; style fields cover geometry, fade timing, track, and thumb.
NodeExtension
Section titled “NodeExtension”Retained per-node behavior. Override only needed hooks for update, mount/unmount, interaction, frame advance, paint phases, text input/selection clients, semantics, semantic actions, focus traversal, and cancel handling. InvalidatePaint() marks its node paint dirty. FrameInfo supplies time and delta; returned FrameResult controls further scheduling.
Indication
Section titled “Indication”IndicationPlacement:BehindContentorAboveContent.IndicationLayer: optional fill, border, corner radii, placement, enter spec, and exit spec.RippleEffect: color, placement, expansion, and fade-out specs.IndicationGeometry: optional layer size and clip radii.Indication: retained modifier with focus, hover, press, ripple, and geometry.FocusRing: color, width, and offset.
VisualFill comes from the paint API and supports colors, gradients, and images.
Reconciliation and paint order
Section titled “Reconciliation and paint order”Property modifiers apply from left to right to one view declaration and do not create wrapper nodes.
Retained modifiers reconcile by descriptor and declaration position; a compatible NodeExtension receives updated declarative data while preserving retained state.
Moving or conditionally inserting retained modifiers can therefore replace an extension just as changing an unkeyed child position can replace a child.
Background paints behind node content, Foreground changes the content foreground color, and indication layers choose behind- or above-content placement.
FocusRing is a style value used by themes and controls, not a standalone ViewModifier.
NodeExtension is an extension API; application components normally prefer property modifiers, typed events, Lifecycle, and built-in indication.
Extension callbacks and invalidation
Section titled “Extension callbacks and invalidation”| Callback or operation | What its owner must do |
|---|---|
Constructor / Update(ViewNode&, const Modifier&) |
Retain owned configuration; preserve compatible transient state during Update. |
OnFrame(ViewNode&, FrameInfo) |
Advance retained state; return needs_frame or an optional wake_after in seconds. |
InvalidatePaint(PaintInvalidation) |
Mark recorded output dirty when a visual input changes; scheduling alone does not do this. |
PrepareGeometry(ViewNode&, TextMeasurer&) |
Reconcile geometry-dependent inputs and return affected paint phases; borrow the measurer only during the call. |
PaintBehindContent / PaintAboveContent |
Record output in node-local coordinates without changing the tree. |
OnInteraction |
Observe current InteractionState and an optional event; do not invent a parallel pressed-state owner. |
OnPreScroll / OnPostScroll |
Consume only a finite, same-direction amount no larger than the available delta. |
OnPreFling |
Apply the corresponding consumption rule to available release velocity. |
FrameInfo::timestamp is monotonic seconds, delta_time is the Runtime-clamped interval, and reduced_motion asks visual motion to settle. FrameResult::wake_after is for sparse updates; do not request continuous frames for a static decoration.
PaintInvalidation::Content invalidates behind-content recording, Foreground above-content recording, Both both, and None neither. These are recording phases, not a request to mutate a text’s Foreground color. Compatible extension reuse follows modifier type and position; destructor cleanup releases subscriptions or owned resources when that attachment ends.
See the complete retained modifier before implementing a custom descriptor. The public automatic nested Extension pattern requires no application access to detail::ModifierDescriptor.
Build interaction visuals without another state store
Section titled “Build interaction visuals without another state store”Use a base Background/Border/CornerRadius for normal appearance. Indication’s optional focus, hover, and press layers describe state-dependent visuals; ripple adds color-based expansion feedback. Omitting a layer means no visual for that state, not an inverted-state selector. Selected or checked appearance comes from the controlled component/style, not a hidden selection flag in Indication.
Each IndicationLayer can override fill, border, and corner_radii, choose placement, and specify enter / exit AnimationSpecs. geometry.layer_size changes the visual footprint without changing measured layout; clip_corner_radii controls clipping of that footprint. RippleEffect uses a Color and separate expansion / fade_out specs, not an arbitrary image fill. Foreground remains a content Color; use a VisualFill in a surface layer for gradients or images.

