fix(tui): harden overlay focus restoration
This commit is contained in:
@@ -2371,7 +2371,7 @@ const result = await ctx.ui.custom<string | null>(
|
||||
);
|
||||
```
|
||||
|
||||
For advanced positioning (anchors, margins, percentages, responsive visibility), pass `overlayOptions`. Use `onHandle` to control visibility programmatically:
|
||||
For advanced positioning (anchors, margins, percentages, responsive visibility), pass `overlayOptions`. Use `onHandle` to control focus or visibility programmatically:
|
||||
|
||||
```typescript
|
||||
const result = await ctx.ui.custom<string | null>(
|
||||
@@ -2379,12 +2379,19 @@ const result = await ctx.ui.custom<string | null>(
|
||||
{
|
||||
overlay: true,
|
||||
overlayOptions: { anchor: "top-right", width: "50%", margin: 2 },
|
||||
onHandle: (handle) => { /* handle.setHidden(true/false) */ }
|
||||
onHandle: (handle) => {
|
||||
handle.focus(); // focus this overlay and bring it to the visual front
|
||||
// handle.unfocus({ target: editorComponent }); // release input to a specific component
|
||||
// handle.setHidden(true/false); // toggle visibility
|
||||
// handle.hide(); // permanently remove
|
||||
}
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
See [tui.md](tui.md) for the full `OverlayOptions` API and [overlay-qa-tests.ts](../examples/extensions/overlay-qa-tests.ts) for examples.
|
||||
A focused visible overlay can reclaim input after temporary non-overlay custom UI closes. If you intentionally want another component to keep input while the overlay stays visible, call `handle.unfocus({ target })`. Passing `{ target: null }` releases the overlay without focusing another component.
|
||||
|
||||
See [tui.md](tui.md) for the full `OverlayOptions` and `OverlayHandle` API and [overlay-qa-tests.ts](../examples/extensions/overlay-qa-tests.ts) for examples.
|
||||
|
||||
### Custom Editor
|
||||
|
||||
|
||||
@@ -145,8 +145,11 @@ const result = await ctx.ui.custom<string | null>(
|
||||
// Responsive: hide on narrow terminals
|
||||
visible: (termWidth, termHeight) => termWidth >= 80,
|
||||
},
|
||||
// Get handle for programmatic visibility control
|
||||
// Get handle for programmatic focus and visibility control
|
||||
onHandle: (handle) => {
|
||||
// handle.focus() - focus this overlay and bring it to the visual front
|
||||
// handle.unfocus() - release input to normal fallback
|
||||
// handle.unfocus({ target }) - release input to a specific component or null
|
||||
// handle.setHidden(true/false) - toggle visibility
|
||||
// handle.hide() - permanently remove
|
||||
},
|
||||
@@ -154,6 +157,12 @@ const result = await ctx.ui.custom<string | null>(
|
||||
);
|
||||
```
|
||||
|
||||
### Overlay Focus
|
||||
|
||||
A focused visible overlay keeps input ownership across temporary non-overlay UI. If an overlay opens another `ctx.ui.custom()` component without `{ overlay: true }`, that replacement UI receives input while it is active; when it closes, the focused overlay can reclaim input.
|
||||
|
||||
Use `handle.unfocus()` when a visible overlay should stop owning input and let TUI fall back to another visible capturing overlay or the previous focus target. Use `handle.unfocus({ target })` when a specific component should receive input while the overlay stays visible. Passing `{ target: null }` intentionally leaves no focused component until focus is set again.
|
||||
|
||||
### Overlay Lifecycle
|
||||
|
||||
Overlay components are disposed when closed. Don't reuse references - create fresh instances:
|
||||
|
||||
Reference in New Issue
Block a user