@nika-js/onlymap 0.4.0 → 0.4.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.
@@ -154,6 +154,10 @@
154
154
  "name": "terrain-texture",
155
155
  "description": "Optional {z}/{x}/{y} imagery template draped over the surface (satellite, etc.)."
156
156
  },
157
+ {
158
+ "name": "widget-style",
159
+ "description": "Layout-token sugar: space-separated key:number pairs → --om-widget-* custom properties (e.g. \"gap:10 opacity:0.9\"). Keys: inset, gap (shorthands), inset-x/-y, gap-x/-y, opacity, radius, size. Numbers are px except opacity."
160
+ },
157
161
  {
158
162
  "name": "validate",
159
163
  "description": "Run manifest validation and show the on-page error panel."
@@ -1644,8 +1648,35 @@
1644
1648
  },
1645
1649
  {
1646
1650
  "name": "position",
1647
- "description": "Corner placement.",
1651
+ "description": "Managed slot (8 logical, RTL-aware: top/center/bottom × start/center/end minus center-center), a legacy corner alias (top-left, …), or \"manual\" (author-styled placement — plain block, no forced positioning). Same-slot widgets stack with flush edges and a shared gap.",
1648
1652
  "values": [
1653
+ {
1654
+ "name": "top-start"
1655
+ },
1656
+ {
1657
+ "name": "top-center"
1658
+ },
1659
+ {
1660
+ "name": "top-end"
1661
+ },
1662
+ {
1663
+ "name": "center-start"
1664
+ },
1665
+ {
1666
+ "name": "center-end"
1667
+ },
1668
+ {
1669
+ "name": "bottom-start"
1670
+ },
1671
+ {
1672
+ "name": "bottom-center"
1673
+ },
1674
+ {
1675
+ "name": "bottom-end"
1676
+ },
1677
+ {
1678
+ "name": "manual"
1679
+ },
1649
1680
  {
1650
1681
  "name": "top-left"
1651
1682
  },
@@ -1660,6 +1691,10 @@
1660
1691
  }
1661
1692
  ]
1662
1693
  },
