@nika-js/onlymap 0.1.1 → 0.2.1

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.
Files changed (40) hide show
  1. package/.vscode/onlymap.code-snippets +4 -4
  2. package/README.md +28 -6
  3. package/dist/attribute-resolution.d.ts +39 -0
  4. package/dist/{basemap-D95W0IIA.js → basemap-COurZNDH.js} +2126 -2105
  5. package/dist/basemap-registry.d.ts +49 -0
  6. package/dist/basemap.d.ts +22 -2
  7. package/dist/html-data.d.ts +2 -2
  8. package/dist/{index-Do7hmHwi.js → index-COu-3-gN.js} +1 -1
  9. package/dist/{index-D74olQ9w.js → index-CgyAD98B.js} +1 -1
  10. package/dist/{index-CU-iOTdr.js → index-CvfuISOc.js} +14602 -14137
  11. package/dist/{index-C9w78NS9.js → index-D-X8KPA1.js} +1 -1
  12. package/dist/{index-BFjXVHly.js → index-DuvXK95V.js} +2 -2
  13. package/dist/index.d.ts +10 -0
  14. package/dist/ir-diff.d.ts +16 -0
  15. package/dist/onlymapjs.js +29 -24
  16. package/dist/onlymapjs.umd.cjs +265 -259
  17. package/dist/programmatic.d.ts +186 -0
  18. package/dist/react/context.d.ts +25 -0
  19. package/dist/react/index.d.ts +20 -0
  20. package/dist/react/om-layer.d.ts +38 -0
  21. package/dist/react/om-map.d.ts +33 -0
  22. package/dist/react/om-overlay.d.ts +27 -0
  23. package/dist/react/om-widget.d.ts +9 -0
  24. package/dist/react/use-om-map.d.ts +2 -0
  25. package/dist/react.js +280 -0
  26. package/dist/runtime-core.d.ts +34 -1
  27. package/dist/widget-registry.d.ts +2 -0
  28. package/docs/3d-assets.md +74 -0
  29. package/docs/basemaps.md +89 -0
  30. package/docs/live-data.md +83 -0
  31. package/docs/react.md +120 -0
  32. package/docs/stories.md +134 -0
  33. package/docs/testing.md +165 -0
  34. package/llms.txt +8 -4
  35. package/onlymapjs.html-data.json +57 -1
  36. package/package.json +24 -2
  37. package/skills/onlymapjs/SKILL.md +15 -3
  38. package/skills/onlymapjs/references/patterns.md +2 -2
  39. package/skills/onlymapjs/references/react.md +68 -0
  40. package/skills/onlymapjs/references/syntax.md +6 -2
@@ -10,8 +10,8 @@
10
10
  " <meta charset=\"utf-8\" />",
11
11
  " <title>${1:My map}</title>",
12
12
  " <script type=\"module\">",
13
- " import \"onlymapjs\";",
14
- " import \"onlymapjs/onlymapjs.css\";",
13
+ " import \"@nika-js/onlymap\";",
14
+ " import \"@nika-js/onlymap/onlymapjs.css\";",
15
15
  " </script>",
16
16
  "</head>",
17
17
  "<body>",
@@ -55,8 +55,8 @@
55
55
  " <meta charset=\"utf-8\" />",
56
56
  " <title>${1:My map}</title>",
57
57
  " <script type=\"module\">",
58
- " import \"onlymapjs\";",
59
- " import \"onlymapjs/onlymapjs.css\";",
58
+ " import \"@nika-js/onlymap\";",
59
+ " import \"@nika-js/onlymap/onlymapjs.css\";",
60
60
  " </script>",
61
61
  "</head>",
62
62
  "<body>",
package/README.md CHANGED
@@ -54,9 +54,9 @@ Five elements, one rule: **attributes are kebab-case versions of deck.gl props**
54
54
 
55
55
  | Element | Role |
56
56
  |---|---|
