Compare commits

...

16 Commits

Author SHA1 Message Date
Harel M f306d8e143 Fix lint 2024-02-07 09:15:14 +00:00
Harel M 6a27913114 Fix colum misalignemnt 2024-02-07 09:12:25 +00:00
HarelM 285dca8d2c Fix lint 2024-02-04 18:07:43 +02:00
HarelM 2a3b6aa770 Improve inspect hover 2024-02-04 18:02:37 +02:00
HarelM c84c7a7b96 Fix redo issue 2024-02-04 16:37:47 +02:00
Harel M cb77c6b4e2 Add nominatim search to maputnik (#873)
This replaces PR:
- #785

Before:

![image](https://github.com/maplibre/maputnik/assets/3269297/95297211-4108-43d8-8a43-42f87e2fbe16)
After:

![image](https://github.com/maplibre/maputnik/assets/3269297/86c3ae58-1bb7-4d2c-8ad9-6b84a21c96f7)

This is based on the geocoder example in maplibre docs:
https://maplibre.org/maplibre-gl-js/docs/examples/geocoder/
2024-02-04 11:37:23 +02:00
Harel M ea42f434eb Update MapLibre to version 4 (#872)
This updates maplibre from a pre-release to an official release.
It also removed the pre.2 from maputnik as maputnik is now published and
there's no reason to keep it in pre-release version name.
This doesn't mean maputnik has an npm package at this point though.
2024-02-04 10:01:22 +02:00
dependabot[bot] 6f82c12861 Bump vite from 5.0.10 to 5.0.12 (#865)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite)
from 5.0.10 to 5.0.12.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/vitejs/vite/blob/v5.0.12/packages/vite/CHANGELOG.md">vite's
changelog</a>.</em></p>
<blockquote>
<h2><!-- raw HTML omitted -->5.0.12 (2024-01-19)<!-- raw HTML omitted
--></h2>
<ul>
<li>fix: await <code>configResolved</code> hooks of worker plugins (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/15597">#15597</a>)
(<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/15605">#15605</a>)
(<a href="https://github.com/vitejs/vite/commit/ef89f80">ef89f80</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/15597">#15597</a>
<a
href="https://redirect.github.com/vitejs/vite/issues/15605">#15605</a></li>
<li>fix: fs deny for case insensitive systems (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/15653">#15653</a>)
(<a href="https://github.com/vitejs/vite/commit/91641c4">91641c4</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/15653">#15653</a></li>
</ul>
<h2><!-- raw HTML omitted -->5.0.11 (2024-01-05)<!-- raw HTML omitted
--></h2>
<ul>
<li>fix: don't pretransform classic script links (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/15361">#15361</a>)
(<a href="https://github.com/vitejs/vite/commit/19e3c9a">19e3c9a</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/15361">#15361</a></li>
<li>fix: inject <code>__vite__mapDeps</code> code before sourcemap file
comment (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/15483">#15483</a>)
(<a href="https://github.com/vitejs/vite/commit/d2aa096">d2aa096</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/15483">#15483</a></li>
<li>fix(assets): avoid splitting <code>,</code> inside base64 value of
<code>srcset</code> attribute (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/15422">#15422</a>)
(<a href="https://github.com/vitejs/vite/commit/8de7bd2">8de7bd2</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/15422">#15422</a></li>
<li>fix(html): handle offset magic-string slice error (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/15435">#15435</a>)
(<a href="https://github.com/vitejs/vite/commit/5ea9edb">5ea9edb</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/15435">#15435</a></li>
<li>chore(deps): update dependency strip-literal to v2 (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/15475">#15475</a>)
(<a href="https://github.com/vitejs/vite/commit/49d21fe">49d21fe</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/15475">#15475</a></li>
<li>chore(deps): update tj-actions/changed-files action to v41 (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/15476">#15476</a>)
(<a href="https://github.com/vitejs/vite/commit/2a540ee">2a540ee</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/15476">#15476</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/vitejs/vite/commit/ee81e196769c102a6b1bf30f8444ccde236e71d5"><code>ee81e19</code></a>
release: v5.0.12</li>
<li><a
href="https://github.com/vitejs/vite/commit/91641c4da0a011d4c5352e88fc68389d4e1289a5"><code>91641c4</code></a>
fix: fs deny for case insensitive systems (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/15653">#15653</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/ef89f8092f0eb1d8fd7d21256e6af8c4e64fe9b2"><code>ef89f80</code></a>
fix: await <code>configResolved</code> hooks of worker plugins (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/15597">#15597</a>)
(<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/15605">#15605</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/b44c49302ffbf0c82f984f6219ed6376d1e4552a"><code>b44c493</code></a>
release: v5.0.11</li>
<li><a
href="https://github.com/vitejs/vite/commit/d2aa0969ee316000d3b957d7e879f001e85e369e"><code>d2aa096</code></a>
fix: inject <code>__vite__mapDeps</code> code before sourcemap file
comment (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/15483">#15483</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/2a540eee82f9a31deff8215bdbdccfa46d494a06"><code>2a540ee</code></a>
chore(deps): update tj-actions/changed-files action to v41 (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/15476">#15476</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/5ea9edbc9ceb991e85f893fe62d68ed028677451"><code>5ea9edb</code></a>
fix(html): handle offset magic-string slice error (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/15435">#15435</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/49d21fe1feaac30dee0196bd484480a8000a4363"><code>49d21fe</code></a>
chore(deps): update dependency strip-literal to v2 (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/15475">#15475</a>)</li>
<li><a
href="https://github.com/vitejs/vite/commit/8de7bd2b68db27b83d9484cc8d4e26436615168e"><code>8de7bd2</code></a>
fix(assets): avoid splitting <code>,</code> inside base64 value of
<code>srcset</code> attribute (#...</li>
<li><a
href="https://github.com/vitejs/vite/commit/19e3c9a8a16847486fbad8a8cd48fc771b1538bb"><code>19e3c9a</code></a>
fix: don't pretransform classic script links (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/15361">#15361</a>)</li>
<li>See full diff in <a
href="https://github.com/vitejs/vite/commits/v5.0.12/packages/vite">compare
view</a></li>
</ul>
</details>
<br />


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

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

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

---

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

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/maplibre/maputnik/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-04 09:18:19 +02:00
HarelM 3b95b25777 Remove unneed console.log 2024-01-13 14:38:56 +02:00
Harel M 1da65f2116 Fix missing logo (#863)
Fixes #861
This should hopefully address the last item in the below issue of the
missing logo.
I tested it locally and it seems to be working as expected, I hope this
will be the case once deployed.
- #861
2024-01-12 18:46:10 +02:00
Harel M a62db148cd Remove Storybook, cleanups (#860)
1. Changed references to point to this new repo
2. Fixed docker image publishing to point to ghcr.io.
3. Remove survey link - the survey is closed and there's no point in
keeping it.
4. Remove storybook - Basically a storybook is the ability to look at
components and see how they look and interact with them.
It's a powerful tool for developing component library with "live"
documentation.
But it's an overkill for this project and I would like to reduce
maintenance costs.
Currently all the "stories" are in javascript and not in typescript and
it feels like a waste of time to try and maintain it, along with
updating the storybook library itself and everything around it.
2024-01-12 10:59:57 +02:00
HarelM 6ed10a862f Update pages deploy on every commit to main 2024-01-11 22:57:07 +02:00
HarelM 123e84f19b login to ghcr.io 2024-01-11 22:29:46 +02:00
HarelM d9b1b6f3ae Fix docker deploy, remove unneeded files 2024-01-11 22:24:47 +02:00
Harel M e0cef99c07 Update LICENSE 2024-01-11 22:11:18 +02:00
Harel M eb48bed32a Update MapLibre dependencies, add terrain editing (#859)
This PR aims at updating MapLibre dependencies.

The main goal of this update is to allow adding terrain specification to
the editor.
This requires version 4 of maplibre so currently it will use the
pre-release.
2024-01-11 22:05:47 +02:00
86 changed files with 673 additions and 7100 deletions
-4
View File
@@ -1,4 +0,0 @@
{
"packages": [],
"sandboxes": ["/"]
}
+3 -9
View File
@@ -15,7 +15,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- run: docker build -t docker.pkg.github.com/maputnik/editor/editor:main .
- run: docker build -t test-docker-image-build .
# build the editor
build-node:
@@ -53,17 +53,11 @@ jobs:
node-version-file: '.nvmrc'
- run: npm ci
- run: npm run build
- run: npm run build-storybook
- name: artifacts/editor
- name: artifacts/maputnik
uses: actions/upload-artifact@v1
with:
name: editor
name: maputnik
path: dist
- name: artifacts/storybook
uses: actions/upload-artifact@v1
with:
name: storybook
path: build/storybook
# Build and upload desktop CLI artifacts
- name: Set up Go
+33 -8
View File
@@ -3,24 +3,49 @@ name: deploy
on:
push:
branches: [ main ]
tags:
- 'v*'
jobs:
deploy-pages:
name: deploy/pages
runs-on: ubuntu-latest
if: ${{ github.event_name == 'push' }}
steps:
- uses: actions/checkout@v4
- name: Use Node.js from nvmrc
uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
- name: Install
run: npm ci
- name: Build
run: npm run build
- name: Upload to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: dist
# publish docker to GitHub registry
deploy-docker:
name: deploy/docker
runs-on: ${{ matrix.os }}
runs-on: ubuntu-latest
if: ${{ github.event_name == 'push' }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
steps:
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/checkout@v4
- run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login docker.pkg.github.com -u orangemug --password-stdin
- run: docker build -t docker.pkg.github.com/maputnik/editor/editor:main .
- run: docker push docker.pkg.github.com/maputnik/editor/editor:main
- run: docker build -t ghcr.io/maplibre/maputnik:main .
- run: docker push ghcr.io/maplibre/maputnik:main
-9
View File
@@ -1,9 +0,0 @@
const config = {
stories: ['../stories/**/*.stories.jsx'],
addons: ['@storybook/addon-actions', '@storybook/addon-links', '@storybook/addon-a11y/register', '@storybook/addon-storysource'],
framework: {
name: '@storybook/react-vite',
options: {}
}
};
export default config;
-7
View File
@@ -1,7 +0,0 @@
import { addons } from '@storybook/addons';
import { themes } from '@storybook/theming';
import theme from './maputnik.theme';
addons.setConfig({
theme: theme,
});
-8
View File
@@ -1,8 +0,0 @@
import { create } from '@storybook/theming/create';
export default create({
base: 'light',
brandTitle: 'Maputnik',
brandUrl: 'https://github.com/maputnik/editor',
});
+1 -1
View File
@@ -7,7 +7,7 @@ RUN npm install
# Build maputnik
COPY . .
RUN npm run build
RUN npx vite build
#---------------------------------------------------------------------------
# Create a clean nginx-alpine slim image with just the build results
+1
View File
@@ -1,5 +1,6 @@
The MIT License (MIT)
Copyright (c) 2015 Lukas Martinelli
Copyright (c) 2024 MapLibre contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
+6 -6
View File
@@ -1,10 +1,10 @@
<img width="200" alt="Maputnik logo" src="https://cdn.jsdelivr.net/gh/maputnik/design/logos/logo-color.png" />
# Maputnik
[![GitHub CI status](https://github.com/maputnik/editor/workflows/ci/badge.svg)][github-action-ci]
[![GitHub CI status](https://github.com/maplibre/maputnik/workflows/ci/badge.svg)][github-action-ci]
[![License](https://img.shields.io/badge/license-MIT-blue.svg)][license]
[github-action-ci]: https://github.com/maputnik/editor/actions?query=workflow%3Aci
[github-action-ci]: https://github.com/maplibre/maputnik/actions?query=workflow%3Aci
[license]: https://tldrlegal.com/license/mit-license
A free and open visual editor for the [MapLibre GL styles](https://maplibre.org/maplibre-style-spec/)
@@ -14,18 +14,18 @@ targeted at developers and map designers.
## Usage
- :link: Design your maps online at **<https://www.maplibre.org/maputnik/>** (all in local storage)
- :link: Use the [Maputnik CLI](https://github.com/maputnik/editor/wiki/Maputnik-CLI) for local style development
- :link: Use the [Maputnik CLI](https://github.com/maplibre/maputnik/wiki/Maputnik-CLI) for local style development
- In a Docker, run this command and browse to http://localhost:8888, Ctrl+C to stop the server.
```bash
docker run -it --rm -p 8888:8888 maputnik/editor
docker run -it --rm -p 8888:8888 ghcr.io/maplibre/maputnik:main
```
## Documentation
The documentation can be found in the [Wiki](https://github.com/maputnik/editor/wiki). You are welcome to collaborate!
The documentation can be found in the [Wiki](https://github.com/maplibre/maputnik/wiki). You are welcome to collaborate!
- :link: **Study the [Maputnik Wiki](https://github.com/maputnik/editor/wiki)**
- :link: **Study the [Maputnik Wiki](https://github.com/maplibre/maputnik/wiki)**
- :video_camera: Design a map from Scratch https://youtu.be/XoDh0gEnBQo
[![Design Map from Scratch](https://j.gifs.com/g5XMgl.gif)](https://youtu.be/XoDh0gEnBQo)
+35
View File
@@ -87,4 +87,39 @@ describe("history", () => {
],
});
});
it("should not redo after undo and value change", () => {
when.setStyle("geojson");
when.modal.open();
when.modal.fillLayers({
id: "step 1",
type: "background",
});
when.modal.open();
when.modal.fillLayers({
id: "step 2",
type: "background",
});
when.typeKeys(undoKeyCombo);
when.typeKeys(undoKeyCombo);
then(get.styleFromLocalStorage()).shouldDeepNestedInclude({ layers: [] });
when.modal.open();
when.modal.fillLayers({
id: "step 3",
type: "background",
});
when.typeKeys(redoKeyCombo);
then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
layers: [
{
id: "step 3",
type: "background",
},
],
});
});
});
+6
View File
@@ -23,4 +23,10 @@ describe("map", () => {
);
});
});
describe("search", () => {
it('should exist', () => {
then(get.searchControl()).shouldBeVisible();
});
});
});
+1
View File
@@ -177,5 +177,6 @@ export class MaputnikDriver {
skipTargetLayerEditor: () =>
this.helper.get.elementByTestId("skip-target-layer-editor"),
canvas: () => this.helper.get.element("canvas"),
searchControl: () => this.helper.get.element('.maplibregl-ctrl-geocoder')
};
}
+2 -2
View File
@@ -79,12 +79,12 @@ describe("modals", () => {
when.click("nav:settings");
});
describe("when click name", () => {
describe("when click name filed spec information", () => {
beforeEach(() => {
when.click("field-doc-button-Name");
});
it("name", () => {
it("should show the spec information", () => {
then(get.elementsText("spec-field-doc")).shouldInclude(
"name for the style"
);
Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

+415 -5087
View File
File diff suppressed because it is too large Load Diff
+9 -20
View File
@@ -1,29 +1,28 @@
{
"name": "maputnik",
"version": "2.0.0-pre.2",
"version": "2.0.0",
"description": "A MapLibre GL visual style editor",
"type": "module",
"main": "''",
"scripts": {
"start": "vite",
"build": "tsc && vite build",
"build": "tsc && vite build --base=/maputnik/",
"lint": "eslint ./src ./cypress --ext ts,tsx,js,jsx --report-unused-disable-directives --max-warnings 0",
"test": "cypress run",
"cy:open": "cypress open",
"lint-css": "stylelint \"src/styles/*.scss\"",
"storybook": "storybook dev -h 0.0.0.0 -p 6006",
"build-storybook": "storybook build -o build/storybook"
"lint-css": "stylelint \"src/styles/*.scss\""
},
"repository": {
"type": "git",
"url": "https://github.com/maputnik/editor"
"url": "https://github.com/maplibre/maputnik"
},
"author": "Lukas Martinelli",
"license": "MIT",
"homepage": "https://github.com/maputnik/editor#readme",
"homepage": "https://github.com/maplibre/maputnik#readme",
"dependencies": {
"@mapbox/mapbox-gl-rtl-text": "^0.2.3",
"@maplibre/maplibre-gl-style-spec": "^17.0.1",
"@maplibre/maplibre-gl-geocoder": "^1.5.0",
"@maplibre/maplibre-gl-style-spec": "^20.1.0",
"@mdi/js": "^6.6.96",
"@mdi/react": "^1.5.0",
"@typescript-eslint/eslint-plugin": "^6.16.0",
@@ -46,7 +45,7 @@
"lodash.isequal": "^4.5.0",
"lodash.throttle": "^4.1.1",
"mapbox-gl-inspect": "^1.3.1",
"maplibre-gl": "^2.4.0",
"maplibre-gl": "^4.0.0",
"maputnik-design": "github:maputnik/design#172b06c",
"ol": "^6.14.1",
"ol-mapbox-style": "^7.1.1",
@@ -92,15 +91,6 @@
"@istanbuljs/nyc-config-typescript": "^1.0.2",
"@rollup/plugin-replace": "^5.0.5",
"@shellygo/cypress-test-utils": "^2.0.17",
"@storybook/addon-a11y": "^7.6.5",
"@storybook/addon-actions": "^7.6.5",
"@storybook/addon-links": "^7.6.5",
"@storybook/addon-storysource": "^7.6.5",
"@storybook/addons": "^7.6.5",
"@storybook/builder-vite": "^7.6.5",
"@storybook/react": "^7.6.5",
"@storybook/react-vite": "^7.6.5",
"@storybook/theming": "^7.6.5",
"@types/codemirror": "^5.60.15",
"@types/color": "^3.0.6",
"@types/cors": "^2.8.17",
@@ -137,13 +127,12 @@
"mocha": "^9.2.2",
"postcss": "^8.4.12",
"react-hot-loader": "^4.13.0",
"storybook": "^7.6.5",
"stylelint": "^14.6.1",
"stylelint-config-recommended-scss": "^6.0.0",
"stylelint-scss": "^4.2.0",
"typescript": "^5.3.3",
"uuid": "^8.3.2",
"vite": "^5.0.0",
"vite": "^5.0.12",
"vite-plugin-istanbul": "^5.0.0"
}
}
+2 -3
View File
@@ -9,7 +9,7 @@ import {unset} from 'lodash'
import {arrayMoveMutable} from 'array-move'
import hash from "string-hash";
import {Map, LayerSpecification, StyleSpecification, ValidationError, SourceSpecification} from 'maplibre-gl'
import {latest, validate} from '@maplibre/maplibre-gl-style-spec'
import {latest, validateStyleMin} from '@maplibre/maplibre-gl-style-spec'
import MapMaplibreGl from './MapMaplibreGl'
import MapOpenLayers from './MapOpenLayers'
@@ -379,8 +379,7 @@ export default class App extends React.Component<any, AppState> {
this.getInitialStateFromUrl(newStyle);
}
// This "any" can be removed in latest version of maplibre where maplibre re-exported types from style-spec
const errors = validate(newStyle as any, latest) || [];
const errors: ValidationError[] = validateStyleMin(newStyle) || [];
// The validate function doesn't give us errors for duplicate error with
// empty string for layer.id, manually deal with that here.
+6 -32
View File
@@ -2,9 +2,10 @@ import React from 'react'
import classnames from 'classnames'
import {detect} from 'detect-browser';
import {MdFileDownload, MdOpenInBrowser, MdSettings, MdLayers, MdHelpOutline, MdFindInPage, MdAssignmentTurnedIn} from 'react-icons/md'
import {MdFileDownload, MdOpenInBrowser, MdSettings, MdLayers, MdHelpOutline, MdFindInPage} from 'react-icons/md'
import pkgJson from '../../package.json'
//@ts-ignore
import maputnikLogo from 'maputnik-design/logos/logo-color.svg?inline'
// This is required because of <https://stackoverflow.com/a/49846426>, there isn't another way to detect support that I'm aware of.
const browser = detect();
@@ -43,29 +44,6 @@ class ToolbarLink extends React.Component<ToolbarLinkProps> {
}
}
type ToolbarLinkHighlightedProps = {
className?: string
children?: React.ReactNode
href?: string
onToggleModal?(...args: unknown[]): unknown
};
class ToolbarLinkHighlighted extends React.Component<ToolbarLinkHighlightedProps> {
render() {
return <a
className={classnames('maputnik-toolbar-link', "maputnik-toolbar-link--highlighted", this.props.className)}
href={this.props.href}
rel="noopener noreferrer"
target="_blank"
data-wd-key="toolbar:link-highlighted"
>
<span className="maputnik-toolbar-link-wrapper">
{this.props.children}
</span>
</a>
}
}
type ToolbarSelectProps = {
children?: React.ReactNode
wdKey?: string
@@ -216,9 +194,9 @@ export default class AppToolbar extends React.Component<AppToolbarProps> {
className="maputnik-toolbar-logo"
target="blank"
rel="noreferrer noopener"
href="https://github.com/maputnik/editor"
href="https://github.com/maplibre/maputnik"
>
<img src="node_modules/maputnik-design/logos/logo-color.svg" />
<img src={maputnikLogo} alt="Maputnik on GitHub" />
<h1>
<span className="maputnik-toolbar-name">{pkgJson.name}</span>
<span className="maputnik-toolbar-version">v{pkgJson.version}</span>
@@ -272,14 +250,10 @@ export default class AppToolbar extends React.Component<AppToolbarProps> {
</label>
</ToolbarSelect>
<ToolbarLink href={"https://github.com/maputnik/editor/wiki"}>
<ToolbarLink href={"https://github.com/maplibre/maputnik/wiki"}>
<MdHelpOutline />
<IconText>Help</IconText>
</ToolbarLink>
<ToolbarLinkHighlighted href={"https://gregorywolanski.typeform.com/to/cPgaSY"}>
<MdAssignmentTurnedIn />
<IconText>Take the Maputnik Survey</IconText>
</ToolbarLinkHighlighted>
</div>
</div>
</nav>
+1 -1
View File
@@ -31,7 +31,7 @@ export default class Doc extends React.Component<DocProps> {
const renderValues = (
!!values &&
// HACK: Currently we merge additional values into the style spec, so this is required
// See <https://github.com/maputnik/editor/blob/main/src/components/PropertyGroup.jsx#L16>
// See <https://github.com/maplibre/maputnik/blob/main/src/components/PropertyGroup.jsx#L16>
!Array.isArray(values)
);
+1 -1
View File
@@ -1,6 +1,6 @@
import React from 'react'
import {latest} from '@maplibre/maplibre-gl-style-spec'
import latest from '@maplibre/maplibre-gl-style-spec/dist/latest.json'
import Block from './Block'
import InputString from './InputString'
+1 -1
View File
@@ -1,6 +1,6 @@
import React from 'react'
import {latest} from '@maplibre/maplibre-gl-style-spec'
import latest from '@maplibre/maplibre-gl-style-spec/dist/latest.json'
import Block from './Block'
import InputNumber from './InputNumber'
+1 -1
View File
@@ -1,6 +1,6 @@
import React from 'react'
import {latest} from '@maplibre/maplibre-gl-style-spec'
import latest from '@maplibre/maplibre-gl-style-spec/dist/latest.json'
import Block from './Block'
import InputNumber from './InputNumber'
+1 -1
View File
@@ -1,6 +1,6 @@
import React from 'react'
import {latest} from '@maplibre/maplibre-gl-style-spec'
import latest from '@maplibre/maplibre-gl-style-spec/dist/latest.json'
import Block from './Block'
import InputAutocomplete from './InputAutocomplete'
+1 -1
View File
@@ -1,6 +1,6 @@
import React from 'react'
import {latest} from '@maplibre/maplibre-gl-style-spec'
import latest from '@maplibre/maplibre-gl-style-spec/dist/latest.json'
import Block from './Block'
import InputSelect from './InputSelect'
import InputString from './InputString'
+1 -1
View File
@@ -47,7 +47,7 @@ function createStyleFromFilter(filter: LegacyFilterSpecification | ExpressionSpe
"sources": {
"tmp": {
"type": "geojson",
"data": {}
"data": ''
}
},
"sprite": "",
+54 -28
View File
@@ -13,9 +13,9 @@ import { HighlightedLayer, colorHighlightedLayer } from '../libs/highlight'
import 'maplibre-gl/dist/maplibre-gl.css'
import '../maplibregl.css'
import '../libs/maplibre-rtl'
const IS_SUPPORTED = MapLibreGl.supported();
//@ts-ignore
import MaplibreGeocoder from '@maplibre/maplibre-gl-geocoder';
import '@maplibre/maplibre-gl-geocoder/dist/maplibre-gl-geocoder.css';
function renderPopup(popup: JSX.Element, mountNode: ReactDOM.Container) {
ReactDOM.render(popup, mountNode);
@@ -92,8 +92,6 @@ export default class MapMaplibreGl extends React.Component<MapMaplibreGlProps, M
}
updateMapFromProps(props: MapMaplibreGlProps) {
if(!IS_SUPPORTED) return;
if(!this.state.map) return
//Maplibre GL now does diffing natively so we don't need to calculate
@@ -115,14 +113,12 @@ export default class MapMaplibreGl extends React.Component<MapMaplibreGlProps, M
}
componentDidUpdate() {
if(!IS_SUPPORTED) return;
const map = this.state.map;
this.updateMapFromProps(this.props);
if(this.state.inspect && this.props.inspectModeEnabled !== this.state.inspect._showInspectMap) {
// HACK: Fix for <https://github.com/maputnik/editor/issues/576>, while we wait for a proper fix.
// HACK: Fix for <https://github.com/maplibre/maputnik/issues/576>, while we wait for a proper fix.
// eslint-disable-next-line
this.state.inspect._popupBlocked = false;
this.state.inspect.toggleInspector()
@@ -146,8 +142,6 @@ export default class MapMaplibreGl extends React.Component<MapMaplibreGlProps, M
}
componentDidMount() {
if(!IS_SUPPORTED) return;
const mapOpts = {
...this.props.options,
container: this.container!,
@@ -169,6 +163,8 @@ export default class MapMaplibreGl extends React.Component<MapMaplibreGlProps, M
map.showCollisionBoxes = mapOpts.showCollisionBoxes!;
map.showOverdrawInspector = mapOpts.showOverdrawInspector!;
this.initGeocoder(map);
const zoomControl = new ZoomControl;
map.addControl(zoomControl, 'top-right');
@@ -234,25 +230,55 @@ export default class MapMaplibreGl extends React.Component<MapMaplibreGlProps, M
this.props.onLayerSelect(index);
}
initGeocoder(map: Map) {
const geocoderConfig = {
forwardGeocode: async (config:{query: string, limit: number, language: string[]}) => {
const features = [];
try {
const request = `https://nominatim.openstreetmap.org/search?q=${config.query}&format=geojson&polygon_geojson=1&addressdetails=1`;
const response = await fetch(request);
const geojson = await response.json();
for (const feature of geojson.features) {
const center = [
feature.bbox[0] +
(feature.bbox[2] - feature.bbox[0]) / 2,
feature.bbox[1] +
(feature.bbox[3] - feature.bbox[1]) / 2
];
const point = {
type: 'Feature',
geometry: {
type: 'Point',
coordinates: center
},
place_name: feature.properties.display_name,
properties: feature.properties,
text: feature.properties.display_name,
place_type: ['place'],
center
};
features.push(point);
}
} catch (e) {
console.error(`Failed to forwardGeocode with error: ${e}`);
}
return {
features
};
}
};
const geocoder = new MaplibreGeocoder(geocoderConfig, {maplibregl: MapLibreGl});
map.addControl(geocoder, 'top-left');
}
render() {
if(IS_SUPPORTED) {
return <div
className="maputnik-map__map"
role="region"
aria-label="Map view"
ref={x => this.container = x}
data-wd-key="maplibre:map"
></div>
}
else {
return <div
className="maputnik-map maputnik-map--error"
>
<div className="maputnik-map__error-message">
Error: Cannot load MaplibreGL, WebGL is either unsupported or disabled
</div>
</div>
}
return <div
className="maputnik-map__map"
role="region"
aria-label="Map view"
ref={x => this.container = x}
data-wd-key="maplibre:map"
></div>
}
}
@@ -1,6 +1,4 @@
import React from 'react'
import Block from './Block'
import FieldString from './FieldString'
export type InspectFeature = {
id: string
@@ -21,30 +19,25 @@ function displayValue(value: string | number | Date | object) {
return value;
}
function renderProperties(feature: InspectFeature) {
return Object.keys(feature.properties).map(propertyName => {
const property = feature.properties[propertyName]
return <Block key={propertyName} label={propertyName}>
<FieldString value={displayValue(property)} style={{backgroundColor: 'transparent'}}/>
</Block>
})
}
function renderFeatureId(feature: InspectFeature) {
return <Block key={"feature-id"} label={"feature_id"}>
<FieldString value={displayValue(feature.id)} style={{backgroundColor: 'transparent'}} />
</Block>
function renderKeyValueTableRow(key: string, value: string) {
return <tr key={key}>
<td className="maputnik-popup-table-cell">{key}</td>
<td className="maputnik-popup-table-cell">{value}</td>
</tr>
}
function renderFeature(feature: InspectFeature, idx: number) {
return <div key={`${feature.sourceLayer}-${idx}`}>
<div className="maputnik-popup-layer-id">{feature.layer['source']}: {feature.layer['source-layer']}{feature.inspectModeCounter && <span> × {feature.inspectModeCounter}</span>}</div>
<Block key={"property-type"} label={"$type"}>
<FieldString value={feature.geometry.type} style={{backgroundColor: 'transparent'}} />
</Block>
{renderFeatureId(feature)}
{renderProperties(feature)}
</div>
return <>
<tr key={`${feature.sourceLayer}-${idx}`}>
<td colSpan={2} className="maputnik-popup-layer-id">{feature.layer['source']}: {feature.layer['source-layer']}{feature.inspectModeCounter && <span> × {feature.inspectModeCounter}</span>}</td>
</tr>
{renderKeyValueTableRow("$type", feature.geometry.type)}
{renderKeyValueTableRow("Feature ID", displayValue(feature.id))}
{Object.keys(feature.properties).map(propertyName => {
const property = feature.properties[propertyName];
return renderKeyValueTableRow(propertyName, displayValue(property))
})}
</>
}
function removeDuplicatedFeatures(features: InspectFeature[]) {
@@ -78,7 +71,9 @@ class FeaturePropertyPopup extends React.Component<FeaturePropertyPopupProps> {
render() {
const features = removeDuplicatedFeatures(this.props.features)
return <div className="maputnik-feature-property-popup">
{features.map(renderFeature)}
<table className="maputnik-popup-table">
{features.map(renderFeature)}
</table>
</div>
}
}
+1 -1
View File
@@ -20,7 +20,7 @@ export default class Modal extends React.Component<ModalProps> {
underlayClickExits: true
}
// See <https://github.com/maputnik/editor/issues/416>
// See <https://github.com/maplibre/maputnik/issues/416>
onClose = () => {
if (document.activeElement) {
(document.activeElement as HTMLElement).blur();
+47 -21
View File
@@ -1,6 +1,6 @@
import React from 'react'
import {latest} from '@maplibre/maplibre-gl-style-spec'
import type {LightSpecification, StyleSpecification, TransitionSpecification} from 'maplibre-gl'
import latest from '@maplibre/maplibre-gl-style-spec/dist/latest.json'
import type {LightSpecification, StyleSpecification, TerrainSpecification, TransitionSpecification} from 'maplibre-gl'
import FieldArray from './FieldArray'
import FieldNumber from './FieldNumber'
@@ -58,6 +58,25 @@ export default class ModalSettings extends React.Component<ModalSettingsProps> {
});
}
changeTerrainProperty(property: keyof TerrainSpecification, value: any) {
const terrain = {
...this.props.mapStyle.terrain,
}
if (value === undefined) {
delete terrain[property];
}
else {
// @ts-ignore
terrain[property] = value;
}
this.props.onStyleChanged({
...this.props.mapStyle,
terrain,
});
}
changeStyleProperty(property: keyof StyleSpecification | "owner", value: any) {
const changedStyle = {
...this.props.mapStyle,
@@ -77,10 +96,10 @@ export default class ModalSettings extends React.Component<ModalSettingsProps> {
render() {
const metadata = this.props.mapStyle.metadata || {} as any;
const {onChangeMetadataProperty, mapStyle} = this.props;
const inputProps = { }
const light = this.props.mapStyle.light || {};
const transition = this.props.mapStyle.transition || {};
const terrain = this.props.mapStyle.terrain || {} as TerrainSpecification;
return <Modal
data-wd-key="modal:settings"
@@ -89,21 +108,21 @@ export default class ModalSettings extends React.Component<ModalSettingsProps> {
title={'Style Settings'}
>
<div className="modal:settings">
<FieldString {...inputProps}
<FieldString
label={"Name"}
fieldSpec={latest.$root.name}
data-wd-key="modal:settings.name"
value={this.props.mapStyle.name}
onChange={this.changeStyleProperty.bind(this, "name")}
/>
<FieldString {...inputProps}
<FieldString
label={"Owner"}
fieldSpec={{doc: "Owner ID of the style. Used by Mapbox or future style APIs."}}
data-wd-key="modal:settings.owner"
value={(this.props.mapStyle as any).owner}
onChange={this.changeStyleProperty.bind(this, "owner")}
/>
<FieldUrl {...inputProps}
<FieldUrl
fieldSpec={latest.$root.sprite}
label="Sprite URL"
data-wd-key="modal:settings.sprite"
@@ -111,7 +130,7 @@ export default class ModalSettings extends React.Component<ModalSettingsProps> {
onChange={this.changeStyleProperty.bind(this, "sprite")}
/>
<FieldUrl {...inputProps}
<FieldUrl
label="Glyphs URL"
fieldSpec={latest.$root.glyphs}
data-wd-key="modal:settings.glyphs"
@@ -119,7 +138,7 @@ export default class ModalSettings extends React.Component<ModalSettingsProps> {
onChange={this.changeStyleProperty.bind(this, "glyphs")}
/>
<FieldString {...inputProps}
<FieldString
label={fieldSpecAdditional.maputnik.maptiler_access_token.label}
fieldSpec={fieldSpecAdditional.maputnik.maptiler_access_token}
data-wd-key="modal:settings.maputnik:openmaptiles_access_token"
@@ -127,7 +146,7 @@ export default class ModalSettings extends React.Component<ModalSettingsProps> {
onChange={onChangeMetadataProperty.bind(this, "maputnik:openmaptiles_access_token")}
/>
<FieldString {...inputProps}
<FieldString
label={fieldSpecAdditional.maputnik.thunderforest_access_token.label}
fieldSpec={fieldSpecAdditional.maputnik.thunderforest_access_token}
data-wd-key="modal:settings.maputnik:thunderforest_access_token"
@@ -141,21 +160,19 @@ export default class ModalSettings extends React.Component<ModalSettingsProps> {
length={2}
type="number"
value={mapStyle.center || []}
default={latest.$root.center.default || [0, 0]}
default={[0, 0]}
onChange={this.changeStyleProperty.bind(this, "center")}
/>
<FieldNumber
{...inputProps}
label={"Zoom"}
fieldSpec={latest.$root.zoom}
value={mapStyle.zoom}
default={latest.$root.zoom.default || 0}
default={0}
onChange={this.changeStyleProperty.bind(this, "zoom")}
/>
<FieldNumber
{...inputProps}
label={"Bearing"}
fieldSpec={latest.$root.bearing}
value={mapStyle.bearing}
@@ -164,7 +181,6 @@ export default class ModalSettings extends React.Component<ModalSettingsProps> {
/>
<FieldNumber
{...inputProps}
label={"Pitch"}
fieldSpec={latest.$root.pitch}
value={mapStyle.pitch}
@@ -173,7 +189,6 @@ export default class ModalSettings extends React.Component<ModalSettingsProps> {
/>
<FieldEnum
{...inputProps}
label={"Light anchor"}
fieldSpec={latest.light.anchor}
name="light-anchor"
@@ -184,7 +199,6 @@ export default class ModalSettings extends React.Component<ModalSettingsProps> {
/>
<FieldColor
{...inputProps}
label={"Light color"}
fieldSpec={latest.light.color}
value={light.color as string}
@@ -193,7 +207,6 @@ export default class ModalSettings extends React.Component<ModalSettingsProps> {
/>
<FieldNumber
{...inputProps}
label={"Light intensity"}
fieldSpec={latest.light.intensity}
value={light.intensity as number}
@@ -202,7 +215,6 @@ export default class ModalSettings extends React.Component<ModalSettingsProps> {
/>
<FieldArray
{...inputProps}
label={"Light position"}
fieldSpec={latest.light.position}
type="number"
@@ -212,8 +224,23 @@ export default class ModalSettings extends React.Component<ModalSettingsProps> {
onChange={this.changeLightProperty.bind(this, "position")}
/>
<FieldString
label={"Terrain source"}
fieldSpec={latest.terrain.source}
data-wd-key="modal:settings.maputnik:terrain_source"
value={terrain.source}
onChange={this.changeTerrainProperty.bind(this, "source")}
/>
<FieldNumber
label={"Terrain exaggeration"}
fieldSpec={latest.terrain.exaggeration}
value={terrain.exaggeration}
default={latest.terrain.exaggeration.default}
onChange={this.changeTerrainProperty.bind(this, "exaggeration")}
/>
<FieldNumber
{...inputProps}
label={"Transition delay"}
fieldSpec={latest.transition.delay}
value={transition.delay}
@@ -222,7 +249,6 @@ export default class ModalSettings extends React.Component<ModalSettingsProps> {
/>
<FieldNumber
{...inputProps}
label={"Transition duration"}
fieldSpec={latest.transition.duration}
value={transition.duration}
@@ -230,7 +256,7 @@ export default class ModalSettings extends React.Component<ModalSettingsProps> {
onChange={this.changeTransitionProperty.bind(this, "duration")}
/>
<FieldSelect {...inputProps}
<FieldSelect
label={fieldSpecAdditional.maputnik.style_renderer.label}
fieldSpec={fieldSpecAdditional.maputnik.style_renderer}
data-wd-key="modal:settings.maputnik:renderer"
+2 -2
View File
@@ -1,6 +1,6 @@
import React from 'react'
import {MdAddCircleOutline, MdDelete} from 'react-icons/md'
import {latest} from '@maplibre/maplibre-gl-style-spec'
import latest from '@maplibre/maplibre-gl-style-spec/dist/latest.json'
import type {GeoJSONSourceSpecification, RasterDEMSourceSpecification, RasterSourceSpecification, SourceSpecification, StyleSpecification, VectorSourceSpecification} from 'maplibre-gl'
import Modal from './Modal'
@@ -134,7 +134,7 @@ class AddSource extends React.Component<AddSourceProps, AddSourceState> {
case 'geojson_json': return {
type: 'geojson',
cluster: (source as GeoJSONSourceSpecification).cluster || false,
data: {}
data: ''
}
case 'tilejson_vector': return {
type: 'vector',
+2 -2
View File
@@ -1,6 +1,6 @@
import React from 'react'
import {mdiFunctionVariant, mdiTableRowPlusAfter} from '@mdi/js';
import {latest} from '@maplibre/maplibre-gl-style-spec'
import latest from '@maplibre/maplibre-gl-style-spec/dist/latest.json'
import InputButton from './InputButton'
import InputSpec from './InputSpec'
@@ -302,7 +302,7 @@ export default class DataProperty extends React.Component<DataPropertyProps, Dat
<div className="maputnik-data-spec-property-input">
<InputSpec
fieldName={"base"}
fieldSpec={latest.function.base}
fieldSpec={latest.function.base as typeof latest.function.base & { type: "number" }}
value={this.props.value?.base}
onChange={(_, newValue) => this.changeBase(newValue as number)}
/>
+2 -2
View File
@@ -1,6 +1,6 @@
import React from 'react'
import {mdiFunctionVariant, mdiTableRowPlusAfter} from '@mdi/js';
import {latest} from '@maplibre/maplibre-gl-style-spec'
import latest from '@maplibre/maplibre-gl-style-spec/dist/latest.json'
import InputButton from './InputButton'
import InputSpec from './InputSpec'
@@ -207,7 +207,7 @@ export default class ZoomProperty extends React.Component<ZoomPropertyProps, Zoo
<div className="maputnik-data-spec-property-input">
<InputSpec
fieldName={"base"}
fieldSpec={latest.function.base}
fieldSpec={latest.function.base as typeof latest.function.base & { type: "number" }}
value={this.props.value?.base}
onChange={(_, newValue) => this.changeBase(newValue as number | undefined)}
/>
+1 -1
View File
@@ -1,4 +1,4 @@
{
"openmaptiles": "KDhMfHvorAFkFe64wlZb",
"openmaptiles": "get_your_own_OpIi9ZULNHzrESv6T2vL",
"thunderforest": "b71f7f0ba4064f5eb9e903859a9cf5c6"
}
+2 -2
View File
@@ -2,7 +2,7 @@
import jsonlint from 'jsonlint';
import CodeMirror, { MarkerRange } from 'codemirror';
import jsonToAst from 'json-to-ast';
import {expression, validate} from '@maplibre/maplibre-gl-style-spec';
import {expression, validateStyleMin} from '@maplibre/maplibre-gl-style-spec';
type MarkerRangeWithMessage = MarkerRange & {message: string};
@@ -102,7 +102,7 @@ CodeMirror.registerHelper("lint", "mgl", (text: string, opts: any, doc: any) =>
let out: ReturnType<typeof expression.createExpression> | null = null;
if (context === "layer") {
// Just an empty style so we can validate a layer.
const errors = validate({
const errors = validateStyleMin({
"version": 8,
"name": "Empty Style",
"metadata": {},
+1 -1
View File
@@ -1,4 +1,4 @@
import {latest} from '@maplibre/maplibre-gl-style-spec'
import latest from '@maplibre/maplibre-gl-style-spec/dist/latest.json'
export const combiningFilterOps = ['all', 'any', 'none'];
export const setFilterOps = ['in', '!in'];
+1 -1
View File
@@ -1,3 +1,3 @@
import MapLibreGl from "maplibre-gl"
MapLibreGl.setRTLTextPlugin('https://unpkg.com/@mapbox/mapbox-gl-rtl-text@0.2.3/mapbox-gl-rtl-text.min.js', () => {});
MapLibreGl.setRTLTextPlugin('https://unpkg.com/@mapbox/mapbox-gl-rtl-text@0.2.3/mapbox-gl-rtl-text.min.js', false);
+5 -2
View File
@@ -19,10 +19,13 @@ export class RevisionStore {
}
addRevision(revision: StyleSpecification & {id: string}) {
//TODO: compare new revision style id with old ones
//and ensure that it is always the same id
// clear any "redo" revisions once a change is made
// and ensure current index is at end of list
this.revisions = this.revisions.slice(0, this.currentIdx + 1);
this.revisions.push(revision)
this.currentIdx++
//}
}
undo() {
+9
View File
@@ -36,3 +36,12 @@
margin-top: $margin-2;
}
}
.maputnik-popup-table {
width: 100%;
}
.maputnik-popup-table-cell {
color: $color-lowgray;
padding-left: $margin-2;
}
-26
View File
@@ -1,26 +0,0 @@
import '../src/styles/index.scss';
import React from 'react';
import {Describe} from './ui';
export default {
title: 'Welcome',
};
export const ToStorybook = () => {
return (
<Describe>
<h1>Maputnik component library</h1>
<p>
This is the Maputnik component library, which shows the uses of some commonly used components from the Maputnik editor. This is a stand alone place where we can better refine them and improve their API separate from their use inside the editor.
</p>
<p>
This should also help us better refine our CSS and make it more modular as currently we rely on the cascade quite a bit in a number of places.
</p>
</Describe>
);
}
ToStorybook.story = {
name: 'Intro',
};
-44
View File
@@ -1,44 +0,0 @@
import React from 'react';
import {useActionState} from './helper';
import FieldArray from '../src/components/FieldArray';
import {Wrapper} from './ui';
export default {
title: 'FieldArray',
component: FieldArray,
};
export const NumberType = () => {
const [value, setValue] = useActionState("onChange", [1,2,3]);
return (
<Wrapper>
<FieldArray
label="Foobar"
type="number"
value={value}
length={3}
onChange={setValue}
/>
</Wrapper>
);
};
export const StringType = () => {
const [value, setValue] = useActionState("onChange", ["a", "b", "c"]);
return (
<Wrapper>
<FieldArray
label="Foobar"
type="string"
value={value}
length={3}
onChange={setValue}
/>
</Wrapper>
);
};
-27
View File
@@ -1,27 +0,0 @@
import React from 'react';
import {useActionState} from './helper';
import FieldAutocomplete from '../src/components/FieldAutocomplete';
import {Wrapper} from './ui';
export default {
title: 'FieldAutocomplete',
component: FieldAutocomplete,
};
export const Basic = () => {
const options = [["FOO", "foo"], ["BAR", "bar"], ["BAZ", "baz"]];
const [value, setValue] = useActionState("onChange", "bar");
return (
<Wrapper>
<FieldAutocomplete
label="Foobar"
options={options}
value={value}
onChange={setValue}
/>
</Wrapper>
);
};
-39
View File
@@ -1,39 +0,0 @@
import React from 'react';
import {useActionState} from './helper';
import FieldCheckbox from '../src/components/FieldCheckbox';
import {Wrapper} from './ui';
export default {
title: 'FieldCheckbox',
component: FieldCheckbox,
};
export const BasicUnchecked = () => {
const [value, setValue] = useActionState("onChange", false);
return (
<Wrapper>
<FieldCheckbox
label="Foobar"
value={value}
onChange={setValue}
/>
</Wrapper>
);
};
export const BasicChecked = () => {
const [value, setValue] = useActionState("onChange", true);
return (
<Wrapper>
<FieldCheckbox
label="Foobar"
value={value}
onChange={setValue}
/>
</Wrapper>
);
};
-25
View File
@@ -1,25 +0,0 @@
import React from 'react';
import {useActionState} from './helper';
import FieldColor from '../src/components/FieldColor';
import {Wrapper} from './ui';
export default {
title: 'FieldColor',
component: FieldColor,
};
export const Basic = () => {
const [color, setColor] = useActionState("onChange", "#ff0000");
return (
<Wrapper>
<FieldColor
label="Foobar"
value={color}
onChange={setColor}
/>
</Wrapper>
);
};
-56
View File
@@ -1,56 +0,0 @@
import React from 'react';
import {useActionState} from './helper';
import FieldDynamicArray from '../src/components/FieldDynamicArray';
import {Wrapper} from './ui';
export default {
title: 'FieldDynamicArray',
component: FieldDynamicArray,
};
export const NumberType = () => {
const [value, setValue] = useActionState("onChange", [1,2,3]);
return (
<Wrapper>
<FieldDynamicArray
label="Foobar"
type="number"
value={value}
onChange={setValue}
/>
</Wrapper>
);
};
export const UrlType = () => {
const [value, setValue] = useActionState("onChange", ["http://example.com"]);
return (
<Wrapper>
<FieldDynamicArray
label="Foobar"
type="url"
value={value}
onChange={setValue}
/>
</Wrapper>
);
};
export const EnumType = () => {
const [value, setValue] = useActionState("onChange", ["foo"]);
return (
<Wrapper>
<FieldDynamicArray
label="Foobar"
fieldSpec={{values: {"foo": null, "bar": null, "baz": null}}}
type="enum"
value={value}
onChange={setValue}
/>
</Wrapper>
);
};
-78
View File
@@ -1,78 +0,0 @@
import React from 'react';
import {useActionState} from './helper';
import FieldEnum from '../src/components/FieldEnum';
import {Wrapper} from './ui';
export default {
title: 'FieldEnum',
component: FieldEnum,
};
export const BasicFew = () => {
const options = ["Foo", "Bar", "Baz"];
const [value, setValue] = useActionState("onChange", "Foo");
return (
<Wrapper>
<FieldEnum
label="Foobar"
options={options}
value={value}
onChange={setValue}
/>
</Wrapper>
);
};
export const BasicFewWithDefault = () => {
const options = ["Foo", "Bar", "Baz"];
const [value, setValue] = useActionState("onChange", null);
return (
<Wrapper>
<FieldEnum
label="Foobar"
options={options}
default={"Baz"}
value={value}
onChange={setValue}
/>
</Wrapper>
);
};
export const BasicMany = () => {
const options = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"];
const [value, setValue] = useActionState("onChange", "a");
return (
<Wrapper>
<FieldEnum
label="Foobar"
options={options}
value={value}
onChange={setValue}
/>
</Wrapper>
);
};
export const BasicManyWithDefault = () => {
const options = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"];
const [value, setValue] = useActionState("onChange", "a");
return (
<Wrapper>
<FieldEnum
label="Foobar"
options={options}
default={"h"}
value={value}
onChange={setValue}
/>
</Wrapper>
);
};
-39
View File
@@ -1,39 +0,0 @@
import React from 'react';
import FieldFunction from '../src/components/FieldFunction';
import {latest} from '@maplibre/maplibre-gl-style-spec'
export default {
title: 'FieldFunction',
component: FieldFunction,
};
export const Basic = () => {
const value = {
"property": "rank",
"type": "categorical",
"default": "#222",
"stops": [
[
{"zoom": 6, "value": ""},
["#777"]
],
[
{"zoom": 10, "value": ""},
["#444"]
]
]
};
return <div style={{width: "360px"}}>
<FieldFunction
onChange={() => {}}
value={value}
errors={[]}
fieldName={"Color"}
fieldType={"color"}
fieldSpec={latest['paint_fill']['fill-color']}
/>
</div>
};
-27
View File
@@ -1,27 +0,0 @@
import React from 'react';
import {useActionState} from './helper';
import FieldMultiInput from '../src/components/FieldMultiInput';
import {Wrapper} from './ui';
export default {
title: 'FieldMultiInput',
component: FieldMultiInput,
};
export const Basic = () => {
const options = [["FOO", "foo"], ["BAR", "bar"], ["BAZ", "baz"]];
const [value, setValue] = useActionState("onChange", "FOO");
return (
<Wrapper>
<FieldMultiInput
label="Foobar"
options={options}
value={value}
onChange={setValue}
/>
</Wrapper>
);
};
-41
View File
@@ -1,41 +0,0 @@
import React from 'react';
import {useActionState} from './helper';
import FieldNumber from '../src/components/FieldNumber';
import {Wrapper} from './ui';
export default {
title: 'FieldNumber',
component: FieldNumber,
};
export const Basic = () => {
const [value, setValue] = useActionState("onChange", 1);
return (
<Wrapper>
<FieldNumber
label="number"
value={value}
onChange={setValue}
/>
</Wrapper>
);
};
export const Range = () => {
const [value, setValue] = useActionState("onChange", 1);
return (
<Wrapper>
<FieldNumber
label="number"
value={value}
onChange={setValue}
min={1}
max={24}
allowRange={true}
rangeStep={1}
/>
</Wrapper>
);
};
-28
View File
@@ -1,28 +0,0 @@
import React from 'react';
import {useActionState} from './helper';
import FieldSelect from '../src/components/FieldSelect';
import {Wrapper} from './ui';
export default {
title: 'FieldSelect',
component: FieldSelect,
};
export const Basic = () => {
const options = [["FOO", "Foo"], ["BAR", "Bar"], ["BAZ", "Baz"]];
const [value, setValue] = useActionState("onChange", "FOO");
return (
<Wrapper>
<FieldSelect
label="Foobar"
options={options}
value={value}
onChange={setValue}
/>
</Wrapper>
);
};
-25
View File
@@ -1,25 +0,0 @@
import React from 'react';
import {useActionState} from './helper';
import FieldString from '../src/components/FieldString';
import {Wrapper} from './ui';
export default {
title: 'FieldString',
component: FieldString,
};
export const Basic = () => {
const [value, setValue] = useActionState("onChange", "Hello world");
return (
<Wrapper>
<FieldString
label="Foobar"
value={value}
onChange={setValue}
/>
</Wrapper>
);
};
-42
View File
@@ -1,42 +0,0 @@
import React from 'react';
import {useActionState} from './helper';
import FieldUrl from '../src/components/FieldUrl';
import {Wrapper} from './ui';
export default {
title: 'FieldUrl',
component: FieldUrl,
};
export const Valid = () => {
const [value, setValue] = useActionState("onChange", "http://example.com");
return (
<Wrapper>
<FieldUrl
label="Foobar"
value={value}
onChange={setValue}
onInput={setValue}
/>
</Wrapper>
);
};
export const Invalid = () => {
const [value, setValue] = useActionState("onChange", "foo");
return (
<Wrapper>
<FieldUrl
label="Foobar"
value={value}
onChange={setValue}
onInput={setValue}
/>
</Wrapper>
);
};
-53
View File
@@ -1,53 +0,0 @@
import React from 'react';
import IconLayer from '../src/components/IconLayer';
import {Wrapper} from './ui';
export default {
title: 'IconLayer',
component: IconLayer,
};
export const IconList = () => {
const types = [
'fill-extrusion',
'raster',
'hillshade',
'heatmap',
'fill',
'background',
'line',
'symbol',
'circle',
'INVALID',
]
return <Wrapper>
<table style={{textAlign: "left"}}>
<thead style={{borderBottom: "solid 1px white"}}>
<tr>
<td>ID</td>
<td>Preview</td>
</tr>
</thead>
<tbody>
{types.map(type => (
<tr>
<td style={{paddingRight: "1em"}}>
<code>{type}</code>
</td>
<td>
<IconLayer type={type} />
</td>
</tr>
))}
</tbody>
</table>
</Wrapper>
};
-42
View File
@@ -1,42 +0,0 @@
import React from 'react';
import {useActionState} from './helper';
import InputArray from '../src/components/InputArray';
import {Wrapper} from './ui';
export default {
title: 'InputArray',
component: InputArray,
};
export const NumberType = () => {
const [value, setValue] = useActionState("onChange", [1,2,3]);
return (
<Wrapper>
<InputArray
type="number"
value={value}
length={3}
onChange={setValue}
/>
</Wrapper>
);
};
export const StringType = () => {
const [value, setValue] = useActionState("onChange", ["a", "b", "c"]);
return (
<Wrapper>
<InputArray
type="string"
value={value}
length={3}
onChange={setValue}
/>
</Wrapper>
);
};
-27
View File
@@ -1,27 +0,0 @@
import React from 'react';
import {useActionState} from './helper';
import InputAutocomplete from '../src/components/InputAutocomplete';
import {InputContainer} from './ui';
export default {
title: 'InputAutocomplete',
component: InputAutocomplete,
};
export const Basic = () => {
const options = [["FOO", "foo"], ["BAR", "bar"], ["BAZ", "baz"]];
const [value, setValue] = useActionState("onChange", "bar");
return (
<InputContainer>
<InputAutocomplete
label="Foobar"
options={options}
value={value}
onChange={setValue}
/>
</InputContainer>
);
};
-18
View File
@@ -1,18 +0,0 @@
import React from 'react';
import InputButton from '../src/components/InputButton';
import {action} from '@storybook/addon-actions';
import {InputContainer} from './ui';
export default {
title: 'InputButton',
component: InputButton,
};
export const Basic = () => (
<InputContainer>
<InputButton onClick={action('onClick')}>
Hello InputButton
</InputButton>
</InputContainer>
);
-39
View File
@@ -1,39 +0,0 @@
import React from 'react';
import {useActionState} from './helper';
import InputCheckbox from '../src/components/InputCheckbox';
import {InputContainer} from './ui';
export default {
title: 'InputCheckbox',
component: InputCheckbox,
};
export const BasicUnchecked = () => {
const [value, setValue] = useActionState("onChange", false);
return (
<InputContainer>
<InputCheckbox
label="Foobar"
value={value}
onChange={setValue}
/>
</InputContainer>
);
};
export const BasicChecked = () => {
const [value, setValue] = useActionState("onChange", true);
return (
<InputContainer>
<InputCheckbox
label="Foobar"
value={value}
onChange={setValue}
/>
</InputContainer>
);
};
-25
View File
@@ -1,25 +0,0 @@
import React from 'react';
import {useActionState} from './helper';
import InputColor from '../src/components/InputColor';
import {InputContainer} from './ui';
export default {
title: 'InputColor',
component: InputColor,
};
export const Basic = () => {
const [color, setColor] = useActionState("onChange", "#ff0000");
return (
<InputContainer>
<InputColor
label="Foobar"
value={color}
onChange={setColor}
/>
</InputContainer>
);
};
-53
View File
@@ -1,53 +0,0 @@
import React from 'react';
import {useActionState} from './helper';
import InputDynamicArray from '../src/components/InputDynamicArray';
import {Wrapper} from './ui';
export default {
title: 'InputDynamicArray',
component: InputDynamicArray,
};
export const NumberType = () => {
const [value, setValue] = useActionState("onChange", [1,2,3]);
return (
<Wrapper>
<InputDynamicArray
type="number"
value={value}
onChange={setValue}
/>
</Wrapper>
);
};
export const UrlType = () => {
const [value, setValue] = useActionState("onChange", ["http://example.com"]);
return (
<Wrapper>
<InputDynamicArray
type="url"
value={value}
onChange={setValue}
/>
</Wrapper>
);
};
export const EnumType = () => {
const [value, setValue] = useActionState("onChange", ["foo"]);
return (
<Wrapper>
<InputDynamicArray
fieldSpec={{values: {"foo": null, "bar": null, "baz": null}}}
type="enum"
value={value}
onChange={setValue}
/>
</Wrapper>
);
};
-75
View File
@@ -1,75 +0,0 @@
import React from 'react';
import {useActionState} from './helper';
import InputEnum from '../src/components/InputEnum';
import {InputContainer} from './ui';
export default {
title: 'InputEnum',
component: InputEnum,
};
export const BasicFew = () => {
const options = ["Foo", "Bar", "Baz"];
const [value, setValue] = useActionState("onChange", "Foo");
return (
<InputContainer>
<InputEnum
options={options}
value={value}
onChange={setValue}
/>
</InputContainer>
);
};
export const BasicFewWithDefault = () => {
const options = ["Foo", "Bar", "Baz"];
const [value, setValue] = useActionState("onChange", null);
return (
<InputContainer>
<InputEnum
options={options}
default={"Baz"}
value={value}
onChange={setValue}
/>
</InputContainer>
);
};
export const BasicMany = () => {
const options = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"];
const [value, setValue] = useActionState("onChange", "a");
return (
<InputContainer>
<InputEnum
options={options}
value={value}
onChange={setValue}
/>
</InputContainer>
);
};
export const BasicManyWithDefault = () => {
const options = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"];
const [value, setValue] = useActionState("onChange", "a");
return (
<InputContainer>
<InputEnum
options={options}A
default={"h"}
value={value}
onChange={setValue}
/>
</InputContainer>
);
};
-24
View File
@@ -1,24 +0,0 @@
import React from 'react';
import InputJson from '../src/components/InputJson';
import {action} from '@storybook/addon-actions';
import {Wrapper} from './ui';
export default {
title: 'InputJson',
component: InputJson,
};
export const Basic = () => {
const layer = {
id: "background",
type: "background",
};
return <Wrapper>
<InputJson
layer={layer}
onClick={action('onClick')}
/>
</Wrapper>
};
-27
View File
@@ -1,27 +0,0 @@
import React from 'react';
import {useActionState} from './helper';
import InputMultiInput from '../src/components/InputMultiInput';
import {InputContainer} from './ui';
export default {
title: 'InputMultiInput',
component: InputMultiInput,
};
export const Basic = () => {
const options = [["FOO", "foo"], ["BAR", "bar"], ["BAZ", "baz"]];
const [value, setValue] = useActionState("onChange", "FOO");
return (
<InputContainer>
<InputMultiInput
options={options}
value={value}
onChange={setValue}
/>
</InputContainer>
);
};
-42
View File
@@ -1,42 +0,0 @@
import React from 'react';
import {useActionState} from './helper';
import InputNumber from '../src/components/InputNumber';
import {InputContainer} from './ui';
export default {
title: 'InputNumber',
component: InputNumber,
};
export const Basic = () => {
const [value, setValue] = useActionState("onChange", 1);
return (
<InputContainer>
<InputNumber
name="number"
value={value}
onChange={setValue}
/>
</InputContainer>
);
};
export const Range = () => {
const [value, setValue] = useActionState("onChange", 1);
return (
<InputContainer>
<InputNumber
name="number"
value={value}
onChange={setValue}
min={1}
max={24}
allowRange={true}
rangeStep={1}
/>
</InputContainer>
);
};
-28
View File
@@ -1,28 +0,0 @@
import React from 'react';
import {useActionState} from './helper';
import InputSelect from '../src/components/InputSelect';
import {InputContainer} from './ui';
export default {
title: 'InputSelect',
component: InputSelect,
};
export const Basic = () => {
const options = [["FOO", "Foo"], ["BAR", "Bar"], ["BAZ", "Baz"]];
const [value, setValue] = useActionState("onChange", "FOO");
return (
<InputContainer>
<InputSelect
options={options}
value={value}
onChange={setValue}
/>
</InputContainer>
);
};
-67
View File
@@ -1,67 +0,0 @@
import React from 'react';
import {useActionState} from './helper';
import InputString from '../src/components/InputString';
import {InputContainer} from './ui';
export default {
title: 'InputString',
component: InputString,
};
export const Basic = () => {
const [value, setValue] = useActionState("onChange", "Hello world");
return (
<InputContainer>
<InputString
value={value}
onChange={setValue}
/>
</InputContainer>
);
};
export const WithDefault = () => {
const [value, setValue] = useActionState("onChange", null);
return (
<InputContainer>
<InputString
value={value}
default={"Edit me..."}
onChange={setValue}
/>
</InputContainer>
);
};
export const Multiline = () => {
const [value, setValue] = useActionState("onChange", "Hello\nworld");
return (
<InputContainer>
<InputString
multi={true}
value={value}
onChange={setValue}
/>
</InputContainer>
);
};
export const MultilineWithDefault = () => {
const [value, setValue] = useActionState("onChange", null);
return (
<InputContainer>
<InputString
multi={true}
default={"Edit\nme.."}
value={value}
onChange={setValue}
/>
</InputContainer>
);
};
-40
View File
@@ -1,40 +0,0 @@
import React from 'react';
import {useActionState} from './helper';
import InputUrl from '../src/components/InputUrl';
import {InputContainer} from './ui';
export default {
title: 'InputUrl',
component: InputUrl,
};
export const Valid = () => {
const [value, setValue] = useActionState("onChange", "http://example.com");
return (
<InputContainer>
<InputUrl
value={value}
onChange={setValue}
onInput={setValue}
/>
</InputContainer>
);
};
export const Invalid = () => {
const [value, setValue] = useActionState("onChange", "foo");
return (
<InputContainer>
<InputUrl
value={value}
onChange={setValue}
onInput={setValue}
/>
</InputContainer>
);
};
-198
View File
@@ -1,198 +0,0 @@
import React from 'react';
import LayerEditor from '../src/components/LayerEditor';
export default {
title: 'LayerEditor',
component: LayerEditor,
};
export const Background = () => (
<div>
<LayerEditor
layer={{id: "background", type: "background"}}
sources={{}}
vectorLayers={{}}
spec={latest}
errors={[]}
onLayerChanged={() => {}}
onLayerIdChange={() => {}}
onMoveLayer={() => {}}
onLayerDestroy={() => {}}
onLayerCopy={() => {}}
onLayerVisibilityToggle={() => {}}
isFirstLayer={true}
isLastLayer={false}
layerIndex={0}
/>
</div>
);
export const Fill = () => (
<div>
<LayerEditor
layer={{id: "fill", type: "fill", source: "openmaptiles"}}
sources={{}}
vectorLayers={{}}
spec={latest}
errors={[]}
onLayerChanged={() => {}}
onLayerIdChange={() => {}}
onMoveLayer={() => {}}
onLayerDestroy={() => {}}
onLayerCopy={() => {}}
onLayerVisibilityToggle={() => {}}
isFirstLayer={true}
isLastLayer={false}
layerIndex={0}
/>
</div>
);
export const Line = () => (
<div>
<LayerEditor
layer={{id: "line", type: "line", source: "openmaptiles"}}
sources={{}}
vectorLayers={{}}
spec={latest}
errors={[]}
onLayerChanged={() => {}}
onLayerIdChange={() => {}}
onMoveLayer={() => {}}
onLayerDestroy={() => {}}
onLayerCopy={() => {}}
onLayerVisibilityToggle={() => {}}
isFirstLayer={true}
isLastLayer={false}
layerIndex={0}
/>
</div>
);
export const Symbol = () => (
<div>
<LayerEditor
layer={{id: "symbol", type: "symbol", source: "openmaptiles"}}
sources={{}}
vectorLayers={{}}
spec={latest}
errors={[]}
onLayerChanged={() => {}}
onLayerIdChange={() => {}}
onMoveLayer={() => {}}
onLayerDestroy={() => {}}
onLayerCopy={() => {}}
onLayerVisibilityToggle={() => {}}
isFirstLayer={true}
isLastLayer={false}
layerIndex={0}
/>
</div>
);
export const Raster = () => (
<div>
<LayerEditor
layer={{id: "raster", type: "raster", source: "openmaptiles"}}
sources={{}}
vectorLayers={{}}
spec={latest}
errors={[]}
onLayerChanged={() => {}}
onLayerIdChange={() => {}}
onMoveLayer={() => {}}
onLayerDestroy={() => {}}
onLayerCopy={() => {}}
onLayerVisibilityToggle={() => {}}
isFirstLayer={true}
isLastLayer={false}
layerIndex={0}
/>
</div>
);
export const Cirlce = () => (
<div>
<LayerEditor
layer={{id: "circle", type: "circle", source: "openmaptiles"}}
sources={{}}
vectorLayers={{}}
spec={latest}
errors={[]}
onLayerChanged={() => {}}
onLayerIdChange={() => {}}
onMoveLayer={() => {}}
onLayerDestroy={() => {}}
onLayerCopy={() => {}}
onLayerVisibilityToggle={() => {}}
isFirstLayer={true}
isLastLayer={false}
layerIndex={0}
/>
</div>
);
export const FillExtrusion = () => (
<div>
<LayerEditor
layer={{id: "fill-extrusion", type: "fill-extrusion", source: "openmaptiles"}}
sources={{}}
vectorLayers={{}}
spec={latest}
errors={[]}
onLayerChanged={() => {}}
onLayerIdChange={() => {}}
onMoveLayer={() => {}}
onLayerDestroy={() => {}}
onLayerCopy={() => {}}
onLayerVisibilityToggle={() => {}}
isFirstLayer={true}
isLastLayer={false}
layerIndex={0}
/>
</div>
);
export const Heatmap = () => (
<div>
<LayerEditor
layer={{id: "heatmap", type: "heatmap", source: "openmaptiles"}}
sources={{}}
vectorLayers={{}}
spec={latest}
errors={[]}
onLayerChanged={() => {}}
onLayerIdChange={() => {}}
onMoveLayer={() => {}}
onLayerDestroy={() => {}}
onLayerCopy={() => {}}
onLayerVisibilityToggle={() => {}}
isFirstLayer={true}
isLastLayer={false}
layerIndex={0}
/>
</div>
);
export const Hillshade = () => (
<div>
<LayerEditor
layer={{id: "hillshade", type: "hillshade", source: "openmaptiles"}}
sources={{}}
vectorLayers={{}}
spec={latest}
errors={[]}
onLayerChanged={() => {}}
onLayerIdChange={() => {}}
onMoveLayer={() => {}}
onLayerDestroy={() => {}}
onLayerCopy={() => {}}
onLayerVisibilityToggle={() => {}}
isFirstLayer={true}
isLastLayer={false}
layerIndex={0}
/>
</div>
);
-55
View File
@@ -1,55 +0,0 @@
import React from 'react';
import LayerList from '../src/components/LayerList';
import {Wrapper} from './ui';
export default {
title: 'LayerList',
component: LayerList,
};
export const Basic = () => (
<Wrapper>
<div style={{width: "200px"}}>
<LayerList
layers={[
{
id: "background",
type: "background",
},
{
id: "water",
type: "fill",
source: "openmaptiles"
},
{
id: "road_trunk",
type: "line",
source: "openmaptiles"
},
{
id: "road_minor",
type: "line",
source: "openmaptiles"
},
{
id: "building",
type: "fill",
source: "openmaptiles"
},
]}
selectedLayerIndex={0}
onLayersChange={() => {}}
onLayerSelect={() => {}}
onLayerDestroy={() => {}}
onLayerCopy={() => {}}
onLayerVisibilityToggle={() => {}}
onMoveLayer={() => {}}
sources={{}}
errors={[]}
/>
</div>
</Wrapper>
);
-104
View File
@@ -1,104 +0,0 @@
import React from 'react';
import MapMaplibreGl from '../src/components/MapMaplibreGl';
export default {
title: 'MapMaplibreGl',
component: MapMaplibreGl,
};
const mapStyle = {
"version": 8,
"sources": {
"test1": {
"type": "geojson",
"data": {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [0, -10]
},
"properties": {}
}
]
}
},
"test2": {
"type": "geojson",
"data": {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [15, 10]
},
"properties": {}
}
]
}
},
"test3": {
"type": "geojson",
"data": {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-15, 10]
},
"properties": {}
}
]
}
}
},
"sprite": "",
"glyphs": "https://orangemug.github.io/font-glyphs/glyphs/{fontstack}/{range}.pbf",
"layers": [
{
"id": "test1",
"type": "circle",
"source": "test1",
"paint": {
"circle-radius": 40,
"circle-color": "red"
}
},
{
"id": "test2",
"type": "circle",
"source": "test2",
"paint": {
"circle-radius": 40,
"circle-color": "green"
}
},
{
"id": "test3",
"type": "circle",
"source": "test3",
"paint": {
"circle-radius": 40,
"circle-color": "blue"
}
}
]
}
export const Basic = () => {
return <div style={{height: "100vh", width: "100vw"}}>
<MapMaplibreGl
mapStyle={mapStyle}
inspectModeEnabled={false}
replaceAccessTokens={(s) => s}
/>
</div>
};
-108
View File
@@ -1,108 +0,0 @@
import React from 'react';
import MapOpenLayers from '../src/components/MapOpenLayers';
export default {
title: 'MapOpenLayers',
component: MapOpenLayers,
};
const mapStyle = {
"version": 8,
"sources": {
"test1": {
"type": "geojson",
"data": {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [0, -10]
},
"properties": {}
}
]
}
},
"test2": {
"type": "geojson",
"data": {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [15, 10]
},
"properties": {}
}
]
}
},
"test3": {
"type": "geojson",
"data": {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-15, 10]
},
"properties": {}
}
]
}
}
},
"sprite": "",
"glyphs": "https://orangemug.github.io/font-glyphs/glyphs/{fontstack}/{range}.pbf",
"layers": [
{
"id": "test1",
"type": "circle",
"source": "test1",
"paint": {
"circle-radius": 40,
"circle-color": "red"
}
},
{
"id": "test2",
"type": "circle",
"source": "test2",
"paint": {
"circle-radius": 40,
"circle-color": "green"
}
},
{
"id": "test3",
"type": "circle",
"source": "test3",
"paint": {
"circle-radius": 40,
"circle-color": "blue"
}
}
]
}
export const Basic = () => {
return <div style={{height: "100vh", width: "100vw", display: "flex"}}>
<MapOpenLayers
mapStyle={mapStyle}
inspectModeEnabled={false}
replaceAccessTokens={(s) => s}
onChange={() => {}}
debugToolbox={true}
/>
</div>
};
-23
View File
@@ -1,23 +0,0 @@
import React from 'react';
import Modal from '../src/components/Modal';
import {Wrapper} from './ui';
export default {
title: 'Modal',
component: Modal,
};
export const Basic = () => (
<Wrapper>
<div style={{maxHeight: "200px"}}>
<Modal title="hello" isOpen={true}>
{[...Array(50).keys()].map(() => {
return <p>Some text</p>
})}
</Modal>
</div>
</Wrapper>
);
-22
View File
@@ -1,22 +0,0 @@
import React from 'react';
import ModalAdd from '../src/components/ModalAdd';
import {Wrapper} from './ui';
export default {
title: 'ModalAdd',
component: ModalAdd,
};
export const Basic = () => (
<Wrapper>
<div style={{maxHeight: "200px"}}>
<ModalAdd
layers={[]}
sources={{}}
isOpen={true}
/>
</div>
</Wrapper>
);
-25
View File
@@ -1,25 +0,0 @@
import React from 'react';
import ModalDebug from '../src/components/ModalDebug';
import {Wrapper} from './ui';
export default {
title: 'ModalDebug',
component: ModalDebug,
};
export const Basic = () => (
<Wrapper>
<div style={{maxHeight: "200px"}}>
<ModalDebug
isOpen={true}
renderer="mlgljs"
maplibreGlDebugOptions={{}}
mapView={{zoom: 1, center: {lat: 0, lng: 0}}}
/>
</div>
</Wrapper>
);
-23
View File
@@ -1,23 +0,0 @@
import React from 'react';
import ModalExport from '../src/components/ModalExport';
import {Wrapper} from './ui';
export default {
title: 'ModalExport',
component: ModalExport,
};
export const Basic = () => (
<Wrapper>
<div style={{maxHeight: "200px"}}>
<ModalExport
isOpen={true}
mapStyle={{}}
/>
</div>
</Wrapper>
);
-22
View File
@@ -1,22 +0,0 @@
import React from 'react';
import ModalLoading from '../src/components/ModalLoading';
import {Wrapper} from './ui';
export default {
title: 'ModalLoading',
component: ModalLoading,
};
export const Basic = () => (
<Wrapper>
<div style={{maxHeight: "200px"}}>
<ModalLoading
isOpen={true}
title="Loading"
message="Loading 'something.geojson'"
/>
</div>
</Wrapper>
);
-29
View File
@@ -1,29 +0,0 @@
import React from 'react';
import ModalOpen from '../src/components/ModalOpen';
import {action} from '@storybook/addon-actions';
import {Wrapper} from './ui';
export default {
title: 'ModalOpen',
component: ModalOpen,
};
export const Basic = () => (
<Wrapper>
<div style={{maxHeight: "200px"}}>
<ModalOpen
isOpen={true}
mapStyle={{}}
onChangeMetadataProperty={action("onChangeMetadataProperty")}
onStyleChanged={action("onStyleChanged")}
/>
</div>
</Wrapper>
);
-26
View File
@@ -1,26 +0,0 @@
import React from 'react';
import ModalSettings from '../src/components/ModalSettings';
import {action} from '@storybook/addon-actions';
import {Wrapper} from './ui';
export default {
title: 'ModalSettings',
component: ModalSettings,
};
export const Basic = () => (
<Wrapper>
<div style={{maxHeight: "200px"}}>
<ModalSettings
isOpen={true}
mapStyle={{}}
onStyleChanged={action("onStyleChanged")}
onChangeMetadataProperty={action("onChangeMetadataProperty")}
/>
</div>
</Wrapper>
);
-30
View File
@@ -1,30 +0,0 @@
import React from 'react';
import ModalSources from '../src/components/ModalSources';
import {action} from '@storybook/addon-actions';
import {Wrapper} from './ui';
export default {
title: 'ModalSources',
component: ModalSources,
};
export const Basic = () => (
<Wrapper>
<div style={{maxHeight: "200px"}}>
<ModalSources
isOpen={true}
mapStyle={{sources: {}}}
onChangeMetadataProperty={action("onChangeMetadataProperty")}
onStyleChanged={action("onStyleChanged")}
/>
</div>
</Wrapper>
);
-26
View File
@@ -1,26 +0,0 @@
import React from 'react';
import ModalSurvey from '../src/components/ModalSurvey';
import {Wrapper} from './ui';
export default {
title: 'ModalSurvey',
component: ModalSurvey,
};
export const Basic = () => (
<Wrapper>
<div style={{maxHeight: "200px"}}>
<ModalSurvey
isOpen={true}
/>
</div>
</Wrapper>
);
-23
View File
@@ -1,23 +0,0 @@
import React from 'react';
import ScrollContainer from '../src/components/ScrollContainer';
import {Wrapper} from './ui';
export default {
title: 'ScrollContainer',
component: ScrollContainer,
};
export const Basic = () => (
<Wrapper>
<div style={{maxHeight: "200px"}}>
<ScrollContainer>
{[...Array(50).keys()].map(() => {
return <p>Some text</p>
})}
</ScrollContainer>
</div>
</Wrapper>
);
-12
View File
@@ -1,12 +0,0 @@
import React, {useState} from 'react';
import {action} from '@storybook/addon-actions';
export function useActionState (name, initialVal) {
const [val, fn] = useState(initialVal);
const actionFn = action(name);
function retFn(val) {
actionFn(val);
return fn(val);
}
return [val, retFn];
}
-27
View File
@@ -1,27 +0,0 @@
import React from 'react';
export function Describe ({children}) {
return (
<div style={{maxWidth: "600px", margin: "0.8em"}}>
{children}
</div>
)
}
export function Wrapper ({children}) {
return (
<div style={{maxWidth: "260px", margin: "0.4em"}}>
{children}
</div>
);
};
export function InputContainer ({children}) {
return (
<div style={{maxWidth: "171px", margin: "0.4em"}}>
{children}
</div>
);
};