@flyingrobots/bijou-tui 5.0.0 → 7.1.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 +152 -1
- package/dist/animate.d.ts +4 -0
- package/dist/animate.d.ts.map +1 -1
- package/dist/animate.js +47 -20
- package/dist/animate.js.map +1 -1
- package/dist/app-frame-actions.d.ts.map +1 -1
- package/dist/app-frame-actions.js +56 -1
- package/dist/app-frame-actions.js.map +1 -1
- package/dist/app-frame-i18n.d.ts.map +1 -1
- package/dist/app-frame-i18n.js +3 -1
- package/dist/app-frame-i18n.js.map +1 -1
- package/dist/app-frame-overlays.d.ts +16 -1
- package/dist/app-frame-overlays.d.ts.map +1 -1
- package/dist/app-frame-overlays.js +63 -1
- package/dist/app-frame-overlays.js.map +1 -1
- package/dist/app-frame-palette.d.ts.map +1 -1
- package/dist/app-frame-palette.js +36 -16
- package/dist/app-frame-palette.js.map +1 -1
- package/dist/app-frame-render.d.ts.map +1 -1
- package/dist/app-frame-render.js +14 -5
- package/dist/app-frame-render.js.map +1 -1
- package/dist/app-frame-types.d.ts +22 -0
- package/dist/app-frame-types.d.ts.map +1 -1
- package/dist/app-frame-types.js.map +1 -1
- package/dist/app-frame-utils.d.ts +3 -1
- package/dist/app-frame-utils.d.ts.map +1 -1
- package/dist/app-frame-utils.js +5 -0
- package/dist/app-frame-utils.js.map +1 -1
- package/dist/app-frame.d.ts +68 -6
- package/dist/app-frame.d.ts.map +1 -1
- package/dist/app-frame.js +121 -17
- package/dist/app-frame.js.map +1 -1
- package/dist/canvas.d.ts +11 -3
- package/dist/canvas.d.ts.map +1 -1
- package/dist/canvas.js +122 -9
- package/dist/canvas.js.map +1 -1
- package/dist/cell-glyph-fit.d.ts +20 -0
- package/dist/cell-glyph-fit.d.ts.map +1 -0
- package/dist/cell-glyph-fit.js +82 -0
- package/dist/cell-glyph-fit.js.map +1 -0
- package/dist/command-palette.d.ts +2 -0
- package/dist/command-palette.d.ts.map +1 -1
- package/dist/command-palette.js +36 -19
- package/dist/command-palette.js.map +1 -1
- package/dist/eventbus.d.ts +20 -0
- package/dist/eventbus.d.ts.map +1 -1
- package/dist/eventbus.js +47 -0
- package/dist/eventbus.js.map +1 -1
- package/dist/file-picker.d.ts +4 -0
- package/dist/file-picker.d.ts.map +1 -1
- package/dist/file-picker.js +9 -1
- package/dist/file-picker.js.map +1 -1
- package/dist/focus-area.d.ts +6 -5
- package/dist/focus-area.d.ts.map +1 -1
- package/dist/focus-area.js +6 -5
- package/dist/focus-area.js.map +1 -1
- package/dist/focus-map.d.ts +40 -0
- package/dist/focus-map.d.ts.map +1 -0
- package/dist/focus-map.js +133 -0
- package/dist/focus-map.js.map +1 -0
- package/dist/index.d.ts +22 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -2
- package/dist/index.js.map +1 -1
- package/dist/input-map.d.ts +68 -0
- package/dist/input-map.d.ts.map +1 -0
- package/dist/input-map.js +162 -0
- package/dist/input-map.js.map +1 -0
- package/dist/input-routing-inspector.d.ts +24 -0
- package/dist/input-routing-inspector.d.ts.map +1 -0
- package/dist/input-routing-inspector.js +76 -0
- package/dist/input-routing-inspector.js.map +1 -0
- package/dist/keybindings.d.ts.map +1 -1
- package/dist/keybindings.js +3 -0
- package/dist/keybindings.js.map +1 -1
- package/dist/layout-inspector.d.ts +31 -0
- package/dist/layout-inspector.d.ts.map +1 -0
- package/dist/layout-inspector.js +133 -0
- package/dist/layout-inspector.js.map +1 -0
- package/dist/notification.d.ts.map +1 -1
- package/dist/notification.js +38 -5
- package/dist/notification.js.map +1 -1
- package/dist/pipeline/middleware/motion.d.ts.map +1 -1
- package/dist/pipeline/middleware/motion.js +2 -1
- package/dist/pipeline/middleware/motion.js.map +1 -1
- package/dist/pipeline/middleware/paint.d.ts.map +1 -1
- package/dist/pipeline/middleware/paint.js +2 -1
- package/dist/pipeline/middleware/paint.js.map +1 -1
- package/dist/pipeline/pipeline.d.ts +8 -1
- package/dist/pipeline/pipeline.d.ts.map +1 -1
- package/dist/pipeline/pipeline.js +43 -7
- package/dist/pipeline/pipeline.js.map +1 -1
- package/dist/raster-glyph.d.ts +45 -0
- package/dist/raster-glyph.d.ts.map +1 -0
- package/dist/raster-glyph.js +405 -0
- package/dist/raster-glyph.js.map +1 -0
- package/dist/raytrace.d.ts +59 -0
- package/dist/raytrace.d.ts.map +1 -0
- package/dist/raytrace.js +121 -0
- package/dist/raytrace.js.map +1 -0
- package/dist/runtime-binding.d.ts +59 -0
- package/dist/runtime-binding.d.ts.map +1 -0
- package/dist/runtime-binding.js +271 -0
- package/dist/runtime-binding.js.map +1 -0
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +51 -6
- package/dist/runtime.js.map +1 -1
- package/dist/shell-quit.js +1 -1
- package/dist/shell-quit.js.map +1 -1
- package/dist/surface-budget.d.ts +27 -0
- package/dist/surface-budget.d.ts.map +1 -0
- package/dist/surface-budget.js +61 -0
- package/dist/surface-budget.js.map +1 -0
- package/dist/surface-diff.d.ts +36 -0
- package/dist/surface-diff.d.ts.map +1 -0
- package/dist/surface-diff.js +202 -0
- package/dist/surface-diff.js.map +1 -0
- package/dist/surface-layout.d.ts +11 -0
- package/dist/surface-layout.d.ts.map +1 -1
- package/dist/surface-layout.js +16 -1
- package/dist/surface-layout.js.map +1 -1
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +4 -4
package/dist/app-frame.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Provides tabs, pane focus/scroll isolation, shell key handling, help,
|
|
5
5
|
* panel-scoped overlay context, and optional frame-level command palette.
|
|
6
6
|
*/
|
|
7
|
-
import { cloneContextWithResolvedTheme,
|
|
7
|
+
import { cloneContextWithResolvedTheme, createSurface, perfOverlaySurface, setDefaultContext, resolveClock, resolveSafeCtx, } from '@flyingrobots/bijou';
|
|
8
8
|
import { createKeyMap, formatKeyCombo } from './keybindings.js';
|
|
9
9
|
import { isKeyMsg, isMouseMsg, isResizeMsg } from './types.js';
|
|
10
10
|
import { quit } from './commands.js';
|
|
@@ -15,14 +15,15 @@ import { commandPaletteSurface, commandPaletteKeyMap, } from './command-palette.
|
|
|
15
15
|
import { restoreLayoutState } from './layout-preset.js';
|
|
16
16
|
import { createNotificationState, dismissNotification, hitTestNotificationStack, notificationsNeedTick, pushNotification, renderNotificationStack, tickNotifications, trimNotificationsToViewport, } from './notification.js';
|
|
17
17
|
import { isFrameScopedMsg, isPageScopedMsg, wrapCmdForPage, emitMsg, emitMsgForPage, wrapFrameMsg, } from './app-frame-types.js';
|
|
18
|
-
import { createFrameKeyMap, frameBodyRect, mergeBindingSources, } from './app-frame-utils.js';
|
|
19
|
-
import { renderHelpOverlay, isHelpScrollAction, resolveCurrentShellTheme, resolveNextShellTheme, resolveShellThemeForContext, resolveFrameSettings, resolveFrameNotificationCenter, resolveSettingsLayout, resolveNotificationCenterLayout, resolveInputAreas, findInputAreaByPaneId, moveSettingsFocus, scrollSettingsBy, clampSettingsScroll, scrollNotificationCenterBy, cycleNotificationCenterFilter, clampSettingsFocus, renderSettingsDrawer, renderNotificationCenterDrawer, resolveNotificationFooterCue, } from './app-frame-overlays.js';
|
|
18
|
+
import { createFrameKeyMap, frameBodyRect, mergeBindingSources, resolveFramePageText, } from './app-frame-utils.js';
|
|
19
|
+
import { renderHelpOverlay, isHelpScrollAction, resolveFrameShellThemeChoices, resolveCurrentShellTheme, resolveNextShellTheme, resolveShellThemeForContext, resolveFrameSettings, resolveFrameNotificationCenter, resolveSettingsLayout, resolveNotificationCenterLayout, resolveInputAreas, findInputAreaByPaneId, moveSettingsFocus, scrollSettingsBy, clampSettingsScroll, scrollNotificationCenterBy, cycleNotificationCenterFilter, clampSettingsFocus, renderSettingsDrawer, renderNotificationCenterDrawer, resolveNotificationFooterCue, } from './app-frame-overlays.js';
|
|
20
20
|
import { activeFrameLayer, describeFrameRuntimeViewStack, projectFrameControls, } from './app-frame-layers.js';
|
|
21
21
|
import { applyRuntimeCommandBuffer, bufferRuntimeRouteResult, createRuntimeBuffers, createRuntimeRetainedLayouts, retainRuntimeLayout, routeRuntimeInput, } from './runtime-engine.js';
|
|
22
22
|
import { frameMessage, frameNotificationFilterLabel, } from './app-frame-i18n.js';
|
|
23
23
|
import { resolveHeaderLine, renderHelpLine, renderPageContent, renderPageContentInto, renderMaximizedPane, renderMaximizedPaneInto, renderTransition, createFramePaneScratchPool, } from './app-frame-render.js';
|
|
24
24
|
import { applyFrameAction, scrollFocusedPane, switchTab, syncPageFrameState, } from './app-frame-actions.js';
|
|
25
25
|
import { handlePaletteKey, openCommandPalette, openSearchPalette, } from './app-frame-palette.js';
|
|
26
|
+
import { createInputActionMap, createInputGestureRecognizer, } from './input-map.js';
|
|
26
27
|
export { emitFrameAction, notify, } from './app-frame-types.js';
|
|
27
28
|
export { activeFrameLayer, describeFrameLayerStack, describeFrameRuntimeViewStack, projectFrameControls, underlyingFrameLayer, } from './app-frame-layers.js';
|
|
28
29
|
// ---------------------------------------------------------------------------
|
|
@@ -31,6 +32,7 @@ export { activeFrameLayer, describeFrameLayerStack, describeFrameRuntimeViewStac
|
|
|
31
32
|
const FRAME_NOTIFICATION_TICK_MS = 40;
|
|
32
33
|
const DEFAULT_FRAME_NOTIFICATION_DURATION_MS = 6_000;
|
|
33
34
|
const SETTINGS_FEEDBACK_TOAST_WIDTH = 40;
|
|
35
|
+
const FRAME_FOOTER_DOUBLE_TAB_MS = 300;
|
|
34
36
|
const EMPTY_RUNTIME_LAYOUTS = createRuntimeRetainedLayouts();
|
|
35
37
|
function createQuitHelpKeys(i18n) {
|
|
36
38
|
const t = (id, fallback) => frameMessage(i18n, id, fallback);
|
|
@@ -146,7 +148,7 @@ function cloneShellThemeContext(ctx, resolvedTheme) {
|
|
|
146
148
|
function readStageDuration(timings, stage) {
|
|
147
149
|
return timings.find((timing) => timing.stage === stage)?.durationMs ?? 0;
|
|
148
150
|
}
|
|
149
|
-
function summarizeFrameTimings(timings, frameBudgetMs) {
|
|
151
|
+
export function summarizeFrameTimings(timings, frameBudgetMs) {
|
|
150
152
|
const frameTimeMs = timings.reduce((total, timing) => total + timing.durationMs, 0);
|
|
151
153
|
return {
|
|
152
154
|
frameTimeMs,
|
|
@@ -156,6 +158,36 @@ function summarizeFrameTimings(timings, frameBudgetMs) {
|
|
|
156
158
|
frameOverBudget: frameBudgetMs != null && frameTimeMs > frameBudgetMs,
|
|
157
159
|
};
|
|
158
160
|
}
|
|
161
|
+
export function renderFramePerfHudOverlay(telemetry, options = {}) {
|
|
162
|
+
const refreshRate = telemetry.refreshRate ?? options.ctx?.runtime.refreshRate ?? 60;
|
|
163
|
+
const fps = telemetry.frameTimeMs > 0
|
|
164
|
+
? Math.min(refreshRate, 1000 / telemetry.frameTimeMs)
|
|
165
|
+
: refreshRate;
|
|
166
|
+
const width = Math.max(12, Math.min(40, telemetry.columns - 2));
|
|
167
|
+
const surface = perfOverlaySurface({
|
|
168
|
+
fps,
|
|
169
|
+
frameTimeMs: telemetry.frameTimeMs,
|
|
170
|
+
width: telemetry.columns,
|
|
171
|
+
height: telemetry.rows,
|
|
172
|
+
extras: [
|
|
173
|
+
{ label: 'view', value: `${telemetry.viewTimeMs.toFixed(2)} ms` },
|
|
174
|
+
{ label: 'diff', value: `${telemetry.diffTimeMs.toFixed(2)} ms` },
|
|
175
|
+
],
|
|
176
|
+
}, {
|
|
177
|
+
title: frameMessage(options.i18n, 'perfHud.title', 'Perf HUD'),
|
|
178
|
+
width,
|
|
179
|
+
showChart: false,
|
|
180
|
+
borderToken: options.ctx?.border('primary'),
|
|
181
|
+
bgToken: options.ctx?.surface('elevated'),
|
|
182
|
+
ctx: options.ctx,
|
|
183
|
+
});
|
|
184
|
+
return {
|
|
185
|
+
content: '',
|
|
186
|
+
surface,
|
|
187
|
+
row: 1,
|
|
188
|
+
col: Math.max(0, telemetry.columns - surface.width - 1),
|
|
189
|
+
};
|
|
190
|
+
}
|
|
159
191
|
function applyFrameTimingSnapshot(model, snapshot) {
|
|
160
192
|
if (model.frameTimeMs === snapshot.frameTimeMs
|
|
161
193
|
&& model.viewTimeMs === snapshot.viewTimeMs
|
|
@@ -206,7 +238,8 @@ export function createFramedApp(options) {
|
|
|
206
238
|
const shellThemeSpecs = options.shellThemes ?? [];
|
|
207
239
|
let defaultFrameCtx = options.ctx ?? resolveSafeCtx();
|
|
208
240
|
let resolvedShellThemes = [];
|
|
209
|
-
const enableShellThemeSettings = shellThemeSpecs.length > 1
|
|
241
|
+
const enableShellThemeSettings = shellThemeSpecs.length > 1
|
|
242
|
+
|| shellThemeSpecs.some((theme) => (theme.modes?.length ?? 0) > 1);
|
|
210
243
|
const usesAmbientDefaultContext = options.ctx == null && defaultFrameCtx != null;
|
|
211
244
|
let frameCtx = options.ctx;
|
|
212
245
|
let frameCtxShellThemeId;
|
|
@@ -219,13 +252,7 @@ export function createFramedApp(options) {
|
|
|
219
252
|
throw new Error('createFramedApp: shellThemes requires options.ctx, app.run({ ctx }), or a default Bijou context');
|
|
220
253
|
}
|
|
221
254
|
defaultFrameCtx ??= baseCtx;
|
|
222
|
-
resolvedShellThemes = shellThemeSpecs
|
|
223
|
-
id: theme.id,
|
|
224
|
-
label: theme.label,
|
|
225
|
-
description: theme.description,
|
|
226
|
-
shellTheme: theme,
|
|
227
|
-
resolvedTheme: createResolved(theme.theme, defaultFrameCtx.theme.noColor, defaultFrameCtx.theme.colorScheme),
|
|
228
|
-
}));
|
|
255
|
+
resolvedShellThemes = resolveFrameShellThemeChoices(shellThemeSpecs, defaultFrameCtx);
|
|
229
256
|
}
|
|
230
257
|
if (frameCtx != null) {
|
|
231
258
|
ensureResolvedShellThemes(frameCtx);
|
|
@@ -261,6 +288,11 @@ export function createFramedApp(options) {
|
|
|
261
288
|
}
|
|
262
289
|
options.onShellThemeChange?.({
|
|
263
290
|
shellTheme: nextTheme.shellTheme,
|
|
291
|
+
shellThemeSpec: nextTheme.shellThemeSpec,
|
|
292
|
+
shellThemeId: nextTheme.shellThemeId,
|
|
293
|
+
shellThemeLabel: nextTheme.shellThemeLabel,
|
|
294
|
+
modeId: nextTheme.modeId,
|
|
295
|
+
modeLabel: nextTheme.modeLabel,
|
|
264
296
|
ctx: frameCtx,
|
|
265
297
|
});
|
|
266
298
|
return frameCtx;
|
|
@@ -270,6 +302,13 @@ export function createFramedApp(options) {
|
|
|
270
302
|
enableNotifications: options.notificationCenter != null || options.runtimeNotifications !== false,
|
|
271
303
|
i18n: options.i18n,
|
|
272
304
|
});
|
|
305
|
+
const frameInputRecognizer = createInputGestureRecognizer({
|
|
306
|
+
doubleTapMs: FRAME_FOOTER_DOUBLE_TAB_MS,
|
|
307
|
+
});
|
|
308
|
+
const frameInputActions = createInputActionMap()
|
|
309
|
+
.bind('frame.footer.doubleTab', 'Toggle footer', [
|
|
310
|
+
{ deviceId: 'keyboard', featureId: 'key.tab', type: 'double-tap' },
|
|
311
|
+
], { type: 'toggle-footer' });
|
|
273
312
|
const quitHelpKeys = createQuitHelpKeys(options.i18n);
|
|
274
313
|
const helpLayerHelpKeys = createHelpLayerHelpKeys(options.i18n);
|
|
275
314
|
const settingsHelpKeys = createSettingsHelpKeys(options.i18n);
|
|
@@ -553,6 +592,23 @@ export function createFramedApp(options) {
|
|
|
553
592
|
}
|
|
554
593
|
return [{ type: 'observed-key', msg, route }, { type: 'open-quit-confirm' }];
|
|
555
594
|
}
|
|
595
|
+
function resolveFrameInputActionCommands(msg, route) {
|
|
596
|
+
const inputEvent = frameInputRecognizer.observeKey(msg, resolveClock(resolveFrameCtx()).now());
|
|
597
|
+
const inputAction = frameInputActions.handle(inputEvent);
|
|
598
|
+
if (inputAction == null || msg.ctrl || msg.alt || msg.shift) {
|
|
599
|
+
return undefined;
|
|
600
|
+
}
|
|
601
|
+
return [{ type: 'observed-key', msg, route }, { type: 'apply-frame-action', action: inputAction }];
|
|
602
|
+
}
|
|
603
|
+
function routeForFrameInputAction(layerKind) {
|
|
604
|
+
if (layerKind === 'search' || layerKind === 'command-palette')
|
|
605
|
+
return 'palette';
|
|
606
|
+
if (layerKind === 'help')
|
|
607
|
+
return 'help';
|
|
608
|
+
if (layerKind === 'page-modal')
|
|
609
|
+
return 'page';
|
|
610
|
+
return 'frame';
|
|
611
|
+
}
|
|
556
612
|
function resolveFrameActionCommands(msg, action, route) {
|
|
557
613
|
if (action.type === 'open-search' && options.enableCommandPalette) {
|
|
558
614
|
return [{ type: 'observed-key', msg, route }, { type: 'open-search-palette' }];
|
|
@@ -584,6 +640,9 @@ export function createFramedApp(options) {
|
|
|
584
640
|
if (frameAction?.type === 'toggle-notifications') {
|
|
585
641
|
return [obs, { type: 'close-palette' }, { type: 'apply-frame-action', action: frameAction }];
|
|
586
642
|
}
|
|
643
|
+
if (frameAction?.type === 'toggle-perf-hud') {
|
|
644
|
+
return [obs, { type: 'apply-frame-action', action: frameAction }];
|
|
645
|
+
}
|
|
587
646
|
return [obs, { type: 'palette-key', msg }];
|
|
588
647
|
}
|
|
589
648
|
function handleHelpLayerKeyCommands(msg) {
|
|
@@ -595,6 +654,9 @@ export function createFramedApp(options) {
|
|
|
595
654
|
return quitRequestCommands(msg, 'help');
|
|
596
655
|
}
|
|
597
656
|
const helpAction = frameKeys.handle(msg);
|
|
657
|
+
if (helpAction?.type === 'toggle-perf-hud') {
|
|
658
|
+
return [obs, { type: 'apply-frame-action', action: helpAction }];
|
|
659
|
+
}
|
|
598
660
|
if (helpAction && isHelpScrollAction(helpAction)) {
|
|
599
661
|
const action = helpAction.type === 'scroll-down' ? 'down'
|
|
600
662
|
: helpAction.type === 'scroll-up' ? 'up'
|
|
@@ -633,6 +695,9 @@ export function createFramedApp(options) {
|
|
|
633
695
|
if (settingsFrameAction?.type === 'toggle-notifications') {
|
|
634
696
|
return [obs, { type: 'apply-frame-action', action: settingsFrameAction }];
|
|
635
697
|
}
|
|
698
|
+
if (settingsFrameAction?.type === 'toggle-perf-hud') {
|
|
699
|
+
return [obs, { type: 'apply-frame-action', action: settingsFrameAction }];
|
|
700
|
+
}
|
|
636
701
|
if (!msg.ctrl && !msg.alt && msg.key === 'up') {
|
|
637
702
|
return [obs, { type: 'settings-focus-move', delta: -1 }];
|
|
638
703
|
}
|
|
@@ -685,6 +750,9 @@ export function createFramedApp(options) {
|
|
|
685
750
|
if (centerFrameAction?.type === 'toggle-notifications') {
|
|
686
751
|
return [obs, { type: 'apply-frame-action', action: centerFrameAction }];
|
|
687
752
|
}
|
|
753
|
+
if (centerFrameAction?.type === 'toggle-perf-hud') {
|
|
754
|
+
return [obs, { type: 'apply-frame-action', action: centerFrameAction }];
|
|
755
|
+
}
|
|
688
756
|
if (!msg.ctrl && !msg.alt && msg.key === 'f2') {
|
|
689
757
|
return [obs, { type: 'close-notification-center' }, { type: 'apply-frame-action', action: { type: 'toggle-settings' } }];
|
|
690
758
|
}
|
|
@@ -772,6 +840,10 @@ export function createFramedApp(options) {
|
|
|
772
840
|
const frameLayer = layer.model;
|
|
773
841
|
if (frameLayer == null)
|
|
774
842
|
return undefined;
|
|
843
|
+
const inputActionCommands = resolveFrameInputActionCommands(msg, routeForFrameInputAction(frameLayer.kind));
|
|
844
|
+
if (inputActionCommands != null) {
|
|
845
|
+
return { handled: true, commands: inputActionCommands };
|
|
846
|
+
}
|
|
775
847
|
if (frameLayer.kind === 'search' || frameLayer.kind === 'command-palette') {
|
|
776
848
|
return { handled: true, commands: handlePaletteLayerKeyCommands(msg, frameLayer.kind) };
|
|
777
849
|
}
|
|
@@ -788,6 +860,10 @@ export function createFramedApp(options) {
|
|
|
788
860
|
}
|
|
789
861
|
if (frameLayer.kind === 'quit-confirm') {
|
|
790
862
|
const obs = { type: 'observed-key', msg, route: 'frame' };
|
|
863
|
+
const frameAction = frameKeys.handle(msg);
|
|
864
|
+
if (frameAction?.type === 'toggle-perf-hud') {
|
|
865
|
+
return { handled: true, commands: [obs, { type: 'apply-frame-action', action: frameAction }] };
|
|
866
|
+
}
|
|
791
867
|
if (isShellQuitConfirmAccept(msg)) {
|
|
792
868
|
return { handled: true, commands: [obs, { type: 'close-quit-confirm' }, { type: 'quit' }] };
|
|
793
869
|
}
|
|
@@ -799,6 +875,10 @@ export function createFramedApp(options) {
|
|
|
799
875
|
if (frameLayer.kind === 'page-modal') {
|
|
800
876
|
const { modalKeyMap } = context;
|
|
801
877
|
const obs = { type: 'observed-key', msg, route: 'page' };
|
|
878
|
+
const frameAction = frameKeys.handle(msg);
|
|
879
|
+
if (frameAction?.type === 'toggle-perf-hud') {
|
|
880
|
+
return { handled: true, commands: [obs, { type: 'apply-frame-action', action: frameAction }] };
|
|
881
|
+
}
|
|
802
882
|
if (modalKeyMap != null) {
|
|
803
883
|
const modalAction = modalKeyMap.handle(msg);
|
|
804
884
|
if (modalAction !== undefined) {
|
|
@@ -1101,21 +1181,22 @@ export function createFramedApp(options) {
|
|
|
1101
1181
|
const quitHint = frameMessage(options.i18n, 'quit.footer', 'Y quit • N stay');
|
|
1102
1182
|
const paletteTitle = model.commandPaletteTitle
|
|
1103
1183
|
?? frameMessage(options.i18n, 'palette.title', 'Command Palette');
|
|
1184
|
+
const activePageTitle = resolveFramePageText(activePage.title, activePageModel) ?? '';
|
|
1104
1185
|
const searchTitle = model.commandPaletteTitle
|
|
1105
|
-
?? activePage.searchTitle
|
|
1186
|
+
?? resolveFramePageText(activePage.searchTitle, activePageModel)
|
|
1106
1187
|
?? frameMessage(options.i18n, 'search.title', 'Search');
|
|
1107
1188
|
const notificationsTitle = notificationCenter == null
|
|
1108
1189
|
? frameMessage(options.i18n, 'notifications.title', 'Notifications')
|
|
1109
1190
|
: `${notificationCenter.title} • ${frameNotificationFilterLabel(options.i18n, notificationCenter.activeFilter)}`;
|
|
1110
1191
|
const pageLayers = activePage.layers?.(activePageModel);
|
|
1111
1192
|
const workspaceLayer = {
|
|
1112
|
-
title:
|
|
1193
|
+
title: activePageTitle,
|
|
1113
1194
|
hintSource: workspaceHintSource,
|
|
1114
1195
|
helpSource: workspaceHelpSource,
|
|
1115
1196
|
...pageLayers?.workspace,
|
|
1116
1197
|
};
|
|
1117
1198
|
const pageModalLayer = {
|
|
1118
|
-
title:
|
|
1199
|
+
title: activePageTitle,
|
|
1119
1200
|
hintSource: modalKeyMap ?? activePage.helpSource ?? activePage.keyMap,
|
|
1120
1201
|
helpSource: mergeBindingSources(quitHelpKeys, modalKeyMap, activePage.helpSource ?? activePage.keyMap),
|
|
1121
1202
|
...pageLayers?.['page-modal'],
|
|
@@ -1270,7 +1351,11 @@ export function createFramedApp(options) {
|
|
|
1270
1351
|
diffTimeMs: 0,
|
|
1271
1352
|
frameBudgetMs: undefined,
|
|
1272
1353
|
frameOverBudget: false,
|
|
1354
|
+
perfHudOpen: false,
|
|
1273
1355
|
helpOpen: false,
|
|
1356
|
+
footerVisible: true,
|
|
1357
|
+
footerTranslateY: 0,
|
|
1358
|
+
footerAnimationGeneration: 0,
|
|
1274
1359
|
helpScrollY: 0,
|
|
1275
1360
|
commandPaletteKind: undefined,
|
|
1276
1361
|
settingsOpen: false,
|
|
@@ -1446,7 +1531,12 @@ export function createFramedApp(options) {
|
|
|
1446
1531
|
frameSurface.clear();
|
|
1447
1532
|
frameSurface.blit(header, 0, 0);
|
|
1448
1533
|
if (model.rows > 1) {
|
|
1449
|
-
|
|
1534
|
+
const footerVisible = model.footerVisible ?? true;
|
|
1535
|
+
const footerTranslateY = Math.max(0, Math.min(1, model.footerTranslateY ?? (footerVisible ? 0 : 1)));
|
|
1536
|
+
const footerRow = model.rows - helpLine.height + Math.floor(footerTranslateY * helpLine.height);
|
|
1537
|
+
if (footerRow < model.rows) {
|
|
1538
|
+
frameSurface.blit(helpLine, 0, footerRow);
|
|
1539
|
+
}
|
|
1450
1540
|
}
|
|
1451
1541
|
let activeResult;
|
|
1452
1542
|
let bodySurface;
|
|
@@ -1551,10 +1641,24 @@ export function createFramedApp(options) {
|
|
|
1551
1641
|
if (model.quitConfirmOpen) {
|
|
1552
1642
|
overlays.push(renderShellQuitOverlay(model.columns, model.rows, options.i18n, themedFrameCtx));
|
|
1553
1643
|
}
|
|
1644
|
+
const dimBackground = overlays.length > 0;
|
|
1645
|
+
if (model.perfHudOpen) {
|
|
1646
|
+
overlays.push(renderFramePerfHudOverlay({
|
|
1647
|
+
columns: model.columns,
|
|
1648
|
+
rows: model.rows,
|
|
1649
|
+
frameTimeMs: model.frameTimeMs,
|
|
1650
|
+
viewTimeMs: model.viewTimeMs,
|
|
1651
|
+
diffTimeMs: model.diffTimeMs,
|
|
1652
|
+
refreshRate: themedFrameCtx?.runtime.refreshRate,
|
|
1653
|
+
}, {
|
|
1654
|
+
i18n: options.i18n,
|
|
1655
|
+
ctx: themedFrameCtx,
|
|
1656
|
+
}));
|
|
1657
|
+
}
|
|
1554
1658
|
if (bodySurface != null && bodyRect.width > 0 && bodyRect.height > 0) {
|
|
1555
1659
|
frameSurface.blit(bodySurface, bodyRect.col, bodyRect.row);
|
|
1556
1660
|
}
|
|
1557
|
-
return compositeSurfaceInto(frameSurface, frameSurface, overlays, { dim:
|
|
1661
|
+
return compositeSurfaceInto(frameSurface, frameSurface, overlays, { dim: dimBackground });
|
|
1558
1662
|
},
|
|
1559
1663
|
routeRuntimeIssue(issue) {
|
|
1560
1664
|
if (!frameNotificationOptions.enabled)
|