Skip to content

nsh v0.3.0

Latest

Choose a tag to compare

@github-actions github-actions released this 26 Oct 12:51
· 74 commits to main since this release
76fa8a7

Native Shell 0.3.0 expands the unstyled component foundation with editors, tables, dockable workspaces and charts; improves layout, scrolling and animation; and brings a simpler module structure to Rust and TSX apps.

Upgrading from 0.2.x? This release includes breaking API changes. See the migration notes below before rebuilding your app.

Highlights

  • Editors and data-heavy interfaces. Build code editing and review tools with Editor and DiffView, large tables with DataTable and Table, and dockable workspaces with DockArea, ResizablePanelGroup and ResizablePanel. These components provide behavior and state; your app supplies their look. (#321, #452, #458)
  • More UI building blocks. Add expandable content with Collapsible, task progress with Progress, notifications with Toast / ToastStack / ToastManager, and charts with Plot, Line, Area and Grid from nsh/base/plot. (#347, #352, #386, #403)
  • Richer motion and scrolling. Compose keyframes, motion presets and createMotion; use sticky positioning and animated sticky offsets; load more items at the start of a list; and draw custom pull-to-refresh indicators. Desktop and iOS animations now draw at the display’s refresh rate. (#387, #374, #376, #369, #433, #436)
  • Closer integration with embedding apps. Exchange messages through the host channel, route external URLs through the host, override embedded theme tokens on mobile, and use the system tab bar through TabBar from nsh/mobile. (#378, #388, #377, #423)
  • More resilient screens and images. Isolate rendering failures with ErrorBoundary, pick photos as native files, display data: and blob: image sources, position images with objectPosition, and reuse downloaded images from disk across launches. (#370, #390, #375, #371, #383)

Performance and platform improvements

  • Layout updates visit only the parts a change can move, unchanged text measurements avoid repeated layout, and lists bind visible rows before pacing their overscan. (#368, #410, #328)
  • iOS gains Liquid Glass, selectable system materials for backdrop blur, sharper images on 3× screens, and fixes for swipe-back navigation and keyboard interaction. (#338, #359, #362, #430, #443)
  • Android adds armeabi-v7a runtime builds and 16 KB page-size alignment, with fixes for back handling, native component cleanup and text input. (#420, #422, #341, #340, #421, #480)
  • Desktop and web fixes improve scrolling, focus, shortcuts, text rendering and accessibility. nsh check and nsh test now also run Cargo checks and tests for apps with Rust crates. (#327, #302, #322, #405, #434)

Migrating from 0.2.x

0.3.0 gives each API one home: primitives, environment and capabilities in nsh; unstyled functional components in nsh/base; and platform-specific APIs in nsh/mobile and nsh/desktop. The old import paths are removed. (#488)

- import { Clipboard } from "nsh/clipboard";
+ import { Clipboard } from "nsh";
- import { Input, type InputProps } from "nsh";
+ import { Input, type InputProps } from "nsh/base";
- import { Keyboard, safeAreaInsets } from "nsh/base";
+ import { Keyboard, safeAreaInsets } from "nsh";
- import { BackHandler } from "nsh/android";
- import { InputAccessoryView } from "nsh/ios";
+ import { BackHandler, InputAccessoryView } from "nsh/mobile";

The former nsh/animated, nsh/device, nsh/gesture, nsh/clipboard, nsh/host, nsh/picker, nsh/storage, nsh/keymap, nsh/native, nsh/accessibility, nsh/image, nsh/list, nsh/canvas, nsh/webview and nsh/video exports now come from nsh.

Use CSS environment values for safe-area and keyboard spacing, and View selectable for text selection:

- <SafeAreaView edges={["top"]}>…</SafeAreaView>
+ <View style={{ paddingTop: "env(safe-area-inset-top)" }}>…</View>
- <KeyboardAvoidingView behavior="padding">…</KeyboardAvoidingView>
+ <View class="pb-[env(keyboard-inset-height)]">…</View>
- <SelectionArea>…</SelectionArea>
+ <View selectable>…</View>

Also update these APIs:

  • Pass a Tooltip element to tooltip in place of a string.
  • Use Toast / ToastManager from nsh/base in place of Android’s Toast.show.
  • Use platform.os in place of the former iOS / Android isAvailable exports.
  • In Rust, replace nsh_core::ui imports with nsh_core::element, use nsh_core::prelude, and rename element::element to element::builder. Use nsh_base::{nav_stack, nav_page, dialog, alert_dialog} for navigation and dialogs.

The compatibility baseline is still being prepared; 0.3.0 is not a frozen compatibility release. (#496)

Downloads

Prebuilt toolchains are available below for macOS Apple Silicon, Linux x86_64 and Windows x86_64, alongside the iOS and Android embedding SDKs. Each archive has a .sha256 checksum file.

Documentation and live demos · Full changelog

All merged pull requests

What's Changed

  • ci: Supply the Docker API required by the LayerFS trial by @huacnlee in #334
  • website: Use Switch and Tabs where demos and docs built them from Button by @madcodelife in #345
  • core: Give the views of a hidden subtree no frames by @sunli829 in #346
  • ci: Check web packages where the CLI writes them in the Homebrew test by @huacnlee in #343
  • docs: Explain local LayerFS workspace reuse by @huacnlee in #342
  • core: Round layouts in the core instead of Taffy's rounding pass by @sunli829 in #348
  • base: Add Collapsible, a region whose content expands and collapses by @madcodelife in #347
  • android: Wait for the overscroll stretch before a test presses by @mengyinghu-sys in #349
  • cli: Let Rust apps opt in to Linux web views by @huacnlee in #350
  • gpui: Let the app's shortcuts reach it while a native component has focus by @mwatts in #307
  • ci: Add a direct LayerFS development command by @huacnlee in #354
  • web: Show local times in the browser's time zone by @twosugar in #335
  • android: Take the back key where OnBackInvokedCallback is not in effect by @mengyinghu-sys in #341
  • android: Destroy native components when their app stops by @mengyinghu-sys in #340
  • xtask: Pass compat record its version instead of Cargo's target dir by @huacnlee in #357
  • js: Check requestAnimationFrame and cancelAnimationFrame in compat by @huacnlee in #356
  • base: Add Progress, a linear progress bar by @madcodelife in #352
  • ios: Decode images at the screen's scale so they stay sharp on 3x screens by @Cooooooker in #362
  • core: Give each engine a context its UI sets' functions read by @mwatts in #300
  • gpui: A field the app focuses takes the window's keyboard by @mwatts in #314
  • ios: glassEffect draws Apple's Liquid Glass by @ohdarling in #338
  • testing: Run headless apps under their nsh.json capabilities by @twosugar in #336
  • core: Keep JS's shortcuts when the first Rust component binds its own by @mwatts in #308
  • base: Add DockArea and Resizable, gpui-base's dock and resizable panels by @huacnlee in #321
  • core: Press events carry where the pointer was by @mwatts in #313
  • engine: Give the gallery scroll benchmark the nsh/base UI set by @dXnSix in #325
  • core: Show data: URIs and blob: URLs in Image on every backend by @huacnlee in #375
  • ci: Build the distribution only on tags and by hand by @sunli829 in #366
  • cli: Show the compiler's errors when a test's app fails to build by @huacnlee in #367
  • macos: Scroll by layer transform, commit bounds at rest by @hexuria in #327
  • core: Let images choose where they sit in their box with objectPosition by @huacnlee in #371
  • ios: Choose the system material for backdrop blur by @ohdarling in #359
  • core: maskImage fades a view out along a gradient by @ohdarling in #361
  • core: Let views stick with position: sticky in the scroll view around them by @dXnSix in #374
  • core: Keep app-written image keys out of the shared caches by @huacnlee in #382
  • core: Make room for 128 event kinds by @huacnlee in #384
  • testing: Move a manual clock through a long press's hold on real platforms by @huacnlee in #381
  • core: Serve a UI set's submodules under paths of its specifier by @madcodelife in #400
  • core: Let Rust components take rows of data typed by the app by @madcodelife in #402
  • gpui: Build the backend's tests again by @huacnlee in #396
  • windows: Build again after inline image sources left a parameter unused by @huacnlee in #395
  • ios: Let VoiceOver's escape gesture close menus and popovers by @huacnlee in #380
  • js: Add ErrorBoundary, so one failing part of a view keeps to its part by @huacnlee in #370
  • testing: Leave the cells a list parked out of what selectors match by @huacnlee in #365
  • tailwind: Make every class mean what it means in a browser by @dXnSix in #323
  • gpui: Let an embedding app own its window, its quit and its menu bar by @mwatts in #302
  • gpui: Let a menu item leave a focused field the keys it uses by @mwatts in #306
  • core: Measure a line of text and name the parts a canvas draws by @mwatts in #316
  • website: Present NSH as a Rust-first native UI framework for every platform by @huacnlee in #407
  • core: Lay out only what a change can move on large pages by @sunli829 in #368
  • docs: Start the compatibility contract at 0.3.0 by @sunli829 in #406
  • core: Lay nothing out again for a text that measures as before by @sunli829 in #410
  • core: Bind a list's visible rows first and pace its overscan by @hexuria in #328
  • mobile: Fire the app's keyboard shortcuts from a hardware keyboard by @huacnlee in #373
  • mobile: Let host apps override the embedded app's theme tokens by @huacnlee in #377
  • runtime: Add nsh/host for calling functions of the embedding host by @twosugar in #337
  • runtime: Add nsh/picker to let users pick photos as native files by @huacnlee in #390
  • ios: Let a tap press the trigger of a context menu by @huacnlee in #364
  • video: Add audioSession, for sound that plays with the ringer silenced by @hanxuanliang in #339
  • core: Load more at a list's start with onLoadMoreAtStart by @huacnlee in #369
  • ios: Give a pushed screen its stack's size right away by @ohdarling in #413
  • engine: Let embedding apps and their modules talk through a host channel by @huacnlee in #378
  • macos: Report the requested title-bar height for our own toolbar by @hexuria in #329
  • Revert "macos: Report the requested title-bar height for our own toolbar" by @huacnlee in #418
  • runtime: Open URLs outside the app, letting embedding apps route them by @huacnlee in #388
  • testing: Let tests play the embedding app and record the URLs opened by @huacnlee in #391
  • core: Press events carry the modifier keys and the click count by @mwatts in #392
  • ios: Inset a screen by a side bar only where its stack meets it by @ohdarling in #416
  • core: Add keyframes, motion presets and createMotion to animations by @huacnlee in #387
  • core: Keep downloaded images on disk across launches on every backend by @huacnlee in #383
  • core: Keep a moved child in its children_each wrapper by @huacnlee in #393
  • js: Keep a component's keyed children across updates by @huacnlee in #394
  • web: Fix tabular-nums widths, CJK line starts and generic font families by @ihavecoke in #322
  • android: Build the runtime for armeabi-v7a as well by @mengyinghu-sys in #420
  • android: Restore input text selection after window attachment by @Areo-Joe in #421
  • android: Align native runtimes for 16 KB page sizes by @Areo-Joe in #422
  • ios: Draw the trailing header button with UIKit's own by @Heyana in #419
  • base: Add Toast, ToastStack and ToastManager, gpui-base's toasts by @huacnlee in #386
  • core: Let sticky views and headers stick at an animated offset by @dXnSix in #376
  • core: Report where an input's caret is with onCaretMove by @huacnlee in #379
  • windows: Bound translucent views' layers and fade single shapes without one by @LeeDashan in #408
  • cli: Sign apps under wildcard profiles with their bundle id by @huacnlee in #426
  • gallery: Let iOS draw the theme button in the navigation bar by @huacnlee in #427
  • core: Let a diffClamp settle a floating bar fully shown or hidden by @dXnSix in #389
  • mobile: Add nsh/mobile with the system's tab bar by @Heyana in #423
  • web: Let scroll commands win over a wheel or key scroll in flight by @dXnSix in #398
  • gallery: Add a header that collapses to a bar as the page scrolls by @dXnSix in #397
  • cli: Run cargo check and cargo test for apps with Rust crates by @huacnlee in #434
  • core: Hide spare list cells from screen readers and touches by @dXnSix in #404
  • desktop: Hide views with visibility: hidden from screen readers by @dXnSix in #405
  • ios: Restore swipe back with hidden navigation headers by @huacnlee in #439
  • docs: Clarify component design goals and platform boundaries by @huacnlee in #440
  • testing: Read a span's resolved style by @mwatts in #317
  • web: Preserve unsigned shortcut IDs across WebAssembly by @honsunrise in #372
  • core: Move what makes room for the keyboard with the keyboard by @huacnlee in #425
  • ios: Restore headerless swipe back and dismiss editing during swipes by @Cooooooker in #430
  • base: Let bottom sheets follow downward drags by @Cooooooker in #435
  • core: Draw animated pages at the display's rate on every desktop and iOS by @huacnlee in #436
  • macos: Draw a canvas at once unless it paints often by @vicanso in #444
  • core: Add SVG paint properties for what Rust components draw by @madcodelife in #401
  • macos: Align single-line input placeholders with the editor by @Areo-Joe in #455
  • ios: a page's scroll view no longer takes the edge swipe, or moves sideways by @Heyana in #443
  • windows: Let the split canvas test allow the rasterizer's rounding by @huacnlee in #456
  • core: Keep Each rows whose root is a dynamic region by @huacnlee in #451
  • base: Apply typed TextView root styles before app overrides by @huacnlee in #450
  • base: Add the Editor and DiffView components by @huacnlee in #452
  • base: Expect the Editor's deprecated warning to be struck and underlined by @huacnlee in #459
  • base: Line up the Editor's selections and links with its text by @huacnlee in #460
  • ios: judge a scroll view's content width once the batch is in place by @Heyana in #457
  • base: Show the Editor's line numbers in whole points on every platform by @huacnlee in #462
  • base: Keep the Editor fast with a hundred thousand diagnostics by @huacnlee in #464
  • testing: Press the matched view on real platforms, not its button's middle by @huacnlee in #466
  • desktop: Report where presses land, their modifiers and click count by @huacnlee in #453
  • core: Check an input's pasteBehavior in the compat events case by @huacnlee in #442
  • base: Add DataTable and Table, as gpui-component's by @huacnlee in #458
  • gallery: Keep the Editor demo responsive on files of 200K lines by @huacnlee in #463
  • core: Let apps draw their own pull-to-refresh indicator by @alexwan02 in #433
  • core: Add hit testing to the text engines by @zerx-lab in #424
  • core: Default the row type of generic props to any by @madcodelife in #468
  • core: Let components call the app's functions of their rows by @madcodelife in #469
  • core: Take springs and timings as props of Rust components by @madcodelife in #470
  • core: Send no empty drawing to a canvas that has drawn nothing by @madcodelife in #471
  • core: Declare a component method's trailing Option parameters optional by @madcodelife in #472
  • macos: Draw text that overflows an ancestor that does not clip by @madcodelife in #476
  • testing: Decode test steps' floats whatever serde_json's features by @madcodelife in #477
  • js: Read the app's theme tokens in the first render by @madcodelife in #478
  • android: Center an input's text on phones whose fonts fall back taller by @huacnlee in #480
  • website: Share one button and field style across the demos by @madcodelife in #481
  • examples: Use nsh/base's controls where the examples built their own by @madcodelife in #482
  • website: Give every pressable in the demos its hover, press and focus states by @madcodelife in #483
  • core: Let native component props follow animated values by @mengyinghu-sys in #479
  • base: Add Plot, Line, Area and Grid by @madcodelife in #403
  • chore: Extract shared internal nsh-gallery-ui and keep DataTable headless by @huacnlee in #486
  • core: Give every API one home in nsh, nsh/base and nsh/mobile by @huacnlee in #488
  • release: Prepare version 0.3.0 by @huacnlee in #496
  • base: Let nsh-base publish before nsh-js by @huacnlee in #497

New Contributors

Full Changelog: v0.2.0...v0.3.0