跳转到内容

11. API 参考

公共类型命名

Sus* 是产品 API(在 using Sharq.Core 之后调用的 Runtime 与面向买家的 Editor 类型)。 Sharq*.sharq 编译器与流水线(解析器、解释器、导入器)。产品接口使用 ISus*。无前缀的公共类型是封闭的祖父级集合(响应式原语、host/layer 名词,以及这些 API 的配套类型)。不要新增无前缀公共类型;新产品类型用 Sus* / ISus*,新编译器类型用 Sharq*

SusApp — fluent bootstrap

官方文档化的应用入口点。它是 SusBootstrap 之上的一个轻量 fluent 构建器, 保证初始化顺序: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(在 root 与 OverlayHost 上的 UseCustomStyles
  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

Sharq.Core 中的进程级 gated logger。代理到 UnityEngine.Debug,以便 Editor Console 与游戏内 开发控制台 继续接收消息。不是 SusConsoleService 使用的环形缓冲 SusLogEntry 类型 — 该 struct 只存储被拦截的 Unity 日志,供叠加 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
脚本定义 SUS_VERBOSE_LOGS初始化时把下限抬到 Verbose;配置与 UseLogLevel 不能再降低

优先级:define 下限 → 最后一次 UseLogLevel / SusLog.Level → 配置中的 logLevel → 默认 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)。从构造函数/deferred 调用 ScheduleReactiveUpdates 的做法已被移除——挂载之前 schedule 可能不会触发。

Bind 辅助方法(响应式)

所有绑定都通过 ReactiveEffect 工作——自动订阅 Prop<T> / Computed<T>,并在任意来源变化时更新。 每个辅助方法都返回一个 WatchHandle(在 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.sfccom.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