@elaraai/east-ui 1.0.13 → 1.0.15
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/dist/src/collections/index.d.ts +1 -0
- package/dist/src/collections/index.d.ts.map +1 -1
- package/dist/src/collections/index.js +1 -0
- package/dist/src/collections/index.js.map +1 -1
- package/dist/src/collections/map/index.d.ts +1180 -0
- package/dist/src/collections/map/index.d.ts.map +1 -0
- package/dist/src/collections/map/index.js +802 -0
- package/dist/src/collections/map/index.js.map +1 -0
- package/dist/src/collections/map/types.d.ts +586 -0
- package/dist/src/collections/map/types.d.ts.map +1 -0
- package/dist/src/collections/map/types.js +315 -0
- package/dist/src/collections/map/types.js.map +1 -0
- package/dist/src/component.d.ts +225 -0
- package/dist/src/component.d.ts.map +1 -1
- package/dist/src/component.js +36 -0
- package/dist/src/component.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/internal.d.ts +1 -1
- package/dist/src/internal.d.ts.map +1 -1
- package/dist/src/internal.js +1 -1
- package/dist/src/internal.js.map +1 -1
- package/dist/src/runtime/collections/index.d.ts +1 -0
- package/dist/src/runtime/collections/index.d.ts.map +1 -1
- package/dist/src/runtime/collections/index.js +1 -0
- package/dist/src/runtime/collections/index.js.map +1 -1
- package/dist/src/runtime/collections/map.d.ts +74 -0
- package/dist/src/runtime/collections/map.d.ts.map +1 -0
- package/dist/src/runtime/collections/map.js +70 -0
- package/dist/src/runtime/collections/map.js.map +1 -0
- package/dist/test/collections/map.examples.d.ts +8 -0
- package/dist/test/collections/map.examples.d.ts.map +1 -0
- package/dist/test/collections/map.examples.js +150 -0
- package/dist/test/collections/map.examples.js.map +1 -0
- package/dist/test/collections/schematic.examples.d.ts.map +1 -1
- package/dist/test/collections/schematic.examples.js +30 -2
- package/dist/test/collections/schematic.examples.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,802 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* `Map` — an interactive geographic basemap (CARTO / OSM raster tiles) with
|
|
7
|
+
* H3 hex and filled-area overlays, connector lines, pins, standalone labels,
|
|
8
|
+
* and a generalised overlay slot that hosts arbitrary East `UIComponent`
|
|
9
|
+
* children (a HUD, a legend, a back button) positioned over the canvas.
|
|
10
|
+
* **Read-only / selection-only**: click an area (returns its key), zoom, and
|
|
11
|
+
* fly to; any writes ride in through ordinary `Button` children in the
|
|
12
|
+
* overlay slot. Colour stays theme-owned — data selects a `tone` / `status`
|
|
13
|
+
* and the renderer's recipe maps each to a token.
|
|
14
|
+
*
|
|
15
|
+
* @packageDocumentation
|
|
16
|
+
*/
|
|
17
|
+
import { East, Expr, variant, some, none, ArrayType, BooleanType, FloatType, FunctionType, IntegerType, NullType, OptionType, StringType, StructType, } from "@elaraai/east";
|
|
18
|
+
import { UIComponentType } from "../../component.js";
|
|
19
|
+
import { AlignType } from "../../style/content.js";
|
|
20
|
+
import {} from "../../style/interaction.js";
|
|
21
|
+
import {} from "../../display/icon/types.js";
|
|
22
|
+
import { MapLatLngType, MapToneType, MapCartoStyleType, MapTileType, MapFocusType, MapAreaShapeType, MapAreaType, MapHexLayerType, MapMarkerType, MapLineStyleType, MapLineType, MapLabelType, } from "./types.js";
|
|
23
|
+
// Re-export types
|
|
24
|
+
export { MapLatLngType, MapToneType, MapCartoStyleType, MapTileType, MapFocusType, MapAreaShapeType, MapAreaType, MapHexLayerType, MapMarkerType, MapLineStyleType, MapLineType, MapLabelType, } from "./types.js";
|
|
25
|
+
function toneValue(tone) {
|
|
26
|
+
return tone !== undefined ? some(variant(tone, null)) : none;
|
|
27
|
+
}
|
|
28
|
+
/** Wrap a `tone` override into its option — accepts a string literal shorthand
|
|
29
|
+
* (`"brand"`) or an East tone expression / value. */
|
|
30
|
+
function toneOption(tone) {
|
|
31
|
+
if (tone === undefined)
|
|
32
|
+
return none;
|
|
33
|
+
return typeof tone === "string" ? some(variant(tone, null)) : some(tone);
|
|
34
|
+
}
|
|
35
|
+
function buildAlign(a) {
|
|
36
|
+
return typeof a === "string" ? East.value(variant(a, null), AlignType) : a;
|
|
37
|
+
}
|
|
38
|
+
// ============================================================================
|
|
39
|
+
// Geometry + style sub-builders
|
|
40
|
+
// ============================================================================
|
|
41
|
+
/**
|
|
42
|
+
* Builds a geographic point value.
|
|
43
|
+
*
|
|
44
|
+
* @param lat - Latitude in degrees
|
|
45
|
+
* @param lng - Longitude in degrees
|
|
46
|
+
* @returns A `MapLatLngType` value
|
|
47
|
+
*/
|
|
48
|
+
function at(lat, lng) {
|
|
49
|
+
return East.value({ lat, lng }, MapLatLngType);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Builds a CARTO raster basemap.
|
|
53
|
+
*
|
|
54
|
+
* @param style - The CARTO preset (default `positron`)
|
|
55
|
+
* @returns A `MapTileType` value
|
|
56
|
+
*/
|
|
57
|
+
function carto(style = "positron") {
|
|
58
|
+
return East.value(variant("carto", { style: variant(style, null) }), MapTileType);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Builds an OpenStreetMap raster basemap.
|
|
62
|
+
*
|
|
63
|
+
* @returns A `MapTileType` value
|
|
64
|
+
*/
|
|
65
|
+
function osm() {
|
|
66
|
+
return East.value(variant("osm", null), MapTileType);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Builds a raw XYZ basemap with explicit attribution.
|
|
70
|
+
*
|
|
71
|
+
* @param config - The tile URL, attribution, and optional `subdomains` / `maxZoom` / `detectRetina`
|
|
72
|
+
* @returns A `MapTileType` value
|
|
73
|
+
*/
|
|
74
|
+
function tile(config) {
|
|
75
|
+
return East.value(variant("custom", {
|
|
76
|
+
url: config.url,
|
|
77
|
+
attribution: config.attribution,
|
|
78
|
+
subdomains: config.subdomains !== undefined ? some(config.subdomains) : none,
|
|
79
|
+
maxZoom: config.maxZoom !== undefined ? some(config.maxZoom) : none,
|
|
80
|
+
detectRetina: config.detectRetina !== undefined ? some(config.detectRetina) : none,
|
|
81
|
+
}), MapTileType);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Builds an `hexDisk` area shape — a `gridDisk(origin, k)` blob at a resolution.
|
|
85
|
+
*
|
|
86
|
+
* @param center - The disk origin
|
|
87
|
+
* @param k - Ring count around the origin
|
|
88
|
+
* @param resolution - H3 resolution
|
|
89
|
+
* @returns A `MapAreaShapeType` value
|
|
90
|
+
*/
|
|
91
|
+
function hexDisk(center, k, resolution) {
|
|
92
|
+
return East.value(variant("hexDisk", { center, k, resolution }), MapAreaShapeType);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Builds a `cells` area shape — an explicit set of H3 cell ids.
|
|
96
|
+
*
|
|
97
|
+
* @param ids - The H3 cell ids
|
|
98
|
+
* @returns A `MapAreaShapeType` value
|
|
99
|
+
*/
|
|
100
|
+
function cells(ids) {
|
|
101
|
+
return East.value(variant("cells", ids), MapAreaShapeType);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Builds a `polygon` area shape — an explicit ring of points (an irregular
|
|
105
|
+
* region boundary). Two polygons that share an edge abut exactly, so adjacent
|
|
106
|
+
* regions running up against each other are authored by reusing the shared
|
|
107
|
+
* boundary points in both.
|
|
108
|
+
*
|
|
109
|
+
* @param points - The boundary points, in order (auto-closed; `Map.at(...)`)
|
|
110
|
+
* @returns A `MapAreaShapeType` value
|
|
111
|
+
*/
|
|
112
|
+
function polygon(points) {
|
|
113
|
+
return East.value(variant("polygon", points), MapAreaShapeType);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Builds a `point` camera target — centre on a point at a zoom level.
|
|
117
|
+
*
|
|
118
|
+
* @param center - The centre
|
|
119
|
+
* @param zoom - The zoom level to settle at
|
|
120
|
+
* @returns A `MapFocusType` value
|
|
121
|
+
*/
|
|
122
|
+
function point(center, zoom) {
|
|
123
|
+
return East.value(variant("point", { center, zoom }), MapFocusType);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Builds a `bounds` camera target — frame a south-west / north-east box.
|
|
127
|
+
*
|
|
128
|
+
* @param sw - South-west corner
|
|
129
|
+
* @param ne - North-east corner
|
|
130
|
+
* @returns A `MapFocusType` value
|
|
131
|
+
*/
|
|
132
|
+
function bounds(sw, ne) {
|
|
133
|
+
return East.value(variant("bounds", { sw, ne }), MapFocusType);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Builds a `solid` line style.
|
|
137
|
+
*
|
|
138
|
+
* @param config - Optional stroke configuration (`tone`, `weight`)
|
|
139
|
+
* @returns A `MapLineStyleType` value
|
|
140
|
+
*/
|
|
141
|
+
function solid(config) {
|
|
142
|
+
return East.value(variant("solid", {
|
|
143
|
+
tone: toneValue(config?.tone),
|
|
144
|
+
weight: config?.weight !== undefined ? some(config.weight) : none,
|
|
145
|
+
}), MapLineStyleType);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Builds a `dashed` line style.
|
|
149
|
+
*
|
|
150
|
+
* @param config - Optional stroke configuration (`tone`, `weight`)
|
|
151
|
+
* @returns A `MapLineStyleType` value
|
|
152
|
+
*/
|
|
153
|
+
function dashed(config) {
|
|
154
|
+
return East.value(variant("dashed", {
|
|
155
|
+
tone: toneValue(config?.tone),
|
|
156
|
+
weight: config?.weight !== undefined ? some(config.weight) : none,
|
|
157
|
+
}), MapLineStyleType);
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Builds the hex layer — a faint background lattice plus optional per-cell
|
|
161
|
+
* detail revealed at LOD.
|
|
162
|
+
*
|
|
163
|
+
* @param config - Optional `lattice`, `cells`, `tone`, and `interactive`
|
|
164
|
+
* @returns A `MapHexLayerType` value
|
|
165
|
+
*/
|
|
166
|
+
function hex(config) {
|
|
167
|
+
return East.value({
|
|
168
|
+
lattice: config?.lattice !== undefined
|
|
169
|
+
? some(East.value({ center: config.lattice.center, k: config.lattice.k, resolution: config.lattice.resolution }, StructType({ center: MapLatLngType, k: IntegerType, resolution: IntegerType })))
|
|
170
|
+
: none,
|
|
171
|
+
cells: (config?.cells ?? []).map(c => ({
|
|
172
|
+
id: c.id,
|
|
173
|
+
status: c.status !== undefined ? c.status : none,
|
|
174
|
+
fillOpacity: c.fillOpacity !== undefined ? some(c.fillOpacity) : none,
|
|
175
|
+
detail: c.detail !== undefined ? some(c.detail) : none,
|
|
176
|
+
})),
|
|
177
|
+
tone: toneOption(config?.tone),
|
|
178
|
+
interactive: config?.interactive !== undefined ? some(config.interactive) : none,
|
|
179
|
+
}, MapHexLayerType);
|
|
180
|
+
}
|
|
181
|
+
// ============================================================================
|
|
182
|
+
// Overlay slot
|
|
183
|
+
// ============================================================================
|
|
184
|
+
/**
|
|
185
|
+
* The generalised overlay slot value — an East `UIComponent` positioned over
|
|
186
|
+
* the map, either screen-anchored (`align` / `verticalAlign`) or pinned to a
|
|
187
|
+
* coordinate (`geoAnchor`).
|
|
188
|
+
*
|
|
189
|
+
* @property content - The East child tree rendered over the canvas
|
|
190
|
+
* @property align - Horizontal screen anchor
|
|
191
|
+
* @property verticalAlign - Vertical screen anchor
|
|
192
|
+
* @property key - Optional stable child storage-key segment
|
|
193
|
+
* @property geoAnchor - Optional coordinate the overlay follows on pan / zoom
|
|
194
|
+
* @property offset - Optional px nudge from the anchor
|
|
195
|
+
* @property interactive - Optional pointer-events flag (default true)
|
|
196
|
+
*/
|
|
197
|
+
export const MapOverlayType = StructType({
|
|
198
|
+
/** The East child tree rendered over the canvas */
|
|
199
|
+
content: UIComponentType,
|
|
200
|
+
/** Horizontal screen anchor */
|
|
201
|
+
align: AlignType,
|
|
202
|
+
/** Vertical screen anchor */
|
|
203
|
+
verticalAlign: AlignType,
|
|
204
|
+
/** Optional stable child storage-key segment */
|
|
205
|
+
key: OptionType(StringType),
|
|
206
|
+
/** Optional coordinate the overlay follows on pan / zoom */
|
|
207
|
+
geoAnchor: OptionType(MapLatLngType),
|
|
208
|
+
/** Optional px nudge from the anchor */
|
|
209
|
+
offset: OptionType(StructType({ x: FloatType, y: FloatType })),
|
|
210
|
+
/** Optional pointer-events flag (default true; false ⇒ click-through) */
|
|
211
|
+
interactive: OptionType(BooleanType),
|
|
212
|
+
});
|
|
213
|
+
/**
|
|
214
|
+
* Builds a positioned overlay child for the `overlays` slot.
|
|
215
|
+
*
|
|
216
|
+
* @param content - The East child tree (a HUD, legend, back button)
|
|
217
|
+
* @param options - Anchor / offset / interactivity options
|
|
218
|
+
* @returns A `MapOverlayType` value
|
|
219
|
+
*/
|
|
220
|
+
function overlay(content, options) {
|
|
221
|
+
return East.value({
|
|
222
|
+
content,
|
|
223
|
+
align: buildAlign(options?.align ?? "start"),
|
|
224
|
+
verticalAlign: buildAlign(options?.verticalAlign ?? "start"),
|
|
225
|
+
key: options?.key !== undefined ? some(options.key) : none,
|
|
226
|
+
geoAnchor: options?.geoAnchor !== undefined ? some(options.geoAnchor) : none,
|
|
227
|
+
offset: options?.offset !== undefined
|
|
228
|
+
? some(East.value({ x: options.offset.x, y: options.offset.y }, StructType({ x: FloatType, y: FloatType })))
|
|
229
|
+
: none,
|
|
230
|
+
interactive: options?.interactive !== undefined ? some(options.interactive) : none,
|
|
231
|
+
}, MapOverlayType);
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Builds a resolved marker value.
|
|
235
|
+
*
|
|
236
|
+
* @param fields - The marker fields ({@link MapMarkerFields})
|
|
237
|
+
* @returns A `MapMarkerType` value
|
|
238
|
+
*/
|
|
239
|
+
function marker(fields) {
|
|
240
|
+
return East.value({
|
|
241
|
+
key: fields.key,
|
|
242
|
+
at: at(fields.lat, fields.lng),
|
|
243
|
+
label: fields.label !== undefined ? some(fields.label) : none,
|
|
244
|
+
icon: fields.icon !== undefined ? some(fields.icon) : none,
|
|
245
|
+
tone: toneOption(fields.tone),
|
|
246
|
+
minZoom: fields.minZoom !== undefined ? some(fields.minZoom) : none,
|
|
247
|
+
interactive: fields.interactive !== undefined ? some(fields.interactive) : none,
|
|
248
|
+
}, MapMarkerType);
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Builds a resolved area value.
|
|
252
|
+
*
|
|
253
|
+
* @param fields - The area fields ({@link MapAreaFields})
|
|
254
|
+
* @returns A `MapAreaType` value
|
|
255
|
+
*/
|
|
256
|
+
function area(fields) {
|
|
257
|
+
return East.value({
|
|
258
|
+
key: fields.key,
|
|
259
|
+
shape: fields.shape,
|
|
260
|
+
label: fields.label !== undefined ? some(fields.label) : none,
|
|
261
|
+
detailLabel: fields.detailLabel !== undefined ? some(fields.detailLabel) : none,
|
|
262
|
+
status: fields.status !== undefined ? fields.status : none,
|
|
263
|
+
tone: toneOption(fields.tone),
|
|
264
|
+
color: fields.color !== undefined ? some(fields.color) : none,
|
|
265
|
+
fillOpacity: fields.fillOpacity !== undefined ? some(fields.fillOpacity) : none,
|
|
266
|
+
weight: fields.weight !== undefined ? some(fields.weight) : none,
|
|
267
|
+
pulse: fields.pulse !== undefined ? some(fields.pulse) : none,
|
|
268
|
+
flyTo: fields.flyTo !== undefined ? some(fields.flyTo) : none,
|
|
269
|
+
}, MapAreaType);
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Builds a resolved line value.
|
|
273
|
+
*
|
|
274
|
+
* @param fields - The line fields ({@link MapLineFields})
|
|
275
|
+
* @returns A `MapLineType` value
|
|
276
|
+
*/
|
|
277
|
+
function line(fields) {
|
|
278
|
+
return East.value({
|
|
279
|
+
key: fields.key,
|
|
280
|
+
points: East.value(fields.points, ArrayType(MapLatLngType)),
|
|
281
|
+
style: fields.style !== undefined ? fields.style : solid(),
|
|
282
|
+
flow: fields.flow !== undefined ? some(fields.flow) : none,
|
|
283
|
+
arrow: fields.arrow !== undefined ? some(fields.arrow) : none,
|
|
284
|
+
}, MapLineType);
|
|
285
|
+
}
|
|
286
|
+
function label(fields) {
|
|
287
|
+
return East.value({ key: fields.key, at: at(fields.lat, fields.lng), text: fields.text }, MapLabelType);
|
|
288
|
+
}
|
|
289
|
+
// ============================================================================
|
|
290
|
+
// Root type + factory
|
|
291
|
+
// ============================================================================
|
|
292
|
+
/**
|
|
293
|
+
* East StructType for the Map component.
|
|
294
|
+
*
|
|
295
|
+
* @remarks
|
|
296
|
+
* The `overlays` slot and (via `content`) any child trees are recursive
|
|
297
|
+
* `UIComponentType` values; the registration in `component.ts` spells the
|
|
298
|
+
* same shape with the recursion `node`.
|
|
299
|
+
*
|
|
300
|
+
* @property tiles - Basemap source
|
|
301
|
+
* @property center - Initial centre
|
|
302
|
+
* @property zoom - Initial zoom
|
|
303
|
+
* @property minZoom - Optional minimum zoom clamp
|
|
304
|
+
* @property maxZoom - Optional maximum zoom clamp
|
|
305
|
+
* @property lodZoom - Optional detail-LOD threshold
|
|
306
|
+
* @property fitBounds - Optional camera framing (alternative to center / zoom)
|
|
307
|
+
* @property areas - Filled boundaries
|
|
308
|
+
* @property hexes - Optional H3 lattice + per-cell detail
|
|
309
|
+
* @property markers - Pins
|
|
310
|
+
* @property lines - Connectors / move arrows
|
|
311
|
+
* @property labels - Standalone labels
|
|
312
|
+
* @property overlays - Positioned East children (HUD / legend / back)
|
|
313
|
+
* @property scrollWheelZoom - Optional scroll-wheel zoom (default true)
|
|
314
|
+
* @property attributionPrefix - Optional Leaflet prefix toggle (default false)
|
|
315
|
+
* @property height - Optional fixed panel height
|
|
316
|
+
* @property onAreaClick - Optional area-click callback (receives the area key)
|
|
317
|
+
* @property onMarkerClick - Optional marker-click callback (receives the marker key)
|
|
318
|
+
* @property onZoom - Optional zoom-end callback (receives the zoom level)
|
|
319
|
+
* @property onSelect - Optional hex / marker selection callback (receives the key)
|
|
320
|
+
*/
|
|
321
|
+
export const MapRootType = StructType({
|
|
322
|
+
tiles: MapTileType,
|
|
323
|
+
center: MapLatLngType,
|
|
324
|
+
zoom: IntegerType,
|
|
325
|
+
minZoom: OptionType(IntegerType),
|
|
326
|
+
maxZoom: OptionType(IntegerType),
|
|
327
|
+
lodZoom: OptionType(IntegerType),
|
|
328
|
+
fitBounds: OptionType(MapFocusType),
|
|
329
|
+
areas: ArrayType(MapAreaType),
|
|
330
|
+
hexes: OptionType(MapHexLayerType),
|
|
331
|
+
markers: ArrayType(MapMarkerType),
|
|
332
|
+
lines: ArrayType(MapLineType),
|
|
333
|
+
labels: ArrayType(MapLabelType),
|
|
334
|
+
overlays: ArrayType(MapOverlayType),
|
|
335
|
+
scrollWheelZoom: OptionType(BooleanType),
|
|
336
|
+
attributionPrefix: OptionType(BooleanType),
|
|
337
|
+
height: OptionType(StringType),
|
|
338
|
+
onAreaClick: OptionType(FunctionType([StringType], NullType)),
|
|
339
|
+
onMarkerClick: OptionType(FunctionType([StringType], NullType)),
|
|
340
|
+
onZoom: OptionType(FunctionType([IntegerType], NullType)),
|
|
341
|
+
onSelect: OptionType(FunctionType([StringType], NullType)),
|
|
342
|
+
});
|
|
343
|
+
function buildRoot(markers, config) {
|
|
344
|
+
const markerMapper = config.marker;
|
|
345
|
+
const resolvedMarkers = markerMapper === undefined
|
|
346
|
+
? East.value(markers, ArrayType(MapMarkerType))
|
|
347
|
+
: East.value(markers).map((_$, row) => {
|
|
348
|
+
const r = markerMapper(row);
|
|
349
|
+
if (r instanceof Expr)
|
|
350
|
+
return East.value(r, MapMarkerType);
|
|
351
|
+
return marker(r);
|
|
352
|
+
});
|
|
353
|
+
const areaMapper = config.area;
|
|
354
|
+
const resolvedAreas = config.areas === undefined
|
|
355
|
+
? East.value([], ArrayType(MapAreaType))
|
|
356
|
+
: areaMapper === undefined
|
|
357
|
+
? East.value(config.areas, ArrayType(MapAreaType))
|
|
358
|
+
: East.value(config.areas).map((_$, row) => {
|
|
359
|
+
const r = areaMapper(row);
|
|
360
|
+
if (r instanceof Expr)
|
|
361
|
+
return East.value(r, MapAreaType);
|
|
362
|
+
return area(r);
|
|
363
|
+
});
|
|
364
|
+
const labelMapper = config.label;
|
|
365
|
+
const resolvedLabels = config.labels === undefined
|
|
366
|
+
? East.value([], ArrayType(MapLabelType))
|
|
367
|
+
: labelMapper === undefined
|
|
368
|
+
? East.value(config.labels, ArrayType(MapLabelType))
|
|
369
|
+
: East.value(config.labels).map((_$, row) => {
|
|
370
|
+
const r = labelMapper(row);
|
|
371
|
+
if (r instanceof Expr)
|
|
372
|
+
return East.value(r, MapLabelType);
|
|
373
|
+
return label(r);
|
|
374
|
+
});
|
|
375
|
+
const lineMapper = config.line;
|
|
376
|
+
const resolvedLines = config.lines === undefined
|
|
377
|
+
? East.value([], ArrayType(MapLineType))
|
|
378
|
+
: lineMapper === undefined
|
|
379
|
+
? East.value(config.lines, ArrayType(MapLineType))
|
|
380
|
+
: East.value(config.lines).map((_$, row) => {
|
|
381
|
+
const r = lineMapper(row);
|
|
382
|
+
if (r instanceof Expr)
|
|
383
|
+
return East.value(r, MapLineType);
|
|
384
|
+
return line(r);
|
|
385
|
+
});
|
|
386
|
+
return East.value(variant("Map", {
|
|
387
|
+
tiles: config.tiles !== undefined ? config.tiles : carto("positron"),
|
|
388
|
+
center: config.center,
|
|
389
|
+
zoom: config.zoom,
|
|
390
|
+
minZoom: config.minZoom !== undefined ? some(config.minZoom) : none,
|
|
391
|
+
maxZoom: config.maxZoom !== undefined ? some(config.maxZoom) : none,
|
|
392
|
+
lodZoom: config.lodZoom !== undefined ? some(config.lodZoom) : none,
|
|
393
|
+
fitBounds: config.fitBounds !== undefined ? some(config.fitBounds) : none,
|
|
394
|
+
areas: resolvedAreas,
|
|
395
|
+
hexes: config.hexes !== undefined ? some(config.hexes) : none,
|
|
396
|
+
markers: resolvedMarkers,
|
|
397
|
+
lines: resolvedLines,
|
|
398
|
+
labels: resolvedLabels,
|
|
399
|
+
overlays: config.overlays !== undefined
|
|
400
|
+
? East.value([...config.overlays], ArrayType(MapOverlayType))
|
|
401
|
+
: East.value([], ArrayType(MapOverlayType)),
|
|
402
|
+
scrollWheelZoom: config.scrollWheelZoom !== undefined ? some(config.scrollWheelZoom) : none,
|
|
403
|
+
attributionPrefix: config.attributionPrefix !== undefined ? some(config.attributionPrefix) : none,
|
|
404
|
+
height: config.height !== undefined ? some(config.height) : none,
|
|
405
|
+
onAreaClick: config.onAreaClick !== undefined ? some(config.onAreaClick) : none,
|
|
406
|
+
onMarkerClick: config.onMarkerClick !== undefined ? some(config.onMarkerClick) : none,
|
|
407
|
+
onZoom: config.onZoom !== undefined ? some(config.onZoom) : none,
|
|
408
|
+
onSelect: config.onSelect !== undefined ? some(config.onSelect) : none,
|
|
409
|
+
}), UIComponentType);
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Creates a Map — an interactive geographic basemap with H3 / area overlays
|
|
413
|
+
* and a generalised East-child overlay slot.
|
|
414
|
+
*
|
|
415
|
+
* @typeParam M - The markers-table input
|
|
416
|
+
* @typeParam A - The areas-table input
|
|
417
|
+
* @typeParam La - The labels-table input
|
|
418
|
+
* @typeParam L - The lines-table input
|
|
419
|
+
* @param markers - The pin rows (the required first table)
|
|
420
|
+
* @param config - The Map configuration ({@link MapConfig})
|
|
421
|
+
* @returns An East expression of `UIComponentType`
|
|
422
|
+
*
|
|
423
|
+
* @example
|
|
424
|
+
* ```ts
|
|
425
|
+
* import { East } from "@elaraai/east";
|
|
426
|
+
* import { Map, UIComponentType } from "@elaraai/east-ui";
|
|
427
|
+
*
|
|
428
|
+
* const example = East.function([], UIComponentType, _$ =>
|
|
429
|
+
* Map.Root(
|
|
430
|
+
* [{ id: "okafor", lat: -34.842, lng: 138.598, name: "J. Okafor" }],
|
|
431
|
+
* {
|
|
432
|
+
* center: Map.at(-34.881, 138.6), zoom: 12n,
|
|
433
|
+
* marker: m => ({ key: m.id, lat: m.lat, lng: m.lng, label: m.name }),
|
|
434
|
+
* },
|
|
435
|
+
* ),
|
|
436
|
+
* );
|
|
437
|
+
* ```
|
|
438
|
+
*/
|
|
439
|
+
function createMap(markers, config) {
|
|
440
|
+
return buildRoot(markers, config);
|
|
441
|
+
}
|
|
442
|
+
// ============================================================================
|
|
443
|
+
// Namespace export
|
|
444
|
+
// ============================================================================
|
|
445
|
+
/**
|
|
446
|
+
* Map component namespace.
|
|
447
|
+
*
|
|
448
|
+
* @remarks
|
|
449
|
+
* `Map.Root(markers, config)` builds the basemap from flat tables (markers,
|
|
450
|
+
* areas, labels, lines) plus the `hexes` layer and the `overlays` slot;
|
|
451
|
+
* closed-set fields in data (`status`, `tone`, `style`) are typed variant
|
|
452
|
+
* values (`Map.Types.*`).
|
|
453
|
+
*/
|
|
454
|
+
export const Map = {
|
|
455
|
+
/**
|
|
456
|
+
* Creates a Map — an interactive geographic basemap with H3 / area
|
|
457
|
+
* overlays and a generalised East-child overlay slot.
|
|
458
|
+
*
|
|
459
|
+
* @typeParam M - The markers-table input
|
|
460
|
+
* @typeParam A - The areas-table input
|
|
461
|
+
* @typeParam La - The labels-table input
|
|
462
|
+
* @typeParam L - The lines-table input
|
|
463
|
+
* @param markers - The pin rows (the required first table)
|
|
464
|
+
* @param config - The Map configuration ({@link MapConfig})
|
|
465
|
+
* @returns An East expression of `UIComponentType`
|
|
466
|
+
*
|
|
467
|
+
* @example
|
|
468
|
+
* ```ts
|
|
469
|
+
* import { East } from "@elaraai/east";
|
|
470
|
+
* import { Map, UIComponentType } from "@elaraai/east-ui";
|
|
471
|
+
*
|
|
472
|
+
* const example = East.function([], UIComponentType, _$ =>
|
|
473
|
+
* Map.Root(
|
|
474
|
+
* [{ id: "okafor", lat: -34.842, lng: 138.598, name: "J. Okafor" }],
|
|
475
|
+
* {
|
|
476
|
+
* center: Map.at(-34.881, 138.6), zoom: 12n,
|
|
477
|
+
* marker: m => ({ key: m.id, lat: m.lat, lng: m.lng, label: m.name }),
|
|
478
|
+
* },
|
|
479
|
+
* ),
|
|
480
|
+
* );
|
|
481
|
+
* ```
|
|
482
|
+
*/
|
|
483
|
+
Root: createMap,
|
|
484
|
+
/**
|
|
485
|
+
* Builds a geographic point value.
|
|
486
|
+
*
|
|
487
|
+
* @param lat - Latitude in degrees
|
|
488
|
+
* @param lng - Longitude in degrees
|
|
489
|
+
* @returns A `MapLatLngType` value
|
|
490
|
+
*
|
|
491
|
+
* @example
|
|
492
|
+
* ```ts
|
|
493
|
+
* Map.at(-34.881, 138.6)
|
|
494
|
+
* ```
|
|
495
|
+
*/
|
|
496
|
+
at,
|
|
497
|
+
/**
|
|
498
|
+
* Builds a CARTO raster basemap.
|
|
499
|
+
*
|
|
500
|
+
* @param style - The CARTO preset (default `positron`)
|
|
501
|
+
* @returns A `MapTileType` value
|
|
502
|
+
*
|
|
503
|
+
* @example
|
|
504
|
+
* ```ts
|
|
505
|
+
* Map.carto("voyager")
|
|
506
|
+
* ```
|
|
507
|
+
*/
|
|
508
|
+
carto,
|
|
509
|
+
/**
|
|
510
|
+
* Builds an OpenStreetMap raster basemap.
|
|
511
|
+
*
|
|
512
|
+
* @returns A `MapTileType` value
|
|
513
|
+
*
|
|
514
|
+
* @example
|
|
515
|
+
* ```ts
|
|
516
|
+
* Map.osm()
|
|
517
|
+
* ```
|
|
518
|
+
*/
|
|
519
|
+
osm,
|
|
520
|
+
/**
|
|
521
|
+
* Builds a raw XYZ basemap with explicit attribution.
|
|
522
|
+
*
|
|
523
|
+
* @param config - The tile URL, attribution, and optional layer options
|
|
524
|
+
* @returns A `MapTileType` value
|
|
525
|
+
*
|
|
526
|
+
* @example
|
|
527
|
+
* ```ts
|
|
528
|
+
* Map.tile({ url: "https://{s}.tiles.example/{z}/{x}/{y}.png", attribution: "© Example" })
|
|
529
|
+
* ```
|
|
530
|
+
*/
|
|
531
|
+
tile,
|
|
532
|
+
/**
|
|
533
|
+
* Builds an `hexDisk` area shape — a `gridDisk(origin, k)` blob.
|
|
534
|
+
*
|
|
535
|
+
* @param center - The disk origin
|
|
536
|
+
* @param k - Ring count around the origin
|
|
537
|
+
* @param resolution - H3 resolution
|
|
538
|
+
* @returns A `MapAreaShapeType` value
|
|
539
|
+
*
|
|
540
|
+
* @example
|
|
541
|
+
* ```ts
|
|
542
|
+
* Map.hexDisk(Map.at(-34.9258, 138.5994), 1n, 8n)
|
|
543
|
+
* ```
|
|
544
|
+
*/
|
|
545
|
+
hexDisk,
|
|
546
|
+
/**
|
|
547
|
+
* Builds a `cells` area shape — an explicit set of H3 cell ids.
|
|
548
|
+
*
|
|
549
|
+
* @param ids - The H3 cell ids
|
|
550
|
+
* @returns A `MapAreaShapeType` value
|
|
551
|
+
*
|
|
552
|
+
* @example
|
|
553
|
+
* ```ts
|
|
554
|
+
* Map.cells(["882830829bfffff"])
|
|
555
|
+
* ```
|
|
556
|
+
*/
|
|
557
|
+
cells,
|
|
558
|
+
/**
|
|
559
|
+
* Builds a `polygon` area shape — an explicit ring of points (an irregular
|
|
560
|
+
* region boundary). Two polygons sharing an edge abut exactly.
|
|
561
|
+
*
|
|
562
|
+
* @param points - The boundary points, in order (auto-closed; `Map.at(...)`)
|
|
563
|
+
* @returns A `MapAreaShapeType` value
|
|
564
|
+
*/
|
|
565
|
+
polygon,
|
|
566
|
+
/**
|
|
567
|
+
* Builds the hex layer — a faint background lattice plus optional per-cell
|
|
568
|
+
* detail revealed at LOD.
|
|
569
|
+
*
|
|
570
|
+
* @param config - Optional `lattice`, `cells`, `tone`, and `interactive`
|
|
571
|
+
* @returns A `MapHexLayerType` value
|
|
572
|
+
*
|
|
573
|
+
* @example
|
|
574
|
+
* ```ts
|
|
575
|
+
* Map.hex({ lattice: { center: Map.at(-34.881, 138.6), k: 11n, resolution: 8n }, tone: "muted" })
|
|
576
|
+
* ```
|
|
577
|
+
*/
|
|
578
|
+
hex,
|
|
579
|
+
/**
|
|
580
|
+
* Builds a resolved marker value.
|
|
581
|
+
*
|
|
582
|
+
* @param fields - The marker fields ({@link MapMarkerFields})
|
|
583
|
+
* @returns A `MapMarkerType` value
|
|
584
|
+
*
|
|
585
|
+
* @example
|
|
586
|
+
* ```ts
|
|
587
|
+
* Map.marker({ key: "okafor", lat: -34.842, lng: 138.598, label: "J. Okafor", icon: "house" })
|
|
588
|
+
* ```
|
|
589
|
+
*/
|
|
590
|
+
marker,
|
|
591
|
+
/**
|
|
592
|
+
* Builds a resolved area value.
|
|
593
|
+
*
|
|
594
|
+
* @param fields - The area fields ({@link MapAreaFields})
|
|
595
|
+
* @returns A `MapAreaType` value
|
|
596
|
+
*
|
|
597
|
+
* @example
|
|
598
|
+
* ```ts
|
|
599
|
+
* Map.area({ key: "5000", shape: Map.hexDisk(Map.at(-34.9258, 138.5994), 1n, 8n), label: "5000 · CBD" })
|
|
600
|
+
* ```
|
|
601
|
+
*/
|
|
602
|
+
area,
|
|
603
|
+
/**
|
|
604
|
+
* Builds a resolved line value.
|
|
605
|
+
*
|
|
606
|
+
* @param fields - The line fields ({@link MapLineFields})
|
|
607
|
+
* @returns A `MapLineType` value
|
|
608
|
+
*
|
|
609
|
+
* @example
|
|
610
|
+
* ```ts
|
|
611
|
+
* Map.line({ key: "move", points: [Map.at(-34.905, 138.6), Map.at(-34.852, 138.6)], style: Map.dashed({ tone: "brand" }), arrow: true })
|
|
612
|
+
* ```
|
|
613
|
+
*/
|
|
614
|
+
line,
|
|
615
|
+
/**
|
|
616
|
+
* Builds a `solid` line style.
|
|
617
|
+
*
|
|
618
|
+
* @param config - Optional stroke configuration (`tone`, `weight`)
|
|
619
|
+
* @returns A `MapLineStyleType` value
|
|
620
|
+
*
|
|
621
|
+
* @example
|
|
622
|
+
* ```ts
|
|
623
|
+
* Map.solid({ tone: "brand" })
|
|
624
|
+
* ```
|
|
625
|
+
*/
|
|
626
|
+
solid,
|
|
627
|
+
/**
|
|
628
|
+
* Builds a `dashed` line style.
|
|
629
|
+
*
|
|
630
|
+
* @param config - Optional stroke configuration (`tone`, `weight`)
|
|
631
|
+
* @returns A `MapLineStyleType` value
|
|
632
|
+
*
|
|
633
|
+
* @example
|
|
634
|
+
* ```ts
|
|
635
|
+
* Map.dashed({ tone: "brand" })
|
|
636
|
+
* ```
|
|
637
|
+
*/
|
|
638
|
+
dashed,
|
|
639
|
+
/**
|
|
640
|
+
* Builds a `point` camera target.
|
|
641
|
+
*
|
|
642
|
+
* @param center - The centre
|
|
643
|
+
* @param zoom - The zoom level to settle at
|
|
644
|
+
* @returns A `MapFocusType` value
|
|
645
|
+
*
|
|
646
|
+
* @example
|
|
647
|
+
* ```ts
|
|
648
|
+
* Map.point(Map.at(-34.9258, 138.5994), 14n)
|
|
649
|
+
* ```
|
|
650
|
+
*/
|
|
651
|
+
point,
|
|
652
|
+
/**
|
|
653
|
+
* Builds a `bounds` camera target.
|
|
654
|
+
*
|
|
655
|
+
* @param sw - South-west corner
|
|
656
|
+
* @param ne - North-east corner
|
|
657
|
+
* @returns A `MapFocusType` value
|
|
658
|
+
*
|
|
659
|
+
* @example
|
|
660
|
+
* ```ts
|
|
661
|
+
* Map.bounds(Map.at(-34.95, 138.55), Map.at(-34.80, 138.65))
|
|
662
|
+
* ```
|
|
663
|
+
*/
|
|
664
|
+
bounds,
|
|
665
|
+
/**
|
|
666
|
+
* Builds a positioned overlay child for the `overlays` slot.
|
|
667
|
+
*
|
|
668
|
+
* @param content - The East child tree (a HUD, legend, back button)
|
|
669
|
+
* @param options - Anchor / offset / interactivity options
|
|
670
|
+
* @returns A `MapOverlayType` value
|
|
671
|
+
*
|
|
672
|
+
* @example
|
|
673
|
+
* ```ts
|
|
674
|
+
* Map.overlay(Text.Root("ELARA"), { align: "start", verticalAlign: "start", key: "hud" })
|
|
675
|
+
* ```
|
|
676
|
+
*/
|
|
677
|
+
overlay,
|
|
678
|
+
Types: {
|
|
679
|
+
/**
|
|
680
|
+
* East StructType for the Map component.
|
|
681
|
+
*
|
|
682
|
+
* @remarks
|
|
683
|
+
* See {@link MapRootType} for per-field docs.
|
|
684
|
+
*
|
|
685
|
+
* @property tiles - Basemap source
|
|
686
|
+
* @property center - Initial centre
|
|
687
|
+
* @property zoom - Initial zoom
|
|
688
|
+
* @property areas - Filled boundaries
|
|
689
|
+
* @property markers - Pins
|
|
690
|
+
* @property overlays - Positioned East children
|
|
691
|
+
*/
|
|
692
|
+
Map: MapRootType,
|
|
693
|
+
/**
|
|
694
|
+
* A geographic point.
|
|
695
|
+
*
|
|
696
|
+
* @property lat - Latitude in degrees
|
|
697
|
+
* @property lng - Longitude in degrees
|
|
698
|
+
*/
|
|
699
|
+
LatLng: MapLatLngType,
|
|
700
|
+
/**
|
|
701
|
+
* Theme tone for areas / hexes / markers / lines.
|
|
702
|
+
*
|
|
703
|
+
* @property brand - Brand teal
|
|
704
|
+
* @property ink - Foreground ink
|
|
705
|
+
* @property muted - Muted foreground
|
|
706
|
+
* @property success - Status ok
|
|
707
|
+
* @property warning - Status warn
|
|
708
|
+
* @property danger - Status bad
|
|
709
|
+
*/
|
|
710
|
+
Tone: MapToneType,
|
|
711
|
+
/**
|
|
712
|
+
* CARTO basemap preset.
|
|
713
|
+
*
|
|
714
|
+
* @property positron - Light base
|
|
715
|
+
* @property darkMatter - Dark base
|
|
716
|
+
* @property voyager - Colour base
|
|
717
|
+
*/
|
|
718
|
+
CartoStyle: MapCartoStyleType,
|
|
719
|
+
/**
|
|
720
|
+
* Basemap source (`carto` / `osm` / `custom`).
|
|
721
|
+
*
|
|
722
|
+
* @property carto - A CARTO raster preset
|
|
723
|
+
* @property osm - OpenStreetMap raster tiles
|
|
724
|
+
* @property custom - A raw XYZ template with attribution
|
|
725
|
+
*/
|
|
726
|
+
Tile: MapTileType,
|
|
727
|
+
/**
|
|
728
|
+
* Camera target (`point` / `bounds`).
|
|
729
|
+
*
|
|
730
|
+
* @property point - Centre on a point at a zoom level
|
|
731
|
+
* @property bounds - Frame a south-west / north-east box
|
|
732
|
+
*/
|
|
733
|
+
Focus: MapFocusType,
|
|
734
|
+
/**
|
|
735
|
+
* Area boundary (`hexDisk` / `polygon` / `cells`).
|
|
736
|
+
*
|
|
737
|
+
* @property hexDisk - A `gridDisk(origin, k)` blob
|
|
738
|
+
* @property polygon - An explicit ring of points
|
|
739
|
+
* @property cells - Explicit H3 cell ids
|
|
740
|
+
*/
|
|
741
|
+
AreaShape: MapAreaShapeType,
|
|
742
|
+
/**
|
|
743
|
+
* A resolved area.
|
|
744
|
+
*
|
|
745
|
+
* @property key - Area identity
|
|
746
|
+
* @property shape - The boundary
|
|
747
|
+
* @property status - Optional status (drives colour + pulse)
|
|
748
|
+
* @property flyTo - Optional click camera target
|
|
749
|
+
*/
|
|
750
|
+
Area: MapAreaType,
|
|
751
|
+
/**
|
|
752
|
+
* The hex layer (lattice + per-cell detail).
|
|
753
|
+
*
|
|
754
|
+
* @property lattice - Optional faint background lattice
|
|
755
|
+
* @property cells - Per-cell detail
|
|
756
|
+
* @property tone - Optional lattice stroke tone
|
|
757
|
+
*/
|
|
758
|
+
Hex: MapHexLayerType,
|
|
759
|
+
/**
|
|
760
|
+
* A resolved marker.
|
|
761
|
+
*
|
|
762
|
+
* @property key - Marker identity
|
|
763
|
+
* @property at - The pin location
|
|
764
|
+
* @property minZoom - Optional LOD gate
|
|
765
|
+
*/
|
|
766
|
+
Marker: MapMarkerType,
|
|
767
|
+
/**
|
|
768
|
+
* Line render style (`solid` / `dashed`).
|
|
769
|
+
*
|
|
770
|
+
* @property solid - A solid connector
|
|
771
|
+
* @property dashed - A dashed / routing connector
|
|
772
|
+
*/
|
|
773
|
+
LineStyle: MapLineStyleType,
|
|
774
|
+
/**
|
|
775
|
+
* A resolved line.
|
|
776
|
+
*
|
|
777
|
+
* @property key - Line identity
|
|
778
|
+
* @property points - The polyline points
|
|
779
|
+
* @property style - Render style
|
|
780
|
+
* @property flow - Optional animated dash-offset
|
|
781
|
+
*/
|
|
782
|
+
Line: MapLineType,
|
|
783
|
+
/**
|
|
784
|
+
* A resolved standalone label.
|
|
785
|
+
*
|
|
786
|
+
* @property key - Label identity
|
|
787
|
+
* @property at - The anchor
|
|
788
|
+
* @property text - The text
|
|
789
|
+
*/
|
|
790
|
+
Label: MapLabelType,
|
|
791
|
+
/**
|
|
792
|
+
* The overlay slot value.
|
|
793
|
+
*
|
|
794
|
+
* @property content - The East child tree
|
|
795
|
+
* @property align - Horizontal screen anchor
|
|
796
|
+
* @property verticalAlign - Vertical screen anchor
|
|
797
|
+
* @property geoAnchor - Optional coordinate anchor
|
|
798
|
+
*/
|
|
799
|
+
Overlay: MapOverlayType,
|
|
800
|
+
},
|
|
801
|
+
};
|
|
802
|
+
//# sourceMappingURL=index.js.map
|