К содержимому

11. Справочник API

Публичные имена типов

Sus* — продуктовый API (Runtime и buyer-facing Editor-типы, которые вы вызываете после using Sharq.Core). Sharq* — компилятор и пайплайн .sharq (парсер, интерпретатор, импортёры). Продуктовые интерфейсы — ISus*. Непрефиксные публичные типы — закрытый grandfathered-набор (реактивные примитивы, host- и layer-существительные, компаньоны этих API). Не добавляйте новые непрефиксные публичные типы; новые продуктовые типы — Sus* / ISus*, новые типы компилятора — Sharq*.

SusApp — fluent bootstrap

Задокументированная точка входа приложения. Тонкий fluent-билдер над SusBootstrap, который гарантирует порядок инициализации: panel TSS → EventSystem → каскад токенов → OverlayHost → world panel → шрифты → custom styles → configure → mount → тема (последней).

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 UseLogLevel(SusLogLevel level);       // process gate; call before Run/Mount
    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 (Run / Mount)

  1. Иконки (UseIconsSusIconRegistry.RegisterProvider)
  2. Каскад токенов (LoadTokenCascade: _palette_font_themedesign-tokens_icon → дополнения + OverlayHost)
  3. World-space панель (EnsureWorldSpacePanel, если в Play Mode и включён UseWorldSpace)
  4. Шрифты (UseFonts)
  5. Custom styles (UseCustomStyles на root + OverlayHost)
  6. Коллбэки Configure
  7. Монтирование корневого компонента (если Mount<T>)
  8. Тема — последней (SusThemeService.Instance.SetTheme(root, theme))

UseLogLevel не входит в finalize — он сразу выставляет SusLog.Level (безопасно до Run / Mount).

csharp
SusApp.Create(uiDocument)
    .UseTheme(SusTheme.Dark)
    .UseLogLevel(SusLogLevel.Verbose)   // optional — diagnostics / audits
    .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();

SusLog

Процессный gated-логгер в Sharq.Core. Проксирует в UnityEngine.Debug, чтобы Editor Console и игровая dev-консоль продолжали получать сообщения. Не путать с ring-buffer типом SusLogEntry у SusConsoleService — тот struct только хранит перехваченные Unity-логи для overlay UI.

csharp
public enum SusLogLevel
{
    Error = 0,
    Warn = 1,      // default buyer level
    Info = 2,
    Verbose = 3,   // audits, probes, bootstrap traces
}

public static class SusLog
{
    public static SusLogLevel Level { get; set; }   // minimum emitted; default Warn
    public static bool IsEnabled(SusLogLevel level);
    public static bool IsVerbose { get; }           // IsEnabled(Verbose)

    public static void Error(string message);
    public static void Error(string message, Object context);
    public static void Warn(string message);
    public static void Warn(string message, Object context);
    public static void Info(string message);
    public static void Verbose(string message);
    public static void Diagnostic(string message);  // same gate as Verbose
}

По умолчанию: Warn (Error + критичный Warn). Диагностика молчит, пока не поднять уровень.

Как включить Verbose

ИсточникЭффект
SusApp.UseLogLevel(SusLogLevel.Verbose) / SusLog.Level = …Переопределение из кода; вызывать до Run / Mount
Assets/sus.config.json"logLevel": "Verbose"Читается при первом обращении к SusLog (см. 10-configuration)
Scripting define SUS_VERBOSE_LOGSНа init поднимает пол до Verbose; конфиг и UseLogLevel не могут понизить

Приоритет: пол define → последний UseLogLevel / SusLog.LevellogLevel в конфиге → default Warn.

Для дорогих дампов сначала гейт: if (SusLog.IsVerbose) SusLog.Verbose(...).

SusComponent — базовый класс

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()
}

Жизненный цикл (порядок)

Constructor:
  Created() → BeforeMounted() → Build() → LoadCompanionStyleSheets()
Deferred(schedule.Execute, next frame):
  Mounted()
OnAttachToPanel:
  ScheduleReactiveUpdates() → Updated() ~60 FPS
OnDetachFromPanel:
  BeforeUnmounted() → _updateItem.Pause() → DisposeAllBindings() → Unmounted()

Updated() выполняется только когда элемент прикреплён к панели (OnAttachToPanelHandler). Вызов ScheduleReactiveUpdates из конструктора/deferred убран — до attach schedule может не тикать.

Bind-хелперы (реактивные)

Все биндинги работают через ReactiveEffect — авто-подписка на Prop<T> / Computed<T> и обновление при изменении любого источника. Каждый хелпер возвращает WatchHandle (отслеживается для dispose при 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 (двусторонний биндинг)

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 между компонентами

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 (переупорядочивание с сохранением состояния)

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);
}

Что заменяет (v1 → v2)

Старое (v1)Новое (v2)
sus (UPM com.sus.sfc)com.sharq-it.sus.core
sharq-ui-system (SusCompiler.exe, LibSassHost)SharqFileImporter (AssetPostprocessor)
ElementBase — рефлективныйSusComponent : VisualElement
compiled ui/ — смесь ручного и автогенерируемогоgenerated/ — только автоген, .gitignored

Место в экосистеме

sus-core (this package)
    ├── sus-router — navigation (Push/Replace/Back, screens)
    └── your Unity project — consumer app