57
- | `<om-map>` | The map. `center`, `zoom`, `pitch`, `bearing`; `basemap="maplibre"` (default style or any style URL no token) or `"none"` (standalone canvas); `validate` for a live on-page error panel. |
57
+ | `<om-map>` | The map. `center`, `zoom`, `pitch`, `bearing`; `basemap` takes a free preset (`positron`, `liberty`, `dark-matter`, `osm`, ), a style URL, or `"none"` (standalone canvas) — and switches **live**; `validate` for a live on-page error panel. |
58
58
  | `<om-layer>` | Any of **33 layer types** by name — all of deck.gl's core, geo, aggregation, and mesh layers (Scatterplot, GeoJson, Arc, Path, Heatmap, Hexagon, Trips, Tile, Tile3D, Scenegraph, …) plus the built-in `PopupLayer` for WebGL badges/labels at scale. `id` required; `label`/`color` feed the legend. |
59
- | `<om-widget>` | UI panels. Built-ins: `legend`, `layer-switcher`, `zoom-controls`, `scale-bar`, `attribution`, `filter`, `draw`, `vega-lite` (live charts). Or write your own inline with HTML + a `<script type="om/widget">`. |
59
+ | `<om-widget>` | UI panels. Built-ins: `legend`, `layer-switcher`, `basemap-switcher`, `zoom-controls`, `scale-bar`, `attribution`, `filter`, `draw`, `vega-lite` (live charts). Or write your own inline with HTML + a `<script type="om/widget">`. |
60
60
  | `<om-overlay>` | Rich HTML anchored to a map location — a static `anchor="[lng, lat]"`, the current selection, or a feature's own geometry via `anchor-layer`/`anchor-feature-id`. `{{field}}` interpolates the picked feature, HTML-escaped by default. |
61
61
  | `<om-behavior>` | Declarative interactions: `on="click|hover|drag|load|data-loaded"` → a named action. |
62
62
  | `<om-story>` | A storyboard: `<om-step>` children fire actions on a timeline. Controlled by the `player` widget, behaviors, or `storyEl.play()/pause()/seek()`. |
@@ -93,7 +93,9 @@ Private endpoints: `OmMap.configureData({ headers, credentials, fetch })` — ap
93
93
 
94
94
  ### Interaction
95
95
 
