Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions assets/localization/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -274,15 +274,15 @@
"%markerMenu_noResults%": "No results found.",
"%markerMenu_searchPlaceholder%": "Type a style or search.",
"%menuItemName_wordList%": "Word List",
"%overlay_aria_commandPaletteOpened%": "Command palette opened",
"%overlay_aria_comboBoxOpened%": "Combo box opened",
"%overlay_aria_contextMenuOpened%": "Context menu opened",
"%overlay_aria_dialogOpened%": "{title} dialog opened",
"%overlay_aria_popoverOpened%": "Popover opened",
"%overlay_dialog_title_alert%": "Alert",
"%overlay_dialog_title_confirm%": "Confirm",
"%overlay_dialog_title_dialog%": "Dialog",
"%overlay_commandPalette_searchPlaceholder%": "Search...",
"%overlay_commandPalette_noResults%": "No results found",
"%overlay_comboBox_searchPlaceholder%": "Search...",
"%overlay_comboBox_noResults%": "No results found",
"%product_name%": "Platform.Bible",
"%product_shortName%": "Platform",
"%project_full_name_missing%": "*Name Missing*",
Expand Down
6 changes: 3 additions & 3 deletions assets/localization/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -395,15 +395,15 @@
"%markerMenu_noResults%": "No se encontraron resultados.",
"%markerMenu_searchPlaceholder%": "Escriba un estilo o busque.",
"%menuItemName_wordList%": "Lista de Palabras",
"%overlay_aria_commandPaletteOpened%": "Paleta de comandos abierta",
"%overlay_aria_comboBoxOpened%": "Cuadro combinado abierto",
"%overlay_aria_contextMenuOpened%": "Menú contextual abierto",
"%overlay_aria_dialogOpened%": "Diálogo {title} abierto",
"%overlay_aria_popoverOpened%": "Ventana emergente abierta",
"%overlay_dialog_title_alert%": "Alerta",
"%overlay_dialog_title_confirm%": "Confirmar",
"%overlay_dialog_title_dialog%": "Diálogo",
"%overlay_commandPalette_searchPlaceholder%": "Buscar...",
"%overlay_commandPalette_noResults%": "No se encontraron resultados",
"%overlay_comboBox_searchPlaceholder%": "Buscar...",
"%overlay_comboBox_noResults%": "No se encontraron resultados",
"%product_name%": "Platform.Bible",
"%product_shortName%": "Platform",
"%project_full_name_missing%": "*Falta el Nombre*",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -536,9 +536,9 @@ globalThis.webViewComponent = function HelloRock3({
dismissPersonPopover();
}, [dismissPersonPopover]);

