mirror of
https://github.com/maputnik/editor.git
synced 2026-07-27 16:27:26 +00:00
Compare commits
30 Commits
b7f9753ff7
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| d990d55f1b | |||
| c2f3bf30da | |||
| 10dc48f3ca | |||
| cf836a1969 | |||
| cbccff7d92 | |||
| 2b5f03f3c2 | |||
| ccfb9a3111 | |||
| 23ce685a91 | |||
| ea67387e65 | |||
| 30bcfc2265 | |||
| a408437cf8 | |||
| 01e58e0895 | |||
| 8128fef161 | |||
| 283ef008a6 | |||
| d021155991 | |||
| d06a3e7e1e | |||
| e0f27214b7 | |||
| 167f83abe9 | |||
| 0936afc2f9 | |||
| b664caa13e | |||
| d90d7b743b | |||
| 0152a02858 | |||
| 0b076e3896 | |||
| cf54b6fdeb | |||
| e5e09e846a | |||
| 43bb23801c | |||
| f14eeae38b | |||
| 9c1499b805 | |||
| 21e141542a | |||
| 320f94b707 |
+11
-12
@@ -21,9 +21,9 @@ jobs:
|
|||||||
os: [ ubuntu-latest, windows-latest, macos-latest ]
|
os: [ ubuntu-latest, windows-latest, macos-latest ]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
with: { persist-credentials: false }
|
with: { persist-credentials: false }
|
||||||
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
@@ -41,9 +41,9 @@ jobs:
|
|||||||
if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' }}
|
if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
with: { persist-credentials: false }
|
with: { persist-credentials: false }
|
||||||
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
@@ -56,7 +56,7 @@ jobs:
|
|||||||
|
|
||||||
# Build and upload desktop CLI artifacts
|
# Build and upload desktop CLI artifacts
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
|
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
||||||
with:
|
with:
|
||||||
go-version: ^1.23.x
|
go-version: ^1.23.x
|
||||||
cache-dependency-path: desktop/go.sum
|
cache-dependency-path: desktop/go.sum
|
||||||
@@ -90,13 +90,12 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
with: { persist-credentials: false }
|
with: { persist-credentials: false }
|
||||||
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
- run: npx playwright install --with-deps chromium
|
|
||||||
- run: npm run test-unit-ci
|
- run: npm run test-unit-ci
|
||||||
- name: Upload coverage reports to Codecov
|
- name: Upload coverage reports to Codecov
|
||||||
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
|
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
|
||||||
@@ -112,9 +111,9 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
with: { persist-credentials: false }
|
with: { persist-credentials: false }
|
||||||
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
@@ -140,9 +139,9 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
with: { persist-credentials: false }
|
with: { persist-credentials: false }
|
||||||
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
|
|||||||
@@ -38,11 +38,11 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3
|
uses: github/codeql-action/init@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
@@ -67,4 +67,4 @@ jobs:
|
|||||||
# make release
|
# make release
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3
|
uses: github/codeql-action/analyze@e0647621c2984b5ed2f768cb892365bf2a616ad1 # v4.37.2
|
||||||
|
|||||||
@@ -16,13 +16,13 @@ jobs:
|
|||||||
run:
|
run:
|
||||||
shell: bash
|
shell: bash
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
ref: main
|
ref: main
|
||||||
|
|
||||||
- name: Use Node.js from nvmrc
|
- name: Use Node.js from nvmrc
|
||||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||||
with:
|
with:
|
||||||
node-version-file: ".nvmrc"
|
node-version-file: ".nvmrc"
|
||||||
|
|
||||||
|
|||||||
@@ -12,11 +12,11 @@ jobs:
|
|||||||
contents: write
|
contents: write
|
||||||
if: ${{ github.event_name == 'push' }}
|
if: ${{ github.event_name == 'push' }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
with: { persist-credentials: false }
|
with: { persist-credentials: false }
|
||||||
|
|
||||||
- name: Use Node.js from nvmrc
|
- name: Use Node.js from nvmrc
|
||||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
|
|
||||||
@@ -45,11 +45,11 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
|
uses: docker/login-action@abd2ef45e78c5afb21d64d4ca52ee8550d9572c7 # v4.5.1
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
- run: docker build -t ghcr.io/maplibre/maputnik:main .
|
- run: docker build -t ghcr.io/maplibre/maputnik:main .
|
||||||
- run: docker push ghcr.io/maplibre/maputnik:main
|
- run: docker push ghcr.io/maplibre/maputnik:main
|
||||||
|
|||||||
@@ -15,14 +15,14 @@ jobs:
|
|||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
ref: main
|
ref: main
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Use Node.js from nvmrc
|
- name: Use Node.js from nvmrc
|
||||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||||
with:
|
with:
|
||||||
node-version-file: ".nvmrc"
|
node-version-file: ".nvmrc"
|
||||||
|
|
||||||
@@ -42,19 +42,19 @@ jobs:
|
|||||||
run:
|
run:
|
||||||
shell: bash
|
shell: bash
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
ref: main
|
ref: main
|
||||||
|
|
||||||
- name: Use Node.js from nvmrc
|
- name: Use Node.js from nvmrc
|
||||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||||
with:
|
with:
|
||||||
node-version-file: ".nvmrc"
|
node-version-file: ".nvmrc"
|
||||||
registry-url: "https://registry.npmjs.org"
|
registry-url: "https://registry.npmjs.org"
|
||||||
|
|
||||||
- name: Set up Go for desktop build
|
- name: Set up Go for desktop build
|
||||||
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
|
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
||||||
with:
|
with:
|
||||||
go-version: ^1.23.x
|
go-version: ^1.23.x
|
||||||
cache-dependency-path: desktop/go.sum
|
cache-dependency-path: desktop/go.sum
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ Then run the end-to-end tests (Playwright starts the dev server automatically):
|
|||||||
npm run test
|
npm run test
|
||||||
```
|
```
|
||||||
|
|
||||||
Run the unit and component tests with Vitest:
|
Run the unit tests with Vitest:
|
||||||
|
|
||||||
```
|
```
|
||||||
npm run test-unit
|
npm run test-unit
|
||||||
@@ -45,3 +45,106 @@ npm run test-unit
|
|||||||
## Pull Requests
|
## Pull Requests
|
||||||
|
|
||||||
- Pull requests should update `CHANGELOG.md` with a short description of the change.
|
- Pull requests should update `CHANGELOG.md` with a short description of the change.
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
### Prefer end-to-end tests
|
||||||
|
|
||||||
|
Most of this codebase is React components, and they are only reachable from an
|
||||||
|
end-to-end test. E2E coverage is the primary signal.
|
||||||
|
|
||||||
|
Reach for a unit test only for pure logic that e2e cannot cheaply reach (parsers,
|
||||||
|
sorting, watchers, stores). Before writing one, check whether e2e already covers
|
||||||
|
the file — a unit test that duplicates existing e2e coverage adds test code and
|
||||||
|
almost no coverage:
|
||||||
|
|
||||||
|
```
|
||||||
|
npx nyc report --reporter=text --include="src/libs/style.ts"
|
||||||
|
```
|
||||||
|
|
||||||
|
Do **not** merge the Vitest (v8) and e2e (istanbul) coverage reports locally. They
|
||||||
|
produce conflicting statement maps for the same files and the combined percentage
|
||||||
|
is meaningless. Codecov merges the two uploads server-side; that is the number to
|
||||||
|
trust. Locally, read them separately:
|
||||||
|
|
||||||
|
- e2e: `npx playwright test` then `npx nyc report --reporter=text-summary` (reads `.nyc_output/`)
|
||||||
|
- unit: `npx vitest run --coverage` (writes `coverage/`)
|
||||||
|
|
||||||
|
### E2E layering
|
||||||
|
|
||||||
|
Three layers, and the boundaries matter:
|
||||||
|
|
||||||
|
- `e2e/playwright-helper.ts` — generic, app-agnostic browser actions. **The only
|
||||||
|
file allowed to import `@playwright/test`** (besides `e2e/utils/fixtures.ts`).
|
||||||
|
- `e2e/maputnik-driver.ts` — domain actions (layers, filters, functions, the
|
||||||
|
style). Knows nothing about `page` or Playwright.
|
||||||
|
- `e2e/modal-driver.ts` — actions scoped to a modal, exposed as `when.modal.*`.
|
||||||
|
|
||||||
|
Specs get a driver at describe scope and assert fluently:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
describe("layer editor", () => {
|
||||||
|
const { given, get, when, then } = new MaputnikDriver();
|
||||||
|
...
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({ layers: [{ id, type: "fill" }] });
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
New UI interactions belong in a driver, not inline in a spec.
|
||||||
|
|
||||||
|
### Writing assertions
|
||||||
|
|
||||||
|
- `shouldDeepNestedInclude` is a recursive partial match (`toMatchObject`): nested
|
||||||
|
objects are matched as subsets, arrays and primitives must match exactly
|
||||||
|
(including array length).
|
||||||
|
- Assert against the whole style, not an extracted slice. Avoid
|
||||||
|
`get.styleFromLocalStorage().then(style => style.layers.find(...))` — it moves
|
||||||
|
test logic into the test. Compare the real object instead.
|
||||||
|
- `Query.then()` is lazy and returns a new `Query`, **not** a Promise. `await
|
||||||
|
get.styleFromLocalStorage()` hangs forever. Use `.get()` to await it directly,
|
||||||
|
or pass the Query to `then(...)`.
|
||||||
|
|
||||||
|
### One behaviour per test
|
||||||
|
|
||||||
|
If a test needs comments narrating "and now this…", it is several tests. Split it,
|
||||||
|
and hoist the shared setup into a nested `describe` + `beforeEach`.
|
||||||
|
|
||||||
|
### Test ids
|
||||||
|
|
||||||
|
Test ids use the `data-wd-key` attribute and are read via `get.elementByTestId`.
|
||||||
|
|
||||||
|
The `Input*` components already accept `data-wd-key` and render it on the real
|
||||||
|
`<input>`; the `Field*` wrappers forward it through their `{...props}` spread. So
|
||||||
|
passing `data-wd-key` to a `Field*` component is usually enough. Do **not** also
|
||||||
|
add it to `Block`/`Fieldset` — the id then matches two elements and locators fail
|
||||||
|
in strict mode.
|
||||||
|
|
||||||
|
Note `InputNumber` renders `<key>-text` and `<key>-range` when `allowRange` is set,
|
||||||
|
and `<key>` otherwise.
|
||||||
|
|
||||||
|
### Input commit semantics (common source of "the value didn't save")
|
||||||
|
|
||||||
|
- `InputString` only fires its `onChange` on **blur** or **Enter**. Typing alone
|
||||||
|
fires `onInput`. A driver that calls `fill()` must then call `blur()`, or the
|
||||||
|
value never reaches the style.
|
||||||
|
- `InputNumber` commits on every change; no blur needed.
|
||||||
|
- The autocomplete inputs (layer source, add-layer source) are controlled
|
||||||
|
downshift comboboxes. Keystroke typing is dropped/reordered — `{selectall}` then
|
||||||
|
typing `raster` yields `"exampleaster"`. Use `fill()`, which dispatches a single
|
||||||
|
input event, then pick from the filtered menu.
|
||||||
|
- CodeMirror auto-closes brackets and quotes, and types over its own closers, so
|
||||||
|
inserting a well-formed JSON fragment stays well-formed. To break JSON on
|
||||||
|
purpose, insert a bare word.
|
||||||
|
|
||||||
|
### Fixtures
|
||||||
|
|
||||||
|
Style fixtures live in `e2e/fixtures/`. A new one must be registered in two places
|
||||||
|
in `maputnik-driver.ts`: the list in `given.setupMockBackedResponses` and the
|
||||||
|
`styleFileByKey` map in `when.setStyle`.
|
||||||
|
|
||||||
|
### Verify a new test can fail
|
||||||
|
|
||||||
|
A test that passes for the wrong reason is worse than no test. After writing one,
|
||||||
|
mutate the expected value and confirm it fails. This has caught real mistakes
|
||||||
|
(e.g. a driver that never committed its input, so the assertion was matching a
|
||||||
|
value written by the *previous* step).
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
import { test, expect, describe, beforeEach } from "./utils/fixtures";
|
||||||
|
import { MaputnikDriver } from "./maputnik-driver";
|
||||||
|
import tokens from "../src/config/tokens.json" with { type: "json" };
|
||||||
|
|
||||||
|
describe("access tokens", () => {
|
||||||
|
const { given, when } = new MaputnikDriver();
|
||||||
|
|
||||||
|
const tileJson = {
|
||||||
|
tilejson: "2.2.0",
|
||||||
|
tiles: ["https://example.local/{z}/{x}/{y}.pbf"],
|
||||||
|
minzoom: 0,
|
||||||
|
maxzoom: 14,
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await given.setupMockBackedResponses();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("uses the thunderforest token for a thunderforest source", async () => {
|
||||||
|
await given.interceptAndMockResponse({
|
||||||
|
method: "GET",
|
||||||
|
url: /tile\.thunderforest\.com\/.*/,
|
||||||
|
response: tileJson,
|
||||||
|
alias: "thunderforest",
|
||||||
|
});
|
||||||
|
|
||||||
|
await when.setStyle("access_tokens");
|
||||||
|
|
||||||
|
const request = await when.waitForResponse("thunderforest");
|
||||||
|
expect(request.url()).toContain(`apikey=${tokens.thunderforest}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("uses the locationiq token for a locationiq source", async () => {
|
||||||
|
await given.interceptAndMockResponse({
|
||||||
|
method: "GET",
|
||||||
|
url: /tiles\.locationiq\.com\/.*/,
|
||||||
|
response: tileJson,
|
||||||
|
alias: "locationiq",
|
||||||
|
});
|
||||||
|
|
||||||
|
await when.setStyle("access_tokens");
|
||||||
|
|
||||||
|
const request = await when.waitForResponse("locationiq");
|
||||||
|
expect(request.url()).toContain(`key=${tokens.locationiq}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("appends the stadia token as a query parameter", async () => {
|
||||||
|
await given.interceptAndMockResponse({
|
||||||
|
method: "GET",
|
||||||
|
url: /tiles\.stadiamaps\.com\/.*/,
|
||||||
|
response: tileJson,
|
||||||
|
alias: "stadia",
|
||||||
|
});
|
||||||
|
|
||||||
|
await when.setStyle("access_tokens");
|
||||||
|
|
||||||
|
const request = await when.waitForResponse("stadia");
|
||||||
|
expect(request.url()).toContain("?api_key=stadia-test-token");
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"version": 8,
|
||||||
|
"name": "Access token style",
|
||||||
|
"metadata": {
|
||||||
|
"maputnik:stadia_access_token": "stadia-test-token"
|
||||||
|
},
|
||||||
|
"sources": {
|
||||||
|
"thunderforest_transport": {
|
||||||
|
"type": "vector",
|
||||||
|
"url": "https://tile.thunderforest.com/thunderforest.transport-v2.json?apikey={key}"
|
||||||
|
},
|
||||||
|
"stadia_outdoors": {
|
||||||
|
"type": "vector",
|
||||||
|
"url": "https://tiles.stadiamaps.com/data/openmaptiles.json"
|
||||||
|
},
|
||||||
|
"locationiq": {
|
||||||
|
"type": "vector",
|
||||||
|
"url": "https://tiles.locationiq.com/v3/pbf/tiles.json?key={key}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"layers": []
|
||||||
|
}
|
||||||
+367
-9
@@ -25,7 +25,18 @@ describe("layer editor", () => {
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
test.skip("expand/collapse", () => {});
|
test("expand/collapse", async () => {
|
||||||
|
const bgId = await createBackground();
|
||||||
|
await when.click("layer-list-item:background:" + bgId);
|
||||||
|
|
||||||
|
await then(get.elementByTestId("layer-editor.layer-id.input")).shouldBeVisible();
|
||||||
|
|
||||||
|
await when.toggleGroupInLayerEditor("Layer");
|
||||||
|
await then(get.elementByTestId("layer-editor.layer-id.input")).shouldNotBeVisible();
|
||||||
|
|
||||||
|
await when.toggleGroupInLayerEditor("Layer");
|
||||||
|
await then(get.elementByTestId("layer-editor.layer-id.input")).shouldBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
test("id", async () => {
|
test("id", async () => {
|
||||||
const bgId = await createBackground();
|
const bgId = await createBackground();
|
||||||
@@ -76,6 +87,14 @@ describe("layer editor", () => {
|
|||||||
layers: [{ id: "background:" + bgId, type: "background", minzoom: 1 }],
|
layers: [{ id: "background:" + bgId, type: "background", minzoom: 1 }],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("the range slider adjusts min-zoom", async () => {
|
||||||
|
await when.focus("min-zoom.input-range");
|
||||||
|
await when.typeKeys("{rightarrow}");
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
layers: [{ id: "background:" + bgId, type: "background", minzoom: 2 }],
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("max-zoom", () => {
|
describe("max-zoom", () => {
|
||||||
@@ -145,6 +164,13 @@ describe("layer editor", () => {
|
|||||||
layers: [{ id: "background:" + bgId, type: "background" }],
|
layers: [{ id: "background:" + bgId, type: "background" }],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("typing a hex value updates the paint color", async () => {
|
||||||
|
await when.setColorValue("background-color", "#ff0000");
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
layers: [{ id: "background:" + bgId, type: "background", paint: { "background-color": "#ff0000" } }],
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("opacity", () => {
|
describe("opacity", () => {
|
||||||
@@ -166,8 +192,287 @@ describe("layer editor", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("filter", () => {
|
describe("filter", () => {
|
||||||
test.skip("expand/collapse", () => {});
|
let id: string;
|
||||||
test.skip("compound filter", () => {});
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
id = await when.modal.fillLayers({ type: "fill", layer: "example" });
|
||||||
|
await when.addFilter();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should add a filter item", async () => {
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
layers: [{ id, type: "fill", source: "example", filter: ["all", ["==", "name", ""]] }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should change the filter operator", async () => {
|
||||||
|
await when.selectFilterOperator("!=");
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
layers: [{ id, filter: ["all", ["!=", "name", ""]] }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should extend the compound filter with a second item", async () => {
|
||||||
|
await when.addFilter();
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
layers: [{ id, filter: ["all", ["==", "name", ""], ["==", "name", ""]] }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should change the combining operator", async () => {
|
||||||
|
await when.selectFilterCombiningOperator("any");
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
layers: [{ id, filter: ["any", ["==", "name", ""]] }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should delete a filter item", async () => {
|
||||||
|
await when.addFilter();
|
||||||
|
await when.deleteFilterItem();
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
layers: [{ id, filter: ["all", ["==", "name", ""]] }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when converted to an expression", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await when.convertFilterToExpression();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should migrate the filter to an expression", async () => {
|
||||||
|
// A single-item "all" collapses to the bare comparison when migrated.
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
layers: [{ id, filter: ["==", ["get", "name"], ""] }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should restore the default filter when the expression is deleted", async () => {
|
||||||
|
await when.deleteFilterExpression();
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
layers: [{ id, filter: ["all"] }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("functions", () => {
|
||||||
|
let id: string;
|
||||||
|
|
||||||
|
describe("zoom function", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
id = await when.modal.fillLayers({ type: "circle", layer: "example" });
|
||||||
|
await when.makeZoomFunction("circle-radius");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should convert the property to a zoom function", async () => {
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
layers: [
|
||||||
|
{ id, type: "circle", source: "example", paint: { "circle-radius": { stops: [[6, 5], [10, 5]] } } },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should add a stop", async () => {
|
||||||
|
await when.addFunctionStop("circle-radius");
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
layers: [{ id, paint: { "circle-radius": { stops: [[6, 5], [10, 5], [11, 5]] } } }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should delete the first stop", async () => {
|
||||||
|
// A function needs more than two stops, otherwise deleting one collapses
|
||||||
|
// it back into a plain value.
|
||||||
|
await when.addFunctionStop("circle-radius");
|
||||||
|
await when.deleteFunctionStop("circle-radius");
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
layers: [{ id, paint: { "circle-radius": { stops: [[10, 5], [11, 5]] } } }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should set the base", async () => {
|
||||||
|
await when.setFunctionBase("circle-radius", "2");
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
layers: [{ id, paint: { "circle-radius": { base: 2, stops: [[6, 5], [10, 5]] } } }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should edit the zoom of a stop", async () => {
|
||||||
|
await when.setFunctionStopValue("circle-radius", "Zoom", 0, "3");
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
layers: [{ id, paint: { "circle-radius": { stops: [[3, 5], [10, 5]] } } }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should edit the output value of a stop", async () => {
|
||||||
|
await when.setFunctionStopValue("circle-radius", "Output value", 0, "9");
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
layers: [{ id, paint: { "circle-radius": { stops: [[6, 9], [10, 5]] } } }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should convert to an expression", async () => {
|
||||||
|
await when.makeExpression("circle-radius");
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
layers: [{ id, paint: { "circle-radius": ["interpolate", ["linear"], ["zoom"], 6, 5, 10, 5] } }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when converted to a data function", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
// Any non-interpolate scale turns the zoom function into a data one.
|
||||||
|
await when.selectFunctionType("circle-radius", "categorical");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should carry the stops over as zoom/value pairs", async () => {
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
layers: [
|
||||||
|
{
|
||||||
|
id,
|
||||||
|
paint: {
|
||||||
|
"circle-radius": {
|
||||||
|
property: "",
|
||||||
|
type: "exponential",
|
||||||
|
stops: [[{ zoom: 6, value: 0 }, 5], [{ zoom: 10, value: 0 }, 5]],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should convert back to a zoom function", async () => {
|
||||||
|
await when.selectFunctionType("circle-radius", "interpolate");
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
layers: [{ id, paint: { "circle-radius": { stops: [[6, 5], [10, 5]] } } }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("data function", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
id = await when.modal.fillLayers({ type: "circle", layer: "example" });
|
||||||
|
await when.setValue("spec-field-input:circle-blur", "1");
|
||||||
|
await when.makeDataFunction("circle-blur");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should convert the property to a data function", async () => {
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
layers: [
|
||||||
|
{
|
||||||
|
id,
|
||||||
|
type: "circle",
|
||||||
|
source: "example",
|
||||||
|
paint: {
|
||||||
|
"circle-blur": {
|
||||||
|
property: "",
|
||||||
|
type: "exponential",
|
||||||
|
stops: [[{ zoom: 6, value: 0 }, 1], [{ zoom: 10, value: 0 }, 1]],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should add a stop", async () => {
|
||||||
|
await when.addFunctionStop("circle-blur");
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
layers: [
|
||||||
|
{
|
||||||
|
id,
|
||||||
|
paint: {
|
||||||
|
"circle-blur": {
|
||||||
|
stops: [[{ zoom: 6, value: 0 }, 1], [{ zoom: 10, value: 0 }, 1], [{ zoom: 11, value: 0 }, 1]],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should delete the first stop", async () => {
|
||||||
|
await when.addFunctionStop("circle-blur");
|
||||||
|
await when.deleteFunctionStop("circle-blur");
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
layers: [
|
||||||
|
{
|
||||||
|
id,
|
||||||
|
paint: {
|
||||||
|
"circle-blur": {
|
||||||
|
stops: [[{ zoom: 10, value: 0 }, 1], [{ zoom: 11, value: 0 }, 1]],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should set the property", async () => {
|
||||||
|
await when.setFunctionProperty("circle-blur", "myprop");
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
layers: [{ id, paint: { "circle-blur": { property: "myprop" } } }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should set the default", async () => {
|
||||||
|
await when.setFunctionDefault("circle-blur", "0.5");
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
layers: [{ id, paint: { "circle-blur": { default: 0.5 } } }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should edit the input value of a stop", async () => {
|
||||||
|
await when.setFunctionStopValue("circle-blur", "Input value", 0, "7");
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
layers: [
|
||||||
|
{
|
||||||
|
id,
|
||||||
|
paint: {
|
||||||
|
"circle-blur": {
|
||||||
|
stops: [[{ zoom: 6, value: 7 }, 1], [{ zoom: 10, value: 0 }, 1]],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should change the function type", async () => {
|
||||||
|
await when.selectFunctionType("circle-blur", "categorical");
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
layers: [{ id, paint: { "circle-blur": { type: "categorical" } } }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("expression", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
id = await when.modal.fillLayers({ type: "circle", layer: "example" });
|
||||||
|
await when.setValue("spec-field-input:circle-blur", "1");
|
||||||
|
await when.makeExpression("circle-blur");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should wrap the property value in a literal expression", async () => {
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
layers: [{ id, paint: { "circle-blur": ["literal", 1] } }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should restore the plain value when reverted", async () => {
|
||||||
|
await when.undoExpression("circle-blur");
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
layers: [{ id, paint: { "circle-blur": 1 } }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should fall back to the spec default when deleted", async () => {
|
||||||
|
await when.deleteExpression("circle-blur");
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
layers: [{ id, paint: { "circle-blur": 0 } }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("layout", () => {
|
describe("layout", () => {
|
||||||
@@ -183,10 +488,43 @@ describe("layer editor", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("paint", () => {
|
describe("paint", () => {
|
||||||
test.skip("expand/collapse", () => {});
|
let id: string;
|
||||||
test.skip("color", () => {});
|
|
||||||
test.skip("pattern", () => {});
|
beforeEach(async () => {
|
||||||
test.skip("opacity", () => {});
|
id = await when.modal.fillLayers({ type: "fill", layer: "example" });
|
||||||
|
});
|
||||||
|
|
||||||
|
test("expand/collapse", async () => {
|
||||||
|
await then(get.elementByTestId("spec-field:fill-color")).shouldBeVisible();
|
||||||
|
|
||||||
|
await when.toggleGroupInLayerEditor("Paint properties");
|
||||||
|
await then(get.elementByTestId("spec-field:fill-color")).shouldNotBeVisible();
|
||||||
|
|
||||||
|
await when.toggleGroupInLayerEditor("Paint properties");
|
||||||
|
await then(get.elementByTestId("spec-field:fill-color")).shouldBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("color", async () => {
|
||||||
|
await when.setColorValue("fill-color", "#ff0000");
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
layers: [{ id, type: "fill", source: "example", paint: { "fill-color": "#ff0000" } }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("pattern", async () => {
|
||||||
|
await when.setStringValue("fill-pattern", "some-pattern");
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
layers: [{ id, type: "fill", source: "example", paint: { "fill-pattern": "some-pattern" } }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("opacity", async () => {
|
||||||
|
await when.setValue("spec-field-input:fill-opacity", "0.4");
|
||||||
|
await when.click("layer-editor.layer-id");
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
layers: [{ id, type: "fill", source: "example", paint: { "fill-opacity": 0.4 } }],
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("json-editor", () => {
|
describe("json-editor", () => {
|
||||||
@@ -206,8 +544,28 @@ describe("layer editor", () => {
|
|||||||
await then(get.element(".cm-lint-marker-error")).shouldExist();
|
await then(get.element(".cm-lint-marker-error")).shouldExist();
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip("expand/collapse", () => {});
|
test("expand/collapse", async () => {
|
||||||
test.skip("modify", () => {});
|
const bgId = await createBackground();
|
||||||
|
await when.click("layer-list-item:background:" + bgId);
|
||||||
|
|
||||||
|
await then(get.element(".cm-content")).shouldBeVisible();
|
||||||
|
|
||||||
|
await when.toggleGroupInLayerEditor("JSON Editor");
|
||||||
|
await then(get.element(".cm-content")).shouldNotBeVisible();
|
||||||
|
|
||||||
|
await when.toggleGroupInLayerEditor("JSON Editor");
|
||||||
|
await then(get.element(".cm-content")).shouldBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("modify", async () => {
|
||||||
|
const bgId = await createBackground();
|
||||||
|
await when.click("layer-list-item:background:" + bgId);
|
||||||
|
|
||||||
|
await when.appendToJsonEditorLine('"background"', ',\n"minzoom": 5');
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
layers: [{ id: "background:" + bgId, type: "background", minzoom: 5 }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test("parse error", async () => {
|
test("parse error", async () => {
|
||||||
const bgId = await createBackground();
|
const bgId = await createBackground();
|
||||||
|
|||||||
+16
-3
@@ -97,7 +97,15 @@ describe("layers list", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip("modify", () => {});
|
test("modify", async () => {
|
||||||
|
const id = await when.modal.fillLayers({ type: "background" });
|
||||||
|
await when.click("layer-list-item:" + id);
|
||||||
|
await when.setValue("spec-field-input:background-opacity", "0.4");
|
||||||
|
await when.click("layer-editor.layer-id");
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
layers: [{ id, type: "background", paint: { "background-opacity": 0.4 } }],
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("fill", () => {
|
describe("fill", () => {
|
||||||
@@ -108,8 +116,13 @@ describe("layers list", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: Change source
|
test("change source", async () => {
|
||||||
test.skip("change source", () => {});
|
const id = await when.modal.fillLayers({ type: "fill", layer: "example" });
|
||||||
|
await when.changeLayerSource("raster");
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
layers: [{ id, type: "fill", source: "raster" }],
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("line", () => {
|
describe("line", () => {
|
||||||
|
|||||||
+167
-1
@@ -38,6 +38,7 @@ export class MaputnikDriver {
|
|||||||
"example-style-with-fonts.json",
|
"example-style-with-fonts.json",
|
||||||
"example-style-with-zoom-7-and-center-0-51.json",
|
"example-style-with-zoom-7-and-center-0-51.json",
|
||||||
"example-style-with-zoom-5-and-center-50-50.json",
|
"example-style-with-zoom-5-and-center-50-50.json",
|
||||||
|
"access-token-style.json",
|
||||||
];
|
];
|
||||||
for (const fixture of styleFixtures) {
|
for (const fixture of styleFixtures) {
|
||||||
await this.helper.given.interceptAndMockResponse({
|
await this.helper.given.interceptAndMockResponse({
|
||||||
@@ -71,6 +72,7 @@ export class MaputnikDriver {
|
|||||||
| "rectangles"
|
| "rectangles"
|
||||||
| "font"
|
| "font"
|
||||||
| "zoom_7_center_0_51"
|
| "zoom_7_center_0_51"
|
||||||
|
| "access_tokens"
|
||||||
| "",
|
| "",
|
||||||
zoom?: number
|
zoom?: number
|
||||||
) => {
|
) => {
|
||||||
@@ -82,6 +84,7 @@ export class MaputnikDriver {
|
|||||||
rectangles: "rectangles-style.json",
|
rectangles: "rectangles-style.json",
|
||||||
font: "example-style-with-fonts.json",
|
font: "example-style-with-fonts.json",
|
||||||
zoom_7_center_0_51: "example-style-with-zoom-7-and-center-0-51.json",
|
zoom_7_center_0_51: "example-style-with-zoom-7-and-center-0-51.json",
|
||||||
|
access_tokens: "access-token-style.json",
|
||||||
};
|
};
|
||||||
|
|
||||||
const url = new URL(baseUrl);
|
const url = new URL(baseUrl);
|
||||||
@@ -107,7 +110,13 @@ export class MaputnikDriver {
|
|||||||
},
|
},
|
||||||
|
|
||||||
chooseExampleFile: async () => {
|
chooseExampleFile: async () => {
|
||||||
await this.helper.when.openFileByFixture("example-style.json", "modal:open.dropzone", "modal:open.file.input");
|
await this.helper.when.openFileByFixture("example-style.json", "modal:open.dropzone");
|
||||||
|
await this.helper.when.wait(200);
|
||||||
|
},
|
||||||
|
|
||||||
|
/** Picks the example style through the browser's native file chooser. */
|
||||||
|
chooseExampleFileFromPicker: async () => {
|
||||||
|
await this.helper.when.chooseFileFromPicker("example-style.json", "modal:open.dropzone");
|
||||||
await this.helper.when.wait(200);
|
await this.helper.when.wait(200);
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -128,6 +137,22 @@ export class MaputnikDriver {
|
|||||||
await this.helper.get.element(".maputnik-layer-editor-group__button").nth(index).click();
|
await this.helper.get.element(".maputnik-layer-editor-group__button").nth(index).click();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/** Expands/collapses a layer-editor group by its title, e.g. "Paint properties". */
|
||||||
|
toggleGroupInLayerEditor: async (title: string) => {
|
||||||
|
await this.helper.when.click("layer-editor-group:" + title);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Picks a source for the selected layer from the source autocomplete.
|
||||||
|
* The autocomplete is a controlled (downshift) input, so the value has to be
|
||||||
|
* filled rather than typed key by key, then chosen from the filtered menu.
|
||||||
|
*/
|
||||||
|
changeLayerSource: async (sourceId: string) => {
|
||||||
|
const input = this.helper.get.elementByTestId("layer-editor.layer-source").locator("input");
|
||||||
|
await input.fill(sourceId);
|
||||||
|
await this.helper.get.element(".maputnik-autocomplete-menu-item").first().click();
|
||||||
|
},
|
||||||
|
|
||||||
appendTextInJsonEditor: async (text: string) => {
|
appendTextInJsonEditor: async (text: string) => {
|
||||||
await this.helper.get.element(".cm-line").first().click();
|
await this.helper.get.element(".cm-line").first().click();
|
||||||
// Move to the very start of the document so the inserted text breaks the
|
// Move to the very start of the document so the inserted text breaks the
|
||||||
@@ -158,6 +183,147 @@ export class MaputnikDriver {
|
|||||||
await this.helper.when.typeText(value);
|
await this.helper.when.typeText(value);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
makeZoomFunction: async (fieldName: string) => {
|
||||||
|
const container = this.helper.get.elementByTestId("spec-field-container:" + fieldName);
|
||||||
|
await container.scrollIntoViewIfNeeded();
|
||||||
|
await container.locator(".maputnik-make-zoom-function").last().click({ force: true });
|
||||||
|
},
|
||||||
|
|
||||||
|
makeDataFunction: async (fieldName: string) => {
|
||||||
|
const container = this.helper.get.elementByTestId("spec-field-container:" + fieldName);
|
||||||
|
await container.scrollIntoViewIfNeeded();
|
||||||
|
await container.locator(".maputnik-make-data-function").click({ force: true });
|
||||||
|
},
|
||||||
|
|
||||||
|
addFunctionStop: async (fieldName: string) => {
|
||||||
|
const container = this.helper.get.elementByTestId("spec-field-container:" + fieldName);
|
||||||
|
await container.locator(".maputnik-add-stop").first().click({ force: true });
|
||||||
|
},
|
||||||
|
|
||||||
|
deleteFunctionStop: async (fieldName: string) => {
|
||||||
|
const container = this.helper.get.elementByTestId("spec-field-container:" + fieldName);
|
||||||
|
await container.locator(".maputnik-delete-stop").first().click({ force: true });
|
||||||
|
},
|
||||||
|
|
||||||
|
/** Turns the property into a raw style expression. */
|
||||||
|
makeExpression: async (fieldName: string) => {
|
||||||
|
const container = this.helper.get.elementByTestId("spec-field-container:" + fieldName);
|
||||||
|
await container.scrollIntoViewIfNeeded();
|
||||||
|
// In the plain spec field the expression button shares the zoom-function
|
||||||
|
// class and comes first; inside a function editor it has its own test id.
|
||||||
|
const inFunctionEditor = container.locator("[data-wd-key='convert-to-expression']");
|
||||||
|
const button =
|
||||||
|
(await inFunctionEditor.count()) > 0
|
||||||
|
? inFunctionEditor
|
||||||
|
: container.locator(".maputnik-make-zoom-function").first();
|
||||||
|
await button.click({ force: true });
|
||||||
|
},
|
||||||
|
|
||||||
|
/** Reverts an expression back to a plain value. */
|
||||||
|
undoExpression: async (fieldName: string) => {
|
||||||
|
const container = this.helper.get.elementByTestId("spec-field-container:" + fieldName);
|
||||||
|
await container.locator("[data-wd-key='undo-expression']").click({ force: true });
|
||||||
|
},
|
||||||
|
|
||||||
|
/** Removes an expression, restoring the property's spec default. */
|
||||||
|
deleteExpression: async (fieldName: string) => {
|
||||||
|
const container = this.helper.get.elementByTestId("spec-field-container:" + fieldName);
|
||||||
|
await container.locator("[data-wd-key='delete-expression']").click({ force: true });
|
||||||
|
},
|
||||||
|
|
||||||
|
/** Picks the function scale (categorical/interval/exponential/identity/interpolate). */
|
||||||
|
selectFunctionType: async (fieldName: string, type: string) => {
|
||||||
|
const container = this.helper.get.elementByTestId("spec-field-container:" + fieldName);
|
||||||
|
await container.locator("[data-wd-key='function-type'] select").selectOption(type);
|
||||||
|
},
|
||||||
|
|
||||||
|
/** Sets the "Base" input of a zoom/data function. */
|
||||||
|
setFunctionBase: async (fieldName: string, value: string) => {
|
||||||
|
const container = this.helper.get.elementByTestId("spec-field-container:" + fieldName);
|
||||||
|
await container.locator("[data-wd-key='function-base'] input").fill(value);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the data property a data function keys off of. This is an InputString,
|
||||||
|
* which only commits its value on blur, so typing alone is not enough.
|
||||||
|
*/
|
||||||
|
setFunctionProperty: async (fieldName: string, value: string) => {
|
||||||
|
const container = this.helper.get.elementByTestId("spec-field-container:" + fieldName);
|
||||||
|
const input = container.locator("[data-wd-key='function-property'] input");
|
||||||
|
await input.fill(value);
|
||||||
|
await input.blur();
|
||||||
|
},
|
||||||
|
|
||||||
|
/** Sets the fallback value used when a feature has no matching stop. */
|
||||||
|
setFunctionDefault: async (fieldName: string, value: string) => {
|
||||||
|
const container = this.helper.get.elementByTestId("spec-field-container:" + fieldName);
|
||||||
|
await container.locator("[data-wd-key='function-default'] input").fill(value);
|
||||||
|
},
|
||||||
|
|
||||||
|
/** Edits one cell of a function's stop table ("Zoom", "Input value" or "Output value"). */
|
||||||
|
setFunctionStopValue: async (fieldName: string, column: string, index: number, value: string) => {
|
||||||
|
const container = this.helper.get.elementByTestId("spec-field-container:" + fieldName);
|
||||||
|
await container.locator(`[aria-label="${column}"]`).nth(index).fill(value);
|
||||||
|
},
|
||||||
|
|
||||||
|
addFilter: async () => {
|
||||||
|
const button = this.helper.get.elementByTestId("layer-filter-button");
|
||||||
|
await button.scrollIntoViewIfNeeded();
|
||||||
|
await button.click({ force: true });
|
||||||
|
},
|
||||||
|
|
||||||
|
selectFilterOperator: async (value: string) => {
|
||||||
|
await this.helper.get.element(".maputnik-filter-editor-operator select").first().selectOption(value);
|
||||||
|
},
|
||||||
|
|
||||||
|
/** Chooses how the filter items combine: all / none / any. */
|
||||||
|
selectFilterCombiningOperator: async (value: string) => {
|
||||||
|
await this.helper.when.selectWithin("filter-combining-operator", value);
|
||||||
|
},
|
||||||
|
|
||||||
|
deleteFilterItem: async (index = 0) => {
|
||||||
|
await this.helper.get
|
||||||
|
.element(".maputnik-filter-editor-block-action .maputnik-icon-button")
|
||||||
|
.nth(index)
|
||||||
|
.click();
|
||||||
|
},
|
||||||
|
|
||||||
|
/** Converts the simple filter editor into a raw expression editor. */
|
||||||
|
convertFilterToExpression: async () => {
|
||||||
|
await this.helper.when.click("filter-convert-to-expression");
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the filter expression, restoring the simple filter editor.
|
||||||
|
* The filter group precedes the paint group, so its button comes first.
|
||||||
|
*/
|
||||||
|
deleteFilterExpression: async () => {
|
||||||
|
await this.helper.get.element("[data-wd-key='delete-expression']").first().click();
|
||||||
|
},
|
||||||
|
|
||||||
|
setColorValue: async (fieldName: string, value: string) => {
|
||||||
|
const input = this.helper.get.elementByTestId("spec-field:" + fieldName).locator(".maputnik-color");
|
||||||
|
await input.fill(value);
|
||||||
|
},
|
||||||
|
|
||||||
|
/** Sets a plain string spec field (e.g. a pattern), which has no dedicated input test id. */
|
||||||
|
setStringValue: async (fieldName: string, value: string) => {
|
||||||
|
const input = this.helper.get.elementByTestId("spec-field:" + fieldName).locator("input.maputnik-string");
|
||||||
|
await input.fill(value);
|
||||||
|
await input.blur();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends text to the end of the JSON editor line holding `lineText`.
|
||||||
|
* CodeMirror types over its own auto-inserted closing quotes/brackets, so a
|
||||||
|
* well-formed fragment stays well-formed.
|
||||||
|
*/
|
||||||
|
appendToJsonEditorLine: async (lineText: string, text: string) => {
|
||||||
|
await this.helper.when.clickByText(lineText);
|
||||||
|
await this.helper.when.typeKeys("{end}");
|
||||||
|
await this.helper.when.typeText(text);
|
||||||
|
},
|
||||||
|
|
||||||
waitForExampleFileResponse: () => this.helper.when.waitForResponse("example-style.json"),
|
waitForExampleFileResponse: () => this.helper.when.waitForResponse("example-style.json"),
|
||||||
|
|
||||||
/** Fill localStorage until we get a QuotaExceededError. */
|
/** Fill localStorage until we get a QuotaExceededError. */
|
||||||
|
|||||||
@@ -34,5 +34,45 @@ export class ModalDriver {
|
|||||||
close: async (key: string) => {
|
close: async (key: string) => {
|
||||||
await this.helper.when.click(key + ".close-modal");
|
await this.helper.when.click(key + ".close-modal");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a source of the given type from the sources modal, keeping whatever
|
||||||
|
* defaults that type's editor prefills.
|
||||||
|
*/
|
||||||
|
addSource: async (sourceId: string, sourceType: string) => {
|
||||||
|
const { when } = this.helper;
|
||||||
|
await when.setValue("modal:sources.add.source_id", sourceId);
|
||||||
|
await when.select("modal:sources.add.source_type", sourceType);
|
||||||
|
await when.click("modal:sources.add.add_source");
|
||||||
|
await when.wait(200);
|
||||||
|
},
|
||||||
|
|
||||||
|
/** Adds one of the predefined public sources listed in the sources modal. */
|
||||||
|
addPublicSource: async (index = 0) => {
|
||||||
|
await this.helper.get.element(".maputnik-public-source-select").nth(index).click();
|
||||||
|
},
|
||||||
|
|
||||||
|
deleteFirstActiveSource: async () => {
|
||||||
|
await this.helper.get.element(".maputnik-active-source-type-editor-header-delete").first().click();
|
||||||
|
},
|
||||||
|
|
||||||
|
/** Fills one number box of a coordinate pair in the image/video source editor. */
|
||||||
|
setCoordinateValue: async (index: number, value: string) => {
|
||||||
|
const input = this.helper.get
|
||||||
|
.elementByTestId("modal:sources")
|
||||||
|
.locator(".maputnik-array input")
|
||||||
|
.nth(index);
|
||||||
|
await input.fill(value);
|
||||||
|
await input.blur();
|
||||||
|
},
|
||||||
|
|
||||||
|
exportCreateHtml: async () => {
|
||||||
|
await this.helper.get.element(".maputnik-modal-export-buttons button").last().click();
|
||||||
|
},
|
||||||
|
|
||||||
|
exportSaveStyle: async () => {
|
||||||
|
await this.helper.stubSaveFilePicker();
|
||||||
|
await this.helper.get.element(".maputnik-modal-export-buttons button").first().click();
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+198
-26
@@ -43,6 +43,16 @@ describe("modals", () => {
|
|||||||
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude(get.responseBody("example-style.json"));
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude(get.responseBody("example-style.json"));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("without the File System Access API", () => {
|
||||||
|
test("upload via the file chooser", async () => {
|
||||||
|
await given.noFileSystemAccessApi();
|
||||||
|
await when.setStyle("");
|
||||||
|
await when.click("nav:open");
|
||||||
|
await when.chooseExampleFileFromPicker();
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude(get.fixture("example-style.json"));
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("shortcuts", () => {
|
describe("shortcuts", () => {
|
||||||
@@ -64,8 +74,15 @@ describe("modals", () => {
|
|||||||
await then(get.elementByTestId("modal:export")).shouldNotExist();
|
await then(get.elementByTestId("modal:export")).shouldNotExist();
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: Work out how to download a file and check the contents
|
test("download HTML and save the style", async () => {
|
||||||
test.skip("download", () => {});
|
// Generate the standalone HTML export (triggers a file download).
|
||||||
|
await when.modal.exportCreateHtml();
|
||||||
|
await then(get.elementByTestId("modal:export")).shouldExist();
|
||||||
|
|
||||||
|
// Saving the style closes the export modal.
|
||||||
|
await when.modal.exportSaveStyle();
|
||||||
|
await then(get.elementByTestId("modal:export")).shouldNotExist();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("sources", () => {
|
describe("sources", () => {
|
||||||
@@ -74,8 +91,27 @@ describe("modals", () => {
|
|||||||
await when.click("nav:sources");
|
await when.click("nav:sources");
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip("active sources", () => {});
|
test("active sources are listed and can be deleted", async () => {
|
||||||
test.skip("public source", () => {});
|
await when.setStyle("both");
|
||||||
|
await when.click("nav:sources");
|
||||||
|
const before = Object.keys(get.fixture("geojson-raster-style.json").sources).length;
|
||||||
|
await when.modal.deleteFirstActiveSource();
|
||||||
|
await then(
|
||||||
|
get.styleFromLocalStorage().then((style) => Object.keys(style.sources).length)
|
||||||
|
).shouldEqual(before - 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("public source", async () => {
|
||||||
|
await when.modal.addPublicSource();
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
sources: {
|
||||||
|
openmaptiles: {
|
||||||
|
type: "vector",
|
||||||
|
url: `https://api.maptiler.com/tiles/v3-openmaptiles/tiles.json?key=${tokens.openmaptiles}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test("add new source", async () => {
|
test("add new source", async () => {
|
||||||
const sourceId = "n1z2v3r";
|
const sourceId = "n1z2v3r";
|
||||||
@@ -84,8 +120,8 @@ describe("modals", () => {
|
|||||||
await when.select("modal:sources.add.scheme_type", "tms");
|
await when.select("modal:sources.add.scheme_type", "tms");
|
||||||
await when.click("modal:sources.add.add_source");
|
await when.click("modal:sources.add.add_source");
|
||||||
await when.wait(200);
|
await when.wait(200);
|
||||||
await then(get.styleFromLocalStorage().then((style) => style.sources[sourceId])).shouldInclude({
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
scheme: "tms",
|
sources: { [sourceId]: { scheme: "tms" } },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -118,8 +154,110 @@ describe("modals", () => {
|
|||||||
await when.setValue("modal:sources.add.tile_size", "128");
|
await when.setValue("modal:sources.add.tile_size", "128");
|
||||||
await when.click("modal:sources.add.add_source");
|
await when.click("modal:sources.add.add_source");
|
||||||
await when.wait(200);
|
await when.wait(200);
|
||||||
await then(get.styleFromLocalStorage().then((style) => style.sources[sourceId])).shouldInclude({
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
tileSize: 128,
|
sources: { [sourceId]: { tileSize: 128 } },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("add new geojson url source", async () => {
|
||||||
|
await when.modal.addSource("geojsonurl", "geojson_url");
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
sources: {
|
||||||
|
geojsonurl: { type: "geojson", data: "http://localhost:3000/geojson.json" },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("add new geojson json source", async () => {
|
||||||
|
await when.modal.addSource("geojsonjson", "geojson_json");
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
sources: {
|
||||||
|
geojsonjson: { type: "geojson", cluster: false, data: "" },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("add new tilejson vector source", async () => {
|
||||||
|
await when.modal.addSource("tilejsonvector", "tilejson_vector");
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
sources: {
|
||||||
|
tilejsonvector: { type: "vector", url: "http://localhost:3000/tilejson.json" },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("add new tilejson raster source", async () => {
|
||||||
|
await when.modal.addSource("tilejsonraster", "tilejson_raster");
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
sources: {
|
||||||
|
tilejsonraster: { type: "raster", url: "http://localhost:3000/tilejson.json" },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("add new tilejson raster-dem source", async () => {
|
||||||
|
await when.modal.addSource("tilejsonrasterdem", "tilejson_raster-dem");
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
sources: {
|
||||||
|
tilejsonrasterdem: { type: "raster-dem", url: "http://localhost:3000/tilejson.json" },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("add new tile xyz raster-dem source", async () => {
|
||||||
|
await when.modal.addSource("tilexyzrasterdem", "tilexyz_raster-dem");
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
sources: {
|
||||||
|
tilexyzrasterdem: {
|
||||||
|
type: "raster-dem",
|
||||||
|
tiles: ["http://localhost:3000/{x}/{y}/{z}.png"],
|
||||||
|
minzoom: 0,
|
||||||
|
maxzoom: 14,
|
||||||
|
tileSize: 512,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("add new image source", async () => {
|
||||||
|
await when.modal.addSource("imagesource", "image");
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
sources: {
|
||||||
|
imagesource: {
|
||||||
|
type: "image",
|
||||||
|
url: "http://localhost:3000/image.png",
|
||||||
|
coordinates: [[0, 0], [0, 0], [0, 0], [0, 0]],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("add new video source", async () => {
|
||||||
|
await when.modal.addSource("videosource", "video");
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
sources: {
|
||||||
|
videosource: {
|
||||||
|
type: "video",
|
||||||
|
urls: ["http://localhost:3000/movie.mp4"],
|
||||||
|
coordinates: [[0, 0], [0, 0], [0, 0], [0, 0]],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("edit the corner coordinates of an image source", async () => {
|
||||||
|
const sourceId = "imagecoords";
|
||||||
|
await when.setValue("modal:sources.add.source_id", sourceId);
|
||||||
|
await when.select("modal:sources.add.source_type", "image");
|
||||||
|
// The first corner is the first two number boxes of the coordinate arrays.
|
||||||
|
await when.modal.setCoordinateValue(0, "1");
|
||||||
|
await when.modal.setCoordinateValue(1, "2");
|
||||||
|
await when.click("modal:sources.add.add_source");
|
||||||
|
await when.wait(200);
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
sources: {
|
||||||
|
[sourceId]: { type: "image", coordinates: [[1, 2], [0, 0], [0, 0], [0, 0]] },
|
||||||
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -204,8 +342,8 @@ describe("modals", () => {
|
|||||||
const apiKey = "testing123";
|
const apiKey = "testing123";
|
||||||
await when.setValue("modal:settings.maputnik:openmaptiles_access_token", apiKey);
|
await when.setValue("modal:settings.maputnik:openmaptiles_access_token", apiKey);
|
||||||
await when.click("modal:settings.name");
|
await when.click("modal:settings.name");
|
||||||
await then(get.styleFromLocalStorage().then((style) => style.metadata)).shouldInclude({
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
"maputnik:openmaptiles_access_token": apiKey,
|
metadata: { "maputnik:openmaptiles_access_token": apiKey },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -213,8 +351,8 @@ describe("modals", () => {
|
|||||||
const apiKey = "testing123";
|
const apiKey = "testing123";
|
||||||
await when.setValue("modal:settings.maputnik:thunderforest_access_token", apiKey);
|
await when.setValue("modal:settings.maputnik:thunderforest_access_token", apiKey);
|
||||||
await when.click("modal:settings.name");
|
await when.click("modal:settings.name");
|
||||||
await then(get.styleFromLocalStorage().then((style) => style.metadata)).shouldInclude({
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
"maputnik:thunderforest_access_token": apiKey,
|
metadata: { "maputnik:thunderforest_access_token": apiKey },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -222,8 +360,8 @@ describe("modals", () => {
|
|||||||
const apiKey = "testing123";
|
const apiKey = "testing123";
|
||||||
await when.setValue("modal:settings.maputnik:stadia_access_token", apiKey);
|
await when.setValue("modal:settings.maputnik:stadia_access_token", apiKey);
|
||||||
await when.click("modal:settings.name");
|
await when.click("modal:settings.name");
|
||||||
await then(get.styleFromLocalStorage().then((style) => style.metadata)).shouldInclude({
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
"maputnik:stadia_access_token": apiKey,
|
metadata: { "maputnik:stadia_access_token": apiKey },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -231,29 +369,67 @@ describe("modals", () => {
|
|||||||
const apiKey = "testing123";
|
const apiKey = "testing123";
|
||||||
await when.setValue("modal:settings.maputnik:locationiq_access_token", apiKey);
|
await when.setValue("modal:settings.maputnik:locationiq_access_token", apiKey);
|
||||||
await when.click("modal:settings.name");
|
await when.click("modal:settings.name");
|
||||||
await then(get.styleFromLocalStorage().then((style) => style.metadata)).shouldInclude({
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
"maputnik:locationiq_access_token": apiKey,
|
metadata: { "maputnik:locationiq_access_token": apiKey },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("map view defaults", async () => {
|
||||||
|
await when.setValue("modal:settings.zoom", "4");
|
||||||
|
await when.setValue("modal:settings.bearing", "12");
|
||||||
|
await when.setValue("modal:settings.pitch", "30");
|
||||||
|
await when.click("modal:settings.name");
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
zoom: 4,
|
||||||
|
bearing: 12,
|
||||||
|
pitch: 30,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("light intensity", async () => {
|
||||||
|
await when.setValue("modal:settings.light-intensity", "0.7");
|
||||||
|
await when.click("modal:settings.name");
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
light: { intensity: 0.7 },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("terrain source and exaggeration", async () => {
|
||||||
|
await when.setValue("modal:settings.maputnik:terrain_source", "terrain");
|
||||||
|
await when.setValue("modal:settings.terrain-exaggeration", "1.5");
|
||||||
|
await when.click("modal:settings.name");
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
terrain: { source: "terrain", exaggeration: 1.5 },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("transition delay and duration", async () => {
|
||||||
|
await when.setValue("modal:settings.transition-delay", "100");
|
||||||
|
await when.setValue("modal:settings.transition-duration", "500");
|
||||||
|
await when.click("modal:settings.name");
|
||||||
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
|
transition: { delay: 100, duration: 500 },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("style projection mercator", async () => {
|
test("style projection mercator", async () => {
|
||||||
await when.select("modal:settings.projection", "mercator");
|
await when.select("modal:settings.projection", "mercator");
|
||||||
await then(get.styleFromLocalStorage().then((style) => style.projection)).shouldInclude({
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
type: "mercator",
|
projection: { type: "mercator" },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("style projection globe", async () => {
|
test("style projection globe", async () => {
|
||||||
await when.select("modal:settings.projection", "globe");
|
await when.select("modal:settings.projection", "globe");
|
||||||
await then(get.styleFromLocalStorage().then((style) => style.projection)).shouldInclude({
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
type: "globe",
|
projection: { type: "globe" },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("style projection vertical-perspective", async () => {
|
test("style projection vertical-perspective", async () => {
|
||||||
await when.select("modal:settings.projection", "vertical-perspective");
|
await when.select("modal:settings.projection", "vertical-perspective");
|
||||||
await then(get.styleFromLocalStorage().then((style) => style.projection)).shouldInclude({
|
await then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
|
||||||
type: "vertical-perspective",
|
projection: { type: "vertical-perspective" },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -311,10 +487,6 @@ describe("modals", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("sources placeholder", () => {
|
|
||||||
test.skip("toggle", () => {});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("global state", () => {
|
describe("global state", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await when.click("nav:global-state");
|
await when.click("nav:global-state");
|
||||||
|
|||||||
+61
-22
@@ -62,11 +62,12 @@ function isLocator(target: unknown): target is Locator {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Asserts that every top-level key in `expected` deep-equals its counterpart in `actual`. */
|
/**
|
||||||
function assertDeepNestedInclude(actual: any, expected: Record<string, unknown>): void {
|
* Asserts that `actual` recursively contains everything in `expected`: nested
|
||||||
for (const key of Object.keys(expected)) {
|
* objects are matched as subsets, while arrays and primitives must match exactly.
|
||||||
expect(actual?.[key], `property "${key}"`).toEqual(expected[key]);
|
*/
|
||||||
}
|
function assertDeepNestedInclude(actual: any, expected: Record<string, unknown> | unknown[]): void {
|
||||||
|
expect(actual).toMatchObject(expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -130,7 +131,7 @@ export class Assertable<T> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
shouldDeepNestedInclude = (value: Record<string, unknown>) =>
|
shouldDeepNestedInclude = (value: Record<string, unknown> | unknown[]) =>
|
||||||
this.assertValue((actual) => assertDeepNestedInclude(actual, value));
|
this.assertValue((actual) => assertDeepNestedInclude(actual, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,6 +145,8 @@ async function typeSequence(page: Page, text: string): Promise<void> {
|
|||||||
del: "Delete",
|
del: "Delete",
|
||||||
tab: "Tab",
|
tab: "Tab",
|
||||||
home: "Home",
|
home: "Home",
|
||||||
|
end: "End",
|
||||||
|
rightarrow: "ArrowRight",
|
||||||
};
|
};
|
||||||
|
|
||||||
for (let i = 0; i < tokens.length; i++) {
|
for (let i = 0; i < tokens.length; i++) {
|
||||||
@@ -202,10 +205,31 @@ export class PlaywrightHelper {
|
|||||||
return new Query<T>(getter);
|
return new Query<T>(getter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Stubs the File System Access "save" picker so file saves complete headlessly. */
|
||||||
|
public stubSaveFilePicker(): Promise<void> {
|
||||||
|
return this.page.evaluate(() => {
|
||||||
|
(window as any).showSaveFilePicker = async () => ({
|
||||||
|
createWritable: async () => ({ write: async () => {}, close: async () => {} }),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/** Entry point for fluent assertions over a Locator or a value/Query. */
|
/** Entry point for fluent assertions over a Locator or a value/Query. */
|
||||||
public then = <T>(target: T): Assertable<T> => new Assertable(target);
|
public then = <T>(target: T): Assertable<T> => new Assertable(target);
|
||||||
|
|
||||||
public given = {
|
public given = {
|
||||||
|
/**
|
||||||
|
* Removes the File System Access API so the app falls back to a plain
|
||||||
|
* <input type="file">, the way Firefox and Safari behave. Must be called
|
||||||
|
* before the page under test is loaded.
|
||||||
|
*/
|
||||||
|
noFileSystemAccessApi: async () => {
|
||||||
|
await this.page.addInitScript(() => {
|
||||||
|
delete (window as any).showOpenFilePicker;
|
||||||
|
delete (window as any).showSaveFilePicker;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
intercept: async (pattern: RegExp, alias: string, _method = "GET") => {
|
intercept: async (pattern: RegExp, alias: string, _method = "GET") => {
|
||||||
this.recordedRequests.set(alias, []);
|
this.recordedRequests.set(alias, []);
|
||||||
await this.page.route(pattern, (route) => {
|
await this.page.route(pattern, (route) => {
|
||||||
@@ -333,23 +357,38 @@ export class PlaywrightHelper {
|
|||||||
await this.page.mouse.up();
|
await this.page.mouse.up();
|
||||||
},
|
},
|
||||||
|
|
||||||
openFileByFixture: async (fixture: string, buttonTestId: string, inputTestId: string) => {
|
/**
|
||||||
|
* Opens a fixture through the File System Access API, which raises no
|
||||||
|
* "filechooser" event and so has to be stubbed. For the <input type="file">
|
||||||
|
* fallback that browsers without the API use, see chooseFileFromPicker.
|
||||||
|
*/
|
||||||
|
openFileByFixture: async (fixture: string, buttonTestId: string) => {
|
||||||
const content = JSON.stringify(this.readFixture(fixture));
|
const content = JSON.stringify(this.readFixture(fixture));
|
||||||
const hasPicker = await this.page.evaluate(() => "showOpenFilePicker" in window);
|
await this.page.evaluate((fileContent) => {
|
||||||
if (hasPicker) {
|
(window as any).showOpenFilePicker = async () => [
|
||||||
await this.page.evaluate((fileContent) => {
|
{ getFile: async () => ({ text: async () => fileContent }) },
|
||||||
(window as any).showOpenFilePicker = async () => [
|
];
|
||||||
{ getFile: async () => ({ text: async () => fileContent }) },
|
}, content);
|
||||||
];
|
await this.testId(buttonTestId).click();
|
||||||
}, content);
|
},
|
||||||
await this.testId(buttonTestId).click();
|
|
||||||
} else {
|
/**
|
||||||
await this.testId(inputTestId).setInputFiles({
|
* Clicks a control that opens the browser's native file chooser and answers
|
||||||
name: fixture,
|
* it with a fixture. Only works on the <input type="file"> path — the File
|
||||||
mimeType: "application/json",
|
* System Access API does not raise a "filechooser" event, so pair this with
|
||||||
buffer: Buffer.from(content),
|
* given.noFileSystemAccessApi().
|
||||||
});
|
*/
|
||||||
}
|
chooseFileFromPicker: async (fixture: string, triggerTestId: string) => {
|
||||||
|
const content = JSON.stringify(this.readFixture(fixture));
|
||||||
|
const [fileChooser] = await Promise.all([
|
||||||
|
this.page.waitForEvent("filechooser"),
|
||||||
|
this.testId(triggerTestId).click(),
|
||||||
|
]);
|
||||||
|
await fileChooser.setFiles({
|
||||||
|
name: fixture,
|
||||||
|
mimeType: "application/json",
|
||||||
|
buffer: Buffer.from(content),
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
dropFileByFixture: async (fixture: string, dropzoneTestId: string) => {
|
dropFileByFixture: async (fixture: string, dropzoneTestId: string) => {
|
||||||
|
|||||||
+3
-1
@@ -34,7 +34,9 @@ export default defineConfig({
|
|||||||
rules: {
|
rules: {
|
||||||
"react-refresh/only-export-components": [
|
"react-refresh/only-export-components": [
|
||||||
"warn",
|
"warn",
|
||||||
{ allowConstantExport: true }
|
// Many components are exported as withTranslation()(Component); without
|
||||||
|
// this the rule cannot tell the HOC's result is still a component.
|
||||||
|
{ allowConstantExport: true, extraHOCs: ["withTranslation"] }
|
||||||
],
|
],
|
||||||
"@typescript-eslint/no-explicit-any": "off",
|
"@typescript-eslint/no-explicit-any": "off",
|
||||||
"@typescript-eslint/no-unused-vars": [
|
"@typescript-eslint/no-unused-vars": [
|
||||||
|
|||||||
Generated
+167
-323
@@ -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.8.2",
|
"@maplibre/maplibre-gl-inspect": "^1.8.2",
|
||||||
"@maplibre/maplibre-gl-style-spec": "^25.0.2",
|
"@maplibre/maplibre-gl-style-spec": "^26.2.1",
|
||||||
"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",
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
"downshift": "^9.4.0",
|
"downshift": "^9.4.0",
|
||||||
"events": "^3.3.0",
|
"events": "^3.3.0",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
"i18next": "^26.3.4",
|
"i18next": "^26.3.6",
|
||||||
"i18next-browser-languagedetector": "^8.2.1",
|
"i18next-browser-languagedetector": "^8.2.1",
|
||||||
"i18next-resources-to-backend": "^1.2.1",
|
"i18next-resources-to-backend": "^1.2.1",
|
||||||
"json-stringify-pretty-compact": "^4.0.0",
|
"json-stringify-pretty-compact": "^4.0.0",
|
||||||
@@ -90,31 +90,28 @@
|
|||||||
"@types/string-hash": "^1.1.3",
|
"@types/string-hash": "^1.1.3",
|
||||||
"@types/wicg-file-system-access": "^2023.10.7",
|
"@types/wicg-file-system-access": "^2023.10.7",
|
||||||
"@vitejs/plugin-react": "5.2",
|
"@vitejs/plugin-react": "5.2",
|
||||||
"@vitest/browser": "^4.1.10",
|
|
||||||
"@vitest/browser-playwright": "^4.1.10",
|
|
||||||
"@vitest/coverage-v8": "^4.1.10",
|
"@vitest/coverage-v8": "^4.1.10",
|
||||||
"cors": "^2.8.6",
|
"cors": "^2.8.6",
|
||||||
"eslint": "^10.6.0",
|
"eslint": "^10.7.0",
|
||||||
"eslint-plugin-react": "^7.37.5",
|
"eslint-plugin-react": "^7.37.5",
|
||||||
"eslint-plugin-react-hooks": "^7.1.1",
|
"eslint-plugin-react-hooks": "^7.1.1",
|
||||||
"eslint-plugin-react-refresh": "^0.5.3",
|
"eslint-plugin-react-refresh": "^0.5.3",
|
||||||
"i18next-cli": "^1.65.0",
|
"i18next-cli": "^1.67.1",
|
||||||
"istanbul": "^0.4.5",
|
"istanbul": "^0.4.5",
|
||||||
"istanbul-lib-coverage": "^3.2.2",
|
"istanbul-lib-coverage": "^3.2.2",
|
||||||
"nyc": "^18.0.0",
|
"nyc": "^18.0.0",
|
||||||
"postcss": "^8.5.16",
|
"postcss": "^8.5.22",
|
||||||
"react-hot-loader": "^4.13.1",
|
"react-hot-loader": "^4.13.1",
|
||||||
"sass": "^1.101.0",
|
"sass": "^1.101.7",
|
||||||
"stylelint": "^17.14.0",
|
"stylelint": "^17.14.1",
|
||||||
"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.62.1",
|
"typescript-eslint": "^8.65.0",
|
||||||
"uuid": "^14.0.1",
|
"uuid": "^14.0.1",
|
||||||
"vite": "^7.3.2",
|
"vite": "^7.3.2",
|
||||||
"vite-plugin-istanbul": "^9.0.1",
|
"vite-plugin-istanbul": "^9.0.1",
|
||||||
"vitest": "^4.1.10",
|
"vitest": "^4.1.10"
|
||||||
"vitest-browser-react": "^2.2.0"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/code-frame": {
|
"node_modules/@babel/code-frame": {
|
||||||
@@ -438,21 +435,14 @@
|
|||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@blazediff/core": {
|
|
||||||
"version": "1.9.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@blazediff/core/-/core-1.9.1.tgz",
|
|
||||||
"integrity": "sha512-ehg3jIkYKulZh+8om/O25vkvSsXXwC+skXmyA87FFx6A/45eqOkZsBltMw/TVteb0mloiGT8oGRTcjRAz66zaA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/@cacheable/memory": {
|
"node_modules/@cacheable/memory": {
|
||||||
"version": "2.0.9",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@cacheable/memory/-/memory-2.0.9.tgz",
|
"resolved": "https://registry.npmjs.org/@cacheable/memory/-/memory-2.2.0.tgz",
|
||||||
"integrity": "sha512-HdMx6DoGywB30vacDbBsITbIX4pgFqj1zsrV58jZBUw3klzkNoXhj7qOqAgledhxG7YZI5rBSJg7Zp8/VG0DuA==",
|
"integrity": "sha512-CTLKqLItRCEixEAewD3/j9DB3/o96gpTPD4eJ1v+DGOlxZRZncRQkGYqqnAGCscYd6RNeXfGeiuCphsPtqyIfQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cacheable/utils": "^2.4.1",
|
"@cacheable/utils": "^2.5.0",
|
||||||
"@keyv/bigmap": "^1.3.1",
|
"@keyv/bigmap": "^1.3.1",
|
||||||
"hookified": "^1.15.1",
|
"hookified": "^1.15.1",
|
||||||
"keyv": "^5.6.0"
|
"keyv": "^5.6.0"
|
||||||
@@ -469,9 +459,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@cacheable/utils": {
|
"node_modules/@cacheable/utils": {
|
||||||
"version": "2.4.1",
|
"version": "2.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/@cacheable/utils/-/utils-2.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/@cacheable/utils/-/utils-2.5.0.tgz",
|
||||||
"integrity": "sha512-eiFgzCbIneyMlLOmNG4g9xzF7Hv3Mga4LjxjcSC/ues6VYq2+gUbQI8JqNuw/ZM8tJIeIaBGpswAsqV2V7ApgA==",
|
"integrity": "sha512-buipgOVDkkPXNR5+xBpDw7Zk2n1EvU7qBJCNUcL7rhQ//kfpOXPAvQ511Os0vpLYJ1pZnvudNytkQt2hst3wqA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -657,9 +647,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@csstools/css-syntax-patches-for-csstree": {
|
"node_modules/@csstools/css-syntax-patches-for-csstree": {
|
||||||
"version": "1.1.5",
|
"version": "1.1.7",
|
||||||
"resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.7.tgz",
|
||||||
"integrity": "sha512-oNjBvzLq2GPZtJphCjLqXow/cHySHSgtxvKZb7OqSZ/xHgw6NWNhfad+6AB9cLeVm6eA9d/qMll3JdEHjy6M+A==",
|
"integrity": "sha512-fQ+05118eQS1cofO3aJpB5efgpBZMvIzwr/sbC8kDLVA5XLG8q1kJV5yzrUAI1f7lvhPnm8fgIjzFB8/O/5Dig==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -2189,9 +2179,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@maplibre/maplibre-gl-style-spec": {
|
"node_modules/@maplibre/maplibre-gl-style-spec": {
|
||||||
"version": "25.0.2",
|
"version": "26.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-25.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-26.2.1.tgz",
|
||||||
"integrity": "sha512-hTNlIVG1gaLKz6UvOV23PYcT8wVS69LLMK9jbGT2hDWzs6hlTbMejeMyQsAF0rebj9czVp77Vhp4KRaUHHUp9g==",
|
"integrity": "sha512-QFKCXkOeSzOr8jF75jm6kySOg+dUvOehPhRi68gcOYPHb7U5JloUq0dJW0Y5/fZV8ygfT0Vp2RWodvq+fyxFWA==",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mapbox/jsonlint-lines-primitives": "^2.0.3",
|
"@mapbox/jsonlint-lines-primitives": "^2.0.3",
|
||||||
@@ -2631,13 +2621,6 @@
|
|||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@polka/url": {
|
|
||||||
"version": "1.0.0-next.29",
|
|
||||||
"resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz",
|
|
||||||
"integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/@rolldown/pluginutils": {
|
"node_modules/@rolldown/pluginutils": {
|
||||||
"version": "1.0.0-rc.3",
|
"version": "1.0.0-rc.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.3.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.3.tgz",
|
||||||
@@ -3758,17 +3741,17 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||||
"version": "8.62.1",
|
"version": "8.65.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.62.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.65.0.tgz",
|
||||||
"integrity": "sha512-4EQM77WgVNxj7OkL/5b/D/xZsw00G577+UriYTC7JF5opcF3T2AuoeY7ueLaZgSVjSgCS6yOAJB5bRGLPSJUzA==",
|
"integrity": "sha512-IEgob78X12rHpUmtcwFsXhZdVGJtwTVP8FiCLZkR6GlYVrl2PcuB+KhCE5BlVC/eQpQnu8WXRtkHZuPar+gCRA==",
|
||||||
"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.62.1",
|
"@typescript-eslint/scope-manager": "8.65.0",
|
||||||
"@typescript-eslint/type-utils": "8.62.1",
|
"@typescript-eslint/type-utils": "8.65.0",
|
||||||
"@typescript-eslint/utils": "8.62.1",
|
"@typescript-eslint/utils": "8.65.0",
|
||||||
"@typescript-eslint/visitor-keys": "8.62.1",
|
"@typescript-eslint/visitor-keys": "8.65.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"
|
||||||
@@ -3781,15 +3764,15 @@
|
|||||||
"url": "https://opencollective.com/typescript-eslint"
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@typescript-eslint/parser": "^8.62.1",
|
"@typescript-eslint/parser": "^8.65.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.5",
|
"version": "7.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.6.tgz",
|
||||||
"integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==",
|
"integrity": "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -3797,16 +3780,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/parser": {
|
"node_modules/@typescript-eslint/parser": {
|
||||||
"version": "8.62.1",
|
"version": "8.65.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.62.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.65.0.tgz",
|
||||||
"integrity": "sha512-sPhE4iHuJDSvoAiec+Ro8JyXw8f0ql13HFR82P99nCm9GwTEKG0KYLvDe6REk8BCXuit6vJAv/Yxg5ABaNS2rA==",
|
"integrity": "sha512-CZ4nMxWwgu1HEEFNkeaCptra9QCtkmKdgf3sWh1rl1trIhmxLilgTV4cwcbQ4wemnT4sWQN8CaKOmdYx+g2gMA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "8.62.1",
|
"@typescript-eslint/scope-manager": "8.65.0",
|
||||||
"@typescript-eslint/types": "8.62.1",
|
"@typescript-eslint/types": "8.65.0",
|
||||||
"@typescript-eslint/typescript-estree": "8.62.1",
|
"@typescript-eslint/typescript-estree": "8.65.0",
|
||||||
"@typescript-eslint/visitor-keys": "8.62.1",
|
"@typescript-eslint/visitor-keys": "8.65.0",
|
||||||
"debug": "^4.4.3"
|
"debug": "^4.4.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -3822,14 +3805,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/project-service": {
|
"node_modules/@typescript-eslint/project-service": {
|
||||||
"version": "8.62.1",
|
"version": "8.65.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.62.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.65.0.tgz",
|
||||||
"integrity": "sha512-yQ3RgY5RkSBpsNS1Bx/JQEcA24FOSdfGktoyprAr5u18390UQdtVcfnEv4nIrIshNnavlVyZBKxQwT1fIAE6cg==",
|
"integrity": "sha512-SxnPhbTsGahizDgbu7oqFH/xVtzIqMd/s+WtnSxNxJZJpLbdT5IPdzg8EZxO3+PoKahXmwJLeNQOpKJb3/bi7Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/tsconfig-utils": "^8.62.1",
|
"@typescript-eslint/tsconfig-utils": "^8.65.0",
|
||||||
"@typescript-eslint/types": "^8.62.1",
|
"@typescript-eslint/types": "^8.65.0",
|
||||||
"debug": "^4.4.3"
|
"debug": "^4.4.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -3844,14 +3827,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/scope-manager": {
|
"node_modules/@typescript-eslint/scope-manager": {
|
||||||
"version": "8.62.1",
|
"version": "8.65.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.62.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.65.0.tgz",
|
||||||
"integrity": "sha512-r4d249KbQ1SFdpeStvob8Ih6aPPIzfqllPVOtvhve6ZcpuVcYo5/7zUWckKpHE7StASX4kTKZTLf0WQm/wPkcg==",
|
"integrity": "sha512-Esbl8OSYiVxBokYgWPf7VVWg/BE798wXhimnn9ML9Pt5qoDf8bfQlgjlKXR/k98+AcNzlLKYrpCcrcuZ9DZLgg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.62.1",
|
"@typescript-eslint/types": "8.65.0",
|
||||||
"@typescript-eslint/visitor-keys": "8.62.1"
|
"@typescript-eslint/visitor-keys": "8.65.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@@ -3862,9 +3845,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/tsconfig-utils": {
|
"node_modules/@typescript-eslint/tsconfig-utils": {
|
||||||
"version": "8.62.1",
|
"version": "8.65.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.62.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.65.0.tgz",
|
||||||
"integrity": "sha512-xadytJqX9vJVQ2fdQjkcIVigwaOJNWkpjdLt6cEQ+xPnrI1fkp+/jZE/I97k9KUjqtpd25i0HeyZf3T6dutv2g==",
|
"integrity": "sha512-j6GzGqCiRdA7Qhur2VVmKZAkBLfnHFQfx4TaJGL9RMveZqCo48jSHHO0DTgizEnGhtWnqmbtCUSrqSkdiY/0Hg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -3879,15 +3862,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/type-utils": {
|
"node_modules/@typescript-eslint/type-utils": {
|
||||||
"version": "8.62.1",
|
"version": "8.65.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.62.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.65.0.tgz",
|
||||||
"integrity": "sha512-aXM5xlqXiTxPibXB93cLAURfT3rlizf7uMXISCXy66Isr/9hISJx3yDsKl0L7lKa51b8JpFuNKby0/O0pEm9jg==",
|
"integrity": "sha512-YjaZ7PRI5qY7ax2L3PbvX0rRyGtipAReCWs0mhhDBHjH/vl0g0BonaGXrKdKpMbIIsMIwDgbk/xzkBTyAltS5g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.62.1",
|
"@typescript-eslint/types": "8.65.0",
|
||||||
"@typescript-eslint/typescript-estree": "8.62.1",
|
"@typescript-eslint/typescript-estree": "8.65.0",
|
||||||
"@typescript-eslint/utils": "8.62.1",
|
"@typescript-eslint/utils": "8.65.0",
|
||||||
"debug": "^4.4.3",
|
"debug": "^4.4.3",
|
||||||
"ts-api-utils": "^2.5.0"
|
"ts-api-utils": "^2.5.0"
|
||||||
},
|
},
|
||||||
@@ -3904,9 +3887,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/types": {
|
"node_modules/@typescript-eslint/types": {
|
||||||
"version": "8.62.1",
|
"version": "8.65.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.62.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.65.0.tgz",
|
||||||
"integrity": "sha512-ooCzJFaf+Hg+uG6fA3NRFGuFjlfNlDhBthbv4ZPU/0elCAFUfnyXUvf/WOpHz/jYwSmvU2GkR2LtyUfy1AxZ1Q==",
|
"integrity": "sha512-JSSwWNy+H0E/01jJEM+hrX6N0OFDzFzeIhHFSAS01tlVaevpG8cFyYRPhS5yjGOvBUx3sqQHVMjCL1CAZZMxBg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -3918,16 +3901,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree": {
|
"node_modules/@typescript-eslint/typescript-estree": {
|
||||||
"version": "8.62.1",
|
"version": "8.65.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.62.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.65.0.tgz",
|
||||||
"integrity": "sha512-xMcW9oP9u7fAMXYs9A65CVmtLQe2r//oXINHfi8HV+oiqhih17sbLdhXr4540YWlgpDKQdY854OL5ZrdCiQsAA==",
|
"integrity": "sha512-JboAE2swaYt4tb1fHhHTABE2K+OLy09XfcTbhnk4Pw96f9dd2e9iYsJ28gBggHlo5z5x1rkyWvcPoTuNTd4oGg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/project-service": "8.62.1",
|
"@typescript-eslint/project-service": "8.65.0",
|
||||||
"@typescript-eslint/tsconfig-utils": "8.62.1",
|
"@typescript-eslint/tsconfig-utils": "8.65.0",
|
||||||
"@typescript-eslint/types": "8.62.1",
|
"@typescript-eslint/types": "8.65.0",
|
||||||
"@typescript-eslint/visitor-keys": "8.62.1",
|
"@typescript-eslint/visitor-keys": "8.65.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",
|
||||||
@@ -3956,16 +3939,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
|
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
|
||||||
"version": "5.0.7",
|
"version": "5.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.8.tgz",
|
||||||
"integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==",
|
"integrity": "sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"balanced-match": "^4.0.2"
|
"balanced-match": "^4.0.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "18 || 20 || >=22"
|
"node": "20 || >=22"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
|
"node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
|
||||||
@@ -3985,16 +3968,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/utils": {
|
"node_modules/@typescript-eslint/utils": {
|
||||||
"version": "8.62.1",
|
"version": "8.65.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.62.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.65.0.tgz",
|
||||||
"integrity": "sha512-sHtbPfuKNZCG+ih8SyjjucqRntSVmp8XgL5u6o9mAhiSn8ds5o/M/XdM0abweme2Tln3szOstOrZ9OXitvPh0g==",
|
"integrity": "sha512-gXiwIHsYreboxeJucHKPvgwl7dXt50mF8s1/c00cP/WoVTyWKFdtfhRWwZiXYFU5H2O8vVoSLNrexFZjYS/SGA==",
|
||||||
"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.62.1",
|
"@typescript-eslint/scope-manager": "8.65.0",
|
||||||
"@typescript-eslint/types": "8.62.1",
|
"@typescript-eslint/types": "8.65.0",
|
||||||
"@typescript-eslint/typescript-estree": "8.62.1"
|
"@typescript-eslint/typescript-estree": "8.65.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@@ -4009,13 +3992,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/visitor-keys": {
|
"node_modules/@typescript-eslint/visitor-keys": {
|
||||||
"version": "8.62.1",
|
"version": "8.65.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.62.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.65.0.tgz",
|
||||||
"integrity": "sha512-4g3BLxfdTMy8iZG0MaBkadnlRrCJ74cQiFbyEVMrkwIoqdyaXXQM22cotDvrl4x28wgIZ9rEJRoM+mmhSJpJ1g==",
|
"integrity": "sha512-8C71BQkGjiMmXtop7pHVJu1l2NNShFdkCyD6a2ezzs5vU/L3LRtb69EtcteFwz0mYMPzIgOw0n6OV4VBUWZd7A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.62.1",
|
"@typescript-eslint/types": "8.65.0",
|
||||||
"eslint-visitor-keys": "^5.0.0"
|
"eslint-visitor-keys": "^5.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -4066,53 +4049,6 @@
|
|||||||
"vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
|
"vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vitest/browser": {
|
|
||||||
"version": "4.1.10",
|
|
||||||
"resolved": "https://registry.npmjs.org/@vitest/browser/-/browser-4.1.10.tgz",
|
|
||||||
"integrity": "sha512-UDwuWGwXj646CBx/bQHOaJSX7np0I8JL/UKQYa1e4QrVHH8VdWtx8eaOuf8sy0ShwDgR6NjJAsp5eF6vjF6qng==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@blazediff/core": "1.9.1",
|
|
||||||
"@vitest/mocker": "4.1.10",
|
|
||||||
"@vitest/utils": "4.1.10",
|
|
||||||
"magic-string": "^0.30.21",
|
|
||||||
"pngjs": "^7.0.0",
|
|
||||||
"sirv": "^3.0.2",
|
|
||||||
"tinyrainbow": "^3.1.0",
|
|
||||||
"ws": "^8.19.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/vitest"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"vitest": "4.1.10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@vitest/browser-playwright": {
|
|
||||||
"version": "4.1.10",
|
|
||||||
"resolved": "https://registry.npmjs.org/@vitest/browser-playwright/-/browser-playwright-4.1.10.tgz",
|
|
||||||
"integrity": "sha512-nMoXGEiRpT7m3W7NsbvrM2aKNwiNHZf+zEpUCvMteGjZFvfT96Q9fh7QyB98dvDWXiKvrLxA7bJ1mCOOv+JQPw==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@vitest/browser": "4.1.10",
|
|
||||||
"@vitest/mocker": "4.1.10",
|
|
||||||
"tinyrainbow": "^3.1.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/vitest"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"playwright": "*",
|
|
||||||
"vitest": "4.1.10"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"playwright": {
|
|
||||||
"optional": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@vitest/coverage-v8": {
|
"node_modules/@vitest/coverage-v8": {
|
||||||
"version": "4.1.10",
|
"version": "4.1.10",
|
||||||
"resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.10.tgz",
|
"resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.10.tgz",
|
||||||
@@ -4757,14 +4693,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/cacheable": {
|
"node_modules/cacheable": {
|
||||||
"version": "2.3.5",
|
"version": "2.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/cacheable/-/cacheable-2.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/cacheable/-/cacheable-2.5.0.tgz",
|
||||||
"integrity": "sha512-EQfaKe09tl615iNvq/TBRWTFf1AKJNXYQSsMx0Z3EI0nA+pVsVPS8wJhnRlkbdacKPh1d0qVIhwTc2zsQNFEEg==",
|
"integrity": "sha512-60cyAOytib/OzBw1JNSoSV/boK1AtHryDIjvVBk7XbN4ugfkM3+Sry7fEjNgPMGgOjuaZPAp8ruZ0Cxafwyq9g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cacheable/memory": "^2.0.8",
|
"@cacheable/memory": "^2.2.0",
|
||||||
"@cacheable/utils": "^2.4.1",
|
"@cacheable/utils": "^2.5.0",
|
||||||
"hookified": "^1.15.0",
|
"hookified": "^1.15.0",
|
||||||
"keyv": "^5.6.0",
|
"keyv": "^5.6.0",
|
||||||
"qified": "^0.10.1"
|
"qified": "^0.10.1"
|
||||||
@@ -5921,9 +5857,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint": {
|
"node_modules/eslint": {
|
||||||
"version": "10.6.0",
|
"version": "10.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-10.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint/-/eslint-10.7.0.tgz",
|
||||||
"integrity": "sha512-6lVbcqSodALYo+4ELD0heG6lFiFxnLMuLkiMi2qV8LMp54N8tE8FT1GMH+ev4Ti00nFjNze2+Su6DsV5OQW3Dg==",
|
"integrity": "sha512-GVTD7s1vdIl6UYvAfriOPeY1Df8LIZjfofLvHwde+erDHGGuHyuM6xoxRxmHiebhYuD2p1vN4wWh0XzPARSGDQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
@@ -6346,9 +6282,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/fast-uri": {
|
"node_modules/fast-uri": {
|
||||||
"version": "3.1.2",
|
"version": "3.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.4.tgz",
|
||||||
"integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==",
|
"integrity": "sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -6931,9 +6867,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/globby": {
|
"node_modules/globby": {
|
||||||
"version": "16.2.0",
|
"version": "16.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/globby/-/globby-16.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/globby/-/globby-16.2.2.tgz",
|
||||||
"integrity": "sha512-QrJia2qDf5BB/V6HYlDTs0I0lBahyjLzpGQg3KT7FnCdTonAyPy2RtY802m2k4ALx6Dp752f82WsOczEVr3l6Q==",
|
"integrity": "sha512-NLvV9ubZ6NDsJaOpKPy3cQeJpKi9DcWiyCiFUpJPA0YihRqiE6RWaLUmgNNPr8MgPpLZjnBjSmou7uZBRJv9wA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -6952,41 +6888,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/globby/node_modules/ignore": {
|
"node_modules/globby/node_modules/ignore": {
|
||||||
"version": "7.0.5",
|
"version": "7.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.6.tgz",
|
||||||
"integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==",
|
"integrity": "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 4"
|
"node": ">= 4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/globby/node_modules/is-path-inside": {
|
|
||||||
"version": "4.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz",
|
|
||||||
"integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/globby/node_modules/slash": {
|
|
||||||
"version": "5.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz",
|
|
||||||
"integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14.16"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/globjoin": {
|
"node_modules/globjoin": {
|
||||||
"version": "0.1.4",
|
"version": "0.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz",
|
||||||
@@ -7294,9 +7204,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/i18next": {
|
"node_modules/i18next": {
|
||||||
"version": "26.3.4",
|
"version": "26.3.6",
|
||||||
"resolved": "https://registry.npmjs.org/i18next/-/i18next-26.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/i18next/-/i18next-26.3.6.tgz",
|
||||||
"integrity": "sha512-pa7m0d7pBDqGHZxljT+WPFeyFgQ7P7SciPPo1tTqYuO0z4sqADYhwnBESmmGp/wEof1inwdls/k8ZgTg8rxFHA==",
|
"integrity": "sha512-Bu5Z2nAXgfVyM8xvW3jk9EKRIuX37PudsrBViThNFx7CR7aaYTpP01cxNB/E4c4UUzTDiAZRstEhsRfPOL/8xA==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "individual",
|
"type": "individual",
|
||||||
@@ -7313,7 +7223,7 @@
|
|||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"typescript": "^5 || ^6"
|
"typescript": "^5 || ^6 || ^7"
|
||||||
},
|
},
|
||||||
"peerDependenciesMeta": {
|
"peerDependenciesMeta": {
|
||||||
"typescript": {
|
"typescript": {
|
||||||
@@ -7331,9 +7241,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/i18next-cli": {
|
"node_modules/i18next-cli": {
|
||||||
"version": "1.65.0",
|
"version": "1.67.1",
|
||||||
"resolved": "https://registry.npmjs.org/i18next-cli/-/i18next-cli-1.65.0.tgz",
|
"resolved": "https://registry.npmjs.org/i18next-cli/-/i18next-cli-1.67.1.tgz",
|
||||||
"integrity": "sha512-sak+2Ry4P7wtl7xMAZg2sWG2vup1lRHFBKA7h5IeEqFUog51QEgeYUhHxd2x85+MvS4BhVOZZs833clnd1WgYA==",
|
"integrity": "sha512-X5Ev7R9XNUs932vroHAIJhDITE4mhvAcwoSu6fKTeRT2FREjbnfftSQkkMA0M+zLBdQHg+J4cjN0Mi25SmbQ6w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -7667,9 +7577,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/immutable": {
|
"node_modules/immutable": {
|
||||||
"version": "5.1.5",
|
"version": "5.1.9",
|
||||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.9.tgz",
|
||||||
"integrity": "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==",
|
"integrity": "sha512-m8nVez3rwrgmWxtLMt1ZYXB2Lv7OKYn/disyxAlSDYAlKSlFoPPfIAmAM/M5xqL4m4C/wAPw7S2/CNaUii1Hxg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
@@ -8108,6 +8018,19 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/is-path-inside": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-plain-obj": {
|
"node_modules/is-plain-obj": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz",
|
||||||
@@ -9767,16 +9690,6 @@
|
|||||||
"mkdirp": "bin/cmd.js"
|
"mkdirp": "bin/cmd.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mrmime": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz",
|
|
||||||
"integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/ms": {
|
"node_modules/ms": {
|
||||||
"version": "2.1.3",
|
"version": "2.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||||
@@ -9800,9 +9713,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/nanoid": {
|
"node_modules/nanoid": {
|
||||||
"version": "3.3.12",
|
"version": "3.3.16",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz",
|
||||||
"integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==",
|
"integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -10818,16 +10731,6 @@
|
|||||||
"fflate": "^0.8.2"
|
"fflate": "^0.8.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pngjs": {
|
|
||||||
"version": "7.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz",
|
|
||||||
"integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14.19.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/possible-typed-array-names": {
|
"node_modules/possible-typed-array-names": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
|
||||||
@@ -10839,9 +10742,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.5.16",
|
"version": "8.5.22",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.16.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.22.tgz",
|
||||||
"integrity": "sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg==",
|
"integrity": "sha512-KBDEIpLrvpv16pp3K0Fw+UCoZfopFjjgeB+0tA/aaThfEE74kKDLrgg603YvOWJyg3+WYtyq3xYsQWsIyZlPqQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -10859,7 +10762,7 @@
|
|||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.3.12",
|
"nanoid": "^3.3.16",
|
||||||
"picocolors": "^1.1.1",
|
"picocolors": "^1.1.1",
|
||||||
"source-map-js": "^1.2.1"
|
"source-map-js": "^1.2.1"
|
||||||
},
|
},
|
||||||
@@ -11822,9 +11725,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/sass": {
|
"node_modules/sass": {
|
||||||
"version": "1.101.0",
|
"version": "1.101.7",
|
||||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.101.0.tgz",
|
"resolved": "https://registry.npmjs.org/sass/-/sass-1.101.7.tgz",
|
||||||
"integrity": "sha512-OL3GoQyoUdDt843DpVmDO6y2k1sc5IhUDSpu8XucEI+35neq5QivZ1iuegnpraEVTJXlQGK1gl27zKcTLEPbQw==",
|
"integrity": "sha512-cDeUYU0dhwKVbpYg/ppsjyuoddxYhWlJOkRoI7+/iZsaSp7iowWDfm+tL2HcUafedWBDvbf/+hx0QRgKG4JSHA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -12033,19 +11936,17 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/sirv": {
|
"node_modules/slash": {
|
||||||
"version": "3.0.2",
|
"version": "5.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz",
|
||||||
"integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==",
|
"integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
|
||||||
"@polka/url": "^1.0.0-next.24",
|
|
||||||
"mrmime": "^2.0.0",
|
|
||||||
"totalist": "^3.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=14.16"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/slugify": {
|
"node_modules/slugify": {
|
||||||
@@ -12371,9 +12272,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/stylelint": {
|
"node_modules/stylelint": {
|
||||||
"version": "17.14.0",
|
"version": "17.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/stylelint/-/stylelint-17.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/stylelint/-/stylelint-17.14.1.tgz",
|
||||||
"integrity": "sha512-8xkHPpdqYryeIsOgfsYTmr6cIeC4nLYWk5S8BPxpodq8mIuepggkMljsHewWfuAjj/+qpRKou2QerhjMH3iasg==",
|
"integrity": "sha512-xVQwyiuxALUBNB2fBe0tmNemg9KqLtdj3T64mioFDar79B2cU8LIyz+3KL6LdiHs9NkeNfwxpKSaIVOY8f112g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -12389,7 +12290,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@csstools/css-calc": "^3.2.1",
|
"@csstools/css-calc": "^3.2.1",
|
||||||
"@csstools/css-parser-algorithms": "^4.0.0",
|
"@csstools/css-parser-algorithms": "^4.0.0",
|
||||||
"@csstools/css-syntax-patches-for-csstree": "^1.1.5",
|
"@csstools/css-syntax-patches-for-csstree": "^1.1.6",
|
||||||
"@csstools/css-tokenizer": "^4.0.0",
|
"@csstools/css-tokenizer": "^4.0.0",
|
||||||
"@csstools/media-query-list-parser": "^5.0.0",
|
"@csstools/media-query-list-parser": "^5.0.0",
|
||||||
"@csstools/selector-resolve-nested": "^4.0.0",
|
"@csstools/selector-resolve-nested": "^4.0.0",
|
||||||
@@ -12401,9 +12302,9 @@
|
|||||||
"debug": "^4.4.3",
|
"debug": "^4.4.3",
|
||||||
"fast-glob": "^3.3.3",
|
"fast-glob": "^3.3.3",
|
||||||
"fastest-levenshtein": "^1.0.16",
|
"fastest-levenshtein": "^1.0.16",
|
||||||
"file-entry-cache": "^11.1.3",
|
"file-entry-cache": "^11.1.5",
|
||||||
"global-modules": "^2.0.0",
|
"global-modules": "^2.0.0",
|
||||||
"globby": "^16.2.0",
|
"globby": "^16.2.1",
|
||||||
"globjoin": "^0.1.4",
|
"globjoin": "^0.1.4",
|
||||||
"html-tags": "^5.1.0",
|
"html-tags": "^5.1.0",
|
||||||
"ignore": "^7.0.5",
|
"ignore": "^7.0.5",
|
||||||
@@ -12413,12 +12314,12 @@
|
|||||||
"micromatch": "^4.0.8",
|
"micromatch": "^4.0.8",
|
||||||
"normalize-path": "^3.0.0",
|
"normalize-path": "^3.0.0",
|
||||||
"picocolors": "^1.1.1",
|
"picocolors": "^1.1.1",
|
||||||
"postcss": "^8.5.15",
|
"postcss": "^8.5.16",
|
||||||
"postcss-safe-parser": "^7.0.1",
|
"postcss-safe-parser": "^7.0.1",
|
||||||
"postcss-selector-parser": "^7.1.4",
|
"postcss-selector-parser": "^7.1.4",
|
||||||
"postcss-value-parser": "^4.2.0",
|
"postcss-value-parser": "^4.2.0",
|
||||||
"string-width": "^8.2.1",
|
"string-width": "^8.2.1",
|
||||||
"supports-hyperlinks": "^4.4.0",
|
"supports-hyperlinks": "^4.5.0",
|
||||||
"svg-tags": "^1.0.0",
|
"svg-tags": "^1.0.0",
|
||||||
"table": "^6.9.0",
|
"table": "^6.9.0",
|
||||||
"write-file-atomic": "^7.0.1"
|
"write-file-atomic": "^7.0.1"
|
||||||
@@ -12517,23 +12418,23 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/stylelint/node_modules/file-entry-cache": {
|
"node_modules/stylelint/node_modules/file-entry-cache": {
|
||||||
"version": "11.1.3",
|
"version": "11.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-11.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-11.1.5.tgz",
|
||||||
"integrity": "sha512-oMbq0PD6VIiIwMF6LIa7MEwd/l9huKwmqRKXqmrkqIZv8CvRbfowL+L0ryAl8h//HfAS0zS+4SbYoRyAoA6BJA==",
|
"integrity": "sha512-+PFTHITI08JIGhnNpGNI8T8inUpgZfk3GNEqfT9R2zZV2iFXg3CvqzSl/uEhs7TSGujYRELEANyDvS8Fj7+S7Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"flat-cache": "^6.1.22"
|
"flat-cache": "^6.1.23"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/stylelint/node_modules/flat-cache": {
|
"node_modules/stylelint/node_modules/flat-cache": {
|
||||||
"version": "6.1.22",
|
"version": "6.1.23",
|
||||||
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-6.1.22.tgz",
|
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-6.1.23.tgz",
|
||||||
"integrity": "sha512-N2dnzVJIphnNsjHcrxGW7DePckJ6haPrSFqpsBUhHYgwtKGVq4JrBGielEGD2fCVnsGm1zlBVZ8wGhkyuetgug==",
|
"integrity": "sha512-f++BY9pTk+983xK1FLzlLpmM0i0z+jHmx3QESGkURMXujQZz1k5wzwX6hjnQ8goaD0B+sYnDK1yZ6MTyZfUaqA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cacheable": "^2.3.4",
|
"cacheable": "^2.5.0",
|
||||||
"flatted": "^3.4.2",
|
"flatted": "^3.4.2",
|
||||||
"hookified": "^1.15.0"
|
"hookified": "^1.15.0"
|
||||||
}
|
}
|
||||||
@@ -12646,9 +12547,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/supports-hyperlinks": {
|
"node_modules/supports-hyperlinks": {
|
||||||
"version": "4.4.0",
|
"version": "4.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-4.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-4.5.0.tgz",
|
||||||
"integrity": "sha512-UKbpT93hN5Nr9go5UY7bopIB9YQlMz9nm/ct4IXt/irb5YRkn9WaqrOBJGZ5Pwvsd5FQzSVeYlGdXoCAPQZrPg==",
|
"integrity": "sha512-ZW2OvfeCXrNTbLakPUzjQG922EeGCOteFSVoek5DKStTh898wf7zgtuFlzQN8HfZCxC3Eh02yJVrRW51hADf+w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -12919,16 +12820,6 @@
|
|||||||
"node": ">=8.0"
|
"node": ">=8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/totalist": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
|
|
||||||
"integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/trim-lines": {
|
"node_modules/trim-lines": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz",
|
||||||
@@ -13094,16 +12985,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/typescript-eslint": {
|
"node_modules/typescript-eslint": {
|
||||||
"version": "8.62.1",
|
"version": "8.65.0",
|
||||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.62.1.tgz",
|
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.65.0.tgz",
|
||||||
"integrity": "sha512-vymnnM5g0AKQDSAyfP12nMIBvgwgA42syg74kkuZ4x1VuTzwQKwc5h9rGxeShCjny5o+zWAb6OEoz7XLgrIkIw==",
|
"integrity": "sha512-/ggrHAwyjENDusvyxbuqxAC2dTnZg/Z8F+fgQtYIz+L6n/9HfSlEZcFGV/NsMNa6CkGk0xUjUAFwC0vHOflvIA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/eslint-plugin": "8.62.1",
|
"@typescript-eslint/eslint-plugin": "8.65.0",
|
||||||
"@typescript-eslint/parser": "8.62.1",
|
"@typescript-eslint/parser": "8.65.0",
|
||||||
"@typescript-eslint/typescript-estree": "8.62.1",
|
"@typescript-eslint/typescript-estree": "8.65.0",
|
||||||
"@typescript-eslint/utils": "8.62.1"
|
"@typescript-eslint/utils": "8.65.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@@ -13679,31 +13570,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vitest-browser-react": {
|
|
||||||
"version": "2.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/vitest-browser-react/-/vitest-browser-react-2.2.0.tgz",
|
|
||||||
"integrity": "sha512-oY3KM6305kwJMa6nHo92vVtkOsih7mjEf12dLKuphaF+9ywWPEc+qanIBd394SZ6m5LadVEaG6dicvvizOzmjA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/vitest"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"@types/react": "^18.0.0 || ^19.0.0",
|
|
||||||
"@types/react-dom": "^18.0.0 || ^19.0.0",
|
|
||||||
"react": "^18.0.0 || ^19.0.0",
|
|
||||||
"react-dom": "^18.0.0 || ^19.0.0",
|
|
||||||
"vitest": "^4.0.0"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"@types/react": {
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"@types/react-dom": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/void-elements": {
|
"node_modules/void-elements": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
|
||||||
@@ -13891,28 +13757,6 @@
|
|||||||
"typedarray-to-buffer": "^3.1.5"
|
"typedarray-to-buffer": "^3.1.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ws": {
|
|
||||||
"version": "8.21.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz",
|
|
||||||
"integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10.0.0"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"bufferutil": "^4.0.1",
|
|
||||||
"utf-8-validate": ">=5.0.2"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"bufferutil": {
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"utf-8-validate": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/xml-utils": {
|
"node_modules/xml-utils": {
|
||||||
"version": "1.10.2",
|
"version": "1.10.2",
|
||||||
"resolved": "https://registry.npmjs.org/xml-utils/-/xml-utils-1.10.2.tgz",
|
"resolved": "https://registry.npmjs.org/xml-utils/-/xml-utils-1.10.2.tgz",
|
||||||
|
|||||||
+9
-12
@@ -37,7 +37,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.8.2",
|
"@maplibre/maplibre-gl-inspect": "^1.8.2",
|
||||||
"@maplibre/maplibre-gl-style-spec": "^25.0.2",
|
"@maplibre/maplibre-gl-style-spec": "^26.2.1",
|
||||||
"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",
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
"downshift": "^9.4.0",
|
"downshift": "^9.4.0",
|
||||||
"events": "^3.3.0",
|
"events": "^3.3.0",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
"i18next": "^26.3.4",
|
"i18next": "^26.3.6",
|
||||||
"i18next-browser-languagedetector": "^8.2.1",
|
"i18next-browser-languagedetector": "^8.2.1",
|
||||||
"i18next-resources-to-backend": "^1.2.1",
|
"i18next-resources-to-backend": "^1.2.1",
|
||||||
"json-stringify-pretty-compact": "^4.0.0",
|
"json-stringify-pretty-compact": "^4.0.0",
|
||||||
@@ -124,30 +124,27 @@
|
|||||||
"@types/string-hash": "^1.1.3",
|
"@types/string-hash": "^1.1.3",
|
||||||
"@types/wicg-file-system-access": "^2023.10.7",
|
"@types/wicg-file-system-access": "^2023.10.7",
|
||||||
"@vitejs/plugin-react": "5.2",
|
"@vitejs/plugin-react": "5.2",
|
||||||
"@vitest/browser": "^4.1.10",
|
|
||||||
"@vitest/browser-playwright": "^4.1.10",
|
|
||||||
"@vitest/coverage-v8": "^4.1.10",
|
"@vitest/coverage-v8": "^4.1.10",
|
||||||
"cors": "^2.8.6",
|
"cors": "^2.8.6",
|
||||||
"eslint": "^10.6.0",
|
"eslint": "^10.7.0",
|
||||||
"eslint-plugin-react": "^7.37.5",
|
"eslint-plugin-react": "^7.37.5",
|
||||||
"eslint-plugin-react-hooks": "^7.1.1",
|
"eslint-plugin-react-hooks": "^7.1.1",
|
||||||
"eslint-plugin-react-refresh": "^0.5.3",
|
"eslint-plugin-react-refresh": "^0.5.3",
|
||||||
"i18next-cli": "^1.65.0",
|
"i18next-cli": "^1.67.1",
|
||||||
"istanbul": "^0.4.5",
|
"istanbul": "^0.4.5",
|
||||||
"istanbul-lib-coverage": "^3.2.2",
|
"istanbul-lib-coverage": "^3.2.2",
|
||||||
"nyc": "^18.0.0",
|
"nyc": "^18.0.0",
|
||||||
"postcss": "^8.5.16",
|
"postcss": "^8.5.22",
|
||||||
"react-hot-loader": "^4.13.1",
|
"react-hot-loader": "^4.13.1",
|
||||||
"sass": "^1.101.0",
|
"sass": "^1.101.7",
|
||||||
"stylelint": "^17.14.0",
|
"stylelint": "^17.14.1",
|
||||||
"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.62.1",
|
"typescript-eslint": "^8.65.0",
|
||||||
"uuid": "^14.0.1",
|
"uuid": "^14.0.1",
|
||||||
"vite": "^7.3.2",
|
"vite": "^7.3.2",
|
||||||
"vite-plugin-istanbul": "^9.0.1",
|
"vite-plugin-istanbul": "^9.0.1",
|
||||||
"vitest": "^4.1.10",
|
"vitest": "^4.1.10"
|
||||||
"vitest-browser-react": "^2.2.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-23
@@ -11,29 +11,29 @@ import {type Map, type LayerSpecification, type StyleSpecification, type Validat
|
|||||||
import {validateStyleMin} from "@maplibre/maplibre-gl-style-spec";
|
import {validateStyleMin} from "@maplibre/maplibre-gl-style-spec";
|
||||||
import latest from "@maplibre/maplibre-gl-style-spec/dist/latest.json";
|
import latest from "@maplibre/maplibre-gl-style-spec/dist/latest.json";
|
||||||
|
|
||||||
import MapMaplibreGl from "./MapMaplibreGl";
|
import { MapMaplibreGl } from "./MapMaplibreGl";
|
||||||
import MapOpenLayers from "./MapOpenLayers";
|
import { MapOpenLayers } from "./MapOpenLayers";
|
||||||
import CodeEditor from "./CodeEditor";
|
import { CodeEditor } from "./CodeEditor";
|
||||||
import LayerList from "./LayerList";
|
import { LayerList } from "./LayerList";
|
||||||
import LayerEditor from "./LayerEditor";
|
import { LayerEditor } from "./LayerEditor";
|
||||||
import AppToolbar, { type MapState } from "./AppToolbar";
|
import { AppToolbar, type MapState } from "./AppToolbar";
|
||||||
import AppLayout from "./AppLayout";
|
import { AppLayout } from "./AppLayout";
|
||||||
import MessagePanel from "./AppMessagePanel";
|
import { AppMessagePanel as MessagePanel } from "./AppMessagePanel";
|
||||||
|
|
||||||
import ModalSettings from "./modals/ModalSettings";
|
import { ModalSettings } from "./modals/ModalSettings";
|
||||||
import ModalExport from "./modals/ModalExport";
|
import { ModalExport } from "./modals/ModalExport";
|
||||||
import ModalSources from "./modals/ModalSources";
|
import { ModalSources } from "./modals/ModalSources";
|
||||||
import ModalOpen from "./modals/ModalOpen";
|
import { ModalOpen } from "./modals/ModalOpen";
|
||||||
import ModalShortcuts from "./modals/ModalShortcuts";
|
import { ModalShortcuts } from "./modals/ModalShortcuts";
|
||||||
import ModalDebug from "./modals/ModalDebug";
|
import { ModalDebug } from "./modals/ModalDebug";
|
||||||
import ModalGlobalState from "./modals/ModalGlobalState";
|
import { ModalGlobalState } from "./modals/ModalGlobalState";
|
||||||
|
|
||||||
import {downloadGlyphsMetadata, downloadSpriteMetadata} from "../libs/metadata";
|
import {downloadGlyphsMetadata, downloadSpriteMetadata} from "../libs/metadata";
|
||||||
import style from "../libs/style";
|
import { emptyStyle, getAccessToken, replaceAccessTokens } from "../libs/style";
|
||||||
import { undoMessages, redoMessages } from "../libs/diffmessage";
|
import { undoMessages, redoMessages } from "../libs/diffmessage";
|
||||||
import { createStyleStore, type IStyleStore } from "../libs/store/style-store-factory";
|
import { createStyleStore, type IStyleStore } from "../libs/store/style-store-factory";
|
||||||
import { RevisionStore } from "../libs/revisions";
|
import { RevisionStore } from "../libs/revisions";
|
||||||
import LayerWatcher from "../libs/layerwatcher";
|
import { LayerWatcher } from "../libs/layerwatcher";
|
||||||
import tokens from "../config/tokens.json";
|
import tokens from "../config/tokens.json";
|
||||||
import isEqual from "lodash.isequal";
|
import isEqual from "lodash.isequal";
|
||||||
import { type MapOptions } from "maplibre-gl";
|
import { type MapOptions } from "maplibre-gl";
|
||||||
@@ -48,19 +48,19 @@ function setFetchAccessToken(url: string, mapStyle: StyleSpecification) {
|
|||||||
const matchesThunderforest = url.match(/\.thunderforest\.com/);
|
const matchesThunderforest = url.match(/\.thunderforest\.com/);
|
||||||
const matchesLocationIQ = url.match(/\.locationiq\.com/);
|
const matchesLocationIQ = url.match(/\.locationiq\.com/);
|
||||||
if (matchesTilehosting || matchesMaptiler) {
|
if (matchesTilehosting || matchesMaptiler) {
|
||||||
const accessToken = style.getAccessToken("openmaptiles", mapStyle, {allowFallback: true});
|
const accessToken = getAccessToken("openmaptiles", mapStyle, {allowFallback: true});
|
||||||
if (accessToken) {
|
if (accessToken) {
|
||||||
return url.replace("{key}", accessToken);
|
return url.replace("{key}", accessToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (matchesThunderforest) {
|
else if (matchesThunderforest) {
|
||||||
const accessToken = style.getAccessToken("thunderforest", mapStyle, {allowFallback: true});
|
const accessToken = getAccessToken("thunderforest", mapStyle, {allowFallback: true});
|
||||||
if (accessToken) {
|
if (accessToken) {
|
||||||
return url.replace("{key}", accessToken);
|
return url.replace("{key}", accessToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (matchesLocationIQ) {
|
else if (matchesLocationIQ) {
|
||||||
const accessToken = style.getAccessToken("locationiq", mapStyle, {allowFallback: true});
|
const accessToken = getAccessToken("locationiq", mapStyle, {allowFallback: true});
|
||||||
if (accessToken) {
|
if (accessToken) {
|
||||||
return url.replace("{key}", accessToken);
|
return url.replace("{key}", accessToken);
|
||||||
}
|
}
|
||||||
@@ -123,7 +123,7 @@ type AppState = {
|
|||||||
fileHandle: FileSystemFileHandle | null
|
fileHandle: FileSystemFileHandle | null
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class App extends React.Component<any, AppState> {
|
export class App extends React.Component<any, AppState> {
|
||||||
revisionStore: RevisionStore;
|
revisionStore: RevisionStore;
|
||||||
styleStore: IStyleStore | null = null;
|
styleStore: IStyleStore | null = null;
|
||||||
layerWatcher: LayerWatcher;
|
layerWatcher: LayerWatcher;
|
||||||
@@ -137,7 +137,7 @@ export default class App extends React.Component<any, AppState> {
|
|||||||
this.state = {
|
this.state = {
|
||||||
errors: [],
|
errors: [],
|
||||||
infos: [],
|
infos: [],
|
||||||
mapStyle: style.emptyStyle,
|
mapStyle: emptyStyle,
|
||||||
selectedLayerIndex: 0,
|
selectedLayerIndex: 0,
|
||||||
sources: {},
|
sources: {},
|
||||||
vectorLayers: {},
|
vectorLayers: {},
|
||||||
@@ -698,7 +698,7 @@ export default class App extends React.Component<any, AppState> {
|
|||||||
mapStyle: (dirtyMapStyle || mapStyle),
|
mapStyle: (dirtyMapStyle || mapStyle),
|
||||||
mapView: this.state.mapView,
|
mapView: this.state.mapView,
|
||||||
replaceAccessTokens: (mapStyle: StyleSpecification) => {
|
replaceAccessTokens: (mapStyle: StyleSpecification) => {
|
||||||
return style.replaceAccessTokens(mapStyle, {
|
return replaceAccessTokens(mapStyle, {
|
||||||
allowFallback: true
|
allowFallback: true
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import ScrollContainer from "./ScrollContainer";
|
import { ScrollContainer } from "./ScrollContainer";
|
||||||
import { type WithTranslation, withTranslation } from "react-i18next";
|
import { type WithTranslation, withTranslation } from "react-i18next";
|
||||||
import { IconContext } from "react-icons";
|
import { IconContext } from "react-icons";
|
||||||
|
|
||||||
@@ -50,5 +50,4 @@ class AppLayoutInternal extends React.Component<AppLayoutInternalProps> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const AppLayout = withTranslation()(AppLayoutInternal);
|
export const AppLayout = withTranslation()(AppLayoutInternal);
|
||||||
export default AppLayout;
|
|
||||||
|
|||||||
@@ -61,5 +61,4 @@ class AppMessagePanelInternal extends React.Component<AppMessagePanelInternalPro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const AppMessagePanel = withTranslation()(AppMessagePanelInternal);
|
export const AppMessagePanel = withTranslation()(AppMessagePanelInternal);
|
||||||
export default AppMessagePanel;
|
|
||||||
|
|||||||
@@ -306,5 +306,4 @@ class AppToolbarInternal extends React.Component<AppToolbarInternalProps> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const AppToolbar = withTranslation()(AppToolbarInternal);
|
export const AppToolbar = withTranslation()(AppToolbarInternal);
|
||||||
export default AppToolbar;
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, {type CSSProperties, type PropsWithChildren, type SyntheticEvent} from "react";
|
import React, {type CSSProperties, type PropsWithChildren, type SyntheticEvent} from "react";
|
||||||
import classnames from "classnames";
|
import classnames from "classnames";
|
||||||
import FieldDocLabel from "./FieldDocLabel";
|
import { FieldDocLabel } from "./FieldDocLabel";
|
||||||
import Doc from "./Doc";
|
import { Doc } from "./Doc";
|
||||||
|
|
||||||
export type BlockProps = PropsWithChildren & {
|
export type BlockProps = PropsWithChildren & {
|
||||||
"data-wd-key"?: string
|
"data-wd-key"?: string
|
||||||
@@ -19,7 +19,7 @@ type BlockState = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/** Wrap a component with a label */
|
/** Wrap a component with a label */
|
||||||
export default class Block extends React.Component<BlockProps, BlockState> {
|
export class Block extends React.Component<BlockProps, BlockState> {
|
||||||
_blockEl: HTMLDivElement | null = null;
|
_blockEl: HTMLDivElement | null = null;
|
||||||
|
|
||||||
constructor (props: BlockProps) {
|
constructor (props: BlockProps) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import InputJson from "./InputJson";
|
import { InputJson } from "./InputJson";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { withTranslation, type WithTranslation } from "react-i18next";
|
import { withTranslation, type WithTranslation } from "react-i18next";
|
||||||
import { type StyleSpecification } from "maplibre-gl";
|
import { type StyleSpecification } from "maplibre-gl";
|
||||||
@@ -24,6 +24,4 @@ const CodeEditorInternal: React.FC<CodeEditorProps> = (props) => {
|
|||||||
</>;
|
</>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const CodeEditor = withTranslation()(CodeEditorInternal);
|
export const CodeEditor = withTranslation()(CodeEditorInternal);
|
||||||
|
|
||||||
export default CodeEditor;
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ type CollapseProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export default class Collapse extends React.Component<CollapseProps> {
|
export class Collapse extends React.Component<CollapseProps> {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
isActive: true
|
isActive: true
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ type CollapserProps = {
|
|||||||
style?: object
|
style?: object
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class Collapser extends React.Component<CollapserProps> {
|
export class Collapser extends React.Component<CollapserProps> {
|
||||||
render() {
|
render() {
|
||||||
const iconStyle = {
|
const iconStyle = {
|
||||||
width: 20,
|
width: 20,
|
||||||
|
|||||||
@@ -3,19 +3,19 @@ import {PiListPlusBold} from "react-icons/pi";
|
|||||||
import {TbMathFunction} from "react-icons/tb";
|
import {TbMathFunction} from "react-icons/tb";
|
||||||
import latest from "@maplibre/maplibre-gl-style-spec/dist/latest.json";
|
import latest from "@maplibre/maplibre-gl-style-spec/dist/latest.json";
|
||||||
|
|
||||||
import InputButton from "./InputButton";
|
import { InputButton } from "./InputButton";
|
||||||
import InputSpec from "./InputSpec";
|
import { InputSpec } from "./InputSpec";
|
||||||
import InputNumber from "./InputNumber";
|
import { InputNumber } from "./InputNumber";
|
||||||
import InputString from "./InputString";
|
import { InputString } from "./InputString";
|
||||||
import InputSelect from "./InputSelect";
|
import { InputSelect } from "./InputSelect";
|
||||||
import Block from "./Block";
|
import { Block } from "./Block";
|
||||||
import docUid from "../libs/document-uid";
|
import { generateUniqueId as docUid } from "../libs/document-uid";
|
||||||
import sortNumerically from "../libs/sort-numerically";
|
import { sortNumerically } from "../libs/sort-numerically";
|
||||||
import {findDefaultFromSpec} from "../libs/spec-helper";
|
import {findDefaultFromSpec} from "../libs/spec-helper";
|
||||||
import { type WithTranslation, withTranslation } from "react-i18next";
|
import { type WithTranslation, withTranslation } from "react-i18next";
|
||||||
|
|
||||||
import labelFromFieldName from "../libs/label-from-field-name";
|
import { labelFromFieldName } from "../libs/label-from-field-name";
|
||||||
import DeleteStopButton from "./_DeleteStopButton";
|
import { DeleteStopButton } from "./DeleteStopButton";
|
||||||
import { type MappedLayerErrors } from "../libs/definitions";
|
import { type MappedLayerErrors } from "../libs/definitions";
|
||||||
|
|
||||||
|
|
||||||
@@ -289,6 +289,7 @@ class DataPropertyInternal extends React.Component<DataPropertyInternalProps, Da
|
|||||||
<Block
|
<Block
|
||||||
label={t("Function")}
|
label={t("Function")}
|
||||||
key="function"
|
key="function"
|
||||||
|
data-wd-key="function-type"
|
||||||
>
|
>
|
||||||
<div className="maputnik-data-spec-property-input">
|
<div className="maputnik-data-spec-property-input">
|
||||||
<InputSelect
|
<InputSelect
|
||||||
@@ -303,6 +304,7 @@ class DataPropertyInternal extends React.Component<DataPropertyInternalProps, Da
|
|||||||
<Block
|
<Block
|
||||||
label={t("Base")}
|
label={t("Base")}
|
||||||
key="base"
|
key="base"
|
||||||
|
data-wd-key="function-base"
|
||||||
>
|
>
|
||||||
<div className="maputnik-data-spec-property-input">
|
<div className="maputnik-data-spec-property-input">
|
||||||
<InputSpec
|
<InputSpec
|
||||||
@@ -317,6 +319,7 @@ class DataPropertyInternal extends React.Component<DataPropertyInternalProps, Da
|
|||||||
<Block
|
<Block
|
||||||
label={"Property"}
|
label={"Property"}
|
||||||
key="property"
|
key="property"
|
||||||
|
data-wd-key="function-property"
|
||||||
>
|
>
|
||||||
<div className="maputnik-data-spec-property-input">
|
<div className="maputnik-data-spec-property-input">
|
||||||
<InputString
|
<InputString
|
||||||
@@ -330,6 +333,7 @@ class DataPropertyInternal extends React.Component<DataPropertyInternalProps, Da
|
|||||||
<Block
|
<Block
|
||||||
label={t("Default")}
|
label={t("Default")}
|
||||||
key="default"
|
key="default"
|
||||||
|
data-wd-key="function-default"
|
||||||
>
|
>
|
||||||
<InputSpec
|
<InputSpec
|
||||||
fieldName={this.props.fieldName}
|
fieldName={this.props.fieldName}
|
||||||
@@ -368,6 +372,7 @@ class DataPropertyInternal extends React.Component<DataPropertyInternalProps, Da
|
|||||||
}
|
}
|
||||||
<InputButton
|
<InputButton
|
||||||
className="maputnik-add-stop"
|
className="maputnik-add-stop"
|
||||||
|
data-wd-key="convert-to-expression"
|
||||||
onClick={this.props.onExpressionClick?.bind(this)}
|
onClick={this.props.onExpressionClick?.bind(this)}
|
||||||
>
|
>
|
||||||
<TbMathFunction style={{ verticalAlign: "text-bottom" }} />
|
<TbMathFunction style={{ verticalAlign: "text-bottom" }} />
|
||||||
@@ -380,5 +385,4 @@ class DataPropertyInternal extends React.Component<DataPropertyInternalProps, Da
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const DataProperty = withTranslation()(DataPropertyInternal);
|
export const DataProperty = withTranslation()(DataPropertyInternal);
|
||||||
export default DataProperty;
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import InputButton from "./InputButton";
|
import { InputButton } from "./InputButton";
|
||||||
import {MdDelete} from "react-icons/md";
|
import {MdDelete} from "react-icons/md";
|
||||||
import { type WithTranslation, withTranslation } from "react-i18next";
|
import { type WithTranslation, withTranslation } from "react-i18next";
|
||||||
|
|
||||||
@@ -23,5 +23,4 @@ class DeleteStopButtonInternal extends React.Component<DeleteStopButtonInternalP
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const DeleteStopButton = withTranslation()(DeleteStopButtonInternal);
|
export const DeleteStopButton = withTranslation()(DeleteStopButtonInternal);
|
||||||
export default DeleteStopButton;
|
|
||||||
@@ -23,7 +23,7 @@ type DocProps = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class Doc extends React.Component<DocProps> {
|
export class Doc extends React.Component<DocProps> {
|
||||||
render () {
|
render () {
|
||||||
const {fieldSpec} = this.props;
|
const {fieldSpec} = this.props;
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ import React from "react";
|
|||||||
import {MdDelete, MdUndo} from "react-icons/md";
|
import {MdDelete, MdUndo} from "react-icons/md";
|
||||||
import { type WithTranslation, withTranslation } from "react-i18next";
|
import { type WithTranslation, withTranslation } from "react-i18next";
|
||||||
|
|
||||||
import Block from "./Block";
|
import { Block } from "./Block";
|
||||||
import InputButton from "./InputButton";
|
import { InputButton } from "./InputButton";
|
||||||
import labelFromFieldName from "../libs/label-from-field-name";
|
import { labelFromFieldName } from "../libs/label-from-field-name";
|
||||||
import FieldJson from "./FieldJson";
|
import { FieldJson } from "./FieldJson";
|
||||||
import type { StylePropertySpecification } from "maplibre-gl";
|
import type { StylePropertySpecification } from "maplibre-gl";
|
||||||
import { type MappedLayerErrors } from "../libs/definitions";
|
import { type MappedLayerErrors } from "../libs/definitions";
|
||||||
|
|
||||||
@@ -50,6 +50,7 @@ class ExpressionPropertyInternal extends React.Component<ExpressionPropertyInter
|
|||||||
onClick={this.props.onUndo}
|
onClick={this.props.onUndo}
|
||||||
disabled={undoDisabled}
|
disabled={undoDisabled}
|
||||||
className="maputnik-delete-stop"
|
className="maputnik-delete-stop"
|
||||||
|
data-wd-key="undo-expression"
|
||||||
title={t("Revert from expression")}
|
title={t("Revert from expression")}
|
||||||
>
|
>
|
||||||
<MdUndo />
|
<MdUndo />
|
||||||
@@ -59,6 +60,7 @@ class ExpressionPropertyInternal extends React.Component<ExpressionPropertyInter
|
|||||||
key="delete_action"
|
key="delete_action"
|
||||||
onClick={this.props.onDelete}
|
onClick={this.props.onDelete}
|
||||||
className="maputnik-delete-stop"
|
className="maputnik-delete-stop"
|
||||||
|
data-wd-key="delete-expression"
|
||||||
title={t("Delete expression")}
|
title={t("Delete expression")}
|
||||||
>
|
>
|
||||||
<MdDelete />
|
<MdDelete />
|
||||||
@@ -90,5 +92,4 @@ class ExpressionPropertyInternal extends React.Component<ExpressionPropertyInter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ExpressionProperty = withTranslation()(ExpressionPropertyInternal);
|
export const ExpressionProperty = withTranslation()(ExpressionPropertyInternal);
|
||||||
export default ExpressionProperty;
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import InputArray, { type InputArrayProps } from "./InputArray";
|
import { InputArray, type InputArrayProps } from "./InputArray";
|
||||||
import Fieldset from "./Fieldset";
|
import { Fieldset } from "./Fieldset";
|
||||||
|
|
||||||
type FieldArrayProps = InputArrayProps & {
|
type FieldArrayProps = InputArrayProps & {
|
||||||
name?: string
|
name?: string
|
||||||
@@ -8,12 +8,10 @@ type FieldArrayProps = InputArrayProps & {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const FieldArray: React.FC<FieldArrayProps> = (props) => {
|
export const FieldArray: React.FC<FieldArrayProps> = (props) => {
|
||||||
return (
|
return (
|
||||||
<Fieldset label={props.label} fieldSpec={props.fieldSpec}>
|
<Fieldset label={props.label} fieldSpec={props.fieldSpec}>
|
||||||
<InputArray {...props} />
|
<InputArray {...props} />
|
||||||
</Fieldset>
|
</Fieldset>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default FieldArray;
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import Block from "./Block";
|
import { Block } from "./Block";
|
||||||
import InputAutocomplete, { type InputAutocompleteProps } from "./InputAutocomplete";
|
import { InputAutocomplete, type InputAutocompleteProps } from "./InputAutocomplete";
|
||||||
|
|
||||||
|
|
||||||
type FieldAutocompleteProps = InputAutocompleteProps & {
|
type FieldAutocompleteProps = InputAutocompleteProps & {
|
||||||
@@ -7,12 +7,10 @@ type FieldAutocompleteProps = InputAutocompleteProps & {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const FieldAutocomplete: React.FC<FieldAutocompleteProps> = (props) => {
|
export const FieldAutocomplete: React.FC<FieldAutocompleteProps> = (props) => {
|
||||||
return (
|
return (
|
||||||
<Block label={props.label}>
|
<Block label={props.label}>
|
||||||
<InputAutocomplete {...props} />
|
<InputAutocomplete {...props} />
|
||||||
</Block>
|
</Block>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default FieldAutocomplete;
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import Block from "./Block";
|
import { Block } from "./Block";
|
||||||
import InputCheckbox, {type InputCheckboxProps} from "./InputCheckbox";
|
import { InputCheckbox, type InputCheckboxProps } from "./InputCheckbox";
|
||||||
|
|
||||||
|
|
||||||
type FieldCheckboxProps = InputCheckboxProps & {
|
type FieldCheckboxProps = InputCheckboxProps & {
|
||||||
@@ -7,12 +7,10 @@ type FieldCheckboxProps = InputCheckboxProps & {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const FieldCheckbox: React.FC<FieldCheckboxProps> = (props) => {
|
export const FieldCheckbox: React.FC<FieldCheckboxProps> = (props) => {
|
||||||
return (
|
return (
|
||||||
<Block label={props.label}>
|
<Block label={props.label}>
|
||||||
<InputCheckbox {...props} />
|
<InputCheckbox {...props} />
|
||||||
</Block>
|
</Block>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default FieldCheckbox;
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import Block from "./Block";
|
import { Block } from "./Block";
|
||||||
import InputColor, {type InputColorProps} from "./InputColor";
|
import { InputColor, type InputColorProps } from "./InputColor";
|
||||||
|
|
||||||
|
|
||||||
type FieldColorProps = InputColorProps & {
|
type FieldColorProps = InputColorProps & {
|
||||||
@@ -10,12 +10,10 @@ type FieldColorProps = InputColorProps & {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const FieldColor: React.FC<FieldColorProps> = (props) => {
|
export const FieldColor: React.FC<FieldColorProps> = (props) => {
|
||||||
return (
|
return (
|
||||||
<Block label={props.label} fieldSpec={props.fieldSpec}>
|
<Block label={props.label} fieldSpec={props.fieldSpec}>
|
||||||
<InputColor {...props} />
|
<InputColor {...props} />
|
||||||
</Block>
|
</Block>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default FieldColor;
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import Block from "./Block";
|
import { Block } from "./Block";
|
||||||
import InputString from "./InputString";
|
import { InputString } from "./InputString";
|
||||||
import { type WithTranslation, withTranslation } from "react-i18next";
|
import { type WithTranslation, withTranslation } from "react-i18next";
|
||||||
|
|
||||||
type FieldCommentInternalProps = {
|
type FieldCommentInternalProps = {
|
||||||
@@ -36,5 +36,4 @@ const FieldCommentInternal: React.FC<FieldCommentInternalProps> = (props) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const FieldComment = withTranslation()(FieldCommentInternal);
|
export const FieldComment = withTranslation()(FieldCommentInternal);
|
||||||
export default FieldComment;
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ type FieldDocLabelProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const FieldDocLabel: React.FC<FieldDocLabelProps> = (props) => {
|
export const FieldDocLabel: React.FC<FieldDocLabelProps> = (props) => {
|
||||||
const [open, setOpen] = React.useState(false);
|
const [open, setOpen] = React.useState(false);
|
||||||
|
|
||||||
const onToggleDoc = (state: boolean) => {
|
const onToggleDoc = (state: boolean) => {
|
||||||
@@ -49,5 +49,3 @@ const FieldDocLabel: React.FC<FieldDocLabelProps> = (props) => {
|
|||||||
}
|
}
|
||||||
return <div />;
|
return <div />;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default FieldDocLabel;
|
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
import InputDynamicArray, {type InputDynamicArrayProps} from "./InputDynamicArray";
|
import { InputDynamicArray, type InputDynamicArrayProps } from "./InputDynamicArray";
|
||||||
import Fieldset from "./Fieldset";
|
import { Fieldset } from "./Fieldset";
|
||||||
|
|
||||||
type FieldDynamicArrayProps = InputDynamicArrayProps & {
|
type FieldDynamicArrayProps = InputDynamicArrayProps & {
|
||||||
name?: string
|
name?: string;
|
||||||
|
fieldSpec?: {
|
||||||
|
value?: string;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const FieldDynamicArray: React.FC<FieldDynamicArrayProps> = (props) => {
|
export const FieldDynamicArray: React.FC<FieldDynamicArrayProps> = (props) => {
|
||||||
return (
|
return (
|
||||||
<Fieldset label={props.label}>
|
<Fieldset label={props.label}>
|
||||||
<InputDynamicArray {...props} />
|
<InputDynamicArray {...props} />
|
||||||
</Fieldset>
|
</Fieldset>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default FieldDynamicArray;
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import InputEnum, {type InputEnumProps} from "./InputEnum";
|
import { InputEnum, type InputEnumProps } from "./InputEnum";
|
||||||
import Fieldset from "./Fieldset";
|
import { Fieldset } from "./Fieldset";
|
||||||
|
|
||||||
|
|
||||||
type FieldEnumProps = InputEnumProps & {
|
type FieldEnumProps = InputEnumProps & {
|
||||||
@@ -10,12 +10,10 @@ type FieldEnumProps = InputEnumProps & {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const FieldEnum: React.FC<FieldEnumProps> = (props) => {
|
export const FieldEnum: React.FC<FieldEnumProps> = (props) => {
|
||||||
return (
|
return (
|
||||||
<Fieldset label={props.label} fieldSpec={props.fieldSpec}>
|
<Fieldset label={props.label} fieldSpec={props.fieldSpec}>
|
||||||
<InputEnum {...props} />
|
<InputEnum {...props} />
|
||||||
</Fieldset>
|
</Fieldset>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default FieldEnum;
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import SpecProperty from "./_SpecProperty";
|
import { SpecProperty } from "./SpecProperty";
|
||||||
import DataProperty, { type Stop } from "./_DataProperty";
|
import { DataProperty, type Stop } from "./DataProperty";
|
||||||
import ZoomProperty from "./_ZoomProperty";
|
import { ZoomProperty } from "./ZoomProperty";
|
||||||
import ExpressionProperty from "./_ExpressionProperty";
|
import { ExpressionProperty } from "./ExpressionProperty";
|
||||||
import {function as styleFunction} from "@maplibre/maplibre-gl-style-spec";
|
import {function as styleFunction} from "@maplibre/maplibre-gl-style-spec";
|
||||||
import {findDefaultFromSpec} from "../libs/spec-helper";
|
import {findDefaultFromSpec} from "../libs/spec-helper";
|
||||||
import { type MappedLayerErrors } from "../libs/definitions";
|
import { type MappedLayerErrors } from "../libs/definitions";
|
||||||
@@ -128,7 +128,7 @@ type FieldFunctionProps = {
|
|||||||
/** Supports displaying spec field for zoom function objects
|
/** Supports displaying spec field for zoom function objects
|
||||||
* https://www.mapbox.com/mapbox-gl-style-spec/#types-function-zoom-property
|
* https://www.mapbox.com/mapbox-gl-style-spec/#types-function-zoom-property
|
||||||
*/
|
*/
|
||||||
const FieldFunction: React.FC<FieldFunctionProps> = (props) => {
|
export const FieldFunction: React.FC<FieldFunctionProps> = (props) => {
|
||||||
const [dataType, setDataType] = React.useState(
|
const [dataType, setDataType] = React.useState(
|
||||||
getDataType(props.value, props.fieldSpec)
|
getDataType(props.value, props.fieldSpec)
|
||||||
);
|
);
|
||||||
@@ -402,5 +402,3 @@ const FieldFunction: React.FC<FieldFunctionProps> = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default FieldFunction;
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
import latest from "@maplibre/maplibre-gl-style-spec/dist/latest.json";
|
import latest from "@maplibre/maplibre-gl-style-spec/dist/latest.json";
|
||||||
import Block from "./Block";
|
import { Block } from "./Block";
|
||||||
import InputString from "./InputString";
|
import { InputString } from "./InputString";
|
||||||
|
|
||||||
type FieldIdProps = {
|
type FieldIdProps = {
|
||||||
value: string
|
value: string
|
||||||
@@ -10,7 +10,7 @@ type FieldIdProps = {
|
|||||||
error?: {message: string}
|
error?: {message: string}
|
||||||
};
|
};
|
||||||
|
|
||||||
const FieldId: React.FC<FieldIdProps> = (props) => {
|
export const FieldId: React.FC<FieldIdProps> = (props) => {
|
||||||
return (
|
return (
|
||||||
<Block label="ID" fieldSpec={latest.layer.id}
|
<Block label="ID" fieldSpec={latest.layer.id}
|
||||||
data-wd-key={props.wdKey}
|
data-wd-key={props.wdKey}
|
||||||
@@ -24,5 +24,3 @@ const FieldId: React.FC<FieldIdProps> = (props) => {
|
|||||||
</Block>
|
</Block>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default FieldId;
|
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
import InputJson, {type InputJsonProps} from "./InputJson";
|
import { InputJson, type InputJsonProps } from "./InputJson";
|
||||||
|
|
||||||
|
|
||||||
type FieldJsonProps = InputJsonProps & {};
|
type FieldJsonProps = InputJsonProps & {};
|
||||||
|
|
||||||
|
|
||||||
const FieldJson: React.FC<FieldJsonProps> = (props) => {
|
export const FieldJson: React.FC<FieldJsonProps> = (props) => {
|
||||||
return <InputJson {...props} />;
|
return <InputJson {...props} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default FieldJson;
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import latest from "@maplibre/maplibre-gl-style-spec/dist/latest.json";
|
import latest from "@maplibre/maplibre-gl-style-spec/dist/latest.json";
|
||||||
import Block from "./Block";
|
import { Block } from "./Block";
|
||||||
import InputNumber from "./InputNumber";
|
import { InputNumber } from "./InputNumber";
|
||||||
import { type WithTranslation, withTranslation } from "react-i18next";
|
import { type WithTranslation, withTranslation } from "react-i18next";
|
||||||
|
|
||||||
type FieldMaxZoomInternalProps = {
|
type FieldMaxZoomInternalProps = {
|
||||||
@@ -31,5 +31,4 @@ const FieldMaxZoomInternal: React.FC<FieldMaxZoomInternalProps> = (props) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const FieldMaxZoom = withTranslation()(FieldMaxZoomInternal);
|
export const FieldMaxZoom = withTranslation()(FieldMaxZoomInternal);
|
||||||
export default FieldMaxZoom;
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import latest from "@maplibre/maplibre-gl-style-spec/dist/latest.json";
|
import latest from "@maplibre/maplibre-gl-style-spec/dist/latest.json";
|
||||||
import Block from "./Block";
|
import { Block } from "./Block";
|
||||||
import InputNumber from "./InputNumber";
|
import { InputNumber } from "./InputNumber";
|
||||||
import { type WithTranslation, withTranslation } from "react-i18next";
|
import { type WithTranslation, withTranslation } from "react-i18next";
|
||||||
|
|
||||||
type FieldMinZoomInternalProps = {
|
type FieldMinZoomInternalProps = {
|
||||||
@@ -31,5 +31,4 @@ const FieldMinZoomInternal: React.FC<FieldMinZoomInternalProps> = (props) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const FieldMinZoom = withTranslation()(FieldMinZoomInternal);
|
export const FieldMinZoom = withTranslation()(FieldMinZoomInternal);
|
||||||
export default FieldMinZoom;
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import InputMultiInput, {type InputMultiInputProps} from "./InputMultiInput";
|
import { InputMultiInput, type InputMultiInputProps } from "./InputMultiInput";
|
||||||
import Fieldset from "./Fieldset";
|
import { Fieldset } from "./Fieldset";
|
||||||
|
|
||||||
|
|
||||||
type FieldMultiInputProps = InputMultiInputProps & {
|
type FieldMultiInputProps = InputMultiInputProps & {
|
||||||
@@ -7,12 +7,10 @@ type FieldMultiInputProps = InputMultiInputProps & {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const FieldMultiInput: React.FC<FieldMultiInputProps> = (props) => {
|
export const FieldMultiInput: React.FC<FieldMultiInputProps> = (props) => {
|
||||||
return (
|
return (
|
||||||
<Fieldset label={props.label}>
|
<Fieldset label={props.label}>
|
||||||
<InputMultiInput {...props} />
|
<InputMultiInput {...props} />
|
||||||
</Fieldset>
|
</Fieldset>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default FieldMultiInput;
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import InputNumber, {type InputNumberProps} from "./InputNumber";
|
import { InputNumber, type InputNumberProps } from "./InputNumber";
|
||||||
import Block from "./Block";
|
import { Block } from "./Block";
|
||||||
|
|
||||||
|
|
||||||
type FieldNumberProps = InputNumberProps & {
|
type FieldNumberProps = InputNumberProps & {
|
||||||
@@ -10,12 +10,10 @@ type FieldNumberProps = InputNumberProps & {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const FieldNumber: React.FC<FieldNumberProps> = (props) => {
|
export const FieldNumber: React.FC<FieldNumberProps> = (props) => {
|
||||||
return (
|
return (
|
||||||
<Block label={props.label} fieldSpec={props.fieldSpec}>
|
<Block label={props.label} fieldSpec={props.fieldSpec}>
|
||||||
<InputNumber {...props} />
|
<InputNumber {...props} />
|
||||||
</Block>
|
</Block>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default FieldNumber;
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import Block from "./Block";
|
import { Block } from "./Block";
|
||||||
import InputSelect, {type InputSelectProps} from "./InputSelect";
|
import { InputSelect, type InputSelectProps } from "./InputSelect";
|
||||||
|
|
||||||
|
|
||||||
type FieldSelectProps = InputSelectProps & {
|
type FieldSelectProps = InputSelectProps & {
|
||||||
@@ -10,12 +10,10 @@ type FieldSelectProps = InputSelectProps & {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const FieldSelect: React.FC<FieldSelectProps> = (props) => {
|
export const FieldSelect: React.FC<FieldSelectProps> = (props) => {
|
||||||
return (
|
return (
|
||||||
<Block label={props.label} fieldSpec={props.fieldSpec}>
|
<Block label={props.label} fieldSpec={props.fieldSpec}>
|
||||||
<InputSelect {...props} />
|
<InputSelect {...props} />
|
||||||
</Block>
|
</Block>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default FieldSelect;
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import latest from "@maplibre/maplibre-gl-style-spec/dist/latest.json";
|
import latest from "@maplibre/maplibre-gl-style-spec/dist/latest.json";
|
||||||
import Block from "./Block";
|
import { Block } from "./Block";
|
||||||
import InputAutocomplete from "./InputAutocomplete";
|
import { InputAutocomplete } from "./InputAutocomplete";
|
||||||
import { type WithTranslation, withTranslation } from "react-i18next";
|
import { type WithTranslation, withTranslation } from "react-i18next";
|
||||||
|
|
||||||
type FieldSourceInternalProps = {
|
type FieldSourceInternalProps = {
|
||||||
@@ -38,5 +38,4 @@ const FieldSourceInternal: React.FC<FieldSourceInternalProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const FieldSource = withTranslation()(FieldSourceInternal);
|
export const FieldSource = withTranslation()(FieldSourceInternal);
|
||||||
export default FieldSource;
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import {latest} from "@maplibre/maplibre-gl-style-spec";
|
import {latest} from "@maplibre/maplibre-gl-style-spec";
|
||||||
import Block from "./Block";
|
import { Block } from "./Block";
|
||||||
import InputAutocomplete from "./InputAutocomplete";
|
import { InputAutocomplete } from "./InputAutocomplete";
|
||||||
import { type WithTranslation, withTranslation } from "react-i18next";
|
import { type WithTranslation, withTranslation } from "react-i18next";
|
||||||
|
|
||||||
type FieldSourceLayerInternalProps = {
|
type FieldSourceLayerInternalProps = {
|
||||||
@@ -35,5 +35,4 @@ const FieldSourceLayerInternal: React.FC<FieldSourceLayerInternalProps> = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const FieldSourceLayer = withTranslation()(FieldSourceLayerInternal);
|
export const FieldSourceLayer = withTranslation()(FieldSourceLayerInternal);
|
||||||
export default FieldSourceLayer;
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import Block, { type BlockProps } from "./Block";
|
import { Block, type BlockProps } from "./Block";
|
||||||
import InputSpec, { type FieldSpecType, type InputSpecProps } from "./InputSpec";
|
import { InputSpec, type FieldSpecType, type InputSpecProps } from "./InputSpec";
|
||||||
import Fieldset, { type FieldsetProps } from "./Fieldset";
|
import { Fieldset, type FieldsetProps } from "./Fieldset";
|
||||||
|
|
||||||
function getElementFromType(fieldSpec: { type?: FieldSpecType, values?: unknown[] }): typeof Fieldset | typeof Block {
|
function getElementFromType(fieldSpec: { type?: FieldSpecType, values?: unknown[] }): typeof Fieldset | typeof Block {
|
||||||
switch(fieldSpec.type) {
|
switch(fieldSpec.type) {
|
||||||
@@ -36,7 +36,7 @@ function getElementFromType(fieldSpec: { type?: FieldSpecType, values?: unknown[
|
|||||||
|
|
||||||
export type FieldSpecProps = InputSpecProps & BlockProps & FieldsetProps;
|
export type FieldSpecProps = InputSpecProps & BlockProps & FieldsetProps;
|
||||||
|
|
||||||
const FieldSpec: React.FC<FieldSpecProps> = (props) => {
|
export const FieldSpec: React.FC<FieldSpecProps> = (props) => {
|
||||||
const TypeBlock = getElementFromType(props.fieldSpec!);
|
const TypeBlock = getElementFromType(props.fieldSpec!);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -45,5 +45,3 @@ const FieldSpec: React.FC<FieldSpecProps> = (props) => {
|
|||||||
</TypeBlock>
|
</TypeBlock>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default FieldSpec;
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import Block from "./Block";
|
import { Block } from "./Block";
|
||||||
import InputString, {type InputStringProps} from "./InputString";
|
import { InputString, type InputStringProps } from "./InputString";
|
||||||
|
|
||||||
type FieldStringProps = InputStringProps & {
|
type FieldStringProps = InputStringProps & {
|
||||||
name?: string
|
name?: string
|
||||||
@@ -9,12 +9,10 @@ type FieldStringProps = InputStringProps & {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const FieldString: React.FC<FieldStringProps> = (props) => {
|
export const FieldString: React.FC<FieldStringProps> = (props) => {
|
||||||
return (
|
return (
|
||||||
<Block label={props.label} fieldSpec={props.fieldSpec}>
|
<Block label={props.label} fieldSpec={props.fieldSpec}>
|
||||||
<InputString {...props} />
|
<InputString {...props} />
|
||||||
</Block>
|
</Block>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default FieldString;
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import {v8} from "@maplibre/maplibre-gl-style-spec";
|
import {v8} from "@maplibre/maplibre-gl-style-spec";
|
||||||
import Block from "./Block";
|
import { Block } from "./Block";
|
||||||
import InputSelect from "./InputSelect";
|
import { InputSelect } from "./InputSelect";
|
||||||
import InputString from "./InputString";
|
import { InputString } from "./InputString";
|
||||||
import { type WithTranslation, withTranslation } from "react-i18next";
|
import { type WithTranslation, withTranslation } from "react-i18next";
|
||||||
import { startCase } from "lodash";
|
import { startCase } from "lodash";
|
||||||
|
|
||||||
@@ -43,5 +43,4 @@ const FieldTypeInternal: React.FC<FieldTypeInternalProps> = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const FieldType = withTranslation()(FieldTypeInternal);
|
export const FieldType = withTranslation()(FieldTypeInternal);
|
||||||
export default FieldType;
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import InputUrl, {type FieldUrlProps as InputUrlProps} from "./InputUrl";
|
import { InputUrl, type FieldUrlProps as InputUrlProps } from "./InputUrl";
|
||||||
import Block from "./Block";
|
import { Block } from "./Block";
|
||||||
|
|
||||||
|
|
||||||
type FieldUrlProps = InputUrlProps & {
|
type FieldUrlProps = InputUrlProps & {
|
||||||
@@ -10,12 +10,10 @@ type FieldUrlProps = InputUrlProps & {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const FieldUrl: React.FC<FieldUrlProps> = (props) => {
|
export const FieldUrl: React.FC<FieldUrlProps> = (props) => {
|
||||||
return (
|
return (
|
||||||
<Block label={props.label} fieldSpec={props.fieldSpec}>
|
<Block label={props.label} fieldSpec={props.fieldSpec}>
|
||||||
<InputUrl {...props} />
|
<InputUrl {...props} />
|
||||||
</Block>
|
</Block>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default FieldUrl;
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import React, { type PropsWithChildren, type ReactElement } from "react";
|
import React, { type PropsWithChildren, type ReactElement } from "react";
|
||||||
import classnames from "classnames";
|
import classnames from "classnames";
|
||||||
import FieldDocLabel from "./FieldDocLabel";
|
import { FieldDocLabel } from "./FieldDocLabel";
|
||||||
import Doc from "./Doc";
|
import { Doc } from "./Doc";
|
||||||
import generateUniqueId from "../libs/document-uid";
|
import { generateUniqueId } from "../libs/document-uid";
|
||||||
|
|
||||||
export type FieldsetProps = PropsWithChildren & {
|
export type FieldsetProps = PropsWithChildren & {
|
||||||
label?: string,
|
label?: string,
|
||||||
@@ -12,7 +12,7 @@ export type FieldsetProps = PropsWithChildren & {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const Fieldset: React.FC<FieldsetProps> = (props) => {
|
export const Fieldset: React.FC<FieldsetProps> = (props) => {
|
||||||
const [showDoc, setShowDoc] = React.useState(false);
|
const [showDoc, setShowDoc] = React.useState(false);
|
||||||
const labelId = React.useRef(generateUniqueId("fieldset_label_"));
|
const labelId = React.useRef(generateUniqueId("fieldset_label_"));
|
||||||
|
|
||||||
@@ -49,5 +49,3 @@ const Fieldset: React.FC<FieldsetProps> = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Fieldset;
|
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ import {migrate, convertFilter} from "@maplibre/maplibre-gl-style-spec";
|
|||||||
import latest from "@maplibre/maplibre-gl-style-spec/dist/latest.json";
|
import latest from "@maplibre/maplibre-gl-style-spec/dist/latest.json";
|
||||||
|
|
||||||
import {combiningFilterOps} from "../libs/filterops";
|
import {combiningFilterOps} from "../libs/filterops";
|
||||||
import InputSelect from "./InputSelect";
|
import { InputSelect } from "./InputSelect";
|
||||||
import Block from "./Block";
|
import { Block } from "./Block";
|
||||||
import SingleFilterEditor from "./SingleFilterEditor";
|
import { SingleFilterEditor } from "./SingleFilterEditor";
|
||||||
import FilterEditorBlock from "./FilterEditorBlock";
|
import { FilterEditorBlock } from "./FilterEditorBlock";
|
||||||
import InputButton from "./InputButton";
|
import { InputButton } from "./InputButton";
|
||||||
import Doc from "./Doc";
|
import { Doc } from "./Doc";
|
||||||
import ExpressionProperty from "./_ExpressionProperty";
|
import { ExpressionProperty } from "./ExpressionProperty";
|
||||||
import { type WithTranslation, withTranslation } from "react-i18next";
|
import { type WithTranslation, withTranslation } from "react-i18next";
|
||||||
import type { MappedLayerErrors, StyleSpecificationWithId } from "../libs/definitions";
|
import type { MappedLayerErrors, StyleSpecificationWithId } from "../libs/definitions";
|
||||||
|
|
||||||
@@ -215,6 +215,7 @@ class FilterEditorInternal extends React.Component<FilterEditorInternalProps, Fi
|
|||||||
onClick={this.makeExpression}
|
onClick={this.makeExpression}
|
||||||
title={t("Convert to expression")}
|
title={t("Convert to expression")}
|
||||||
className="maputnik-make-zoom-function"
|
className="maputnik-make-zoom-function"
|
||||||
|
data-wd-key="filter-convert-to-expression"
|
||||||
>
|
>
|
||||||
<TbMathFunction />
|
<TbMathFunction />
|
||||||
</InputButton>
|
</InputButton>
|
||||||
@@ -248,6 +249,7 @@ class FilterEditorInternal extends React.Component<FilterEditorInternalProps, Fi
|
|||||||
fieldSpec={fieldSpec}
|
fieldSpec={fieldSpec}
|
||||||
label={t("Filter")}
|
label={t("Filter")}
|
||||||
action={actions}
|
action={actions}
|
||||||
|
data-wd-key="filter-combining-operator"
|
||||||
>
|
>
|
||||||
<InputSelect
|
<InputSelect
|
||||||
value={combiningOp}
|
value={combiningOp}
|
||||||
@@ -316,5 +318,4 @@ class FilterEditorInternal extends React.Component<FilterEditorInternalProps, Fi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const FilterEditor = withTranslation()(FilterEditorInternal);
|
export const FilterEditor = withTranslation()(FilterEditorInternal);
|
||||||
export default FilterEditor;
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { type PropsWithChildren } from "react";
|
import React, { type PropsWithChildren } from "react";
|
||||||
import InputButton from "./InputButton";
|
import { InputButton } from "./InputButton";
|
||||||
import {MdDelete} from "react-icons/md";
|
import {MdDelete} from "react-icons/md";
|
||||||
import { type WithTranslation, withTranslation } from "react-i18next";
|
import { type WithTranslation, withTranslation } from "react-i18next";
|
||||||
|
|
||||||
@@ -27,5 +27,4 @@ class FilterEditorBlockInternal extends React.Component<FilterEditorBlockInterna
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const FilterEditorBlock = withTranslation()(FilterEditorBlockInternal);
|
export const FilterEditorBlock = withTranslation()(FilterEditorBlockInternal);
|
||||||
export default FilterEditorBlock;
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import InputButton from "./InputButton";
|
import { InputButton } from "./InputButton";
|
||||||
import {MdFunctions, MdInsertChart} from "react-icons/md";
|
import {MdFunctions, MdInsertChart} from "react-icons/md";
|
||||||
import { TbMathFunction } from "react-icons/tb";
|
import { TbMathFunction } from "react-icons/tb";
|
||||||
import { type WithTranslation, withTranslation } from "react-i18next";
|
import { type WithTranslation, withTranslation } from "react-i18next";
|
||||||
@@ -67,5 +67,4 @@ class FunctionInputButtonsInternal extends React.Component<FunctionInputButtonsI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const FunctionInputButtons = withTranslation()(FunctionInputButtonsInternal);
|
export const FunctionInputButtons = withTranslation()(FunctionInputButtonsInternal);
|
||||||
export default FunctionInputButtons;
|
|
||||||
@@ -13,7 +13,7 @@ type IconLayerProps = {
|
|||||||
className?: string
|
className?: string
|
||||||
};
|
};
|
||||||
|
|
||||||
const IconLayer: React.FC<IconLayerProps> = (props) => {
|
export const IconLayer: React.FC<IconLayerProps> = (props) => {
|
||||||
const iconProps = { style: props.style };
|
const iconProps = { style: props.style };
|
||||||
switch(props.type) {
|
switch(props.type) {
|
||||||
case "fill-extrusion": return <IoMdCube {...iconProps} />;
|
case "fill-extrusion": return <IoMdCube {...iconProps} />;
|
||||||
@@ -29,5 +29,3 @@ const IconLayer: React.FC<IconLayerProps> = (props) => {
|
|||||||
default: return <MdPriorityHigh {...iconProps} />;
|
default: return <MdPriorityHigh {...iconProps} />;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default IconLayer;
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import InputString from "./InputString";
|
import { InputString } from "./InputString";
|
||||||
import InputNumber from "./InputNumber";
|
import { InputNumber } from "./InputNumber";
|
||||||
|
|
||||||
export type InputArrayProps = {
|
export type InputArrayProps = {
|
||||||
value: (string | number | undefined)[]
|
value: (string | number | undefined)[]
|
||||||
@@ -17,7 +17,7 @@ type InputArrayState = {
|
|||||||
initialPropsValue: unknown[]
|
initialPropsValue: unknown[]
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class InputArray extends React.Component<InputArrayProps, InputArrayState> {
|
export class InputArray extends React.Component<InputArrayProps, InputArrayState> {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
value: [],
|
value: [],
|
||||||
default: [],
|
default: [],
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
import { expect, test } from "vitest";
|
|
||||||
import { render } from "vitest-browser-react";
|
|
||||||
import { page } from "vitest/browser";
|
|
||||||
import InputAutocomplete from "./InputAutocomplete";
|
|
||||||
|
|
||||||
const fruits = ["apple", "banana", "cherry"];
|
|
||||||
|
|
||||||
test("filters options when typing", async () => {
|
|
||||||
render(<InputAutocomplete aria-label="Fruit" options={fruits.map((f) => [f, f])} />);
|
|
||||||
|
|
||||||
const input = page.getByLabelText("Fruit");
|
|
||||||
await input.click();
|
|
||||||
|
|
||||||
const menuItems = page.getByRole("option");
|
|
||||||
await expect.element(menuItems.first()).toBeVisible();
|
|
||||||
expect(menuItems.all()).toHaveLength(3);
|
|
||||||
|
|
||||||
await input.fill("ch");
|
|
||||||
await expect.element(page.getByText("cherry")).toBeVisible();
|
|
||||||
expect(page.getByRole("option").all()).toHaveLength(1);
|
|
||||||
|
|
||||||
await page.getByText("cherry").click();
|
|
||||||
await expect.element(input).toHaveValue("cherry");
|
|
||||||
});
|
|
||||||
@@ -11,7 +11,7 @@ export type InputAutocompleteProps = {
|
|||||||
"aria-label"?: string
|
"aria-label"?: string
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function InputAutocomplete({
|
export function InputAutocomplete({
|
||||||
value,
|
value,
|
||||||
options = [],
|
options = [],
|
||||||
onChange = () => {},
|
onChange = () => {},
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ type InputButtonProps = {
|
|||||||
title?: string
|
title?: string
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class InputButton extends React.Component<InputButtonProps> {
|
export class InputButton extends React.Component<InputButtonProps> {
|
||||||
render() {
|
render() {
|
||||||
return <button
|
return <button
|
||||||
id={this.props.id}
|
id={this.props.id}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ export type InputCheckboxProps = {
|
|||||||
onChange(...args: unknown[]): unknown
|
onChange(...args: unknown[]): unknown
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class InputCheckbox extends React.Component<InputCheckboxProps> {
|
export class InputCheckbox extends React.Component<InputCheckboxProps> {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
value: false,
|
value: false,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export type InputColorProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*** Number fields with support for min, max and units and documentation*/
|
/*** Number fields with support for min, max and units and documentation*/
|
||||||
export default class InputColor extends React.Component<InputColorProps> {
|
export class InputColor extends React.Component<InputColorProps> {
|
||||||
state = {
|
state = {
|
||||||
pickerOpened: false
|
pickerOpened: false
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ import capitalize from "lodash.capitalize";
|
|||||||
import {MdDelete} from "react-icons/md";
|
import {MdDelete} from "react-icons/md";
|
||||||
import { type WithTranslation, withTranslation } from "react-i18next";
|
import { type WithTranslation, withTranslation } from "react-i18next";
|
||||||
|
|
||||||
import InputString from "./InputString";
|
import { InputString } from "./InputString";
|
||||||
import InputNumber from "./InputNumber";
|
import { InputNumber } from "./InputNumber";
|
||||||
import InputButton from "./InputButton";
|
import { InputButton } from "./InputButton";
|
||||||
import FieldDocLabel from "./FieldDocLabel";
|
import { FieldDocLabel } from "./FieldDocLabel";
|
||||||
import InputEnum from "./InputEnum";
|
import { InputEnum } from "./InputEnum";
|
||||||
import InputUrl from "./InputUrl";
|
import { InputUrl } from "./InputUrl";
|
||||||
import InputColor from "./InputColor";
|
import { InputColor } from "./InputColor";
|
||||||
|
|
||||||
|
|
||||||
export type InputDynamicArrayProps = {
|
export type InputDynamicArrayProps = {
|
||||||
@@ -141,9 +141,7 @@ class InputDynamicArrayInternal extends React.Component<InputDynamicArrayInterna
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const InputDynamicArray = withTranslation()(InputDynamicArrayInternal);
|
export const InputDynamicArray = withTranslation()(InputDynamicArrayInternal);
|
||||||
export default InputDynamicArray;
|
|
||||||
|
|
||||||
type DeleteValueInputButtonProps = {
|
type DeleteValueInputButtonProps = {
|
||||||
onClick?(...args: unknown[]): unknown
|
onClick?(...args: unknown[]): unknown
|
||||||
} & WithTranslation;
|
} & WithTranslation;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import InputSelect from "./InputSelect";
|
import { InputSelect } from "./InputSelect";
|
||||||
import InputMultiInput from "./InputMultiInput";
|
import { InputMultiInput } from "./InputMultiInput";
|
||||||
|
|
||||||
|
|
||||||
function optionsLabelLength(options: any[]) {
|
function optionsLabelLength(options: any[]) {
|
||||||
@@ -25,7 +25,7 @@ export type InputEnumProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export default class InputEnum extends React.Component<InputEnumProps> {
|
export class InputEnum extends React.Component<InputEnumProps> {
|
||||||
render() {
|
render() {
|
||||||
const {options, value, onChange, name, label} = this.props;
|
const {options, value, onChange, name, label} = this.props;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import InputAutocomplete from "./InputAutocomplete";
|
import { InputAutocomplete } from "./InputAutocomplete";
|
||||||
|
|
||||||
export type InputFontProps = {
|
export type InputFontProps = {
|
||||||
name: string
|
name: string
|
||||||
@@ -11,7 +11,7 @@ export type InputFontProps = {
|
|||||||
"aria-label"?: string
|
"aria-label"?: string
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class InputFont extends React.Component<InputFontProps> {
|
export class InputFont extends React.Component<InputFontProps> {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
fonts: []
|
fonts: []
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -135,5 +135,4 @@ class InputJsonInternal extends React.Component<InputJsonInternalProps, InputJso
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const InputJson = withTranslation()(InputJsonInternal);
|
export const InputJson = withTranslation()(InputJsonInternal);
|
||||||
export default InputJson;
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export type InputMultiInputProps = {
|
|||||||
"aria-label"?: string
|
"aria-label"?: string
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class InputMultiInput extends React.Component<InputMultiInputProps> {
|
export class InputMultiInput extends React.Component<InputMultiInputProps> {
|
||||||
render() {
|
render() {
|
||||||
let options = this.props.options;
|
let options = this.props.options;
|
||||||
if(options.length > 0 && !Array.isArray(options[0])) {
|
if(options.length > 0 && !Array.isArray(options[0])) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { type BaseSyntheticEvent } from "react";
|
import React, { type BaseSyntheticEvent } from "react";
|
||||||
import generateUniqueId from "../libs/document-uid";
|
import { generateUniqueId } from "../libs/document-uid";
|
||||||
|
|
||||||
export type InputNumberProps = {
|
export type InputNumberProps = {
|
||||||
value?: number
|
value?: number
|
||||||
@@ -25,7 +25,7 @@ type InputNumberState = {
|
|||||||
dirtyValue?: number | string | undefined
|
dirtyValue?: number | string | undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class InputNumber extends React.Component<InputNumberProps, InputNumberState> {
|
export class InputNumber extends React.Component<InputNumberProps, InputNumberState> {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
rangeStep: 1
|
rangeStep: 1
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export type InputSelectProps = {
|
|||||||
"aria-label"?: string
|
"aria-label"?: string
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class InputSelect extends React.Component<InputSelectProps> {
|
export class InputSelect extends React.Component<InputSelectProps> {
|
||||||
render() {
|
render() {
|
||||||
let options = this.props.options;
|
let options = this.props.options;
|
||||||
if(options.length > 0 && !Array.isArray(options[0])) {
|
if(options.length > 0 && !Array.isArray(options[0])) {
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import React, { type ReactElement } from "react";
|
import React, { type ReactElement } from "react";
|
||||||
|
|
||||||
import InputColor, { type InputColorProps } from "./InputColor";
|
import { InputColor, type InputColorProps } from "./InputColor";
|
||||||
import InputNumber, { type InputNumberProps } from "./InputNumber";
|
import { InputNumber, type InputNumberProps } from "./InputNumber";
|
||||||
import InputCheckbox, { type InputCheckboxProps } from "./InputCheckbox";
|
import { InputCheckbox, type InputCheckboxProps } from "./InputCheckbox";
|
||||||
import InputString, { type InputStringProps } from "./InputString";
|
import { InputString, type InputStringProps } from "./InputString";
|
||||||
import InputArray, { type InputArrayProps } from "./InputArray";
|
import { InputArray, type InputArrayProps } from "./InputArray";
|
||||||
import InputDynamicArray, { type InputDynamicArrayProps } from "./InputDynamicArray";
|
import { InputDynamicArray, type InputDynamicArrayProps } from "./InputDynamicArray";
|
||||||
import InputFont, { type InputFontProps } from "./InputFont";
|
import { InputFont, type InputFontProps } from "./InputFont";
|
||||||
import InputAutocomplete, { type InputAutocompleteProps } from "./InputAutocomplete";
|
import { InputAutocomplete, type InputAutocompleteProps } from "./InputAutocomplete";
|
||||||
import InputEnum, { type InputEnumProps } from "./InputEnum";
|
import { InputEnum, type InputEnumProps } from "./InputEnum";
|
||||||
import capitalize from "lodash.capitalize";
|
import capitalize from "lodash.capitalize";
|
||||||
|
|
||||||
const iconProperties = ["background-pattern", "fill-pattern", "line-pattern", "fill-extrusion-pattern", "icon-image"];
|
const iconProperties = ["background-pattern", "fill-pattern", "line-pattern", "fill-extrusion-pattern", "icon-image"];
|
||||||
@@ -38,7 +38,7 @@ export type InputSpecProps = {
|
|||||||
/** Display any field from the Maplibre GL style spec and
|
/** Display any field from the Maplibre GL style spec and
|
||||||
* choose the correct field component based on the @{fieldSpec}
|
* choose the correct field component based on the @{fieldSpec}
|
||||||
* to display @{value}. */
|
* to display @{value}. */
|
||||||
export default class InputSpec extends React.Component<InputSpecProps> {
|
export class InputSpec extends React.Component<InputSpecProps> {
|
||||||
|
|
||||||
childNodes() {
|
childNodes() {
|
||||||
const commonProps = {
|
const commonProps = {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ type InputStringState = {
|
|||||||
value?: string
|
value?: string
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class InputString extends React.Component<InputStringProps, InputStringState> {
|
export class InputString extends React.Component<InputStringProps, InputStringState> {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
onInput: () => {},
|
onInput: () => {},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { type JSX } from "react";
|
import React, { type JSX } from "react";
|
||||||
import InputString from "./InputString";
|
import { InputString } from "./InputString";
|
||||||
import SmallError from "./SmallError";
|
import { SmallError } from "./SmallError";
|
||||||
import { Trans, type WithTranslation, withTranslation } from "react-i18next";
|
import { Trans, type WithTranslation, withTranslation } from "react-i18next";
|
||||||
import { type TFunction } from "i18next";
|
import { type TFunction } from "i18next";
|
||||||
import { ErrorType, validate } from "../libs/urlopen";
|
import { ErrorType, validate } from "../libs/urlopen";
|
||||||
@@ -91,5 +91,4 @@ class InputUrlInternal extends React.Component<InputUrlInternalProps, InputUrlSt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const InputUrl = withTranslation()(InputUrlInternal);
|
export const InputUrl = withTranslation()(InputUrlInternal);
|
||||||
export default InputUrl;
|
|
||||||
|
|||||||
@@ -6,17 +6,17 @@ import { IconContext } from "react-icons";
|
|||||||
import { type BackgroundLayerSpecification, type LayerSpecification, type SourceSpecification } from "maplibre-gl";
|
import { type BackgroundLayerSpecification, type LayerSpecification, type SourceSpecification } from "maplibre-gl";
|
||||||
import { v8 } from "@maplibre/maplibre-gl-style-spec";
|
import { v8 } from "@maplibre/maplibre-gl-style-spec";
|
||||||
|
|
||||||
import FieldJson from "./FieldJson";
|
import { FieldJson } from "./FieldJson";
|
||||||
import FilterEditor from "./FilterEditor";
|
import { FilterEditor } from "./FilterEditor";
|
||||||
import PropertyGroup from "./PropertyGroup";
|
import { PropertyGroup } from "./PropertyGroup";
|
||||||
import LayerEditorGroup from "./LayerEditorGroup";
|
import { LayerEditorGroup } from "./LayerEditorGroup";
|
||||||
import FieldType from "./FieldType";
|
import { FieldType } from "./FieldType";
|
||||||
import FieldId from "./FieldId";
|
import { FieldId } from "./FieldId";
|
||||||
import FieldMinZoom from "./FieldMinZoom";
|
import { FieldMinZoom } from "./FieldMinZoom";
|
||||||
import FieldMaxZoom from "./FieldMaxZoom";
|
import { FieldMaxZoom } from "./FieldMaxZoom";
|
||||||
import FieldComment from "./FieldComment";
|
import { FieldComment } from "./FieldComment";
|
||||||
import FieldSource from "./FieldSource";
|
import { FieldSource } from "./FieldSource";
|
||||||
import FieldSourceLayer from "./FieldSourceLayer";
|
import { FieldSourceLayer } from "./FieldSourceLayer";
|
||||||
import { changeType, changeProperty } from "../libs/layer";
|
import { changeType, changeProperty } from "../libs/layer";
|
||||||
import { formatLayerId } from "../libs/format";
|
import { formatLayerId } from "../libs/format";
|
||||||
import { type WithTranslation, withTranslation } from "react-i18next";
|
import { type WithTranslation, withTranslation } from "react-i18next";
|
||||||
@@ -74,20 +74,20 @@ function getLayoutForType(type: LayerSpecification["type"], t: TFunction): Maput
|
|||||||
return getLayoutForSymbolType(t);
|
return getLayoutForSymbolType(t);
|
||||||
}
|
}
|
||||||
const groups: MaputnikLayoutGroup[] = [];
|
const groups: MaputnikLayoutGroup[] = [];
|
||||||
if (Object.keys(v8["paint_" + type]).length > 0) {
|
if (Object.keys(v8["paint_" + type as keyof typeof v8]).length > 0) {
|
||||||
groups.push({
|
groups.push({
|
||||||
title: t("Paint properties"),
|
title: t("Paint properties"),
|
||||||
id: "Paint_properties",
|
id: "Paint_properties",
|
||||||
type: "properties",
|
type: "properties",
|
||||||
fields: Object.keys(v8["paint_" + type]),
|
fields: Object.keys(v8["paint_" + type as keyof typeof v8]),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (Object.keys(v8["layout_" + type]).length > 0) {
|
if (Object.keys(v8["layout_" + type as keyof typeof v8]).length > 0) {
|
||||||
groups.push({
|
groups.push({
|
||||||
title: t("Layout properties"),
|
title: t("Layout properties"),
|
||||||
id: "Layout_properties",
|
id: "Layout_properties",
|
||||||
type: "properties",
|
type: "properties",
|
||||||
fields: Object.keys(v8["layout_" + type])
|
fields: Object.keys(v8["layout_" + type as keyof typeof v8])
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return groups;
|
return groups;
|
||||||
@@ -230,6 +230,7 @@ class LayerEditorInternal extends React.Component<LayerEditorInternalProps, Laye
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
{this.props.layer.type !== "background" && <FieldSource
|
{this.props.layer.type !== "background" && <FieldSource
|
||||||
|
wdKey="layer-editor.layer-source"
|
||||||
error={errorData.source}
|
error={errorData.source}
|
||||||
sourceIds={Object.keys(this.props.sources!)}
|
sourceIds={Object.keys(this.props.sources!)}
|
||||||
value={this.props.layer.source}
|
value={this.props.layer.source}
|
||||||
@@ -419,5 +420,4 @@ class LayerEditorInternal extends React.Component<LayerEditorInternalProps, Laye
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const LayerEditor = withTranslation()(LayerEditorInternal);
|
export const LayerEditor = withTranslation()(LayerEditorInternal);
|
||||||
export default LayerEditor;
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ type LayerEditorGroupProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export default class LayerEditorGroup extends React.Component<LayerEditorGroupProps> {
|
export class LayerEditorGroup extends React.Component<LayerEditorGroupProps> {
|
||||||
render() {
|
render() {
|
||||||
return <AccordionItem uuid={this.props.id}>
|
return <AccordionItem uuid={this.props.id}>
|
||||||
<AccordionItemHeading className="maputnik-layer-editor-group"
|
<AccordionItemHeading className="maputnik-layer-editor-group"
|
||||||
|
|||||||
@@ -14,12 +14,12 @@ import {
|
|||||||
verticalListSortingStrategy,
|
verticalListSortingStrategy,
|
||||||
} from "@dnd-kit/sortable";
|
} from "@dnd-kit/sortable";
|
||||||
|
|
||||||
import LayerListGroup from "./LayerListGroup";
|
import { LayerListGroup } from "./LayerListGroup";
|
||||||
import LayerListItem from "./LayerListItem";
|
import { LayerListItem } from "./LayerListItem";
|
||||||
import ModalAdd from "./modals/ModalAdd";
|
import { ModalAdd } from "./modals/ModalAdd";
|
||||||
|
|
||||||
import type {LayerSpecification, SourceSpecification} from "maplibre-gl";
|
import type {LayerSpecification, SourceSpecification} from "maplibre-gl";
|
||||||
import generateUniqueId from "../libs/document-uid";
|
import { generateUniqueId } from "../libs/document-uid";
|
||||||
import { findClosestCommonPrefix, layerPrefix } from "../libs/layer";
|
import { findClosestCommonPrefix, layerPrefix } from "../libs/layer";
|
||||||
import { type WithTranslation, withTranslation } from "react-i18next";
|
import { type WithTranslation, withTranslation } from "react-i18next";
|
||||||
import { type MappedError, type OnMoveLayerCallback } from "../libs/definitions";
|
import { type MappedError, type OnMoveLayerCallback } from "../libs/definitions";
|
||||||
@@ -336,7 +336,7 @@ type LayerListProps = LayerListContainerProps & {
|
|||||||
onMoveLayer: OnMoveLayerCallback
|
onMoveLayer: OnMoveLayerCallback
|
||||||
};
|
};
|
||||||
|
|
||||||
const LayerList: React.FC<LayerListProps> = (props) => {
|
export const LayerList: React.FC<LayerListProps> = (props) => {
|
||||||
const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 5 } }));
|
const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 5 } }));
|
||||||
|
|
||||||
const handleDragEnd = (event: DragEndEvent) => {
|
const handleDragEnd = (event: DragEndEvent) => {
|
||||||
@@ -361,5 +361,3 @@ const LayerList: React.FC<LayerListProps> = (props) => {
|
|||||||
</DndContext>
|
</DndContext>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default LayerList;
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Collapser from "./Collapser";
|
import { Collapser } from "./Collapser";
|
||||||
|
|
||||||
type LayerListGroupProps = {
|
type LayerListGroupProps = {
|
||||||
title: string
|
title: string
|
||||||
@@ -9,7 +9,7 @@ type LayerListGroupProps = {
|
|||||||
"aria-controls"?: string
|
"aria-controls"?: string
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class LayerListGroup extends React.Component<LayerListGroupProps> {
|
export class LayerListGroup extends React.Component<LayerListGroupProps> {
|
||||||
render() {
|
render() {
|
||||||
return <li className="maputnik-layer-list-group">
|
return <li className="maputnik-layer-list-group">
|
||||||
<div className="maputnik-layer-list-group-header"
|
<div className="maputnik-layer-list-group-header"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { IconContext } from "react-icons";
|
|||||||
import { useSortable } from "@dnd-kit/sortable";
|
import { useSortable } from "@dnd-kit/sortable";
|
||||||
import { CSS } from "@dnd-kit/utilities";
|
import { CSS } from "@dnd-kit/utilities";
|
||||||
|
|
||||||
import IconLayer from "./IconLayer";
|
import { IconLayer } from "./IconLayer";
|
||||||
import type { VisibilitySpecification } from "maplibre-gl";
|
import type { VisibilitySpecification } from "maplibre-gl";
|
||||||
|
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@ type LayerListItemProps = {
|
|||||||
onLayerVisibilityToggle?(...args: unknown[]): unknown
|
onLayerVisibilityToggle?(...args: unknown[]): unknown
|
||||||
};
|
};
|
||||||
|
|
||||||
const LayerListItem = React.forwardRef<HTMLLIElement, LayerListItemProps>((props, ref) => {
|
export const LayerListItem = React.forwardRef<HTMLLIElement, LayerListItemProps>((props, ref) => {
|
||||||
const {
|
const {
|
||||||
isSelected = false,
|
isSelected = false,
|
||||||
visibility = "visible",
|
visibility = "visible",
|
||||||
@@ -162,5 +162,3 @@ const LayerListItem = React.forwardRef<HTMLLIElement, LayerListItemProps>((props
|
|||||||
</li>
|
</li>
|
||||||
</IconContext.Provider>;
|
</IconContext.Provider>;
|
||||||
});
|
});
|
||||||
|
|
||||||
export default LayerListItem;
|
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ import {createRoot} from "react-dom/client";
|
|||||||
import MapLibreGl, {type LayerSpecification, type LngLat, type Map, type MapOptions, type SourceSpecification, type StyleSpecification} from "maplibre-gl";
|
import MapLibreGl, {type LayerSpecification, type LngLat, type Map, type MapOptions, type SourceSpecification, type StyleSpecification} from "maplibre-gl";
|
||||||
import MaplibreInspect from "@maplibre/maplibre-gl-inspect";
|
import MaplibreInspect from "@maplibre/maplibre-gl-inspect";
|
||||||
import colors from "@maplibre/maplibre-gl-inspect/lib/colors";
|
import colors from "@maplibre/maplibre-gl-inspect/lib/colors";
|
||||||
import MapMaplibreGlLayerPopup from "./MapMaplibreGlLayerPopup";
|
import { FeatureLayerPopup as MapMaplibreGlLayerPopup } from "./MapMaplibreGlLayerPopup";
|
||||||
import MapMaplibreGlFeaturePropertyPopup, { type InspectFeature } from "./MapMaplibreGlFeaturePropertyPopup";
|
import { FeaturePropertyPopup as MapMaplibreGlFeaturePropertyPopup, type InspectFeature } from "./MapMaplibreGlFeaturePropertyPopup";
|
||||||
import Color from "color";
|
import Color from "color";
|
||||||
import ZoomControl from "../libs/zoomcontrol";
|
import { ZoomControl } from "../libs/zoomcontrol";
|
||||||
import { type HighlightedLayer, colorHighlightedLayer } from "../libs/highlight";
|
import { type HighlightedLayer, colorHighlightedLayer } from "../libs/highlight";
|
||||||
import "maplibre-gl/dist/maplibre-gl.css";
|
import "maplibre-gl/dist/maplibre-gl.css";
|
||||||
import "../maplibregl.css";
|
import "../maplibregl.css";
|
||||||
@@ -322,5 +322,4 @@ class MapMaplibreGlInternal extends React.Component<MapMaplibreGlInternalProps,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const MapMaplibreGl = withTranslation()(MapMaplibreGlInternal);
|
export const MapMaplibreGl = withTranslation()(MapMaplibreGlInternal);
|
||||||
export default MapMaplibreGl;
|
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ type FeaturePropertyPopupProps = {
|
|||||||
features: InspectFeature[]
|
features: InspectFeature[]
|
||||||
};
|
};
|
||||||
|
|
||||||
class FeaturePropertyPopup extends React.Component<FeaturePropertyPopupProps> {
|
export class FeaturePropertyPopup extends React.Component<FeaturePropertyPopupProps> {
|
||||||
render() {
|
render() {
|
||||||
const features = removeDuplicatedFeatures(this.props.features);
|
const features = removeDuplicatedFeatures(this.props.features);
|
||||||
return <div className="maputnik-feature-property-popup" dir="ltr" data-wd-key="feature-property-popup">
|
return <div className="maputnik-feature-property-popup" dir="ltr" data-wd-key="feature-property-popup">
|
||||||
@@ -75,6 +75,3 @@ class FeaturePropertyPopup extends React.Component<FeaturePropertyPopupProps> {
|
|||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export default FeaturePropertyPopup;
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import IconLayer from "./IconLayer";
|
import { IconLayer } from "./IconLayer";
|
||||||
import type {InspectFeature} from "./MapMaplibreGlFeaturePropertyPopup";
|
import type {InspectFeature} from "./MapMaplibreGlFeaturePropertyPopup";
|
||||||
|
|
||||||
function groupFeaturesBySourceLayer(features: InspectFeature[]) {
|
function groupFeaturesBySourceLayer(features: InspectFeature[]) {
|
||||||
@@ -32,7 +32,7 @@ type FeatureLayerPopupProps = {
|
|||||||
zoom?: number
|
zoom?: number
|
||||||
};
|
};
|
||||||
|
|
||||||
class FeatureLayerPopup extends React.Component<FeatureLayerPopupProps> {
|
export class FeatureLayerPopup extends React.Component<FeatureLayerPopupProps> {
|
||||||
_getFeatureColor(feature: InspectFeature, _zoom?: number) {
|
_getFeatureColor(feature: InspectFeature, _zoom?: number) {
|
||||||
// Guard because openlayers won't have this
|
// Guard because openlayers won't have this
|
||||||
if (!feature.layer.paint) {
|
if (!feature.layer.paint) {
|
||||||
@@ -109,6 +109,3 @@ class FeatureLayerPopup extends React.Component<FeatureLayerPopupProps> {
|
|||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export default FeatureLayerPopup;
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import React from "react";
|
|||||||
import {throttle} from "lodash";
|
import {throttle} from "lodash";
|
||||||
import { type WithTranslation, withTranslation } from "react-i18next";
|
import { type WithTranslation, withTranslation } from "react-i18next";
|
||||||
|
|
||||||
import MapMaplibreGlLayerPopup from "./MapMaplibreGlLayerPopup";
|
import { FeatureLayerPopup as MapMaplibreGlLayerPopup } from "./MapMaplibreGlLayerPopup";
|
||||||
|
|
||||||
import "ol/ol.css";
|
import "ol/ol.css";
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
@@ -204,5 +204,4 @@ class MapOpenLayersInternal extends React.Component<MapOpenLayersInternalProps,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const MapOpenLayers = withTranslation()(MapOpenLayersInternal);
|
export const MapOpenLayers = withTranslation()(MapOpenLayersInternal);
|
||||||
export default MapOpenLayers;
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import FieldFunction from "./FieldFunction";
|
import { FieldFunction } from "./FieldFunction";
|
||||||
import type {LayerSpecification} from "maplibre-gl";
|
import type {LayerSpecification} from "maplibre-gl";
|
||||||
import { type MappedLayerErrors } from "../libs/definitions";
|
import { type MappedLayerErrors } from "../libs/definitions";
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ type PropertyGroupProps = {
|
|||||||
errors?: MappedLayerErrors
|
errors?: MappedLayerErrors
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class PropertyGroup extends React.Component<PropertyGroupProps> {
|
export class PropertyGroup extends React.Component<PropertyGroupProps> {
|
||||||
onPropertyChange = (property: string, newValue: any) => {
|
onPropertyChange = (property: string, newValue: any) => {
|
||||||
const group = getGroupName(this.props.spec, this.props.layer.type, property);
|
const group = getGroupName(this.props.spec, this.props.layer.type, property);
|
||||||
this.props.onChange(group ,property, newValue);
|
this.props.onChange(group ,property, newValue);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ type ScrollContainerProps = {
|
|||||||
children?: React.ReactNode
|
children?: React.ReactNode
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class ScrollContainer extends React.Component<ScrollContainerProps> {
|
export class ScrollContainer extends React.Component<ScrollContainerProps> {
|
||||||
render() {
|
render() {
|
||||||
return <div className="maputnik-scroll-container">
|
return <div className="maputnik-scroll-container">
|
||||||
{this.props.children}
|
{this.props.children}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import {otherFilterOps} from "../libs/filterops";
|
import {otherFilterOps} from "../libs/filterops";
|
||||||
import InputString from "./InputString";
|
import { InputString } from "./InputString";
|
||||||
import InputAutocomplete from "./InputAutocomplete";
|
import { InputAutocomplete } from "./InputAutocomplete";
|
||||||
import InputSelect from "./InputSelect";
|
import { InputSelect } from "./InputSelect";
|
||||||
|
|
||||||
function tryParseInt(v: string | number) {
|
function tryParseInt(v: string | number) {
|
||||||
if (v === "") return v;
|
if (v === "") return v;
|
||||||
@@ -40,7 +40,7 @@ type SingleFilterEditorProps = {
|
|||||||
properties?: {[key: string]: string}
|
properties?: {[key: string]: string}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class SingleFilterEditor extends React.Component<SingleFilterEditorProps> {
|
export class SingleFilterEditor extends React.Component<SingleFilterEditorProps> {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
properties: {},
|
properties: {},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,5 +18,4 @@ class SmallErrorInternal extends React.Component<SmallErrorInternalProps> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const SmallError = withTranslation()(SmallErrorInternal);
|
export const SmallError = withTranslation()(SmallErrorInternal);
|
||||||
export default SmallError;
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import FieldSpec, {type FieldSpecProps} from "./FieldSpec";
|
import { FieldSpec, type FieldSpecProps } from "./FieldSpec";
|
||||||
import FunctionButtons from "./_FunctionButtons";
|
import { FunctionInputButtons as FunctionButtons } from "./FunctionButtons";
|
||||||
|
|
||||||
import labelFromFieldName from "../libs/label-from-field-name";
|
import { labelFromFieldName } from "../libs/label-from-field-name";
|
||||||
|
|
||||||
|
|
||||||
type SpecPropertyProps = FieldSpecProps & {
|
type SpecPropertyProps = FieldSpecProps & {
|
||||||
@@ -19,7 +19,7 @@ type SpecPropertyProps = FieldSpecProps & {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export default class SpecProperty extends React.Component<SpecPropertyProps> {
|
export class SpecProperty extends React.Component<SpecPropertyProps> {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
errors: {},
|
errors: {},
|
||||||
};
|
};
|
||||||
@@ -4,17 +4,17 @@ import { TbMathFunction } from "react-icons/tb";
|
|||||||
import latest from "@maplibre/maplibre-gl-style-spec/dist/latest.json";
|
import latest from "@maplibre/maplibre-gl-style-spec/dist/latest.json";
|
||||||
import { type WithTranslation, withTranslation } from "react-i18next";
|
import { type WithTranslation, withTranslation } from "react-i18next";
|
||||||
|
|
||||||
import InputButton from "./InputButton";
|
import { InputButton } from "./InputButton";
|
||||||
import InputSpec from "./InputSpec";
|
import { InputSpec } from "./InputSpec";
|
||||||
import InputNumber from "./InputNumber";
|
import { InputNumber } from "./InputNumber";
|
||||||
import InputSelect from "./InputSelect";
|
import { InputSelect } from "./InputSelect";
|
||||||
import Block from "./Block";
|
import { Block } from "./Block";
|
||||||
|
|
||||||
import DeleteStopButton from "./_DeleteStopButton";
|
import { DeleteStopButton } from "./DeleteStopButton";
|
||||||
import labelFromFieldName from "../libs/label-from-field-name";
|
import { labelFromFieldName } from "../libs/label-from-field-name";
|
||||||
|
|
||||||
import docUid from "../libs/document-uid";
|
import { generateUniqueId as docUid } from "../libs/document-uid";
|
||||||
import sortNumerically from "../libs/sort-numerically";
|
import { sortNumerically } from "../libs/sort-numerically";
|
||||||
import { type MappedLayerErrors } from "../libs/definitions";
|
import { type MappedLayerErrors } from "../libs/definitions";
|
||||||
|
|
||||||
|
|
||||||
@@ -194,6 +194,7 @@ class ZoomPropertyInternal extends React.Component<ZoomPropertyInternalProps, Zo
|
|||||||
<div className="maputnik-data-fieldset-inner">
|
<div className="maputnik-data-fieldset-inner">
|
||||||
<Block
|
<Block
|
||||||
label={t("Function")}
|
label={t("Function")}
|
||||||
|
data-wd-key="function-type"
|
||||||
>
|
>
|
||||||
<div className="maputnik-data-spec-property-input">
|
<div className="maputnik-data-spec-property-input">
|
||||||
<InputSelect
|
<InputSelect
|
||||||
@@ -206,6 +207,7 @@ class ZoomPropertyInternal extends React.Component<ZoomPropertyInternalProps, Zo
|
|||||||
</Block>
|
</Block>
|
||||||
<Block
|
<Block
|
||||||
label={t("Base")}
|
label={t("Base")}
|
||||||
|
data-wd-key="function-base"
|
||||||
>
|
>
|
||||||
<div className="maputnik-data-spec-property-input">
|
<div className="maputnik-data-spec-property-input">
|
||||||
<InputSpec
|
<InputSpec
|
||||||
@@ -240,6 +242,7 @@ class ZoomPropertyInternal extends React.Component<ZoomPropertyInternalProps, Zo
|
|||||||
</InputButton>
|
</InputButton>
|
||||||
<InputButton
|
<InputButton
|
||||||
className="maputnik-add-stop"
|
className="maputnik-add-stop"
|
||||||
|
data-wd-key="convert-to-expression"
|
||||||
onClick={this.props.onExpressionClick?.bind(this)}
|
onClick={this.props.onExpressionClick?.bind(this)}
|
||||||
>
|
>
|
||||||
<TbMathFunction style={{ verticalAlign: "text-bottom" }} />
|
<TbMathFunction style={{ verticalAlign: "text-bottom" }} />
|
||||||
@@ -264,5 +267,4 @@ class ZoomPropertyInternal extends React.Component<ZoomPropertyInternalProps, Zo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ZoomProperty = withTranslation()(ZoomPropertyInternal);
|
export const ZoomProperty = withTranslation()(ZoomPropertyInternal);
|
||||||
export default ZoomProperty;
|
|
||||||
@@ -67,5 +67,4 @@ class ModalInternal extends React.Component<ModalInternalProps> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const Modal = withTranslation()(ModalInternal);
|
export const Modal = withTranslation()(ModalInternal);
|
||||||
export default Modal;
|
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ import React from "react";
|
|||||||
import { type WithTranslation, withTranslation } from "react-i18next";
|
import { type WithTranslation, withTranslation } from "react-i18next";
|
||||||
import type {LayerSpecification, SourceSpecification} from "maplibre-gl";
|
import type {LayerSpecification, SourceSpecification} from "maplibre-gl";
|
||||||
|
|
||||||
import InputButton from "../InputButton";
|
import { InputButton } from "../InputButton";
|
||||||
import Modal from "./Modal";
|
import { Modal } from "./Modal";
|
||||||
import FieldType from "../FieldType";
|
import { FieldType } from "../FieldType";
|
||||||
import FieldId from "../FieldId";
|
import { FieldId } from "../FieldId";
|
||||||
import FieldSource from "../FieldSource";
|
import { FieldSource } from "../FieldSource";
|
||||||
import FieldSourceLayer from "../FieldSourceLayer";
|
import { FieldSourceLayer } from "../FieldSourceLayer";
|
||||||
import { NON_SOURCE_LAYERS } from "../../libs/non-source-layers";
|
import { NON_SOURCE_LAYERS } from "../../libs/non-source-layers";
|
||||||
|
|
||||||
type ModalAddInternalProps = {
|
type ModalAddInternalProps = {
|
||||||
@@ -192,5 +192,4 @@ class ModalAddInternal extends React.Component<ModalAddInternalProps, ModalAddSt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ModalAdd = withTranslation()(ModalAddInternal);
|
export const ModalAdd = withTranslation()(ModalAddInternal);
|
||||||
export default ModalAdd;
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Trans, type WithTranslation, withTranslation } from "react-i18next";
|
import { Trans, type WithTranslation, withTranslation } from "react-i18next";
|
||||||
|
|
||||||
import Modal from "./Modal";
|
import { Modal } from "./Modal";
|
||||||
|
|
||||||
|
|
||||||
type ModalDebugInternalProps = {
|
type ModalDebugInternalProps = {
|
||||||
@@ -79,5 +79,4 @@ class ModalDebugInternal extends React.Component<ModalDebugInternalProps> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ModalDebug = withTranslation()(ModalDebugInternal);
|
export const ModalDebug = withTranslation()(ModalDebugInternal);
|
||||||
export default ModalDebug;
|
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ import {format} from "@maplibre/maplibre-gl-style-spec";
|
|||||||
import {MdMap, MdSave} from "react-icons/md";
|
import {MdMap, MdSave} from "react-icons/md";
|
||||||
import {type WithTranslation, withTranslation} from "react-i18next";
|
import {type WithTranslation, withTranslation} from "react-i18next";
|
||||||
|
|
||||||
import FieldString from "../FieldString";
|
import { FieldString } from "../FieldString";
|
||||||
import InputButton from "../InputButton";
|
import { InputButton } from "../InputButton";
|
||||||
import Modal from "./Modal";
|
import { Modal } from "./Modal";
|
||||||
import style from "../../libs/style";
|
import { replaceAccessTokens, stripAccessTokens } from "../../libs/style";
|
||||||
import fieldSpecAdditional from "../../libs/field-spec-additional";
|
import { spec as fieldSpecAdditional } from "../../libs/field-spec-additional";
|
||||||
import type {OnStyleChangedCallback, StyleSpecificationWithId} from "../../libs/definitions";
|
import type {OnStyleChangedCallback, StyleSpecificationWithId} from "../../libs/definitions";
|
||||||
|
|
||||||
|
|
||||||
@@ -32,8 +32,8 @@ class ModalExportInternal extends React.Component<ModalExportInternalProps> {
|
|||||||
|
|
||||||
tokenizedStyle() {
|
tokenizedStyle() {
|
||||||
return format(
|
return format(
|
||||||
style.stripAccessTokens(
|
stripAccessTokens(
|
||||||
style.replaceAccessTokens(this.props.mapStyle)
|
replaceAccessTokens(this.props.mapStyle)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -217,5 +217,4 @@ class ModalExportInternal extends React.Component<ModalExportInternalProps> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ModalExport = withTranslation()(ModalExportInternal);
|
export const ModalExport = withTranslation()(ModalExportInternal);
|
||||||
export default ModalExport;
|
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ import { withTranslation, type WithTranslation } from "react-i18next";
|
|||||||
import { MdDelete } from "react-icons/md";
|
import { MdDelete } from "react-icons/md";
|
||||||
import latest from "@maplibre/maplibre-gl-style-spec/dist/latest.json";
|
import latest from "@maplibre/maplibre-gl-style-spec/dist/latest.json";
|
||||||
|
|
||||||
import Modal from "./Modal";
|
import { Modal } from "./Modal";
|
||||||
import FieldString from "../FieldString";
|
import { FieldString } from "../FieldString";
|
||||||
import InputButton from "../InputButton";
|
import { InputButton } from "../InputButton";
|
||||||
import { PiListPlusBold } from "react-icons/pi";
|
import { PiListPlusBold } from "react-icons/pi";
|
||||||
import { type StyleSpecificationWithId } from "../../libs/definitions";
|
import { type StyleSpecificationWithId } from "../../libs/definitions";
|
||||||
import { type SchemaSpecification } from "maplibre-gl";
|
import { type SchemaSpecification } from "maplibre-gl";
|
||||||
import Doc from "../Doc";
|
import { Doc } from "../Doc";
|
||||||
|
|
||||||
type ModalGlobalStateInternalProps = {
|
type ModalGlobalStateInternalProps = {
|
||||||
mapStyle: StyleSpecificationWithId;
|
mapStyle: StyleSpecificationWithId;
|
||||||
@@ -151,5 +151,4 @@ const ModalGlobalStateInternal: React.FC<ModalGlobalStateInternalProps> = (props
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const ModalGlobalState = withTranslation()(ModalGlobalStateInternal);
|
export const ModalGlobalState = withTranslation()(ModalGlobalStateInternal);
|
||||||
export default ModalGlobalState;
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { type WithTranslation, withTranslation } from "react-i18next";
|
import { type WithTranslation, withTranslation } from "react-i18next";
|
||||||
|
|
||||||
import InputButton from "../InputButton";
|
import { InputButton } from "../InputButton";
|
||||||
import Modal from "./Modal";
|
import { Modal } from "./Modal";
|
||||||
|
|
||||||
|
|
||||||
type ModalLoadingInternalProps = {
|
type ModalLoadingInternalProps = {
|
||||||
@@ -35,5 +35,4 @@ class ModalLoadingInternal extends React.Component<ModalLoadingInternalProps> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ModalLoading = withTranslation()(ModalLoadingInternal);
|
export const ModalLoading = withTranslation()(ModalLoadingInternal);
|
||||||
export default ModalLoading;
|
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ import { MdFileUpload } from "react-icons/md";
|
|||||||
import { MdAddCircleOutline } from "react-icons/md";
|
import { MdAddCircleOutline } from "react-icons/md";
|
||||||
import { Trans, type WithTranslation, withTranslation } from "react-i18next";
|
import { Trans, type WithTranslation, withTranslation } from "react-i18next";
|
||||||
|
|
||||||
import ModalLoading from "./ModalLoading";
|
import { ModalLoading } from "./ModalLoading";
|
||||||
import Modal from "./Modal";
|
import { Modal } from "./Modal";
|
||||||
import InputButton from "../InputButton";
|
import { InputButton } from "../InputButton";
|
||||||
import InputUrl from "../InputUrl";
|
import { InputUrl } from "../InputUrl";
|
||||||
|
|
||||||
import style from "../../libs/style";
|
import { ensureStyleValidity } from "../../libs/style";
|
||||||
import publicStyles from "../../config/styles.json";
|
import publicStyles from "../../config/styles.json";
|
||||||
|
|
||||||
type PublicStyleProps = {
|
type PublicStyleProps = {
|
||||||
@@ -109,7 +109,7 @@ class ModalOpenInternal extends React.Component<ModalOpenInternalProps, ModalOpe
|
|||||||
activeRequestUrl: null
|
activeRequestUrl: null
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapStyle = style.ensureStyleValidity(body);
|
const mapStyle = ensureStyleValidity(body);
|
||||||
console.log("Loaded style ", mapStyle.id);
|
console.log("Loaded style ", mapStyle.id);
|
||||||
this.props.onStyleOpen(mapStyle);
|
this.props.onStyleOpen(mapStyle);
|
||||||
this.onOpenToggle();
|
this.onOpenToggle();
|
||||||
@@ -165,7 +165,7 @@ class ModalOpenInternal extends React.Component<ModalOpenInternalProps, ModalOpe
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mapStyle = style.ensureStyleValidity(mapStyle);
|
mapStyle = ensureStyleValidity(mapStyle);
|
||||||
|
|
||||||
this.props.onStyleOpen(mapStyle, fileHandle);
|
this.props.onStyleOpen(mapStyle, fileHandle);
|
||||||
this.onOpenToggle();
|
this.onOpenToggle();
|
||||||
@@ -193,7 +193,7 @@ class ModalOpenInternal extends React.Component<ModalOpenInternalProps, ModalOpe
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mapStyle = style.ensureStyleValidity(mapStyle);
|
mapStyle = ensureStyleValidity(mapStyle);
|
||||||
this.props.onStyleOpen(mapStyle);
|
this.props.onStyleOpen(mapStyle);
|
||||||
this.onOpenToggle();
|
this.onOpenToggle();
|
||||||
};
|
};
|
||||||
@@ -364,5 +364,4 @@ class ModalOpenInternal extends React.Component<ModalOpenInternalProps, ModalOpe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ModalOpen = withTranslation()(ModalOpenInternal);
|
export const ModalOpen = withTranslation()(ModalOpenInternal);
|
||||||
export default ModalOpen;
|
|
||||||
|
|||||||
@@ -3,17 +3,17 @@ import latest from "@maplibre/maplibre-gl-style-spec/dist/latest.json";
|
|||||||
import type {LightSpecification, ProjectionSpecification, StyleSpecification, TerrainSpecification, TransitionSpecification} from "maplibre-gl";
|
import type {LightSpecification, ProjectionSpecification, StyleSpecification, TerrainSpecification, TransitionSpecification} from "maplibre-gl";
|
||||||
import { type WithTranslation, withTranslation } from "react-i18next";
|
import { type WithTranslation, withTranslation } from "react-i18next";
|
||||||
|
|
||||||
import FieldArray from "../FieldArray";
|
import { FieldArray } from "../FieldArray";
|
||||||
import FieldNumber from "../FieldNumber";
|
import { FieldNumber } from "../FieldNumber";
|
||||||
import FieldString from "../FieldString";
|
import { FieldString } from "../FieldString";
|
||||||
import FieldUrl from "../FieldUrl";
|
import { FieldUrl } from "../FieldUrl";
|
||||||
import FieldSelect from "../FieldSelect";
|
import { FieldSelect } from "../FieldSelect";
|
||||||
import FieldEnum from "../FieldEnum";
|
import { FieldEnum } from "../FieldEnum";
|
||||||
import FieldColor from "../FieldColor";
|
import { FieldColor } from "../FieldColor";
|
||||||
import Modal from "./Modal";
|
import { Modal } from "./Modal";
|
||||||
import FieldJson from "../FieldJson";
|
import { FieldJson } from "../FieldJson";
|
||||||
import Block from "../Block";
|
import { Block } from "../Block";
|
||||||
import fieldSpecAdditional from "../../libs/field-spec-additional";
|
import { spec as fieldSpecAdditional } from "../../libs/field-spec-additional";
|
||||||
import type {OnStyleChangedCallback, StyleSpecificationWithId} from "../../libs/definitions";
|
import type {OnStyleChangedCallback, StyleSpecificationWithId} from "../../libs/definitions";
|
||||||
|
|
||||||
type ModalSettingsInternalProps = {
|
type ModalSettingsInternalProps = {
|
||||||
@@ -206,6 +206,7 @@ class ModalSettingsInternal extends React.Component<ModalSettingsInternalProps>
|
|||||||
|
|
||||||
<FieldNumber
|
<FieldNumber
|
||||||
label={t("Zoom")}
|
label={t("Zoom")}
|
||||||
|
data-wd-key="modal:settings.zoom"
|
||||||
fieldSpec={latest.$root.zoom}
|
fieldSpec={latest.$root.zoom}
|
||||||
value={mapStyle.zoom}
|
value={mapStyle.zoom}
|
||||||
default={0}
|
default={0}
|
||||||
@@ -214,6 +215,7 @@ class ModalSettingsInternal extends React.Component<ModalSettingsInternalProps>
|
|||||||
|
|
||||||
<FieldNumber
|
<FieldNumber
|
||||||
label={t("Bearing")}
|
label={t("Bearing")}
|
||||||
|
data-wd-key="modal:settings.bearing"
|
||||||
fieldSpec={latest.$root.bearing}
|
fieldSpec={latest.$root.bearing}
|
||||||
value={mapStyle.bearing}
|
value={mapStyle.bearing}
|
||||||
default={latest.$root.bearing.default}
|
default={latest.$root.bearing.default}
|
||||||
@@ -222,6 +224,7 @@ class ModalSettingsInternal extends React.Component<ModalSettingsInternalProps>
|
|||||||
|
|
||||||
<FieldNumber
|
<FieldNumber
|
||||||
label={t("Pitch")}
|
label={t("Pitch")}
|
||||||
|
data-wd-key="modal:settings.pitch"
|
||||||
fieldSpec={latest.$root.pitch}
|
fieldSpec={latest.$root.pitch}
|
||||||
value={mapStyle.pitch}
|
value={mapStyle.pitch}
|
||||||
default={latest.$root.pitch.default}
|
default={latest.$root.pitch.default}
|
||||||
@@ -248,6 +251,7 @@ class ModalSettingsInternal extends React.Component<ModalSettingsInternalProps>
|
|||||||
|
|
||||||
<FieldNumber
|
<FieldNumber
|
||||||
label={t("Light intensity")}
|
label={t("Light intensity")}
|
||||||
|
data-wd-key="modal:settings.light-intensity"
|
||||||
fieldSpec={latest.light.intensity}
|
fieldSpec={latest.light.intensity}
|
||||||
value={light.intensity as number}
|
value={light.intensity as number}
|
||||||
default={latest.light.intensity.default}
|
default={latest.light.intensity.default}
|
||||||
@@ -274,6 +278,7 @@ class ModalSettingsInternal extends React.Component<ModalSettingsInternalProps>
|
|||||||
|
|
||||||
<FieldNumber
|
<FieldNumber
|
||||||
label={t("Terrain exaggeration")}
|
label={t("Terrain exaggeration")}
|
||||||
|
data-wd-key="modal:settings.terrain-exaggeration"
|
||||||
fieldSpec={latest.terrain.exaggeration}
|
fieldSpec={latest.terrain.exaggeration}
|
||||||
value={terrain.exaggeration}
|
value={terrain.exaggeration}
|
||||||
default={latest.terrain.exaggeration.default}
|
default={latest.terrain.exaggeration.default}
|
||||||
@@ -282,6 +287,7 @@ class ModalSettingsInternal extends React.Component<ModalSettingsInternalProps>
|
|||||||
|
|
||||||
<FieldNumber
|
<FieldNumber
|
||||||
label={t("Transition delay")}
|
label={t("Transition delay")}
|
||||||
|
data-wd-key="modal:settings.transition-delay"
|
||||||
fieldSpec={latest.transition.delay}
|
fieldSpec={latest.transition.delay}
|
||||||
value={transition.delay}
|
value={transition.delay}
|
||||||
default={latest.transition.delay.default}
|
default={latest.transition.delay.default}
|
||||||
@@ -290,6 +296,7 @@ class ModalSettingsInternal extends React.Component<ModalSettingsInternalProps>
|
|||||||
|
|
||||||
<FieldNumber
|
<FieldNumber
|
||||||
label={t("Transition duration")}
|
label={t("Transition duration")}
|
||||||
|
data-wd-key="modal:settings.transition-duration"
|
||||||
fieldSpec={latest.transition.duration}
|
fieldSpec={latest.transition.duration}
|
||||||
value={transition.duration}
|
value={transition.duration}
|
||||||
default={latest.transition.duration.default}
|
default={latest.transition.duration.default}
|
||||||
@@ -325,5 +332,4 @@ class ModalSettingsInternal extends React.Component<ModalSettingsInternalProps>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ModalSettings = withTranslation()(ModalSettingsInternal);
|
export const ModalSettings = withTranslation()(ModalSettingsInternal);
|
||||||
export default ModalSettings;
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Trans, type WithTranslation, withTranslation } from "react-i18next";
|
import { Trans, type WithTranslation, withTranslation } from "react-i18next";
|
||||||
|
|
||||||
import Modal from "./Modal";
|
import { Modal } from "./Modal";
|
||||||
|
|
||||||
|
|
||||||
type ModalShortcutsInternalProps = {
|
type ModalShortcutsInternalProps = {
|
||||||
@@ -134,5 +134,4 @@ class ModalShortcutsInternal extends React.Component<ModalShortcutsInternalProps
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ModalShortcuts = withTranslation()(ModalShortcutsInternal);
|
export const ModalShortcuts = withTranslation()(ModalShortcutsInternal);
|
||||||
export default ModalShortcuts;
|
|
||||||
|
|||||||
@@ -4,13 +4,13 @@ import latest from "@maplibre/maplibre-gl-style-spec/dist/latest.json";
|
|||||||
import type {GeoJSONSourceSpecification, RasterDEMSourceSpecification, RasterSourceSpecification, SourceSpecification, VectorSourceSpecification} from "maplibre-gl";
|
import type {GeoJSONSourceSpecification, RasterDEMSourceSpecification, RasterSourceSpecification, SourceSpecification, VectorSourceSpecification} from "maplibre-gl";
|
||||||
import { type WithTranslation, withTranslation } from "react-i18next";
|
import { type WithTranslation, withTranslation } from "react-i18next";
|
||||||
|
|
||||||
import Modal from "./Modal";
|
import { Modal } from "./Modal";
|
||||||
import InputButton from "../InputButton";
|
import { InputButton } from "../InputButton";
|
||||||
import FieldString from "../FieldString";
|
import { FieldString } from "../FieldString";
|
||||||
import FieldSelect from "../FieldSelect";
|
import { FieldSelect } from "../FieldSelect";
|
||||||
import ModalSourcesTypeEditor, { type EditorMode } from "./ModalSourcesTypeEditor";
|
import { ModalSourcesTypeEditor, type EditorMode } from "./ModalSourcesTypeEditor";
|
||||||
|
|
||||||
import style from "../../libs/style";
|
import { generateId } from "../../libs/style";
|
||||||
import { deleteSource, addSource, changeSource } from "../../libs/source";
|
import { deleteSource, addSource, changeSource } from "../../libs/source";
|
||||||
import publicSources from "../../config/tilesets.json";
|
import publicSources from "../../config/tilesets.json";
|
||||||
import { type OnStyleChangedCallback, type StyleSpecificationWithId } from "../../libs/definitions";
|
import { type OnStyleChangedCallback, type StyleSpecificationWithId } from "../../libs/definitions";
|
||||||
@@ -121,7 +121,7 @@ class AddSource extends React.Component<AddSourceProps, AddSourceState> {
|
|||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
mode: "tilejson_vector",
|
mode: "tilejson_vector",
|
||||||
sourceId: style.generateId(),
|
sourceId: generateId(),
|
||||||
source: this.defaultSource("tilejson_vector"),
|
source: this.defaultSource("tilejson_vector"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -343,5 +343,4 @@ class ModalSourcesInternal extends React.Component<ModalSourcesInternalProps> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ModalSources = withTranslation()(ModalSourcesInternal);
|
export const ModalSources = withTranslation()(ModalSourcesInternal);
|
||||||
export default ModalSources;
|
|
||||||
|
|||||||
@@ -3,14 +3,14 @@ import {latest} from "@maplibre/maplibre-gl-style-spec";
|
|||||||
import { type WithTranslation, withTranslation } from "react-i18next";
|
import { type WithTranslation, withTranslation } from "react-i18next";
|
||||||
import { type TFunction } from "i18next";
|
import { type TFunction } from "i18next";
|
||||||
|
|
||||||
import Block from "../Block";
|
import { Block } from "../Block";
|
||||||
import FieldUrl from "../FieldUrl";
|
import { FieldUrl } from "../FieldUrl";
|
||||||
import FieldNumber from "../FieldNumber";
|
import { FieldNumber } from "../FieldNumber";
|
||||||
import FieldSelect from "../FieldSelect";
|
import { FieldSelect } from "../FieldSelect";
|
||||||
import FieldDynamicArray from "../FieldDynamicArray";
|
import { FieldDynamicArray } from "../FieldDynamicArray";
|
||||||
import FieldArray from "../FieldArray";
|
import { FieldArray } from "../FieldArray";
|
||||||
import FieldJson from "../FieldJson";
|
import { FieldJson } from "../FieldJson";
|
||||||
import FieldCheckbox from "../FieldCheckbox";
|
import { FieldCheckbox } from "../FieldCheckbox";
|
||||||
|
|
||||||
|
|
||||||
export type EditorMode = "video" | "image" | "tilejson_vector" | "tile_raster" | "tilejson_raster" | "tilexyz_raster-dem" | "tilejson_raster-dem" | "pmtiles_vector" | "tile_vector" | "geojson_url" | "geojson_json" | null;
|
export type EditorMode = "video" | "image" | "tilejson_vector" | "tile_raster" | "tilejson_raster" | "tilexyz_raster-dem" | "tilejson_raster-dem" | "pmtiles_vector" | "tile_vector" | "geojson_url" | "geojson_json" | null;
|
||||||
@@ -375,5 +375,4 @@ class ModalSourcesTypeEditorInternal extends React.Component<ModalSourcesTypeEdi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ModalSourcesTypeEditor = withTranslation()(ModalSourcesTypeEditorInternal);
|
export const ModalSourcesTypeEditor = withTranslation()(ModalSourcesTypeEditorInternal);
|
||||||
export default ModalSourcesTypeEditor;
|
|
||||||
|
|||||||
+1
-1
@@ -42,4 +42,4 @@ i18n
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export default i18n;
|
export { i18n };
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ import { createRoot } from "react-dom/client";
|
|||||||
import "./favicon.ico";
|
import "./favicon.ico";
|
||||||
import "./styles/index.scss";
|
import "./styles/index.scss";
|
||||||
import "./i18n";
|
import "./i18n";
|
||||||
import App from "./components/App";
|
import { App } from "./components/App";
|
||||||
|
|
||||||
const root = createRoot(document.querySelector("#app"));
|
const root = createRoot(document.querySelector("#app"));
|
||||||
root.render(
|
root.render(
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user