OptionalVERSIONOrchestrator version tag, set by ui-api.ts.
OptionalBUILDBuild tag, set by ui-api.ts.
OptionalinitBoots the UI kernel (delegation, theme, containers).
OptionalcleanupTears listeners down and resets the delegation flag.
OptionalgetAvailability report for the UI sub-modules.
OptionalapplyApplies a theme by name.
Sets the theme classes on <body> and #geoleaf-map, then dispatches
geoleaf:ui-theme-changed. ⚠️ Always prefer this over touching the CSS classes
directly — a manual classList.add("gl-theme-dark") skips the event, so anything
listening for the change never learns of it.
OptionalsetAlias of GeoLeafUIFacade.applyTheme — the SAME reference, by design.
OptionalgetThe theme currently applied.
OptionalinitApplies the theme declared in the profile configuration. Called during boot.
OptionalinitWires a theme-toggle button, located by the configured buttonSelector.
OptionaltoggleSwitches to the other theme and applies it.
OptionalNotificationsThe notification renderer, reachable through the UI façade.
⚠️ Typed Record<string, unknown>, so nothing here is arity-checked — the real
surface is the one documented on NotificationSystem. The unknown-typed
remainder only ever shrinks — never widened back.
OptionalshowShows a toast of an explicit type. Bound form of Notifications.show.
OptionalshowShows a success toast. Bound form of Notifications.success.
OptionalshowShows an error toast. Bound form of Notifications.error.
OptionalshowShows a warning toast. Bound form of Notifications.warning.
OptionalshowShows an informational toast. Bound form of Notifications.info.
OptionalclearDismisses every visible toast and empties the queue.
OptionalnotifyRich toast surface — the KERNEL one, mounted by globals/globals.ui.ts.
Distinct from GeoLeafUIFacade.Notifications: notify is the anchor-B2
adapter that reads the renderer back lazily, so a build without the
toast-renderer capability degrades to a silent no-op instead of throwing.
⚠️ Optional chaining is not cosmetic here: without a writer the member is
absent, and GeoLeaf.UI.notify.success(…) throws. It is also what avoids
adding a baseline entry to typecheck-docs-examples.
OptionalinitMounts the mobile toolbar. Set by setupUIKernel() in globals/globals.ui.ts.
Initializes the mobile utility pill toolbar and sheet modal.
Must be called after the map and .gl-main DOM are ready. Safe to call again: a
toolbar already mounted in the same glMain is left alone, and one left over from a
previous shell is torn down first.
⚠️ On the no-op branch options is NOT refreshed — a new map handle or new show*
flags passed to a redundant call are ignored. initDesktopPanel behaves the same way.
Pass through destroyMobileToolbar() to change them.
Host element, map handles and which controls to show.
OptionaldestroyTears the mobile toolbar down. Set by setupUIKernel().
Tears the mobile toolbar down: removes the four nodes it appended to glMain,
disconnects its observer and drops its listeners.
Registered as a lifecycle teardown, so Core.destroy() runs it. Also called by
initMobileToolbar() when it finds a toolbar left over from a previous shell.
⚠️ Call it BEFORE the shell is destroyed, not after. The sheet moves shared nodes
(filter panel, legend, layer manager) into its body; this function gives them back,
but it can only give them back to a parent that still exists. A host that drops
.gl-main first has already lost them.
⚠️ Proximity mode is NOT cancelled. Clearing it would mean calling back into the filter capability — a business effect on a teardown path — so the engine keeps whatever filter was applied while the pill's own flag resets. A host that tears down mid-proximity should cancel it itself first.
OptionalinitMounts the desktop side-panel. Set by setupUIKernel().
Builds the side panel DOM (>= 1440px). Does NOT move any element in — call activateDesktopPanel() afterwards.
OptionalactivateReveals the desktop side-panel. Set by setupUIKernel().
Moves the filter panel, the layer manager and the legend into their tabs of the side panel.
Any of the three built after this call is adopted as soon as it appears, so the call need not
follow Legend.init() or LayerManager.init(). A no-op before initDesktopPanel() and below
the desktop breakpoint, whose crossing activates the panel on its own.
OptionaldestroyTears the desktop side-panel down. Set by setupUIKernel().
Destroys the side panel and restores the elements to their original place.
OptionalopenOpens a side-panel tab by id, without toggling — calling it twice with the same id leaves the panel open.
⚠️ This is what separates it from a click on the tab, which closes an already-open
tab. Set by setupUIKernel().
Opens a side-panel tab by id, without toggling.
Calling it twice with the same id leaves the panel open — that is exactly what separates it from a click on the tab, which closes an already-open tab. Use it to drive the panel from host code (a menu entry, a deep link, a workflow step).
Tab to open: "filters", "layers" or "legend", depending on what the
profile enabled at initDesktopPanel().
true if the tab exists and is now open, false if the panel is not built, the
desktop breakpoint is not active, or no such tab was declared.
OptionalcloseCloses whichever side-panel tab is open. A no-op when none is.
Closes whichever side-panel tab is open. A no-op when none is.
OptionalgetThe id of the open side-panel tab, or null when closed or not built.
The id of the currently open tab, or null when the panel is closed or not built.
⚠️ The open state has no dedicated variable: it lives in the DOM, as the gl-is-active
class on the tab button. This reads it back rather than shadowing it, so the value cannot
drift from what the user sees.
OptionalregisterOffers a panel surface to whichever host is live — the desktop side panel above 1440px, the mobile sheet below it.
The host ADOPTS the element named by selector: it moves the node, and puts it
back where it came from on close. Register before or after boot; a registration
arriving late is synced into an already-built panel.
OptionalopenOpens a registered pane on whichever host is live.
⚠️ Prefer this to GeoLeafUIFacade.openPanel from a plugin: openPanel
drives the DESKTOP panel and answers false below its breakpoint, where the same
content belongs in the mobile sheet. A caller reacting to a click on a feature
cannot be asked to know which surface the current width implies.
Opens a registered pane on whichever host is live.
This is the entry point a plugin calls: it does not know, and must not have to know, whether the current width puts its content in the desktop panel or in the mobile sheet.
The pane to show.
true when a host displayed it, false when none could.
OptionalcloseCloses the pane on every live host.
Closes the pane on every live host.
OptionalsetTurns the immersive UI mode on or off — strips the chrome the kernel owns, and optionally asks for browser fullscreen.
Turns the immersive UI mode on or off.
The mode strips the chrome the kernel owns — theme bars, filter entry point, right panel, proximity bar — so a caller that needs the whole surface for one task can have it without knowing which controls exist.
Whether the document should be immersive.
fullscreen also asks the browser for fullscreen — best-effort, a refusal
never propagates, because a caller that entered immersive mode has still
entered it. See the note on ownership: an exitFullscreen only happens when
this module was the one that entered.
⚠️ The shape is inlined rather than a named exported interface: nothing outside needed to name it, and an exported type nobody imports is indistinguishable from one left behind after a deletion.
OptionalisWhether the document is currently in immersive mode.
Whether the document is currently in immersive mode.
Read back from the DOM rather than from a variable: the class IS the state, so the answer cannot drift from what the user sees.
true while the immersive class is set.
OptionalCacheOffline cache button — mounted by the offline-ui PLUGIN
(ui/cache-button.ts), read by app/boot-modules/ui.module.ts.
⚠️ Typed STRUCTURALLY on purpose. The no-plugin-in-core rule
(scripts/verify-core-standalone.cjs) forbids the core to name
@geoleaf-plugins/*: a typeof import(...) is unavailable here, and that is
not a shortcut but the architecture boundary. The member stays optional — a
build without the plugin has no writer.
GeoLeaf.UI— the kernel UI façade.Why a hand-written interface, and not a
typeof import(...)kernel/ui/ui-api.tsdoesconst UI = _g.GeoLeaf.UI;then re-exports it: the exported value IS the namespace member. Atypeof import("./api/geoleaf.ui.js").UIis therefore structurally circular — measured,tscemitsTS7022thenTS2303. Most probably the reason this member used to be declaredRecord<string, unknown>: the easy form does not compile.That is no reason to type nothing. The facade is mounted by mutation from ~10 modules; the 24 members below were read off the real assignment sites, and the named interface breaks the cycle by depending on no value.
The
[key: string]: unknowntail is REMOVED (09/08/2026)⚠️ The motive that justified it here was false. It said "
boot-core.tsandinit-features.tsstill set members outside this list". Measured: those two files set no member onGeoLeaf.UI— their onlyui.occurrences are config reads (init-features.ts). The 6 genuinely missing members came fromglobals/globals.ui.tsand theoffline-uiplugin; they are declared below, read off their assignment sites.What the tail cost. It made any invented member
unknown— hence indistinguishable from a real untyped one.GeoLeaf.UI.toggleFilterPanel(true)was taught by the@exampleofapi/geoleaf.ui.tsalthough that identifier never existed in the repo, and the three documentation gates came out green on it. Measured on 31/07/2026 (mutationGeoLeaf.UI.cetteApiNExistePas("dark")→ GREEN), with the conclusion: the benefit of compiling the examples grows with the namespace's typing, and not otherwise. Tail removed, a phantom member yields TS2339, whichtypecheck-docs-examples.cjsknows.No assignment site breaks:
globals.ui.tswrites through_gl.UI as Record<string, unknown>,cache-button.tsthrough its own cast, andui.module.tsreads through the dynamic helpermember(obj: unknown, …).