@compilr-dev/cli 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -12
- package/dist/agent.d.ts +74 -1
- package/dist/agent.js +259 -76
- package/dist/anchors/index.d.ts +9 -0
- package/dist/anchors/index.js +9 -0
- package/dist/anchors/project-anchors.d.ts +79 -0
- package/dist/anchors/project-anchors.js +202 -0
- package/dist/commands/handler-types.d.ts +68 -0
- package/dist/commands/handler-types.js +8 -0
- package/dist/commands/handlers/agent-commands.d.ts +13 -0
- package/dist/commands/handlers/agent-commands.js +305 -0
- package/dist/commands/handlers/design-commands.d.ts +15 -0
- package/dist/commands/handlers/design-commands.js +334 -0
- package/dist/commands/handlers/index.d.ts +20 -0
- package/dist/commands/handlers/index.js +43 -0
- package/dist/commands/handlers/overlay-commands.d.ts +21 -0
- package/dist/commands/handlers/overlay-commands.js +287 -0
- package/dist/commands/handlers/project-commands.d.ts +11 -0
- package/dist/commands/handlers/project-commands.js +167 -0
- package/dist/commands/handlers/simple-commands.d.ts +19 -0
- package/dist/commands/handlers/simple-commands.js +144 -0
- package/dist/commands/index.d.ts +2 -1
- package/dist/commands/registry.d.ts +50 -0
- package/dist/commands/registry.js +75 -0
- package/dist/commands-v2/handlers/context.d.ts +13 -0
- package/dist/commands-v2/handlers/context.js +348 -0
- package/dist/commands-v2/handlers/core.d.ts +13 -0
- package/dist/commands-v2/handlers/core.js +165 -0
- package/dist/commands-v2/handlers/debug.d.ts +11 -0
- package/dist/commands-v2/handlers/debug.js +159 -0
- package/dist/commands-v2/handlers/index.d.ts +12 -0
- package/dist/commands-v2/handlers/index.js +24 -0
- package/dist/commands-v2/handlers/project.d.ts +22 -0
- package/dist/commands-v2/handlers/project.js +814 -0
- package/dist/commands-v2/handlers/settings.d.ts +15 -0
- package/dist/commands-v2/handlers/settings.js +235 -0
- package/dist/commands-v2/index.d.ts +13 -0
- package/dist/commands-v2/index.js +15 -0
- package/dist/commands-v2/registry.d.ts +37 -0
- package/dist/commands-v2/registry.js +80 -0
- package/dist/commands-v2/types.d.ts +75 -0
- package/dist/commands-v2/types.js +7 -0
- package/dist/commands.js +110 -7
- package/dist/index.js +288 -29
- package/dist/input-handlers/index.d.ts +7 -0
- package/dist/input-handlers/index.js +7 -0
- package/dist/input-handlers/memory-handler.d.ts +26 -0
- package/dist/input-handlers/memory-handler.js +68 -0
- package/dist/repl-helpers.d.ts +63 -0
- package/dist/repl-helpers.js +318 -0
- package/dist/repl-v2.d.ts +155 -0
- package/dist/repl-v2.js +774 -0
- package/dist/repl.d.ts +32 -4
- package/dist/repl.js +250 -977
- package/dist/settings/index.d.ts +23 -0
- package/dist/settings/index.js +48 -0
- package/dist/settings/paths.d.ts +110 -0
- package/dist/settings/paths.js +264 -0
- package/dist/templates/compilr-md.js +7 -4
- package/dist/templates/index.js +3 -4
- package/dist/themes/colors.js +3 -1
- package/dist/themes/registry.d.ts +5 -36
- package/dist/themes/registry.js +11 -95
- package/dist/themes/types.d.ts +3 -38
- package/dist/themes/types.js +2 -2
- package/dist/tools/anchor-tools.d.ts +31 -0
- package/dist/tools/anchor-tools.js +255 -0
- package/dist/tools/backlog-wrappers.d.ts +54 -0
- package/dist/tools/backlog-wrappers.js +338 -0
- package/dist/tools/backlog.js +1 -1
- package/dist/tools/db-tools.d.ts +65 -0
- package/dist/tools/db-tools.js +19 -0
- package/dist/tools/document-db.d.ts +43 -0
- package/dist/tools/document-db.js +220 -0
- package/dist/tools/project-db.d.ts +102 -0
- package/dist/tools/project-db.js +370 -0
- package/dist/tools/workitem-db.d.ts +103 -0
- package/dist/tools/workitem-db.js +549 -0
- package/dist/tools.js +13 -3
- package/dist/ui/agents-overlay-v2.d.ts +43 -0
- package/dist/ui/agents-overlay-v2.js +809 -0
- package/dist/ui/agents-overlay.d.ts +5 -5
- package/dist/ui/agents-overlay.js +782 -420
- package/dist/ui/anchors-overlay.d.ts +12 -0
- package/dist/ui/anchors-overlay.js +775 -0
- package/dist/ui/arch-type-overlay.d.ts +1 -6
- package/dist/ui/arch-type-overlay.js +175 -203
- package/dist/ui/ask-user-overlay-v2.d.ts +26 -0
- package/dist/ui/ask-user-overlay-v2.js +555 -0
- package/dist/ui/ask-user-overlay.d.ts +2 -2
- package/dist/ui/ask-user-overlay.js +443 -535
- package/dist/ui/ask-user-simple-overlay-v2.d.ts +25 -0
- package/dist/ui/ask-user-simple-overlay-v2.js +215 -0
- package/dist/ui/ask-user-simple-overlay.d.ts +2 -2
- package/dist/ui/ask-user-simple-overlay.js +182 -209
- package/dist/ui/backlog-overlay.d.ts +16 -1
- package/dist/ui/backlog-overlay.js +525 -659
- package/dist/ui/base/index.d.ts +26 -0
- package/dist/ui/base/index.js +33 -0
- package/dist/ui/base/inline-overlay-utils.d.ts +217 -0
- package/dist/ui/base/inline-overlay-utils.js +320 -0
- package/dist/ui/base/inline-overlay.d.ts +159 -0
- package/dist/ui/base/inline-overlay.js +257 -0
- package/dist/ui/base/key-utils.d.ts +15 -0
- package/dist/ui/base/key-utils.js +30 -0
- package/dist/ui/base/overlay-base-v2.d.ts +193 -0
- package/dist/ui/base/overlay-base-v2.js +246 -0
- package/dist/ui/base/overlay-base.d.ts +156 -0
- package/dist/ui/base/overlay-base.js +238 -0
- package/dist/ui/base/overlay-lifecycle.d.ts +65 -0
- package/dist/ui/base/overlay-lifecycle.js +159 -0
- package/dist/ui/base/overlay-types.d.ts +185 -0
- package/dist/ui/base/overlay-types.js +7 -0
- package/dist/ui/base/render-utils.d.ts +8 -0
- package/dist/ui/base/render-utils.js +11 -0
- package/dist/ui/base/screen-stack.d.ts +148 -0
- package/dist/ui/base/screen-stack.js +184 -0
- package/dist/ui/base/tabbed-list-overlay-v2.d.ts +103 -0
- package/dist/ui/base/tabbed-list-overlay-v2.js +317 -0
- package/dist/ui/base/tabbed-list-overlay.d.ts +153 -0
- package/dist/ui/base/tabbed-list-overlay.js +369 -0
- package/dist/ui/commands-overlay-v2.d.ts +33 -0
- package/dist/ui/commands-overlay-v2.js +441 -0
- package/dist/ui/commands-overlay.d.ts +7 -2
- package/dist/ui/commands-overlay.js +384 -355
- package/dist/ui/config-overlay.d.ts +5 -4
- package/dist/ui/config-overlay.js +243 -513
- package/dist/ui/conversation.d.ts +75 -4
- package/dist/ui/conversation.js +374 -161
- package/dist/ui/docs-overlay.d.ts +17 -0
- package/dist/ui/docs-overlay.js +303 -0
- package/dist/ui/ephemeral.d.ts +1 -1
- package/dist/ui/ephemeral.js +1 -1
- package/dist/ui/features/index.d.ts +34 -0
- package/dist/ui/features/index.js +34 -0
- package/dist/ui/features/input-feature.d.ts +85 -0
- package/dist/ui/features/input-feature.js +238 -0
- package/dist/ui/features/list-feature.d.ts +155 -0
- package/dist/ui/features/list-feature.js +244 -0
- package/dist/ui/features/pagination-feature.d.ts +154 -0
- package/dist/ui/features/pagination-feature.js +238 -0
- package/dist/ui/features/search-feature.d.ts +148 -0
- package/dist/ui/features/search-feature.js +185 -0
- package/dist/ui/features/tab-feature.d.ts +194 -0
- package/dist/ui/features/tab-feature.js +307 -0
- package/dist/ui/footer-v2.d.ts +222 -0
- package/dist/ui/footer-v2.js +1349 -0
- package/dist/ui/footer.d.ts +107 -0
- package/dist/ui/footer.js +359 -67
- package/dist/ui/guardrail-overlay.d.ts +29 -0
- package/dist/ui/guardrail-overlay.js +145 -0
- package/dist/ui/help-overlay-v2.d.ts +34 -0
- package/dist/ui/help-overlay-v2.js +309 -0
- package/dist/ui/help-overlay.d.ts +16 -0
- package/dist/ui/help-overlay.js +316 -0
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/index.js +1 -3
- package/dist/ui/init-overlay-v2.d.ts +34 -0
- package/dist/ui/init-overlay-v2.js +600 -0
- package/dist/ui/init-overlay.d.ts +12 -2
- package/dist/ui/init-overlay.js +349 -270
- package/dist/ui/input-prompt-v2.d.ts +1 -0
- package/dist/ui/input-prompt-v2.js +14 -6
- package/dist/ui/input-prompt.d.ts +116 -33
- package/dist/ui/input-prompt.js +536 -337
- package/dist/ui/iteration-limit-overlay-v2.d.ts +21 -0
- package/dist/ui/iteration-limit-overlay-v2.js +114 -0
- package/dist/ui/iteration-limit-overlay.d.ts +2 -2
- package/dist/ui/iteration-limit-overlay.js +92 -128
- package/dist/ui/keys-overlay-v2.d.ts +41 -0
- package/dist/ui/keys-overlay-v2.js +248 -0
- package/dist/ui/keys-overlay.d.ts +1 -0
- package/dist/ui/keys-overlay.js +203 -141
- package/dist/ui/line-utils.d.ts +88 -0
- package/dist/ui/line-utils.js +150 -0
- package/dist/ui/live-region.d.ts +161 -0
- package/dist/ui/live-region.js +387 -0
- package/dist/ui/mascot/expressions.d.ts +32 -0
- package/dist/ui/mascot/expressions.js +213 -0
- package/dist/ui/mascot/index.d.ts +8 -0
- package/dist/ui/mascot/index.js +8 -0
- package/dist/ui/mascot/renderer.d.ts +19 -0
- package/dist/ui/mascot/renderer.js +97 -0
- package/dist/ui/mascot-overlay-v2.d.ts +41 -0
- package/dist/ui/mascot-overlay-v2.js +138 -0
- package/dist/ui/mascot-overlay.d.ts +21 -0
- package/dist/ui/mascot-overlay.js +146 -0
- package/dist/ui/model-overlay-v2.d.ts +49 -0
- package/dist/ui/model-overlay-v2.js +118 -0
- package/dist/ui/model-overlay.d.ts +27 -0
- package/dist/ui/model-overlay.js +221 -0
- package/dist/ui/model-warning-overlay.js +3 -5
- package/dist/ui/new-overlay.d.ts +34 -0
- package/dist/ui/new-overlay.js +604 -0
- package/dist/ui/overlay/impl/agents-overlay-v2.d.ts +45 -0
- package/dist/ui/overlay/impl/agents-overlay-v2.js +825 -0
- package/dist/ui/overlay/impl/anchors-overlay-v2.d.ts +47 -0
- package/dist/ui/overlay/impl/anchors-overlay-v2.js +783 -0
- package/dist/ui/overlay/impl/arch-type-overlay-v2.d.ts +37 -0
- package/dist/ui/overlay/impl/arch-type-overlay-v2.js +240 -0
- package/dist/ui/overlay/impl/ask-user-overlay-v2.d.ts +72 -0
- package/dist/ui/overlay/impl/ask-user-overlay-v2.js +584 -0
- package/dist/ui/overlay/impl/ask-user-simple-overlay-v2.d.ts +46 -0
- package/dist/ui/overlay/impl/ask-user-simple-overlay-v2.js +204 -0
- package/dist/ui/overlay/impl/backlog-overlay-v2.d.ts +49 -0
- package/dist/ui/overlay/impl/backlog-overlay-v2.js +642 -0
- package/dist/ui/overlay/impl/commands-overlay-v2.d.ts +33 -0
- package/dist/ui/overlay/impl/commands-overlay-v2.js +441 -0
- package/dist/ui/overlay/impl/config-overlay-v2.d.ts +100 -0
- package/dist/ui/overlay/impl/config-overlay-v2.js +654 -0
- package/dist/ui/overlay/impl/dashboard-overlay-v2.d.ts +55 -0
- package/dist/ui/overlay/impl/dashboard-overlay-v2.js +359 -0
- package/dist/ui/overlay/impl/docs-overlay-v2.d.ts +45 -0
- package/dist/ui/overlay/impl/docs-overlay-v2.js +114 -0
- package/dist/ui/overlay/impl/document-detail-overlay-v2.d.ts +77 -0
- package/dist/ui/overlay/impl/document-detail-overlay-v2.js +1071 -0
- package/dist/ui/overlay/impl/guardrail-overlay-v2.d.ts +43 -0
- package/dist/ui/overlay/impl/guardrail-overlay-v2.js +114 -0
- package/dist/ui/overlay/impl/help-overlay-v2.d.ts +34 -0
- package/dist/ui/overlay/impl/help-overlay-v2.js +309 -0
- package/dist/ui/overlay/impl/init-overlay-v2.d.ts +77 -0
- package/dist/ui/overlay/impl/init-overlay-v2.js +593 -0
- package/dist/ui/overlay/impl/init-setup-overlay-v2.d.ts +25 -0
- package/dist/ui/overlay/impl/init-setup-overlay-v2.js +97 -0
- package/dist/ui/overlay/impl/iteration-limit-overlay-v2.d.ts +35 -0
- package/dist/ui/overlay/impl/iteration-limit-overlay-v2.js +105 -0
- package/dist/ui/overlay/impl/keys-overlay-v2.d.ts +41 -0
- package/dist/ui/overlay/impl/keys-overlay-v2.js +248 -0
- package/dist/ui/overlay/impl/mascot-overlay-v2.d.ts +41 -0
- package/dist/ui/overlay/impl/mascot-overlay-v2.js +138 -0
- package/dist/ui/overlay/impl/model-overlay-v2.d.ts +49 -0
- package/dist/ui/overlay/impl/model-overlay-v2.js +118 -0
- package/dist/ui/overlay/impl/model-warning-overlay-v2.d.ts +46 -0
- package/dist/ui/overlay/impl/model-warning-overlay-v2.js +132 -0
- package/dist/ui/overlay/impl/new-overlay-v2.d.ts +77 -0
- package/dist/ui/overlay/impl/new-overlay-v2.js +593 -0
- package/dist/ui/overlay/impl/permission-overlay-v2.d.ts +36 -0
- package/dist/ui/overlay/impl/permission-overlay-v2.js +380 -0
- package/dist/ui/overlay/impl/projects-overlay-v2.d.ts +36 -0
- package/dist/ui/overlay/impl/projects-overlay-v2.js +499 -0
- package/dist/ui/overlay/impl/theme-overlay-v2.d.ts +42 -0
- package/dist/ui/overlay/impl/theme-overlay-v2.js +135 -0
- package/dist/ui/overlay/impl/tools-overlay-v2.d.ts +47 -0
- package/dist/ui/overlay/impl/tools-overlay-v2.js +218 -0
- package/dist/ui/overlay/impl/tutorial-overlay-v2.d.ts +31 -0
- package/dist/ui/overlay/impl/tutorial-overlay-v2.js +1035 -0
- package/dist/ui/overlay/impl/workflow-overlay-v2.d.ts +80 -0
- package/dist/ui/overlay/impl/workflow-overlay-v2.js +637 -0
- package/dist/ui/overlay/index.d.ts +33 -0
- package/dist/ui/overlay/index.js +35 -0
- package/dist/ui/overlay/key-utils.d.ts +6 -0
- package/dist/ui/overlay/key-utils.js +6 -0
- package/dist/ui/overlay/overlay-types.d.ts +128 -0
- package/dist/ui/overlay/overlay-types.js +22 -0
- package/dist/ui/overlay/types.d.ts +135 -0
- package/dist/ui/overlay/types.js +22 -0
- package/dist/ui/overlays/help-overlay-v2.d.ts +28 -0
- package/dist/ui/overlays/help-overlay-v2.js +198 -0
- package/dist/ui/overlays/index.d.ts +11 -0
- package/dist/ui/overlays/index.js +11 -0
- package/dist/ui/overlays.d.ts +0 -4
- package/dist/ui/overlays.js +0 -444
- package/dist/ui/permission-overlay-v2.d.ts +36 -0
- package/dist/ui/permission-overlay-v2.js +380 -0
- package/dist/ui/permission-overlay.d.ts +1 -1
- package/dist/ui/permission-overlay.js +186 -298
- package/dist/ui/projects-overlay.d.ts +19 -0
- package/dist/ui/projects-overlay.js +484 -0
- package/dist/ui/providers/types.d.ts +178 -0
- package/dist/ui/providers/types.js +9 -0
- package/dist/ui/render-modes.d.ts +36 -0
- package/dist/ui/render-modes.js +44 -0
- package/dist/ui/startup-menu.d.ts +36 -0
- package/dist/ui/startup-menu.js +236 -0
- package/dist/ui/subagent-renderer.d.ts +117 -0
- package/dist/ui/subagent-renderer.js +334 -0
- package/dist/ui/terminal-codes.d.ts +94 -0
- package/dist/ui/terminal-codes.js +124 -0
- package/dist/ui/terminal-renderer.d.ts +221 -0
- package/dist/ui/terminal-renderer.js +751 -0
- package/dist/ui/terminal-ui.d.ts +463 -0
- package/dist/ui/terminal-ui.js +2296 -0
- package/dist/ui/terminal.d.ts +20 -0
- package/dist/ui/terminal.js +72 -0
- package/dist/ui/theme-overlay-v2.d.ts +42 -0
- package/dist/ui/theme-overlay-v2.js +135 -0
- package/dist/ui/theme-overlay.d.ts +24 -0
- package/dist/ui/theme-overlay.js +127 -0
- package/dist/ui/todo-zone.js +53 -25
- package/dist/ui/tool-formatters.d.ts +16 -0
- package/dist/ui/tool-formatters.js +516 -0
- package/dist/ui/tools-overlay-v2.d.ts +47 -0
- package/dist/ui/tools-overlay-v2.js +218 -0
- package/dist/ui/tools-overlay.d.ts +10 -2
- package/dist/ui/tools-overlay.js +172 -220
- package/dist/ui/tutorial-overlay-v2.d.ts +31 -0
- package/dist/ui/tutorial-overlay-v2.js +1035 -0
- package/dist/ui/tutorial-overlay.d.ts +1 -0
- package/dist/ui/tutorial-overlay.js +400 -302
- package/dist/ui/workflow-overlay.d.ts +22 -0
- package/dist/ui/workflow-overlay.js +636 -0
- package/dist/utils/debug-log.d.ts +28 -0
- package/dist/utils/debug-log.js +57 -0
- package/dist/utils/model-tiers.js +1 -1
- package/dist/utils/path-safety.d.ts +56 -0
- package/dist/utils/path-safety.js +239 -0
- package/dist/workflow/guided-mode-injector.d.ts +42 -0
- package/dist/workflow/guided-mode-injector.js +191 -0
- package/dist/workflow/index.d.ts +8 -0
- package/dist/workflow/index.js +8 -0
- package/dist/workflow/step-criteria.d.ts +62 -0
- package/dist/workflow/step-criteria.js +150 -0
- package/dist/workflow/step-tracker.d.ts +92 -0
- package/dist/workflow/step-tracker.js +141 -0
- package/package.json +12 -5
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Overlay Lifecycle Manager
|
|
3
|
+
*
|
|
4
|
+
* Handles the common setup and cleanup operations for all overlays:
|
|
5
|
+
* - Raw mode management
|
|
6
|
+
* - Cursor visibility
|
|
7
|
+
* - Event listener setup/teardown
|
|
8
|
+
* - Line clearing on close
|
|
9
|
+
*/
|
|
10
|
+
import * as terminal from '../terminal.js';
|
|
11
|
+
import { pauseForOverlay, resumeAfterOverlay } from '../overlay-controller.js';
|
|
12
|
+
import { debugLog } from '../../utils/debug-log.js';
|
|
13
|
+
// =============================================================================
|
|
14
|
+
// OverlayLifecycle Class
|
|
15
|
+
// =============================================================================
|
|
16
|
+
/**
|
|
17
|
+
* Manages the lifecycle of an overlay.
|
|
18
|
+
*
|
|
19
|
+
* Usage:
|
|
20
|
+
* ```typescript
|
|
21
|
+
* const lifecycle = new OverlayLifecycle(config, (data) => handleKey(data));
|
|
22
|
+
*
|
|
23
|
+
* // Setup - call before first render
|
|
24
|
+
* lifecycle.setup();
|
|
25
|
+
*
|
|
26
|
+
* // ... overlay logic ...
|
|
27
|
+
*
|
|
28
|
+
* // Cleanup - call when closing
|
|
29
|
+
* lifecycle.cleanup(lineCount);
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export class OverlayLifecycle {
|
|
33
|
+
config;
|
|
34
|
+
onKey;
|
|
35
|
+
wasRawMode = false;
|
|
36
|
+
dataHandler = null;
|
|
37
|
+
isActive = false;
|
|
38
|
+
constructor(config, onKey) {
|
|
39
|
+
this.config = config;
|
|
40
|
+
this.onKey = onKey;
|
|
41
|
+
}
|
|
42
|
+
// ===========================================================================
|
|
43
|
+
// Public Methods
|
|
44
|
+
// ===========================================================================
|
|
45
|
+
/**
|
|
46
|
+
* Setup the overlay for interaction.
|
|
47
|
+
* Call this before the first render.
|
|
48
|
+
*/
|
|
49
|
+
setup() {
|
|
50
|
+
if (this.isActive) {
|
|
51
|
+
return; // Already set up
|
|
52
|
+
}
|
|
53
|
+
debugLog('OverlayLifecycle:setup', 'start');
|
|
54
|
+
// Pause footer animation and clear it
|
|
55
|
+
// This is done HERE (not in REPL) so constructor I/O doesn't cause blank screen
|
|
56
|
+
pauseForOverlay();
|
|
57
|
+
debugLog('OverlayLifecycle:setup', 'footer paused');
|
|
58
|
+
// Save current raw mode state
|
|
59
|
+
this.wasRawMode = process.stdin.isRaw;
|
|
60
|
+
// Enter raw mode for character-by-character input
|
|
61
|
+
terminal.enableRawMode();
|
|
62
|
+
// Hide cursor (unless config says not to)
|
|
63
|
+
if (this.config.hideCursor !== false) {
|
|
64
|
+
terminal.hideCursor();
|
|
65
|
+
}
|
|
66
|
+
// Setup key handler
|
|
67
|
+
this.dataHandler = (data) => {
|
|
68
|
+
if (this.isActive) {
|
|
69
|
+
this.onKey(data);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
process.stdin.on('data', this.dataHandler);
|
|
73
|
+
this.isActive = true;
|
|
74
|
+
debugLog('OverlayLifecycle:setup', 'done');
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Cleanup after overlay closes.
|
|
78
|
+
* Restores terminal state and removes event listeners.
|
|
79
|
+
*
|
|
80
|
+
* @param lineCount - Number of lines to clear (typically maxLineCount)
|
|
81
|
+
*/
|
|
82
|
+
cleanup(lineCount) {
|
|
83
|
+
if (!this.isActive) {
|
|
84
|
+
return; // Already cleaned up
|
|
85
|
+
}
|
|
86
|
+
debugLog('OverlayLifecycle:cleanup', 'start');
|
|
87
|
+
this.isActive = false;
|
|
88
|
+
// Remove event listener
|
|
89
|
+
if (this.dataHandler) {
|
|
90
|
+
process.stdin.removeListener('data', this.dataHandler);
|
|
91
|
+
this.dataHandler = null;
|
|
92
|
+
}
|
|
93
|
+
// Clear the overlay content
|
|
94
|
+
if (lineCount > 0) {
|
|
95
|
+
terminal.clearLinesAbove(lineCount);
|
|
96
|
+
}
|
|
97
|
+
// Restore cursor visibility
|
|
98
|
+
if (this.config.hideCursor !== false) {
|
|
99
|
+
terminal.showCursor();
|
|
100
|
+
}
|
|
101
|
+
// Restore raw mode state
|
|
102
|
+
if (!this.wasRawMode) {
|
|
103
|
+
terminal.disableRawMode();
|
|
104
|
+
}
|
|
105
|
+
// Resume footer animation
|
|
106
|
+
resumeAfterOverlay();
|
|
107
|
+
debugLog('OverlayLifecycle:cleanup', 'footer resumed');
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Check if the lifecycle is currently active.
|
|
111
|
+
*/
|
|
112
|
+
isSetUp() {
|
|
113
|
+
return this.isActive;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// =============================================================================
|
|
117
|
+
// Standalone Helper Functions
|
|
118
|
+
// =============================================================================
|
|
119
|
+
/**
|
|
120
|
+
* Create a standard overlay setup without using the class.
|
|
121
|
+
* Returns a cleanup function.
|
|
122
|
+
*
|
|
123
|
+
* This is useful for simple overlays that don't need the full class.
|
|
124
|
+
*
|
|
125
|
+
* @param onKey - Key handler callback
|
|
126
|
+
* @param config - Optional configuration
|
|
127
|
+
* @returns Cleanup function
|
|
128
|
+
*/
|
|
129
|
+
export function setupOverlay(onKey, config = {}) {
|
|
130
|
+
const wasRawMode = process.stdin.isRaw;
|
|
131
|
+
// Pause footer animation and clear it
|
|
132
|
+
pauseForOverlay();
|
|
133
|
+
// Enter raw mode
|
|
134
|
+
terminal.enableRawMode();
|
|
135
|
+
// Hide cursor
|
|
136
|
+
if (config.hideCursor !== false) {
|
|
137
|
+
terminal.hideCursor();
|
|
138
|
+
}
|
|
139
|
+
// Setup handler
|
|
140
|
+
const dataHandler = (data) => {
|
|
141
|
+
onKey(data);
|
|
142
|
+
};
|
|
143
|
+
process.stdin.on('data', dataHandler);
|
|
144
|
+
// Return cleanup function
|
|
145
|
+
return (lineCount = 0) => {
|
|
146
|
+
process.stdin.removeListener('data', dataHandler);
|
|
147
|
+
if (lineCount > 0) {
|
|
148
|
+
terminal.clearLinesAbove(lineCount);
|
|
149
|
+
}
|
|
150
|
+
if (config.hideCursor !== false) {
|
|
151
|
+
terminal.showCursor();
|
|
152
|
+
}
|
|
153
|
+
if (!wasRawMode) {
|
|
154
|
+
terminal.disableRawMode();
|
|
155
|
+
}
|
|
156
|
+
// Resume footer animation
|
|
157
|
+
resumeAfterOverlay();
|
|
158
|
+
};
|
|
159
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Overlay Type Definitions
|
|
3
|
+
*
|
|
4
|
+
* Core interfaces and types for the overlay system.
|
|
5
|
+
* These provide the foundation for BaseOverlay and composable features.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Result of handling a key press within a feature or overlay.
|
|
9
|
+
*
|
|
10
|
+
* - `handled: false` - Key was not handled, try next handler
|
|
11
|
+
* - `handled: true` - Key was handled
|
|
12
|
+
* - `action: 'render'` - State changed, re-render needed
|
|
13
|
+
* - `action: 'close'` - Overlay should close
|
|
14
|
+
* - No action - Key was consumed but no visual change
|
|
15
|
+
*/
|
|
16
|
+
export type KeyResult = {
|
|
17
|
+
handled: false;
|
|
18
|
+
} | {
|
|
19
|
+
handled: true;
|
|
20
|
+
action?: 'render' | 'close';
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Result of handling a key press within a screen.
|
|
24
|
+
*
|
|
25
|
+
* - `action: 'stay'` - Stay on current screen (optionally re-render)
|
|
26
|
+
* - `action: 'push'` - Push a new screen onto the stack
|
|
27
|
+
* - `action: 'pop'` - Go back to previous screen
|
|
28
|
+
* - `action: 'close'` - Close the entire overlay with a result
|
|
29
|
+
*/
|
|
30
|
+
export type ScreenResult<TResult = unknown> = {
|
|
31
|
+
action: 'stay';
|
|
32
|
+
render?: boolean;
|
|
33
|
+
} | {
|
|
34
|
+
action: 'push';
|
|
35
|
+
screen: BaseScreenInterface;
|
|
36
|
+
} | {
|
|
37
|
+
action: 'pop';
|
|
38
|
+
} | {
|
|
39
|
+
action: 'close';
|
|
40
|
+
result: TResult;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Base state that all overlays must include.
|
|
44
|
+
* Tracks line counts for proper terminal clearing.
|
|
45
|
+
*/
|
|
46
|
+
export interface OverlayState {
|
|
47
|
+
/** Current rendered line count */
|
|
48
|
+
lineCount: number;
|
|
49
|
+
/** Maximum line count seen (for clearing) */
|
|
50
|
+
maxLineCount: number;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* State for list-based selection.
|
|
54
|
+
*/
|
|
55
|
+
export interface ListState {
|
|
56
|
+
/** Currently selected index */
|
|
57
|
+
selectedIndex: number;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* State for tabbed overlays.
|
|
61
|
+
*/
|
|
62
|
+
export interface TabState {
|
|
63
|
+
/** Current tab index (0-based) */
|
|
64
|
+
currentTab: number;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* State for paginated overlays.
|
|
68
|
+
*/
|
|
69
|
+
export interface PaginationState {
|
|
70
|
+
/** Current page (0-based) */
|
|
71
|
+
currentPage: number;
|
|
72
|
+
/** Items per page */
|
|
73
|
+
pageSize: number;
|
|
74
|
+
/** Total number of items */
|
|
75
|
+
totalItems: number;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* State for text input.
|
|
79
|
+
*/
|
|
80
|
+
export interface InputState {
|
|
81
|
+
/** Current input buffer */
|
|
82
|
+
inputBuffer: string;
|
|
83
|
+
/** Whether input mode is active */
|
|
84
|
+
isInputMode: boolean;
|
|
85
|
+
/** Validation error message (if any) */
|
|
86
|
+
error?: string | null;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* State for search functionality.
|
|
90
|
+
*/
|
|
91
|
+
export interface SearchState {
|
|
92
|
+
/** Current search query */
|
|
93
|
+
searchQuery: string;
|
|
94
|
+
/** Whether search mode is active */
|
|
95
|
+
isSearchMode: boolean;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Configuration options for an overlay.
|
|
99
|
+
*/
|
|
100
|
+
export interface OverlayConfig {
|
|
101
|
+
/** Minimum height in lines (for consistent sizing) */
|
|
102
|
+
minHeight?: number;
|
|
103
|
+
/** Whether to show border (default: true) */
|
|
104
|
+
showBorder?: boolean;
|
|
105
|
+
/** Whether to hide cursor during overlay (default: true) */
|
|
106
|
+
hideCursor?: boolean;
|
|
107
|
+
/** Whether to enable vim-style navigation (default: true) */
|
|
108
|
+
enableVimNav?: boolean;
|
|
109
|
+
/** Whether to enable number keys for tabs (default: true for tabbed overlays) */
|
|
110
|
+
enableNumberKeys?: boolean;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Tab definition for tabbed overlays.
|
|
114
|
+
*/
|
|
115
|
+
export interface TabDefinition {
|
|
116
|
+
/** Unique identifier for the tab */
|
|
117
|
+
id: string;
|
|
118
|
+
/** Display label */
|
|
119
|
+
label: string;
|
|
120
|
+
/** Optional keyboard shortcut (1-9) */
|
|
121
|
+
shortcut?: number;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Interface for composable features.
|
|
125
|
+
* Features handle specific aspects of overlay behavior (list, tabs, pagination, etc.)
|
|
126
|
+
*/
|
|
127
|
+
export interface Feature<TState = unknown> {
|
|
128
|
+
/**
|
|
129
|
+
* Handle a key press.
|
|
130
|
+
* @param data - Raw key buffer
|
|
131
|
+
* @param state - Current state (feature-specific portion)
|
|
132
|
+
* @returns KeyResult if handled, null if not handled
|
|
133
|
+
*/
|
|
134
|
+
handleKey(data: Buffer, state: TState): KeyResult | null;
|
|
135
|
+
/**
|
|
136
|
+
* Optional render method for feature-specific content.
|
|
137
|
+
* @param state - Current state
|
|
138
|
+
* @returns Array of lines to render
|
|
139
|
+
*/
|
|
140
|
+
render?(state: TState): string[];
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Interface for screens in a multi-screen overlay.
|
|
144
|
+
*/
|
|
145
|
+
export interface BaseScreenInterface {
|
|
146
|
+
/**
|
|
147
|
+
* Render the screen content.
|
|
148
|
+
* @returns Array of lines to render
|
|
149
|
+
*/
|
|
150
|
+
render(): string[];
|
|
151
|
+
/**
|
|
152
|
+
* Handle a key press.
|
|
153
|
+
* @param data - Raw key buffer
|
|
154
|
+
* @returns ScreenResult indicating what action to take
|
|
155
|
+
*/
|
|
156
|
+
handleKey(data: Buffer): ScreenResult;
|
|
157
|
+
/**
|
|
158
|
+
* Optional lifecycle hook called when screen becomes active.
|
|
159
|
+
*/
|
|
160
|
+
onEnter?(): void;
|
|
161
|
+
/**
|
|
162
|
+
* Optional lifecycle hook called when screen is deactivated.
|
|
163
|
+
*/
|
|
164
|
+
onExit?(): void;
|
|
165
|
+
/**
|
|
166
|
+
* Optional: Return minimum height for stable rendering.
|
|
167
|
+
* Override to prevent visual jitter when screen content varies.
|
|
168
|
+
*/
|
|
169
|
+
getMinHeight?(): number;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Options for rendering an item in a list.
|
|
173
|
+
*/
|
|
174
|
+
export interface ListItemRenderOptions<T> {
|
|
175
|
+
/** The item to render */
|
|
176
|
+
item: T;
|
|
177
|
+
/** Whether this item is selected */
|
|
178
|
+
isSelected: boolean;
|
|
179
|
+
/** Index in the list */
|
|
180
|
+
index: number;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Function type for custom list item rendering.
|
|
184
|
+
*/
|
|
185
|
+
export type ListItemRenderer<T> = (options: ListItemRenderOptions<T>) => string;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Render Utilities
|
|
3
|
+
*
|
|
4
|
+
* Re-exported from @compilr-dev/ui-core for consistency.
|
|
5
|
+
* CLI-specific aliases provided for backward compatibility.
|
|
6
|
+
*/
|
|
7
|
+
export { renderBorder, wrapText, truncatePlain, truncateAnsi, normalizeText, padToHeight, emptyLines, padToWidth, } from '@compilr-dev/ui-core/utils';
|
|
8
|
+
export { truncatePlain as truncate } from '@compilr-dev/ui-core/utils';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Render Utilities
|
|
3
|
+
*
|
|
4
|
+
* Re-exported from @compilr-dev/ui-core for consistency.
|
|
5
|
+
* CLI-specific aliases provided for backward compatibility.
|
|
6
|
+
*/
|
|
7
|
+
export { renderBorder, wrapText, truncatePlain, truncateAnsi, normalizeText, padToHeight, emptyLines, padToWidth, } from '@compilr-dev/ui-core/utils';
|
|
8
|
+
// Re-export truncatePlain as truncate for CLI compatibility
|
|
9
|
+
// (ui-core's truncate in ansi.ts is ANSI-aware with '...' suffix,
|
|
10
|
+
// CLI expects plain text truncate with '…' suffix)
|
|
11
|
+
export { truncatePlain as truncate } from '@compilr-dev/ui-core/utils';
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Screen Stack
|
|
3
|
+
*
|
|
4
|
+
* Navigation stack for multi-screen overlays.
|
|
5
|
+
* Enables proper "back" behavior where Esc goes to previous screen.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* ```typescript
|
|
9
|
+
* class MyOverlay extends BaseOverlay<MyState, MyResult> {
|
|
10
|
+
* private screenStack = new ScreenStack();
|
|
11
|
+
*
|
|
12
|
+
* constructor() {
|
|
13
|
+
* super(initialState);
|
|
14
|
+
* this.screenStack.push(new ListScreen());
|
|
15
|
+
* }
|
|
16
|
+
*
|
|
17
|
+
* handleKey(data: Buffer): void {
|
|
18
|
+
* if (isEscape(data)) {
|
|
19
|
+
* if (this.screenStack.size() > 1) {
|
|
20
|
+
* this.screenStack.pop();
|
|
21
|
+
* this.update();
|
|
22
|
+
* } else {
|
|
23
|
+
* this.close(null);
|
|
24
|
+
* }
|
|
25
|
+
* return;
|
|
26
|
+
* }
|
|
27
|
+
*
|
|
28
|
+
* const result = this.screenStack.current()?.handleKey(data);
|
|
29
|
+
* this.handleScreenResult(result);
|
|
30
|
+
* }
|
|
31
|
+
*
|
|
32
|
+
* render(): string[] {
|
|
33
|
+
* return [
|
|
34
|
+
* ...this.renderHeader('My Overlay'),
|
|
35
|
+
* ...this.screenStack.current()?.render() ?? [],
|
|
36
|
+
* ...this.renderFooter(this.getCurrentHints())
|
|
37
|
+
* ];
|
|
38
|
+
* }
|
|
39
|
+
* }
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
import type { BaseScreenInterface, ScreenResult } from './overlay-types.js';
|
|
43
|
+
export type { BaseScreenInterface, ScreenResult };
|
|
44
|
+
/**
|
|
45
|
+
* Abstract base class for screens.
|
|
46
|
+
* Extend this to create screens for multi-screen overlays.
|
|
47
|
+
*/
|
|
48
|
+
export declare abstract class BaseScreen implements BaseScreenInterface {
|
|
49
|
+
/**
|
|
50
|
+
* Render the screen content.
|
|
51
|
+
* @returns Array of lines to render
|
|
52
|
+
*/
|
|
53
|
+
abstract render(): string[];
|
|
54
|
+
/**
|
|
55
|
+
* Handle a key press.
|
|
56
|
+
* @param data - Raw key buffer
|
|
57
|
+
* @returns ScreenResult indicating what action to take
|
|
58
|
+
*/
|
|
59
|
+
abstract handleKey(data: Buffer): ScreenResult;
|
|
60
|
+
/**
|
|
61
|
+
* Optional lifecycle hook called when screen becomes active.
|
|
62
|
+
* Override to perform setup when navigating to this screen.
|
|
63
|
+
*/
|
|
64
|
+
onEnter?(): void;
|
|
65
|
+
/**
|
|
66
|
+
* Optional lifecycle hook called when screen is deactivated.
|
|
67
|
+
* Override to perform cleanup when navigating away.
|
|
68
|
+
*/
|
|
69
|
+
onExit?(): void;
|
|
70
|
+
/**
|
|
71
|
+
* Optional: Return minimum height for stable rendering.
|
|
72
|
+
* Override to prevent visual jitter when screen content varies.
|
|
73
|
+
* @returns Minimum number of lines this screen should occupy
|
|
74
|
+
*/
|
|
75
|
+
getMinHeight(): number;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Stack-based navigation for multi-screen overlays.
|
|
79
|
+
*
|
|
80
|
+
* The stack maintains a history of screens, allowing:
|
|
81
|
+
* - push() to navigate forward to a new screen
|
|
82
|
+
* - pop() to go back to the previous screen
|
|
83
|
+
* - current() to get the active screen
|
|
84
|
+
*/
|
|
85
|
+
export declare class ScreenStack {
|
|
86
|
+
private readonly screens;
|
|
87
|
+
/**
|
|
88
|
+
* Push a new screen onto the stack.
|
|
89
|
+
* Calls onExit() on current screen and onEnter() on new screen.
|
|
90
|
+
*
|
|
91
|
+
* @param screen - Screen to push
|
|
92
|
+
*/
|
|
93
|
+
push(screen: BaseScreenInterface): void;
|
|
94
|
+
/**
|
|
95
|
+
* Pop the current screen and return to the previous one.
|
|
96
|
+
* Calls onExit() on popped screen and onEnter() on revealed screen.
|
|
97
|
+
*
|
|
98
|
+
* @returns The popped screen, or null if stack was empty
|
|
99
|
+
*/
|
|
100
|
+
pop(): BaseScreenInterface | null;
|
|
101
|
+
/**
|
|
102
|
+
* Get the current (topmost) screen.
|
|
103
|
+
*
|
|
104
|
+
* @returns Current screen, or undefined if stack is empty
|
|
105
|
+
*/
|
|
106
|
+
current(): BaseScreenInterface | undefined;
|
|
107
|
+
/**
|
|
108
|
+
* Get the number of screens in the stack.
|
|
109
|
+
*/
|
|
110
|
+
size(): number;
|
|
111
|
+
/**
|
|
112
|
+
* Check if the stack is empty.
|
|
113
|
+
*/
|
|
114
|
+
isEmpty(): boolean;
|
|
115
|
+
/**
|
|
116
|
+
* Check if there's more than one screen (can go back).
|
|
117
|
+
*/
|
|
118
|
+
canGoBack(): boolean;
|
|
119
|
+
/**
|
|
120
|
+
* Clear all screens from the stack.
|
|
121
|
+
* Calls onExit() on each screen in reverse order.
|
|
122
|
+
*/
|
|
123
|
+
clear(): void;
|
|
124
|
+
/**
|
|
125
|
+
* Replace the current screen with a new one.
|
|
126
|
+
* Useful for "replace" navigation (no back).
|
|
127
|
+
*
|
|
128
|
+
* @param screen - Screen to replace with
|
|
129
|
+
*/
|
|
130
|
+
replace(screen: BaseScreenInterface): void;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Helper to create a ScreenResult for staying on the current screen.
|
|
134
|
+
*/
|
|
135
|
+
export declare function stay(render?: boolean): ScreenResult;
|
|
136
|
+
/**
|
|
137
|
+
* Helper to create a ScreenResult for pushing a new screen.
|
|
138
|
+
*/
|
|
139
|
+
export declare function pushScreen(screen: BaseScreenInterface): ScreenResult;
|
|
140
|
+
/**
|
|
141
|
+
* Helper to create a ScreenResult for popping the current screen.
|
|
142
|
+
*/
|
|
143
|
+
export declare function popScreen(): ScreenResult;
|
|
144
|
+
/**
|
|
145
|
+
* Helper to create a ScreenResult for closing the overlay.
|
|
146
|
+
* Result is optional for void result types.
|
|
147
|
+
*/
|
|
148
|
+
export declare function closeOverlay<T = void>(result?: T): ScreenResult<T>;
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Screen Stack
|
|
3
|
+
*
|
|
4
|
+
* Navigation stack for multi-screen overlays.
|
|
5
|
+
* Enables proper "back" behavior where Esc goes to previous screen.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* ```typescript
|
|
9
|
+
* class MyOverlay extends BaseOverlay<MyState, MyResult> {
|
|
10
|
+
* private screenStack = new ScreenStack();
|
|
11
|
+
*
|
|
12
|
+
* constructor() {
|
|
13
|
+
* super(initialState);
|
|
14
|
+
* this.screenStack.push(new ListScreen());
|
|
15
|
+
* }
|
|
16
|
+
*
|
|
17
|
+
* handleKey(data: Buffer): void {
|
|
18
|
+
* if (isEscape(data)) {
|
|
19
|
+
* if (this.screenStack.size() > 1) {
|
|
20
|
+
* this.screenStack.pop();
|
|
21
|
+
* this.update();
|
|
22
|
+
* } else {
|
|
23
|
+
* this.close(null);
|
|
24
|
+
* }
|
|
25
|
+
* return;
|
|
26
|
+
* }
|
|
27
|
+
*
|
|
28
|
+
* const result = this.screenStack.current()?.handleKey(data);
|
|
29
|
+
* this.handleScreenResult(result);
|
|
30
|
+
* }
|
|
31
|
+
*
|
|
32
|
+
* render(): string[] {
|
|
33
|
+
* return [
|
|
34
|
+
* ...this.renderHeader('My Overlay'),
|
|
35
|
+
* ...this.screenStack.current()?.render() ?? [],
|
|
36
|
+
* ...this.renderFooter(this.getCurrentHints())
|
|
37
|
+
* ];
|
|
38
|
+
* }
|
|
39
|
+
* }
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
// =============================================================================
|
|
43
|
+
// BaseScreen Abstract Class
|
|
44
|
+
// =============================================================================
|
|
45
|
+
/**
|
|
46
|
+
* Abstract base class for screens.
|
|
47
|
+
* Extend this to create screens for multi-screen overlays.
|
|
48
|
+
*/
|
|
49
|
+
export class BaseScreen {
|
|
50
|
+
/**
|
|
51
|
+
* Optional: Return minimum height for stable rendering.
|
|
52
|
+
* Override to prevent visual jitter when screen content varies.
|
|
53
|
+
* @returns Minimum number of lines this screen should occupy
|
|
54
|
+
*/
|
|
55
|
+
getMinHeight() {
|
|
56
|
+
return 0; // Default: no minimum, use overlay's minHeight
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// =============================================================================
|
|
60
|
+
// ScreenStack Class
|
|
61
|
+
// =============================================================================
|
|
62
|
+
/**
|
|
63
|
+
* Stack-based navigation for multi-screen overlays.
|
|
64
|
+
*
|
|
65
|
+
* The stack maintains a history of screens, allowing:
|
|
66
|
+
* - push() to navigate forward to a new screen
|
|
67
|
+
* - pop() to go back to the previous screen
|
|
68
|
+
* - current() to get the active screen
|
|
69
|
+
*/
|
|
70
|
+
export class ScreenStack {
|
|
71
|
+
screens = [];
|
|
72
|
+
/**
|
|
73
|
+
* Push a new screen onto the stack.
|
|
74
|
+
* Calls onExit() on current screen and onEnter() on new screen.
|
|
75
|
+
*
|
|
76
|
+
* @param screen - Screen to push
|
|
77
|
+
*/
|
|
78
|
+
push(screen) {
|
|
79
|
+
// Call exit hook on current screen
|
|
80
|
+
this.current()?.onExit?.();
|
|
81
|
+
// Push new screen
|
|
82
|
+
this.screens.push(screen);
|
|
83
|
+
// Call enter hook on new screen
|
|
84
|
+
screen.onEnter?.();
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Pop the current screen and return to the previous one.
|
|
88
|
+
* Calls onExit() on popped screen and onEnter() on revealed screen.
|
|
89
|
+
*
|
|
90
|
+
* @returns The popped screen, or null if stack was empty
|
|
91
|
+
*/
|
|
92
|
+
pop() {
|
|
93
|
+
if (this.screens.length === 0) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
// Pop and call exit hook
|
|
97
|
+
const screen = this.screens.pop();
|
|
98
|
+
if (screen) {
|
|
99
|
+
screen.onExit?.();
|
|
100
|
+
}
|
|
101
|
+
// Call enter hook on now-current screen
|
|
102
|
+
this.current()?.onEnter?.();
|
|
103
|
+
return screen ?? null;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Get the current (topmost) screen.
|
|
107
|
+
*
|
|
108
|
+
* @returns Current screen, or undefined if stack is empty
|
|
109
|
+
*/
|
|
110
|
+
current() {
|
|
111
|
+
return this.screens[this.screens.length - 1];
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Get the number of screens in the stack.
|
|
115
|
+
*/
|
|
116
|
+
size() {
|
|
117
|
+
return this.screens.length;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Check if the stack is empty.
|
|
121
|
+
*/
|
|
122
|
+
isEmpty() {
|
|
123
|
+
return this.screens.length === 0;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Check if there's more than one screen (can go back).
|
|
127
|
+
*/
|
|
128
|
+
canGoBack() {
|
|
129
|
+
return this.screens.length > 1;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Clear all screens from the stack.
|
|
133
|
+
* Calls onExit() on each screen in reverse order.
|
|
134
|
+
*/
|
|
135
|
+
clear() {
|
|
136
|
+
while (this.screens.length > 0) {
|
|
137
|
+
this.pop();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Replace the current screen with a new one.
|
|
142
|
+
* Useful for "replace" navigation (no back).
|
|
143
|
+
*
|
|
144
|
+
* @param screen - Screen to replace with
|
|
145
|
+
*/
|
|
146
|
+
replace(screen) {
|
|
147
|
+
if (this.screens.length > 0) {
|
|
148
|
+
const current = this.screens.pop();
|
|
149
|
+
if (current) {
|
|
150
|
+
current.onExit?.();
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
this.screens.push(screen);
|
|
154
|
+
screen.onEnter?.();
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
// =============================================================================
|
|
158
|
+
// Helper Types
|
|
159
|
+
// =============================================================================
|
|
160
|
+
/**
|
|
161
|
+
* Helper to create a ScreenResult for staying on the current screen.
|
|
162
|
+
*/
|
|
163
|
+
export function stay(render = true) {
|
|
164
|
+
return { action: 'stay', render };
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Helper to create a ScreenResult for pushing a new screen.
|
|
168
|
+
*/
|
|
169
|
+
export function pushScreen(screen) {
|
|
170
|
+
return { action: 'push', screen };
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Helper to create a ScreenResult for popping the current screen.
|
|
174
|
+
*/
|
|
175
|
+
export function popScreen() {
|
|
176
|
+
return { action: 'pop' };
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Helper to create a ScreenResult for closing the overlay.
|
|
180
|
+
* Result is optional for void result types.
|
|
181
|
+
*/
|
|
182
|
+
export function closeOverlay(result) {
|
|
183
|
+
return { action: 'close', result: result };
|
|
184
|
+
}
|