BaseOverlayEditor
Base class for grid editors that display a floating overlay panel.
Provides infrastructure for:
- Overlay positioning — CSS Anchor Positioning with JS fallback
- Focus gating — in row editing mode, the panel only opens for the focused cell
- Click-outside detection — closes the panel when clicking outside
- MutationObserver — detects cell focus changes (row editing mode)
- Escape handling — closes the panel and returns focus to the inline input
- Synthetic Tab dispatch — advances grid focus after overlay close
- Automatic teardown — removes the panel from
<body>and cleans up listeners - External focus registration — auto-registers the panel via
grid.registerExternalFocusContainer()so the grid keepsdata-has-focusand editors stay open while the overlay has focus
import { Component, viewChild, ElementRef, effect } from '@angular/core';import { BaseOverlayEditor } from '@toolbox-web/grid-angular';
@Component({ selector: 'app-date-editor', template: ` <input #inlineInput readonly [value]="currentValue()" (click)="onInlineClick()" (keydown)="onInlineKeydown($event)" /> <div #panel class="tbw-overlay-panel" style="width: 280px;"> <!-- your date picker UI here --> <div class="actions"> <button (click)="selectAndClose(selectedDate)">OK</button> <button (click)="hideOverlay()">Cancel</button> </div> </div> `})export class DateEditorComponent extends BaseOverlayEditor<MyRow, string> { panelRef = viewChild.required<ElementRef<HTMLElement>>('panel'); inputRef = viewChild.required<ElementRef<HTMLInputElement>>('inlineInput');
protected override overlayPosition = 'below' as const;
constructor() { super(); effect(() => { const panel = this.panelRef().nativeElement; this.initOverlay(panel); if (this.isCellFocused()) this.showOverlay(); }); }
protected getInlineInput(): HTMLInputElement | null { return this.inputRef()?.nativeElement ?? null; }
protected onOverlayOutsideClick(): void { this.hideOverlay(); }
selectAndClose(date: string): void { this.commitValue(date); this.hideOverlay(); }}Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
overlayPosition | OverlayPosition | Position of the overlay panel relative to the anchor cell. Override in subclasses to change the default position. |
_isOpen | boolean | Whether the overlay is currently visible. |
_focusObserver | MutationObserver | unknown | MutationObserver watching cell focus class changes. |
Property Details
Section titled “Property Details”overlayPosition
Section titled “overlayPosition”Default: 'below'
Methods
Section titled “Methods”initOverlay()
Section titled “initOverlay()”Initialise the overlay with the panel element.
Call this in an effect() or afterNextRender() with your viewChild panel reference.
The panel is moved to <body> and hidden until showOverlay is called.
initOverlay(panel: HTMLElement): voidParameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
panel | HTMLElement | The overlay panel DOM element |
showOverlay()
Section titled “showOverlay()”Show the overlay panel.
If CSS Anchor Positioning is not supported, falls back to JS-based
positioning using getBoundingClientRect().
showOverlay(): voidhideOverlay()
Section titled “hideOverlay()”Hide the overlay panel.
hideOverlay(suppressTabAdvance: boolean): voidParameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
suppressTabAdvance | boolean | When true, skip synthetic Tab dispatch |
| (useful when hiding is triggered by an external focus change). |
reopenOverlay()
Section titled “reopenOverlay()”Close and immediately re-open the overlay. Useful after the panel content changes size and needs repositioning.
reopenOverlay(): voidteardownOverlay()
Section titled “teardownOverlay()”Remove the overlay from the DOM and clean up all listeners.
Called automatically on DestroyRef.onDestroy. Can also be called
manually if the editor needs early cleanup.
teardownOverlay(): voidonEditClose()
Section titled “onEditClose()”Override in edit-close handler to also hide the overlay.
This is called automatically by BaseGridEditor when the grid
ends the editing session.
onEditClose(): voidonInlineKeydown()
Section titled “onInlineKeydown()”Keydown handler for the inline readonly input.
- Enter / Space / ArrowDown / F2 → open overlay
- Escape → calls handleEscape
Bind this to (keydown) on your inline input element.
onInlineKeydown(event: KeyboardEvent): voidParameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
event | KeyboardEvent |
onInlineClick()
Section titled “onInlineClick()”Click handler for the inline input. Opens the overlay and calls onOverlayOpened.
Bind this to (click) on your inline input element.
onInlineClick(): voidhandleEscape()
Section titled “handleEscape()”Handle Escape key press.
If the overlay is open, closes it and returns focus to the inline input. If the overlay is already closed, cancels the edit entirely.
handleEscape(event: Event): voidParameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
event | Event |
advanceGridFocus()
Section titled “advanceGridFocus()”Dispatch a synthetic Tab key event to advance grid focus.
Call this after committing a value and closing the overlay so the grid moves focus to the next cell.
advanceGridFocus(backward: boolean): voidParameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
backward | boolean | When true, dispatch Shift+Tab to move backwards. |
getInlineInput()
Section titled “getInlineInput()”Return the inline input element, if any.
Used by overlay infrastructure to return focus after hiding.
Return null if there is no inline input.
getInlineInput(): HTMLInputElement | nullonOverlayOutsideClick()
Section titled “onOverlayOutsideClick()”Called when a pointerdown event occurs outside the overlay panel and outside the editor’s host element.
Typically, subclasses call hideOverlay() here.
onOverlayOutsideClick(): voidonOverlayOpened()
Section titled “onOverlayOpened()”Called after the overlay is shown.
Override to focus an element inside the panel, start animations, etc. Default implementation is a no-op.
onOverlayOpened(): void_setupFocusObserver()
Section titled “_setupFocusObserver()”Set up a MutationObserver on the parent cell to watch for
cell-focus class changes. This handles row-editing mode where
all editors exist simultaneously but only the focused cell’s
editor should have its overlay visible.
A justOpened flash guard suppresses the observer from
immediately closing the overlay when beginBulkEdit() moves
focus to the first editable column. Without this guard,
double-click triggers a “flash open then close” effect.
_setupFocusObserver(): void