@silo-code/sdk 0.31.0 → 0.33.0

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.
Files changed (55) hide show
  1. package/dist/ActivityGlyph.d.ts +25 -0
  2. package/dist/ActivityGlyph.d.ts.map +1 -0
  3. package/dist/ActivityGlyph.js +25 -0
  4. package/dist/ActivityGlyph.js.map +1 -0
  5. package/dist/IconButton.d.ts +23 -6
  6. package/dist/IconButton.d.ts.map +1 -1
  7. package/dist/IconButton.js +14 -5
  8. package/dist/IconButton.js.map +1 -1
  9. package/dist/activity.d.ts +36 -0
  10. package/dist/activity.d.ts.map +1 -0
  11. package/dist/activity.js +33 -0
  12. package/dist/activity.js.map +1 -0
  13. package/dist/editor-service.d.ts +5 -1
  14. package/dist/editor-service.d.ts.map +1 -1
  15. package/dist/icon-button-classes.d.ts +10 -2
  16. package/dist/icon-button-classes.d.ts.map +1 -1
  17. package/dist/icon-button-classes.js +9 -5
  18. package/dist/icon-button-classes.js.map +1 -1
  19. package/dist/index.d.ts +7 -1
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +2 -0
  22. package/dist/index.js.map +1 -1
  23. package/dist/phosphor-icon.d.ts +15 -0
  24. package/dist/phosphor-icon.d.ts.map +1 -0
  25. package/dist/phosphor-icon.js +2 -0
  26. package/dist/phosphor-icon.js.map +1 -0
  27. package/dist/tab-adornment.d.ts +242 -0
  28. package/dist/tab-adornment.d.ts.map +1 -0
  29. package/dist/tab-adornment.js +2 -0
  30. package/dist/tab-adornment.js.map +1 -0
  31. package/dist/terminal-service.d.ts +18 -35
  32. package/dist/terminal-service.d.ts.map +1 -1
  33. package/dist/toolbar-items.d.ts +171 -0
  34. package/dist/toolbar-items.d.ts.map +1 -0
  35. package/dist/toolbar-items.js +2 -0
  36. package/dist/toolbar-items.js.map +1 -0
  37. package/dist/types.d.ts +15 -0
  38. package/dist/types.d.ts.map +1 -1
  39. package/dist/workspace-service.d.ts +66 -45
  40. package/dist/workspace-service.d.ts.map +1 -1
  41. package/package.json +1 -1
  42. package/src/ActivityGlyph.tsx +43 -0
  43. package/src/IconButton.tsx +28 -6
  44. package/src/activity.test.ts +35 -0
  45. package/src/activity.ts +57 -0
  46. package/src/editor-service.ts +5 -1
  47. package/src/icon-button-classes.test.ts +10 -0
  48. package/src/icon-button-classes.ts +18 -5
  49. package/src/index.ts +35 -1
  50. package/src/phosphor-icon.ts +14 -0
  51. package/src/tab-adornment.ts +261 -0
  52. package/src/terminal-service.ts +21 -35
  53. package/src/toolbar-items.ts +190 -0
  54. package/src/types.ts +17 -0
  55. package/src/workspace-service.ts +72 -45
