feat(proBoardRegistry): attachBuiltins — overlay-owned built-in peripheral wiring

Boards with built-in hardware (LCD on the element's own canvas, speaker,
on-board buttons/keyboard) need run-time wiring between the DOM element and
the board's simulator shim / ESP32 bridge. One generic SimulatorCanvas effect
now hands those handles to the overlay's attachBuiltins shortly after run
start and runs its cleanup on stop — no board names in the OSS tree.
This commit is contained in:
David Montero Crespo 2026-07-22 22:33:46 +02:00
parent d90e738995
commit 78f5f5ebc3
2 changed files with 43 additions and 1 deletions

View File

@ -1,4 +1,5 @@
import { useSimulatorStore, getEsp32Bridge } from '../../store/useSimulatorStore';
import { useSimulatorStore, getEsp32Bridge, getBoardSimulator } from '../../store/useSimulatorStore';
import { getProBoard } from '../../lib/proBoardRegistry';
import { useElectricalStore } from '../../store/useElectricalStore';
import { openDeviceGateway } from '../../lib/openDeviceGateway';
import React, { useEffect, useState, useRef, useCallback } from 'react';
@ -206,6 +207,36 @@ export const SimulatorCanvas = ({ headerSlot }: SimulatorCanvasProps = {}) => {
}
}, [registry, registryLoaded]);
// Overlay-registered boards: built-in peripheral attachment (LCD decoder on
// the board's own canvas, speaker, on-board button/keyboard forwarding). The
// overlay owns the wiring via ProBoardDef.attachBuiltins; we hand it the DOM
// element + the board's simulator/bridge handles shortly after run start
// (the element and bridge need a beat to exist) and dispose on stop/unmount.
useEffect(() => {
const cleanups: (() => void)[] = [];
boards.forEach((board) => {
const proDef = getProBoard(board.boardKind);
if (!proDef?.attachBuiltins || !board.running) return;
const timeout = setTimeout(() => {
const el = document.getElementById(board.id);
if (!el) return;
try {
cleanups.push(
proDef.attachBuiltins!({
el,
sim: getBoardSimulator(board.id),
bridge: getEsp32Bridge(board.id),
}),
);
} catch (e) {
console.warn(`[${board.boardKind}] built-in peripheral attach failed:`, e);
}
}, 500);
cleanups.push(() => clearTimeout(timeout));
});
return () => cleanups.forEach((fn) => fn());
}, [boards]);
// Component selection
const [selectedComponentId, setSelectedComponentId] = useState<string | null>(null);

View File

@ -78,6 +78,17 @@ export interface ProBoardDef {
/** Built-in microSD on a shared SPI bus: the CS pin the bridge must gate.
* (A standalone SD card component still overrides this to un-gated.) */
builtInSdCsPin?: number;
/** Built-in peripheral attachment for a RUNNING board (LCD decoder onto the
* element's own canvas, speaker, on-board button/keyboard event forwarding).
* Called shortly after run start with the board's DOM element plus its
* simulator shim and ESP32 bridge (either may be null depending on the run
* path); must return a cleanup that detaches everything. */
attachBuiltins?: (ctx: {
el: HTMLElement;
sim: unknown;
bridge: unknown;
}) => () => void;
/** Sidebar / toolbar accents (fall back to a neutral chip icon). */
icon?: string;
color?: string;