From 30234875fe63304d13150a2c1bb77792a7673450 Mon Sep 17 00:00:00 2001 From: Dustin Swan Date: Mon, 9 Feb 2026 21:28:46 -0700 Subject: [PATCH] adding autoFocus to stateful components. getting global keys working --- src/cg/03-ui-components.cg | 3 ++- src/runtime-compiled.ts | 23 ++++++++++++++++++----- src/valueToUI-compiled.ts | 1 + 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/cg/03-ui-components.cg b/src/cg/03-ui-components.cg index 20b4e0c..ac83441 100644 --- a/src/cg/03-ui-components.cg +++ b/src/cg/03-ui-components.cg @@ -84,6 +84,7 @@ findCursorPos = text clickX scrollOffset inputPadding \ textInput = config \ ui.stateful { key = config.key, focusable = True, + autoFocus = config.initialFocus, # init : State init = { @@ -95,7 +96,7 @@ textInput = config \ ui.stateful { # update : State \ Event \ State update = state event \ event - | Key { key = c, printable = True } \ + | Key { key = c, printable = True, meta = False, ctrl = False } \ newText = insertChar state.text state.cursorPos c; newCursorPos = state.cursorPos + 1; newScroll = calcScrollOffset newText newCursorPos state.scrollOffset config.w; diff --git a/src/runtime-compiled.ts b/src/runtime-compiled.ts index 92803eb..0e3f777 100644 --- a/src/runtime-compiled.ts +++ b/src/runtime-compiled.ts @@ -67,11 +67,14 @@ export function runAppCompiled(app: App, canvas: HTMLCanvasElement, rt: any) { } } - function expandStateful(ui: UIValue, path: number[]): UIValue { + function expandStateful(ui: UIValue, path: number[], renderedKeys: Set): UIValue { switch (ui.kind) { case 'stateful': { const fullKey = [...path, ui.key].join('.'); + renderedKeys.add(fullKey); + let instance = componentInstances.get(fullKey); + const isNew = !instance; if (!instance) { instance = { @@ -86,6 +89,10 @@ export function runAppCompiled(app: App, canvas: HTMLCanvasElement, rt: any) { instance.view = ui.view; } + if (ui.autoFocus && isNew) { + setFocus(fullKey); + } + const viewResult = instance.view(instance.state); let viewUI = valueToUI(viewResult); @@ -96,7 +103,7 @@ export function runAppCompiled(app: App, canvas: HTMLCanvasElement, rt: any) { event: { _tag: 'FocusAndClick', _0: fullKey } }; } - return expandStateful(viewUI, path); + return expandStateful(viewUI, path, renderedKeys); } case 'stack': @@ -105,7 +112,7 @@ export function runAppCompiled(app: App, canvas: HTMLCanvasElement, rt: any) { return { ...ui, children: ui.children.map((child: UIValue, i: number) => - expandStateful(child, [...path, i]) + expandStateful(child, [...path, i], renderedKeys) ) } } @@ -117,7 +124,7 @@ export function runAppCompiled(app: App, canvas: HTMLCanvasElement, rt: any) { case 'clip': { return { ...ui, - child: expandStateful((ui as any).child, [...path, 0]) + child: expandStateful((ui as any).child, [...path, 0], renderedKeys) }; } @@ -130,11 +137,17 @@ export function runAppCompiled(app: App, canvas: HTMLCanvasElement, rt: any) { function rerender() { const viewport = { width: window.innerWidth, height: window.innerHeight }; + const renderedKeys = new Set(); try { const uiValue = app.view(state)(viewport); const ui = valueToUI(uiValue); - const expandedUI = expandStateful(ui, []); + const expandedUI = expandStateful(ui, [], renderedKeys); + + if (focusedComponentKey && !renderedKeys.has(focusedComponentKey)) { + focusedComponentKey = null; + } + render(expandedUI, canvas); } catch (error) { console.error('Render error:', error); diff --git a/src/valueToUI-compiled.ts b/src/valueToUI-compiled.ts index a7965a3..b69940b 100644 --- a/src/valueToUI-compiled.ts +++ b/src/valueToUI-compiled.ts @@ -85,6 +85,7 @@ export function valueToUI(value: any): any { kind: 'stateful', key: value.key, focusable: value.focusable, + autoFocus: value.autoFocus, init: value.init, update: value.update, view: value.view,