Optional ReadonlylayerGeoLeaf layer id the feature belongs to.
Optional ReadonlyfeatureRaw feature property bag (for cross-field lookups).
Optional ReadonlyfeatureFeature identifier, carried for type: "action" buttons.
⚠️ This field and the next were missing for the whole life of the action
type, and that is exactly what made the feature get abandoned: the click detail
carries them (GeoLeafFeatureClickDetail), but the render context stopped at
layerId — so the renderer could not build the payload the contract promised.
⚠️ And the first fix repaired only HALF, which was only seen on
14/08/2026: surfaces/popup.ts passed all three fields,
surfaces/sidepanel.ts stuck to layerId. The action widget living in the
shared dispatch table, it renders on both surfaces — an action clicked in the
panel therefore emitted featureId: null for sixteen days, under a comment
saying the opposite. An asymmetric repair reads as a repair.
Optional ReadonlylngGeographic position of the popup, for the action payload.
Optional ReadonlyonCloses the surface this context belongs to — supplied by surfaces/popup.ts
(closePopup) and surfaces/sidepanel.ts (closeSidePanel).
⚠️ First non-data field of this interface, and it is injected rather than imported for a
structural reason. The graph runs surfaces/popup.ts → render/popup-content.ts → render/widget-dispatch.ts (and symmetrically for the side panel); a renderer importing a
surface back would close a cycle. Injection is also the only way to close the RIGHT
surface — the action widget is in the shared dispatch table and renders on both.
Optional because most render paths have no surface to close (tooltip, tests, direct
renderFieldNode calls). Absent, close() on the event detail is a no-op.
Per-surface context threaded from a surface handler down to the field renderers.
layerId+featurelet taxonomy-aware renderers resolve a value against the whole feature (e.g. a category label).