GeoLeaf Core API - v3.0.0
    Preparing search index...

    Map of the GeoLeaf DOM events that carry a live HTMLElement and are therefore dispatched as raw CustomEvents, never through dispatchGeoLeafEvent.

    dispatchGeoLeafEvent sanitises through JSON.parse(JSON.stringify(detail)). Put geoleaf:toolbar:action in the sanitised map and dispatchGeoLeafEvent("geoleaf:toolbar:action", { action, element }) becomes type-legal and runtime-wrong: element arrives at every listener as {}. The type system would be actively inviting the bug that two files in this repo already go out of their way to warn about — kernel/ui/desktop/desktop-tabs-seam.ts:17-19 and kernel/layer-manager/item-controls-seam.ts:19 both describe themselves as mirroring the existing geoleaf:toolbar:action seam for precisely this reason.

    Splitting the map keeps both halves honest: listening is typed for everyone (the Events facade accepts keys of both maps), and emission stays impossible to get wrong.

    ⚠ Adding a key here is a statement that the payload cannot be JSON-cloned. If it can, it belongs in GeoLeafEventMap, where it also gets a typed emitter.

    GeoLeafEventMap — the sanitised bus.

    interface GeoLeafRawEventMap {
        "geoleaf:layer-manager:panel": {
            container: HTMLElement;
            mainWrapper: HTMLElement;
            headerWrapper: HTMLElement;
        };
        "geoleaf:toolbar:action": { action: string; element: HTMLElement };
    }
    Index

    Properties

    "geoleaf:layer-manager:panel": {
        container: HTMLElement;
        mainWrapper: HTMLElement;
        headerWrapper: HTMLElement;
    }

    The layer-manager panel seam. Emitted by kernel/layer-manager/control.ts once the panel structure is built, so capabilities (e.g. profile-switcher) can insert their own controls without the kernel importing them.

    Lives HERE, not in GeoLeafEventMap: the detail carries live DOM nodes, which the sanitising bus (JSON-only) would destroy.

    ⚠️ Fires again on every panel rebuild (destroy → recreate): subscribers must be idempotent.

    "geoleaf:toolbar:action": { action: string; element: HTMLElement }

    The plugin ↔ toolbar seam. Emitted by kernel/ui/toolbar-dispatch.ts:20-27 (mobile pill, desktop tab strip).

    ⚠️ This seam is one-way, and the direction matters. Plugins and capabilities LISTEN; they do not dispatch. The kernel-side helper dispatchToolbarAction(action, element) is the entry point for the kernel's own emitters — it is deliberately NOT exported: absent from kernel/ui/index.ts, from kernel-exports.ts, from the global namespace, and from every published exports subpath. Reaching it from capabilities/** is refused by the R.8 boundary (eslint.config.mjs), and widening the barrel to reach it would drag components.js + pill-search.js + theme.js into the importer's bundle closure. That trade was measured, then declined, and the decision is written up as D-18 in _docs_projet/registres/dette_technique.md — do not re-litigate it from this line.

    ⚠️ This comment called that helper "the canonical entry point" until 09/08/2026, with no qualifier. The sentence was true for the kernel and false for every other reader of this contract — who cannot reach it at all. A contract that names an entry point its audience cannot call sends that audience looking for an export that was withheld on purpose.

    element is the button that was clicked — plugins read it to anchor a floating menu (editor, measure, geocoding all do). Both fields are always set by the emitter, so neither is optional here even though several listeners historically declared them so.