11. API Reference
SusApp — fluent bootstrap
Documented application entry point. Thin fluent builder over SusBootstrap that guarantees initialization order: panel TSS → EventSystem → token cascade → OverlayHost → world panel → fonts → custom styles → configure → mount → theme (last).
csharp
public sealed class SusApp
{
public VisualElement Root { get; }
public UIDocument Document { get; }
public SusWorldSpacePanel WorldPanel { get; } // after Run/Mount; null if UseWorldSpace(false)
// Create
public static SusApp Create(UIDocument document); // ApplyDefaultTSS + root
public static SusApp Create(VisualElement root); // advanced — no TSS
// Fluent config (all return this)
public SusApp UseTheme(SusTheme theme); // default Dark; applied last
public SusApp UseTokenCascade(bool enabled = true); // L1–L5 + OverlayHost (default on)
public SusApp UseWorldSpace(bool enabled = true); // SusWorldSpacePanel + Default (default on)
public SusApp UseCustomStyles(params string[] resourcePaths); // after cascade
public SusApp UseFonts(SusFontAsset fontAsset);
public SusApp UseIcons(params ISusIconProvider[] providers);
public SusApp UseIcons(SusIconSetAsset iconSet);
public SusApp Configure(Action<VisualElement> configure); // before theme; router/manual UI
// Finalize
public VisualElement Run(); // no root component
public T Mount<T>() where T : SusComponent, new(); // Mount + Finalize
}Finalize order (Run / Mount)
- Icons (
UseIcons→SusIconRegistry.RegisterProvider) - Token cascade (
LoadTokenCascade:_palette→_font→_theme→design-tokens→_icon→ extras + OverlayHost) - World-space panel (
EnsureWorldSpacePanel, if playing andUseWorldSpace) - Fonts (
UseFonts) - Custom styles (
UseCustomStyleson root + OverlayHost) - Configure callbacks
- Mount root component (if
Mount<T>) - Theme last (
SusThemeService.Instance.SetTheme(root, theme))
csharp
SusApp.Create(uiDocument)
.UseTheme(SusTheme.Dark)
.UseCustomStyles("SusRuntime/demo-tokens")
.UseWorldSpace(true)
.Configure(root => BuildManualUi(root))
.Mount<HomeScreen>();
// Router apps (sus-router extension):
SusApp.Create(uiDocument)
.UseTheme(SusTheme.Dark)
.UseRouter(router, r => r.Register("/", typeof(HomeScreen)), initialPath: "/")
.Run();SusComponent - base class
csharp
public abstract partial class SusComponent : VisualElement
{
// ─── Creating reactive properties ───
protected Prop<T> P<T>(T initial = default);
protected Computed<T> C<T>(Func<T> fn);
protected WatchHandle Watch<T>(Prop<T> source, Action<T, T> callback);
protected WatchHandle WatchEffect(Action fn);
// ─── Life cycle ───
protected virtual void Created(); // constructor
protected virtual void BeforeMounted(); // between Created() and Build()
protected virtual void Mounted(); // after Build() - deferred
protected virtual void Updated(); // every frame
protected virtual void BeforeUnmounted(); // BEFORE removing from the panel
protected virtual void Unmounted(); // AFTER deletion
// ─── Generation ───
protected abstract void Build(); // generated by the compiler
// ─── Provide / Inject ───
// overwrite:false (default) fires OnDuplicateProvide if the key already exists, then still writes
protected void Provide<T>(string key, T value, bool overwrite = false);
protected T Inject<T>(string key);
protected bool TryInject<T>(string key, out T value);
protected bool HasInjection(string key);
// ─── Events ───
protected void Emit<T>(string eventName, T data);
public void On(string eventName, Delegate handler);
public void Off(string eventName, Delegate handler);
// ─── Slots ───
protected void RegisterSlotContent(string name, VisualElement content,
Func<Dictionary<string, object>, VisualElement> builder); // called from the generated Build()
protected void BuildSlot(string name, Func<VisualElement, VisualElement> wrapper,
VisualElement container);
protected VisualElement GetSlotContainer(string name);
public VisualElement Slot(string name); // runtime access after Build()
}Life cycle (order)
Constructor:
Created() → BeforeMounted() → Build() → LoadCompanionStyleSheets()
Deferred(schedule.Execute, next frame):
Mounted()
OnAttachToPanel:
ScheduleReactiveUpdates() → Updated() ~60 FPS
OnDetachFromPanel:
BeforeUnmounted() → _updateItem.Pause() → DisposeAllBindings() → Unmounted()
Updated()runs only when attached to the panel (OnAttachToPanelHandler). From constructor/deferred callScheduleReactiveUpdatesremoved — before attachmentschedulemay not tick.
Bind helpers (reactive)
All bindings work through ReactiveEffect — auto-subscription to Prop<T> / Computed<T>and updating when any source changes. Each helper returns a WatchHandle (tracked for dispose on detach).
csharp
// v-if: add/remove from DOM (reactive)
protected WatchHandle BindVisibility(VisualElement el, Func<bool> getter);
// v-show: toggle display (reactive)
protected WatchHandle BindShow(VisualElement el, Func<bool> getter);
// :text: bind string to Label (reactive)
protected WatchHandle BindText(Label label, Func<string> getter);
// :class: switch CSS class by condition (reactive)
protected WatchHandle BindClass(VisualElement el, string className, Func<bool> getter);
// v-for (generic, key-based diff, reactive)
protected WatchHandle BindList<T>(VisualElement container,
Func<IEnumerable<T>> source,
Func<T, int, VisualElement> itemBuilder,
Func<T, object> keySelector = null);
// v-for (generic, IEnumerable - typed item access, reactive)
protected WatchHandle BindListFor<T>(VisualElement container,
IEnumerable<T> source,
Func<T, int, VisualElement> itemBuilder,
Func<T, object> keySelector = null);v-model (two-way binding)
csharp
// Real BindModel overloads (SusComponent.Bind.cs):
BindModel(myTextField, NameProp); // TextField ↔ Prop<string>
BindModel(mySlider, VolumeProp); // Slider ↔ Prop<float>
BindModel(myToggle, MuteProp); // Toggle ↔ Prop<bool>
BindModel(myDropdown, ModeProp); // DropdownField ↔ Prop<string>Props between components
csharp
// Reactive bind on child Prop<T> (:prop="expr" in .sharq)
// case-insensitive, ReactiveEffect, auto-cleanup. Non-generic: getter returns object.
protected void BindChildProp(VisualElement child, string propName, Func<object> getter);
// Direct bind to a Prop<T> instance (old way, PascalCase-sensitive)
protected void BindProperty<T>(Prop<T> target, Func<T> getter);
// Literal prop (prop="value" in .sharq)
// case-insensitive, mutates .Value (does not replace Prop<T>)
internal static void SetChildProp(VisualElement el, string propName, object value);
// Scalar conversion: string→bool/int/float/enum/string
private static object ConvertScalar(object value, Type targetType);BindList (stateful reorderer)
csharp
// Insert instead of Remove+Add - focus/scroll/input is not lost
// All three options (BindList<T>, BindListFor, BindListFor<T>) have been fixed.SusBootstrap
csharp
public static class SusBootstrap
{
// Mounts component T into the container.
// Loads the design-token cascade in order:
// _palette → _font → _theme → design-tokens → _icon → extras + OverlayHost
// (_global comes from SusDefault.tss / ApplyDefaultTSS — not this cascade.)
// When called for the first time, automatically creates an EventSystem (no InputModule).
public static T Mount<T>(VisualElement container) where T : SusComponent, new();
public static T Mount<T>(UIDocument uiDocument) where T : SusComponent, new();
// Cascade only (no component) — used by SusApp and manual UI.
public static void LoadTokenCascade(VisualElement container);
// Returns or creates the OverlayHost as the last child of the container.
public static OverlayHost GetOrCreateOverlay(VisualElement container);
// Finds or creates SusWorldSpacePanel + wires WorldSpaceService.Default
// (SusApp calls this automatically unless UseWorldSpace(false)).
public static SusWorldSpacePanel EnsureWorldSpacePanel(
Camera camera = null, OverlayHost overlayHost = null);
// Panel TSS (_palette + _font + _global via SusDefault.tss).
public static void ApplyDefaultTSS(UIDocument document);
}What replaces (v1 → v2)
| Old (v1) | New (v2) |
|---|---|
sus (UPM com.sus.sfc) | com.sharq-it.sus.core |
sharq-ui-system (SusCompiler.exe, LibSassHost) | SharqFileImporter (AssetPostprocessor) |
ElementBase — reflective | SusComponent : VisualElement |
compiled ui/ — a mixture of manual and auto | generated/ — auto only, .gitignored |
Place in the ecosystem
sus-core (this package)
├── sus-router — navigation (Push/Replace/Back, screens)
└── your Unity project — consumer app