1694
+ {
1695
+ "name": "order",
1696
+ "description": "Deterministic in-slot ordering (flex order; lower renders first). Default: DOM order."
1697
+ },
1663
1698
  {
1664
1699
  "name": "watch",
1665
1700
  "description": "Space-separated watch tokens: viewport, selection, layers, history, basemap, lighting, terrain, data:<layerId>."
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nika-js/onlymap",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Declarative deck.gl maps for HTML and React — interactive WebGL mapping with GeoJSON/CSV/Arrow data, MapLibre basemaps, widgets, popups, and live streams from a custom-element manifest or typed React components. TypeScript, no build step.",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "publishConfig": {
@@ -113,6 +113,7 @@
113
113
  "prepublishOnly": "npm run build",
114
114
  "try": "vite-node dev/expr-repl.mjs",
115
115
  "test:e2e": "playwright test",
116
+ "check-layout": "playwright test e2e/layout-audit.spec.ts",
116
117
  "gen:html-data": "vite-node dev/generate-html-data.ts",
117
118
  "gen:public": "npm run gen:html-data && vite-node dev/build-public.ts",
118
119
  "test:public": "npm run gen:public -- --dry-run --strict",
@@ -23,7 +23,7 @@ Use OnlyMapJS as a declarative HTML map library. Write custom elements such as `
23
23
  </script>
24
24
  ```
25
25
 
26
- For no-build CDN pages, use the single-file standalone bundle from a raw-file CDN — `https://unpkg.com/@nika-js/onlymap@0.4.0` (the bare package URL serves `dist/onlymap.standalone.js`) — plus `<link rel="stylesheet" href="https://unpkg.com/@nika-js/onlymap@0.4.0/dist/onlymapjs.css">`. Never a rebundling CDN (esm.sh, skypack): re-bundling duplicates the deck.gl/luma.gl runtime and every layer fails shader compilation.
26
+ For no-build CDN pages, use the single-file standalone bundle from a raw-file CDN — `https://unpkg.com/@nika-js/onlymap@0.4.1` (the bare package URL serves `dist/onlymap.standalone.js`) — plus `<link rel="stylesheet" href="https://unpkg.com/@nika-js/onlymap@0.4.1/dist/onlymapjs.css">`. Never a rebundling CDN (esm.sh, skypack): re-bundling duplicates the deck.gl/luma.gl runtime and every layer fails shader compilation.
27
27
 
28
28
  ## React Projects
29
29
 
@@ -48,9 +48,9 @@ function StatsPanel({ onToggle }) {
48
48
 
49
49
  ## Component surface
50
50
 
51
- - **`<OmMap>`** — `center`/`zoom`/`pitch`/`bearing` (initial; later changes move the camera, unchanged props never fight user panning), `basemap`, `headless`, `onReady`, `onViewStateChange`, `onRuntimeError`. Give it a size via `style`/`className`. `ref` exposes the imperative `MapController` handle: `flyTo`, `setView`, `emit`, `getLayers`, `getSelection`, `injectPick`, `ready` (promise), `project`.
51
+ - **`<OmMap>`** — `center`/`zoom`/`pitch`/`bearing` (initial; later changes move the camera, unchanged props never fight user panning), `basemap`, `headless`, `widgetStyle` (layout-token sugar, the `widget-style` attribute's twin: `"gap:10 opacity:0.9"` → `--om-widget-*` custom properties), `onReady`, `onViewStateChange`, `onRuntimeError`. Give it a size via `style`/`className`. `ref` exposes the imperative `MapController` handle: `flyTo`, `setView`, `emit`, `getLayers`, `getSelection`, `injectPick`, `ready` (promise), `project`.
52
52
  - **`<OmLayer>`** — `id` + `type` (any registered deck.gl layer type) + deck props. `data`: stable inline reference or URL string (full Data Layer: CSV/Arrow/Shapefile/KML formats, `ws(s)://` streams via `source`/`streamKey`/`flush`, `refresh` polling). `label`/`color` feed `ctx.layers`; `filterField`/`filterRange` = GPU filter; `onClick`/`onHover` receive the flattened picked object (`onHover(null)` = pointer left).
53
- - **`<OmWidget>`** — positioning shell: `position="top-left|top-right|bottom-left|bottom-right"` + arbitrary JSX. Widgets sharing a corner stack.
53
+ - **`<OmWidget>`** — positioning shell: `position` takes one of 8 managed slots (logical, RTL-aware: `top-start|top-center|top-end|center-start|center-end|bottom-start|bottom-center|bottom-end`; legacy corners `top-left` etc. alias) + arbitrary JSX. Same-slot widgets stack with flush edges and a shared gap; `order={1}` sets deterministic in-slot ordering. `position="manual"` renders a plain block at the JSX site — note it sits inside OmMap's overflow-hidden box, so for UI OUTSIDE the map render your own element next to `<OmMap>` and drive the map via `useOmMap()`/the ref instead.
54
54
  - **`<OmOverlay>`** — geo-anchored HTML with managed projection/tracking/culling. `anchor={[lng, lat]}` or `anchorFrom="selection"` (+ `layer` to scope which picks move it); children may be `(selection) => JSX`; `anchorOffset` (default `bottom-center`); `interactive={false}` for hover-following tooltips.
55
55
  - **`useOmMap(watch?)`** — the same `ctx` contract HTML widget scripts get, typed: `layers`, `viewport`, `selection`, `emit`, `data()`, `dataInViewport()`, `stats()`. Watch tokens: `"viewport"`, `"selection"`, `"layers"`, `"data:<layerId>"`. Rides `useSyncExternalStore` (tearing-safe; `ctx` identity stable until a watched token fires).
56
56
  - **`controller.getStore(token)`** — framework-free `{subscribe, getSnapshot}` per watch token (cached plain-data snapshots; viewport snapshots carry `origin: "user"|"programmatic"` for echo-free two-way binding). Use it to sync map state into Redux/MobX/Zustand/Jotai — recipes in docs/external-stores.md; never mirror row arrays into a store (use the `data:<id>` version stamp + `ctx.data()`).
@@ -213,7 +213,7 @@ Built-ins:
213
213
  - `lighting` — scene-lighting controller: preset radios (Off/daylight/studio/flat/custom) + ambient/sun/azimuth/elevation/camera sliders, all over the lighting* attributes via `set-lighting` (undoable; re-syncs when anything else writes them). A bare preset click is a clean RESET (stale lighting-* overrides removed); a slider edit flips to `custom` and sets only the touched key.
214
214
  - `undo-redo` — undo/redo buttons over the manifest history (layer toggles, filters, basemap switches, element edits, drawn sketches). Keyboard works without the widget: Cmd/Ctrl-Z, Shift-Cmd/Ctrl-Z, Ctrl-Y. Camera moves, hover effects, and story playback are not undo steps.
215
215
 
216
- Positions: `top-left`, `top-right`, `bottom-left`, `bottom-right`.
216
+ Positions — 8 managed slots (logical, RTL-aware): `top-start`, `top-center`, `top-end`, `center-start`, `center-end`, `bottom-start`, `bottom-center`, `bottom-end`. Legacy corner names (`top-left`, `top-right`, `bottom-left`, `bottom-right`) are aliases. Same-slot widgets stack in one library-owned flex container: flush edges, shared gap — never overlapping. `order="1"` sets deterministic in-slot ordering (default: DOM order). `position="manual"` opts out of management: the widget renders as a plain block you place with your own CSS (even outside the map, e.g. in an app header, driving the map through actions). Layout tokens: `--om-widget-inset-x/-y` (slot inset, default 12px), `--om-widget-gap-x/-y` (stack gap, default 8px), `--om-widget-opacity`, `--om-widget-radius` — or the no-CSS sugar attribute `<om-map widget-style="gap:10 opacity:0.9 inset:16">` (keys: inset, gap, inset-x/-y, gap-x/-y, opacity, radius, size; numbers are px except opacity).
217
217
 
218
218
  Theming: built-in widgets read `--om-widget-*` CSS custom properties, which inherit through their shadow roots — so plain page CSS themes them, no JS:
219
219