@silo-code/sdk 0.57.0 → 0.59.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.
@@ -50,6 +50,12 @@ export interface ToolbarItemContext {
50
50
  kindId: string;
51
51
  workspaceId: string;
52
52
  params: Readonly<Record<string, unknown>>;
53
+ /**
54
+ * This panel's {@link DockPanelRecord.id} — the same id {@link
55
+ * Workspace.panels} enumerates. `undefined` for a panel kind that isn't
56
+ * `persistence: "recorded"` (no record exists to name).
57
+ */
58
+ recordId?: string;
53
59
  };
54
60
  }
55
61
 
@@ -107,9 +113,49 @@ export interface ToolbarItemFields<S extends ToolbarSurface = ToolbarSurface> {
107
113
  checked?: (ctx: ContextKeys, target: ToolbarItemContext[S]) => boolean;
108
114
  }
109
115
 
116
+ /**
117
+ * The dropdown half of a {@link ToolbarCommandItemContribution} that sets
118
+ * {@link ToolbarCommandItemContribution.dropdown | dropdown} — the caret the
119
+ * host welds onto the right edge of the command control.
120
+ *
121
+ * It carries its own {@link ToolbarItemDropdown.label | label} and
122
+ * {@link ToolbarItemDropdown.tooltip | tooltip} because the two halves answer
123
+ * different questions: the action half names what clicking *does* ("Mark as
124
+ * follow-up: Bug"), the caret names what opening it *offers* ("Follow-up
125
+ * options"). Visibility is not its own concern — the whole control appears or
126
+ * hides together via {@link ToolbarItemFields.when | when}.
127
+ *
128
+ * @category Registration
129
+ * @public
130
+ */
131
+ export interface ToolbarItemDropdown<
132
+ S extends ToolbarSurface = ToolbarSurface,
133
+ > {
134
+ /**
135
+ * Build the dropdown for this target. May be sync or async. The host
136
+ * anchors the menu on the caret half (`align: "end"`, toggle on) — the same
137
+ * chrome a {@link ToolbarMenuItemContribution} gets.
138
+ */
139
+ menu: (target: ToolbarItemContext[S]) => MenuEntry[] | Promise<MenuEntry[]>;
140
+ /**
141
+ * Accessible name for the caret half. Falls back to the item's
142
+ * {@link ToolbarItemFields.label | label} suffixed with "options".
143
+ */
144
+ label?: string;
145
+ /** Hover tooltip for the caret half. Falls back to `label`. */
146
+ tooltip?: string;
147
+ }
148
+
110
149
  /**
111
150
  * Command-backed toolbar control — click runs {@link ToolbarCommandItemContribution.command}.
112
151
  *
152
+ * Adding {@link ToolbarCommandItemContribution.dropdown | dropdown} turns it
153
+ * into a **split control**: one welded unit whose left half runs the command
154
+ * and whose right half opens a menu. Reach for that when a toolbar has a
155
+ * single obvious default action plus variations on it — "mark with the default
156
+ * label" next to "mark with…" — rather than registering two adjacent items,
157
+ * which the host is free to separate, reorder, or collapse chrome between.
158
+ *
113
159
  * @category Registration
114
160
  * @public
115
161
  */
@@ -118,6 +164,16 @@ export interface ToolbarCommandItemContribution<
118
164
  > extends ToolbarItemFields<S> {
119
165
  /** The command to run; receives {@link ToolbarItemContext}[S] as its first arg. */
120
166
  command: string;
167
+ /**
168
+ * Optional dropdown half, welded to the command half as one split control.
169
+ * Omit for a plain command button.
170
+ *
171
+ * {@link ToolbarItemFields.checked | checked} still describes the *command* —
172
+ * but the host tints the whole control, caret included, so a marked split
173
+ * control reads as one pressed thing rather than a pressed button beside an
174
+ * unpressed caret.
175
+ */
176
+ dropdown?: ToolbarItemDropdown<S>;
121
177
  menu?: undefined;
122
178
  type?: undefined;
123
179
  }
@@ -139,6 +195,12 @@ export interface ToolbarMenuItemContribution<
139
195
  */
140
196
  menu: (target: ToolbarItemContext[S]) => MenuEntry[] | Promise<MenuEntry[]>;
141
197
  command?: undefined;
198
+ /**
199
+ * A menu-only control is already all dropdown — there is no action half to
200
+ * weld one onto. Use {@link ToolbarCommandItemContribution.dropdown} for a
201
+ * split control.
202
+ */
203
+ dropdown?: undefined;
142
204
  type?: undefined;
143
205
  }
144
206
 
@@ -204,8 +266,9 @@ export interface ToolbarSpacerContribution<
204
266
  *
205
267
  * Interactive items set exactly one of
206
268
  * {@link ToolbarCommandItemContribution.command | command} or
207
- * {@link ToolbarMenuItemContribution.menu | menu}. Separators and spacers use
208
- * `type: "separator" | "spacer"`.
269
+ * {@link ToolbarMenuItemContribution.menu | menu}; a command item may also set
270
+ * {@link ToolbarCommandItemContribution.dropdown | dropdown} to become a split
271
+ * control. Separators and spacers use `type: "separator" | "spacer"`.
209
272
  *
210
273
  * Contributions are independent of context-menu items — an extension may
211
274
  * register either, both, or neither. Hosts only render items while that
package/src/types.ts CHANGED
@@ -505,6 +505,15 @@ export interface MenuContext {
505
505
  kindId: string;
506
506
  workspaceId: string;
507
507
  params: Readonly<Record<string, unknown>>;
508
+ /**
509
+ * This tab's {@link DockPanelRecord.id} — the same id {@link
510
+ * Workspace.panels} enumerates, so a handler that persists something
511
+ * per-panel can key off it directly instead of rebuilding a
512
+ * `panelId → DockPanelRecord.id` index from `Workspace.panels` itself.
513
+ * `undefined` for a panel kind that isn't `persistence: "recorded"` (no
514
+ * record exists to name).
515
+ */
516
+ recordId?: string;
508
517
  };
509
518
  workspace: Workspace;
510
519
  }