Compare commits

...

8 Commits

Author SHA1 Message Date
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
80 changed files with 500 additions and 7069 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)
+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

+366 -5084
View File
File diff suppressed because it is too large Load Diff
+6 -18
View File
@@ -6,24 +6,22 @@
"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-style-spec": "^20.1.0",
"@mdi/js": "^6.6.96",
"@mdi/react": "^1.5.0",
"@typescript-eslint/eslint-plugin": "^6.16.0",
@@ -46,7 +44,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-pre.4",
"maputnik-design": "github:maputnik/design#172b06c",
"ol": "^6.14.1",
"ol-mapbox-style": "^7.1.1",
@@ -92,15 +90,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,7 +126,6 @@
"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",
+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": "",
+8 -28
View File
@@ -14,9 +14,6 @@ import 'maplibre-gl/dist/maplibre-gl.css'
import '../maplibregl.css'
import '../libs/maplibre-rtl'
const IS_SUPPORTED = MapLibreGl.supported();
function renderPopup(popup: JSX.Element, mountNode: ReactDOM.Container) {
ReactDOM.render(popup, mountNode);
return mountNode;
@@ -92,8 +89,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 +110,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 +139,6 @@ export default class MapMaplibreGl extends React.Component<MapMaplibreGlProps, M
}
componentDidMount() {
if(!IS_SUPPORTED) return;
const mapOpts = {
...this.props.options,
container: this.container!,
@@ -235,24 +226,13 @@ export default class MapMaplibreGl extends React.Component<MapMaplibreGlProps, M
}
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 -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);
-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>
);
};