Repository navigation
Native Shell 0.4.0 fills out the unstyled component foundation with form controls, rich text and more chart marks; adds shader effects and transitions; runs web apps on the browser's own JavaScript engine; and gives the APIs apps use one consistent shape.
Upgrading from 0.3.x? This release includes breaking API changes. See the migration notes below before rebuilding your app.
Highlights
- Shaders across the UI. Draw a view's box with WGSL using
Shader, draw views and the whole screen through a program withShaderEffect,ShaderTransition,ScreenEffectandScreenTransition, and let pages and dialogs come and go through one withtransitionShader. All of it draws on macOS, iOS, Android, Windows, Linux and the web; the GPUI backend drawsShaderfills. (#517, #682, #763, #764, #765, #766, #767, #768, #769, #770) - A full set of form controls. Build forms and toolbars with
Select,Combobox,Slider,NumberInput,OtpInput,DatePicker,Calendar,TimeField,ColorPicker,Toggle/ToggleGroup,Toolbar,Link,Pagination,Avatar/AvatarGroupandAccordion. They provide behavior, state and accessibility; your app supplies their look. (#536, #585, #510, #534, #535, #598, #577, #621, #702, #624, #690, #706, #610) - Rich content and navigation. Edit documents with
RichEditor, a ProseMirror-style editor with tables; add a command palette withCommand, nested lists withTree, slides withCarousel, hover previews withHoverCardand scroll bars in your own look withScrollbar.TextViewtypesets formulas out of the box. (#494, #518, #785, #725, #722, #697, #579, #841) - More charts from
nsh/base/plot. ComposeBar,Pie,Arc,Sankey,Treemap,Dot,Cell,Rule,RadialLineandRadialGridmarks withPlotAxisandPlotLabel, color marks by category, plot against a second y scale, and move a plot's hover with the keyboard and screen readers. (#505, #501, #601, #867, #829, #861, #819, #596, #549, #599, #592, #839, #521) - Web apps on the browser's own engine. Every web app now runs on the browser's JavaScript engine, in development with hot updates too. The runtime loads its parts on demand, which takes the gallery's first load from 13.03 MB to 4.35 MB (4.01 MB to 1.41 MB gzipped), and published sites carry Brotli and gzip copies of their files. (#541, #603, #853)
- More of the system and the toolchain. Follow whether the app is in use with
lifecycle(), recognize speech withSpeech.starton macOS and iOS, read shipped files withfetchonasset:/URLs, and use WOFF and WOFF2 fonts with fallback alongfontFamilylists. Rust apps gain file dialogs, system paths, window and menu APIs andsvg(); an app's crate can register native components in its generated hosts; andnsh publish <package>signs an existing package again with another release key. (#747, 0520080, #746, #745, #773, #629, #674, #683, #886)
Performance and platform improvements
- Layout rounds to device pixels, frames that stay on their pixels stay unsent, and a subtree that moves by whole pixels skips its frame walk. Animation graphs evaluate each node once a frame and find interpolation segments by bisection. (#557, #617, #637, #588, #589, #590)
- Images load through one bounded pipeline on the desktops, taking peak memory from about 1.3 GB to about 370 MB when scrolling 1,000 remote photos as thumbnails on Linux. Pasting 474 KB of unbroken text into a multiline
Inputtakes 58 ms where it took 12 s on macOS, andDataTable,Editor,Select,Calendarand the input controls do less work as they scroll and take keys. (#674, #627, #622, #604, #638, #656, #817, #672) - iOS keeps focused inputs above the keyboard and launches on iOS 15 to 17, adds leading and SF Symbol bar buttons, draws backdrop blur behind a view's background, and draws system alerts and the
TabBarin the app's theme colors. (#821, #888, #809, #866, #742, #741) - Android fixes
wss://WebSockets, follows display density changes while the app runs, keeps its runtime classes in minified embedding apps, strips release libraries, and improves keyboard and input handling. (#530, #431, #639, #538, #714, #715, #717, #836) - macOS draws fades without redrawing their views, taking one app's memory footprint from 92 MB to 27 MB, and adds trusted web view input with
sendInputand web view downloads. Linux draws images at device pixels on fractional scales, Windows speeds up plots and gives the wheel to native components, and GPUI delivers files dragged in from other applications and adds see-through windows. (#877, #895, #743, #758, #834, #879, #712, #591, #876) - The web applies state styles, platform props and scroll views'
contentStyleandcontentClass, and passes every event payload field to the app. Selections stay intact across virtual list rows on every platform, arrow keys follow right-to-left layouts, and parts style witharia-expanded:anddata-*attributes.nsh testcompares values as Jest does. (#865, #885, #883, #892, #703, #797, #556, #815, #711)
Migrating from 0.3.x
0.4.0 gives each kind of API one shape: styles in CSS's properties, one unit per quantity, one object per event, objects as return values, on(event, listener) for listeners, and one way to report failures. The old forms are removed. (#495, #524, #533, #558, #593, #612, #651)
Move styling props into style and use CSS's shadows. Classes reach all of them too:
- <View style={{ shadowColor: "#000", shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.2, shadowRadius: 4 }} />
+ <View style={{ boxShadow: "0 2px 4px rgb(0 0 0 / 0.2)" }} />
- <Text style={{ textShadowColor: "#000", textShadowOffset: { width: 0, height: 1 }, textShadowRadius: 2 }}>…</Text>
+ <Text style={{ textShadow: "0 1px 2px #000" }}>…</Text>
- <Text numberOfLines={2} ellipsizeMode="middle" selectable>…</Text>
+ <Text style={{ numberOfLines: 2, textOverflow: "ellipsis-middle", userSelect: "text" }}>…</Text>
- <View pointerEvents="box-none" />
+ <View style={{ pointerEvents: "box-none" }} />
- <Image resizeMode="contain" />
+ <Image style={{ objectFit: "contain" }} />Every event handler takes one object, and mouse events carry the DOM's names:
- <Checkbox onChange={(checked) => …} />
+ <Checkbox onChange={({ checked }) => …} />
- <Input onChange={(text) => …} />
+ <Input onChange={({ value }) => …} />
- <Popover onOpenChange={(open, reason) => …} />
+ <Popover onOpenChange={({ open, reason }) => …} />
- onLayout={(bounds) => bounds.size.width}
+ onLayout={({ bounds }) => bounds.size.width}
- onScrollEnd={(offset) => …} // and the drag and momentum events
+ onScrollEnd={({ offset }) => …}
- onLoad={(size) => …} // Image
+ onLoad={({ size }) => …}
- onContentSizeChange={(size) => …}
+ onContentSizeChange={({ size }) => …}
- e.translationX, e.translationY, e.velocityX, e.velocityY, e.valueX, e.valueY // PanEvent
+ e.translation.x, e.translation.y, e.velocity.x, e.velocity.y, e.value?.x, e.value?.y
- keymap.bind("mod+k", (keystroke) => …)
+ keymap.bind("mod+k", ({ keystroke }) => …)
- onHoverIn={…} onHoverOut={…} onHoverMove={(e: HoverEvent) => …}
+ onMouseEnter={…} onMouseLeave={…} onMouseMove={(e: MouseEvent) => …}Functions return objects, options come as one object, and each element has a ref type of its own (ViewRef, InputRef, ScrollRef, ListRef, WebViewRef, VideoRef, NativeComponentRef):
- const finished = await value.timing(1); // and spring, decay, keyframes, play, start
+ const { finished } = await value.timing(1);
- const last = await value.stop();
+ const { value: last } = await value.stop();
- const id = await AlertDialog.show({ actions: [{ label: "OK" }] });
+ const { action } = await AlertDialog.show({ actions: [{ id: "ok", label: "OK" }] });
- const opened = await openUrl(url);
+ const { opened } = await openUrl(url);
- const count = await editor.replaceAll(text);
+ const { count } = await editor.replaceAll(text);
- if (await Image.prefetch(src)) …
+ await Image.prefetch(src); // rejects on failure
- Window.setTitleBar("hidden", 40);
+ Window.setTitleBar({ style: "hidden", height: 40 });
- net.connect(host, port);
+ net.connect({ host, port });
- let node: YNode;
+ let node: ViewRef;
- BackHandler.onBackPress(listener);
+ BackHandler.on("press", listener);
- const sub = host.on(name, listener); sub.remove();
+ const stop = host.on(name, listener); stop();Update these units and names:
- gestureState.vx // points per millisecond, also vy
+ gestureState.vx // points per second, also vy
- keyboardFrame().duration // seconds
+ keyboardFrame().duration // milliseconds
- viewAreaCoveragePercentThreshold: 50, itemVisiblePercentThreshold: 50
+ viewAreaCoverageThreshold: 0.5, itemVisibleThreshold: 0.5
- ImageSize
+ PixelSizeUse the websocket module's own connect, which ends reads cleanly:
- import { WebSocket } from "websocket"; const c = await WebSocket.connect(url);
+ import { connect } from "websocket"; const c = await connect(url);
- await c.read() // rejected on a clean close
+ await c.read() // null after a clean closeAlso update these APIs:
- Handle failures by rejection and
code: every function returning a promise rejects, a denied capability is anErrorwithcode: "ERR_ACCESS_DENIED",permissionandresource(fetchkeeps aTypeErrorwith the same fields), and platforms and quotas reportERR_FEATURE_UNAVAILABLE_ON_PLATFORMandERR_NSH_QUOTA_EXCEEDED.ClipboardandPickerreject where they are not granted, andnew WebSocketto a URL not granted fireserror, thenclose(1006). (#651) - Read
signalbesidecodeinprocess.run's output;codeisnullwhen a signal ended the child. (#651) - Handle
Clipboard.readImagerejecting over 48 MB and on Android, andClipboard.writeImagerejecting on Android. (#701) - Add
flexDirection: "column"to a view that setsdisplay: "flex"and stacks its children: that display lays them out in a row, as in CSS. (#495) - Use
start,end,marginStart,paddingEndand their relatives for sides that follow the direction:left,right,paddingLeft,textAlign: "left"and their relatives keep their side right to left, as in a browser. (#495) - Give
Windowframes the window's top-left corner, y down from the primary screen's top, on every platform (macOS used the bottom-left corner), and dropanchorTop. (#698) - Check
platform.desktoporplatform.idiom === "desktop"for the desktop idiom:idiomis"desktop"exactly whereplatform.desktopis true, andplatform.catalystis true under Mac Catalyst in every idiom. (#705) - Leave
focusableunset on views that are not Tab stops:focusable={true}makes any view one. (#503) - Expect arrow keys in
TabsandRadioGroup: only the group's stop is focusable, andTab'sonPressandRadio'sonChangealso fire when the keys move the focus. (#537) - Accept
(error, reset)in every function given asErrorBoundary'sfallback: each one is called, whatever parameters it declares. (#685) - Keep
ios={{…}}anddesktop={{…}}to their typed keys: an unknown key fails the type check. (#667) - Size elements in a component's slots yourself where they relied on stretching: a slot takes its element's own box, laid out as the component's item. (#606)
- Set your theme's
primaryto chooseTabBar's selected color, which now follows that token. (#741) - Use
nsh run --port <port>or--port 0to run apps side by side: a plainnsh runreplaces the NSH session on its port. (#428) - Add
--abi arm64-v8a,armeabi-v7a,x86_64tonsh package --target androidwhen you shipx86_64: the default isarm64-v8aandarmeabi-v7a, and--runstill addsx86_64on an x86_64 emulator. (#539) - On the web, call
await player.runModule(entryURL, { appId, capabilities, chunks })in place ofplayer.run(bytecode, …)on custom pages, and importList,Image,Canvas,WebViewandVideofromnshin place of their former module paths. App code runs in the page's realm, so browser APIs follow the browser's CORS, permission and secure-context rules. (#541, #603, #700) - In
nsh/test, importPickRequestin place ofPick, allow forapp.clockbeingnull, writetext:before literal text shaped like a selector prefix, handleERR_NSH_TEST_UNSUPPORTEDforopenoptions a--targetcannot honor, expect Jest'stoBeandtoEqual, and passnetwork: "live"for real sockets and WebSockets. (#684, #708, #710, #711, #719)
In Rust, update these as well:
- text(s).ellipsize_mode(EllipsizeMode::Middle).selectable(true)
+ text(s).text_overflow(EllipsizeMode::Middle).select_text()
- image(src).resize_mode(ResizeMode::Contain)
+ image(src).object_fit(ResizeMode::Contain)
- .on_hover_in(|_: &()| ..) .on_hover_out(|_: &()| ..) .on_hover_move(|e: &HoverEvent| ..)
+ .on_mouse_enter(|e: &MouseEvent| ..) .on_mouse_leave(|e: &MouseEvent| ..) .on_mouse_move(|e: &MouseEvent| ..)
- .action("OK") .cancel("Cancel") .destructive("Delete")
+ .action("ok", "OK") .cancel("cancel", "Cancel") .destructive("delete", "Delete")
- area().y0(0.0)
+ area().y0(AreaY0::from(0.0))
- Scale::Point, Scale::Linear { domain }
+ Scale::Point { reverse: false }, Scale::Linear { domain, reverse: false }
- nsh_core::element::ambient::watch_scroll
+ nsh_core::element::watch_scroll
- nsh-core = "0.3"
+ nsh-core = { version = "0.4", features = ["declarations"] } # where you read declarations- Take
Size<DevicePixels>inimage().on_load, and setViewability'sview_area_coverage_thresholdanditem_visible_thresholdasPercentage. (#524) - Pass
line_heightaLineHeight, and handlePrefetch'sResult<(), String>. (#495, #593) - Forward a generic helper's listener to
on_pressasIntoListener<PressEvent, M>. (#629) - Read
GridProps'xandyasProp<Option<Vec<f64>>>, and end fullEnvironmentstruct literals with..Default::default(). (#839, #747) - Build
nsh-platform-webwith itsbrowserfeature, and dropBundle::with_harden_bytecodeandharden_bytecode. (#603)
The compatibility baseline is still being prepared; 0.4.0 is not a frozen compatibility release.
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
- website: Fix links to the merged nsh page and the Chinese anchors by @huacnlee in #498
- core: Add the listbox and option accessibility roles by @madcodelife in #487
- macos: Open a context menu with no place where the pointer last was by @madcodelife in #491
- core: Let a view be a keyboard focus stop without taking presses by @madcodelife in #503
- cli: Open
nsh test --target macos's windows off the main screen by @madcodelife in #492 - examples: Import
InputPropsfromnsh/base, where #488 moved it by @madcodelife in #502 - core: Keep a component's bindings on an app's slot live by @madcodelife in #506
- ios: Apply stack changes that arrive while a modal opens or closes by @Cooooooker in #507
- web: Let a field in a draggable view take focus when pressed by @Cooooooker in #508
- base: Add
PieandArctonsh/base/plotby @madcodelife in #501 - base: Add RichEditor, a ProseMirror-style rich text editor by @huacnlee in #494
- cli: Preserve Wasm import keys when publishing JS snippets by @honsunrise in #500
- base: Add
Barwith band scales, stacks and grouped bars tonsh/base/plotby @madcodelife in #505 - base: Add
Slider, a value or a range picked along a track by @madcodelife in #510 - js: Keep a component's root condition from making the component again by @huacnlee in #514
- base: Rename the rich editor's TextStyle extension to RichTextStyle by @huacnlee in #515
- base: Fix RichEditor's list commands and add a bubble menu by @huacnlee in #516
- core: Measure a list's rows once the app's drawing of them arrives by @madcodelife in #504
- core: Let a Rust view's content of a nested component read its context by @madcodelife in #509
- ios: Let VoiceOver step elements with increment and decrement actions by @madcodelife in #493
- core: Style with CSS's properties in native forms, typed below TSX by @sunli829 in #495
- core: Add
Interactive::project_focusedfor a control's parts by @madcodelife in #512 - core: Add
Accessible::accessibility_elements_hiddenfor Rust elements by @madcodelife in #513 - core: Let a ref's focus() focus a pressable view by @madcodelife in #489
- base: Report a popup's open change before it opens or closes by @madcodelife in #511
- ios: Dismiss the keyboard of an input in a modal by @Cooooooker in #522
- base: Pick RichEditor's Mac or PC keys by the platform it runs on by @sunli829 in #523
- core: Give each quantity one unit across the APIs apps use by @sunli829 in #524
- core: Add Shader, a view whose box a WGSL shader draws by @huacnlee in #517
- gpui: Hold text typed ahead until the engine handles the key before it by @mwatts in #399
- web: Let a nested text's link take its press by @Cooooooker in #526
- cli: Build an app's development web runtime incrementally by @dXnSix in #429
- cli: Replace the previous development session on its port by @dXnSix in #428
- core: Repeat repeating gradients on macOS, iOS and Android by @madcodelife in #531
- core: Keep a JS-drawn row in its own cell when rows before it go by @madcodelife in #532
- docs: Check what canvases draw in compat scripts with
drawingsteps by @madcodelife in #490 - cli: Package only phones' ABIs into APKs, or the ones --abi names by @mengyinghu-sys in #539
- web: Keep a link's characters in their run by @Cooooooker in #528
- gallery: Make the Charts page a showcase built from plot parts by @madcodelife in #525
- core: Share object field decoders to reduce the web runtime by @huacnlee in #520
- android: Follow display density changes while the app runs by @dXnSix in #431
- base: Move between
TabsandRadioGroupitems with the arrow keys by @madcodelife in #537 - docs: Take nsh-base components' features from GPUI Kit, not only names by @madcodelife in #540
- macos: Fire the app's key bindings for keys
nsh testgives its window by @madcodelife in #527 - web: Run published apps in the browser JavaScript engine by @huacnlee in #541
- web: Load syntaxes on first use and serve small apps a lite runtime by @BeADre in #542
- gallery: Draw the checkbox's check and dash with one bold pen by @madcodelife in #544
- core: Name the mouse events as the DOM does, with one move event by @sunli829 in #533
- mobile: let a page take the system tab bar away by @Heyana in #441
- core: Stop the listeners of a region's replaced run from running by @vicanso in #465
- base: Add
NumberInput, a number typed in a field or stepped by @madcodelife in #534 - base: Give RichEditor Apple's keys in a browser on a Mac by @Cooooooker in #547
- android: Strip release libnsh.so before it goes into APKs by @mengyinghu-sys in #538
- base: Add tables to RichEditor, with merged cells, resizing and reordering by @huacnlee in #518
- base: Keep an input method's composition out of RichEditor's document until it commits by @Cooooooker in #543
- macos: Let nsh test's steps end before a scroll indicator fades by @madcodelife in #554
- base: Let
Area'sy0read a value of each row, making a band by @madcodelife in #550 - base: Add
OtpInput, a one-time code typed into one native field by @madcodelife in #535 - base: Keep text typed again after RichEditor's caret moves by @Cooooooker in #555
- base: Add
Select, a choice from a list of items by @madcodelife in #536 - base: Round
PieandArccorners and sweep them to new angles by @madcodelife in #551 - web: Send the mouse and drop events in the browser JavaScript engine by @madcodelife in #560
- gallery: Rebuild the shell on the approved design, a demo per element by @huacnlee in #545
- core: Round layout to device pixels instead of whole points by @mengyinghu-sys in #557
- web: Let embedding pages show dialogs over the whole window by @BeADre in #546
- core: Style a popup's trigger while it is open with aria-expanded: by @huacnlee in #556
- base: Add
PlotAxisto label a plot's edges with its scale's ticks by @madcodelife in #549 - web: Launch the browser once before the viewport dialog tests by @huacnlee in #566
- web: Move the caret past spaces typed at the end of a line by @Cooooooker in #565
- android: Fix wss:// WebSockets, which had no TLS crypto provider by @jt-wang in #530
- gallery: Count the RichEditor list test's numbers against the screen before by @madcodelife in #564
- base: Glide a plot's linear domains with
motion.updateby @madcodelife in #553 - base: Show RichEditor's mentions as their text instead of a blank by @Cooooooker in #571
- core: Pass every event one object by @sunli829 in #558
- base: Move a plot's hover with the keyboard and screen readers by @madcodelife in #521
- base: Type the text parts of
SelectandOtpInputwith text styles by @madcodelife in #583 - base: Group RichEditor's undo steps by time on the web by @Cooooooker in #568
- base: Keep a paste over the whole document under a character limit by @Cooooooker in #569
- web: Leave keys a shortcut takes out of an input's onKeyPress by @Cooooooker in #567
- cli: Paste in nsh test --target web by @Cooooooker in #573
- testing: Read a span's style with app.spanStyle on real hosts by @Cooooooker in #576
- test: Correct shifted keys and web keyboard events by @Cooooooker in #572
- examples: Keep the demos' panels their content's height in a narrow window by @madcodelife in #586
- base: Add
Combobox, one value or several from a searchable list by @madcodelife in #585 - web: Pass a video's
onLoaditssizein the browser JavaScript engine by @BeADre in #584 - base: Move a
PieorArcon from where it is drawn when changed again by @madcodelife in #594 - base: Label a
Pie's slices outside the ring with leader lines by @madcodelife in #595 - base: Add
reverseto the plot's scales, for bars from the top or right by @madcodelife in #587 - base: Scroll Editor rows into the views already made by @huacnlee in #604
- core: Return objects, and give each element a ref type of its own by @sunli829 in #593
- base: Add
Scrollbarfor scroll bars in the app's own look by @huacnlee in #579 - base: Color plot marks by category with an ordinal
colorScaleby @madcodelife in #592 - base: Add
DatePicker,CalendarandTimeField, as gpui-base's by @madcodelife in #598 - core: Fix text selection seams and a panic on disposed held props by @huacnlee in #615
- docs: Give the Chinese Scrollbar page the
#built-in-barsanchor by @madcodelife in #616 - desktop: Transition a text's color with
transition-colorsby @madcodelife in #602 - core: Lay a slot's content out in its component's layout by @madcodelife in #606
- core: Add group, region, tree roles, a pressed state and
aria-pressed:by @madcodelife in #609 - testing: Never let a looping animation hold a test's steps by @madcodelife in #613
- base: Add ColorPicker with an area, channel sliders, fields and swatches by @huacnlee in #577
- ci: Pass clippy 1.99 on the Android and Windows hosts by @jt-wang in #529
- mobile: Transition a text's color on iOS, Android and the web by @madcodelife in #608
- core: Keep frames that stay on their pixels from being sent again by @mengyinghu-sys in #617
- gallery: Make the sidebar's demos one stop of Tab, moved with Up and Down by @madcodelife in #605
- base: Add
RadialLineandRadialGridmarks for radar charts by @madcodelife in #596 - gallery: Animate the controls' state changes, in richer demos by @madcodelife in #611
- web: Pass input autofill hints to the browser by @burdygin in #570
- core: Find derived animated nodes by a hash of what made them by @dXnSix in #588
- core: Evaluate each animation node once a frame by @dXnSix in #589
- core: Find an interpolation's segment by bisection by @dXnSix in #590
- gallery: Make the popups' demos real scenarios, with motion by @madcodelife in #614
- core: Make every listener
on(event, l)returning a stop function by @sunli829 in #612 - base: Add
PlotLabelto draw texts at data points by @madcodelife in #599 - web: Keep calls into the runtime fast however many values an app holds by @huacnlee in #636
- core: Skip the frames of a subtree that moved by whole pixels by @huacnlee in #637
- base: Keep the Editor's search compiled while typing, and caret moves cheap by @huacnlee in #638
- website: Add App Stories at /apps from the nsh-showcases catalog by @huacnlee in #618
- android: Keep the runtime's classes when an embedding app is minified by @mengyinghu-sys in #639
- base: Move a huge DataTable as far as the finger on touch screens by @mengyinghu-sys in #628
- android: Lay text out at the pixel width layout gave it, within float noise by @mengyinghu-sys in #620
- base: Let popups leave with the app's exit motion, and say where they went by @madcodelife in #631
- base: Move DataTable's window row by row as it scrolls by @mengyinghu-sys in #622
- core: Give Rust apps file dialogs, system paths, window and menu APIs by @huacnlee in #629
- web: Run every web app on the browser's own JavaScript engine by @huacnlee in #603
- gallery: Make the Button and Input demos real scenarios, with motion by @madcodelife in #635
- gallery: List components alphabetically, after the primitives by @madcodelife in #600
- gallery: Make the pickers' demos real scenarios, with motion by @madcodelife in #633
- text: Measure long unbroken runs in multiline inputs in linear time by @sunfuze in #627
- web: Draw canvases and animated values again only when they change by @huacnlee in #640
- base: Add
ToggleandToggleGroup, buttons that stay pressed by @madcodelife in #621 - base: Draw DataTable's scroll bar above its rows by @huacnlee in #646
- web: Show dialogs over the page at the app's scale, see-through in dark by @huacnlee in #643
- web: Run a listener whose owner is gone, as QuickJS does by @huacnlee in #644
- core: Run a component's method called before its view is made, after by @huacnlee in #645
- examples: Draw the demos' check marks as SVG, not a "✓" glyph by @huacnlee in #647
- base: Hide RichEditor's placeholder where an input method composes by @BeADre in #642
- website: Show the Dialog demo's page sheet as tall as its content by @huacnlee in #650
- base: Add the
Sankeymark tonsh/base/plotby @madcodelife in #601 - base: Pick a date in one tap on phones, and span the sheet with the calendar by @madcodelife in #653
- gallery: Reach the sidebar's demos from its search in the test by @madcodelife in #641
- base: Let touches and the wheel on the Editor's text reach its scroll views by @huacnlee in #652
- docs: Link the Chinese Toggle page's keyboard note to its own section by @sunli829 in #655
- base: Reveal a
Collapsibleas it opens and closes, and addAccordionby @madcodelife in #610 - base: Name a rich editor's document JSON
getJSON, as Tiptap does by @madcodelife in #658 - base: Keep the input controls' typing and keys cheap by @madcodelife in #656
- web: Show the keyboard focus only as the app draws it by @huacnlee in #661
- web: Give the calendars local time's offset so date pickers open by @huacnlee in #660
- base: Keep a plot's hover and a slider's thumb under the pointer by @madcodelife in #654
- base: Take no presses anywhere in a hidden
Scrollbarby @madcodelife in #657 - base: Say a disabled
ColorPicker's parts are disabled by @madcodelife in #659 - base: Add
Link, which opens itshrefor lets the app route it by @madcodelife in #624 - docs: Let the unions apps read gain members, as apps handle the rest by @sunli829 in #664
- website: Give the storage test the player's helpers its imports name by @sunli829 in #668
- website: Darken the light theme's borders so cards and controls read by @huacnlee in #673
- web: Read local time's offset only when the calendars ask by @huacnlee in #663
- website: Draw the home hero as a galaxy whose stars presses steer by @huacnlee in #665
- website: State the documentation's license in the footer by @huacnlee in #666
- gallery: Make the gallery's and the website's controls flat by @huacnlee in #648
- core: Animate a reveal's layout only where it moves frames by @madcodelife in #669
- base: Remember finished plot appears in a
PlotAppearScopeby @madcodelife in #607 - base: Turn a calendar's months without making its days again by @madcodelife in #672
- gallery: Sweep the indeterminate bar natively, report tab spans cheaply by @madcodelife in #670
- core: Report every failure of what JS calls one way, with a stable code by @sunli829 in #651
- js: Type the props apps put in
ios={{…}}anddesktop={{…}}by @sunli829 in #667 - core: Load images and SVGs through one bounded pipeline; add
svg()by @huacnlee in #674 - ios: Let test steps settle while a focused input's caret blinks by @dXnSix in #677
- android: Recolor texts without boxing their color by @madcodelife in #671
- core: Let a Rust component's element take a test id, as TSX's testID by @sureshkrishnan-ai in #561
- rich_editor: Show compositions in the line, with steady candidates by @huacnlee in #686
- base: Place a tab list's indicator natively on the selected tab by @madcodelife in #687
- base: Let menu items be checked, with the app's mark before them by @madcodelife in #688
- web: Let a test's manual clock move without freezing the page by @sunli829 in #689
- android: Send test touches to the shown dialog's window by @dXnSix in #675
- ios: Type each key in tests once the one before it landed by @dXnSix in #676
- js: Make the generated declarations type-check with
skipLibCheckoff by @sunli829 in #684 - js: Call a function
ErrorBoundaryfallback whatever parameters it declares by @sunli829 in #685 - base: Add
Pagination, pages to move between with no look of its own by @madcodelife in #690 - docs: Show website demos at their real size, as tall as their content by @huacnlee in #691
- linux: Keep text selections across a virtual list's rows by @huacnlee in #692
- core: Give a Rust-filled slot's listeners to the element it holds by @madcodelife in #696
- desktop: Place a window by its top-left corner on macOS too by @sunli829 in #698
- base: Add
Toolbar, one stop of Tab whose arrows move between its items by @madcodelife in #702 - web: Stop serving the old alias modules, and name nsh's modules when one is missing by @sunli829 in #700
- runtime: Promise clipboard images only as URLs, and reject what cannot be read by @sunli829 in #701
- runtime: Export websocket's
connect, and end reads cleanly with the close code by @sunli829 in #707 - ios: Scroll in tests with a quicker finger by @dXnSix in #678
- android: Build again: pass over the design tokens command by @dXnSix in #681
- macos: Say text and canvases draw into content layers, not drawRect: by @ohdarling in #694
- engine: Read the memory footprint with task_info, public on iOS by @ohdarling in #695
- selection: Keep selections across virtual list rows on every platform by @huacnlee in #703
- docs: Link the Chinese toolbar page to its design guide section by @sunli829 in #720
- avatar: Add
AvatarandAvatarGroup, a picture with its fallback by @madcodelife in #706 - testing: Refuse a selector prefix nsh/test does not know by @sunli829 in #708
- core: Give "desktop" one meaning, with
platform.desktopby @sunli829 in #705 - testing: Keep a test's sockets and WebSockets off the network by @sunli829 in #719
- testing: Let waits move a manual clock, refuse what a --target cannot honor, and give clock null by @sunli829 in #710
- testing: Make expect compare values as Jest does by @sunli829 in #711
- android: Read a selection's rectangles six numbers at a time, as clippy asks by @dXnSix in #727
- android: Set a view's camera distance only when its perspective moves by @mengyinghu-sys in #721
- gpui: Show a canvas's latest frame when it changes on every frame by @dXnSix in #679
- web: Keep a component in an expression child when what it reads changes by @Cooooooker in #737
- cli: Find web.host when the entry is named without a directory by @Cooooooker in #736
- android: Hide the keyboard on a tap in a scroll view when the field is outside it by @jt-wang in #717
- list: Stop making rows again when items are added before them by @Cooooooker in #740
- android: Slide stack screens by whole pixels so their shadows stay cached by @mengyinghu-sys in #732
- macos: Cast a canvas's shadows the way their offsets point by @dXnSix in #680
- editor: Add gutter and overview ruler marks to decorations by @huacnlee in #693
- core: Add ShaderEffect, ShaderTransition, ScreenEffect and ScreenTransition on Shader by @dXnSix in #682
- text_view: Use the automatic underline position for links by @lurenjia534 in #713
- android: Keep an input's text field the size of its content box when the input shrinks by @jt-wang in #715
- android: Let a scroll view inside a pannable view scroll the drags it can take by @jt-wang in #716
- android: A readonly input keeps its selection by @jt-wang in #718
- android: Hide the keyboard on Keyboard.dismiss() after the field that showed it is gone by @jt-wang in #714
- core: Keep a text's rounded width from falling under its measured width by @LeeDashan in #724
- windows: Give the wheel to native components that want it by @WillisXue in #712
- popover: Keep a popover's backdrop under its popup on touch screens by @daydoing in #729
- android: Drop a node's events once its view is destroyed by @mengyinghu-sys in #738
- macos: Hide the hidden title bar's toolbar in full screen by @wheregmis in #755
- mobile: Color the TabBar's selected tab with the theme's primary by @jt-wang in #741
- mobile: Draw system alerts and action sheets in the app's theme colors by @jt-wang in #742
- js: Show a component given as a tooltip in development bundles by @WillisXue in #739
- web: Stop calling an engine that trapped, so its panic stays on screen by @daydoing in #735
- testing: Settle steps on a manual clock without waiting for quiet by @LeeDashan in #723
- gallery: Keep the charts' labels clear of each other and the grid by @madcodelife in #704
- carousel: Add
Carousel, slides on a native scroll view that can loop by @madcodelife in #722 - diff_view: Report the scroll position and where each change is by @Mr-1311 in #730
- android: Stamp the test agent's drag events with the time they are due by @dXnSix in #753
- core: Preserve diagonal resize cursor directions by @WillisXue in #749
- tree: Add
Tree, nested items in a virtual list with one Tab stop by @madcodelife in #725 - windows: Apply cursor changes while the mouse is still by @WillisXue in #751
- docs: Fix the Tree page's Chinese anchor and list Tree after Tooltip by @huacnlee in #772
- hover_card: Add
HoverCard, a card that opens while the pointer rests by @madcodelife in #697 - testing: Start scrolling a view into view where nothing takes the drag by @dXnSix in #752
- gallery: Type-check the Carousel and HoverCard tests with a nullable clock by @madcodelife in #778
- hover_card: Keep the card out of toolbars and accept endless delays by @madcodelife in #780
- tooltip: Accept a
delayofInfinityinstead of panicking by @madcodelife in #781 - web: Hide a field that shows nothing while an input method composes in it by @Cooooooker in #776
- gallery: Page with Previous and Next on phones, numbered pages on desktops by @huacnlee in #792
- macos: Draw a border that turns visible after it was transparent by @madcodelife in #783
- command: Add
Command, a palette whose items filter natively by @madcodelife in #785 - carousel: Settle slides in tree order, ignore stale rests, keep focus by @madcodelife in #790
- toolbar: Keep the demo's overflow menu in reach and test arrow order by @madcodelife in #789
- tree: Act on the row that shows for keys, focus and screen readers by @madcodelife in #786
- core: Re-sort order watches only for moves among their elements by @madcodelife in #788
- menu: Open a menu bar's menus on hover and keep popups clear of their trigger by @huacnlee in #791
- avatar: Give each
srcan image of its own and accept endless delays by @madcodelife in #782 - text: Keep color emoji upright in italic text by @Cooooooker in #779
- core: Retire Rust component views with their creating run by @yuezk in #762
- data_table: Let Rust apps make a DataTable's rows by @sureshkrishnan-ai in #562
- test: Run the compat checks again, the scripts caught up with main by @madcodelife in #662
- test: Check every Sankey prop and the plot scope's memory of appears by @madcodelife in #796
- roving: Swap the arrow keys in right-to-left layouts by @madcodelife in #797
- gallery: Open the menu bar's hover tests in a desktop-wide page by @madcodelife in #795
- core: Add
after_answer, run once the app has answered a component's events by @madcodelife in #798 - core: Make
focus-withinfollow any focus, popups included by @madcodelife in #801 - slider: Show the app's answer to a drag's last move when the drag ends by @madcodelife in #799
- web: Measure emoji as wide as the page draws them on high-density screens by @Cooooooker in #775
- core: Let a Button or other component in a slot take the slot's presses by @Cooooooker in #777
- ios: Size header items with Auto Layout, and add leading and SF Symbol bar buttons by @huacnlee in #809
- tree: Report
onActionon Return over a leaf and on a double press by @madcodelife in #805 - web: Measure figures with the kerning of their character pairs by @Cooooooker in #800
- combobox: Type into the trigger and open lists the trigger's width by @huacnlee in #793
- docs: Update README to simplify installation instructions by @huacnlee in #811
- text: Grow a line for an inline view taller than the line height on Apple by @huacnlee in #810
- hover_card: Stay open while the keyboard focus is in the trigger or card by @madcodelife in #802
- testing: Run a desktop platform's apps as desktops on --target web by @madcodelife in #808
- core: Tell apps whether they are in use by @dXnSix in #747
- text: Center inline chips on the text and keep line spacing even on Apple by @huacnlee in #816
- cli: Let an app's Rust crate register native components in its hosts by @WillisXue in #683
- data_table: Retarget the scroll anchor when a drag ends at the top by @akongG in #814
- linux: Place inline attachments on device pixels and align them to the text by @huacnlee in #812
- compat: Catch the Combobox steps up with typing into the trigger by @madcodelife in #818
- engine: Let fetch read the files the app ships by @dXnSix in #746
- text: Read WOFF and WOFF2 fonts by @dXnSix in #745
- text: Fall back along fontFamily lists by @dXnSix in #773
- core: Place popups against a TSX trigger's own box, as a Rust one's by @madcodelife in #807
- core: Style parts by
data-*attributes components give them by @madcodelife in #815 - engine: Give the asset tests' engines the speech field they now need by @dXnSix in #822
- select: Draw list, segment and calendar items once, their states as classes by @madcodelife in #817
- macos: Save web view downloads to the app's data directory by @wheregmis in #758
- text: Parse fontFamily lists with font_families on every platform by @huacnlee in #820
- macos: Press pressable views from AXPress, as Return does by @0xbentang in #794
- core: Make three tests' path fixtures pass on Windows by @WillisXue in #787
- plot: Add per-row
Barbases and theRulemark by @madcodelife in #819 - testing: Keep scrolling into view after a gesture that moves nothing by @dXnSix in #754
- carousel: Spring back a swipe the app refuses, and count focus in the slides by @madcodelife in #824
- select: Name the search field for screen readers with
searchAccessibilityLabelby @madcodelife in #825 - command: Name the search field apart from the list with
searchAccessibilityLabelby @madcodelife in #826 - macos: Report the hidden title bar's height right after a resize by @madcodelife in #830
- text: Refuse WOFF fonts whose tables declare more than a font may hold by @dXnSix in #823
- linux: Draw images at device pixels on fractional scales by @huacnlee in #834
- plot: Add the
Dotmark for scatter and bubble charts by @madcodelife in #829 - compat: Find the Command row by its label now that parked cells are skipped by @madcodelife in #832
- ios: Keep focused inputs above the keyboard and move with it by @huacnlee in #821
- otp_input: Mark filled cells with
data-filledby @madcodelife in #837 - button: Add
hitSlop, so a small button takes presses near it by @madcodelife in #838 - diff_view: Place file headers below wrapped rows by @huacnlee in #827
- android: Hide the keyboard with a page the app pops or a dialog it closes by @huacnlee in #836
- web: Draw underlines unbroken and clear of the text by @huacnlee in #850
- examples: Open the gallery at one demo and section with cargo run -- by @huacnlee in #851
- bundler: Warn about an ungranted host only when the app calls it by @huacnlee in #852
- plot: Add a second y scale for dual-axis charts by @madcodelife in #839
- gallery: Hover the risk-return plot again after changing its period by @madcodelife in #840
- link: Add
hitSlop, so a small link takes presses near it by @madcodelife in #845 - switch: Add
hitSlop, so a small switch takes presses near it by @madcodelife in #846 - checkbox: Add
hitSlop, so a small checkbox takes presses near it by @madcodelife in #847 - radio: Add
hitSlop, so a small radio takes presses near it by @madcodelife in #848 - toggle: Add
hitSlop, so a small toggle takes presses near it by @madcodelife in #849 - compat: Go back to the gallery's index between its demos by @madcodelife in #854
- color_picker: Mirror the area and horizontal sliders right to left, keys too by @madcodelife in #855
- tree: Swap Left and Right in a right-to-left layout by @madcodelife in #856
- docs: Keep the developer docs to what contributors work with by @huacnlee in #859
- web: Load the runtime's parts on demand, split into side modules by @huacnlee in #853
- website: Publish every release's documentation beside main's by @huacnlee in #862
- plot: Add the
Cellmark for heatmaps by @madcodelife in #861 - macos: Let web views take trusted input with sendInput by @wheregmis in #743
- desktop: Show the pointer over links in selectable text by @huacnlee in #842
- desktop: Keep a nested scroll view's bar in the visible part by @huacnlee in #858
- linux: Hide the placeholder and caret while an input method composes by @huacnlee in #844
- js: Keep list separators alive across data updates by @huacnlee in #828
- web: Let the size check and clippy pass with the runtime's side modules by @huacnlee in #863
- plot: Add the
Treemapmark for market maps and allocations by @madcodelife in #867 - gallery: Keep the drawdown's low label clear of its line by @madcodelife in #868
- ios: Draw backdrop blur behind a view's background, gradient and shadows by @twosugar in #866
- diff_view: Give wide characters two columns and line numbers their full width by @huacnlee in #864
- linux: Keep window controls centered in custom title bars by @yuezk in #857
- macos: Reduce app memory by not redrawing views on fades by @huacnlee in #877
- windows: Fix plot performance on Windows. by @huacnlee in #879
- web: Package apps whose Rust crates call JS through wasm-bindgen by @LVtomatoJ in #870
- web: Apply state styles and accept page header styles by @chaxus in #865
- ios: Launch on iOS 15 to 17 by defining
isEditableon the text view by @madcodelife in #888 - text_view: Typeset formulas when the app gives no
renderMathby @huacnlee in #841 - gallery: Make the editor demo's hover card a slim editor-style panel by @huacnlee in #878
- core: Let pages and dialogs come and go through a shader by @dXnSix in #763
- gallery: Show shader effects and transitions on the Shaders page by @dXnSix in #771
- macos: Draw shader effects, transitions and page shaders by @dXnSix in #764
- ios: Draw shader effects, transitions and page shaders by @dXnSix in #765
- android: Draw shader effects, transitions and page shaders by @dXnSix in #766
- web: Draw shader effects, transitions and page shaders by @dXnSix in #767
- windows: Draw shader effects, transitions and page shaders by @dXnSix in #768
- web: Apply the web's and the desktop's platform props by @chaxus in #885
- linux: Draw shader effects, transitions and page shaders by @dXnSix in #769
- gpui: Draw only shader fills: effects show their children, transitions change at once by @dXnSix in #770
- ios: Keep a view's backdrop blur below its background when it clips by @dXnSix in #882
- input: Hide the placeholder while composing and fit the caret to the text by @huacnlee in #889
- gpui: Add AppOptions::transparent for see-through windows by @sureshkrishnan-ai in #876
- web: Show an app's own component given as a tooltip under nsh run by @chaxus in #887
- gpui: Stop blinking the caret in hidden windows and after ten seconds on Linux by @sureshkrishnan-ai in #875
- gpui: Resize the window on Window.setFrame by @sureshkrishnan-ai in #872
- cli: Let
nsh publishsign a package again with another release key by @ohdarling in #886 - gpui: Deliver files dragged in from other applications by @UncertaintyDeterminesYou4ndMe in #591
- web: Apply a scroll view's contentStyle and contentClass by @chaxus in #883
- macos: Stop checking every out-of-sight view on each frame by @madcodelife in #895
- input: Apply lineHeight to multiline text on Linux by @huacnlee in #891
- web: Pass every event payload field to the app by @madcodelife in #892
- core: Give text inside an inline view the color of the text around it by @madcodelife in #894
- text: Grow a line for an inline view taller than the line height everywhere by @madcodelife in #893
- release: Prepare version 0.4.0 by @huacnlee in #884
New Contributors
- @BeADre made their first contribution in #542
- @jt-wang made their first contribution in #530
- @burdygin made their first contribution in #570
- @sunfuze made their first contribution in #627
- @sureshkrishnan-ai made their first contribution in #561
- @lurenjia534 made their first contribution in #713
- @WillisXue made their first contribution in #712
- @daydoing made their first contribution in #729
- @wheregmis made their first contribution in #755
- @Mr-1311 made their first contribution in #730
- @yuezk made their first contribution in #762
- @akongG made their first contribution in #814
- @0xbentang made their first contribution in #794
- @LVtomatoJ made their first contribution in #870
- @chaxus made their first contribution in #865
- @UncertaintyDeterminesYou4ndMe made their first contribution in #591
Full Changelog: v0.3.0...v0.4.0