Test and ship

Upgrade notes

Move a Tooee 0.12 app to 0.13, a Tooee 0.9 app to 0.12, and a Tooee 0.8 app to 0.9.

bun add @tooee/view@^0.13.0 @opentui/core@^0.5.12 @opentui/react@^0.5.12

Upgrade every @tooee/* package to the same version. Each section lists the changes you can meet on the way, newest first.

Upgrade from 0.12 to 0.13

Read the value in onSubmit or onConfirm

Enter in Ask always calls onSubmit, and Enter in Choose always calls onConfirm. launch() from @tooee/ask and @tooee/choose now resolves with the value. Before, an action with the id submit took the place of the callback, and launch() resolved null. That action is now an ordinary command that runs from the palette or from its own hotkey. Move code that read the value in a submit action into onSubmit or onConfirm. Ask and Choose show the callbacks.

Expect ctx.exit() to close the app

The command context now uses the renderer's destroy as the default exit. ctx.exit() closes View and every launchCli app, where it did nothing before. A context source can still supply its own exit, as Ask and Choose do.

Move off the old directory keys

In the directory view, dir.next-file is now g n and dir.prev-file is g p. h and l only scroll wide blocks and diffs. To keep the old keys, set "dir.next-file": "l" and "dir.prev-file": "h" in keys.

Use @tooee/panels for panel overlays

OverlayRole is now "modal" | "passive". An overlay opened with role: "panel" never became active, and TypeScript now rejects it. Use PanelGroup and Panel from @tooee/panels for panel surfaces.

Check the router context from useRouter()

RouterProvider accepts a router made with createRouter({ context }). In return, useRouter() now returns RouterInstance<unknown>. Check useRouter().context before you use it.

Expect fallback q and r on route pending and error screens

Inside a CommandProvider, the router registers q (quit) and r (retry, error screen only) while a pending or error component shows. An app that binds those keys at the root keeps its own commands, because they register first. Routing describes the fallbacks.

Expect a config write to keep unknown keys

writeGlobalConfig now keeps keys that Tooee does not know. When the global config file is not valid JSON, the write leaves the file unchanged. Before, the write replaced it.

Check the result of copyToClipboard

copyToClipboard from @tooee/clipboard now resolves true or false. Copy commands show an error toast when no clipboard tool is installed. Code that typed the result as void still works.

Expect a one-row status bar

The status bar and the title bar no longer wrap onto a second row. When the items do not fit, the bar hides the items with the lowest priority first and shows ⋯. DocumentScreen now puts Mode: and Cursor: at the right edge, and Cursor: shortens to Ln on a narrow bar. Your statusItems default to the lowest priority after key hints, so give an item a priority from StatusPriority to keep it in view. Update frame snapshots of narrow screens, and tests that expect Mode: after your items. Items with only label and value look the same as before when they fit. Status bar lists the fitting rules.

Expect Escape to close an owned modal

dismissOnEscape now works on a modal overlay with its own command surface. Before, it had no effect there, so each modal registered its own Escape. Those commands still run first, so you can keep them or remove them. Overlays, dialogs, and toasts describes the order.

Expect n and N to land on selectable rows

In a nav-search store, n and N now move to the nearest row that isSelectable accepts. Before, they put the cursor on the match index. A match function that already returns only selectable rows behaves the same.

Check which project theme wins

When two .tooee/themes/ folders hold a theme with the same name, the folder nearest to the working directory now wins, as it does for config files. Before, the folder higher up the tree won.

Check custom themes for the search highlight keys

Themes gain searchMatchBg, searchCurrentMatchBg, searchMatchFg, and searchCurrentMatchFg. A theme that leaves them out gets values derived from warning and primary, so match rows look softer than before. Set the keys to keep the old full colours. Themes lists the derived values.

The onCancel prop of SearchBar is now optional and deprecated. The bar never calls it. Escape cancels through the search-cancel command.

Write + as a hotkey

The hotkey parser now accepts "+", "ctrl++", and + as one step of a sequence such as "z +". Before, "+" parsed to an empty key and never fired. "plus" still works.

Upgrade from 0.9 to 0.12

Install OpenTUI 0.5.12 or later

Every @tooee/* package now declares @opentui/core and @opentui/react ^0.5.12 as peers. Raise both in your package.json when you pin an older 0.5 release. Tooee builds and tests with React 19.3; the react peer range is unchanged.

The CLI installs OpenTUI and React as its own dependencies since 0.10.2. A global install of @tooee/cli needs no separate runtime packages.

Expect heading rows to copy the heading line alone

Markdown parsing moved to marked 18. A heading row in the Markdown view now searches and copies as the heading line, without the blank lines after it. Update tests or scripts that compare the text of a copied heading.

Expect documents to keep their scroll position

A document built on useDocumentController no longer scrolls back to the cursor row when its rows change. A wheel-scrolled view stays where it is while rows stream in or update. The view still follows the cursor when the cursor moves. Pass followTail: true for a log that stays on its newest row, or call revealRow to scroll a row into view. Documents covers both.

g g and G now scroll their row back into view when the cursor is already on it. The nav-search store of @tooee/search emits jumped for every jump that lands on a row, also when the cursor does not move. A subscriber to jumped gets these extra events.

Move app actions off the new View keys

Markdown content in View registers the fold keys z a, z c, z o, z z, z M, and z R, and g o for the heading outline, all in cursor mode. Give your own actions other keys. Keyboard basics lists what the keys do.

Upgrade from 0.8 to 0.9

Tooee 0.9 removes the compatibility APIs that were deprecated in 0.8. Update these calls before you install the new release.

Pass direct props to Choose

The Choose component now accepts chooser options as top-level props. Pass action definitions through actions:

<Choose contentProvider={provider} prompt="Pick" multi actions={actions} />

The launch() function still takes its chooser fields under options. Lower-level chooser primitives still use commands for their extra actions.

Nest launchCli provider settings

Put provider settings under provider when you call launchCli or runCliSession:

await launchCli(<App />, {
  provider: {
    config,
    initialMode: "insert",
    leader: "space",
    sequenceTimeoutMs: 500,
  },
});

The top-level aliases for config, initialMode, leader, and sequenceTimeoutMs have been removed.

Select the table renderer through View

The tooee table command has been removed. Use the View renderer option:

tooee view --renderer table data.csv

Put AppLayout scrolling in one object

AppLayout now accepts its scrollbox ref and settings through scroll:

<AppLayout
  scroll={{ ref: scrollRef, focused: false, stickyScroll: true, stickyStart: "bottom" }}
  statusBar={{ items: [] }}
>
  {content}
</AppLayout>

The separate scrollRef and scrollProps props have been removed.

Import ColorMode from config

Replace the removed config Mode alias with ColorMode:

import type { ColorMode } from "@tooee/config";

The command input type named Mode remains available from @tooee/commands.

Read commands with useSurfaceInvoke

Replace useCommandContext() with useSurfaceInvoke():

const { commands, invoke } = useSurfaceInvoke();

It reads the commands and invocation function for the nearest command surface.

Keep overlay handles

Overlay controllers now use open, handles, and state hooks. Keep the handle returned by open() so you can close or update that entry:

import { overlayValue, useOverlay } from "@tooee/overlays";

const overlay = useOverlay();
const handle = overlay.open(
  "details",
  ({ payload }) => <text content={payload} />,
  "Initial details",
  { mode: null }
);
handle.update(overlayValue("Updated details"));
handle.close();

Use useOverlayState().stack.includes(id) when a component needs to know whether a named overlay is open. Use useHasOverlay() when it only needs to know whether the stack has an entry. The controller still has update(id, next) and closeTop().

Reuse chooser behavior

@tooee/renderers now exports the chooser controller, store, source, filter, list, highlighting, and fuzzy-match primitives. The command palette and theme picker use these primitives, so their filtering, navigation, input, and selection behavior matches @tooee/choose.

Next

On this page