Compare commits

...

5 Commits

Author SHA1 Message Date
CHIIMYEN 95bf5f2c55 Fix keyboard shortcuts being ignored while the map has focus (#2157)
## Launch Checklist

 - [x] Briefly describe the changes in this PR.
 - [x] Link to related issues.
- [ ] Include before/after visuals or gifs if this PR includes visual
changes. — not applicable, nothing visual changes.
 - [x] Write tests for all new functionality.
 - [x] Add an entry to `CHANGELOG.md` under the `## main` section.

### What changed

Keyboard shortcuts went dead as soon as the map had focus.

The global `keyup` handler in `App.tsx` gated shortcuts on
`document.activeElement === document.body`. That reads like "the user is
not
typing", but it actually asks "is nothing focused at all". Clicking the
map makes
`.maplibregl-canvas` the active element, so every shortcut stopped
working until the
map was blurred.

The `m` shortcut demonstrates the problem nicely: its entire job is to
focus that
canvas, so pressing `m` silently disabled all shortcuts until `Esc`.
That path is
covered by an existing test (`'m' should focus map`), which is why the
regression
was easy to miss.

### How

`isTextEntryElement()` now answers the question the guard was reaching
for, so
shortcuts are suppressed only for text entry targets:

`input`, `textarea`, `select`, and `contenteditable` — the last one
covering the
CodeMirror editor, which is a `contenteditable` `.cm-content`.

The check stays independent of either renderer's DOM. MapLibre's
`.maplibregl-canvas` and the OpenLayers viewport live in different
structures, so an
allow-list of canvas class names would have fixed one renderer and left
the other
broken.

### Behaviour change

Single-letter shortcuts now also fire while focus is on a button or a
panel, where
previously they did not. That is inherent to making the map case work —
the old
predicate simply excluded everything that was not `document.body`. Per
@HarelM, this
can be reverted if anyone complains.

### Tests

`e2e/keyboard.spec.ts` gains a `while the map has focus` block. Its
`beforeEach`
focuses the canvas through the `m` shortcut and asserts the canvas
really is focused,
then two independent tests check that `!` and `s` still open their
modals.

Verified the new tests fail without the fix:

```
Error: expect(locator).toBeVisible() failed
Locator: locator('[data-wd-key="modal:debug"]').first()
Expected: visible
Error: element(s) not found
```

and pass with it.

Local results:

| Check | Result |
|---|---|
| `npm run lint` | clean |
| `npx vitest run` | 9 files, 50 tests passed |
| `npx vite build --mode=production` | clean |
| `npx playwright test` | 170 passed, 3 failed |

The 3 failures — `modals › open › upload via drag and drop`,
`modals › global state › remove variable` and `modals › global state ›
edit variable key`
— also fail on unmodified `main`, so they are pre-existing and unrelated
to this
change.

Fixes #940
2026-09-14 08:33:39 +03:00
dependabot[bot] 5822012b87 chore(deps): Bump maplibre-gl from 6.7.0 to 6.8.0 (#2156)
Bumps [maplibre-gl](https://github.com/maplibre/maplibre-gl-js) from
6.7.0 to 6.8.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/maplibre/maplibre-gl-js/releases">maplibre-gl's
releases</a>.</em></p>
<blockquote>
<h2>v6.8.0</h2>
<h3> Features and improvements</h3>
<ul>
<li>Add <code>map.getStyleUrl()</code>, which returns the URL the style
was loaded from, or <code>null</code> when the style was given as an
object (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/issues/7109">#7109</a>)
(by <a
href="https://github.com/bradymadden97"><code>@​bradymadden97</code></a>
and <a href="https://github.com/giswqs"><code>@​giswqs</code></a>)</li>
<li>Sample terrain render-to-texture output through mipmaps with
trilinear filtering, so draped layers stop shimmering and aliasing at
high pitch (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/pull/8328">#8328</a>,
continues <a
href="https://redirect.github.com/maplibre/maplibre-gl-js/pull/7673">#7673</a>)
(by <a
href="https://github.com/AveryanAlex"><code>@​AveryanAlex</code></a>)</li>
<li>Build the <code>Intl.Segmenter</code> instances used for text
shaping on first use instead of at import, shaving several milliseconds
off loading MapLibre on the main thread (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/pull/8337">#8337</a>)
(by <a
href="https://github.com/cherenkov"><code>@​cherenkov</code></a>)</li>
<li>Link shader programs before reading their compile status, so the
driver can overlap the compiles and the main thread waits less on shader
compilation (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/pull/8338">#8338</a>)
(by <a
href="https://github.com/cherenkov"><code>@​cherenkov</code></a>)</li>
<li>Build the default <code>Marker</code> pin once and clone it per
marker, so creating many default markers takes roughly half the
constructor time (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/pull/8340">#8340</a>)
(by <a
href="https://github.com/cherenkov"><code>@​cherenkov</code></a>)</li>
<li>Add SDF rendering support for fill patterns, using
<code>fill-color</code> as the foreground color (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/pull/7747">#7747</a>)
(by <a
href="https://github.com/bradymadden97"><code>@​bradymadden97</code></a>
and <a
href="https://github.com/deniial00"><code>@​deniial00</code></a>)</li>
<li>Warn once when the canvas is clamped to <code>maxCanvasSize</code>,
which previously lowered the rendered resolution silently (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/issues/8200">#8200</a>)
(by <a
href="https://github.com/str0kes"><code>@​str0kes</code></a>)</li>
</ul>
<h3>🐞 Bug fixes</h3>
<ul>
<li>Fix a marker's popup jumping to another world copy when the marker
is moved across the antimeridian on a zoomed-out map (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/issues/5655">#5655</a>,
<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/pull/8326">#8326</a>,
continues <a
href="https://redirect.github.com/maplibre/maplibre-gl-js/pull/5956">#5956</a>)
(by <a
href="https://github.com/yuiseki"><code>@​yuiseki</code></a>)</li>
<li>Fix terrain drape textures not being refreshed after zoom changes,
causing stale rendering at the new zoom level (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/issues/8251">#8251</a>)
(by <a href="https://github.com/patte"><code>@​patte</code></a>)</li>
<li>Fix a gap between the sky and the ground at high pitch while globe
transitions to mercator (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/issues/7382">#7382</a>)
(by <a
href="https://github.com/birkskyum"><code>@​birkskyum</code></a>)</li>
<li>Treat an empty tile response (e.g. HTTP 204) as no data: raster-DEM
tiles now load without elevation instead of failing with a <code>dem
dimension mismatch</code> error, and empty raster tiles render as
transparent (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/issues/1551">#1551</a>)
(by <a
href="https://github.com/clement-igonet"><code>@​clement-igonet</code></a>)</li>
<li>Validate the <code>before</code> layer in <code>map.moveLayer</code>
before reordering, so passing the id of a layer that does not exist
leaves the layer order untouched instead of dropping the moved layer out
of it (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/issues/8301">#8301</a>)
(by <a href="https://github.com/lazerg"><code>@​lazerg</code></a>)</li>
<li>Fix visible seams between hillshade tiles when using linear
interpolation. (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/pull/8302">#8302</a>)
(by <a
href="https://github.com/Turbo87"><code>@​Turbo87</code></a>)</li>
<li>Fix the map freezing when a render task throws an error (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/issues/6093">#6093</a>)
(by <a
href="https://github.com/UberMouse"><code>@​UberMouse</code></a>)</li>
<li>Fix <code>getCameraAltitude()</code> returning <code>NaN</code>
under <code>globe</code> and <code>vertical-perspective</code>, which
disabled marker terrain occlusion and the camera terrain check; the
altitude now follows the sphere (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/issues/6584">#6584</a>)
(by <a
href="https://github.com/bigmistqke"><code>@​bigmistqke</code></a> and
<a href="https://github.com/patte"><code>@​patte</code></a>)</li>
<li>Draw an elevated symbol on globe when the symbol itself is in view
but the ground under it is behind the horizon; occlusion now follows the
line of sight to the elevated point (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/issues/8253">#8253</a>)
(by <a
href="https://github.com/clement-igonet"><code>@​clement-igonet</code></a>)</li>
<li>Fix <code>setTiles</code> producing stale tile URLs when
<code>loadTile</code> runs in the same frame (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/pull/8323">#8323</a>)
(by <a
href="https://github.com/johncarmack1984"><code>@​johncarmack1984</code></a>
and <a
href="https://github.com/nostrorom"><code>@​nostrorom</code></a>)</li>
<li>Keep the tile under an elevated symbol from being culled near the
horizon, so a symbol with a large <code>symbol-height-offset</code>
stays visible until it is behind the planet (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/issues/8316">#8316</a>)
(by <a
href="https://github.com/clement-igonet"><code>@​clement-igonet</code></a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/maplibre/maplibre-gl-js/blob/main/CHANGELOG.md">maplibre-gl's
changelog</a>.</em></p>
<blockquote>
<h2>6.8.0</h2>
<h3> Features and improvements</h3>
<ul>
<li>Add <code>map.getStyleUrl()</code>, which returns the URL the style
was loaded from, or <code>null</code> when the style was given as an
object (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/issues/7109">#7109</a>)
(by <a
href="https://github.com/bradymadden97"><code>@​bradymadden97</code></a>
and <a href="https://github.com/giswqs"><code>@​giswqs</code></a>)</li>
<li>Sample terrain render-to-texture output through mipmaps with
trilinear filtering, so draped layers stop shimmering and aliasing at
high pitch (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/pull/8328">#8328</a>,
continues <a
href="https://redirect.github.com/maplibre/maplibre-gl-js/pull/7673">#7673</a>)
(by <a
href="https://github.com/AveryanAlex"><code>@​AveryanAlex</code></a>)</li>
<li>Build the <code>Intl.Segmenter</code> instances used for text
shaping on first use instead of at import, shaving several milliseconds
off loading MapLibre on the main thread (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/pull/8337">#8337</a>)
(by <a
href="https://github.com/cherenkov"><code>@​cherenkov</code></a>)</li>
<li>Link shader programs before reading their compile status, so the
driver can overlap the compiles and the main thread waits less on shader
compilation (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/pull/8338">#8338</a>)
(by <a
href="https://github.com/cherenkov"><code>@​cherenkov</code></a>)</li>
<li>Build the default <code>Marker</code> pin once and clone it per
marker, so creating many default markers takes roughly half the
constructor time (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/pull/8340">#8340</a>)
(by <a
href="https://github.com/cherenkov"><code>@​cherenkov</code></a>)</li>
<li>Add SDF rendering support for fill patterns, using
<code>fill-color</code> as the foreground color (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/pull/7747">#7747</a>)
(by <a
href="https://github.com/bradymadden97"><code>@​bradymadden97</code></a>
and <a
href="https://github.com/deniial00"><code>@​deniial00</code></a>)</li>
<li>Warn once when the canvas is clamped to <code>maxCanvasSize</code>,
which previously lowered the rendered resolution silently (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/issues/8200">#8200</a>)
(by <a
href="https://github.com/str0kes"><code>@​str0kes</code></a>)</li>
</ul>
<h3>🐞 Bug fixes</h3>
<ul>
<li>Fix a marker's popup jumping to another world copy when the marker
is moved across the antimeridian on a zoomed-out map (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/issues/5655">#5655</a>,
<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/pull/8326">#8326</a>,
continues <a
href="https://redirect.github.com/maplibre/maplibre-gl-js/pull/5956">#5956</a>)
(by <a
href="https://github.com/yuiseki"><code>@​yuiseki</code></a>)</li>
<li>Fix terrain drape textures not being refreshed after zoom changes,
causing stale rendering at the new zoom level (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/issues/8251">#8251</a>)
(by <a href="https://github.com/patte"><code>@​patte</code></a>)</li>
<li>Fix a gap between the sky and the ground at high pitch while globe
transitions to mercator (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/issues/7382">#7382</a>)
(by <a
href="https://github.com/birkskyum"><code>@​birkskyum</code></a>)</li>
<li>Treat an empty tile response (e.g. HTTP 204) as no data: raster-DEM
tiles now load without elevation instead of failing with a <code>dem
dimension mismatch</code> error, and empty raster tiles render as
transparent (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/issues/1551">#1551</a>)
(by <a
href="https://github.com/clement-igonet"><code>@​clement-igonet</code></a>)</li>
<li>Read the map container's dimensions before mutating it in
<code>Map#_setupContainer</code>, avoiding a forced synchronous layout
reflow on every map initialization (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/issues/8307">#8307</a>)
(by <a href="https://github.com/lazerg"><code>@​lazerg</code></a>)</li>
<li>Validate the <code>before</code> layer in <code>map.moveLayer</code>
before reordering, so passing the id of a layer that does not exist
leaves the layer order untouched instead of dropping the moved layer out
of it (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/issues/8301">#8301</a>)
(by <a href="https://github.com/lazerg"><code>@​lazerg</code></a>)</li>
<li>Fix visible seams between hillshade tiles when using linear
interpolation. (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/pull/8302">#8302</a>)
(by <a
href="https://github.com/Turbo87"><code>@​Turbo87</code></a>)</li>
<li>Fix the map freezing when a render task throws an error (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/issues/6093">#6093</a>)
(by <a
href="https://github.com/UberMouse"><code>@​UberMouse</code></a>)</li>
<li>Fix <code>getCameraAltitude()</code> returning <code>NaN</code>
under <code>globe</code> and <code>vertical-perspective</code>, which
disabled marker terrain occlusion and the camera terrain check; the
altitude now follows the sphere (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/issues/6584">#6584</a>)
(by <a
href="https://github.com/bigmistqke"><code>@​bigmistqke</code></a> and
<a href="https://github.com/patte"><code>@​patte</code></a>)</li>
<li>Draw an elevated symbol on globe when the symbol itself is in view
but the ground under it is behind the horizon; occlusion now follows the
line of sight to the elevated point (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/issues/8253">#8253</a>)
(by <a
href="https://github.com/clement-igonet"><code>@​clement-igonet</code></a>)</li>
<li>Fix <code>setTiles</code> producing stale tile URLs when
<code>loadTile</code> runs in the same frame (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/pull/8323">#8323</a>)
(by <a
href="https://github.com/johncarmack1984"><code>@​johncarmack1984</code></a>
and <a
href="https://github.com/nostrorom"><code>@​nostrorom</code></a>)</li>
<li>Keep the tile under an elevated symbol from being culled near the
horizon, so a symbol with a large <code>symbol-height-offset</code>
stays visible until it is behind the planet (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/issues/8316">#8316</a>)
(by <a
href="https://github.com/clement-igonet"><code>@​clement-igonet</code></a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/maplibre/maplibre-gl-js/commit/9df21da874e49ee4943aecb3350db9dfd98e7d1b"><code>9df21da</code></a>
Bump js version to 6.8.0 (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/issues/8371">#8371</a>)</li>
<li><a
href="https://github.com/maplibre/maplibre-gl-js/commit/05302adadc681543ee15ff60290bb70b8348a978"><code>05302ad</code></a>
fix: compute pixelsPerMeter in the transform helper so
getCameraAltitude() wo...</li>
<li><a
href="https://github.com/maplibre/maplibre-gl-js/commit/cf1781cb5ea3af00f9f9665649431d89ebd0856e"><code>cf1781c</code></a>
test: serve the browser tests' tiles and styles from local fixtures (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/issues/8367">#8367</a>)</li>
<li><a
href="https://github.com/maplibre/maplibre-gl-js/commit/055db89755ae902f4a1840308b270bc0313b0784"><code>055db89</code></a>
refactor: unify bucket dependency finalization through addFeatures (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/issues/8347">#8347</a>)</li>
<li><a
href="https://github.com/maplibre/maplibre-gl-js/commit/045a3ce58615fcb0ac155ac309bf9dbf23d1cbd6"><code>045a3ce</code></a>
Warn when the canvas is clamped to maxCanvasSize (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/issues/8275">#8275</a>)</li>
<li><a
href="https://github.com/maplibre/maplibre-gl-js/commit/d2d0371abacb40e6b8f3136af1eba5e93deecdb1"><code>d2d0371</code></a>
Keep tiles under elevated symbols from being culled near the horizon (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/issues/8319">#8319</a>)</li>
<li><a
href="https://github.com/maplibre/maplibre-gl-js/commit/0b33607be5d0ac25844696a7ba2eac1d8ea9dfe3"><code>0b33607</code></a>
chore(deps-dev): bump puppeteer from 25.9.0 to 25.10.0 (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/issues/8359">#8359</a>)</li>
<li><a
href="https://github.com/maplibre/maplibre-gl-js/commit/86d30b0234131b16d1b77681c946be53f88dc91a"><code>86d30b0</code></a>
chore(deps-dev): bump devtools-protocol from 0.0.1687809 to 0.0.1692173
(<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/issues/8354">#8354</a>)</li>
<li><a
href="https://github.com/maplibre/maplibre-gl-js/commit/9a0884f180d7f591323183ff6694af0a2805803e"><code>9a0884f</code></a>
chore(deps-dev): bump cspell from 10.2.0 to 10.2.1 (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/issues/8360">#8360</a>)</li>
<li><a
href="https://github.com/maplibre/maplibre-gl-js/commit/3d42c642babf9d31d8fea3967f62c78d1facc2c5"><code>3d42c64</code></a>
chore(deps-dev): bump postcss from 8.5.26 to 8.5.28 (<a
href="https://redirect.github.com/maplibre/maplibre-gl-js/issues/8362">#8362</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/maplibre/maplibre-gl-js/compare/v6.7.0...v6.8.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=maplibre-gl&package-manager=npm_and_yarn&previous-version=6.7.0&new-version=6.8.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-11 13:55:02 +00:00
dependabot[bot] 06b9130eba chore(deps-dev): Bump typescript-eslint from 8.69.0 to 8.70.0 (#2155)
Bumps
[typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint)
from 8.69.0 to 8.70.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/typescript-eslint/typescript-eslint/releases">typescript-eslint's
releases</a>.</em></p>
<blockquote>
<h2>v8.70.0</h2>
<h2>8.70.0 (2026-09-07)</h2>
<h3>🚀 Features</h3>
<ul>
<li><strong>eslint-plugin:</strong> [no-generated-empty-object-type] add
rule (<a
href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/12730">#12730</a>)</li>
<li><strong>website:</strong> generate per-page social preview cards (<a
href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/12734">#12734</a>)</li>
</ul>
<h3>🩹 Fixes</h3>
<ul>
<li>use stable release of pnpm 12 (<a
href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/12808">#12808</a>)</li>
<li>update pnpm to 12.3.4 and dedupe Docusaurus packages (<a
href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/12829">#12829</a>)</li>
<li><strong>eslint-plugin:</strong> [member-ordering] don't report
fields that read fields declared before them (<a
href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/12729">#12729</a>)</li>
<li><strong>eslint-plugin:</strong> [no-unnecessary-condition] no false
positive on RHS of a nested logical expression (<a
href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/12728">#12728</a>)</li>
<li><strong>eslint-plugin:</strong> [no-deprecated] report deprecated
imported values used in object shorthand properties (<a
href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/12780">#12780</a>)</li>
<li><strong>project-service:</strong> avoid discarded tsserver logs (<a
href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/12748">#12748</a>)</li>
<li><strong>typescript-estree:</strong> clarify the
parserOptions.project error message (<a
href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/12817">#12817</a>)</li>
</ul>
<h3>❤️ Thank You</h3>
<ul>
<li>Barry <a
href="https://github.com/barry166"><code>@​barry166</code></a></li>
<li>Evyatar Daud <a
href="https://github.com/StyleShit"><code>@​StyleShit</code></a></li>
<li>Josh Goldberg</li>
<li>Josh Goldberg  <a
href="https://github.com/JoshuaKGoldberg"><code>@​JoshuaKGoldberg</code></a></li>
<li>Kirk Waiblinger <a
href="https://github.com/kirkwaiblinger"><code>@​kirkwaiblinger</code></a></li>
<li>Ulrich Stark <a
href="https://github.com/ulrichstark"><code>@​ulrichstark</code></a></li>
<li>송재욱</li>
</ul>
<p>See <a
href="https://github.com/typescript-eslint/typescript-eslint/releases/tag/v8.70.0">GitHub
Releases</a> for more information.</p>
<p>You can read about our <a
href="https://typescript-eslint.io/users/versioning">versioning
strategy</a> and <a
href="https://typescript-eslint.io/users/releases">releases</a> on our
website.</p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md">typescript-eslint's
changelog</a>.</em></p>
<blockquote>
<h2>8.70.0 (2026-09-07)</h2>
<h3>🩹 Fixes</h3>
<ul>
<li><strong>eslint-plugin:</strong> [no-deprecated] report deprecated
imported values used in object shorthand properties (<a
href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/12780">#12780</a>)</li>
</ul>
<h3>❤️ Thank You</h3>
<ul>
<li>Ulrich Stark <a
href="https://github.com/ulrichstark"><code>@​ulrichstark</code></a></li>
</ul>
<p>See <a
href="https://github.com/typescript-eslint/typescript-eslint/releases/tag/v8.70.0">GitHub
Releases</a> for more information.</p>
<p>You can read about our <a
href="https://typescript-eslint.io/users/versioning">versioning
strategy</a> and <a
href="https://typescript-eslint.io/users/releases">releases</a> on our
website.</p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/typescript-eslint/typescript-eslint/commit/7ee76085c22e923c0036b8e0733a3ca7dfd82b60"><code>7ee7608</code></a>
chore(release): publish 8.70.0</li>
<li><a
href="https://github.com/typescript-eslint/typescript-eslint/commit/4586535ab24d7d5e9b3ba87e4adb8636f9314aca"><code>4586535</code></a>
fix(eslint-plugin): [no-deprecated] report deprecated imported values
used in...</li>
<li>See full diff in <a
href="https://github.com/typescript-eslint/typescript-eslint/commits/v8.70.0/packages/typescript-eslint">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=typescript-eslint&package-manager=npm_and_yarn&previous-version=8.69.0&new-version=8.70.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-11 13:55:00 +00:00
liuly 80c0d08179 Fix zoom property crash after deleting a stop (#2153)
## Launch Checklist

<!-- Thanks for the PR! Feel free to add or remove items from the
checklist. -->

When a fixed paint value is converted to a zoom function, Maputnik
creates exactly two stops.

<img width="362" height="226" alt="image"
src="https://github.com/user-attachments/assets/209aebbf-7bb3-4422-b0c7-1019e20a9ddb"
/>

Deleting either one of those two stops leaves a single remaining value.
During the transition back to the ordinary field editor, `ZoomProperty`
can render with `stops` undefined. It previously called `.map`
unconditionally, causing the editor to crash.

<img width="2551" height="1248" alt="image"
src="https://github.com/user-attachments/assets/f5c2af59-dcae-4ffe-8245-f175eea9c843"
/>

This PR guards the stop list with optional chaining. The change only
protects the render path and does not alter zoom-function conversion or
value persistence.

Now, the remaining stop's value will be restored after deleting the
other stop:

<img width="367" height="168" alt="image"
src="https://github.com/user-attachments/assets/8d13236b-6140-451b-8613-0bc5f11893de"
/>

The regression test covers `circle-opacity`:

1. Convert a fixed value to a zoom function.
2. Change the second stop's value.
3. Delete the first of the two stops.
4. Verify that the ordinary field editor reappears.
5. Verify that the remaining stop's value is restored.
6. Edit the restored field and verify that the style updates
successfully.

 - [x] Briefly describe the changes in this PR.
 - [ ] Link to related issues.
- [x] Include before/after visuals or gifs if this PR includes visual
changes.
 - [x] Write tests for all new functionality.
 - [x] Add an entry to `CHANGELOG.md` under the `## main` section.
2026-09-09 18:04:32 +03:00
dependabot[bot] 1f475cf715 chore(deps): Bump @maplibre/maplibre-gl-style-spec from 26.4.1 to 26.4.2 (#2154)
Bumps
[@maplibre/maplibre-gl-style-spec](https://github.com/maplibre/maplibre-style-spec)
from 26.4.1 to 26.4.2.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/maplibre/maplibre-style-spec/releases">@​maplibre/maplibre-gl-style-spec's
releases</a>.</em></p>
<blockquote>
<h2>v26.4.2</h2>
<h3> Features and improvements</h3>
<ul>
<li>Allow negative <code>fill-extrusion-base</code> and
<code>fill-extrusion-height</code> values, extruding below ground level
(e.g. underground floors) (<a
href="https://redirect.github.com/maplibre/maplibre-style-spec/pull/1794">#1794</a>)
(by <a
href="https://github.com/clement-igonet"><code>@​clement-igonet</code></a>)</li>
<li>Add SDK support tracking for SDF fill pattern colorization (<a
href="https://redirect.github.com/maplibre/maplibre-style-spec/pull/1854">#1854</a>)
(by <a
href="https://github.com/deniial00"><code>@​deniial00</code></a>)</li>
</ul>
<h3>🐞 Bug fixes</h3>
<ul>
<li>Validate <code>-transition</code> properties on <code>sky</code> the
same way <code>light</code> already does, so
<code>sky-color-transition</code> and similar keys no longer report as
unknown properties (<a
href="https://redirect.github.com/maplibre/maplibre-style-spec/pull/1867">#1867</a>)
(by <a
href="https://github.com/Yasser-Ameur"><code>@​Yasser-Ameur</code></a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/maplibre/maplibre-style-spec/blob/main/CHANGELOG.md">@​maplibre/maplibre-gl-style-spec's
changelog</a>.</em></p>
<blockquote>
<h2>26.4.2</h2>
<h3> Features and improvements</h3>
<ul>
<li>Allow negative <code>fill-extrusion-base</code> and
<code>fill-extrusion-height</code> values, extruding below ground level
(e.g. underground floors) (<a
href="https://redirect.github.com/maplibre/maplibre-style-spec/pull/1794">#1794</a>)
(by <a
href="https://github.com/clement-igonet"><code>@​clement-igonet</code></a>)</li>
<li>Add SDK support tracking for SDF fill pattern colorization (<a
href="https://redirect.github.com/maplibre/maplibre-style-spec/pull/1854">#1854</a>)
(by <a
href="https://github.com/deniial00"><code>@​deniial00</code></a>)</li>
</ul>
<h3>🐞 Bug fixes</h3>
<ul>
<li>Validate <code>-transition</code> properties on <code>sky</code> the
same way <code>light</code> already does, so
<code>sky-color-transition</code> and similar keys no longer report as
unknown properties (<a
href="https://redirect.github.com/maplibre/maplibre-style-spec/pull/1867">#1867</a>)
(by <a
href="https://github.com/Yasser-Ameur"><code>@​Yasser-Ameur</code></a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/maplibre/maplibre-style-spec/commit/4453d2f4a1e755bc1cbc351103d0cdd9fde72b08"><code>4453d2f</code></a>
Bump js version to 26.4.2 (<a
href="https://redirect.github.com/maplibre/maplibre-style-spec/issues/1868">#1868</a>)</li>
<li><a
href="https://github.com/maplibre/maplibre-style-spec/commit/79bc668ac44589b474584589b6c30c9d1d71a9ff"><code>79bc668</code></a>
Validate sky transition properties like light does (<a
href="https://redirect.github.com/maplibre/maplibre-style-spec/issues/1867">#1867</a>)</li>
<li><a
href="https://github.com/maplibre/maplibre-style-spec/commit/487a7ad67e216306ebbd4ffb4d762c7774dce3ad"><code>487a7ad</code></a>
build(deps-dev): bump oxfmt from 0.65.0 to 0.66.0 (<a
href="https://redirect.github.com/maplibre/maplibre-style-spec/issues/1862">#1862</a>)</li>
<li><a
href="https://github.com/maplibre/maplibre-style-spec/commit/e5589ff0619251a8824c7e57d7999453b742e8de"><code>e5589ff</code></a>
build(deps-dev): bump <code>@​types/node</code> from 26.4.0 to 26.4.1
(<a
href="https://redirect.github.com/maplibre/maplibre-style-spec/issues/1863">#1863</a>)</li>
<li><a
href="https://github.com/maplibre/maplibre-style-spec/commit/139dea1e02a5521b421e7816b115b5fdd8065493"><code>139dea1</code></a>
build(deps-dev): bump rolldown from 1.2.6 to 1.2.7 (<a
href="https://redirect.github.com/maplibre/maplibre-style-spec/issues/1864">#1864</a>)</li>
<li><a
href="https://github.com/maplibre/maplibre-style-spec/commit/72778539dd53a4d69dcf4b4eee83b73124842de0"><code>7277853</code></a>
build(deps-dev): bump <code>@​typescript-eslint/eslint-plugin</code> (<a
href="https://redirect.github.com/maplibre/maplibre-style-spec/issues/1857">#1857</a>)</li>
<li><a
href="https://github.com/maplibre/maplibre-style-spec/commit/e7e13161d94b5094224b3dec388f2c7c2c83bc8e"><code>e7e1316</code></a>
build(deps-dev): bump globals from 17.11.0 to 17.12.0 (<a
href="https://redirect.github.com/maplibre/maplibre-style-spec/issues/1858">#1858</a>)</li>
<li><a
href="https://github.com/maplibre/maplibre-style-spec/commit/187f3c3633a9dd5b37148c1ca2686b438f8f7946"><code>187f3c3</code></a>
Document SDK support for SDF fill pattern colorization (<a
href="https://redirect.github.com/maplibre/maplibre-style-spec/issues/1854">#1854</a>)</li>
<li><a
href="https://github.com/maplibre/maplibre-style-spec/commit/d1b5935d9895e6a1b3f554812ba55c4673c3264c"><code>d1b5935</code></a>
ci: cancel superseded pull request runs (<a
href="https://redirect.github.com/maplibre/maplibre-style-spec/issues/1853">#1853</a>)</li>
<li><a
href="https://github.com/maplibre/maplibre-style-spec/commit/3ae6da3d6592ca765b04ff693dc1e59d57765e46"><code>3ae6da3</code></a>
build(deps-dev): bump <code>@​humanfs/node</code> from 0.16.6 to 0.16.8
(<a
href="https://redirect.github.com/maplibre/maplibre-style-spec/issues/1852">#1852</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/maplibre/maplibre-style-spec/compare/v26.4.1...v26.4.2">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@maplibre/maplibre-gl-style-spec&package-manager=npm_and_yarn&previous-version=26.4.1&new-version=26.4.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-09 13:55:05 +00:00
7 changed files with 139 additions and 94 deletions
+3
View File
@@ -8,9 +8,12 @@
- _...Add new stuff here..._ - _...Add new stuff here..._
### 🐞 Bug fixes ### 🐞 Bug fixes
- Prevent a crash when converting a function to an expression
- Prevent a crash when deleting either stop from a function with two stops
- Preserve expanded layer groups when deleting layers, including the first layer of a group - Preserve expanded layer groups when deleting layers, including the first layer of a group
- The map's data listener now fires on tile loads again, so source and vector layer field autocompletion is populated - The map's data listener now fires on tile loads again, so source and vector layer field autocompletion is populated
- The `maputnik` desktop binary now opens the default browser automatically on startup (opt out with `--no-browser`) - The `maputnik` desktop binary now opens the default browser automatically on startup (opt out with `--no-browser`)
- Keyboard shortcuts now keep working while the map has focus, instead of going dead until the map is blurred
- _...Add new stuff here..._ - _...Add new stuff here..._
## 3.1.0 ## 3.1.0
+17
View File
@@ -62,5 +62,22 @@ describe("keyboard", () => {
await when.typeKeys("!"); await when.typeKeys("!");
await then(get.elementByTestId("modal:debug")).shouldBeVisible(); await then(get.elementByTestId("modal:debug")).shouldBeVisible();
}); });
describe("while the map has focus", () => {
beforeEach(async () => {
await when.typeKeys("m");
await then(get.canvas()).shouldBeFocused();
});
test("'!' should show debug modal", async () => {
await when.typeKeys("!");
await then(get.elementByTestId("modal:debug")).shouldBeVisible();
});
test("'s' should show settings modal", async () => {
await when.typeKeys("s");
await then(get.elementByTestId("modal:settings")).shouldBeVisible();
});
});
}); });
}); });
+16 -1
View File
@@ -289,6 +289,20 @@ describe("layer editor", () => {
}); });
}); });
test("should leave a plain editable value after deleting a stop", async () => {
await when.setFunctionStopValue("circle-radius", "Output value", 1, "0");
await when.deleteFunctionStop("circle-radius");
await then(get.elementByTestId("spec-field:circle-radius")).shouldBeVisible();
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
layers: [{ id, paint: { "circle-radius": 0 } }],
});
await when.setValue("spec-field-input:circle-radius", "7");
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
layers: [{ id, paint: { "circle-radius": 7 } }],
});
});
test("should set the base", async () => { test("should set the base", async () => {
await when.setFunctionBase("circle-radius", "2"); await when.setFunctionBase("circle-radius", "2");
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({ await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
@@ -310,8 +324,9 @@ describe("layer editor", () => {
}); });
}); });
test("should convert to an expression", async () => { test("should convert to an expression without crashing", async () => {
await when.makeExpression("circle-radius"); await when.makeExpression("circle-radius");
await then(get.element("[data-wd-key='spec-field-container:circle-radius'] .maputnik-expression-editor")).shouldBeVisible();
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({ await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
layers: [{ id, paint: { "circle-radius": ["interpolate", ["linear"], ["zoom"], 6, 5, 10, 5] } }], layers: [{ id, paint: { "circle-radius": ["interpolate", ["linear"], ["zoom"], 6, 5, 10, 5] } }],
}); });
+77 -77
View File
@@ -20,7 +20,7 @@
"@mapbox/mapbox-gl-rtl-text": "^0.4.0", "@mapbox/mapbox-gl-rtl-text": "^0.4.0",
"@maplibre/maplibre-gl-geocoder": "^1.9.4", "@maplibre/maplibre-gl-geocoder": "^1.9.4",
"@maplibre/maplibre-gl-inspect": "^1.9.0", "@maplibre/maplibre-gl-inspect": "^1.9.0",
"@maplibre/maplibre-gl-style-spec": "^26.4.1", "@maplibre/maplibre-gl-style-spec": "^26.4.2",
"array-move": "^4.0.0", "array-move": "^4.0.0",
"buffer": "^6.0.3", "buffer": "^6.0.3",
"classnames": "^2.5.1", "classnames": "^2.5.1",
@@ -42,7 +42,7 @@
"lodash.get": "^4.4.2", "lodash.get": "^4.4.2",
"lodash.isequal": "^4.5.0", "lodash.isequal": "^4.5.0",
"lodash.throttle": "^4.1.1", "lodash.throttle": "^4.1.1",
"maplibre-gl": "^6.7.0", "maplibre-gl": "^6.8.0",
"maputnik-design": "github:maputnik/design#172b06c", "maputnik-design": "github:maputnik/design#172b06c",
"ol": "^10.10.0", "ol": "^10.10.0",
"ol-mapbox-style": "^13.4.3", "ol-mapbox-style": "^13.4.3",
@@ -107,7 +107,7 @@
"stylelint-config-recommended-scss": "^17.0.1", "stylelint-config-recommended-scss": "^17.0.1",
"stylelint-scss": "^7.2.0", "stylelint-scss": "^7.2.0",
"typescript": "^6.0.3", "typescript": "^6.0.3",
"typescript-eslint": "^8.69.0", "typescript-eslint": "^8.70.0",
"uuid": "^14.0.2", "uuid": "^14.0.2",
"vite": "^8.2.2", "vite": "^8.2.2",
"vite-plugin-istanbul": "^9.0.1", "vite-plugin-istanbul": "^9.0.1",
@@ -1700,9 +1700,9 @@
} }
}, },
"node_modules/@maplibre/maplibre-gl-style-spec": { "node_modules/@maplibre/maplibre-gl-style-spec": {
"version": "26.4.1", "version": "26.4.2",
"resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-26.4.1.tgz", "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-26.4.2.tgz",
"integrity": "sha512-I/qcIKVFHFSg1Meu/eqHrkSTjIez0gCsSaK56TNPutM3TkE61aSq6F1cZ4Kg4KiNs3cpViLtubDjfyRcQCdEJQ==", "integrity": "sha512-6J0vZqMZvRAJKtdWJdDGHEh1YJ2ZHG08/GOur8gCArYhO8ZkM//OXqtI2AAEz4jc2G+Wq4MfcePg8qNK5TZ4Kg==",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@mapbox/jsonlint-lines-primitives": "^2.0.3", "@mapbox/jsonlint-lines-primitives": "^2.0.3",
@@ -1719,9 +1719,9 @@
} }
}, },
"node_modules/@maplibre/mlt": { "node_modules/@maplibre/mlt": {
"version": "1.2.0", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/@maplibre/mlt/-/mlt-1.2.0.tgz", "resolved": "https://registry.npmjs.org/@maplibre/mlt/-/mlt-1.2.1.tgz",
"integrity": "sha512-g45M8gEI4sMO3X9ib4K7n3ZKFf0qQOL+NMkHCnEK51lOrYFHiEssOuZncx1+miIgi1IEE2NcbRMcq8RBkL+QHA==", "integrity": "sha512-5n5dgolE2EYxwCKgx8vlwURCB8A+kyfJJyThlYimjlGgOcOe2Bhw9VxxnnHC91OC9PgHg+nVdgVPTYPkIo62vg==",
"license": "(MIT OR Apache-2.0)", "license": "(MIT OR Apache-2.0)",
"dependencies": { "dependencies": {
"@mapbox/point-geometry": "^1.1.0" "@mapbox/point-geometry": "^1.1.0"
@@ -3078,17 +3078,17 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@typescript-eslint/eslint-plugin": { "node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.69.0", "version": "8.70.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.69.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.70.0.tgz",
"integrity": "sha512-t5jQTKPIgVW1PE6dR6H6Qz5gm8zjMlX5/2gRaOGd9eO6V7J+tQc6iWKukEe7dY8u9HyYasQ0yfF0/FSSTEO2gA==", "integrity": "sha512-/v8HZt6RlyIZxB3ntehELOcUcfxKPVGWXnQdJuHRmzrqgF8nQypcC/oxGW+Ot4VGKDq81XugPKxx0n5PBtf9PA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/regexpp": "^4.12.2", "@eslint-community/regexpp": "^4.12.2",
"@typescript-eslint/scope-manager": "8.69.0", "@typescript-eslint/scope-manager": "8.70.0",
"@typescript-eslint/type-utils": "8.69.0", "@typescript-eslint/type-utils": "8.70.0",
"@typescript-eslint/utils": "8.69.0", "@typescript-eslint/utils": "8.70.0",
"@typescript-eslint/visitor-keys": "8.69.0", "@typescript-eslint/visitor-keys": "8.70.0",
"ignore": "^7.0.5", "ignore": "^7.0.5",
"natural-compare": "^1.4.0", "natural-compare": "^1.4.0",
"ts-api-utils": "^2.5.0" "ts-api-utils": "^2.5.0"
@@ -3101,15 +3101,15 @@
"url": "https://opencollective.com/typescript-eslint" "url": "https://opencollective.com/typescript-eslint"
}, },
"peerDependencies": { "peerDependencies": {
"@typescript-eslint/parser": "^8.69.0", "@typescript-eslint/parser": "^8.70.0",
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
"typescript": ">=4.8.4 <6.1.0" "typescript": ">=4.8.4 <6.1.0"
} }
}, },
"node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": {
"version": "7.0.8", "version": "7.0.9",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.8.tgz", "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.9.tgz",
"integrity": "sha512-YYNsSlXBjMk92SKnkwvB5LOVSa6OznlFUGcsvrFgNJbJCd0M1XKeFVRc8ZByeCqz32FivYNHJVooLmdqrmvp/Q==", "integrity": "sha512-brTTsvFRt5C1gGHtPst/281UjPD5t9fBqbgoMPlVWy11ZLTPfu7HxK4ZYqO9H7o/yC9rSTCI85EaQ4OoY12qYw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@@ -3117,16 +3117,16 @@
} }
}, },
"node_modules/@typescript-eslint/parser": { "node_modules/@typescript-eslint/parser": {
"version": "8.69.0", "version": "8.70.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.69.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.70.0.tgz",
"integrity": "sha512-l4b0DhWioGg6Gt2ebGlvfkFMOjRsauxtsnDRwUSRX1qHq3HdTfQHV8wW9zEXeciai6HfeaKOedQn2Zoofx3WBw==", "integrity": "sha512-zYvrmj9Yxd63UGaXw+kdt6A0F0s0qveJyuatIM77bYC2DE4pgmg7a50u8LR7PRtXd0x+h+Tl3eXabGm06SWd3Q==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "8.69.0", "@typescript-eslint/scope-manager": "8.70.0",
"@typescript-eslint/types": "8.69.0", "@typescript-eslint/types": "8.70.0",
"@typescript-eslint/typescript-estree": "8.69.0", "@typescript-eslint/typescript-estree": "8.70.0",
"@typescript-eslint/visitor-keys": "8.69.0", "@typescript-eslint/visitor-keys": "8.70.0",
"debug": "^4.4.3" "debug": "^4.4.3"
}, },
"engines": { "engines": {
@@ -3142,14 +3142,14 @@
} }
}, },
"node_modules/@typescript-eslint/project-service": { "node_modules/@typescript-eslint/project-service": {
"version": "8.69.0", "version": "8.70.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.69.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.70.0.tgz",
"integrity": "sha512-yi4obFrHMmnsesWehHbkg9zMA7Jt8cXT+mKM08G999pH1yT6nqgsHx7MYm0uY1wAj8CqiBXYRJ7WAT0QdQHQXg==", "integrity": "sha512-hFHbTNqhU9G+2eKFXCBVb1tjFT/LceiJ4+HfLO4pTpDI0KHi6iajpcFFkaSQ9gXmCh7n82A0PthaayEdN6mspQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/tsconfig-utils": "^8.69.0", "@typescript-eslint/tsconfig-utils": "^8.70.0",
"@typescript-eslint/types": "^8.69.0", "@typescript-eslint/types": "^8.70.0",
"debug": "^4.4.3" "debug": "^4.4.3"
}, },
"engines": { "engines": {
@@ -3164,14 +3164,14 @@
} }
}, },
"node_modules/@typescript-eslint/scope-manager": { "node_modules/@typescript-eslint/scope-manager": {
"version": "8.69.0", "version": "8.70.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.69.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.70.0.tgz",
"integrity": "sha512-ewfspqWvSxKSOaplqAUNbaSFO0eB6w1EtQ+esfYFRm3614Ty4uNtExkcbgd6nWsXphbqKyf9ZYdbZdv2xEoWEQ==", "integrity": "sha512-8nP3Kwh5hlgZ4FicGvmznAmJe8UL4sdU8tLukrPaMuQmDuk4Y8xYfzu/aYZW4xT2JCgc7H/TpDI5cGlxcWJSqQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.69.0", "@typescript-eslint/types": "8.70.0",
"@typescript-eslint/visitor-keys": "8.69.0" "@typescript-eslint/visitor-keys": "8.70.0"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -3182,9 +3182,9 @@
} }
}, },
"node_modules/@typescript-eslint/tsconfig-utils": { "node_modules/@typescript-eslint/tsconfig-utils": {
"version": "8.69.0", "version": "8.70.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.69.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.70.0.tgz",
"integrity": "sha512-xNqK7YTDZsLniQMV/4rpFR8Z5JlqeRvVjuG1YgF/mdPVH84HSD19L8CczMA0qg2RfwEV231GHH3VnToJDo4MfQ==", "integrity": "sha512-adnkeeNq9Sq1sUf4+FRVc0KdgYghzsgFpZSQVZVvY0LCuUuN0FnQgyGzCJeC4fW1cdXseBAjU2EOqUIjbNcZUw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@@ -3199,15 +3199,15 @@
} }
}, },
"node_modules/@typescript-eslint/type-utils": { "node_modules/@typescript-eslint/type-utils": {
"version": "8.69.0", "version": "8.70.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.69.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.70.0.tgz",
"integrity": "sha512-ZfoJAVg3JZndQEpEl9petVlxau3lRuElc4HRMuAlLCf8to04/iHz692RUSNmXKDjEuJmIL+KZ2/BsOcBc16dsA==", "integrity": "sha512-NUMKIhYVaVIVLnRL9CRt+VVcuLgSHUCpXn4/+K8wql+vdInUzvx8BjUO1oJ7cG9shjFJKtF8F8Hh2kCh3/KBVw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.69.0", "@typescript-eslint/types": "8.70.0",
"@typescript-eslint/typescript-estree": "8.69.0", "@typescript-eslint/typescript-estree": "8.70.0",
"@typescript-eslint/utils": "8.69.0", "@typescript-eslint/utils": "8.70.0",
"debug": "^4.4.3", "debug": "^4.4.3",
"ts-api-utils": "^2.5.0" "ts-api-utils": "^2.5.0"
}, },
@@ -3224,9 +3224,9 @@
} }
}, },
"node_modules/@typescript-eslint/types": { "node_modules/@typescript-eslint/types": {
"version": "8.69.0", "version": "8.70.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.69.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.70.0.tgz",
"integrity": "sha512-K3VrubUPhlo9VDBS6QdI8YB5j7ClpqLRdefcz6PFrhnwicehBweqQ9Evhl4l+FYz0HdDmMqIiSX0aldGRYtDCA==", "integrity": "sha512-asTOIYhDg4zdzOScCyaytrsV3cR6B4ecPQlXw/dJIm7J/MZTtCtfVII9JD8Geh4jTCrK/Xe6cg5UevoleMcoJQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@@ -3238,16 +3238,16 @@
} }
}, },
"node_modules/@typescript-eslint/typescript-estree": { "node_modules/@typescript-eslint/typescript-estree": {
"version": "8.69.0", "version": "8.70.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.69.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.70.0.tgz",
"integrity": "sha512-AdFkgqck3Vudb/kWnxlyafU/4aBhHrbQ9locP2N4psXTy5mOBg0SHJumnLvx7r6g1gV4DKvUFwV2nJZBoqOD8w==", "integrity": "sha512-d9NmHMPEKQ7QCLLm1jI3zmoQBwT5KwFYjXBJ9ymZfKCUU+5rmTRykKAFvH5Qn/ZCds3CEAFS9OC9M/jkl0X2bA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/project-service": "8.69.0", "@typescript-eslint/project-service": "8.70.0",
"@typescript-eslint/tsconfig-utils": "8.69.0", "@typescript-eslint/tsconfig-utils": "8.70.0",
"@typescript-eslint/types": "8.69.0", "@typescript-eslint/types": "8.70.0",
"@typescript-eslint/visitor-keys": "8.69.0", "@typescript-eslint/visitor-keys": "8.70.0",
"debug": "^4.4.3", "debug": "^4.4.3",
"minimatch": "^10.2.2", "minimatch": "^10.2.2",
"semver": "^7.7.3", "semver": "^7.7.3",
@@ -3305,16 +3305,16 @@
} }
}, },
"node_modules/@typescript-eslint/utils": { "node_modules/@typescript-eslint/utils": {
"version": "8.69.0", "version": "8.70.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.69.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.70.0.tgz",
"integrity": "sha512-tUbx60BBqQa31kXF5MCsOOLL5E/WzUuxIn7YpAvq+eaUlqvk8/NXnXMBNAdLCr0icjkzem7iUA5QqWHe/hJ1aw==", "integrity": "sha512-oZmtKJz/4fufZ2p3+Cn3ijEojcdfR+1zYDH2xKYrEly0dR/Q/1xUPRCOlKGxod78nWlU2UnDe09GZ3TaknBFGA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.9.1", "@eslint-community/eslint-utils": "^4.9.1",
"@typescript-eslint/scope-manager": "8.69.0", "@typescript-eslint/scope-manager": "8.70.0",
"@typescript-eslint/types": "8.69.0", "@typescript-eslint/types": "8.70.0",
"@typescript-eslint/typescript-estree": "8.69.0" "@typescript-eslint/typescript-estree": "8.70.0"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -3329,13 +3329,13 @@
} }
}, },
"node_modules/@typescript-eslint/visitor-keys": { "node_modules/@typescript-eslint/visitor-keys": {
"version": "8.69.0", "version": "8.70.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.69.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.70.0.tgz",
"integrity": "sha512-+rmdgPA+EXkNgKYvHvFfhrs35utXbwaC5PGpDquSXcoXQDKUA5UjV0LmTucG/4JXkM31BTu4TilHtrN8IVBe8w==", "integrity": "sha512-BoC8PiO4Hkdo0TVJh9Ntxr5MxPDI7/oFsrygN5ADelFSeXG/qgNuucIGA+L5Z6JpPTE/uRfcTWtscjbUaufepQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.69.0", "@typescript-eslint/types": "8.70.0",
"eslint-visitor-keys": "^5.0.0" "eslint-visitor-keys": "^5.0.0"
}, },
"engines": { "engines": {
@@ -8394,9 +8394,9 @@
"license": "BSD-2-Clause" "license": "BSD-2-Clause"
}, },
"node_modules/maplibre-gl": { "node_modules/maplibre-gl": {
"version": "6.7.0", "version": "6.8.0",
"resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-6.7.0.tgz", "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-6.8.0.tgz",
"integrity": "sha512-Y1Q1+UP9WXou0DUrnaFdDsoMqiMCWy6aS968IBUaQ2eZi6H1/kPCfpfZOWXFJZbeKMkX9Wo6OFzY/k48qqPf3Q==", "integrity": "sha512-+ZkjKTodsVLY0ewQThvXRxXQsclcsSgOm5LlnrBM3G8AloMJKt6Haw8mY4xrOl8T0WMqH6DTYjktZ9zGQXZd4w==",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"dependencies": { "dependencies": {
"@mapbox/point-geometry": "^1.1.0", "@mapbox/point-geometry": "^1.1.0",
@@ -8405,7 +8405,7 @@
"@mapbox/vector-tile": "^3.0.0", "@mapbox/vector-tile": "^3.0.0",
"@maplibre/geojson-vt": "^6.1.1", "@maplibre/geojson-vt": "^6.1.1",
"@maplibre/maplibre-gl-style-spec": "^26.4.1", "@maplibre/maplibre-gl-style-spec": "^26.4.1",
"@maplibre/mlt": "^1.2.0", "@maplibre/mlt": "^1.2.1",
"@maplibre/vt-pbf": "^4.3.2", "@maplibre/vt-pbf": "^4.3.2",
"@types/geojson": "^7946.0.16", "@types/geojson": "^7946.0.16",
"earcut": "^3.2.3", "earcut": "^3.2.3",
@@ -12430,16 +12430,16 @@
} }
}, },
"node_modules/typescript-eslint": { "node_modules/typescript-eslint": {
"version": "8.69.0", "version": "8.70.0",
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.69.0.tgz", "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.70.0.tgz",
"integrity": "sha512-B3MltX0VqjUBNEe3b3sSuiRbfa6XrfHFtBiPamjT5AsW/dfq+y+bc0wyuS9DxAS1LyzCxRp2+rxzpLUvqM2BvA==", "integrity": "sha512-P/W5cz70/cQAuKfY3xwQMWWTV7BvJ0mAQmi+9mBcsVPaBUpd6Ohpa+fECv9rBFrQcig86jAiNBFNWUqnTjr4pw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/eslint-plugin": "8.69.0", "@typescript-eslint/eslint-plugin": "8.70.0",
"@typescript-eslint/parser": "8.69.0", "@typescript-eslint/parser": "8.70.0",
"@typescript-eslint/typescript-estree": "8.69.0", "@typescript-eslint/typescript-estree": "8.70.0",
"@typescript-eslint/utils": "8.69.0" "@typescript-eslint/utils": "8.70.0"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+3 -3
View File
@@ -38,7 +38,7 @@
"@mapbox/mapbox-gl-rtl-text": "^0.4.0", "@mapbox/mapbox-gl-rtl-text": "^0.4.0",
"@maplibre/maplibre-gl-geocoder": "^1.9.4", "@maplibre/maplibre-gl-geocoder": "^1.9.4",
"@maplibre/maplibre-gl-inspect": "^1.9.0", "@maplibre/maplibre-gl-inspect": "^1.9.0",
"@maplibre/maplibre-gl-style-spec": "^26.4.1", "@maplibre/maplibre-gl-style-spec": "^26.4.2",
"array-move": "^4.0.0", "array-move": "^4.0.0",
"buffer": "^6.0.3", "buffer": "^6.0.3",
"classnames": "^2.5.1", "classnames": "^2.5.1",
@@ -60,7 +60,7 @@
"lodash.get": "^4.4.2", "lodash.get": "^4.4.2",
"lodash.isequal": "^4.5.0", "lodash.isequal": "^4.5.0",
"lodash.throttle": "^4.1.1", "lodash.throttle": "^4.1.1",
"maplibre-gl": "^6.7.0", "maplibre-gl": "^6.8.0",
"maputnik-design": "github:maputnik/design#172b06c", "maputnik-design": "github:maputnik/design#172b06c",
"ol": "^10.10.0", "ol": "^10.10.0",
"ol-mapbox-style": "^13.4.3", "ol-mapbox-style": "^13.4.3",
@@ -142,7 +142,7 @@
"stylelint-config-recommended-scss": "^17.0.1", "stylelint-config-recommended-scss": "^17.0.1",
"stylelint-scss": "^7.2.0", "stylelint-scss": "^7.2.0",
"typescript": "^6.0.3", "typescript": "^6.0.3",
"typescript-eslint": "^8.69.0", "typescript-eslint": "^8.70.0",
"uuid": "^14.0.2", "uuid": "^14.0.2",
"vite": "^8.2.2", "vite": "^8.2.2",
"vite-plugin-istanbul": "^9.0.1", "vite-plugin-istanbul": "^9.0.1",
+17 -1
View File
@@ -83,6 +83,22 @@ function updateRootSpec(spec: any, fieldName: string, newValues: any) {
}; };
} }
/**
* Whether the given element consumes keystrokes as text.
*
* Shortcuts have to stay out of the way while the user is typing, but asking
* whether the focus is on `document.body` answers a different question: the map
* canvas is not a text field, yet focusing it used to disable every shortcut.
*/
function isTextEntryElement(element: Element | null): boolean {
if (!element) return false;
const node = element as HTMLElement;
return node.isContentEditable ||
node.tagName === "INPUT" ||
node.tagName === "TEXTAREA" ||
node.tagName === "SELECT";
}
type AppState = { type AppState = {
errors: MappedError[], errors: MappedError[],
infos: string[], infos: string[],
@@ -242,7 +258,7 @@ export class App extends React.Component<any, AppState> {
(e.target as HTMLElement).blur(); (e.target as HTMLElement).blur();
document.body.focus(); document.body.focus();
} }
else if(this.state.isOpen.shortcuts || document.activeElement === document.body) { else if(this.state.isOpen.shortcuts || !isTextEntryElement(document.activeElement)) {
const shortcut = shortcuts.find((shortcut) => { const shortcut = shortcuts.find((shortcut) => {
return (shortcut.key === e.key); return (shortcut.key === e.key);
}); });
+6 -12
View File
@@ -129,16 +129,10 @@ type FieldFunctionProps = {
* https://www.mapbox.com/mapbox-gl-style-spec/#types-function-zoom-property * https://www.mapbox.com/mapbox-gl-style-spec/#types-function-zoom-property
*/ */
export const FieldFunction: React.FC<FieldFunctionProps> = (props) => { export const FieldFunction: React.FC<FieldFunctionProps> = (props) => {
const [dataType, setDataType] = React.useState(
getDataType(props.value, props.fieldSpec)
);
const [isEditing, setIsEditing] = React.useState(false); const [isEditing, setIsEditing] = React.useState(false);
// Keep the expression editor mounted while typing, but otherwise select the
React.useEffect(() => { // editor from the current value so a collapsed function never renders as stops.
if (!isEditing) { const dataType = isEditing ? "expression" : getDataType(props.value, props.fieldSpec);
setDataType(getDataType(props.value, props.fieldSpec));
}
}, [props.value, props.fieldSpec, isEditing]);
const getFieldFunctionType = (fieldSpec: any) => { const getFieldFunctionType = (fieldSpec: any) => {
if (fieldSpec.expression.interpolated) { if (fieldSpec.expression.interpolated) {
@@ -173,7 +167,7 @@ export const FieldFunction: React.FC<FieldFunctionProps> = (props) => {
const deleteExpression = () => { const deleteExpression = () => {
const { fieldSpec, fieldName } = props; const { fieldSpec, fieldName } = props;
props.onChange(fieldName, fieldSpec.default); props.onChange(fieldName, fieldSpec.default);
setDataType("value"); setIsEditing(false);
}; };
const deleteStop = (stopIdx: number) => { const deleteStop = (stopIdx: number) => {
@@ -233,10 +227,10 @@ export const FieldFunction: React.FC<FieldFunctionProps> = (props) => {
type: "identity", type: "identity",
property: value[1], property: value[1],
}); });
setDataType("value"); setIsEditing(false);
} else if (isLiteralExpression(value)) { } else if (isLiteralExpression(value)) {
props.onChange(fieldName, value[1]); props.onChange(fieldName, value[1]);
setDataType("value"); setIsEditing(false);
} }
}; };