@ngis/plugin-sdk 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +13 -0
- package/README.md +31 -0
- package/dist/index.cjs +76 -0
- package/dist/index.d.ts +77 -0
- package/dist/index.mjs +102 -0
- package/dist/src/api/analysis.d.ts +140 -0
- package/dist/src/api/resources.d.ts +530 -0
- package/dist/src/api/scenes.d.ts +251 -0
- package/dist/src/api/users.d.ts +22 -0
- package/dist/src/domain/algorithms/deck-layer-style.d.ts +34 -0
- package/dist/src/domain/algorithms/maplibre-style.d.ts +63 -0
- package/dist/src/domain/algorithms/raster-color-ramps.d.ts +37 -0
- package/dist/src/domain/algorithms/scene-layer-type.d.ts +25 -0
- package/dist/src/domain/algorithms/symbol-compile.d.ts +100 -0
- package/dist/src/domain/algorithms/symbol-params.d.ts +90 -0
- package/dist/src/domain/map/bounds.d.ts +8 -0
- package/dist/src/domain/map/constants.d.ts +40 -0
- package/dist/src/domain/map/layer-builders.d.ts +32 -0
- package/dist/src/domain/map/rendered-layers.d.ts +30 -0
- package/dist/src/domain/map/style-ready.d.ts +24 -0
- package/dist/src/domain/map/tile-url.d.ts +20 -0
- package/dist/src/domain/map/types.d.ts +128 -0
- package/dist/src/domain/models/deck-layer-style.d.ts +211 -0
- package/dist/src/domain/models/scene-layer-type.d.ts +23 -0
- package/dist/src/domain/models/symbol.d.ts +424 -0
- package/dist/src/lib/api.d.ts +82 -0
- package/dist/src/lib/auth-session.d.ts +22 -0
- package/dist/src/lib/raster-color-layer/RasterColorLayer.d.ts +48 -0
- package/dist/src/lib/raster-color-layer/TileGrid.d.ts +31 -0
- package/dist/src/lib/raster-color-layer/colorRamp.d.ts +18 -0
- package/dist/src/lib/raster-color-layer/shaders/raster-color.frag.d.ts +2 -0
- package/dist/src/lib/raster-color-layer/shaders/raster-color.vert.d.ts +2 -0
- package/dist/src/lib/raster-color-layer/zoomInterpolate.d.ts +2 -0
- package/dist/src/sdk/commands.d.ts +113 -0
- package/dist/src/sdk/context/keys.d.ts +148 -0
- package/dist/src/sdk/context/publishers.d.ts +198 -0
- package/dist/src/sdk/context/store.d.ts +78 -0
- package/dist/src/sdk/context/when.d.ts +69 -0
- package/dist/src/sdk/contributions/dispatch.d.ts +78 -0
- package/dist/src/sdk/contributions/panel-id.d.ts +25 -0
- package/dist/src/sdk/contributions/registry.d.ts +199 -0
- package/dist/src/sdk/contributions/symbol-renderers.d.ts +107 -0
- package/dist/src/sdk/contributions/types.d.ts +288 -0
- package/dist/src/sdk/contributions/views-bridge.d.ts +92 -0
- package/dist/src/sdk/define-plugin.d.ts +17 -0
- package/dist/src/sdk/facets/storage.d.ts +152 -0
- package/dist/src/sdk/facets/types.d.ts +370 -0
- package/dist/src/sdk/host-api.d.ts +256 -0
- package/dist/src/sdk/map-api.d.ts +288 -0
- package/dist/src/sdk/panels.d.ts +130 -0
- package/dist/src/sdk/plugin.d.ts +145 -0
- package/dist/src/sdk/rail-tools.d.ts +58 -0
- package/dist/src/sdk/scopes.d.ts +158 -0
- package/dist/src/systems/renderer/DeckSceneRenderer.d.ts +26 -0
- package/dist/src/systems/renderer/FlowFieldLayer.d.ts +68 -0
- package/dist/src/systems/renderer/LayerRendererRegistry.d.ts +132 -0
- package/dist/src/systems/renderer/authenticated-deck-load.d.ts +4 -0
- package/dist/src/systems/renderer/deck/deck-layer-builders.d.ts +29 -0
- package/dist/src/systems/renderer/deck/deck-layer-helpers.d.ts +21 -0
- package/dist/src/systems/renderer/deck/mvt-point-aggregation-layer.d.ts +107 -0
- package/dist/src/systems/renderer/flow-field/flow-field-resources.d.ts +84 -0
- package/dist/src/systems/renderer/flow-field/flow-field-shaders.d.ts +4 -0
- package/dist/src/systems/renderer/symbol/SpriteRegistry.d.ts +34 -0
- package/dist/src/systems/renderer/symbol/entries.d.ts +67 -0
- package/dist/src/types/analysis.d.ts +205 -0
- package/dist/src/types/common.d.ts +17 -0
- package/dist/src/types/extensions.d.ts +560 -0
- package/dist/src/types/gis.d.ts +242 -0
- package/dist/src/types/market-social.d.ts +378 -0
- package/package.json +47 -0
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `NgisMapAPI` — the typed facade a plugin programs against (L3 SDK contract).
|
|
3
|
+
*
|
|
4
|
+
* This is the "GeoLibre `GeoLibreAppAPI`" equivalent (see
|
|
5
|
+
* `../../GEOLIBRE_VS_NGIS.md` §3, one level up from the repo). It is a **binding
|
|
6
|
+
* layer, not a fourth subsystem**: every method delegates to something that
|
|
7
|
+
* already exists —
|
|
8
|
+
*
|
|
9
|
+
* - the scene controllers' imperative surface (draw / measure / camera),
|
|
10
|
+
* reached today through the composed `GisMapHandle` the shell exposes
|
|
11
|
+
* (which itself reads the *live* scene-map-context method registry
|
|
12
|
+
* `SceneMapHandleRegistry` — see `components/scenes/map/scene-map-context.ts`,
|
|
13
|
+
* C2/C4/C5 — so the facade never captures a stale controller instance);
|
|
14
|
+
* - the GIS scene store (`store/gis-scene.ts`) — the `layers` facet;
|
|
15
|
+
* - the `WorkspacePanelRegistry` (`sdk/panels.ts`, C7) — the `panels` facet;
|
|
16
|
+
* - workspace-owned highlight + view state — the `selection.highlight` and
|
|
17
|
+
* `camera` facets.
|
|
18
|
+
*
|
|
19
|
+
* The facade introduces **zero new direct `maplibregl.Map` access**. The one
|
|
20
|
+
* raw touch it exposes — `getMap()` — is a deliberately-unstable escape hatch
|
|
21
|
+
* that stays `null` until the host wires a raw-map getter into it (the one-line
|
|
22
|
+
* `SceneMapCanvas.tsx` provider hookup applied after C5 lands; see
|
|
23
|
+
* `docs/componentization_stage/session-C8-map-api-facade.md`).
|
|
24
|
+
*
|
|
25
|
+
* GeoLibre's proven decisions, adopted verbatim in shape:
|
|
26
|
+
* 1. **Every subscription returns an unsubscribe function** (`onX(cb) => () => void`).
|
|
27
|
+
* 2. **Newer / not-yet-proven methods are optional-typed** (`api.x?.()`) so
|
|
28
|
+
* plugin code written against v0 keeps compiling as the surface grows.
|
|
29
|
+
* As of 0.2.0 (session P3, plugin-runtime stage) every method is either
|
|
30
|
+
* **real and required** or was deleted; the lone remaining optional member
|
|
31
|
+
* is `draw.snapshot` (see its doc for the stated reason).
|
|
32
|
+
* 3. **A raw-MapLibre escape hatch** (`getMap()`), documented as unstable.
|
|
33
|
+
*
|
|
34
|
+
* Framework-agnostic on purpose: this module imports no React and only
|
|
35
|
+
* type-imports its domain types, so the pure binding/bookkeeping logic is
|
|
36
|
+
* unit-tested directly with `node:test` (`map-api.test.ts`).
|
|
37
|
+
*/
|
|
38
|
+
import type { Map as MapLibreMap } from "maplibre-gl";
|
|
39
|
+
import type { SceneLayerHighlight, SceneMapView } from "../domain/map/types";
|
|
40
|
+
import type { GisDrawMode, GisMeasureKind } from "../types/gis";
|
|
41
|
+
import type { WorkspacePanelRegistry } from "./panels";
|
|
42
|
+
/** Current facade contract version — bumped when the frozen surface changes.
|
|
43
|
+
* A plugin's `minNgisVersion` (`docs/frontend-map-sdk.md` §3) is
|
|
44
|
+
* checked against this. Pre-1.0: the surface may still grow (additively).
|
|
45
|
+
*
|
|
46
|
+
* 0.2.0 (plugin-runtime stage, P3): promoted `camera.flyTo`/`fitBounds`,
|
|
47
|
+
* `layers.onChange` and `draw.onDrawChange` to required; deleted the never-
|
|
48
|
+
* implemented `selection.get`/`clear`/`onChange` (+ the `"selectionchange"`
|
|
49
|
+
* event) per decision D10; bound `draw.snapshot` through the imperative
|
|
50
|
+
* handle (kept optional — see its doc). See `docs/frontend-map-sdk.md` §2.
|
|
51
|
+
*
|
|
52
|
+
* 0.3.0 (Stage 11 E7, design doc §19, ED19): added the `commands` capability
|
|
53
|
+
* (`src/sdk/commands.ts`) — a plugin-declared, externally-invocable seam the
|
|
54
|
+
* codeenv SDK bridge's plugin-invocation executor calls by id. Contract-safe
|
|
55
|
+
* in both directions (the runtime's unknown-capability refusal covers an old
|
|
56
|
+
* runtime seeing a `commands`-declaring plugin; `minNgisVersion` covers a new
|
|
57
|
+
* plugin requiring a runtime this old). The bump lands atomically with this
|
|
58
|
+
* capability's only consumer, per ED19 — never staged ahead of it.
|
|
59
|
+
*
|
|
60
|
+
* 0.4.0 (Stage 13, X4b; F13.13 + ED19): the **`NgisHostAPI` capability
|
|
61
|
+
* contract**. `NgisPluginHost` widens from `{ api }` to the full nine-facet
|
|
62
|
+
* facade (`src/sdk/host-api.ts`), the runtime's first-wins `register` gains an
|
|
63
|
+
* `unregister`/`replace` seam (F13.8), and `contributes` v1 + derived
|
|
64
|
+
* activation events land beside `capabilities`. **`host.api` — this whole
|
|
65
|
+
* module — is unchanged and stays ungated**, which is the back-compat rule: a
|
|
66
|
+
* 0.3-era plugin declares `minNgisVersion: "0.3.0"`, negotiates identically,
|
|
67
|
+
* and keeps working byte-for-byte.
|
|
68
|
+
*
|
|
69
|
+
* Bumped atomically with its consumers per ED19: `plugin.ts`'s alias,
|
|
70
|
+
* `plugin-runtime.ts`, `GisWorkspace.tsx`'s host construction and the loader
|
|
71
|
+
* path all land in the same commit. Note the reverse leg of F13.13 —
|
|
72
|
+
* a 0.4-requiring manifest on a 0.3 host is refused by the `minNgisVersion`
|
|
73
|
+
* semver compare, **not** by the unknown-capability check: `contributes` and
|
|
74
|
+
* `permissions` are top-level manifest siblings, and a 0.3 runtime inspects
|
|
75
|
+
* only `manifest.capabilities`. */
|
|
76
|
+
export declare const NGIS_MAP_API_VERSION = "0.4.0";
|
|
77
|
+
/** A scene layer as the SDK exposes it — a stable projection of the store's
|
|
78
|
+
* `NgisSceneLayer`, so plugins never depend on the store's internal shape. */
|
|
79
|
+
export interface NgisLayerSummary {
|
|
80
|
+
id: string;
|
|
81
|
+
name: string;
|
|
82
|
+
/** Scene layer type id (e.g. `"MAPLIBRE_FILL"`); `null` when unset. */
|
|
83
|
+
type: string | null;
|
|
84
|
+
visible: boolean;
|
|
85
|
+
}
|
|
86
|
+
/** Camera state — identical shape to the scene's persisted `SceneMapView`. */
|
|
87
|
+
export type NgisMapView = SceneMapView;
|
|
88
|
+
/** Geographic bounds `[west, south, east, north]`. */
|
|
89
|
+
export type NgisBounds = [number, number, number, number];
|
|
90
|
+
/** An unsubscribe function — the return value of every `onX` subscription. */
|
|
91
|
+
export type NgisUnsubscribe = () => void;
|
|
92
|
+
/** `layers` facet — list / inspect / focus / toggle scene layers. */
|
|
93
|
+
export interface NgisLayersFacet {
|
|
94
|
+
list(): NgisLayerSummary[];
|
|
95
|
+
get(id: string): NgisLayerSummary | null;
|
|
96
|
+
/** Fit/ease the camera to a layer's extent (the layer-list "focus" action). */
|
|
97
|
+
focus(id: string): void;
|
|
98
|
+
/** Show/hide a layer (persists via the scene store, like the layer list). */
|
|
99
|
+
setVisibility(id: string, visible: boolean): void;
|
|
100
|
+
/** Notified when the effective layer set changes (add/remove/reorder/
|
|
101
|
+
* visibility *and* live style-draft edits — anything that replaces the
|
|
102
|
+
* store's `effectiveLayers` array). The host's binding equality-guards the
|
|
103
|
+
* subscription so listeners only fire on real changes, never on unrelated
|
|
104
|
+
* store updates. Required since 0.2.0. */
|
|
105
|
+
onChange(listener: () => void): NgisUnsubscribe;
|
|
106
|
+
}
|
|
107
|
+
/** `camera` facet — read/move the viewport + observe view changes. */
|
|
108
|
+
export interface NgisCameraFacet {
|
|
109
|
+
/** Current view, or `null` when the raw map isn't bound yet (`getMap()`). */
|
|
110
|
+
getView(): NgisMapView | null;
|
|
111
|
+
/** Subscribe to camera moves (drives view persistence). Returns unsubscribe. */
|
|
112
|
+
onViewChange(listener: (view: NgisMapView) => void): NgisUnsubscribe;
|
|
113
|
+
zoomIn(): void;
|
|
114
|
+
zoomOut(): void;
|
|
115
|
+
/** Ease back to the scene's default/initial view. */
|
|
116
|
+
zoomHome(): void;
|
|
117
|
+
/** Fly to an explicit view. Escape-hatch-backed: delegates to the raw map,
|
|
118
|
+
* so it is a documented **no-op while `getMap()` returns `null`** (i.e.
|
|
119
|
+
* until the host binds a raw-map getter — the first-party canvas does via
|
|
120
|
+
* `useBindNgisRawMap`). Required since 0.2.0. */
|
|
121
|
+
flyTo(view: NgisMapView): void;
|
|
122
|
+
/** Fit the camera to bounds. Escape-hatch-backed — same getMap-null no-op
|
|
123
|
+
* behavior as `flyTo`. Required since 0.2.0. */
|
|
124
|
+
fitBounds(bounds: NgisBounds): void;
|
|
125
|
+
}
|
|
126
|
+
/** Enumerated feature highlight — identical to the scene's `SceneLayerHighlight`. */
|
|
127
|
+
export type NgisHighlight = SceneLayerHighlight;
|
|
128
|
+
/** The highlight sub-facet under `selection` — set/clear the feature-state
|
|
129
|
+
* highlight the attribute table and layer list drive. */
|
|
130
|
+
export interface NgisHighlightFacet {
|
|
131
|
+
get(): NgisHighlight | null;
|
|
132
|
+
set(highlight: NgisHighlight | null): void;
|
|
133
|
+
clear(): void;
|
|
134
|
+
onChange(listener: (highlight: NgisHighlight | null) => void): NgisUnsubscribe;
|
|
135
|
+
}
|
|
136
|
+
/** `selection` facet — feature highlight only.
|
|
137
|
+
*
|
|
138
|
+
* 0.2.0 deleted the declared-but-dead drawn-feature-selection surface
|
|
139
|
+
* (`get?`/`clear?`/`onChange?` + the `"selectionchange"` event): nothing ever
|
|
140
|
+
* implemented or emitted it (decision D10 — contract-safe pre-1.0), and the
|
|
141
|
+
* one cheap first-party emit source (`SelectionController`'s feature-select
|
|
142
|
+
* enable/disable) signals an interaction-mode toggle, not a selection-set
|
|
143
|
+
* change. If a real Terra Draw selection source lands, the members return
|
|
144
|
+
* additively. */
|
|
145
|
+
export interface NgisSelectionFacet {
|
|
146
|
+
highlight: NgisHighlightFacet;
|
|
147
|
+
}
|
|
148
|
+
/** `draw` facet — Terra Draw mode + one-shot geometry actions. */
|
|
149
|
+
export interface NgisDrawFacet {
|
|
150
|
+
setMode(mode: GisDrawMode): void;
|
|
151
|
+
/** Leave the active mode, back to idle. */
|
|
152
|
+
cancelMode(): void;
|
|
153
|
+
getActiveMode(): string | null;
|
|
154
|
+
/** Remove every drawn feature. */
|
|
155
|
+
clear(): void;
|
|
156
|
+
/** Delete the currently selected drawn feature(s). */
|
|
157
|
+
deleteSelection(): void;
|
|
158
|
+
undo(): void;
|
|
159
|
+
redo(): void;
|
|
160
|
+
/** Download the drawn features as GeoJSON. */
|
|
161
|
+
export(): void;
|
|
162
|
+
/** Snapshot the raw Terra Draw features. Bound (0.2.0) through the
|
|
163
|
+
* imperative handle's optional `getDrawSnapshot` — returns `[]` when the
|
|
164
|
+
* handle is absent or doesn't expose the service.
|
|
165
|
+
*
|
|
166
|
+
* **Live since Stage 14 (F14.18).** The first-party shell's composed
|
|
167
|
+
* `GisMapHandle` now surfaces `getDrawSnapshot`, so in the shipping host this
|
|
168
|
+
* returns the real feature list rather than always `[]`. The member **stays
|
|
169
|
+
* optional-typed** because the 0.3 surface is frozen and a host is still
|
|
170
|
+
* allowed to bind a handle without the service; callers keep writing
|
|
171
|
+
* `snapshot?.() ?? []`. */
|
|
172
|
+
snapshot?(): unknown[];
|
|
173
|
+
/** Observe draw changes (drawn-feature/query-result changes and draw-mode
|
|
174
|
+
* transitions). Wired since 0.2.0: the host feeds its draw-result/draw-mode
|
|
175
|
+
* handlers into `NgisMapAPIHandle.emitDrawChange`. Required. */
|
|
176
|
+
onDrawChange(listener: () => void): NgisUnsubscribe;
|
|
177
|
+
}
|
|
178
|
+
/** `measure` facet — the ephemeral distance/area overlay. (Not in GeoLibre's
|
|
179
|
+
* original facet list; added because the rail's measure tools are a real v0
|
|
180
|
+
* consumer — measuring is a sibling Terra Draw control, never a drawn feature.) */
|
|
181
|
+
export interface NgisMeasureFacet {
|
|
182
|
+
start(kind: GisMeasureKind): void;
|
|
183
|
+
clear(): void;
|
|
184
|
+
}
|
|
185
|
+
/** Named lifecycle events a plugin can observe generically.
|
|
186
|
+
* (`"selectionchange"` was deleted in 0.2.0 alongside the dead
|
|
187
|
+
* drawn-feature-selection surface — see `NgisSelectionFacet`.) */
|
|
188
|
+
export type NgisMapEventName = "viewchange" | "highlightchange" | "drawchange";
|
|
189
|
+
/** `events` facet — a generic named-event bus over the same emitters the typed
|
|
190
|
+
* facet subscriptions use (a forward-compat convenience for plugins). */
|
|
191
|
+
export interface NgisEventsFacet {
|
|
192
|
+
on(event: NgisMapEventName, listener: () => void): NgisUnsubscribe;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* The typed facade. v0 — the surface a plugin (and, today, the three first-party
|
|
196
|
+
* consumers) program against. Concrete methods are frozen; optional-typed
|
|
197
|
+
* methods may light up as the map subsystems expose more.
|
|
198
|
+
*/
|
|
199
|
+
export interface NgisMapAPI {
|
|
200
|
+
readonly version: string;
|
|
201
|
+
layers: NgisLayersFacet;
|
|
202
|
+
camera: NgisCameraFacet;
|
|
203
|
+
selection: NgisSelectionFacet;
|
|
204
|
+
draw: NgisDrawFacet;
|
|
205
|
+
measure: NgisMeasureFacet;
|
|
206
|
+
/** The C7 workspace panel registry, re-exposed so a plugin registers UI slots
|
|
207
|
+
* through the same SDK object. */
|
|
208
|
+
panels: WorkspacePanelRegistry;
|
|
209
|
+
events: NgisEventsFacet;
|
|
210
|
+
/** Raw MapLibre instance — the **unstable escape hatch**. `null` until the
|
|
211
|
+
* host binds a getter (post-C5 `SceneMapCanvas` hookup). Anything a plugin
|
|
212
|
+
* does with this is outside the stability contract. */
|
|
213
|
+
getMap(): MapLibreMap | null;
|
|
214
|
+
}
|
|
215
|
+
/** The imperative surface the facade delegates draw/measure/camera to — a
|
|
216
|
+
* structural subset of the shell's `GisMapHandle`, kept structural so this
|
|
217
|
+
* module doesn't import the (large) `SceneMapCanvas` component. */
|
|
218
|
+
export interface NgisMapImperativeHandle {
|
|
219
|
+
setDrawMode(mode: GisDrawMode): void;
|
|
220
|
+
cancelMode(): void;
|
|
221
|
+
getActiveMode(): string | null;
|
|
222
|
+
clearDraw(): void;
|
|
223
|
+
deleteSelection(): void;
|
|
224
|
+
undo(): void;
|
|
225
|
+
redo(): void;
|
|
226
|
+
exportDraw(): void;
|
|
227
|
+
startMeasure(kind: GisMeasureKind): void;
|
|
228
|
+
clearMeasure(): void;
|
|
229
|
+
zoomIn(): void;
|
|
230
|
+
zoomOut(): void;
|
|
231
|
+
zoomHome(): void;
|
|
232
|
+
/** Raw Terra Draw feature snapshot (the scene-map-context `getDrawSnapshot`
|
|
233
|
+
* service). **The first-party shell supplies it since Stage 14 (F14.18)**, so
|
|
234
|
+
* `draw.snapshot` returns real data there; it stays optional so a host may
|
|
235
|
+
* still bind a handle without the service. */
|
|
236
|
+
getDrawSnapshot?(): unknown[];
|
|
237
|
+
}
|
|
238
|
+
/** The layer operations the `layers` facet needs (a thin adapter over the
|
|
239
|
+
* scene store, supplied by the host so the SDK stays store-agnostic). */
|
|
240
|
+
export interface NgisLayersBinding {
|
|
241
|
+
list(): NgisLayerSummary[];
|
|
242
|
+
focus(id: string): void;
|
|
243
|
+
setVisibility(id: string, visible: boolean): void;
|
|
244
|
+
/** Store-change subscription backing `layers.onChange`. The host must
|
|
245
|
+
* equality-guard it (fire only when the effective layer set really changed).
|
|
246
|
+
* Required since 0.2.0 — `onChange` is part of the frozen surface. */
|
|
247
|
+
subscribe(listener: () => void): NgisUnsubscribe;
|
|
248
|
+
}
|
|
249
|
+
/** The highlight sink — the workspace-owned highlight state (the exact data
|
|
250
|
+
* path the attribute table uses today: this ultimately calls `setHighlight`). */
|
|
251
|
+
export interface NgisHighlightBinding {
|
|
252
|
+
set(highlight: NgisHighlight | null): void;
|
|
253
|
+
/** Initial value (defaults to `null`). */
|
|
254
|
+
initial?: NgisHighlight | null;
|
|
255
|
+
}
|
|
256
|
+
export interface NgisMapAPIBindings {
|
|
257
|
+
/** Live composed imperative handle (`mapRef.current`), or `null` before ready. */
|
|
258
|
+
getHandle(): NgisMapImperativeHandle | null;
|
|
259
|
+
layers: NgisLayersBinding;
|
|
260
|
+
panels: WorkspacePanelRegistry;
|
|
261
|
+
highlight: NgisHighlightBinding;
|
|
262
|
+
/** Raw-map getter for `getMap()`. Usually omitted at construction and wired
|
|
263
|
+
* later via `NgisMapAPIHandle.bindRawMap` (the post-C5 hookup). */
|
|
264
|
+
getRawMap?(): MapLibreMap | null;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* The factory's return value: the public `api` plus the host-side "driver"
|
|
268
|
+
* controls (feed-in points the host wires that are *not* part of the public
|
|
269
|
+
* plugin surface).
|
|
270
|
+
*/
|
|
271
|
+
export interface NgisMapAPIHandle {
|
|
272
|
+
api: NgisMapAPI;
|
|
273
|
+
/** Feed a camera-view change into the facade (called from the canvas's
|
|
274
|
+
* `onViewChange` prop today; from `CameraController` post-hookup). */
|
|
275
|
+
emitViewChange(view: NgisMapView): void;
|
|
276
|
+
/** Feed a draw change into the facade — drives `draw.onDrawChange` and the
|
|
277
|
+
* `"drawchange"` event. The host calls this from its draw-result and
|
|
278
|
+
* draw-mode handlers (0.2.0's first-party emit source). */
|
|
279
|
+
emitDrawChange(): void;
|
|
280
|
+
/** Bind (or replace) the raw-map getter behind `getMap()` — the one-line
|
|
281
|
+
* `SceneMapCanvas` provider hookup applied after rebasing onto merged C5. */
|
|
282
|
+
bindRawMap(getter: () => MapLibreMap | null): void;
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Build a facade over the supplied bindings. Pure and framework-agnostic —
|
|
286
|
+
* create it once per workspace (the host memoizes it) and keep it stable.
|
|
287
|
+
*/
|
|
288
|
+
export declare function createNgisMapAPI(bindings: NgisMapAPIBindings): NgisMapAPIHandle;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workspace panel registry — the plugin-readiness seam for GIS workspace UI
|
|
3
|
+
* "slots" (today: the right dock and the bottom docks). Formalizes what used
|
|
4
|
+
* to be a hand-wired `GisRightMode` enum plus three independent booleans
|
|
5
|
+
* (`attributeOpen`/`workflowOpen`/`codeOpen`) into a generic registration API:
|
|
6
|
+
*
|
|
7
|
+
* const unregister = registerPanel({ id, slot, icon, labelKey, render });
|
|
8
|
+
*
|
|
9
|
+
* Design notes (see `docs/componentization_stage/session-C7-*.md`):
|
|
10
|
+
* - `render(container, ctx)` is a **DOM-based, framework-agnostic** contract —
|
|
11
|
+
* modeled on GeoLibre's lesson that forcing every panel to hand back a React
|
|
12
|
+
* element makes a registry impossible for a future non-React plugin loader
|
|
13
|
+
* to target. A real plugin only needs to mutate a `container: HTMLElement`
|
|
14
|
+
* and (optionally) return a cleanup function.
|
|
15
|
+
* - `reactPanel()` below is the React *adapter* the design doc calls for.
|
|
16
|
+
* First-party panels stay ordinary React components; the adapter's returned
|
|
17
|
+
* `render` function still matches the generic signature (so a naive host
|
|
18
|
+
* invoking it imperatively still works, via an internal `createRoot`
|
|
19
|
+
* fallback), but it also carries a `reactNode` escape hatch that a
|
|
20
|
+
* React-aware host (`GisPanelHost`) uses to mount the panel as a normal
|
|
21
|
+
* child in the app's own React tree — preserving context (next-intl, theme)
|
|
22
|
+
* and ordinary prop-driven reactivity, which an isolated `createRoot` tree
|
|
23
|
+
* cannot (separate roots don't share React context).
|
|
24
|
+
* - A slot still shows only one active panel at a time, but it also tracks the
|
|
25
|
+
* panels opened during the current workspace session. Both GIS docks present
|
|
26
|
+
* that list as tabs and keep inactive opened bodies mounted so local UI state
|
|
27
|
+
* survives tab switches.
|
|
28
|
+
*/
|
|
29
|
+
import { type ReactNode } from "react";
|
|
30
|
+
/** Slots this stage. Order matters only for future additions, not behavior. */
|
|
31
|
+
export type PanelSlot = "right" | "bottom";
|
|
32
|
+
export interface PanelRenderContext {
|
|
33
|
+
/** Close this panel in its slot (and its tab, when the host presents tabs). */
|
|
34
|
+
close: () => void;
|
|
35
|
+
}
|
|
36
|
+
export type PanelDisposer = () => void;
|
|
37
|
+
/**
|
|
38
|
+
* The framework-agnostic render contract. A real (future) plugin panel would
|
|
39
|
+
* implement this directly: mutate `container`, return a cleanup function.
|
|
40
|
+
*/
|
|
41
|
+
export type PanelRenderFn = (container: HTMLElement, ctx: PanelRenderContext) => PanelDisposer | void;
|
|
42
|
+
/** `reactPanel()`'s return type — same call signature, plus the fast path. */
|
|
43
|
+
export interface ReactPanelRenderFn extends PanelRenderFn {
|
|
44
|
+
/** Build the React node for this panel "live" — called on every render of
|
|
45
|
+
* the React-aware host, so ordinary prop/state reactivity works exactly
|
|
46
|
+
* like a normal child component. */
|
|
47
|
+
reactNode: (ctx: PanelRenderContext) => ReactNode;
|
|
48
|
+
}
|
|
49
|
+
export interface PanelRegistration {
|
|
50
|
+
id: string;
|
|
51
|
+
slot: PanelSlot;
|
|
52
|
+
/** Plain string identifier (e.g. a lucide icon name) — kept string-typed,
|
|
53
|
+
* not a React node, so the registration shape never requires React. The
|
|
54
|
+
* consuming UI (e.g. `GisCommandRail`'s right-panel entries) resolves it. */
|
|
55
|
+
icon?: string;
|
|
56
|
+
/** i18n key (e.g. `"GIS.panels.ai"`) resolved by the consumer's `t()`. */
|
|
57
|
+
labelKey?: string;
|
|
58
|
+
/** Literal label, for callers without an i18n key (e.g. a future plugin). */
|
|
59
|
+
label?: string;
|
|
60
|
+
/** Lower sorts first. Ties fall back to registration order. */
|
|
61
|
+
order?: number;
|
|
62
|
+
render: PanelRenderFn;
|
|
63
|
+
}
|
|
64
|
+
type Listener = () => void;
|
|
65
|
+
/**
|
|
66
|
+
* A registry instance. `panels.ts` exports a process-wide singleton
|
|
67
|
+
* (`workspacePanelRegistry`) for the app to use, but the class is exported too
|
|
68
|
+
* so tests (or a future second workspace) can build an isolated instance.
|
|
69
|
+
*/
|
|
70
|
+
export declare class WorkspacePanelRegistry {
|
|
71
|
+
private readonly panelsBySlot;
|
|
72
|
+
private readonly orderedCache;
|
|
73
|
+
private readonly activeBySlot;
|
|
74
|
+
private readonly openBySlot;
|
|
75
|
+
private readonly listeners;
|
|
76
|
+
private seq;
|
|
77
|
+
private readonly seqById;
|
|
78
|
+
constructor(slots?: readonly PanelSlot[]);
|
|
79
|
+
/** Register a panel into its slot. Returns an unregister function — the
|
|
80
|
+
* same "every registration returns an unregister function" convention the
|
|
81
|
+
* `NgisMapAPI` facade (C8) uses. */
|
|
82
|
+
registerPanel(def: PanelRegistration): PanelDisposer;
|
|
83
|
+
/** Registered panels in a slot, sorted by `order` then registration order.
|
|
84
|
+
* Cached so repeated calls between mutations return the same array
|
|
85
|
+
* reference (required for `useSyncExternalStore`'s snapshot contract). */
|
|
86
|
+
getPanels(slot: PanelSlot): PanelRegistration[];
|
|
87
|
+
getPanel(slot: PanelSlot, id: string): PanelRegistration | null;
|
|
88
|
+
getActive(slot: PanelSlot): string | null;
|
|
89
|
+
/** Panel ids opened in this slot, in first-opened order. The returned array
|
|
90
|
+
* is referentially stable until the open set changes. */
|
|
91
|
+
getOpenPanelIds(slot: PanelSlot): readonly string[];
|
|
92
|
+
/** Open a registered panel and make it active. Reopening an existing panel
|
|
93
|
+
* only activates it; it does not duplicate or reorder its tab. */
|
|
94
|
+
open(slot: PanelSlot, id: string): void;
|
|
95
|
+
setActive(slot: PanelSlot, id: string | null): void;
|
|
96
|
+
/** Close one opened panel. When it was active, prefer the nearest tab on
|
|
97
|
+
* its left, then the nearest tab on its right. */
|
|
98
|
+
close(slot: PanelSlot, id: string): void;
|
|
99
|
+
/** Invoking the already-active panel closes it — the "toggle-off" parity
|
|
100
|
+
* every rail tool and dock icon relies on. */
|
|
101
|
+
toggle(slot: PanelSlot, id: string): void;
|
|
102
|
+
subscribe(listener: Listener): PanelDisposer;
|
|
103
|
+
private slotMap;
|
|
104
|
+
private invalidate;
|
|
105
|
+
private removeOpenPanel;
|
|
106
|
+
private notify;
|
|
107
|
+
}
|
|
108
|
+
/** Process-wide registry for the `/gis` workspace. */
|
|
109
|
+
export declare const workspacePanelRegistry: WorkspacePanelRegistry;
|
|
110
|
+
/**
|
|
111
|
+
* React adapter: wraps a `(ctx) => ReactNode` factory as a `PanelRenderFn`.
|
|
112
|
+
* First-party panels use this. See the module doc comment for why the
|
|
113
|
+
* returned function carries both an imperative `createRoot` fallback (the
|
|
114
|
+
* literal, framework-agnostic contract) and a `reactNode` fast path
|
|
115
|
+
* (`GisPanelHost` uses this one, to stay inside the app's own React tree).
|
|
116
|
+
*/
|
|
117
|
+
export declare function reactPanel(factory: (ctx: PanelRenderContext) => ReactNode): ReactPanelRenderFn;
|
|
118
|
+
export declare function isReactPanelRenderFn(fn: PanelRenderFn): fn is ReactPanelRenderFn;
|
|
119
|
+
/** Convenience: build a `reactPanel` from a fixed element (no live `ctx`
|
|
120
|
+
* dependency needed) — most first-party panels want the factory form instead
|
|
121
|
+
* so they can pass `ctx.close`, but this keeps trivial cases terse. */
|
|
122
|
+
export declare function staticReactPanel(node: ReactNode): ReactPanelRenderFn;
|
|
123
|
+
/** Reactive list of a slot's registered panels, sorted — for building things
|
|
124
|
+
* like `GisCommandRail`'s right-panel entry group generically. */
|
|
125
|
+
export declare function usePanels(registry: WorkspacePanelRegistry, slot: PanelSlot): readonly PanelRegistration[];
|
|
126
|
+
/** Reactive active-panel id for a slot (`null` when the slot is closed). */
|
|
127
|
+
export declare function usePanelActive(registry: WorkspacePanelRegistry, slot: PanelSlot): string | null;
|
|
128
|
+
/** Reactive first-opened list for hosts that present a slot as tabs. */
|
|
129
|
+
export declare function useOpenPanelIds(registry: WorkspacePanelRegistry, slot: PanelSlot): readonly string[];
|
|
130
|
+
export {};
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NGIS plugin manifest + plugin object types (plugin-runtime stage, session
|
|
3
|
+
* P4). This is the *implemented* version of the `docs/frontend-map-sdk.md` §3
|
|
4
|
+
* draft, with the stage's decisions of record applied
|
|
5
|
+
* (`docs/plugin_runtime_stage/README.md`):
|
|
6
|
+
*
|
|
7
|
+
* - **D3 — typed TS object, not JSON.** First-party plugins compile in-repo,
|
|
8
|
+
* so the manifest gets compile-time checking free. `entry` stays in the type
|
|
9
|
+
* but is optional/reserved — JSON parsing + dynamic bundle loading is
|
|
10
|
+
* exactly the third-party leg this stage excludes (gated on backend auth
|
|
11
|
+
* hardening; see §3.5 of the SDK doc).
|
|
12
|
+
* - **D4 — declarative capabilities, runtime-owned teardown** (deliberate
|
|
13
|
+
* deviation from the original §3 draft): capability fields carry the actual
|
|
14
|
+
* registration definitions, and the **runtime** performs every registration
|
|
15
|
+
* and owns the collected unregister functions. `activate`/`deactivate`
|
|
16
|
+
* demote to optional imperative extras. This eliminates the draft's
|
|
17
|
+
* plugin-kept-unregister honor system — a plugin cannot forget (or refuse)
|
|
18
|
+
* to tear down what it never registered itself.
|
|
19
|
+
*
|
|
20
|
+
* Framework-agnostic on purpose: type-only imports, no React — consumed by
|
|
21
|
+
* the node-tested runtime (`plugin-runtime.ts`).
|
|
22
|
+
*/
|
|
23
|
+
import type { LayerRendererEntry } from "../systems/renderer/LayerRendererRegistry";
|
|
24
|
+
import type { CommandRegistration } from "./commands";
|
|
25
|
+
import type { NgisContributes, NgisPermissionScope } from "./contributions/types";
|
|
26
|
+
import type { NgisSymbolRendererModule } from "./contributions/symbol-renderers";
|
|
27
|
+
import type { PanelRegistration } from "./panels";
|
|
28
|
+
import type { GisDynamicToolDef } from "./rail-tools";
|
|
29
|
+
/**
|
|
30
|
+
* **F13.1 / ED19 (Stage 13, X4b) — the `NgisPluginHost` widening.**
|
|
31
|
+
*
|
|
32
|
+
* Until 0.3.0 this module *declared* `NgisPluginHost` as `{ api: NgisMapAPI }`.
|
|
33
|
+
* At 0.4.0 the name becomes a back-compat alias of the full nine-facet
|
|
34
|
+
* `NgisHostAPI` (`./host-api`), and this is the only line in the repo that says
|
|
35
|
+
* so — `@/sdk`'s barrel keeps re-exporting the name from here, so every
|
|
36
|
+
* `activate(host: NgisPluginHost)` signature is untouched.
|
|
37
|
+
*
|
|
38
|
+
* Why an alias rather than a rename: `host.api` keeps its name **and** its
|
|
39
|
+
* position (XD1's amendment on record — design-v2 §4 spells it `host.map`, and
|
|
40
|
+
* renaming would move every first-party plugin, the E7 command executor and the
|
|
41
|
+
* loader path for zero capability). A 0.3-era plugin that only ever reads
|
|
42
|
+
* `host.api.layers` therefore still type-checks and still runs, unchanged.
|
|
43
|
+
*
|
|
44
|
+
* Type-only re-export, so it is erased at build time and introduces no module
|
|
45
|
+
* cycle: `host-api.ts` does not import this file.
|
|
46
|
+
*/
|
|
47
|
+
import type { NgisPluginHost } from "./host-api";
|
|
48
|
+
export type { NgisPluginHost };
|
|
49
|
+
/** A teardown function collected and invoked by the runtime. */
|
|
50
|
+
export type NgisPluginDisposer = () => void;
|
|
51
|
+
/**
|
|
52
|
+
* Declarative capabilities (D4) — each field carries the real registration
|
|
53
|
+
* definitions for one of the three SDK extension points, wired by the runtime:
|
|
54
|
+
*
|
|
55
|
+
* - `panels` → `host.api.panels.registerPanel(...)` (C7 registry)
|
|
56
|
+
* - `railTools` → `gisRailToolRegistry.register(...)` (D6 seam — ids must be
|
|
57
|
+
* namespaced, "More tools" overflow only)
|
|
58
|
+
* - `layerTypes` → the contributed-entries bridge (D5 — applied after
|
|
59
|
+
* built-ins into `SceneLayersController`'s per-mount renderer registry)
|
|
60
|
+
* - `commands` → `gisCommandRegistry.register(...)` (Stage 11 E7 seam —
|
|
61
|
+
* externally-invocable capabilities a scene script can call through the
|
|
62
|
+
* codeenv plugin-invocation bridge; ids must be namespaced like railTools)
|
|
63
|
+
*
|
|
64
|
+
* An unknown key here refuses activation (`incompatible`), so a plugin built
|
|
65
|
+
* against a newer runtime never half-activates on an older one.
|
|
66
|
+
*/
|
|
67
|
+
export interface NgisPluginCapabilities {
|
|
68
|
+
panels?: PanelRegistration[];
|
|
69
|
+
railTools?: GisDynamicToolDef[];
|
|
70
|
+
layerTypes?: LayerRendererEntry[];
|
|
71
|
+
commands?: CommandRegistration[];
|
|
72
|
+
}
|
|
73
|
+
export interface NgisPluginManifest {
|
|
74
|
+
/** Stable, namespaced, reverse-DNS-ish — **must contain a `.`**
|
|
75
|
+
* (e.g. `"ngis.workflow"`, `"org.acme.heatmap"`); validated at registration. */
|
|
76
|
+
id: string;
|
|
77
|
+
/** Display name (literal — shown in the dev "plugins" panel). */
|
|
78
|
+
name: string;
|
|
79
|
+
/** Plugin's own semver. Informational this stage. */
|
|
80
|
+
version: string;
|
|
81
|
+
/** Minimum `NGIS_MAP_API_VERSION` the plugin needs — semver-compared by the
|
|
82
|
+
* runtime; a too-new requirement marks the plugin `incompatible`. */
|
|
83
|
+
minNgisVersion: string;
|
|
84
|
+
capabilities: NgisPluginCapabilities;
|
|
85
|
+
/**
|
|
86
|
+
* **F13.3 — a top-level sibling of `capabilities`, not a capability key.**
|
|
87
|
+
* `KNOWN_CAPABILITY_KEYS` stays `panels|railTools|layerTypes|commands` in
|
|
88
|
+
* both repos, which is precisely why F13.13's reverse leg lands on the
|
|
89
|
+
* `minNgisVersion` semver compare: a 0.3 runtime inspects only
|
|
90
|
+
* `manifest.capabilities` and never sees this key at all.
|
|
91
|
+
*
|
|
92
|
+
* The split rule: `capabilities` carries **code**, `contributes` carries
|
|
93
|
+
* **only data**, and a contribution that needs code references it by id.
|
|
94
|
+
* Parsed by `parseContributes` (`@/sdk/contributions`, X4a) from the raw
|
|
95
|
+
* manifest the boot / scene-resolve payload already carries — **before any
|
|
96
|
+
* bundle is fetched** (XD4). That passthrough is the lazy-activation
|
|
97
|
+
* substrate.
|
|
98
|
+
*/
|
|
99
|
+
contributes?: NgisContributes;
|
|
100
|
+
/**
|
|
101
|
+
* **F13.5 — the declared permission scopes**, encoded as a flat array of
|
|
102
|
+
* scope strings (frozen at the W1 kickoff: duplicates are a validation
|
|
103
|
+
* error, order is insignificant, an empty array means the same as an absent
|
|
104
|
+
* key). Enforcement is X5's (W3) and is facade-level; the whole 0.3
|
|
105
|
+
* `host.api` surface stays ungated, so a 0.3-era plugin declares nothing
|
|
106
|
+
* here and is never prompted.
|
|
107
|
+
*/
|
|
108
|
+
permissions?: readonly NgisPermissionScope[];
|
|
109
|
+
/** **Reserved, never read this stage** (D3): the future third-party loader's
|
|
110
|
+
* ESM-bundle path. First-party plugins are statically imported instead. */
|
|
111
|
+
entry?: string;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* A plugin = manifest + optional imperative extras (D4). Most first-party
|
|
115
|
+
* plugins are expected to be fully declarative (capabilities only).
|
|
116
|
+
*
|
|
117
|
+
* - `activate?(host)` runs after the runtime registered the declared
|
|
118
|
+
* capabilities. Return `false` to signal a failed activation (the runtime
|
|
119
|
+
* rolls back the capability registrations it already made); return a
|
|
120
|
+
* disposer to have the runtime run it on deactivation; throwing is treated
|
|
121
|
+
* like `false`.
|
|
122
|
+
* - `deactivate?()` runs on teardown, after the runtime ran every collected
|
|
123
|
+
* unregister function.
|
|
124
|
+
*/
|
|
125
|
+
export interface NgisPlugin {
|
|
126
|
+
manifest: NgisPluginManifest;
|
|
127
|
+
/**
|
|
128
|
+
* **F24.13 (Stage 24) — the code half of the T3 bridge.** `manifest
|
|
129
|
+
* .contributes.symbolRenderers` declares `{ id, geometry, params?, slots? }`
|
|
130
|
+
* as data; this is what the bundle exports against those ids.
|
|
131
|
+
*
|
|
132
|
+
* A sibling of `manifest`, not a capability key, for the reason
|
|
133
|
+
* `./contributions/symbol-renderers.ts` sets out: `KNOWN_CAPABILITY_KEYS` is
|
|
134
|
+
* frozen in both repos and an unknown key refuses activation outright, so a
|
|
135
|
+
* sixth one would make a T3 plugin `incompatible` on every older host.
|
|
136
|
+
*
|
|
137
|
+
* Published by the runtime at activation and disposed with every other
|
|
138
|
+
* registration it made — which is what keeps declaring a renderer from
|
|
139
|
+
* forcing eager activation (F13.4): the plugin activates on the first
|
|
140
|
+
* *resolution* of a symbol that names it.
|
|
141
|
+
*/
|
|
142
|
+
symbolRenderers?: NgisSymbolRendererModule;
|
|
143
|
+
activate?(host: NgisPluginHost): void | false | NgisPluginDisposer;
|
|
144
|
+
deactivate?(): void;
|
|
145
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { GisRailInvokeContext } from "../types/gis";
|
|
2
|
+
/** A plugin-contributed rail tool. v1 supports one-shot `kind: "action"` only
|
|
3
|
+
* (no draw-mode/measure lit-state integration — that bookkeeping is keyed to
|
|
4
|
+
* `GisToolId` and stays closed per D6). `invoke` receives the exact same ctx
|
|
5
|
+
* shape as catalog tools, so a dynamic tool drives the map through `ctx.api`
|
|
6
|
+
* like any first-party tool. */
|
|
7
|
+
export interface GisDynamicToolDef {
|
|
8
|
+
/** Namespaced id — **must contain a `.`** (validated at registration), which
|
|
9
|
+
* makes collision with the dot-free `GisToolId` union impossible. */
|
|
10
|
+
id: string;
|
|
11
|
+
/** Literal display label (not an i18n key — third-party path). */
|
|
12
|
+
label: string;
|
|
13
|
+
/** Optional lucide icon name; unmapped names render without an icon. */
|
|
14
|
+
icon?: string;
|
|
15
|
+
/** v1: one-shot actions only. */
|
|
16
|
+
kind: "action";
|
|
17
|
+
/**
|
|
18
|
+
* Rendered greyed-out instead of hidden, and `invoke` is not called
|
|
19
|
+
* (Stage 13 X9, F13.9 / XD12).
|
|
20
|
+
*
|
|
21
|
+
* Additive to D6: the overflow used to have no way to say "this exists but
|
|
22
|
+
* cannot run right now", so a contributed `tools` stanza whose backend tool
|
|
23
|
+
* is missing or whose `enabledWhen` is false would have had to be *dropped*
|
|
24
|
+
* from the list — and hiding it makes a broken install indistinguishable from
|
|
25
|
+
* a feature that was never installed. Nothing about D6's frozen rules
|
|
26
|
+
* changes: ids stay namespaced, the catalog stays closed, and a def that
|
|
27
|
+
* omits this field behaves exactly as before.
|
|
28
|
+
*/
|
|
29
|
+
disabled?: boolean;
|
|
30
|
+
/** Why, shown beside a disabled entry. A plugin's literal string (F13.11) or
|
|
31
|
+
* a host-authored one; never a message key. */
|
|
32
|
+
disabledReason?: string;
|
|
33
|
+
invoke: (ctx: GisRailInvokeContext) => void;
|
|
34
|
+
}
|
|
35
|
+
type Listener = () => void;
|
|
36
|
+
type Disposer = () => void;
|
|
37
|
+
/**
|
|
38
|
+
* Registry instance. A process-wide singleton (`gisRailToolRegistry`) is what
|
|
39
|
+
* the rail and the plugin runtime use; the factory is exported so tests build
|
|
40
|
+
* isolated instances.
|
|
41
|
+
*/
|
|
42
|
+
export interface GisRailToolRegistry {
|
|
43
|
+
/** Register a dynamic tool. Throws if `def.id` does not contain a `.`.
|
|
44
|
+
* Returns an unregister function (idempotent; never removes a different
|
|
45
|
+
* def re-registered under the same id). */
|
|
46
|
+
register(def: GisDynamicToolDef): Disposer;
|
|
47
|
+
/** Registered tools in registration order — cached snapshot between
|
|
48
|
+
* mutations (safe as a `useSyncExternalStore` snapshot). */
|
|
49
|
+
list(): readonly GisDynamicToolDef[];
|
|
50
|
+
subscribe(listener: Listener): Disposer;
|
|
51
|
+
}
|
|
52
|
+
export declare function createGisRailToolRegistry(): GisRailToolRegistry;
|
|
53
|
+
/** Process-wide dynamic rail-tool registry for the `/gis` workspace. */
|
|
54
|
+
export declare const gisRailToolRegistry: GisRailToolRegistry;
|
|
55
|
+
/** Reactive list of registered dynamic tools — `GisCommandRail` merges these
|
|
56
|
+
* into its "More tools" overflow. */
|
|
57
|
+
export declare function useDynamicRailTools(registry?: GisRailToolRegistry): readonly GisDynamicToolDef[];
|
|
58
|
+
export {};
|