@@ -0,0 +1,261 @@
1
+ import type { ReactNode } from "react";
2
+ import type { Activity } from "./activity";
3
+ import type { PhosphorIconName } from "./phosphor-icon";
4
+ import type { Disposable } from "./types";
5
+
6
+ /**
7
+ * Semantic color for a CenterDock tab trailing {@link TabIndicatorAdornment}
8
+ * (and optional chip background).
9
+ *
10
+ * @category Consumer Services
11
+ * @public
12
+ */
13
+ export type TabAdornmentColor = "accent" | "warn" | "ok" | "error" | "muted";
14
+
15
+ /**
16
+ * Leading identity adornment on a CenterDock tab — arbitrary React artwork
17
+ * (e.g. an app logo). Set via {@link EditorService.setIcon} /
18
+ * {@link TerminalService.setIcon}.
19
+ *
20
+ * @category Consumer Services
21
+ * @public
22
+ */
23
+ export interface TabIconAdornment {
24
+ /** Extension-owned key; stacking + {@link EditorService.clearIcon} target. */
25
+ id: string;
26
+ /** Leading glyph / logo rendered before the tab title. */
27
+ icon: ReactNode;
28
+ }
29
+
30
+ /**
31
+ * Soft tinted highlight across the entire CenterDock tab (icon, title, and
32
+ * every other adornment) — not just the label. Contributing one (via `set`
33
+ * or a `bind` that returns non-`null`) is itself the on/off signal; there's
34
+ * no separate boolean. At most one applies per tab — if multiple extensions
35
+ * contribute one for the same target, the first found wins.
36
+ *
37
+ * Set via {@link EditorService.setHighlight} / {@link TerminalService.setHighlight}.
38
+ *
39
+ * @category Consumer Services
40
+ * @public
41
+ */
42
+ export interface TabHighlightAdornment {
43
+ /** Extension-owned key; clear target. */
44
+ id: string;
45
+ /** Semantic color for the highlight fill. Defaults to `"accent"`. */
46
+ color?: TabAdornmentColor;
47
+ }
48
+
49
+ /**
50
+ * Trailing status adornment on a CenterDock tab — static Phosphor glyph.
51
+ * For busy/ready/warn/error chrome use {@link TabActivityAdornment} instead
52
+ * (ADR 0030).
53
+ *
54
+ * Set via {@link EditorService.setIndicator} /
55
+ * {@link TerminalService.setIndicator}.
56
+ *
57
+ * @category Consumer Services
58
+ * @public
59
+ */
60
+ export interface TabIndicatorAdornment {
61
+ /** Extension-owned key; stacking + clear target. */
62
+ id: string;
63
+ /**
64
+ * Glyph as a {@link PhosphorIconName} (e.g. `"Flag"`). The host resolves
65
+ * and paints it at 1em in regular weight by default. Set
66
+ * {@link TabIndicatorAdornment.filled | filled} for Phosphor fill weight;
67
+ * {@link TabIndicatorAdornment.color | color} tints the glyph; set
68
+ * {@link TabIndicatorAdornment.chip | chip} for a soft tinted background.
69
+ */
70
+ icon: PhosphorIconName;
71
+ /** Tooltip shown when hovering the indicator. */
72
+ tooltip?: string;
73
+ /** Semantic color for the glyph (and chip fill). */
74
+ color?: TabAdornmentColor;
75
+ /**
76
+ * When true, paint a soft tinted chip behind the icon. Default is
77
+ * glyph-only — no background.
78
+ */
79
+ chip?: boolean;
80
+ /**
81
+ * When true, paint the glyph with Phosphor `weight="fill"`. Default is
82
+ * regular weight (outline).
83
+ */
84
+ filled?: boolean;
85
+ }
86
+
87
+ /**
88
+ * Host-owned {@link Activity} on a CenterDock tab. Extensions pick the kind
89
+ * (+ optional tooltip); never an icon or color (ADR 0030).
90
+ *
91
+ * @category Consumer Services
92
+ * @public
93
+ */
94
+ export interface TabActivityAdornment {
95
+ /** Extension-owned key; stacking + clear target. */
96
+ id: string;
97
+ activity: Activity;
98
+ tooltip?: string;
99
+ }
100
+
101
+ /**
102
+ * Payload for {@link EditorService.flashIndicator} /
103
+ * {@link TerminalService.flashIndicator} — timed one-shot; no stable `id`
104
+ * (auto-cleared after `durationMs`).
105
+ *
106
+ * @category Consumer Services
107
+ * @public
108
+ */
109
+ export type TabIndicatorFlash = TabIndicatorContribution & {
110
+ /** How long to show the flash. Defaults to host choice (typically ~800ms). */
111
+ durationMs?: number;
112
+ };
113
+
114
+ /**
115
+ * Payload for {@link EditorService.flashActivity} /
116
+ * {@link TerminalService.flashActivity}.
117
+ *
118
+ * @category Consumer Services
119
+ * @public
120
+ */
121
+ export type TabActivityFlash = TabActivityContribution & {
122
+ durationMs?: number;
123
+ };
124
+
125
+ /**
126
+ * Fields contributed by a {@link TabIconBinder.provide} call (the binder’s
127
+ * own `id` is applied by the host).
128
+ *
129
+ * @category Consumer Services
130
+ * @public
131
+ */
132
+ export type TabIconContribution = Omit<TabIconAdornment, "id">;
133
+
134
+ /**
135
+ * Fields contributed by a {@link TabHighlightBinder.provide} call.
136
+ *
137
+ * @category Consumer Services
138
+ * @public
139
+ */
140
+ export type TabHighlightContribution = Omit<TabHighlightAdornment, "id">;
141
+
142
+ /**
143
+ * Fields contributed by a {@link TabIndicatorBinder.provide} call.
144
+ *
145
+ * @category Consumer Services
146
+ * @public
147
+ */
148
+ export type TabIndicatorContribution = Omit<TabIndicatorAdornment, "id">;
149
+
150
+ /**
151
+ * Fields contributed by a {@link TabActivityBinder.provide} call.
152
+ *
153
+ * @category Consumer Services
154
+ * @public
155
+ */
156
+ export type TabActivityContribution = Omit<TabActivityAdornment, "id">;
157
+
158
+ /**
159
+ * Keep a leading-icon projection in sync for every editor/terminal tab.
160
+ * Prefer over repeatedly calling {@link EditorService.setIcon}.
161
+ *
162
+ * @category Consumer Services
163
+ * @public
164
+ */
165
+ export interface TabIconBinder {
166
+ /** Extension-owned key — conventionally `"<extension-id>.tab-icon"`. */
167
+ id: string;
168
+ /**
169
+ * Called synchronously per tab during render. Return `null` to contribute
170
+ * nothing for this target id (editor id or terminal session id).
171
+ */
172
+ provide(targetId: string): TabIconContribution | null;
173
+ }
174
+
175
+ /**
176
+ * Keep a whole-tab highlight projection in sync for every editor/terminal
177
+ * tab.
178
+ *
179
+ * @category Consumer Services
180
+ * @public
181
+ */
182
+ export interface TabHighlightBinder {
183
+ /** Extension-owned key — conventionally `"<extension-id>.tab-highlight"`. */
184
+ id: string;
185
+ /**
186
+ * Called synchronously per tab during render. Return `null` to contribute
187
+ * no highlight for this target id.
188
+ */
189
+ provide(targetId: string): TabHighlightContribution | null;
190
+ }
191
+
192
+ /**
193
+ * Keep a trailing-indicator projection in sync for every editor/terminal tab.
194
+ *
195
+ * @category Consumer Services
196
+ * @public
197
+ */
198
+ export interface TabIndicatorBinder {
199
+ /** Extension-owned key — conventionally `"<extension-id>.tab-indicator"`. */
200
+ id: string;
201
+ /**
202
+ * Called synchronously per tab during render. Return `null` to contribute
203
+ * nothing for this target id.
204
+ */
205
+ provide(targetId: string): TabIndicatorContribution | null;
206
+ }
207
+
208
+ /**
209
+ * Keep a trailing-activity projection in sync for every editor/terminal tab.
210
+ *
211
+ * @category Consumer Services
212
+ * @public
213
+ */
214
+ export interface TabActivityBinder {
215
+ /** Extension-owned key — conventionally `"<extension-id>.tab-activity"`. */
216
+ id: string;
217
+ provide(targetId: string): TabActivityContribution | null;
218
+ }
219
+
220
+ /**
221
+ * Shared adorn verbs for CenterDock editor and terminal tabs. Implemented by
222
+ * {@link EditorService} and {@link TerminalService} (target id is the editor
223
+ * or terminal session id respectively).
224
+ *
225
+ * @category Consumer Services
226
+ * @public
227
+ */
228
+ export interface TabAdornmentMethods {
229
+ setIcon(targetId: string, adornment: TabIconAdornment): void;
230
+ clearIcon(targetId: string, adornmentId: string): void;
231
+ bindIcon(binder: TabIconBinder): Disposable;
232
+
233
+ setHighlight(targetId: string, adornment: TabHighlightAdornment): void;
234
+ clearHighlight(targetId: string, adornmentId: string): void;
235
+ bindHighlight(binder: TabHighlightBinder): Disposable;
236
+
237
+ setIndicator(targetId: string, adornment: TabIndicatorAdornment): void;
238
+ clearIndicator(targetId: string, adornmentId: string): void;
239
+ flashIndicator(targetId: string, flash: TabIndicatorFlash): void;
240
+ bindIndicator(binder: TabIndicatorBinder): Disposable;
241
+
242
+ setActivity(targetId: string, adornment: TabActivityAdornment): void;
243
+ clearActivity(targetId: string, adornmentId: string): void;
244
+ flashActivity(targetId: string, flash: TabActivityFlash): void;
245
+ bindActivity(binder: TabActivityBinder): Disposable;
246
+
247
+ /** All leading icons for `targetId`, in set/bind order. */
248
+ getIcons(targetId: string): TabIconAdornment[];
249
+ /**
250
+ * The whole-tab highlight for `targetId`, or `null` if none. At most one
251
+ * applies — first found across `set`/`bind` order.
252
+ */
253
+ getHighlight(targetId: string): TabHighlightAdornment | null;
254
+ /** All trailing indicators for `targetId`, in set/bind/flash order. */
255
+ getIndicators(targetId: string): TabIndicatorAdornment[];
256
+ /** All trailing activities for `targetId`, in set/bind/flash order. */
257
+ getActivities(targetId: string): TabActivityAdornment[];
258
+ /** Signal that binder data changed — re-query `provide` and re-render. */
259
+ invalidateTabAdornments(): void;
260
+ subscribeTabAdornments(listener: () => void): Disposable;
261
+ }
@@ -1,6 +1,9 @@
1
- import type React from "react";
2
1
  import type { Disposable } from "./types";
