* Show an overlay component with configurable positioning and sizing. * Returns a handle to control the overlay's visibility.
(component: Component, options?: OverlayOptions)
| 501 | * Returns a handle to control the overlay's visibility. |
| 502 | */ |
| 503 | showOverlay(component: Component, options?: OverlayOptions): OverlayHandle { |
| 504 | const entry: OverlayStackEntry = { |
| 505 | component, |
| 506 | ...(options === undefined ? {} : { options }), |
| 507 | preFocus: this.focusedComponent, |
| 508 | hidden: false, |
| 509 | focusOrder: ++this.focusOrderCounter, |
| 510 | }; |
| 511 | this.overlayStack.push(entry); |
| 512 | // Only focus if overlay is actually visible |
| 513 | if (!options?.nonCapturing && this.isOverlayVisible(entry)) { |
| 514 | this.setFocus(component); |
| 515 | } |
| 516 | this.terminal.hideCursor(); |
| 517 | this.requestRender(); |
| 518 | |
| 519 | // Return handle for controlling this overlay |
| 520 | return { |
| 521 | hide: () => { |
| 522 | const index = this.overlayStack.indexOf(entry); |
| 523 | if (index !== -1) { |
| 524 | this.clearOverlayFocusRestoreFor(entry); |
| 525 | this.retargetOverlayPreFocus(entry); |
| 526 | this.overlayStack.splice(index, 1); |
| 527 | // Restore focus if this overlay had focus |
| 528 | if (this.focusedComponent === component) { |
| 529 | const topVisible = this.getTopmostVisibleOverlay(); |
| 530 | this.setFocus(topVisible?.component ?? entry.preFocus); |
| 531 | } |
| 532 | if (this.overlayStack.length === 0) this.terminal.hideCursor(); |
| 533 | this.requestRender(); |
| 534 | } |
| 535 | }, |
| 536 | setHidden: (hidden: boolean) => { |
| 537 | if (entry.hidden === hidden) return; |
| 538 | entry.hidden = hidden; |
| 539 | // Update focus when hiding/showing |
| 540 | if (hidden) { |
| 541 | this.clearOverlayFocusRestoreFor(entry); |
| 542 | // If this overlay had focus, move focus to next visible or preFocus |
| 543 | if (this.focusedComponent === component) { |
| 544 | const topVisible = this.getTopmostVisibleOverlay(); |
| 545 | this.setFocus(topVisible?.component ?? entry.preFocus); |
| 546 | } |
| 547 | } else { |
| 548 | // Restore focus to this overlay when showing (if it's actually visible) |
| 549 | if (!options?.nonCapturing && this.isOverlayVisible(entry)) { |
| 550 | entry.focusOrder = ++this.focusOrderCounter; |
| 551 | this.setFocus(component); |
| 552 | } |
| 553 | } |
| 554 | this.requestRender(); |
| 555 | }, |
| 556 | isHidden: () => entry.hidden, |
| 557 | focus: () => { |
| 558 | if (!this.overlayStack.includes(entry) || !this.isOverlayVisible(entry)) return; |
| 559 | entry.focusOrder = ++this.focusOrderCounter; |
| 560 | this.setFocus(component); |
no test coverage detected