Controls
Hosanna UI controls are regular Hosanna views with a helpful opinionated API. They inherit the same lifecycle, state model, layout, and styling mechanisms as other views, then add control-specific behavior (events, keyboard handling, composition).
How Controls Work
- They extend views: Controls subclass the same
BaseViewas primitives and groups. You use them declaratively ingetViews(). - Stateful styling: Controls read styles via
styleKey, and apply the correct sub-style based onViewStatus(e.g.,normal,focused,selected). - Focus-aware: Each view has
isFocused; the focus system updates it automatically.ViewStatustracks high-level interaction state and drives styles. - Custom data: Use
customData(...)to attach arbitrary data. Retrieve it strongly typed at runtime withview.getCustomData<T>().
Most controls accept text, style keys, and event callbacks. Add features incrementally to keep performance predictable.
Styling Controls with Stateful Styles
Controls use the same theme style system as all views. A styleKey points to a style entry in your style.config.json. Control styles typically live under controls.<ControlType>.<subStyle> and contain per-status dictionaries:
{
"controls": {
"Button": {
"default": {
"normal": { "color": "~theme.colors.white" },
"focused": { "color": "~theme.colors.red" },
"selected": { "opacity": 0.9 }
},
"primary": {
"normal": { "titleFontKey": "~theme.fonts.text-bold-20" }
}
}
}
}
- styleKey: For example,
controls.Button.defaultorcontrols.Button.primary. - Stateful: Sub-keys such as
normal,focused,selected,disabled,error,focusSelectedmap toViewStatusvalues. - Auto-application: When focus changes, the framework switches the active style sub-dictionary automatically.
Use controls.<ControlType>.<subStyle> for control styles (e.g., controls.Button.default). Keep tokens (~theme.colors.*, ~theme.fonts.*) for portability.
Focus, ViewStatus, and Styles
isFocusedis updated by the focus system. You do not set it manually.ViewStatuscan be controlled when needed (e.g., programmatically select a control), and the style engine uses it to pick the right sub-style.- Typical statuses:
normal,focused,selected,disabled,error,focusSelected.
Avoid changing view state inside animation ticks. Let the animator finish, then persist the final logical state.
Custom Data on Controls
Attach context to any view/control and retrieve it later without type assertions scattered across your code:
Button({ text: 'Details', styleKey: 'controls.Button.primary' })
.customData({ productId: item.id })
.onClick((event) => {
const data = event.view.getCustomData<{ productId: string }>();
this.openDetails(data.productId);
});
Example: Button + Stateful Styles
Button({
text: 'Click me',
styleKey: 'controls.Button.default',
width: 300,
height: 50,
})
.onClick(() => this.count++)
.customData({ kind: 'primary-action' });
- On focus,
ViewStatusbecomesfocused, and the style engine applies thefocusedstyle automatically. - You can set
viewStatus(ViewStatus.Selected)when you need a selected visual state.
Controls Index
Use the pages below for focused guides and live examples:
- Button
- CheckBox
- ComboBox
- ScrollView
- Popup
- MiniKeyboard