nexus-shell 0.2.9 → 0.2.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -5
- package/dist/components/layout/PaneHost.d.ts +56 -0
- package/dist/components/layout/ShellLayout.d.ts +18 -7
- package/dist/components/widgets/ActivityBar.d.ts +20 -7
- package/dist/components/widgets/ChatPane.d.ts +17 -3
- package/dist/components/widgets/SidebarPane.d.ts +33 -7
- package/dist/components/widgets/TerminalPane.d.ts +21 -4
- package/dist/connected/ConnectedChatPane.d.ts +8 -5
- package/dist/connected/ConnectedPane.d.ts +24 -0
- package/dist/connected/ConnectedPaneRail.d.ts +25 -0
- package/dist/connected/ConnectedSettingsPanel.d.ts +12 -0
- package/dist/connected/ConnectedTerminalPane.d.ts +7 -4
- package/dist/connected/index.d.ts +4 -2
- package/dist/connected/panels.d.ts +36 -0
- package/dist/core/Boot.d.ts +18 -3
- package/dist/core/services/PaneService.d.ts +66 -0
- package/dist/core/services/TerminalService.d.ts +8 -3
- package/dist/index.d.ts +4 -4
- package/dist/nexus-shell.es.js +2424 -2351
- package/dist/nexus-shell.umd.js +1 -1
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/dist/connected/ConnectedActivityBar.d.ts +0 -10
- package/dist/connected/ConnectedSidebarPane.d.ts +0 -12
- package/dist/core/services/RightSidebarService.d.ts +0 -7
- package/dist/core/services/SidebarService.d.ts +0 -17
package/README.md
CHANGED
|
@@ -28,8 +28,10 @@ import { Boxes, Files } from 'lucide-react';
|
|
|
28
28
|
import {
|
|
29
29
|
AppTitle,
|
|
30
30
|
ShellLayout,
|
|
31
|
+
chatPanel,
|
|
31
32
|
componentRegistry,
|
|
32
33
|
initializeShell,
|
|
34
|
+
terminalPanel,
|
|
33
35
|
useLayoutStore,
|
|
34
36
|
} from 'nexus-shell';
|
|
35
37
|
import 'nexus-shell/style.css';
|
|
@@ -38,7 +40,13 @@ import 'nexus-shell/style.css';
|
|
|
38
40
|
componentRegistry.register('editor', Editor);
|
|
39
41
|
|
|
40
42
|
initializeShell({
|
|
41
|
-
panels: [
|
|
43
|
+
panels: [
|
|
44
|
+
{ id: 'files', label: 'Explorer', icon: Files, component: FileExplorer },
|
|
45
|
+
terminalPanel(),
|
|
46
|
+
],
|
|
47
|
+
// Chat on the right rail. Move it to `panels` for the left, or register
|
|
48
|
+
// the component as a tab — nothing about it is bound to one edge.
|
|
49
|
+
inspectorPanels: [chatPanel()],
|
|
42
50
|
commands: [
|
|
43
51
|
{ id: 'file.save', label: 'File: Save', keybinding: 'Control+s', execute: save },
|
|
44
52
|
],
|
|
@@ -56,6 +64,23 @@ createRoot(document.getElementById('root')!).render(
|
|
|
56
64
|
That is a working IDE: dockable tabs, a command palette on `Cmd/Ctrl+Shift+P`, a
|
|
57
65
|
terminal, a chat pane, and a themable frame.
|
|
58
66
|
|
|
67
|
+
## Where things go
|
|
68
|
+
|
|
69
|
+
The shell has four places a view can live, and nothing is nailed to one of
|
|
70
|
+
them. Chat and the terminal are ordinary registrations, so they go wherever you
|
|
71
|
+
put them — including into a dockable tab, alongside your own views.
|
|
72
|
+
|
|
73
|
+
| Place | How |
|
|
74
|
+
| :-- | :-- |
|
|
75
|
+
| Left rail | `panels: [...]` |
|
|
76
|
+
| Right rail | `inspectorPanels: [...]` |
|
|
77
|
+
| Dockable tab | `componentRegistry.register(id, Component)` + `addTab(id)` |
|
|
78
|
+
| Bottom of the workspace | A tab in the bottom row of your `initialLayoutJson` |
|
|
79
|
+
|
|
80
|
+
Anything hosted in a pane or a tab is told so, and drops its own title bar —
|
|
81
|
+
`SidebarPane` and the tab strip already draw one. Pass `chrome` explicitly to
|
|
82
|
+
force it either way.
|
|
83
|
+
|
|
59
84
|
## Growing an app
|
|
60
85
|
|
|
61
86
|
You add capability by **registering** it. None of this changes the layout, which
|
|
@@ -67,6 +92,8 @@ is what lets plugins and distant code contribute to the shell.
|
|
|
67
92
|
| An action or hotkey | `commandRegistry.registerCommand({ id, label, keybinding, execute })` — appears in the palette automatically |
|
|
68
93
|
| A menu entry | `menuRegistry.registerMenu('File', { id, label, commandId })` |
|
|
69
94
|
| A sidebar panel | Add it to `panels`; it becomes an activity bar icon |
|
|
95
|
+
| An inspector or properties panel | Add it to `inspectorPanels`; it docks right, with its own rail |
|
|
96
|
+
| Chat or a terminal, anywhere | `chatPanel()` / `terminalPanel()` in `panels` or `inspectorPanels`, or register the component as a tab |
|
|
70
97
|
| A status bar item | `useStatusBarStore.getState().addWidget(...)` |
|
|
71
98
|
| A dialog from anywhere | `await useModalStore.getState().openConfirm('Sure?')` |
|
|
72
99
|
| An unsaved-changes guard | `useLayoutStore.getState().setTabDirty(tabId, true)` |
|
|
@@ -114,8 +141,8 @@ shell's own frame and keep every registration working.
|
|
|
114
141
|
|
|
115
142
|
| Component | What it is |
|
|
116
143
|
| :-- | :-- |
|
|
117
|
-
| `ActivityBar` | Vertical icon rail for switching
|
|
118
|
-
| `ChatPane` |
|
|
144
|
+
| `ActivityBar` | Vertical icon rail for switching side panels, either edge |
|
|
145
|
+
| `ChatPane` | Chat transcript with slash-command autocomplete; fills any host |
|
|
119
146
|
| `CommandPalette` | Filterable, keyboard-navigable command list |
|
|
120
147
|
| `ContextMenu` | Floating menu positioned at viewport coordinates |
|
|
121
148
|
| `DataGrid` | Sortable, filterable table with optional virtualisation |
|
|
@@ -124,9 +151,10 @@ shell's own frame and keep every registration working.
|
|
|
124
151
|
| `QuickSearch` | Compact search field with grouped results, for the menu bar |
|
|
125
152
|
| `SearchWidget` | Full-height search panel with autocomplete, for the sidebar |
|
|
126
153
|
| `SettingsPanel` | Theme picker body for the settings sidebar |
|
|
127
|
-
| `SidebarPane` | Titled, closable
|
|
154
|
+
| `SidebarPane` | Titled, closable side panel; `side` docks it left or right |
|
|
128
155
|
| `StatusBar` | Footer with left / center / right item groups |
|
|
129
|
-
| `TerminalPane` |
|
|
156
|
+
| `TerminalPane` | Terminal log and input; fills any host |
|
|
157
|
+
| `PaneHostProvider` | Tells hosted components a title bar is already drawn |
|
|
130
158
|
| `ThemeSwitcher` | Segmented theme control |
|
|
131
159
|
| `TreeWidget` | Virtualised tree for any hierarchy, with drag-to-move and a data-driven menu |
|
|
132
160
|
| `GraphCanvas` | Infinite pannable, zoomable field for node-and-edge editing |
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* What a component can learn about the thing hosting it.
|
|
5
|
+
*
|
|
6
|
+
* A pane, a dockable tab and a bare `<div>` give a component very different
|
|
7
|
+
* surroundings, and the difference that matters is whether a title bar has
|
|
8
|
+
* already been drawn. Without this, a chat pane inside a `SidebarPane` renders
|
|
9
|
+
* two headers and two close buttons.
|
|
10
|
+
*/
|
|
11
|
+
export interface IPaneHost {
|
|
12
|
+
/**
|
|
13
|
+
* The host already draws a title bar and a close affordance, so a hosted
|
|
14
|
+
* component should not draw its own.
|
|
15
|
+
*/
|
|
16
|
+
chrome: boolean;
|
|
17
|
+
/** Where the host sits, when it knows. Useful for choosing a layout. */
|
|
18
|
+
placement?: 'left' | 'right' | 'bottom' | 'tab';
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Read the surrounding host, or `null` when there isn't one.
|
|
22
|
+
*
|
|
23
|
+
* Prefer {@link useHostChrome}, which folds in an explicit prop.
|
|
24
|
+
*/
|
|
25
|
+
export declare const usePaneHost: () => IPaneHost | null;
|
|
26
|
+
/**
|
|
27
|
+
* Whether this component should draw its own title bar.
|
|
28
|
+
*
|
|
29
|
+
* The host provides the *default*; an explicit prop always wins. That ordering
|
|
30
|
+
* is deliberate — auto-detection keeps the common case free of configuration,
|
|
31
|
+
* but a component that can only be told implicitly is one you cannot unit-test
|
|
32
|
+
* without building a host around it, and cannot force when the detection is
|
|
33
|
+
* wrong.
|
|
34
|
+
*
|
|
35
|
+
* @param explicit The component's own `chrome` prop, if the caller set one.
|
|
36
|
+
*/
|
|
37
|
+
export declare const useHostChrome: (explicit?: boolean) => boolean;
|
|
38
|
+
export interface PaneHostProviderProps extends IPaneHost {
|
|
39
|
+
/** Everything that should see this host. */
|
|
40
|
+
children: ReactNode;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Declare that everything inside is hosted.
|
|
44
|
+
*
|
|
45
|
+
* `SidebarPane` and the shell's tab factory do this for you. Wrap your own
|
|
46
|
+
* container in it if you draw a title bar and want hosted components to defer.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```tsx
|
|
50
|
+
* <PaneHostProvider chrome placement="bottom">
|
|
51
|
+
* <MyTitleBar />
|
|
52
|
+
* <ConnectedTerminalPane />
|
|
53
|
+
* </PaneHostProvider>
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export declare const PaneHostProvider: ({ children, ...host }: PaneHostProviderProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -2,15 +2,22 @@ import { ReactNode } from 'react';
|
|
|
2
2
|
import { Model, IJsonModel } from 'flexlayout-react';
|
|
3
3
|
import { IMenuItemConfig } from '../../core/registry/MenuRegistry';
|
|
4
4
|
import { ISlashCommandConfig } from '../../core/services/ChatService';
|
|
5
|
-
import {
|
|
5
|
+
import { IPanel } from '../../core/services/PaneService';
|
|
6
6
|
import { IStatusBarWidgetConfig } from '../../core/services/StatusBarService';
|
|
7
7
|
|
|
8
8
|
export interface ShellLayoutProps {
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
10
|
+
* Panels to register, for every edge.
|
|
11
|
+
*
|
|
12
|
+
* Each panel's `side` decides where it docks — `"left"`, `"right"` or
|
|
13
|
+
* `"bottom"`, defaulting to left — and each edge keeps its own open panel, so
|
|
14
|
+
* a file tree, an inspector and a terminal can all be showing at once. A rail
|
|
15
|
+
* appears only once its edge has a panel.
|
|
16
|
+
*
|
|
17
|
+
* Placement is data on the panel rather than a separate prop per side, so
|
|
18
|
+
* moving something is a one-word change.
|
|
12
19
|
*/
|
|
13
|
-
panels?:
|
|
20
|
+
panels?: IPanel[];
|
|
14
21
|
/** Slash commands available in the chat pane. */
|
|
15
22
|
slashCommands?: ISlashCommandConfig[];
|
|
16
23
|
/** Menu structure, keyed by top-level menu name. Items dispatch by `commandId`. */
|
|
@@ -51,8 +58,8 @@ export interface ShellLayoutProps {
|
|
|
51
58
|
onLayoutChange?: (layout: IJsonModel) => void;
|
|
52
59
|
}
|
|
53
60
|
/**
|
|
54
|
-
* The complete application shell: menu bar,
|
|
55
|
-
* `flexlayout-react` docking workspace,
|
|
61
|
+
* The complete application shell: menu bar, a docked pane and rail on each
|
|
62
|
+
* edge, a `flexlayout-react` docking workspace, and a status bar.
|
|
56
63
|
*
|
|
57
64
|
* **This is where an application starts.** Call {@link initializeShell} once to
|
|
58
65
|
* register your commands, menus and panels, render this component, and add
|
|
@@ -81,7 +88,11 @@ export interface ShellLayoutProps {
|
|
|
81
88
|
* componentRegistry.register('editor', Editor);
|
|
82
89
|
*
|
|
83
90
|
* initializeShell({
|
|
84
|
-
* panels: [
|
|
91
|
+
* panels: [
|
|
92
|
+
* { id: 'files', label: 'Explorer', icon: Files, component: FileTree },
|
|
93
|
+
* chatPanel({ side: 'right' }),
|
|
94
|
+
* terminalPanel({ side: 'bottom' }),
|
|
95
|
+
* ],
|
|
85
96
|
* commands: [{ id: 'file.save', label: 'File: Save', keybinding: 'Control+s', execute: save }],
|
|
86
97
|
* menus: { File: [{ id: 'save', label: 'Save', commandId: 'file.save' }] },
|
|
87
98
|
* statusBar: [{ id: 'branch', label: 'main', alignment: 'left' }],
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { LucideIcon } from 'lucide-react';
|
|
2
|
+
import { PaneSide } from './SidebarPane';
|
|
2
3
|
|
|
3
4
|
/** A single icon button in the {@link ActivityBar}. */
|
|
4
5
|
export interface IActivityBarItem {
|
|
@@ -13,8 +14,12 @@ export interface ActivityBarProps {
|
|
|
13
14
|
/** Items rendered in the main (top) group, in order. */
|
|
14
15
|
items?: IActivityBarItem[];
|
|
15
16
|
/**
|
|
16
|
-
* Items rendered in the bottom group, below the flex spacer.
|
|
17
|
-
*
|
|
17
|
+
* Items rendered in the bottom group, below the flex spacer. Empty by
|
|
18
|
+
* default.
|
|
19
|
+
*
|
|
20
|
+
* This used to default to a Settings item, which meant every rail grew one
|
|
21
|
+
* whether the app had settings or not. Settings is now an ordinary panel with
|
|
22
|
+
* `align: 'end'` — see `settingsPanel()`.
|
|
18
23
|
*/
|
|
19
24
|
bottomItems?: IActivityBarItem[];
|
|
20
25
|
/** Id of the currently active item, or `null` when nothing is selected. */
|
|
@@ -24,17 +29,25 @@ export interface ActivityBarProps {
|
|
|
24
29
|
* deselect it — is the caller's decision, not the component's.
|
|
25
30
|
*/
|
|
26
31
|
onSelect?: (id: string) => void;
|
|
32
|
+
/**
|
|
33
|
+
* Which edge of the shell the rail is docked to. Defaults to `"left"`.
|
|
34
|
+
*
|
|
35
|
+
* The divider and the active-item indicator both mirror, so a right-hand rail
|
|
36
|
+
* marks its selection on the edge facing the content.
|
|
37
|
+
*/
|
|
38
|
+
side?: Exclude<PaneSide, 'bottom'>;
|
|
27
39
|
/** Extra classes merged onto the root `<aside>`. */
|
|
28
40
|
className?: string;
|
|
29
41
|
/** Accessible label for the landmark. Defaults to `"Activity Bar"`. */
|
|
30
42
|
'aria-label'?: string;
|
|
31
43
|
}
|
|
32
44
|
/**
|
|
33
|
-
* The narrow vertical icon rail
|
|
34
|
-
*
|
|
45
|
+
* The narrow vertical icon rail at the edge of the shell, used to switch which
|
|
46
|
+
* panel the adjacent {@link SidebarPane} shows.
|
|
35
47
|
*
|
|
36
|
-
* Controlled — it holds no selection state.
|
|
37
|
-
* by `ShellLayout`, see `ConnectedActivityBar
|
|
48
|
+
* Controlled — it holds no selection state. `side` docks it left or right; for
|
|
49
|
+
* the store-backed variants used by `ShellLayout`, see `ConnectedActivityBar`
|
|
50
|
+
* and `ConnectedInspectorBar`.
|
|
38
51
|
*
|
|
39
52
|
* @example
|
|
40
53
|
* ```tsx
|
|
@@ -45,4 +58,4 @@ export interface ActivityBarProps {
|
|
|
45
58
|
* />
|
|
46
59
|
* ```
|
|
47
60
|
*/
|
|
48
|
-
export declare const ActivityBar: ({ items, bottomItems, activeId, onSelect, className, "aria-label": ariaLabel, }: ActivityBarProps) => import("react/jsx-runtime").JSX.Element;
|
|
61
|
+
export declare const ActivityBar: ({ items, bottomItems, activeId, onSelect, side, className, "aria-label": ariaLabel, }: ActivityBarProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -38,17 +38,31 @@ export interface ChatPaneProps {
|
|
|
38
38
|
placeholder?: string;
|
|
39
39
|
/** Shown in place of the transcript when `messages` is empty. */
|
|
40
40
|
emptyState?: React.ReactNode;
|
|
41
|
+
/**
|
|
42
|
+
* Draw the title bar.
|
|
43
|
+
*
|
|
44
|
+
* Left unset, this follows the host: inside a `SidebarPane` or a dockable tab
|
|
45
|
+
* the title is already drawn, so the pane omits its own. Set it explicitly to
|
|
46
|
+
* force either way — which is also what lets the component be tested without
|
|
47
|
+
* a host around it.
|
|
48
|
+
*/
|
|
49
|
+
chrome?: boolean;
|
|
41
50
|
/** Extra classes merged onto the root element. */
|
|
42
51
|
className?: string;
|
|
43
52
|
}
|
|
44
53
|
/**
|
|
45
|
-
* A
|
|
54
|
+
* A chat panel: a scrolling transcript over a composer with slash-command
|
|
46
55
|
* autocomplete.
|
|
47
56
|
*
|
|
48
57
|
* Fully controlled — it owns only the in-progress input and the suggestion
|
|
49
58
|
* highlight. Messages, sending and visibility belong to the caller, so the same
|
|
50
59
|
* component works against a local array, a websocket, or an LLM endpoint. For
|
|
51
|
-
* the store-backed variant
|
|
60
|
+
* the store-backed variant, see `ConnectedChatPane`.
|
|
61
|
+
*
|
|
62
|
+
* **It fills whatever hosts it.** Register it as a sidebar panel, an inspector
|
|
63
|
+
* panel or a dockable tab and it takes that shape; it carries no width or edge
|
|
64
|
+
* of its own. Inside a host that draws a title bar it omits its own header —
|
|
65
|
+
* see `chrome` to override.
|
|
52
66
|
*
|
|
53
67
|
* @example
|
|
54
68
|
* ```tsx
|
|
@@ -60,4 +74,4 @@ export interface ChatPaneProps {
|
|
|
60
74
|
* />
|
|
61
75
|
* ```
|
|
62
76
|
*/
|
|
63
|
-
export declare const ChatPane: ({ messages, onSend, slashCommands, onSlashCommand, onClose, title, placeholder, emptyState, className, }: ChatPaneProps) => import("react/jsx-runtime").JSX.Element;
|
|
77
|
+
export declare const ChatPane: ({ messages, onSend, slashCommands, onSlashCommand, onClose, title, placeholder, emptyState, chrome, className, }: ChatPaneProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
2
|
|
|
3
|
+
/** Which edge of the shell a pane or rail is docked to. */
|
|
4
|
+
export type PaneSide = 'left' | 'right' | 'bottom';
|
|
3
5
|
export interface SidebarPaneProps {
|
|
4
6
|
/**
|
|
5
7
|
* Heading text. Rendered uppercase with letter-spacing; pass it in natural
|
|
@@ -13,25 +15,49 @@ export interface SidebarPaneProps {
|
|
|
13
15
|
* entirely — useful when the pane is always visible.
|
|
14
16
|
*/
|
|
15
17
|
onClose?: () => void;
|
|
16
|
-
/** Fixed pane width, as a CSS length. Defaults to `"300px"`. */
|
|
18
|
+
/** Fixed pane width, as a CSS length. Ignored when `side` is `"bottom"`. Defaults to `"300px"`. */
|
|
17
19
|
width?: string;
|
|
20
|
+
/** Fixed pane height, as a CSS length. Only used when `side` is `"bottom"`. Defaults to `"240px"`. */
|
|
21
|
+
height?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Which edge of the shell the pane is docked to. Defaults to `"left"`.
|
|
24
|
+
*
|
|
25
|
+
* Only the divider moves — a right-hand pane is the same container, so an
|
|
26
|
+
* inspector does not need a component of its own.
|
|
27
|
+
*/
|
|
28
|
+
side?: PaneSide;
|
|
18
29
|
/** Extra classes merged onto the root `<aside>`. */
|
|
19
30
|
className?: string;
|
|
20
31
|
}
|
|
21
32
|
/**
|
|
22
|
-
*
|
|
23
|
-
*
|
|
33
|
+
* A docked side panel: a titled header with an optional close button, over a
|
|
34
|
+
* scrolling body.
|
|
24
35
|
*
|
|
25
36
|
* A pure container — it decides nothing about which panel is showing and holds
|
|
26
|
-
* no state. Render whatever you like as `children`.
|
|
27
|
-
*
|
|
28
|
-
* `
|
|
37
|
+
* no state. Render whatever you like as `children`.
|
|
38
|
+
*
|
|
39
|
+
* `side` docks it left (beside the {@link ActivityBar}) or right, where it
|
|
40
|
+
* becomes an inspector. Both are the same component deliberately: before this
|
|
41
|
+
* prop existed every application hand-rolled its own right-hand
|
|
42
|
+
* `<div className="w-80 border-l …">`, and they all drifted apart.
|
|
43
|
+
*
|
|
44
|
+
* `bottom` docks it below the workspace, where `width` gives way to `height`.
|
|
45
|
+
*
|
|
46
|
+
* For the store-backed variant used by `ShellLayout`, see `ConnectedPane`.
|
|
29
47
|
*
|
|
30
48
|
* @example
|
|
31
49
|
* ```tsx
|
|
32
50
|
* <SidebarPane title="Explorer" onClose={() => setActive(null)}>
|
|
33
51
|
* <TreeWidget data={files} />
|
|
34
52
|
* </SidebarPane>
|
|
53
|
+
*
|
|
54
|
+
* <SidebarPane title="Properties" side="right" width="320px">
|
|
55
|
+
* <PropertyPanel subjects={selected} fields={fields} />
|
|
56
|
+
* </SidebarPane>
|
|
57
|
+
*
|
|
58
|
+
* <SidebarPane title="Terminal" side="bottom" height="240px">
|
|
59
|
+
* <ConnectedTerminalPane />
|
|
60
|
+
* </SidebarPane>
|
|
35
61
|
* ```
|
|
36
62
|
*/
|
|
37
|
-
export declare const SidebarPane: ({ title, children, onClose, width, className, }: SidebarPaneProps) => import("react/jsx-runtime").JSX.Element;
|
|
63
|
+
export declare const SidebarPane: ({ title, children, onClose, width, height, side, className, }: SidebarPaneProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -12,8 +12,22 @@ export interface TerminalPaneProps {
|
|
|
12
12
|
onCommand?: (command: string) => void;
|
|
13
13
|
/** Called when the collapse or close button is pressed. */
|
|
14
14
|
onClose?: () => void;
|
|
15
|
-
/**
|
|
15
|
+
/**
|
|
16
|
+
* Height of the pane, as a CSS length.
|
|
17
|
+
*
|
|
18
|
+
* Leave it unset inside a host that sizes its own children — a side pane or a
|
|
19
|
+
* dockable tab — and the terminal fills the space instead. Defaults to
|
|
20
|
+
* `"250px"` only when standalone.
|
|
21
|
+
*/
|
|
16
22
|
height?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Draw the title bar.
|
|
25
|
+
*
|
|
26
|
+
* Left unset, this follows the host: inside a `SidebarPane` or a dockable tab
|
|
27
|
+
* the title is already drawn, so the pane omits its own. Set it explicitly to
|
|
28
|
+
* force either way.
|
|
29
|
+
*/
|
|
30
|
+
chrome?: boolean;
|
|
17
31
|
/** Prompt string shown before the input. Defaults to `"$"`. */
|
|
18
32
|
prompt?: string;
|
|
19
33
|
/** Title shown in the pane header. Defaults to `"Terminal"`. */
|
|
@@ -22,14 +36,17 @@ export interface TerminalPaneProps {
|
|
|
22
36
|
className?: string;
|
|
23
37
|
}
|
|
24
38
|
/**
|
|
25
|
-
* A
|
|
26
|
-
* input.
|
|
39
|
+
* A terminal pane: a scrolling output log over a single-line input.
|
|
27
40
|
*
|
|
28
41
|
* Presentational and fully controlled — it owns only the in-progress input
|
|
29
42
|
* text. Visibility, history and command execution all belong to the caller.
|
|
30
43
|
* For the store-backed variant with built-in `clear`/`help` handling, see
|
|
31
44
|
* `ConnectedTerminalPane`.
|
|
32
45
|
*
|
|
46
|
+
* **It fills whatever hosts it.** Bottom of the workspace, a side pane, or a
|
|
47
|
+
* dockable tab — register it wherever it belongs. Inside a host that draws a
|
|
48
|
+
* title bar it omits its own header and its own fixed height.
|
|
49
|
+
*
|
|
33
50
|
* @example
|
|
34
51
|
* ```tsx
|
|
35
52
|
* const [history, setHistory] = useState<string[]>([]);
|
|
@@ -40,4 +57,4 @@ export interface TerminalPaneProps {
|
|
|
40
57
|
* />
|
|
41
58
|
* ```
|
|
42
59
|
*/
|
|
43
|
-
export declare const TerminalPane: ({ history, onCommand, onClose, height, prompt, title, className, }: TerminalPaneProps) => import("react/jsx-runtime").JSX.Element;
|
|
60
|
+
export declare const TerminalPane: ({ history, onCommand, onClose, height, prompt, title, chrome, className, }: TerminalPaneProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -9,10 +9,13 @@ export type ConnectedChatPaneProps = Omit<ChatPaneProps, 'messages' | 'slashComm
|
|
|
9
9
|
onSend?: (text: string) => void;
|
|
10
10
|
};
|
|
11
11
|
/**
|
|
12
|
-
* {@link ChatPane} bound to `useChatStore` and `
|
|
12
|
+
* {@link ChatPane} bound to `useChatStore` and `useChatVisibilityStore`.
|
|
13
13
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
14
|
+
* Appends each submission to the transcript, then either dispatches a
|
|
15
|
+
* registered slash command's `execute` or hands the text to `onSend`.
|
|
16
|
+
*
|
|
17
|
+
* Visibility belongs to whatever hosts it — a pane closes by closing the pane,
|
|
18
|
+
* a tab by closing the tab. Register it with `chatPanel()`, or as a tab
|
|
19
|
+
* component, and put it wherever it belongs.
|
|
17
20
|
*/
|
|
18
|
-
export declare const ConnectedChatPane: ({ onSend, ...props }: ConnectedChatPaneProps) => import("react/jsx-runtime").JSX.Element
|
|
21
|
+
export declare const ConnectedChatPane: ({ onSend, ...props }: ConnectedChatPaneProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { SidebarPaneProps, PaneSide } from '../components/widgets/SidebarPane';
|
|
2
|
+
|
|
3
|
+
export type ConnectedPaneProps = Omit<SidebarPaneProps, 'title' | 'children' | 'onClose'> & {
|
|
4
|
+
/** Which edge to render. Defaults to `"left"`. */
|
|
5
|
+
side?: PaneSide;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* {@link SidebarPane} bound to the pane store for one edge.
|
|
9
|
+
*
|
|
10
|
+
* Renders whichever panel is open on that edge, or nothing when the pane is
|
|
11
|
+
* collapsed. Every edge resolves against its own registry, so the left pane,
|
|
12
|
+
* the right pane and the bottom drawer open and close independently — a file
|
|
13
|
+
* tree, an inspector and a terminal all at once is the normal case, not a
|
|
14
|
+
* special one.
|
|
15
|
+
*
|
|
16
|
+
* There is nothing edge-specific in here. A panel decides where it lives
|
|
17
|
+
* through its `side`, and this renders whatever arrived.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```tsx
|
|
21
|
+
* <ConnectedPane side="right" width="320px" />
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export declare const ConnectedPane: ({ side, ...props }: ConnectedPaneProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ActivityBarProps } from '../components/widgets/ActivityBar';
|
|
2
|
+
import { PaneSide } from '../components/widgets/SidebarPane';
|
|
3
|
+
|
|
4
|
+
export type ConnectedPaneRailProps = Omit<ActivityBarProps, 'items' | 'bottomItems' | 'activeId' | 'onSelect' | 'side'> & {
|
|
5
|
+
/** Which edge to render. Defaults to `"left"`. */
|
|
6
|
+
side?: Exclude<PaneSide, 'bottom'>;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* {@link ActivityBar} bound to the pane store for one edge.
|
|
10
|
+
*
|
|
11
|
+
* Derives its items from the panels registered on that edge and toggles the
|
|
12
|
+
* open one — clicking the already-open item closes the pane. Items with
|
|
13
|
+
* `align: 'end'` go to the far group, which is how settings ends up at the
|
|
14
|
+
* bottom without the rail knowing what settings is.
|
|
15
|
+
*
|
|
16
|
+
* Renders nothing when no panels are registered for the edge. An empty rail is
|
|
17
|
+
* a twelve-pixel strip of nothing, and both edges behave the same way — the
|
|
18
|
+
* left rail used to render regardless, which made the two sides subtly
|
|
19
|
+
* different for no reason anyone had chosen.
|
|
20
|
+
*
|
|
21
|
+
* There is no bottom rail: a bottom drawer is toggled from the status bar, a
|
|
22
|
+
* command or a keybinding, and a horizontal strip of icons under the workspace
|
|
23
|
+
* costs more room than it earns.
|
|
24
|
+
*/
|
|
25
|
+
export declare const ConnectedPaneRail: ({ side, ...props }: ConnectedPaneRailProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { SettingsPanelProps } from '../components/widgets/SettingsPanel';
|
|
2
|
+
|
|
3
|
+
export type ConnectedSettingsPanelProps = Omit<SettingsPanelProps, 'theme' | 'onThemeChange'>;
|
|
4
|
+
/**
|
|
5
|
+
* {@link SettingsPanel} bound to `useThemeStore`.
|
|
6
|
+
*
|
|
7
|
+
* This used to be reached through a reserved `"settings"` panel id that the
|
|
8
|
+
* pane special-cased. Making it an ordinary connected component means the pane
|
|
9
|
+
* has no privileged ids left, and both rails behave identically — register it
|
|
10
|
+
* with `settingsPanel()`, or don't, and nothing else changes.
|
|
11
|
+
*/
|
|
12
|
+
export declare const ConnectedSettingsPanel: (props: ConnectedSettingsPanelProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -11,8 +11,11 @@ export type ConnectedTerminalPaneProps = Omit<TerminalPaneProps, 'history' | 'on
|
|
|
11
11
|
/**
|
|
12
12
|
* {@link TerminalPane} bound to `useTerminalStore`.
|
|
13
13
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
14
|
+
* Echoes each command into history and handles `help` and `clear` internally;
|
|
15
|
+
* anything else is offered to `onCommand` before falling back to a not-found
|
|
16
|
+
* message.
|
|
17
|
+
*
|
|
18
|
+
* Visibility belongs to whatever hosts it. Register it with `terminalPanel()`
|
|
19
|
+
* for a side pane, or as a tab component for the docking area.
|
|
17
20
|
*/
|
|
18
|
-
export declare const ConnectedTerminalPane: ({ onCommand, ...props }: ConnectedTerminalPaneProps) => import("react/jsx-runtime").JSX.Element
|
|
21
|
+
export declare const ConnectedTerminalPane: ({ onCommand, ...props }: ConnectedTerminalPaneProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -9,12 +9,14 @@
|
|
|
9
9
|
* Reach for these when you want the shell's behavior. Reach for the plain
|
|
10
10
|
* components when you want control.
|
|
11
11
|
*/
|
|
12
|
-
export {
|
|
12
|
+
export { chatPanel, terminalPanel, settingsPanel } from './panels';
|
|
13
|
+
export { ConnectedPaneRail, type ConnectedPaneRailProps } from './ConnectedPaneRail';
|
|
13
14
|
export { ConnectedChatPane, type ConnectedChatPaneProps } from './ConnectedChatPane';
|
|
14
15
|
export { ConnectedCommandPalette, type ConnectedCommandPaletteProps } from './ConnectedCommandPalette';
|
|
15
16
|
export { ConnectedMenuBar, type ConnectedMenuBarProps } from './ConnectedMenuBar';
|
|
16
17
|
export { ConnectedModal, type ConnectedModalProps } from './ConnectedModal';
|
|
17
|
-
export {
|
|
18
|
+
export { ConnectedPane, type ConnectedPaneProps } from './ConnectedPane';
|
|
19
|
+
export { ConnectedSettingsPanel, type ConnectedSettingsPanelProps, } from './ConnectedSettingsPanel';
|
|
18
20
|
export { ConnectedStatusBar, type ConnectedStatusBarProps } from './ConnectedStatusBar';
|
|
19
21
|
export { ConnectedTerminalPane, type ConnectedTerminalPaneProps } from './ConnectedTerminalPane';
|
|
20
22
|
export { ConnectedThemeSwitcher, type ConnectedThemeSwitcherProps } from './ConnectedThemeSwitcher';
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { IPanel } from '../core/services/PaneService';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Ready-made panel descriptors for the shell's own pieces.
|
|
5
|
+
*
|
|
6
|
+
* Chat, terminal and settings were each nailed into a fixed place — chat on the
|
|
7
|
+
* right, terminal along the bottom, settings behind a reserved panel id the
|
|
8
|
+
* pane special-cased. They are now ordinary registrations with no privileges,
|
|
9
|
+
* so they go wherever you put them:
|
|
10
|
+
*
|
|
11
|
+
* ```tsx
|
|
12
|
+
* initializeShell({
|
|
13
|
+
* panels: [
|
|
14
|
+
* { id: 'files', label: 'Explorer', icon: Files, component: FileTree },
|
|
15
|
+
* chatPanel({ side: 'right' }),
|
|
16
|
+
* terminalPanel({ side: 'bottom' }),
|
|
17
|
+
* settingsPanel(),
|
|
18
|
+
* ],
|
|
19
|
+
* });
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* Each takes overrides, so the id, label, icon or side can change without
|
|
23
|
+
* rebuilding the descriptor by hand.
|
|
24
|
+
*/
|
|
25
|
+
/** The chat pane, as a registerable panel. */
|
|
26
|
+
export declare const chatPanel: (overrides?: Partial<IPanel>) => IPanel;
|
|
27
|
+
/** The terminal, as a registerable panel. */
|
|
28
|
+
export declare const terminalPanel: (overrides?: Partial<IPanel>) => IPanel;
|
|
29
|
+
/**
|
|
30
|
+
* The theme picker, as a registerable panel.
|
|
31
|
+
*
|
|
32
|
+
* `align: 'end'` pins it to the far group of its rail, which is where a
|
|
33
|
+
* settings icon conventionally sits — and is now the only reason it ends up
|
|
34
|
+
* there, rather than the pane knowing the string `"settings"`.
|
|
35
|
+
*/
|
|
36
|
+
export declare const settingsPanel: (overrides?: Partial<IPanel>) => IPanel;
|
package/dist/core/Boot.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ICommand } from './registry/CommandRegistry';
|
|
2
2
|
import { IMenuItemConfig } from './registry/MenuRegistry';
|
|
3
3
|
import { ISlashCommandConfig } from './services/ChatService';
|
|
4
|
-
import {
|
|
4
|
+
import { IPanel } from './services/PaneService';
|
|
5
5
|
import { IStatusBarWidgetConfig } from './services/StatusBarService';
|
|
6
6
|
|
|
7
7
|
export interface InitializeShellOptions {
|
|
@@ -9,7 +9,7 @@ export interface InitializeShellOptions {
|
|
|
9
9
|
* Sidebar panels to register. Each becomes an icon in the activity bar and
|
|
10
10
|
* renders its `component` in the sidebar when selected.
|
|
11
11
|
*/
|
|
12
|
-
panels?:
|
|
12
|
+
panels?: IPanel[];
|
|
13
13
|
/** Menus keyed by top-level name. Items dispatch through their `commandId`. */
|
|
14
14
|
menus?: Record<string, IMenuItemConfig[]>;
|
|
15
15
|
/** Commands available to the palette, menus and keybindings. */
|
|
@@ -32,6 +32,18 @@ export interface InitializeShellOptions {
|
|
|
32
32
|
}
|
|
33
33
|
/** The command ids `initializeShell` registers unless told not to. */
|
|
34
34
|
export declare const DEFAULT_COMMAND_IDS: readonly ["view.toggleTerminal", "view.toggleChat", "view.toggleSidebar", ...string[]];
|
|
35
|
+
/**
|
|
36
|
+
* Toggle a panel wherever it happens to be registered.
|
|
37
|
+
*
|
|
38
|
+
* Chat and terminal are no longer nailed to one edge, so a command that toggled
|
|
39
|
+
* a fixed slot would be wrong the moment you moved them. This looks the id up
|
|
40
|
+
* in the left rail, then the right, and finally opens it as a tab — which is
|
|
41
|
+
* also what makes `Control+\`` keep working when the terminal is a tab.
|
|
42
|
+
*
|
|
43
|
+
* Returns `false` when the id is registered nowhere, so a caller can tell the
|
|
44
|
+
* difference between "toggled" and "nothing to toggle".
|
|
45
|
+
*/
|
|
46
|
+
export declare const togglePanel: (id: string) => boolean;
|
|
35
47
|
/**
|
|
36
48
|
* Boot the shell: register commands, menus, panels and status bar items into
|
|
37
49
|
* the shell registries and stores.
|
|
@@ -54,7 +66,10 @@ export declare const DEFAULT_COMMAND_IDS: readonly ["view.toggleTerminal", "view
|
|
|
54
66
|
* componentRegistry.register('editor', Editor);
|
|
55
67
|
*
|
|
56
68
|
* initializeShell({
|
|
57
|
-
* panels: [
|
|
69
|
+
* panels: [
|
|
70
|
+
* { id: 'files', label: 'Explorer', icon: Files, component: FileTree },
|
|
71
|
+
* chatPanel({ side: 'right' }),
|
|
72
|
+
* ],
|
|
58
73
|
* commands: [{ id: 'file.save', label: 'File: Save', keybinding: 'Control+s', execute: save }],
|
|
59
74
|
* menus: { File: [{ id: 'save', label: 'Save', commandId: 'file.save' }] },
|
|
60
75
|
* statusBar: [{ id: 'branch', label: 'main', alignment: 'left' }],
|