3
2
  import type { TerminalKind, TerminalRecord } from "./domain-types";
3
+ import type {
4
+ TabAdornmentMethods,
5
+ TabIndicatorContribution,
6
+ } from "./tab-adornment";
4
7
 
5
8
  /**
6
9
  * A parsed OSC (Operating System Command) escape sequence emitted by a
@@ -26,32 +29,18 @@ export interface OscEvent {
26
29
  export type { TerminalKind, TerminalRecord } from "./domain-types";
27
30
 
28
31
  /**
29
- * A decoration that an extension can attach to a terminal tab — a small icon
30
- * with an optional tooltip and semantic color. Registered via
31
- * {@link TerminalService.registerTabDecoration}.
32
+ * @deprecated Prefer {@link TerminalService.setIndicator} /
33
+ * {@link TerminalService.bindIndicator}. Alias for a trailing indicator
34
+ * contribution (no `id` — the provider id supplies it).
32
35
  *
33
36
  * @category Consumer Services
34
37
  * @public
35
38
  */
36
- export interface TerminalTabDecoration {
37
- /**
38
- * Small React node rendered as a decoration badge on the tab (≤16 px).
39
- * The extension supplies the shape; the host applies `color` via a CSS
40
- * data attribute mapped to design tokens.
41
- */
42
- icon: React.ReactNode;
43
- /** Tooltip shown when hovering the decoration icon. */
44
- tooltip?: string;
45
- /**
46
- * Semantic color applied to the icon element. The host maps this to the
47
- * matching `--silo-color-*` design token so themes control the exact shade.
48
- */
49
- color?: "accent" | "warn" | "ok" | "error" | "muted";
50
- }
39
+ export type TerminalTabDecoration = TabIndicatorContribution;
51
40
 
