Repository navigation
Releases: Cuvara/UIToolkit
Release list
v0.7.2
v0.7.1
Fixed
- Removed EcsAutoSinkBinderTests (incomplete interface stubs caused compile errors)
v0.7.0
Added
- LoadingProgressTracker � weighted multi-step loading (13 tests)
- ConfirmDialog � static ShowAsync modal confirmation
- ToastService � auto-dismiss stackable notifications (7 tests)
- IScreenTransition + FadeTransition + SlideTransition
- SettingsModel � common game settings with PlayerPrefs (6 tests)
v0.6.1
Added
- EcsAutoSinkBinder tests � 7 tests covering attach/detach lifecycle,
idempotent dispose, null safety, and no-sink presenter tolerance.
v0.6.0
Added
- Screen Creator Wizard (
Editor/ScreenCreator/). An Editor window
(Assets/Cuvara/Create Screen) that scaffolds a new screen, popup or collection item in
one click: the UXML (withSafeAreaElementfor screens/popups, not items), a USS skeleton,
the C# file (view interface + view + presenter withOnBindAsync(subs, ct), noDispose
override,Require<T>queries), and a test skeleton with thesubs.LiveCount == 0
assertion. Replaces the frozen GameFoundation wizard: noSignalBus, noILoggerManager,
no[Preserve], noISurfaceScreenView, noBindData— every line emitted matches the
package's own v0.5.0 API. Templates are pure string constants, testable with NUnit alone.
21 EditMode tests cover: no banned host-framework tokens, correct base classes, correct
OnBindAsyncsignature,ScreenSubscriptionsparameter,CancellationTokenparameter,
Require<T>instead ofQ<T>, UXML well-formed XML, SafeArea on screens not items,
element names match view queries, placeholder substitution, kebab-case conversion.
v0.4.0 — Hybrid data-binding, UXML codegen
Added
- Hybrid data-binding convention — Unity 6 runtime data binding
(DataBinding/INotifyBindablePropertyChanged/[CreateProperty]) is now allowed, as a
View-internal implementation detail behind the existingIViewinterfaces, for
data-heavy screens. The MVP core is untouched; commands, clicks and navigation stay on
ScreenSubscriptions; every binding isBindingMode.ToTargetwith anameofpath
(stringly UXML<Bindings>discouraged). Convention, walkthrough, testing story and a
per-screen decision table:Documentation~/HYBRID-DATA-BINDING.md. BindableViewModel(Runtime/ViewModel/, namespaceCuvara.UIToolkit.ViewModel).
The notifying base a binding source must derive from:Set<T>(ref field, value)guards
withEqualityComparer<T>.Default, raisespropertyChangedwith the
[CallerMemberName]property name only on real change, and returns whether anything
changed. Notifying is mandatory because a non-notifyingDataBindingsource is
version-polled by the binding system on every UI update — per-frame work the package's
"update on data change, not per frame" contract forbids. Stays plain C#: testable with
NUnit alone, no panel.- EcsHud sample retrofitted as the reference hybrid screen. The imperative
Render(caption, fraction)path is gone: the sink writes properties on a
[CreateProperty]-annotatedVitalsHudViewModel, andVitalsView.Bindassigns
Root.dataSourceand wires the label and bar once viaSetBinding(the
fraction→StyleLengthconversion is a converter on the binding, so UI Toolkit types
never leak above the View). Theadapter → ViewModel → Viewlayering and the ECS rule
are unchanged — nothing inRuntime/Ecs/moved. The sample's UXML (renamed
VitalsView.uxmlso the generated class matches the view) is now enrolled in the
UXML codegen:Generated/VitalsView.uxml.g.csis the other half of the partial View
and is drift-checked by CI alongside the test fixture. - Tests:
Tests/Runtime/ViewModel/BindableViewModelTests.cs(plain C# — raise with
correct name via[CallerMemberName], silence on equal values including null→null,
same-reference and equal-but-distinct strings, return-value semantics, value and
reference types; verified under plaindotnetas well) and
BindableViewModelBindingTests.cs([UnityTest]on a liveUIDocument— aSet()
reaches a boundLabeland a converter-drivenstyle.widththrough the real binding
system, with noRendercall).
Changed
UXML-CODEGEN.mddocuments a batchmode limitation found while verifying 0.3.0 on
a real Editor (6000.3.9f1): a-batchmode -quitsession that starts with compile
errors exits before the asset import step (exit code still 0), so the auto-regen
postprocessor never runs in it — after an element rename breaks consuming code,
batchmode cannot regenerate its way out. The doc lists the recovery paths (git
checkout of the.g.cs, the menu item in an interactive Editor, or
Tools~/UxmlCodegenCli). Docs only; no code change.
v0.2.0 — Screen Flow & Loading Flow Sample
Added
- Screen flow system (
Runtime/Flow/). A stack-based screen navigator with full lifecycle:
PushAsync,PopAsync,ReplaceAsync,PopToRootAsync,PopAllAsync. Screens are UXML
documents managed by presenters with lifecycle hooks:OnBindAsync,OnActivate,
OnDeactivate,OnSuspend,OnResume,OnBackRequested. Model-parameterized variants
(PushAsync<TPresenter, TModel>(model)) pass data to a screen at open time.ScreenNavigator— the stack, per-scene scoped via VContainer.BaseUIToolkitScreenPresenter<TView>/<TView, TModel>— presenter bases.BaseUIToolkitPopupPresenter<TView>/<TView, TModel>— popup convenience withClose().ScreenOptions—None(full screen),Modal(overlay layer),DimsBelow(dims without
suspending the screen below).ScreenSubscriptions— scoped cleanup for button clicks and events.ScreenRegistry— maps presenter type to view type, asset key, and options.ScreenLifecycleState— 9 states fromRegisteredtoDisposed.IScreenScopeFactory/VContainerScreenScopeFactory— one VContainer child scope per screen.ScreenFlowRegistration—RegisterUIToolkit(),RegisterScreenFlow(),
RegisterScreen<T,V>(),RegisterPopup<T,V>()extension methods for VContainer.
- Back navigation (
Runtime/Input/BackNavigationSource). Wires Escape, gamepad B, and
Android back to the navigator. One-line setup:source.BackHandler = navigator.HandleBack.
RootBackPolicycontrols what happens at the bottom of the stack:NotHandled(platform
default),Consume(swallow), orRaise(event). - Assembly definitions for all samples. Samples could not compile when imported via Package
Manager because they had no.asmdef. Each sample now ships its own. - Loading Flow sample (
Samples~/LoadingFlow). Two-scene flow demonstrating every package
feature: LoadingScene (MonoBehaviour-driven progress bar with tips and spinner) transitions to
MainScene (ScreenNavigator with Push, Pop, Replace, PopToRoot, Modal+DimsBelow overlay, model
parameters, lifecycle hooks, OnBackRequested override, BackNavigationSource,
UIToolkitListAdapter collection adapter, and per-scene navigator scoping). - A DOTS/ECS presentation adapter (
Runtime/Ecs/), optional behindcom.unity.entities
and theCUVARA_UITOOLKIT_ENTITIESversionDefine.IViewModelSink<TViewModel>— the contract a host's Presenter implements.EcsViewModelBridge<TComponent, TViewModel>— managedSystemBasein
PresentationSystemGroupthat converts component data to a plain ViewModel.EcsSinkRegistration— binds a sink for a screen's lifetime and unbinds onDispose.Samples~/EcsHud— the five layers end to end.
- CI improvements: samples compile job, samples gate (
check_samples.py), real Unity test
job, install probes,check_standalone.pywired into CI. - A test that
[UpdateInGroup]inherits onto a host's bridge subclass.
Fixed
- A sink registered mid-session received nothing until the simulation next wrote the component.
The next pass after a registration now runs unfiltered exactly once. - CI failed on its own dependency check after the
com.gdk.coredependency was removed. check_standalone.pywas never wired into CI.
v0.1.0
First release. The code was developed inside com.gdk.core on the feat/uitk-migration
branch and extracted here — not unchanged: every file referenced the host framework,
and severing those references is most of what this release is. See "Changed on extraction"
below for what that cost.
Added
- A standalone UI Toolkit screen layer. Screens are UXML documents parented into a
UIDocument's visual tree.BaseUIToolkitView,UIToolkitViewFactory,
VisualElementViewLayer. - Its own contracts, in
Runtime/Core/:IUIToolkitView(the view lifecycle),
IViewLayer/IViewSurface(where a view lives and how it moves),
IVisualTreeAssetLoader(one method — the host supplies the asset pipeline), and
IPresenterInstantiator(the collection adapters' presenter factory). RootUIDocumentplus the default three-layerRootUIDocument.uxml, and aLayers
value carrying the Screen / Hidden / Overlay layers as one thing.- Collection adapters — list, grid and multi-template — with
IUIToolkitItemView,
BaseUIToolkitItemViewandBaseUIToolkitItemPresenter. SafeAreaElement/SafeAreaCalculator— notch handling. Insets are applied as
layout, either as padding or as absolute edges. Note that
PanelSettings.SetScreenToPanelSpaceFunctionis deliberately NOT used: it is present in
6000.3.9f1, but it transforms pointer coordinates, so driving a safe area through it
would move where clicks land without moving any layout.PanelScaleRatio— theCanvasScaler-equivalent aspect-ratio rule, applied to
PanelSettings. It clones the settings asset by default, becausePanelSettingsis a
shared project asset and writing to it at runtime is a source-control diff rather than a
runtime tweak.BackNavigationSource— raises a C# event onNavigationCancelEvent, covering
Escape, gamepad B and the Android back button.- A VContainer registration, in its own assembly. See Dependencies below — it began
as an optional, gated assembly and is not one any more. - A
Notification Popupsample and 113 PlayMode tests.
Dependencies
- VContainer is required, not optional.
jp.hadashikick.vcontaineris a real dependency
and the registration assembly is no longer gated behind aGDK_VCONTAINERversionDefine
plus a matchingdefineConstraints. The project standardises on VContainer for all
dependency injection, so a host without a container is not a supported configuration — and
the gate was an assembly-level branch that nothing exercised.Cuvara.UIToolkit.VContainer
stays a separate assembly for direction rather than for gating: it may reference the view
and manager types, and they may not reference it, which is what keeps a container reference
out of the view layer. com.cysharp.unitaskandcom.unity.modules.uielementsare the other two. All three
resolve from a registry, so the package installs from its own declarations — the OpenUPM
scoped registry forcom.cysharpandjp.hadashikickis the consuming project's to add,
because a UPM package cannot declare a scoped registry of its own.
Changed on extraction
Every one of these was a reference to com.gdk.core that had to be severed, not a
refactor for its own sake:
ISurfaceScreenView/IScreenViewBase→IUIToolkitView. The host contract required a
RectTransformand anIsReadyToUseflag; aVisualElementhas noTransform, and
CloneTreeis synchronous so there is no "not ready yet" window to flag.IViewLayer/IViewSurfaceare now DEFINED here. The host deleted its copies and
consumes these, so there is one definition rather than two.IAssetsManager→IVisualTreeAssetLoader. The host's loader comes from an OpenUPM
scoped registry, and a UPM package cannot declare a scoped registry of its own — so that
dependency could never have resolved for a consumer installing from a git URL.- The collection adapters'
IDependencyContainer, resolved through a static service
locator, →IPresenterInstantiatorpassed in. That locator was both a dependency and the
reason those adapters could not be exercised without a live scene. SignalBus→ plain C# events.ILoggerManager→UnityEngine.Debug.- Namespaces
GameFoundation.Scripts.UIModule.UITK.*→Cuvara.UIToolkit.*; assemblies
GameFoundation.UIModule.UITK→Cuvara.UIToolkit.
Deliberately not here
UIToolkitScreenViewBackend, BaseUIToolkitScreenPresenter,
BaseUIToolkitPopupPresenter, the notification popup presenter, and the back-navigation
policy all stayed in com.gdk.core. Each one exists to bind this package to that
framework — it implements IScreenViewBackend, or takes a SignalBus, or decides what
Back closes. Moving them here would have re-created the dependency this package exists to
remove. A CI gate (.github/scripts/check_standalone.py) fails the build if any of those
host symbols reappears under Runtime/ or Tests/.