Skip to content

Releases: sinomo-lab/sui

SUI 0.6.1

Choose a tag to compare

@github-actions github-actions released this 02 Nov 10:05

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-lucide stays at
    1.47.3.
  • Struct literals of FileDialogSelection need folders (or
    ..Default::default()), and those of ActionTilePaint need
    text_overflow.
  • Building the browser package needs wasm-bindgen-cli 0.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 a Link's on_open_with_ctx; links still open nothing
    on their own. LocalUrlOpenerBackend records the URLs a test opens.
  • A UrlPolicy decides which URLs open. The default allows only absolute
    http, https, and mailto URLs, so untrusted Markdown cannot launch
    local files or other protocol handlers. Install another with
    App::url_policy, extend the default with UrlPolicy::allows_by_default,
    or allow everything with UrlPolicy::allow_all.
  • NativeFileDialogs works on Android 8.0 and later through the system
    document picker. Files chosen there have no path and are read and written
    through their document providers.
  • Folder dialogs return PlatformFolder handles in
    FileDialogSelection::folders, which list, find, and create entries without
    a filesystem path, on desktop, Android, and in browsers with
    showDirectoryPicker.
  • TextInput, PasswordInput, and DateTimeInput scroll text wider than the
    field to keep the caret in view, instead of pinning the caret over hidden
    text. Editable semantics report the offset as scroll_x, and read-only text
    keeps the field's text_style.
  • Sideways touch drags on a wide RichDocumentView code 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 on Button and IconButton are judged by where the button was when
    the finger went down.
  • Added ElidedLine and paint_text_line_elided, which end text too wide for
    its line in "…". SegmentedControl, BrowserTabBar, and ActionTilePaint
    take a text_overflow option: TextOverflow::Ellipsis elides labels
    instead of clipping them, and SegmentedControl then widens the segments
    that need it.
  • Added ActionTileGeometry, which paint_action_tile now returns, with
    ActionTileGeometry::height for 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's on_open
    (onOpen), with set_url_policy (setUrlPolicy) and
    url_allowed_by_default (urlAllowedByDefault) to choose which URLs open.

SUI 0.6.0

Choose a tag to compare

@github-actions github-actions released this 30 Oct 11:17

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.5 to 0.6, and sinomo-ui-lucide to
    1.47.3, which bundles the same Lucide 1.47.0 icons for the 0.6 family.
  • 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
      ColorPickerAppearance aliases → their *Colors types. The unused
      Style struct 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 → child or item,
      activate_with_content → activate_with_child, subtitle → detail,
      TreeItem::children → items, Select::expanded → open,
      Icon::label and Image::label → semantic_name, and the checked-state
      names on, on_when, selected, on_toggle, and
      on_select → checked, checked_when, and on_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_item on Flex → their flex_* 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(),
      and state() on workspaces → shared_state().
    • dynamic(fallback, reader) constructors → new(fallback) with
      text_when, label_when, or document_when; Label::style and
      style_when → text_style and text_style_when;
      RebuildOnChange::new and new_observable → key_when and key_from.
    • register_builtin_icon_resources is gone; built-in icons need no
      registration.
    • RadioButton::on_select, which fired on every activation, has no
      replacement; on_change reports only actual changes.
  • The JavaScript package @sui/ui is now ESM and async-first, and needs
    Node.js 20.19 or newer (CommonJS code can still require it):
    • 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, and callEvery, Timer, and UiTaskQueue
      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 lowerCamelCase only; the PascalCase positional
      functions such as Button are no longer exported.
    • RunningApp.windowId(index) is now windowHandle(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's browser export 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 to setErrorHandler (by default console.error) without
    stopping the app.
  • Added promise helpers: app.once(name), state.changed(), the
    state.changes() async iterator, and running.idle() to wait for async
    callbacks in tests. App.run and listeners take an AbortSignal.
  • app.on returns a Subscription; it and StateSubscription are
    disposable with using.
  • Builders such as Window.root() and App.window() return their object for
    chaining; Point, Size, Rect, and Color have equals and toString;
    added Color.rgba, Color.black, Color.white, version, and
    RunningApp.saveScreenshot.
  • Fixed rebuildOnChange, which rendered nothing, and custom widget event
    callbacks that return nothing, whose context requests were dropped.
  • A virtual table's selected state 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:test suite 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
    runs twine 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_pumped and PumpedDesktop, 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_web and with_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. Added RegisteredFont::try_from_bytes, which checks the data,
    and RegisteredFont::family_name; font_bytes and register_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 run before the
    window is destroyed, which left it on screen until the process exited.
  • ContextMenu keeps 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.
  • VirtualTable publishes 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 --release for the JavaScript package when
    wasm-opt is installed or WASM_OPT is 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_TIMINGS is 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-flat and scroll-retained fixtures to sui-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 ...
Read more

SUI 0.4.1

Choose a tag to compare

@moeinfinityx moeinfinityx released this 04 Oct 14:10

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, and TaskHandle for background work with progress,
    results, errors, and stale-worker protection. refresh keeps the previous
    result visible while loading, cancellation restores it, and TaskHandle::run
    completes the task from a future on the application's executor.
  • Added batch to coalesce notifications, combine and combine_named to
    derive values from two to four observables, and changed().await to 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-write Arc updates with
    set_arc and modify_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 ScrollView and VirtualScrollView.
    Both expose on_offset_change and on_offset_change_with_ctx for 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-lucide remains 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

Choose a tag to compare

@moeinfinityx moeinfinityx released this 26 Sep 09:57

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-webview crate 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-nodes graph-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-demo node-editor workspace behind the
    default-enabled nodes feature, 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.2 to 0.3. Lucide keeps its
    independent 1.47.0 version and now depends on the 0.3 SUI family.
  • Event::RawMouseMotion and WindowEvent::Moved require handling in exhaustive
    event matches. Public widget appearance/configuration structs gained fields,
    including ControlPalette::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.