96
- Ten built-in actions wire to picks, widget buttons (`data-emit`), or script (`ctx.emit`) with one shared payload contract: `show-overlay`, `hide-overlay`, `show-tooltip`, `hide-tooltip`, `toggle-layer`, `highlight-feature`, `zoom-to-feature`, `filter-layer`, `zoom-in`, `zoom-out` — plus `OmMap.registerAction` for your own.
96
+ Built-in actions wire to picks, widget buttons (`data-emit`), or script (`ctx.emit`) with one shared payload contract: `show-overlay`, `hide-overlay`, `show-tooltip`, `hide-tooltip`, `toggle-layer`, `highlight-feature`, `zoom-to-feature`, `filter-layer`, `set-basemap`, `zoom-in`, `zoom-out` — plus `OmMap.registerAction` for your own.
97
+
98
+ **Basemaps:** free presets out of the box — OpenFreeMap `liberty`/`bright`/`positron` (no key, no limits), CARTO `dark-matter`/`voyager`, classic `osm` raster, and keyed `maptiler-*` presets (MapTiler's style editor is the visual way to customize basemap JSON; keys are publishable, via `basemap-key` or `OmMap.configureBasemap`). The `basemap` attribute switches **live** — camera and layers survive — from a hand edit, the `set-basemap` action, or `<om-widget type="basemap-switcher">`. Add your own with `OmMap.registerBasemap(name, { style })`; required attribution renders automatically. Guide: [docs/basemaps.md](docs/basemaps.md).
97
99
 
98
100
  **Animation:** camera moves accept a duration — `map.flyTo(coords, zoom, { duration: 1200, curve: true })`, or the `fly-to` action (`center`/`zoom`/`pitch`/`bearing`/`duration`) from any behavior or button; `prefers-reduced-motion` is honored (moves become instant, final state identical). Per-prop GPU transitions via the `transition` attribute: `transition="get-fill-color 800ms"` fades color changes; on a streaming layer, `transition="get-position 300ms"` makes entities glide between updates.
99
101
 
@@ -105,6 +107,25 @@ GPU filtering is declarative — `filter-field="magnitude" filter-range="[4,10]"
105
107
 
106
108
  Custom widget scripts receive `ctx`: layer metadata, `viewport` (bounds/zoom/project), the current `selection`, `emit()`, and data access — `ctx.data(id)`, `ctx.dataInViewport(id)`, `ctx.stats(id, field)` (count/min/max/mean/stddev/percentiles/histogram, viewport-scoped on request). Declare `watch` tokens (`data:quakes viewport selection layers`) and the runtime re-renders you only when relevant state changes. `vegaEmbed` and `d3` are available as globals for charts.
107
109
 
110
+ ## React
111
+
112
+ The same engine, as real components — `@nika-js/onlymap/react` (React ≥ 18, optional peer). No `om-*` elements are rendered, so React and the library never fight over the DOM: components feed a typed programmatic front-end that produces the same layer IR the HTML manifest does. Accessors are plain functions (no expression language), interactions are event handlers, and `useOmMap()` is the widget `ctx` contract as a fully-typed hook:
113
+
114
+ ```tsx
115
+ import { OmMap, OmLayer, OmWidget, OmOverlay, useOmMap } from "@nika-js/onlymap/react";
116
+
117
+ <OmMap center={[-119, 36]} zoom={5} basemap="maplibre">
118
+ <OmLayer id="quakes" type="ScatterplotLayer" data={features} pickable
119
+ getPosition={d => [d.lon, d.lat]}
120
+ getFillColor={d => (d.mag >= 6 ? [214, 40, 40] : [252, 191, 73])}
121
+ onClick={sel => setSelected(sel.object)} />
122
+ <OmWidget position="top-left"><StatsPanel /></OmWidget>
123
+ <OmOverlay anchorFrom="selection">{sel => sel && <Card feature={sel.object} />}</OmOverlay>
124
+ </OmMap>
125
+ ```
126
+
127
+ `<OmOverlay>` manages projection, per-frame tracking, and off-screen culling for you; `<OmMap headless>` makes the whole tree testable in jsdom/happy-dom. Full guide: [docs/react.md](docs/react.md).
128
+
108
129
  ## Editor IntelliSense
109
130
 
110
131
  `onlymapjs.html-data.json` (generated from the layer registry — `npm run gen:html-data`) gives autocomplete and hover docs for every `om-*` element and attribute in VS Code and any editor speaking the [html-customData](https://github.com/microsoft/vscode-custom-data) format:
@@ -171,18 +192,19 @@ Plus `OmMap.snapshotIR(html)` to lock down what a manifest *means* in a snapshot
171
192
 
172
193
  ## Programmatic surface
173
194
 
174
- - **`OmMap.*`** — `validate`, `snapshotIR`, `registerLayer`, `registerWidget`, `registerAction`, `registerSource`, `registerFormat`, `configureData`, `getLayerSchema`
195
+ - **`OmMap.*`** — `validate`, `snapshotIR`, `registerLayer`, `registerWidget`, `registerAction`, `registerSource`, `registerFormat`, `registerBasemap`, `configureBasemap`, `configureData`, `getLayerSchema`
175
196
  - **On a `<om-map>` element** — `ready` (promise), `flyTo(coords, zoom?)`, `setLayerVisible(id, bool)`, `getLayers()`, `emit(action, payload)`; `document.querySelector("om-map")` is fully typed
197
+ - **`MapController`** — the framework-grade programmatic front-end (typed `LayerDescriptor`s → the same reconcile core, no DOM manifest): `setLayers`, `watch`, `emit`, camera methods, `injectPick`, `ready`. The React adapter rides it; usable directly from vanilla TS or other frameworks
176
198
  - **Testing** — `mountForTest`, and imports are SSR-safe (importing in Node/jsdom never touches browser globals)
177
199
 
178
200
  ## Not implemented yet (honestly)
179
201
 
180
- Mapbox GL basemaps, depth-interleaved 3D compositing, globe projection, SSE transport, multi-field filters, `dblclick` behaviors, the `transform` data pipeline, and the React adapter / typed builder.
202
+ Mapbox GL basemaps, depth-interleaved 3D compositing, globe projection, SSE transport, multi-field filters, `dblclick` behaviors, the `transform` data pipeline, the typed fluent builder, and stories/draw as React components (both work via the HTML manifest).
181
203
 
182
204
  ## Going deeper
183
205
 
184
206
  | | |
185
207
  |---|---|
186
- | [docs/testing.md](docs/testing.md) · [docs/live-data.md](docs/live-data.md) · [docs/3d-assets.md](docs/3d-assets.md) · [docs/stories.md](docs/stories.md) | Consumer guides |
208
+ | [docs/react.md](docs/react.md) · [docs/basemaps.md](docs/basemaps.md) · [docs/testing.md](docs/testing.md) · [docs/live-data.md](docs/live-data.md) · [docs/3d-assets.md](docs/3d-assets.md) · [docs/stories.md](docs/stories.md) | Consumer guides |
187
209
  | [llms.txt](llms.txt) | The agent-facing quick reference |
188
210
  | `skills/onlymapjs` | Installable LLM skill for OnlyMapJS authoring |
@@ -24,6 +24,45 @@ export declare const RESERVED_ATTRS: Set<string>;
24
24
  * dimensions" case is a documented future extension.
25
25
  */
26
26
  export declare const FILTER_ATTRS: Set<string>;
27
+ /** Already-coerced filter declaration — attribute strings (DOM front-end) or typed values (programmatic front-end). */
28
+ export interface LayerFilterSpec {
29
+ filterField?: string;
30
+ filterRange?: [number, number];
31
+ filterSoftRange?: [number, number];
32
+ filterCategoryField?: string;
33
+ filterCategories?: unknown[];
34
+ }
35
+ /**
36
+ * GPU filter wiring (spec: "Filtering"), shared by both front-ends (HU2).
37
+ * `filterRange` is a plain prop (not an accessor): the filter-layer action
38
+ * just rewrites its attribute, which flows through the normal reconcile ->
39
+ * deck.gl setProps() diff as a cheap uniform update, never touching
40
+ * updateTriggers.
41
+ *
42
+ * EVERY layer mounts the extension at birth, filtered or not: adding or
43
+ * removing an extension on a LIVE layer recompiles shaders and corrupts
44
+ * attribute state (the per-feature-trace washed-out-fill bug), while an
45
+ * idle numeric slot is free — deck's default getFilterValue is the
46
+ * CONSTANT 0 (no attribute buffer) inside the default filterRange
47
+ * [-1, 1], so nothing is culled. A later filter-layer action then only
48
+ * swaps accessor + range props on the same shaders. The category slot is
49
+ * NOT pre-mounted: an idle categorySize binds a uint attribute against a
50
+ * float constant (GL_INVALID_OPERATION in real WebGL), so declaring a
51
+ * category filter re-mounts the extension — churn accepted for the rare
52
+ * case, never for the common numeric one.
53
+ *
54
+ * The unfiltered baseline is a FUNCTION accessor (a buffer of zeros, 4
55
+ * bytes/row) plus a baseline trigger — never deck's constant-0 default.
56
+ * Two empirically-found deck behaviors force this: trigger keys absent
57
+ * from the NEW props aren't diffed (a cleared patch would keep its stale
58
+ * buffer), and a buffer→constant accessor transition doesn't rebind the
59
+ * vertex attribute (the attribute state SAYS constant 0, the GPU still
60
+ * draws the old buffer). Function→function with a trigger change is the
61
+ * one transition that recomputes reliably, so every state a layer can
62
+ * reach — unfiltered, authored filter, runtime populate sweep — is
63
+ * buffer-backed.
64
+ */
65
+ export declare function applyFilterWiring(props: Record<string, unknown>, updateTriggers: Record<string, string>, shape: Shape, spec: LayerFilterSpec, warnLabel: string): LayerFilter | undefined;
27
66
  /**
28
67
  * Standard global HTML attributes an author (or the library itself, e.g.
29
68
  * OmLayerElement setting `style.display = "none"`) may set for reasons