Repository navigation
Releases: sinomo-lab/sui
Release list
SUI 0.6.1
This release lets event handlers open URLs, adds file and folder dialogs on
Android, scrolls text that overflows text fields and code blocks, makes touch
taps more reliable, and can elide labels that don't fit.
Upgrading from 0.6.0
- Update the SUI crates together to
0.6.1.sinomo-ui-lucidestays at
1.47.3. - Struct literals of
FileDialogSelectionneedfolders(or
..Default::default()), and those ofActionTilePaintneed
text_overflow. - Building the browser package needs
wasm-bindgen-cli0.2.130.
Rust
- Added
EventCtx::open_url, which opens a URL in the default browser or the
app registered for its scheme on desktop, Android, and the web. Call it from
any handler, such as aLink'son_open_with_ctx; links still open nothing
on their own.LocalUrlOpenerBackendrecords the URLs a test opens. - A
UrlPolicydecides which URLs open. The default allows only absolute
http,https, andmailtoURLs, so untrusted Markdown cannot launch
local files or other protocol handlers. Install another with
App::url_policy, extend the default withUrlPolicy::allows_by_default,
or allow everything withUrlPolicy::allow_all. NativeFileDialogsworks on Android 8.0 and later through the system
document picker. Files chosen there have nopathand are read and written
through their document providers.- Folder dialogs return
PlatformFolderhandles in
FileDialogSelection::folders, which list, find, and create entries without
a filesystem path, on desktop, Android, and in browsers with
showDirectoryPicker. TextInput,PasswordInput, andDateTimeInputscroll text wider than the
field to keep the caret in view, instead of pinning the caret over hidden
text. Editable semantics report the offset asscroll_x, and read-only text
keeps the field'stext_style.- Sideways touch drags on a wide
RichDocumentViewcode block pan the code
instead of selecting text, and clicks in a code block scrolled by the wheel
now land under the pointer. - A tap that moves focus off an editor keeps the soft keyboard up until the
finger lifts, so the relayout no longer moves the tapped button away. Touch
presses onButtonandIconButtonare judged by where the button was when
the finger went down. - Added
ElidedLineandpaint_text_line_elided, which end text too wide for
its line in "…".SegmentedControl,BrowserTabBar, andActionTilePaint
take atext_overflowoption:TextOverflow::Ellipsiselides labels
instead of clipping them, andSegmentedControlthen widens the segments
that need it. - Added
ActionTileGeometry, whichpaint_action_tilenow returns, with
ActionTileGeometry::heightfor the height a tile needs. - Updated dependencies, including PyO3 0.30, napi 3.16, resvg 0.49, and
wasm-bindgen 0.2.130.
Python and JavaScript
- Added
open_url(url)(openUrl), which can serve as a link'son_open
(onOpen), withset_url_policy(setUrlPolicy) and
url_allowed_by_default(urlAllowedByDefault) to choose which URLs open.
SUI 0.6.0
This release makes the JavaScript package async and runs it in browsers on a
WebAssembly build, removes the APIs deprecated in 0.4, and makes small-change
frames much cheaper: retained layers scroll on the compositor, draws batch
across packets with clips applied in shaders, and windows on every platform
redraw only what changed.
Upgrading from 0.5
- Update the SUI crates together from
0.5to0.6, andsinomo-ui-lucideto
1.47.3, which bundles the same Lucide 1.47.0 icons for the0.6family. - Clear 0.5's deprecation warnings before updating: each names its
replacement, and 0.6 removes the deprecated APIs.
Breaking changes
- Removed the APIs deprecated in 0.4, as the 0.4 upgrade notes announced.
Code that compiled without deprecation warnings is unaffected. Use the
replacements the warnings named:- Types:
Modal→Dialog,Drawer→SideSheet,BusyIndicator→
Spinner,ComboBox→Select,SpinBox→NumberInput,
MultilineTextInput→TextArea,Divider→Separator,DataGrid→
Table,PathBar→Breadcrumb,ResizablePane→SplitView, and the
CanvasAppearance,CanvasRulerAppearance,PixelCanvasAppearance, and
ColorPickerAppearancealiases → their*Colorstypes. The unused
Stylestruct is gone. - Builder methods:
spacing→gap,line_spacing→cross_gap,
radius→corner_radius,disabled()→enabled(false),
appearance→colors,shown→open,collapsed()→
expanded(false),without_border()→show_border(false),
content/with_content/with_child→childoritem,
activate_with_content→activate_with_child,subtitle→detail,
TreeItem::children→items,Select::expanded→open,
Icon::labelandImage::label→semantic_name, and the checked-state
nameson,on_when,selected,on_toggle, and
on_select→checked,checked_when, andon_change(and
on_select_with_ctx→on_change_with_ctx).FloatingStack::theme,
which had no effect, is gone. - Accessors and setters:
child()→child_pod(),items/items_mut/
item/set_itemonFlex→ theirflex_*names,is_on/is_selected
→is_checked,set_on/set_selected→set_checked,is_shown/
set_shown→is_open/set_open,label()→current_label(),
color()→current_color(),TextInput::name()→accessible_name(),
andstate()on workspaces →shared_state(). dynamic(fallback, reader)constructors →new(fallback)with
text_when,label_when, ordocument_when;Label::styleand
style_when→text_styleandtext_style_when;
RebuildOnChange::newandnew_observable→key_whenandkey_from.register_builtin_icon_resourcesis gone; built-in icons need no
registration.RadioButton::on_select, which fired on every activation, has no
replacement;on_changereports only actual changes.
- Types:
- The JavaScript package
@sui/uiis now ESM and async-first, and needs
Node.js 20.19 or newer (CommonJS code can stillrequireit):App.run()returns a promise and runs the app on Node's event loop
instead of blocking; pass{ onReady(ui) { … } }instead of calling
App.runWithHandle.UiHandle.post,callLater, andcallEvery,Timer, andUiTaskQueue
are gone; Node's own timers and promises work while the app runs.UiHandle.showFileDialog(options)returns a promise of the paths instead
of taking a callback.- Widget factories are
lowerCamelCaseonly; thePascalCasepositional
functions such asButtonare no longer exported. RunningApp.windowId(index)is nowwindowHandle(index).
JavaScript
- Added a WebAssembly build that runs the same API in browsers: build it with
cargo xtask web build, and bundlers and browsers load it through the
package'sbrowserexport condition.App.run({ canvas })draws on a
canvas and keeps it the size of its container. - Callbacks may be
async, and errors from callbacks, including rejected
promises, go tosetErrorHandler(by defaultconsole.error) without
stopping the app. - Added promise helpers:
app.once(name),state.changed(), the
state.changes()async iterator, andrunning.idle()to wait for async
callbacks in tests.App.runand listeners take anAbortSignal. app.onreturns aSubscription; it andStateSubscriptionare
disposable withusing.- Builders such as
Window.root()andApp.window()return their object for
chaining;Point,Size,Rect, andColorhaveequalsandtoString;
addedColor.rgba,Color.black,Color.white,version, and
RunningApp.saveScreenshot. - Fixed
rebuildOnChange, which rendered nothing, and custom widgetevent
callbacks that return nothing, whose context requests were dropped. - A virtual table's
selectedstate that holds a string now receives the
selected key as a string, matching the key type of its callbacks. - Added
app.fontUrl(url)to fetch and register a font, and
FontHandle.family(also in Python) to read a registered font's family
name. Invalid font data now fails at registration. - Added a
node:testsuite that runs on both the addon and the WebAssembly
build.
Python
- The sdist places the license file at its root, where its metadata declares
it. The release workflow checks each sdist's contents and metadata, and
runstwine check, before uploading it. - The examples open interactive desktop windows with
App.run()instead of
printing snapshots, and paint the theme's window background with a root
surface, as the README's examples now do.
Rust
- Added
DesktopPlatform::start_pumpedandPumpedDesktop, and
App::start_pumped_with_handle, to drive the desktop event loop one turn at
a time from another framework's event loop. - Added
DesktopPlatform::start_webandwith_web_canvas, and
App::start_web_with_handle, to run in the browser on a chosen canvas and
learn when the app exits. - Fonts can be WOFF or WOFF2 as well as TrueType or OpenType, in Rust and in
the bindings. AddedRegisteredFont::try_from_bytes, which checks the data,
andRegisteredFont::family_name;font_bytesandregister_font_bytes
now fail for data that is not a font. - Offscreen renderers share compiled pipelines, and the shared cache did not
tell single-source and dual-source text pipelines apart. A renderer without
dual-source blending could leave its text pipeline for later renderers,
which then drew LCD text in grayscale. Text pipelines are now cached per
variant. - On Windows, closing the last window no longer returns from
runbefore the
window is destroyed, which left it on screen until the process exited. ContextMenukeeps its panel positions, and with them its paint,
semantics, and hit testing, when a parent such as a toolbar measures it
again after arranging it.VirtualTablepublishes its viewport only when arranged, not when a parent
measures provisional sizes, which made layout observers alternate between
sizes forever.- Touch input no longer opens tooltips, which could cover the menu or action
a finger just activated.
Performance
- On Android, a focused window no longer presents every display frame while
its UI is unchanged. Desktop windows keep presenting so that variable
refresh rate does not lower the monitor's refresh rate. - In the browser, a focused canvas no longer wakes on every display frame
while nothing changes, matching Android. - Bundled fallback fonts on the web and Android, and fonts registered by the
app, are shared with the text system instead of copied into the heap. - Release web builds run Binaryen's
wasm-opt -Os(Trunk for the demo,
cargo xtask web build --releasefor the JavaScript package when
wasm-optis installed orWASM_OPTis set) and enable WebAssembly SIMD.
The demo module drops from 16.6 MB to 11.7 MB. - Per-widget layout, paint, and semantics phases only read the clock when
SUI_PROFILE_WIDGET_TIMINGSis set, and the layout graph uses a faster
hasher for widget IDs. - JavaScript widget callbacks and class-instance checks cross the
WebAssembly boundary fewer times per call. - Scrolling and translating a retained layer is now compositor-only: the
renderer reuses the layer's composed geometry and vertex buffers and moves
them with a GPU offset, and rectangular clips are applied as scissors. - Layout change detection no longer rebuilds a node index for every moved
widget, which made each scroll step quadratic in the number of widgets. - Translated layout bounds keep their exact size, and descendants that move
with their paint boundary within f32 rounding stay composition-only, so
retained content far from the origin is no longer repainted on scroll. - Text packets only compare the backdrop under themselves, so text scrolling
over a uniform background keeps its rasterized glyphs. - Added
scroll-flatandscroll-retainedfixtures tosui-bench. - Small-change frames do less whole-tree and whole-scene work:
- The renderer reorders each fragment's draws so draws that share a
pipeline and clip are adjacent, without moving any draw past one it
overlaps, and drops clip rectangles that contain the whole draw. The
controls grid goes from 1,201 to 647 draw calls per frame. - The runtime keeps the graph from before layout by swapping buffers
instead of copying a snapshot, and diffs the two graphs directly. - Stack metadata is only rewritten when it changed, so unchanged frames
keep sharing scene command lists with the renderer. - The frame image registry is reused while its images are unchanged, and
unused text layouts are pruned in batches rather than every frame. - Appending a scene to an empty one shares its commands instead of copying
them, and semantics assembly uses ...
- The renderer reorders each fragment's draws so draws that share a
SUI 0.4.1
This release adds observable background tasks, makes reactive updates and text
rendering cheaper, improves platform font rendering, and adds touch scroll
inertia.
Highlights
- Added
Task,TaskState, andTaskHandlefor background work with progress,
results, errors, and stale-worker protection.refreshkeeps the previous
result visible while loading, cancellation restores it, andTaskHandle::run
completes the task from a future on the application's executor. - Added
batchto coalesce notifications,combineandcombine_namedto
derive values from two to four observables, andchanged().awaitto wait for
a signal, task, or other observable to change. - Added borrowed signal reads and in-place updates with
with,modify, and
mark_changed, plus pointer-compared and copy-on-writeArcupdates with
set_arcandmodify_arc. Selector clones share one source subscription
and a cached result, avoiding repeated work for multiple observers. - Skipped clipped glyphs before rasterization and split grayscale masks from
color and LCD glyphs. A grayscale atlas page now uses 4 MiB of GPU memory
instead of 16 MiB each on the CPU and GPU; only pending uploads keep CPU
pixels. Clipping also preserves tall marks and bitmap emoji at line edges. - Followed Windows ClearType and Linux fontconfig/Xft smoothing preferences,
improved Linux and Android slight hinting and coverage, and loaded Android
system fonts with bundled fallbacks. Runtime text-policy changes now update
retained text correctly. - Added coasting touch scrolling to
ScrollViewandVirtualScrollView.
Both exposeon_offset_changeandon_offset_change_with_ctxfor wheel,
keyboard, touch, fling, scroll bar, and programmatic moves. The widget book's
navigation follows flings and keeps the selected entry after a jump.
Other changes
- Fixed open contours rendering as fans on Adreno 740 under Chrome's Vulkan
WebGPU backend and made tooltip borders continuous around their tails. - Kept menu and context-menu keyboard shortcuts on one line so long
combinations stay aligned and vertically centered. - Added download progress while the web demo loads its Wasm module and fonts,
with startup errors displayed on the loading screen. - Made Chrome text comparisons match the requested grayscale or LCD mode,
added aggregate ink and alignment diagnostics, and added a light/dark,
scale, and antialiasing comparison matrix. - Fixed concurrent selector updates losing changes and reactive diagnostics
recording older versions when notifications arrive out of order. - Updated accessibility, Python, Node, Wasm, and Linux dependencies.
Compatibility and release notes
- Update the SUI crates together to
0.4.1.sinomo-ui-lucideremains at
1.47.1, with the same bundled Lucide 1.47.0 icons. - Selector closures now read signal values while the source is locked; they
must not write to that signal. Debug builds report same-signal reentrant
writes with a named panic instead of deadlocking. Observers still run
synchronously on the writing thread; batching defers them until the batch
ends on that thread. - Rust 1.90 remains the minimum supported version. Browser support remains
alpha, Android remains experimental, and Python and JavaScript bindings
remain source-built and are not part of the registry release.
SUI 0.3.0
This release adds application and editor surfaces, improves text quality and
retained rendering, and expands the source-built language bindings.
Highlights
- Added retained docking workspaces, editor cursor grabbing and raw mouse motion,
safe initial desktop window placement, and GPU interoperability contracts. - Expanded Python and JavaScript bindings for the newer Rust widget and editor
surfaces. These bindings remain source-built and are not registry publications. - Reused paragraph shaping and glyph measurements across layout widths, added
size-only text measurement, and reduced repeated Flex layout probes. - Retained widget output, scene fragments, renderer packets, GPU batches, and
shared scene command storage to reduce repeated frame preparation work. - Overlapped GPU preparation with CPU startup and added reproducible widget,
frame, shrinkwrap-conversation, and editorial-flow benchmarks. - Improved font hinting, transformed text rasterization, LCD coverage and atlas
sampling; isolated node-edge animation repaint work and analytic grid dots. - Added provider-neutral image icons, bounded browser tabs, compact dialogs,
and reserved scrollbar gutters. - Updated dependencies and bundled Lucide icons to 1.47.0.
- Made the Shrinkwrap and Editorial text demos follow shared theme colors,
typography, and radii, including theme changes while paused and cached text
layouts at unchanged window sizes. - Added a size-focused web release profile and kept the demo within the existing
12 MiB uncompressed Wasm budget without removing features. - Restored Rust 1.90 compatibility, corrected offscreen demo-picker test
interactions, and resolved strict workspace Clippy findings. - Bundled complete Noto Sans Arabic and Hebrew fallback fonts for offline web
and Android text, and corrected caret hit testing across right-to-left runs. - Restored corrupted Unicode, emoji, and IME sample text in the demo and its
text-editing benchmarks. - Continued VSync presentation and animation/timer delivery inside native
window move/resize loops, including while the title bar is held still. - Preferred compatible Direct3D12 hardware on Windows to improve native window
drag pacing, retaining explicit backend selection and automatic fallback. - Kept focused, visible VSync windows presenting cached content so an idle UI
does not lower a variable-refresh monitor's refresh rate. - Reused GPU vertex buffers, upload staging storage, and output-transform
resources to avoid repeated allocations and interaction-time frame stalls. - Fixed inflated frame-time/FPS readings after idle mouse motion by attributing
input costs and latency only to a pending redraw across native and test hosts. - Made the demo FPS counter measure host frame cadence, including VSync and
idle intervals, while reporting render work separately. - Retained action cards independently so hover, press, and focus transitions
repaint only the affected cards instead of rebuilding an entire picker grid. - Centralized builder/runtime resource registration so rejected duplicate handles
preserve the original resource, and shared native/web GPU resource setup. - Shared button press, text-change, and caret lifecycle logic across controls;
organized composites, binding infrastructure, and renderer internals by feature. - Made binding signatures language-neutral with explicit numeric and identifier
types, and changed export verification to follow Rust modules and declarations. - Fixed selector observer write-back deadlocks and removed obsolete reactive
dependencies after completed widget phases while preserving cached phases. - Bounded text-layout and renderer path caches, preserving layouts and geometry
still owned by live widgets or frames, and avoided full reindexing on collection
appends. - Matched node-graph spatial bounds to configured Bézier curvature so visible
curves remain available for hit testing and culling. - Added the optional
sinomo-ui-webviewcrate for WRY-backed native child
webviews with retained layout, lifecycle synchronization, thread-safe
controls, typed page/title/IPC events, and application-owned browser policy. - Prevented synchronous live-test flushes from advancing future animation
frames based only on render wall time, avoiding timeouts in repeating demos. - Added affine transformed widget subtrees and Canvas-hosted normal widgets.
Canvas now uniformly scales paint, input, semantics, text, images, and nested
layout by default, with screen-space/custom zoom policies and touch pinch;
retained node widgets use the same path. - Added the
sinomo-ui-nodesgraph-editor library with typed nodes, edges,
handles, controlled and uncontrolled observable state, retained custom node
widgets, dynamic measurement, incremental spatial indexing, subflows,
resizing, edge reconnection, per-element semantics, lifecycle events,
animated viewport and edge behavior, controls, minimap, and graph-owned
appearance overrides. - Added a comprehensive
sui-demonode-editor workspace behind the
default-enablednodesfeature, covering controlled and uncontrolled graphs,
retained node controls, every edge family, subflows, editing, indexing,
semantics, and viewport telemetry.
Compatibility and release notes
- Update SUI crate dependencies together from
0.2to0.3. Lucide keeps its
independent1.47.0version and now depends on the0.3SUI family. Event::RawMouseMotionandWindowEvent::Movedrequire handling in exhaustive
event matches. Public widget appearance/configuration structs gained fields,
includingControlPalette::selection_border; update explicit struct literals.- Rust 1.90 remains the minimum supported version.
- Linux webview builds require the system WebKitGTK 4.1 development libraries;
the Rust bindings do not install the browser engine. - Browser support remains alpha and Android remains experimental. Native
webviews are an optional crate; Python wheels and Node addons are not part of
this Rust registry release.