52
41
  /**
53
- * A decoration provider for terminal tabs. Register via
54
- * {@link TerminalService.registerTabDecoration}.
42
+ * @deprecated Prefer {@link TerminalService.bindIndicator}. Terminal-only
43
+ * trailing-indicator provider kept as a shim over the adornment registry.
55
44
  *
56
45
  * @category Consumer Services
57
46
  * @public
@@ -61,8 +50,7 @@ export interface TerminalTabDecorationProvider {
61
50
  id: string;
62
51
  /**
63
52
  * Called synchronously for each terminal tab during render. Return `null`
64
- * to contribute nothing for this terminal. When multiple providers are
65
- * registered, the first non-null result wins.
53
+ * to contribute nothing for this terminal.
66
54
  */
67
55
  provide(terminalId: string): TerminalTabDecoration | null;
68
56
  }
@@ -92,10 +80,13 @@ export interface CreateTerminalInput {
92
80
  * deleting the workspace. The tab itself is rendered by the core dock from the
93
81
  * workspace's terminal records.
94
82
  *
83
+ * Tab chrome adornments (`setIcon` / `setIndicator` / …) take a **terminal
84
+ * session id** as the target — see {@link TabAdornmentMethods}.
85
+ *
95
86
  * @category Consumer Services
96
87
  * @public
97
88
  */
98
- export interface TerminalService {
89
+ export interface TerminalService extends TabAdornmentMethods {
99
90
  /**
100
91
  * Open a new terminal in a workspace (defaults to the active one). Returns the
101
92
  * created {@link TerminalRecord}; the PTY session spawns lazily when its tab
@@ -156,29 +147,24 @@ export interface TerminalService {
156
147
  focus(terminalId: string): void;
157
148
 
158
149
  /**
159
- * Register a decoration provider for terminal tabs. The first registered
160
- * provider that returns a non-null decoration for a terminal wins; subsequent
161
- * providers are not consulted. Returns a {@link Disposable} that unregisters
162
- * the provider.
150
+ * @deprecated Prefer {@link TerminalService.bindIndicator}. Thin shim that
151
+ * registers a trailing-indicator binder for terminal tabs only.
163
152
  */
164
153
  registerTabDecoration(provider: TerminalTabDecorationProvider): Disposable;
165
154
 
166
155
  /**
167
- * Get the current decoration for a terminal tab. Returns the first non-null
168
- * result from registered providers, or `null` if none apply.
156
+ * @deprecated Prefer {@link TerminalService.getIndicators}. Returns the first
157
+ * trailing indicator for a terminal tab, or `null`.
169
158
  */
170
159
  getTabDecoration(terminalId: string): TerminalTabDecoration | null;
171
160
 
172
161
  /**
173
- * Signal that tab decoration data has changed. Fires all listeners registered
174
- * via {@link TerminalService.subscribeTabDecorations}, causing terminal tabs
175
- * to re-query providers and re-render their decoration.
162
+ * @deprecated Prefer {@link TerminalService.invalidateTabAdornments}.
176
163
  */
177
164
  invalidateTabDecorations(): void;
178
165
 
179
166
  /**
180
- * Subscribe to tab decoration invalidations. Returns a {@link Disposable}
181
- * that cancels the subscription.
167
+ * @deprecated Prefer {@link TerminalService.subscribeTabAdornments}.
182
168
  */
183
169
  subscribeTabDecorations(listener: () => void): Disposable;
184
170
 
@@ -0,0 +1,190 @@
1
+ import type { ContextKeys } from "./context-keys";
2
+ import type { PhosphorIconName } from "./phosphor-icon";
3
+ import type { MenuEntry } from "./ui-service";
4
+
5
+ /**
6
+ * Built-in CenterDock surfaces that accept
7
+ * {@link ToolbarItemContribution}s. One surface per registration.
8
+ *
9
+ * @category Registration
10
+ * @public
11
+ */
12
+ export type ToolbarSurface = "editor" | "terminal";
13
+
14
+ /**
15
+ * The typed target each {@link ToolbarSurface} passes to an invoked command
16
+ * and to `when` / `checked` / {@link ToolbarMenuItemContribution.menu} builders.
17
+ *
18
+ * @category Registration
19
+ * @public
20
+ */
21
+ export interface ToolbarItemContext {
22
+ editor: { editorId: string };
23
+ terminal: { terminalId: string };
24
+ }
25
+
26
+ /**
27
+ * Shared fields for interactive toolbar contributions. Render chrome is driven
28
+ * by {@link ToolbarItemFields.icon | icon} + {@link ToolbarItemFields.title | title}:
29
+ *
30
+ * | icon | title | Control |
31
+ * | ---- | ----- | -------------- |
32
+ * | ✓ | — | icon-only |
33
+ * | — | ✓ | text-only |
34
+ * | ✓ | ✓ | icon + text |
35
+ *
36
+ * Icons are Phosphor export names ({@link PhosphorIconName}); the host
37
+ * resolves and paints them bold at 1em so they match local-web-viewer and
38
+ * track UI zoom. Pass a React node is no longer supported — use the name.
39
+ *
40
+ * @category Registration
41
+ * @public
42
+ */
43
+ export interface ToolbarItemFields<S extends ToolbarSurface = ToolbarSurface> {
44
+ /** Unique id for this contribution. */
45
+ id: string;
46
+ /** Which toolbar to contribute to. */
47
+ surface: S;
48
+ /**
49
+ * Leading glyph as a {@link PhosphorIconName} (e.g. `"Flag"`). Omit for a
50
+ * text-only control (requires {@link ToolbarItemFields.title | title}).
51
+ */
52
+ icon?: PhosphorIconName;
53
+ /**
54
+ * Visible label painted in the control. Omit for icon-only. When both
55
+ * `icon` and `title` are set, the host renders icon + text.
56
+ */
57
+ title?: string;
58
+ /** Hover tooltip (falls back to title / label / command label). */
59
+ tooltip?: string;
60
+ /**
61
+ * Accessible name (falls back to title / the command's label). Always used
62
+ * for `aria-label`; not painted unless {@link ToolbarItemFields.title | title}
63
+ * is also set.
64
+ */
65
+ label?: string;
66
+ /** Ordering within the trailing cluster; lower sorts first. */
67
+ order?: number;
68
+ /**
69
+ * Visibility predicate. Returning false hides the item for this target.
70
+ */
71
+ when?: (ctx: ContextKeys, target: ToolbarItemContext[S]) => boolean;
72
+ /**
73
+ * Toggle-state predicate for command items. When provided, the host renders
74
+ * the control in a pressed/checked visual state whenever this returns true.
75
+ * Menu items put checks on individual {@link MenuEntry} rows instead.
76
+ */
77
+ checked?: (ctx: ContextKeys, target: ToolbarItemContext[S]) => boolean;
78
+ }
79
+
80
+ /**
81
+ * Command-backed toolbar control — click runs {@link ToolbarCommandItemContribution.command}.
82
+ *
83
+ * @category Registration
84
+ * @public
85
+ */
86
+ export interface ToolbarCommandItemContribution<
87
+ S extends ToolbarSurface = ToolbarSurface,
88
+ > extends ToolbarItemFields<S> {
89
+ /** The command to run; receives {@link ToolbarItemContext}[S] as its first arg. */
90
+ command: string;
91
+ menu?: undefined;
92
+ type?: undefined;
93
+ }
94
+
95
+ /**
96
+ * Menu-backed toolbar control — click opens a host dropdown via
97
+ * {@link UiService.showMenu} with entries from
98
+ * {@link ToolbarMenuItemContribution.menu}.
99
+ *
100
+ * @category Registration
101
+ * @public
102
+ */
103
+ export interface ToolbarMenuItemContribution<
104
+ S extends ToolbarSurface = ToolbarSurface,
105
+ > extends ToolbarItemFields<S> {
106
+ /**
107
+ * Build the dropdown for this target. May be sync or async. The host
108
+ * anchors the menu on the toolbar control (`align: "end"`, toggle on).
109
+ */
110
+ menu: (target: ToolbarItemContext[S]) => MenuEntry[] | Promise<MenuEntry[]>;
111
+ command?: undefined;
112
+ type?: undefined;
113
+ }
114
+
115
+ /**
116
+ * Shared placement fields for non-interactive toolbar chrome
117
+ * ({@link ToolbarSeparatorContribution} / {@link ToolbarSpacerContribution}).
118
+ *
119
+ * @category Registration
120
+ * @public
121
+ */
122
+ export interface ToolbarChromeFields<
123
+ S extends ToolbarSurface = ToolbarSurface,
124
+ > {
125
+ id: string;
126
+ surface: S;
127
+ order?: number;
128
+ when?: (ctx: ContextKeys, target: ToolbarItemContext[S]) => boolean;
129
+ }
130
+
131
+ /**
132
+ * A light vertical rule between toolbar controls. Softer than the Text |
133
+ * Preview pipe — host paints it with a low-opacity mix of toolbar text, not
134
+ * `--silo-color-toolbar-text-disabled`.
135
+ *
136
+ * @category Registration
137
+ * @public
138
+ */
139
+ export interface ToolbarSeparatorContribution<
140
+ S extends ToolbarSurface = ToolbarSurface,
141
+ > extends ToolbarChromeFields<S> {
142
+ type: "separator";
143
+ }
144
+
145
+ /**
146
+ * Gap size for {@link ToolbarSpacerContribution}. Maps to em of the toolbar
147
+ * font (`sm` 0.25em / `md` 0.5em / `lg` 0.75em).
148
+ *
149
+ * @category Registration
150
+ * @public
151
+ */
152
+ export type ToolbarSpacerSize = "sm" | "md" | "lg";
153
+
154
+ /**
155
+ * An empty gap between toolbar controls (no rule). Use to group without a
156
+ * hard split; prefer {@link ToolbarSeparatorContribution} when a hairline helps.
157
+ *
158
+ * @category Registration
159
+ * @public
160
+ */
161
+ export interface ToolbarSpacerContribution<
162
+ S extends ToolbarSurface = ToolbarSurface,
163
+ > extends ToolbarChromeFields<S> {
164
+ type: "spacer";
165
+ /** Default `"md"`. */
166
+ size?: ToolbarSpacerSize;
167
+ }
168
+
169
+ /**
170
+ * Adds a control or chrome element to the trailing cluster of a built-in
171
+ * editor or terminal toolbar. Register via
172
+ * {@link ExtensionContext.registerToolbarItem}.
173
+ *
174
+ * Interactive items set exactly one of
175
+ * {@link ToolbarCommandItemContribution.command | command} or
176
+ * {@link ToolbarMenuItemContribution.menu | menu}. Separators and spacers use
177
+ * `type: "separator" | "spacer"`.
178
+ *
179
+ * Contributions are independent of context-menu items — an extension may
180
+ * register either, both, or neither. Hosts only render items while that
181
+ * surface's breadcrumbs setting is on.
182
+ *
183
+ * @category Registration
184
+ * @public
185
+ */
186
+ export type ToolbarItemContribution<S extends ToolbarSurface = ToolbarSurface> =
187
+ | ToolbarCommandItemContribution<S>
188
+ | ToolbarMenuItemContribution<S>
189
+ | ToolbarSeparatorContribution<S>
190
+ | ToolbarSpacerContribution<S>;
package/src/types.ts CHANGED
@@ -47,6 +47,7 @@ import type {
47
47
  ExtensionStorage,
48
48
  ExtensionStorageScopes,
49
49
  } from "./extension-storage";
50
+ import type { ToolbarItemContribution, ToolbarSurface } from "./toolbar-items";
50
51
 
51
52
  /**
52
53
  * The teardown handle returned by every `register*` call on
@@ -630,6 +631,22 @@ export interface ExtensionContext {
630
631
  registerContextMenuItem<S extends MenuSurface>(
631
632
  item: ContextMenuContribution<S>,
632
633
  ): Disposable;
634
+ /**
635
+ * Register a {@link ToolbarItemContribution} (icon-only, text-only,
636
+ * icon+text, or dropdown) in the trailing cluster of an editor or terminal
637
+ * toolbar. Independent of {@link ExtensionContext.registerContextMenuItem}
638
+ * — register either, both, or neither. Hosts only show items while that
639
+ * surface's breadcrumbs setting is on. See
640
+ * {@link ExtensionContext.invalidateToolbarItems}.
641
+ */
642
+ registerToolbarItem<S extends ToolbarSurface>(
643
+ item: ToolbarItemContribution<S>,
644
+ ): Disposable;
645
+ /**
646
+ * Signal that toolbar-item `when` / `checked` data changed. Causes editor
647
+ * and terminal toolbars to re-query contributions and re-render.
648
+ */
649
+ invalidateToolbarItems(): void;
633
650
  /** Register a {@link Keybinding} (bind a shortcut to a command). */
634
651
  registerKeybinding(binding: Keybinding): Disposable;
635
652
  /** Register a {@link SidePanel} (a left/right column panel). */