@nika-js/onlymap 0.1.1 → 0.2.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.
@@ -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
@@ -105,6 +105,25 @@ GPU filtering is declarative — `filter-field="magnitude" filter-range="[4,10]"
105
105
 
106
106
  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
107
 
108
+ ## React
109
+
110
+ 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:
111
+
112
+ ```tsx
113
+ import { OmMap, OmLayer, OmWidget, OmOverlay, useOmMap } from "@nika-js/onlymap/react";
114
+
115
+ <OmMap center={[-119, 36]} zoom={5} basemap="maplibre">
116
+ <OmLayer id="quakes" type="ScatterplotLayer" data={features} pickable
117
+ getPosition={d => [d.lon, d.lat]}
118
+ getFillColor={d => (d.mag >= 6 ? [214, 40, 40] : [252, 191, 73])}
119
+ onClick={sel => setSelected(sel.object)} />
120
+ <OmWidget position="top-left"><StatsPanel /></OmWidget>
121
+ <OmOverlay anchorFrom="selection">{sel => sel && <Card feature={sel.object} />}</OmOverlay>
122
+ </OmMap>
123
+ ```
124
+
125
+ `<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).
126
+
108
127
  ## Editor IntelliSense
109
128
 
110
129
  `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:
@@ -173,16 +192,17 @@ Plus `OmMap.snapshotIR(html)` to lock down what a manifest *means* in a snapshot
173
192
 
174
193
  - **`OmMap.*`** — `validate`, `snapshotIR`, `registerLayer`, `registerWidget`, `registerAction`, `registerSource`, `registerFormat`, `configureData`, `getLayerSchema`
175
194
  - **On a `<om-map>` element** — `ready` (promise), `flyTo(coords, zoom?)`, `setLayerVisible(id, bool)`, `getLayers()`, `emit(action, payload)`; `document.querySelector("om-map")` is fully typed
195
+ - **`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
196
  - **Testing** — `mountForTest`, and imports are SSR-safe (importing in Node/jsdom never touches browser globals)
177
197
 
178
198
  ## Not implemented yet (honestly)
179
199
 
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.
200
+ 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
201
 
182
202
  ## Going deeper
183
203
 
184
204
  | | |
185
205
  |---|---|
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 |
206
+ | [docs/react.md](docs/react.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
207
  | [llms.txt](llms.txt) | The agent-facing quick reference |
188
208
  | `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
@@ -1,7 +1,7 @@
1
1
  var ny = Object.defineProperty;
2
2
  var sy = (_e, Q, me) => Q in _e ? ny(_e, Q, { enumerable: !0, configurable: !0, writable: !0, value: me }) : _e[Q] = me;
3
3
  var oc = (_e, Q, me) => sy(_e, typeof Q != "symbol" ? Q + "" : Q, me);
4
- import { a4 as oy, a5 as ay, a6 as ly, a7 as cy, a8 as ka, a9 as Pd, aa as ac, ab as sm, ac as uy, ad as hy, ae as dy, af as py, ag as ju, ah as Cd, ai as fy, aj as my, ak as gy, al as em, am as _y } from "./index-CU-iOTdr.js";
4
+ import { a4 as oy, a5 as ay, a6 as ly, a7 as cy, a8 as ka, a9 as ac, aa as Pd, ab as sm, ac as uy, ad as hy, ae as dy, af as py, ag as ju, ah as Cd, ai as fy, aj as my, ak as gy, al as em, am as _y } from "./index-DnvxPnDF.js";
5
5
  const Ad = Math.PI / 180, yy = 180 / Math.PI;
6
6
  function tm(_e, Q = 0) {
7
7
  const me = Math.min(180, _e) * Ad;
@@ -1,4 +1,4 @@
1
- import { a2 as _t, a3 as Ct } from "./index-CU-iOTdr.js";
1
+ import { a2 as _t, a3 as Ct } from "./index-DnvxPnDF.js";
2
2
  function Yt(e, r, t = 2, i, o = "xy") {
3
3
  const s = r && r.length, l = s ? r[0] * t : e.length;
4
4
  let c = Ut(e, 0, l, t, !0, i && i[0], o);
@@ -1,7 +1,7 @@
1
1
  var Oe = Object.defineProperty;
2
2
  var ke = (r, e, t) => e in r ? Oe(r, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[e] = t;
3
3
  var l = (r, e, t) => ke(r, typeof e != "symbol" ? e + "" : e, t);
4
- import { g as ve, a as ce, b as he, i as Fe, t as je, l as xe } from "./index-CU-iOTdr.js";
4
+ import { g as ve, a as ce, b as he, i as Fe, t as je, l as xe } from "./index-DnvxPnDF.js";
5
5
  import { ai as Ie, h as ue, au as X, a2 as W, af as fe, Y as Ne, F as Le, aR as Ue, S as Me, bP as qe } from "./recordbatch-HRu0SMKp.js";
6
6
  import { g as $, a as de, b as Ve, c as $e, d as Pe, e as He, m as ze } from "./table-accessors-DBjWgN0C.js";
7
7
  import { c as Qe } from "./convert-arrow-schema-CvZ3cT5m.js";
@@ -1,7 +1,7 @@
1
1
  var Ri = Object.defineProperty;
2
2
  var Ii = (t, a, i) => a in t ? Ri(t, a, { enumerable: !0, configurable: !0, writable: !0, value: i }) : t[a] = i;
3
3
  var N = (t, a, i) => Ii(t, typeof a != "symbol" ? a + "" : a, i);
4
- import { t as zt, $ as ca, a0 as ua, a1 as wi } from "./index-CU-iOTdr.js";
4
+ import { t as zt, $ as ca, a0 as ua, a1 as wi } from "./index-DnvxPnDF.js";
5
5
  import { c as Si } from "./convert-arrow-schema-CvZ3cT5m.js";
6
6
  import { ai as Ni, af as Nt, h as Ci, au as Pi, a2 as Oi } from "./recordbatch-HRu0SMKp.js";
7
7
  class Ti {