Skip to main content

@datalayer/reactor-shell

The shell plugin other plugins extend. A shell — a workspace, a store, a CMS — usually has one control whose options come from everybody else: which editor, which panel, which mode. This plugin is that control made generic.

import { buildReactorFromPlugins, contribution } from '@datalayer/reactor';
import { ShellPlugin, ShellView } from '@datalayer/reactor-shell';

const NotebookPlugin = definePlugin({
name: '@me/notebook',
contributes: [
contribution(ShellView, {
id: 'notebook',
title: 'Notebook',
order: 10,
}),
],
});

const reactor = buildReactorFromPlugins([ShellPlugin, NotebookPlugin]);

It owns four things:

  • A view point — its own ShellView by default, or one the host already declared, passed through config.point. Contributions are what populate everything else.
  • A segmented selector that renders into a slot (config.slot) and shows nothing at all until a plugin contributes: an empty application is an empty control, not a fake one. A view that cannot open right now stays focusable and says why (aria-disabled plus a title), rather than disappearing.
  • A choice store (chooseView, getViewChoice, subscribeViewChoice, nextView) that commands can read and cycle from outside React.
  • A cycle command in the reactor's registry, Mod+Alt+E by default — reachable from the command palette like everything else.

What a chosen view does is the host's business: every choice goes through the configurable announce callback, whose return value says whether anyone was listening — a command invoked with nobody on the other end says so rather than appearing to work.

Configuration

OptionDefaultWhat it does
pointShellViewThe contribution point the views arrive through
describeidentityMaps a contributed value (+ the slot's props as context) to { id, title, icon?, order?, disabled?, disabledReason? }
slot'header'Where the selector renders
defaultView'none'Seeded into the store, not announced
showSelectortrueThe control; the store and command remain either way
allowNonetrueWhether "none" is a choice. false for a host whose views are the whole application: the selector then lists only the views, appears only once there are two, and the cycle command wraps among them
announce() => trueTold of every choice; returns whether anyone heard
commandId, keybindingshell.cycleView, Mod+Alt+EThe cycle command
noneLabel, ariaLabelNone, ViewWords

Grown from Loop

This plugin is the LOOP workspace's editor selector, generalised. The loop's own shell plugin in @datalayer/agent-runtimes is now a thin wrapper: it points config.point at the loop's editor contribution point, describe gates each editor against the live workspace, and announce forwards the choice to the chat's surface-request channel. The Loop documentation describes that composition.