// Command palette demo handler
const handleCommandPalette = useCallback(async () => {
const result = await papi.overlays.showCommandPalette(
// Combo box demo handler
const handleComboBox = useCallback(async () => {
const result = await papi.overlays.showComboBox(
{
items: [
{ id: 'p', label: 'Paragraph (p)', description: 'Normal paragraph', group: 'Paragraphs' },
Expand Down Expand Up @@ -573,7 +573,7 @@ globalThis.webViewComponent = function HelloRock3({
},
globalThis.webViewId,
);
logger.debug(`Command palette selected: ${result ?? 'dismissed'}`);
logger.debug(`Combo box selected: ${result ?? 'dismissed'}`);
}, []);

// #endregion
Expand Down Expand Up @@ -642,10 +642,10 @@ globalThis.webViewComponent = function HelloRock3({
</Button>
</div>
)}
{/* Overlay service demo: command palette */}
{/* Overlay service demo: combo box */}
<div>
<Button data-testid="command-palette-trigger" onClick={handleCommandPalette}>
Show Command Palette
<Button data-testid="combo-box-trigger" onClick={handleComboBox}>
Show Quick Pick
</Button>
</div>
{/* Overlay service demo: hover to show person details popover */}
Expand Down
101 changes: 57 additions & 44 deletions lib/papi-dts/papi.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7918,7 +7918,7 @@ declare module 'renderer/components/overlays/overlay-context-menu.component' {
declare module 'renderer/services/overlays/overlay.service-model' {
/**
* Type definitions for the overlay service, a renderer-only service that manages overlays (context
* menus, popovers, command palettes) rendered in the renderer's top-level document outside iframe
* menus, popovers, combo boxes) rendered in the renderer's top-level document outside iframe
* boundaries. Extensions running in sandboxed WebView iframes cannot render UI above other content,
* so this service provides a way for them to request overlays that the renderer hosts on their
* behalf.
Expand Down Expand Up @@ -8003,13 +8003,13 @@ declare module 'renderer/services/overlays/overlay.service-model' {
showArrow?: boolean;
}
/**
* A single item in a command palette. Items are displayed in a searchable, filterable list. The
* user types to filter and selects one item.
* A single item in a combo box. Items are displayed in a searchable, filterable list. The user
* types to filter and selects one item.
*/
export type CommandPaletteItem = {
export type ComboBoxItem = {
/** Unique identifier returned when this item is selected */
id: string;
/** Primary display text (e.g., marker code like "ft" or command name) */
/** Primary display text (e.g., marker code like "ft") */
label: string | LocalizeKey;
/** Secondary description text displayed below the label */
description?: string | LocalizeKey;
Expand All @@ -8022,12 +8022,12 @@ declare module 'renderer/services/overlays/overlay.service-model' {
/** Whether the item is grayed out and non-selectable. Defaults to false. */
disabled?: boolean;
};
/** Request payload for {@link IOverlayService.showCommandPalette}. */
export interface CommandPaletteRequest {
/** Request payload for {@link IOverlayService.showComboBox}. */
export interface ComboBoxRequest {
/** The selectable items to display */
items: CommandPaletteItem[];
items: ComboBoxItem[];
/**
* Anchor position in pixels relative to the requesting WebView's iframe origin. The palette is
* Anchor position in pixels relative to the requesting WebView's iframe origin. The combo box is
* positioned adjacent to this point. If omitted, centers in the viewport.
*/
anchor?: {
Expand All @@ -8036,31 +8036,39 @@ declare module 'renderer/services/overlays/overlay.service-model' {
width?: number;
height?: number;
};
/** Preferred side of the anchor to place the palette. Defaults to 'bottom'. */
/** Preferred side of the anchor to place the combo box. Defaults to 'bottom'. */
side?: 'top' | 'bottom' | 'left' | 'right';
/** Placeholder text for the search input */
placeholder?: string | LocalizeKey;
/** Maximum width in pixels. Defaults to 500. */
maxWidth?: number;
/** Maximum height in pixels. Defaults to 400. */
maxHeight?: number;
/** Whether clicking outside dismisses the palette. Defaults to true. */
/** Whether clicking outside dismisses the combo box. Defaults to true. */
dismissOnClickOutside?: boolean;
}
/**
* @deprecated Use {@link ComboBoxItem}. The "command palette" terminology was misleading — this
* overlay is a generic per-WebView searchable picker (used today for USFM marker selection), not
* the global Action Palette concept. See `docs/plans/2026-05-15-action-palette-proposal.md`.
*/
export type CommandPaletteItem = ComboBoxItem;
/** @deprecated Use {@link ComboBoxRequest}. See {@link CommandPaletteItem} for context. */
export type CommandPaletteRequest = ComboBoxRequest;
/**
*
* Service for showing overlays (context menus, popovers, command palettes) that render outside
* iframe boundaries in the renderer's top-level document. Renderer-only service.
* Service for showing overlays (context menus, popovers, combo boxes) that render outside iframe
* boundaries in the renderer's top-level document. Renderer-only service.
*
* Extensions in sandboxed WebView iframes cannot render UI above other content or outside their
* iframe bounds. This service accepts overlay requests from WebViews, translates their
* iframe-relative coordinates to document-level coordinates, and renders the overlay in the
* renderer's React tree. Each method returns a promise that resolves when the user interacts with
* the overlay or it is dismissed.
*
* Only one overlay of each type (context menu, popover, command palette) can be active per WebView
* at a time. Requesting a new overlay of the same type from the same WebView replaces the previous
* one and rejects its promise with a PlatformError with code ABORTED.
* Only one overlay of each type (context menu, popover, combo box) can be active per WebView at a
* time. Requesting a new overlay of the same type from the same WebView replaces the previous one
* and rejects its promise with a PlatformError with code ABORTED.
*/
export interface IOverlayService {
/**
Expand Down Expand Up @@ -8131,20 +8139,21 @@ declare module 'renderer/services/overlays/overlay.service-model' {
*/
onPopoverDismissed(overlayId: string): Promise<string | undefined>;
/**
* Shows a command palette with searchable/filterable items. Returns a promise that resolves with
* the selected item's `id`, or `undefined` if dismissed.
* Shows a combo box with searchable/filterable items. Returns a promise that resolves with the
* selected item's `id`, or `undefined` if dismissed.
*
* @param request The items, optional anchor position, and display options
* @param webViewId The ID of the WebView requesting the command palette
* @param webViewId The ID of the WebView requesting the combo box
* @returns The selected item's ID, or `undefined` if dismissed
* @throws PlatformError with code INVALID_ARGUMENT if the request is invalid
* @throws PlatformError with code ABORTED if replaced by another command palette from the same
* WebView
* @throws PlatformError with code ABORTED if replaced by another combo box from the same WebView
*/
showCommandPalette(
request: CommandPaletteRequest,
webViewId: string,
): Promise<string | undefined>;
showComboBox(request: ComboBoxRequest, webViewId: string): Promise<string | undefined>;
/**
* @deprecated Use {@link showComboBox}. The "command palette" terminology was misleading; see
* `docs/plans/2026-05-15-action-palette-proposal.md`.
*/
showCommandPalette(request: ComboBoxRequest, webViewId: string): Promise<string | undefined>;
}
/**
* Internal representation of an active overlay stored in the overlay store. Each entry holds the
Expand All @@ -8156,7 +8165,7 @@ declare module 'renderer/services/overlays/overlay.service-model' {
* - `'contextMenu'` — An active context menu with translated position and menu items.
* - `'modalDialog'` — An active modal dialog with its type-specific options.
* - `'popover'` — An active popover with mutable `content` (updatable via `updatePopover`).
* - `'commandPalette'` — An active command palette with searchable/filterable items.
* - `'comboBox'` — An active combo box with searchable/filterable items.
*
* UI components read entries from the overlay store to render overlays, then call `resolve` or
* `reject` when the user interacts with or dismisses them.
Expand Down Expand Up @@ -8222,15 +8231,15 @@ declare module 'renderer/services/overlays/overlay.service-model' {
reject: (error: PlatformError) => void;
}
| {
type: 'commandPalette';
type: 'comboBox';
/** Unique overlay identifier generated by the service */
id: string;
/** The WebView that requested this overlay */
webViewId: string;
/** The original request */
request: CommandPaletteRequest;
request: ComboBoxRequest;
/** Items to render */
items: CommandPaletteItem[];
items: ComboBoxItem[];
/** Document-relative position (translated + clamped), or undefined for centered */
position?: {
x: number;
Expand All @@ -8249,7 +8258,7 @@ declare module 'renderer/services/overlays/overlay.service-model' {
contextMenu: string | undefined;
modalDialog: unknown;
popover: string | undefined;
commandPalette: string | undefined;
comboBox: string | undefined;
};
}
declare module 'shared/services/app.service-model' {
Expand Down Expand Up @@ -8948,7 +8957,11 @@ declare module '@papi/core' {
export type { DialogTypes } from 'renderer/components/dialogs/dialog-definition.model';
export type { UseDialogCallbackOptions } from 'renderer/hooks/papi-hooks/use-dialog-callback.hook';
export type {
ComboBoxItem,
ComboBoxRequest,
/** @deprecated Use {@link ComboBoxItem}. */
CommandPaletteItem,
/** @deprecated Use {@link ComboBoxRequest}. */
CommandPaletteRequest,
IOverlayService,
PopoverAction,
Expand Down Expand Up @@ -10249,7 +10262,7 @@ declare module 'renderer/services/overlays/overlay-menu-converter' {
declare module 'renderer/services/overlays/overlay-validation' {
import type { OverlayContextMenuItem } from 'renderer/components/overlays/overlay-context-menu.component';
import {
CommandPaletteRequest,
ComboBoxRequest,
PopoverRequest,
} from 'renderer/services/overlays/overlay.service-model';
/**
Expand All @@ -10275,12 +10288,12 @@ declare module 'renderer/services/overlays/overlay-validation' {
*/
export function validatePopoverRequest(request: PopoverRequest): void;
/**
* Validates a command palette request's items, anchor, and options.
* Validates a combo box request's items, anchor, and options.
*
* @param request The command palette request to validate
* @param request The combo box request to validate
* @throws PlatformError with code INVALID_ARGUMENT if validation fails
*/
export function validateCommandPaletteRequest(request: CommandPaletteRequest): void;
export function validateComboBoxRequest(request: ComboBoxRequest): void;
}
declare module 'renderer/services/overlays/overlay-coordinates' {
/**
Expand Down Expand Up @@ -10793,18 +10806,18 @@ declare module '@papi/frontend' {
window: IWindowService;
/**
*
* Service for showing overlays (context menus, popovers, command palettes) that render outside
* iframe boundaries in the renderer's top-level document. Renderer-only service.
* Service for showing overlays (context menus, popovers, combo boxes) that render outside iframe
* boundaries in the renderer's top-level document. Renderer-only service.
*
* Extensions in sandboxed WebView iframes cannot render UI above other content or outside their
* iframe bounds. This service accepts overlay requests from WebViews, translates their
* iframe-relative coordinates to document-level coordinates, and renders the overlay in the
* renderer's React tree. Each method returns a promise that resolves when the user interacts with
* the overlay or it is dismissed.
*
* Only one overlay of each type (context menu, popover, command palette) can be active per WebView
* at a time. Requesting a new overlay of the same type from the same WebView replaces the previous
* one and rejects its promise with a PlatformError with code ABORTED.
* Only one overlay of each type (context menu, popover, combo box) can be active per WebView at a
* time. Requesting a new overlay of the same type from the same WebView replaces the previous one
* and rejects its promise with a PlatformError with code ABORTED.
*/
overlays: IOverlayService;
};
Expand Down Expand Up @@ -10962,18 +10975,18 @@ declare module '@papi/frontend' {
export const window: IWindowService;
/**
*
* Service for showing overlays (context menus, popovers, command palettes) that render outside
* iframe boundaries in the renderer's top-level document. Renderer-only service.
* Service for showing overlays (context menus, popovers, combo boxes) that render outside iframe
* boundaries in the renderer's top-level document. Renderer-only service.
*
* Extensions in sandboxed WebView iframes cannot render UI above other content or outside their
* iframe bounds. This service accepts overlay requests from WebViews, translates their
* iframe-relative coordinates to document-level coordinates, and renders the overlay in the
* renderer's React tree. Each method returns a promise that resolves when the user interacts with
* the overlay or it is dismissed.
*
* Only one overlay of each type (context menu, popover, command palette) can be active per WebView
* at a time. Requesting a new overlay of the same type from the same WebView replaces the previous
* one and rejects its promise with a PlatformError with code ABORTED.
* Only one overlay of each type (context menu, popover, combo box) can be active per WebView at a
* time. Requesting a new overlay of the same type from the same WebView replaces the previous one
* and rejects its promise with a PlatformError with code ABORTED.
*/
export const overlays: IOverlayService;
export type Papi = typeof papi;
Expand Down
6 changes: 3 additions & 3 deletions src/renderer/components/overlay-host.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* overlay store and renders the appropriate overlay components.
*/

import { OverlayCommandPalette } from '@renderer/components/overlays/overlay-command-palette.component';
import { OverlayComboBox } from '@renderer/components/overlays/overlay-combo-box.component';
import { OverlayContextMenu } from '@renderer/components/overlays/overlay-context-menu.component';
import { OverlayModalDialog } from '@renderer/components/overlays/overlay-modal-dialog.component';
import { OverlayPopover } from '@renderer/components/overlays/overlay-popover.component';
Expand Down Expand Up @@ -39,8 +39,8 @@ export function OverlayHost() {
if (overlay.type === 'popover') {
return <OverlayPopover key={overlay.id} overlay={overlay} />;
}
if (overlay.type === 'commandPalette') {
return <OverlayCommandPalette key={overlay.id} overlay={overlay} />;
if (overlay.type === 'comboBox') {
return <OverlayComboBox key={overlay.id} overlay={overlay} />;
}
return undefined;
})}
Expand Down
Loading
Loading