Skip to content

Commit c1e032c

Browse files
committed
refactor: rename overlay CommandPalette → ComboBox
The existing "command palette" overlay is a per-WebView generic searchable picker (currently used by hello-rock3 to pick USFM markers), not a global command-launcher. The CommandPalette name was misleading from day one — the original type comment even hinted at the conflation ("marker code like 'ft' or command name") — and it conflicted with the broader Action Palette concept proposed separately (see PR #2284 and docs/plans/2026-05-15-action-palette-proposal.md). This overlay is the cross-iframe analog of the in-tree `ComboBox` component in `platform-bible-react` — both are built on shadcn's `Command` (which wraps cmdk). cmdk explicitly positions its `Command` primitive as serving both command palettes and accessible comboboxes; aligning the overlay's name with `ComboBox` puts the right breadcrumb for extension authors. Renames: - Types: CommandPaletteItem → ComboBoxItem, CommandPaletteRequest → ComboBoxRequest - Service method: showCommandPalette → showComboBox - Component files: overlay-command-palette.* → overlay-combo-box.* (matches pbr's combo-box.component.tsx kebab-case) - Internal symbols: validateCommandPaletteRequest, OverlayCommandPalette*, localizeCommandPaletteItems, etc. - Overlay discriminator: 'commandPalette' → 'comboBox' - Data attributes: data-overlay-command-palette* → data-overlay-combo-box* - LocalizeKeys: %overlay_commandPalette_*% → %overlay_comboBox_*%, %overlay_aria_commandPaletteOpened% → ...comboBoxOpened% Public PAPI surface preserves CommandPaletteItem, CommandPaletteRequest, and showCommandPalette as @deprecated aliases so out-of-repo extensions keep working. Capitalization note: cmdk's preferred spelling for non-command-palette uses of `Command` is `Combobox` (lowercase b). pbr uses `ComboBox` (capital B); this overlay matches pbr for consistency. Harmonizing toward cmdk's spelling is out of scope here — a future refactor could rename pbr's `ComboBox` → `Combobox`, pbr's `MultiSelectComboBox` → `ComboboxMulti`, and the overlay correspondingly. Flagged for a follow-up PR. Localization values updated: - en: 'Command palette opened' → 'Combo box opened' - es: 'Paleta de comandos abierta' → 'Cuadro combinado abierto' (flag for localizer review) 167 overlay tests pass; ESLint clean; papi.d.ts regenerated.
1 parent ac37eda commit c1e032c

15 files changed

Lines changed: 270 additions & 254 deletions

assets/localization/en.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -274,15 +274,15 @@
274274
"%markerMenu_noResults%": "No results found.",
275275
"%markerMenu_searchPlaceholder%": "Type a style or search.",
276276
"%menuItemName_wordList%": "Word List",
277-
"%overlay_aria_commandPaletteOpened%": "Command palette opened",
277+
"%overlay_aria_comboBoxOpened%": "Combo box opened",
278278
"%overlay_aria_contextMenuOpened%": "Context menu opened",
279279
"%overlay_aria_dialogOpened%": "{title} dialog opened",
280280
"%overlay_aria_popoverOpened%": "Popover opened",
281281
"%overlay_dialog_title_alert%": "Alert",
282282
"%overlay_dialog_title_confirm%": "Confirm",
283283
"%overlay_dialog_title_dialog%": "Dialog",
284-
"%overlay_commandPalette_searchPlaceholder%": "Search...",
285-
"%overlay_commandPalette_noResults%": "No results found",
284+
"%overlay_comboBox_searchPlaceholder%": "Search...",
285+
"%overlay_comboBox_noResults%": "No results found",
286286
"%product_name%": "Platform.Bible",
287287
"%product_shortName%": "Platform",
288288
"%project_full_name_missing%": "*Name Missing*",

assets/localization/es.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -395,15 +395,15 @@
395395
"%markerMenu_noResults%": "No se encontraron resultados.",
396396
"%markerMenu_searchPlaceholder%": "Escriba un estilo o busque.",
397397
"%menuItemName_wordList%": "Lista de Palabras",
398-
"%overlay_aria_commandPaletteOpened%": "Paleta de comandos abierta",
398+
"%overlay_aria_comboBoxOpened%": "Cuadro combinado abierto",
399399
"%overlay_aria_contextMenuOpened%": "Menú contextual abierto",
400400
"%overlay_aria_dialogOpened%": "Diálogo {title} abierto",
401401
"%overlay_aria_popoverOpened%": "Ventana emergente abierta",
402402
"%overlay_dialog_title_alert%": "Alerta",
403403
"%overlay_dialog_title_confirm%": "Confirmar",
404404
"%overlay_dialog_title_dialog%": "Diálogo",
405-
"%overlay_commandPalette_searchPlaceholder%": "Buscar...",
406-
"%overlay_commandPalette_noResults%": "No se encontraron resultados",
405+
"%overlay_comboBox_searchPlaceholder%": "Buscar...",
406+
"%overlay_comboBox_noResults%": "No se encontraron resultados",
407407
"%product_name%": "Platform.Bible",
408408
"%product_shortName%": "Platform",
409409
"%project_full_name_missing%": "*Falta el Nombre*",

extensions/src/hello-rock3/src/web-views/hello-rock3.web-view.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -536,9 +536,9 @@ globalThis.webViewComponent = function HelloRock3({
536536
dismissPersonPopover();
537537
}, [dismissPersonPopover]);
538538

539-
// Command palette demo handler
540-
const handleCommandPalette = useCallback(async () => {
541-
const result = await papi.overlays.showCommandPalette(
539+
// Combo box demo handler
540+
const handleComboBox = useCallback(async () => {
541+
const result = await papi.overlays.showComboBox(
542542
{
543543
items: [
544544
{ id: 'p', label: 'Paragraph (p)', description: 'Normal paragraph', group: 'Paragraphs' },
@@ -573,7 +573,7 @@ globalThis.webViewComponent = function HelloRock3({
573573
},
574574
globalThis.webViewId,
575575
);
576-
logger.debug(`Command palette selected: ${result ?? 'dismissed'}`);
576+
logger.debug(`Combo box selected: ${result ?? 'dismissed'}`);
577577
}, []);
578578

579579
// #endregion
@@ -642,10 +642,10 @@ globalThis.webViewComponent = function HelloRock3({
642642
</Button>
643643
</div>
644644
)}
645-
{/* Overlay service demo: command palette */}
645+
{/* Overlay service demo: combo box */}
646646
<div>
647-
<Button data-testid="command-palette-trigger" onClick={handleCommandPalette}>
648-
Show Command Palette
647+
<Button data-testid="combo-box-trigger" onClick={handleComboBox}>
648+
Show Quick Pick
649649
</Button>
650650
</div>
651651
{/* Overlay service demo: hover to show person details popover */}

lib/papi-dts/papi.d.ts

Lines changed: 57 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -7946,7 +7946,7 @@ declare module 'renderer/components/overlays/overlay-context-menu.component' {
79467946
declare module 'renderer/services/overlays/overlay.service-model' {
79477947
/**
79487948
* Type definitions for the overlay service, a renderer-only service that manages overlays (context
7949-
* menus, popovers, command palettes) rendered in the renderer's top-level document outside iframe
7949+
* menus, popovers, combo boxes) rendered in the renderer's top-level document outside iframe
79507950
* boundaries. Extensions running in sandboxed WebView iframes cannot render UI above other content,
79517951
* so this service provides a way for them to request overlays that the renderer hosts on their
79527952
* behalf.
@@ -8031,13 +8031,13 @@ declare module 'renderer/services/overlays/overlay.service-model' {
80318031
showArrow?: boolean;
80328032
}
80338033
/**
8034-
* A single item in a command palette. Items are displayed in a searchable, filterable list. The
8035-
* user types to filter and selects one item.
8034+
* A single item in a combo box. Items are displayed in a searchable, filterable list. The user
8035+
* types to filter and selects one item.
80368036
*/
8037-
export type CommandPaletteItem = {
8037+
export type ComboBoxItem = {
80388038
/** Unique identifier returned when this item is selected */
80398039
id: string;
8040-
/** Primary display text (e.g., marker code like "ft" or command name) */
8040+
/** Primary display text (e.g., marker code like "ft") */
80418041
label: string | LocalizeKey;
80428042
/** Secondary description text displayed below the label */
80438043
description?: string | LocalizeKey;
@@ -8050,12 +8050,12 @@ declare module 'renderer/services/overlays/overlay.service-model' {
80508050
/** Whether the item is grayed out and non-selectable. Defaults to false. */
80518051
disabled?: boolean;
80528052
};
8053-
/** Request payload for {@link IOverlayService.showCommandPalette}. */
8054-
export interface CommandPaletteRequest {
8053+
/** Request payload for {@link IOverlayService.showComboBox}. */
8054+
export interface ComboBoxRequest {
80558055
/** The selectable items to display */
8056-
items: CommandPaletteItem[];
8056+
items: ComboBoxItem[];
80578057
/**
8058-
* Anchor position in pixels relative to the requesting WebView's iframe origin. The palette is
8058+
* Anchor position in pixels relative to the requesting WebView's iframe origin. The combo box is
80598059
* positioned adjacent to this point. If omitted, centers in the viewport.
80608060
*/
80618061
anchor?: {
@@ -8064,31 +8064,39 @@ declare module 'renderer/services/overlays/overlay.service-model' {
80648064
width?: number;
80658065
height?: number;
80668066
};
8067-
/** Preferred side of the anchor to place the palette. Defaults to 'bottom'. */
8067+
/** Preferred side of the anchor to place the combo box. Defaults to 'bottom'. */
80688068
side?: 'top' | 'bottom' | 'left' | 'right';
80698069
/** Placeholder text for the search input */
80708070
placeholder?: string | LocalizeKey;
80718071
/** Maximum width in pixels. Defaults to 500. */
80728072
maxWidth?: number;
80738073
/** Maximum height in pixels. Defaults to 400. */
80748074
maxHeight?: number;
8075-
/** Whether clicking outside dismisses the palette. Defaults to true. */
8075+
/** Whether clicking outside dismisses the combo box. Defaults to true. */
80768076
dismissOnClickOutside?: boolean;
80778077
}
8078+
/**
8079+
* @deprecated Use {@link ComboBoxItem}. The "command palette" terminology was misleading — this
8080+
* overlay is a generic per-WebView searchable picker (used today for USFM marker selection), not
8081+
* the global Action Palette concept. See `docs/plans/2026-05-15-action-palette-proposal.md`.
8082+
*/
8083+
export type CommandPaletteItem = ComboBoxItem;
8084+
/** @deprecated Use {@link ComboBoxRequest}. See {@link CommandPaletteItem} for context. */
8085+
export type CommandPaletteRequest = ComboBoxRequest;
80788086
/**
80798087
*
8080-
* Service for showing overlays (context menus, popovers, command palettes) that render outside
8081-
* iframe boundaries in the renderer's top-level document. Renderer-only service.
8088+
* Service for showing overlays (context menus, popovers, combo boxes) that render outside iframe
8089+
* boundaries in the renderer's top-level document. Renderer-only service.
80828090
*
80838091
* Extensions in sandboxed WebView iframes cannot render UI above other content or outside their
80848092
* iframe bounds. This service accepts overlay requests from WebViews, translates their
80858093
* iframe-relative coordinates to document-level coordinates, and renders the overlay in the
80868094
* renderer's React tree. Each method returns a promise that resolves when the user interacts with
80878095
* the overlay or it is dismissed.
80888096
*
8089-
* Only one overlay of each type (context menu, popover, command palette) can be active per WebView
8090-
* at a time. Requesting a new overlay of the same type from the same WebView replaces the previous
8091-
* one and rejects its promise with a PlatformError with code ABORTED.
8097+
* Only one overlay of each type (context menu, popover, combo box) can be active per WebView at a
8098+
* time. Requesting a new overlay of the same type from the same WebView replaces the previous one
8099+
* and rejects its promise with a PlatformError with code ABORTED.
80928100
*/
80938101
export interface IOverlayService {
80948102
/**
@@ -8159,20 +8167,21 @@ declare module 'renderer/services/overlays/overlay.service-model' {
81598167
*/
81608168
onPopoverDismissed(overlayId: string): Promise<string | undefined>;
81618169
/**
8162-
* Shows a command palette with searchable/filterable items. Returns a promise that resolves with
8163-
* the selected item's `id`, or `undefined` if dismissed.
8170+
* Shows a combo box with searchable/filterable items. Returns a promise that resolves with the
8171+
* selected item's `id`, or `undefined` if dismissed.
81648172
*
81658173
* @param request The items, optional anchor position, and display options
8166-
* @param webViewId The ID of the WebView requesting the command palette
8174+
* @param webViewId The ID of the WebView requesting the combo box
81678175
* @returns The selected item's ID, or `undefined` if dismissed
81688176
* @throws PlatformError with code INVALID_ARGUMENT if the request is invalid
8169-
* @throws PlatformError with code ABORTED if replaced by another command palette from the same
8170-
* WebView
8177+
* @throws PlatformError with code ABORTED if replaced by another combo box from the same WebView
81718178
*/
8172-
showCommandPalette(
8173-
request: CommandPaletteRequest,
8174-
webViewId: string,
8175-
): Promise<string | undefined>;
8179+
showComboBox(request: ComboBoxRequest, webViewId: string): Promise<string | undefined>;
8180+
/**
8181+
* @deprecated Use {@link showComboBox}. The "command palette" terminology was misleading; see
8182+
* `docs/plans/2026-05-15-action-palette-proposal.md`.
8183+
*/
8184+
showCommandPalette(request: ComboBoxRequest, webViewId: string): Promise<string | undefined>;
81768185
}
81778186
/**
81788187
* Internal representation of an active overlay stored in the overlay store. Each entry holds the
@@ -8184,7 +8193,7 @@ declare module 'renderer/services/overlays/overlay.service-model' {
81848193
* - `'contextMenu'` — An active context menu with translated position and menu items.
81858194
* - `'modalDialog'` — An active modal dialog with its type-specific options.
81868195
* - `'popover'` — An active popover with mutable `content` (updatable via `updatePopover`).
8187-
* - `'commandPalette'` — An active command palette with searchable/filterable items.
8196+
* - `'comboBox'` — An active combo box with searchable/filterable items.
81888197
*
81898198
* UI components read entries from the overlay store to render overlays, then call `resolve` or
81908199
* `reject` when the user interacts with or dismisses them.
@@ -8250,15 +8259,15 @@ declare module 'renderer/services/overlays/overlay.service-model' {
82508259
reject: (error: PlatformError) => void;
82518260
}
82528261
| {
8253-
type: 'commandPalette';
8262+
type: 'comboBox';
82548263
/** Unique overlay identifier generated by the service */
82558264
id: string;
82568265
/** The WebView that requested this overlay */
82578266
webViewId: string;
82588267
/** The original request */
8259-
request: CommandPaletteRequest;
8268+
request: ComboBoxRequest;
82608269
/** Items to render */
8261-
items: CommandPaletteItem[];
8270+
items: ComboBoxItem[];
82628271
/** Document-relative position (translated + clamped), or undefined for centered */
82638272
position?: {
82648273
x: number;
@@ -8277,7 +8286,7 @@ declare module 'renderer/services/overlays/overlay.service-model' {
82778286
contextMenu: string | undefined;
82788287
modalDialog: unknown;
82798288
popover: string | undefined;
8280-
commandPalette: string | undefined;
8289+
comboBox: string | undefined;
82818290
};
82828291
}
82838292
declare module 'shared/services/app.service-model' {
@@ -8976,7 +8985,11 @@ declare module '@papi/core' {
89768985
export type { DialogTypes } from 'renderer/components/dialogs/dialog-definition.model';
89778986
export type { UseDialogCallbackOptions } from 'renderer/hooks/papi-hooks/use-dialog-callback.hook';
89788987
export type {
8988+
ComboBoxItem,
8989+
ComboBoxRequest,
8990+
/** @deprecated Use {@link ComboBoxItem}. */
89798991
CommandPaletteItem,
8992+
/** @deprecated Use {@link ComboBoxRequest}. */
89808993
CommandPaletteRequest,
89818994
IOverlayService,
89828995
PopoverAction,
@@ -10277,7 +10290,7 @@ declare module 'renderer/services/overlays/overlay-menu-converter' {
1027710290
declare module 'renderer/services/overlays/overlay-validation' {
1027810291
import type { OverlayContextMenuItem } from 'renderer/components/overlays/overlay-context-menu.component';
1027910292
import {
10280-
CommandPaletteRequest,
10293+
ComboBoxRequest,
1028110294
PopoverRequest,
1028210295
} from 'renderer/services/overlays/overlay.service-model';
1028310296
/**
@@ -10303,12 +10316,12 @@ declare module 'renderer/services/overlays/overlay-validation' {
1030310316
*/
1030410317
export function validatePopoverRequest(request: PopoverRequest): void;
1030510318
/**
10306-
* Validates a command palette request's items, anchor, and options.
10319+
* Validates a combo box request's items, anchor, and options.
1030710320
*
10308-
* @param request The command palette request to validate
10321+
* @param request The combo box request to validate
1030910322
* @throws PlatformError with code INVALID_ARGUMENT if validation fails
1031010323
*/
10311-
export function validateCommandPaletteRequest(request: CommandPaletteRequest): void;
10324+
export function validateComboBoxRequest(request: ComboBoxRequest): void;
1031210325
}
1031310326
declare module 'renderer/services/overlays/overlay-coordinates' {
1031410327
/**
@@ -10821,18 +10834,18 @@ declare module '@papi/frontend' {
1082110834
window: IWindowService;
1082210835
/**
1082310836
*
10824-
* Service for showing overlays (context menus, popovers, command palettes) that render outside
10825-
* iframe boundaries in the renderer's top-level document. Renderer-only service.
10837+
* Service for showing overlays (context menus, popovers, combo boxes) that render outside iframe
10838+
* boundaries in the renderer's top-level document. Renderer-only service.
1082610839
*
1082710840
* Extensions in sandboxed WebView iframes cannot render UI above other content or outside their
1082810841
* iframe bounds. This service accepts overlay requests from WebViews, translates their
1082910842
* iframe-relative coordinates to document-level coordinates, and renders the overlay in the
1083010843
* renderer's React tree. Each method returns a promise that resolves when the user interacts with
1083110844
* the overlay or it is dismissed.
1083210845
*
10833-
* Only one overlay of each type (context menu, popover, command palette) can be active per WebView
10834-
* at a time. Requesting a new overlay of the same type from the same WebView replaces the previous
10835-
* one and rejects its promise with a PlatformError with code ABORTED.
10846+
* Only one overlay of each type (context menu, popover, combo box) can be active per WebView at a
10847+
* time. Requesting a new overlay of the same type from the same WebView replaces the previous one
10848+
* and rejects its promise with a PlatformError with code ABORTED.
1083610849
*/
1083710850
overlays: IOverlayService;
1083810851
};
@@ -10990,18 +11003,18 @@ declare module '@papi/frontend' {
1099011003
export const window: IWindowService;
1099111004
/**
1099211005
*
10993-
* Service for showing overlays (context menus, popovers, command palettes) that render outside
10994-
* iframe boundaries in the renderer's top-level document. Renderer-only service.
11006+
* Service for showing overlays (context menus, popovers, combo boxes) that render outside iframe
11007+
* boundaries in the renderer's top-level document. Renderer-only service.
1099511008
*
1099611009
* Extensions in sandboxed WebView iframes cannot render UI above other content or outside their
1099711010
* iframe bounds. This service accepts overlay requests from WebViews, translates their
1099811011
* iframe-relative coordinates to document-level coordinates, and renders the overlay in the
1099911012
* renderer's React tree. Each method returns a promise that resolves when the user interacts with
1100011013
* the overlay or it is dismissed.
1100111014
*
11002-
* Only one overlay of each type (context menu, popover, command palette) can be active per WebView
11003-
* at a time. Requesting a new overlay of the same type from the same WebView replaces the previous
11004-
* one and rejects its promise with a PlatformError with code ABORTED.
11015+
* Only one overlay of each type (context menu, popover, combo box) can be active per WebView at a
11016+
* time. Requesting a new overlay of the same type from the same WebView replaces the previous one
11017+
* and rejects its promise with a PlatformError with code ABORTED.
1100511018
*/
1100611019
export const overlays: IOverlayService;
1100711020
export type Papi = typeof papi;

src/renderer/components/overlay-host.component.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* overlay store and renders the appropriate overlay components.
44
*/
55

6-
import { OverlayCommandPalette } from '@renderer/components/overlays/overlay-command-palette.component';
6+
import { OverlayComboBox } from '@renderer/components/overlays/overlay-combo-box.component';
77
import { OverlayContextMenu } from '@renderer/components/overlays/overlay-context-menu.component';
88
import { OverlayModalDialog } from '@renderer/components/overlays/overlay-modal-dialog.component';
99
import { OverlayPopover } from '@renderer/components/overlays/overlay-popover.component';
@@ -39,8 +39,8 @@ export function OverlayHost() {
3939
if (overlay.type === 'popover') {
4040
return <OverlayPopover key={overlay.id} overlay={overlay} />;
4141
}
42-
if (overlay.type === 'commandPalette') {
43-
return <OverlayCommandPalette key={overlay.id} overlay={overlay} />;
42+
if (overlay.type === 'comboBox') {
43+
return <OverlayComboBox key={overlay.id} overlay={overlay} />;
4444
}
4545
return undefined;
4646
})}

0 commit comments

Comments
 (0)