mirror of
https://github.com/maputnik/editor.git
synced 2026-09-01 09:57:27 +00:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c7c1139e87 | |||
| ab102dccd7 | |||
| 901be16ae4 | |||
| df65cc3eff | |||
| c633368a9a | |||
| 732581c39e | |||
| f435ab79c1 | |||
| 50226a9b2e | |||
| e5688fd9a5 | |||
| 0e39476bd9 | |||
| 19fc3970a9 | |||
| 1a09de238a | |||
| 66a0ee5d4e |
@@ -77,11 +77,18 @@ describe("modals", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("name", () => {
|
it("name", () => {
|
||||||
|
when.click("field-doc-button-Name");
|
||||||
|
|
||||||
|
should.containText("spec-field-doc", "name for the style");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("show name specifications", () => {
|
||||||
when.setValue(get.dataAttribute("modal:settings.name"), "foobar");
|
when.setValue(get.dataAttribute("modal:settings.name"), "foobar");
|
||||||
when.click("modal:settings.owner");
|
when.click("modal:settings.owner");
|
||||||
|
|
||||||
should.equalStyleStore((obj) => obj.name, "foobar");
|
should.equalStyleStore((obj) => obj.name, "foobar");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("owner", () => {
|
it("owner", () => {
|
||||||
when.setValue(get.dataAttribute("modal:settings.owner"), "foobar");
|
when.setValue(get.dataAttribute("modal:settings.owner"), "foobar");
|
||||||
when.click("modal:settings.name");
|
when.click("modal:settings.name");
|
||||||
|
|||||||
Generated
+114
@@ -67,11 +67,19 @@
|
|||||||
"@storybook/react": "^7.6.5",
|
"@storybook/react": "^7.6.5",
|
||||||
"@storybook/react-vite": "^7.6.5",
|
"@storybook/react-vite": "^7.6.5",
|
||||||
"@storybook/theming": "^7.6.5",
|
"@storybook/theming": "^7.6.5",
|
||||||
|
"@types/codemirror": "^5.60.15",
|
||||||
|
"@types/color": "^3.0.6",
|
||||||
"@types/cors": "^2.8.17",
|
"@types/cors": "^2.8.17",
|
||||||
|
"@types/lodash.capitalize": "^4.2.9",
|
||||||
"@types/lodash.isequal": "^4.5.8",
|
"@types/lodash.isequal": "^4.5.8",
|
||||||
"@types/lodash.throttle": "^4.1.9",
|
"@types/lodash.throttle": "^4.1.9",
|
||||||
"@types/react": "^16.14.52",
|
"@types/react": "^16.14.52",
|
||||||
|
"@types/react-aria-modal": "^4.0.9",
|
||||||
|
"@types/react-autocomplete": "^1.8.9",
|
||||||
|
"@types/react-color": "^3.0.10",
|
||||||
"@types/react-dom": "^16.9.24",
|
"@types/react-dom": "^16.9.24",
|
||||||
|
"@types/react-file-reader-input": "^2.0.4",
|
||||||
|
"@types/react-icon-base": "^2.1.6",
|
||||||
"@types/uuid": "^9.0.7",
|
"@types/uuid": "^9.0.7",
|
||||||
"@vitejs/plugin-react": "^4.2.0",
|
"@vitejs/plugin-react": "^4.2.0",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
@@ -4583,6 +4591,39 @@
|
|||||||
"@types/chai": "*"
|
"@types/chai": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/codemirror": {
|
||||||
|
"version": "5.60.15",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.15.tgz",
|
||||||
|
"integrity": "sha512-dTOvwEQ+ouKJ/rE9LT1Ue2hmP6H1mZv5+CCnNWu2qtiOe2LQa9lCprEY20HxiDmV/Bxh+dXjywmy5aKvoGjULA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/tern": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/color": {
|
||||||
|
"version": "3.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/color/-/color-3.0.6.tgz",
|
||||||
|
"integrity": "sha512-NMiNcZFRUAiUUCCf7zkAelY8eV3aKqfbzyFQlXpPIEeoNDbsEHGpb854V3gzTsGKYj830I5zPuOwU/TP5/cW6A==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/color-convert": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/color-convert": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/color-convert/-/color-convert-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-2Q6wzrNiuEvYxVQqhh7sXM2mhIhvZR/Paq4FdsQkOMgWsCIkKvSGj8Le1/XalulrmgOzPMqNa0ix+ePY4hTrfg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/color-name": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/color-name": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-87W6MJCKZYDhLAx/J1ikW8niMvmGRyY+rpUxWpL1cO7F8Uu5CHuQoFv+R0/L5pgNdW4jTyda42kv60uwVIPjLw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@types/connect": {
|
"node_modules/@types/connect": {
|
||||||
"version": "3.4.38",
|
"version": "3.4.38",
|
||||||
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz",
|
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz",
|
||||||
@@ -4703,6 +4744,15 @@
|
|||||||
"integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==",
|
"integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/lodash.capitalize": {
|
||||||
|
"version": "4.2.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/lodash.capitalize/-/lodash.capitalize-4.2.9.tgz",
|
||||||
|
"integrity": "sha512-SV1dav/WbuI816SVig4trFz8ID/m5maVzC8I/E/DejPvmlXvIhw7Y0GWxJ03UhU6qaZOj6qQnR1xxC0mP7ZXoQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/lodash": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/lodash.isequal": {
|
"node_modules/@types/lodash.isequal": {
|
||||||
"version": "4.5.8",
|
"version": "4.5.8",
|
||||||
"resolved": "https://registry.npmjs.org/@types/lodash.isequal/-/lodash.isequal-4.5.8.tgz",
|
"resolved": "https://registry.npmjs.org/@types/lodash.isequal/-/lodash.isequal-4.5.8.tgz",
|
||||||
@@ -4831,6 +4881,34 @@
|
|||||||
"csstype": "^3.0.2"
|
"csstype": "^3.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/react-aria-modal": {
|
||||||
|
"version": "4.0.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/react-aria-modal/-/react-aria-modal-4.0.9.tgz",
|
||||||
|
"integrity": "sha512-H8SU5QoB+1ldMGYRHNm1MXfzD5oD+ZdYTrwVzT+KEiFrkTqQG2QdwVc6Ro4/RixnU4LNtMpvF5HKAIfzzGJGjw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/react": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/react-autocomplete": {
|
||||||
|
"version": "1.8.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/react-autocomplete/-/react-autocomplete-1.8.9.tgz",
|
||||||
|
"integrity": "sha512-Il8qJEKvPU0uW+HOPiRHIKxGF61RM6cM5tEnZDmM5ek78OK5kfv04AZbNyqdPsuTnwp8HIRgBnQH2RhgKILjcg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/react": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/react-color": {
|
||||||
|
"version": "3.0.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/react-color/-/react-color-3.0.10.tgz",
|
||||||
|
"integrity": "sha512-6K5BAn3zyd8lW8UbckIAVeXGxR82Za9jyGD2DBEynsa7fKaguLDVtjfypzs7fgEV7bULgs7uhds8A8v1wABTvQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/reactcss": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/react-dom": {
|
"node_modules/@types/react-dom": {
|
||||||
"version": "16.9.24",
|
"version": "16.9.24",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.24.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.24.tgz",
|
||||||
@@ -4840,6 +4918,33 @@
|
|||||||
"@types/react": "^16"
|
"@types/react": "^16"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/react-file-reader-input": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/react-file-reader-input/-/react-file-reader-input-2.0.4.tgz",
|
||||||
|
"integrity": "sha512-Jqrfn+w42j8t8Q3npMXXKPdk+reIM0UHLKVc3ykrA7q7bN3Z62SGhsClZX0+Edlqm66lcKwmDQl+WMm+Xor7Xg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/react": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/react-icon-base": {
|
||||||
|
"version": "2.1.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/react-icon-base/-/react-icon-base-2.1.6.tgz",
|
||||||
|
"integrity": "sha512-ebbN1JjCm6RxBd3HdI1+8VCdiOI4qMjnl9DIHWJFrB/eYLF4mzIgdL34PIqCJBLY3vlwil9v6IHQvzsa8vgMsg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/react": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/reactcss": {
|
||||||
|
"version": "1.2.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/reactcss/-/reactcss-1.2.11.tgz",
|
||||||
|
"integrity": "sha512-0fFy0ubuPlhksId8r9V8nsLcxBAPQnn15g/ERAElgE9L6rOquMj2CapsxqfyBuHlkp0/ndEUVnkYI7MkTtkGpw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/react": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/resolve": {
|
"node_modules/@types/resolve": {
|
||||||
"version": "1.20.6",
|
"version": "1.20.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.6.tgz",
|
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.6.tgz",
|
||||||
@@ -4891,6 +4996,15 @@
|
|||||||
"integrity": "sha512-0vWLNK2D5MT9dg0iOo8GlKguPAU02QjmZitPEsXRuJXU/OGIOt9vT9Fc26wtYuavLxtO45v9PGleoL9Z0k1LHg==",
|
"integrity": "sha512-0vWLNK2D5MT9dg0iOo8GlKguPAU02QjmZitPEsXRuJXU/OGIOt9vT9Fc26wtYuavLxtO45v9PGleoL9Z0k1LHg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/tern": {
|
||||||
|
"version": "0.23.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.9.tgz",
|
||||||
|
"integrity": "sha512-ypzHFE/wBzh+BlH6rrBgS5I/Z7RD21pGhZ2rltb/+ZrVM1awdZwjx7hE5XfuYgHWk9uvV5HLZN3SloevCAp3Bw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/estree": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/uuid": {
|
"node_modules/@types/uuid": {
|
||||||
"version": "9.0.7",
|
"version": "9.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.7.tgz",
|
||||||
|
|||||||
@@ -96,11 +96,19 @@
|
|||||||
"@storybook/react": "^7.6.5",
|
"@storybook/react": "^7.6.5",
|
||||||
"@storybook/react-vite": "^7.6.5",
|
"@storybook/react-vite": "^7.6.5",
|
||||||
"@storybook/theming": "^7.6.5",
|
"@storybook/theming": "^7.6.5",
|
||||||
|
"@types/codemirror": "^5.60.15",
|
||||||
|
"@types/color": "^3.0.6",
|
||||||
"@types/cors": "^2.8.17",
|
"@types/cors": "^2.8.17",
|
||||||
|
"@types/lodash.capitalize": "^4.2.9",
|
||||||
"@types/lodash.isequal": "^4.5.8",
|
"@types/lodash.isequal": "^4.5.8",
|
||||||
"@types/lodash.throttle": "^4.1.9",
|
"@types/lodash.throttle": "^4.1.9",
|
||||||
"@types/react": "^16.14.52",
|
"@types/react": "^16.14.52",
|
||||||
|
"@types/react-aria-modal": "^4.0.9",
|
||||||
|
"@types/react-autocomplete": "^1.8.9",
|
||||||
|
"@types/react-color": "^3.0.10",
|
||||||
"@types/react-dom": "^16.9.24",
|
"@types/react-dom": "^16.9.24",
|
||||||
|
"@types/react-file-reader-input": "^2.0.4",
|
||||||
|
"@types/react-icon-base": "^2.1.6",
|
||||||
"@types/uuid": "^9.0.7",
|
"@types/uuid": "^9.0.7",
|
||||||
"@vitejs/plugin-react": "^4.2.0",
|
"@vitejs/plugin-react": "^4.2.0",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
|
|||||||
@@ -1,40 +1,43 @@
|
|||||||
import React from 'react'
|
import React, {SyntheticEvent} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import FieldDocLabel from './FieldDocLabel'
|
import FieldDocLabel from './FieldDocLabel'
|
||||||
import Doc from './Doc'
|
import Doc from './Doc'
|
||||||
|
|
||||||
|
|
||||||
/** Wrap a component with a label */
|
type BlockProps = {
|
||||||
export default class Block extends React.Component {
|
"data-wd-key"?: string
|
||||||
static propTypes = {
|
label?: string
|
||||||
"data-wd-key": PropTypes.string,
|
action?: React.ReactElement
|
||||||
label: PropTypes.oneOfType([
|
style?: object
|
||||||
PropTypes.string,
|
onChange?(...args: unknown[]): unknown
|
||||||
PropTypes.element,
|
fieldSpec?: object
|
||||||
]),
|
wideMode?: boolean
|
||||||
action: PropTypes.element,
|
error?: unknown[]
|
||||||
children: PropTypes.node.isRequired,
|
};
|
||||||
style: PropTypes.object,
|
|
||||||
onChange: PropTypes.func,
|
|
||||||
fieldSpec: PropTypes.object,
|
|
||||||
wideMode: PropTypes.bool,
|
|
||||||
error: PropTypes.array,
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor (props) {
|
type BlockState = {
|
||||||
|
showDoc: boolean
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Wrap a component with a label */
|
||||||
|
export default class Block extends React.Component<BlockProps, BlockState> {
|
||||||
|
_blockEl: HTMLDivElement | null = null;
|
||||||
|
|
||||||
|
constructor (props: BlockProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
showDoc: false,
|
showDoc: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onChange(e) {
|
onChange(e: React.BaseSyntheticEvent<Event, HTMLInputElement, HTMLInputElement>) {
|
||||||
const value = e.target.value
|
const value = e.target.value
|
||||||
return this.props.onChange(value === "" ? undefined : value)
|
if (this.props.onChange) {
|
||||||
|
return this.props.onChange(value === "" ? undefined : value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onToggleDoc = (val) => {
|
onToggleDoc = (val: boolean) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
showDoc: val
|
showDoc: val
|
||||||
});
|
});
|
||||||
@@ -46,20 +49,17 @@ export default class Block extends React.Component {
|
|||||||
* causing the picker to reopen. This causes a scenario where the picker can
|
* causing the picker to reopen. This causes a scenario where the picker can
|
||||||
* never be closed once open.
|
* never be closed once open.
|
||||||
*/
|
*/
|
||||||
onLabelClick = (event) => {
|
onLabelClick = (event: SyntheticEvent<any, any>) => {
|
||||||
const el = event.nativeEvent.target;
|
const el = event.nativeEvent.target;
|
||||||
const nativeEvent = event.nativeEvent;
|
const contains = this._blockEl?.contains(el);
|
||||||
const contains = this._blockEl.contains(el);
|
|
||||||
|
|
||||||
if (event.nativeEvent.target.nodeName !== "INPUT" && !contains) {
|
if (event.nativeEvent.target.nodeName !== "INPUT" && !contains) {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
}
|
}
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const errors = [].concat(this.props.error || []);
|
|
||||||
|
|
||||||
return <label style={this.props.style}
|
return <label style={this.props.style}
|
||||||
data-wd-key={this.props["data-wd-key"]}
|
data-wd-key={this.props["data-wd-key"]}
|
||||||
className={classnames({
|
className={classnames({
|
||||||
@@ -1,24 +1,33 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
export default class Doc extends React.Component {
|
const headers = {
|
||||||
static propTypes = {
|
js: "JS",
|
||||||
fieldSpec: PropTypes.object.isRequired,
|
android: "Android",
|
||||||
|
ios: "iOS",
|
||||||
|
macos: "macOS",
|
||||||
|
};
|
||||||
|
|
||||||
|
type DocProps = {
|
||||||
|
fieldSpec: {
|
||||||
|
doc?: string
|
||||||
|
values?: {
|
||||||
|
[key: string]: {
|
||||||
|
doc?: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'sdk-support'?: {
|
||||||
|
[key: string]: typeof headers
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class Doc extends React.Component<DocProps> {
|
||||||
render () {
|
render () {
|
||||||
const {fieldSpec} = this.props;
|
const {fieldSpec} = this.props;
|
||||||
|
|
||||||
const {doc, values} = fieldSpec;
|
const {doc, values} = fieldSpec;
|
||||||
const sdkSupport = fieldSpec['sdk-support'];
|
const sdkSupport = fieldSpec['sdk-support'];
|
||||||
|
|
||||||
const headers = {
|
|
||||||
js: "JS",
|
|
||||||
android: "Android",
|
|
||||||
ios: "iOS",
|
|
||||||
macos: "macOS",
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderValues = (
|
const renderValues = (
|
||||||
!!values &&
|
!!values &&
|
||||||
// HACK: Currently we merge additional values into the style spec, so this is required
|
// HACK: Currently we merge additional values into the style spec, so this is required
|
||||||
@@ -30,7 +39,7 @@ export default class Doc extends React.Component {
|
|||||||
<>
|
<>
|
||||||
{doc &&
|
{doc &&
|
||||||
<div className="SpecDoc">
|
<div className="SpecDoc">
|
||||||
<div className="SpecDoc__doc">{doc}</div>
|
<div className="SpecDoc__doc" data-wd-key='spec-field-doc'>{doc}</div>
|
||||||
{renderValues &&
|
{renderValues &&
|
||||||
<ul className="SpecDoc__values">
|
<ul className="SpecDoc__values">
|
||||||
{Object.entries(values).map(([key, value]) => {
|
{Object.entries(values).map(([key, value]) => {
|
||||||
@@ -61,10 +70,9 @@ export default class Doc extends React.Component {
|
|||||||
return (
|
return (
|
||||||
<tr key={key}>
|
<tr key={key}>
|
||||||
<td>{key}</td>
|
<td>{key}</td>
|
||||||
{Object.keys(headers).map(k => {
|
{Object.keys(headers).map((k) => {
|
||||||
const value = supportObj[k];
|
|
||||||
if (supportObj.hasOwnProperty(k)) {
|
if (supportObj.hasOwnProperty(k)) {
|
||||||
return <td key={k}>{supportObj[k]}</td>;
|
return <td key={k}>{supportObj[k as keyof typeof headers]}</td>;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return <td key={k}>no</td>;
|
return <td key={k}>no</td>;
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import Block from './Block'
|
|
||||||
import InputArray from './InputArray'
|
|
||||||
import Fieldset from './Fieldset'
|
|
||||||
|
|
||||||
export default class FieldArray extends React.Component {
|
|
||||||
static propTypes = {
|
|
||||||
...InputArray.propTypes,
|
|
||||||
name: PropTypes.string,
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {props} = this;
|
|
||||||
|
|
||||||
return <Fieldset label={props.label}>
|
|
||||||
<InputArray {...props} />
|
|
||||||
</Fieldset>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import InputArray, { FieldArrayProps as InputArrayProps } from './InputArray'
|
||||||
|
import Fieldset from './Fieldset'
|
||||||
|
|
||||||
|
type FieldArrayProps = InputArrayProps & {
|
||||||
|
name?: string
|
||||||
|
fieldSpec?: {
|
||||||
|
doc: string
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class FieldArray extends React.Component<FieldArrayProps> {
|
||||||
|
render() {
|
||||||
|
return <Fieldset label={this.props.label} fieldSpec={this.props.fieldSpec}>
|
||||||
|
<InputArray {...this.props} />
|
||||||
|
</Fieldset>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import Block from './Block'
|
|
||||||
import InputColor from './InputColor'
|
|
||||||
|
|
||||||
|
|
||||||
export default class FieldColor extends React.Component {
|
|
||||||
static propTypes = {
|
|
||||||
...InputColor.propTypes,
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {props} = this;
|
|
||||||
|
|
||||||
return <Block label={props.label}>
|
|
||||||
<InputColor {...props} />
|
|
||||||
</Block>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import Block from './Block'
|
||||||
|
import InputColor, {InputColorProps} from './InputColor'
|
||||||
|
|
||||||
|
|
||||||
|
type FieldColorProps = InputColorProps & {
|
||||||
|
label?: string
|
||||||
|
fieldSpec?: {
|
||||||
|
doc: string
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export default class FieldColor extends React.Component<FieldColorProps> {
|
||||||
|
render() {
|
||||||
|
return <Block label={this.props.label} fieldSpec={this.props.fieldSpec}>
|
||||||
|
<InputColor {...this.props} />
|
||||||
|
</Block>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,26 +1,27 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
import {MdInfoOutline, MdHighlightOff} from 'react-icons/md'
|
import {MdInfoOutline, MdHighlightOff} from 'react-icons/md'
|
||||||
|
|
||||||
export default class FieldDocLabel extends React.Component {
|
type FieldDocLabelProps = {
|
||||||
static propTypes = {
|
label: object | string | undefined
|
||||||
label: PropTypes.oneOfType([
|
fieldSpec?: {
|
||||||
PropTypes.object,
|
doc?: string
|
||||||
PropTypes.string
|
|
||||||
]).isRequired,
|
|
||||||
fieldSpec: PropTypes.object,
|
|
||||||
onToggleDoc: PropTypes.func,
|
|
||||||
}
|
}
|
||||||
|
onToggleDoc?(...args: unknown[]): unknown
|
||||||
|
};
|
||||||
|
|
||||||
constructor (props) {
|
type FieldDocLabelState = {
|
||||||
|
open: boolean
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class FieldDocLabel extends React.Component<FieldDocLabelProps, FieldDocLabelState> {
|
||||||
|
constructor (props: FieldDocLabelProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
open: false,
|
open: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onToggleDoc = (open) => {
|
onToggleDoc = (open: boolean) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
open,
|
open,
|
||||||
}, () => {
|
}, () => {
|
||||||
@@ -43,6 +44,7 @@ export default class FieldDocLabel extends React.Component {
|
|||||||
aria-label={this.state.open ? "close property documentation" : "open property documentation"}
|
aria-label={this.state.open ? "close property documentation" : "open property documentation"}
|
||||||
className={`maputnik-doc-button maputnik-doc-button--${this.state.open ? 'open' : 'closed'}`}
|
className={`maputnik-doc-button maputnik-doc-button--${this.state.open ? 'open' : 'closed'}`}
|
||||||
onClick={() => this.onToggleDoc(!this.state.open)}
|
onClick={() => this.onToggleDoc(!this.state.open)}
|
||||||
|
data-wd-key={'field-doc-button-'+label}
|
||||||
>
|
>
|
||||||
{this.state.open ? <MdHighlightOff /> : <MdInfoOutline />}
|
{this.state.open ? <MdHighlightOff /> : <MdInfoOutline />}
|
||||||
</button>
|
</button>
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import InputEnum from './InputEnum'
|
|
||||||
import Block from './Block';
|
|
||||||
import Fieldset from './Fieldset';
|
|
||||||
|
|
||||||
|
|
||||||
export default class FieldEnum extends React.Component {
|
|
||||||
static propTypes = {
|
|
||||||
...InputEnum.propTypes,
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {props} = this;
|
|
||||||
|
|
||||||
return <Fieldset label={props.label}>
|
|
||||||
<InputEnum {...props} />
|
|
||||||
</Fieldset>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import InputEnum, {InputEnumProps} from './InputEnum'
|
||||||
|
import Fieldset from './Fieldset';
|
||||||
|
|
||||||
|
|
||||||
|
type FieldEnumProps = InputEnumProps & {
|
||||||
|
label?: string;
|
||||||
|
fieldSpec?: {
|
||||||
|
doc: string
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export default class FieldEnum extends React.Component<FieldEnumProps> {
|
||||||
|
render() {
|
||||||
|
return <Fieldset label={this.props.label} fieldSpec={this.props.fieldSpec}>
|
||||||
|
<InputEnum {...this.props} />
|
||||||
|
</Fieldset>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,18 +1,17 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
import {latest} from '@maplibre/maplibre-gl-style-spec'
|
import {latest} from '@maplibre/maplibre-gl-style-spec'
|
||||||
import Block from './Block'
|
import Block from './Block'
|
||||||
import InputString from './InputString'
|
import InputString from './InputString'
|
||||||
|
|
||||||
export default class FieldId extends React.Component {
|
type FieldIdProps = {
|
||||||
static propTypes = {
|
value: string
|
||||||
value: PropTypes.string.isRequired,
|
wdKey: string
|
||||||
wdKey: PropTypes.string.isRequired,
|
onChange(...args: unknown[]): unknown
|
||||||
onChange: PropTypes.func.isRequired,
|
error?: unknown[]
|
||||||
error: PropTypes.object,
|
};
|
||||||
}
|
|
||||||
|
|
||||||
|
export default class FieldId extends React.Component<FieldIdProps> {
|
||||||
render() {
|
render() {
|
||||||
return <Block label={"ID"} fieldSpec={latest.layer.id}
|
return <Block label={"ID"} fieldSpec={latest.layer.id}
|
||||||
data-wd-key={this.props.wdKey}
|
data-wd-key={this.props.wdKey}
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import InputJson from './InputJson'
|
|
||||||
|
|
||||||
|
|
||||||
export default class FieldJson extends React.Component {
|
|
||||||
static propTypes = {
|
|
||||||
...InputJson.propTypes,
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {props} = this;
|
|
||||||
return <InputJson {...props} />
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import InputJson, {InputJsonProps} from './InputJson'
|
||||||
|
|
||||||
|
|
||||||
|
type FieldJsonProps = InputJsonProps & {};
|
||||||
|
|
||||||
|
|
||||||
|
export default class FieldJson extends React.Component<FieldJsonProps> {
|
||||||
|
render() {
|
||||||
|
return <InputJson {...this.props} />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,17 +1,16 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
import {latest} from '@maplibre/maplibre-gl-style-spec'
|
import {latest} from '@maplibre/maplibre-gl-style-spec'
|
||||||
import Block from './Block'
|
import Block from './Block'
|
||||||
import InputNumber from './InputNumber'
|
import InputNumber from './InputNumber'
|
||||||
|
|
||||||
export default class FieldMaxZoom extends React.Component {
|
type FieldMaxZoomProps = {
|
||||||
static propTypes = {
|
value?: number
|
||||||
value: PropTypes.number,
|
onChange(...args: unknown[]): unknown
|
||||||
onChange: PropTypes.func.isRequired,
|
error?: unknown[]
|
||||||
error: PropTypes.object,
|
};
|
||||||
}
|
|
||||||
|
|
||||||
|
export default class FieldMaxZoom extends React.Component<FieldMaxZoomProps> {
|
||||||
render() {
|
render() {
|
||||||
return <Block label={"Max Zoom"} fieldSpec={latest.layer.maxzoom}
|
return <Block label={"Max Zoom"} fieldSpec={latest.layer.maxzoom}
|
||||||
error={this.props.error}
|
error={this.props.error}
|
||||||
@@ -1,17 +1,16 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
import {latest} from '@maplibre/maplibre-gl-style-spec'
|
import {latest} from '@maplibre/maplibre-gl-style-spec'
|
||||||
import Block from './Block'
|
import Block from './Block'
|
||||||
import InputNumber from './InputNumber'
|
import InputNumber from './InputNumber'
|
||||||
|
|
||||||
export default class FieldMinZoom extends React.Component {
|
type FieldMinZoomProps = {
|
||||||
static propTypes = {
|
value?: number
|
||||||
value: PropTypes.number,
|
onChange(...args: unknown[]): unknown
|
||||||
onChange: PropTypes.func.isRequired,
|
error?: unknown[]
|
||||||
error: PropTypes.object,
|
};
|
||||||
}
|
|
||||||
|
|
||||||
|
export default class FieldMinZoom extends React.Component<FieldMinZoomProps> {
|
||||||
render() {
|
render() {
|
||||||
return <Block label={"Min Zoom"} fieldSpec={latest.layer.minzoom}
|
return <Block label={"Min Zoom"} fieldSpec={latest.layer.minzoom}
|
||||||
error={this.props.error}
|
error={this.props.error}
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import Block from './Block'
|
|
||||||
import InputMultiInput from './InputMultiInput'
|
|
||||||
import Fieldset from './Fieldset'
|
|
||||||
|
|
||||||
|
|
||||||
export default class FieldMultiInput extends React.Component {
|
|
||||||
static propTypes = {
|
|
||||||
...InputMultiInput.propTypes,
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {props} = this;
|
|
||||||
|
|
||||||
return <Fieldset label={props.label}>
|
|
||||||
<InputMultiInput {...props} />
|
|
||||||
</Fieldset>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import InputMultiInput, {InputMultiInputProps} from './InputMultiInput'
|
||||||
|
import Fieldset from './Fieldset'
|
||||||
|
|
||||||
|
|
||||||
|
type FieldMultiInputProps = InputMultiInputProps & {
|
||||||
|
label?: string
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export default class FieldMultiInput extends React.Component<FieldMultiInputProps> {
|
||||||
|
render() {
|
||||||
|
const {props} = this;
|
||||||
|
|
||||||
|
return <Fieldset label={props.label}>
|
||||||
|
<InputMultiInput {...props} />
|
||||||
|
</Fieldset>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import InputNumber from './InputNumber'
|
|
||||||
import Block from './Block'
|
|
||||||
|
|
||||||
|
|
||||||
export default class FieldNumber extends React.Component {
|
|
||||||
static propTypes = {
|
|
||||||
...InputNumber.propTypes,
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {props} = this;
|
|
||||||
return <Block label={props.label}>
|
|
||||||
<InputNumber {...props} />
|
|
||||||
</Block>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import InputNumber, {InputNumberProps} from './InputNumber'
|
||||||
|
import Block from './Block'
|
||||||
|
|
||||||
|
|
||||||
|
type FieldNumberProps = InputNumberProps & {
|
||||||
|
label?: string
|
||||||
|
fieldSpec?: {
|
||||||
|
doc: string
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export default class FieldNumber extends React.Component<FieldNumberProps> {
|
||||||
|
render() {
|
||||||
|
return <Block label={this.props.label} fieldSpec={this.props.fieldSpec}>
|
||||||
|
<InputNumber {...this.props} />
|
||||||
|
</Block>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import Block from './Block'
|
|
||||||
import InputSelect from './InputSelect'
|
|
||||||
|
|
||||||
|
|
||||||
export default class FieldSelect extends React.Component {
|
|
||||||
static propTypes = {
|
|
||||||
...InputSelect.propTypes,
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {props} = this;
|
|
||||||
|
|
||||||
return <Block label={props.label}>
|
|
||||||
<InputSelect {...props}/>
|
|
||||||
</Block>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import Block from './Block'
|
||||||
|
import InputSelect, {InputSelectProps} from './InputSelect'
|
||||||
|
|
||||||
|
|
||||||
|
type FieldSelectProps = InputSelectProps & {
|
||||||
|
label?: string
|
||||||
|
fieldSpec?: {
|
||||||
|
doc: string
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export default class FieldSelect extends React.Component<FieldSelectProps> {
|
||||||
|
render() {
|
||||||
|
return <Block label={this.props.label} fieldSpec={this.props.fieldSpec}>
|
||||||
|
<InputSelect {...this.props}/>
|
||||||
|
</Block>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import Block from './Block'
|
|
||||||
import InputString from './InputString'
|
|
||||||
|
|
||||||
export default class FieldString extends React.Component {
|
|
||||||
static propTypes = {
|
|
||||||
...InputString.propTypes,
|
|
||||||
name: PropTypes.string,
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {props} = this;
|
|
||||||
|
|
||||||
return <Block label={props.label}>
|
|
||||||
<InputString {...props} />
|
|
||||||
</Block>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import Block from './Block'
|
||||||
|
import InputString, {InputStringProps} from './InputString'
|
||||||
|
|
||||||
|
type FieldStringProps = InputStringProps & {
|
||||||
|
name?: string
|
||||||
|
label?: string
|
||||||
|
fieldSpec?: {
|
||||||
|
doc: string
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class FieldString extends React.Component<FieldStringProps> {
|
||||||
|
render() {
|
||||||
|
return <Block label={this.props.label} fieldSpec={this.props.fieldSpec}>
|
||||||
|
<InputString {...this.props} />
|
||||||
|
</Block>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,20 +1,19 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
import {latest} from '@maplibre/maplibre-gl-style-spec'
|
import {latest} from '@maplibre/maplibre-gl-style-spec'
|
||||||
import Block from './Block'
|
import Block from './Block'
|
||||||
import InputSelect from './InputSelect'
|
import InputSelect from './InputSelect'
|
||||||
import InputString from './InputString'
|
import InputString from './InputString'
|
||||||
|
|
||||||
export default class FieldType extends React.Component {
|
type FieldTypeProps = {
|
||||||
static propTypes = {
|
value: string
|
||||||
value: PropTypes.string.isRequired,
|
wdKey?: string
|
||||||
wdKey: PropTypes.string,
|
onChange(...args: unknown[]): unknown
|
||||||
onChange: PropTypes.func.isRequired,
|
error?: unknown[] | undefined
|
||||||
error: PropTypes.object,
|
disabled?: boolean
|
||||||
disabled: PropTypes.bool,
|
};
|
||||||
}
|
|
||||||
|
|
||||||
|
export default class FieldType extends React.Component<FieldTypeProps> {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
import React, {Fragment} from 'react'
|
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import InputUrl from './InputUrl'
|
|
||||||
import Block from './Block'
|
|
||||||
|
|
||||||
|
|
||||||
export default class FieldUrl extends React.Component {
|
|
||||||
static propTypes = {
|
|
||||||
...InputUrl.propTypes,
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const {props} = this;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Block label={this.props.label}>
|
|
||||||
<InputUrl {...props} />
|
|
||||||
</Block>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import InputUrl, {FieldUrlProps as InputUrlProps} from './InputUrl'
|
||||||
|
import Block from './Block'
|
||||||
|
|
||||||
|
|
||||||
|
type FieldUrlProps = InputUrlProps & {
|
||||||
|
label: string;
|
||||||
|
fieldSpec?: {
|
||||||
|
doc: string
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export default class FieldUrl extends React.Component<FieldUrlProps> {
|
||||||
|
render () {
|
||||||
|
return (
|
||||||
|
<Block label={this.props.label} fieldSpec={this.props.fieldSpec}>
|
||||||
|
<InputUrl {...this.props} />
|
||||||
|
</Block>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,13 +1,23 @@
|
|||||||
import React from 'react'
|
import React, { ReactElement } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import FieldDocLabel from './FieldDocLabel'
|
import FieldDocLabel from './FieldDocLabel'
|
||||||
import Doc from './Doc'
|
import Doc from './Doc'
|
||||||
|
|
||||||
|
type FieldsetProps = {
|
||||||
|
label?: string,
|
||||||
|
fieldSpec?: { doc?: string },
|
||||||
|
action?: ReactElement,
|
||||||
|
};
|
||||||
|
|
||||||
|
type FieldsetState = {
|
||||||
|
showDoc: boolean
|
||||||
|
};
|
||||||
|
|
||||||
let IDX = 0;
|
let IDX = 0;
|
||||||
|
|
||||||
export default class Fieldset extends React.Component {
|
export default class Fieldset extends React.Component<FieldsetProps, FieldsetState> {
|
||||||
constructor (props) {
|
_labelId: string;
|
||||||
|
|
||||||
|
constructor (props: FieldsetProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this._labelId = `fieldset_label_${(IDX++)}`;
|
this._labelId = `fieldset_label_${(IDX++)}`;
|
||||||
this.state = {
|
this.state = {
|
||||||
@@ -15,15 +25,13 @@ export default class Fieldset extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onToggleDoc = (val) => {
|
onToggleDoc = (val: boolean) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
showDoc: val
|
showDoc: val
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const {props} = this;
|
|
||||||
|
|
||||||
return <div className="maputnik-input-block" role="group" aria-labelledby={this._labelId}>
|
return <div className="maputnik-input-block" role="group" aria-labelledby={this._labelId}>
|
||||||
{this.props.fieldSpec &&
|
{this.props.fieldSpec &&
|
||||||
<div className="maputnik-input-block-label">
|
<div className="maputnik-input-block-label">
|
||||||
@@ -36,14 +44,14 @@ export default class Fieldset extends React.Component {
|
|||||||
}
|
}
|
||||||
{!this.props.fieldSpec &&
|
{!this.props.fieldSpec &&
|
||||||
<div className="maputnik-input-block-label">
|
<div className="maputnik-input-block-label">
|
||||||
{props.label}
|
{this.props.label}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
<div className="maputnik-input-block-action">
|
<div className="maputnik-input-block-action">
|
||||||
{this.props.action}
|
{this.props.action}
|
||||||
</div>
|
</div>
|
||||||
<div className="maputnik-input-block-content">
|
<div className="maputnik-input-block-content">
|
||||||
{props.children}
|
{this.props.children}
|
||||||
</div>
|
</div>
|
||||||
{this.props.fieldSpec &&
|
{this.props.fieldSpec &&
|
||||||
<div
|
<div
|
||||||
@@ -1,14 +1,12 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import InputButton from './InputButton'
|
import InputButton from './InputButton'
|
||||||
import {MdDelete} from 'react-icons/md'
|
import {MdDelete} from 'react-icons/md'
|
||||||
|
|
||||||
export default class FilterEditorBlock extends React.Component {
|
type FilterEditorBlockProps = {
|
||||||
static propTypes = {
|
onDelete(...args: unknown[]): unknown
|
||||||
onDelete: PropTypes.func.isRequired,
|
};
|
||||||
children: PropTypes.element.isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
export default class FilterEditorBlock extends React.Component<FilterEditorBlockProps> {
|
||||||
render() {
|
render() {
|
||||||
return <div className="maputnik-filter-editor-block">
|
return <div className="maputnik-filter-editor-block">
|
||||||
<div className="maputnik-filter-editor-block-action">
|
<div className="maputnik-filter-editor-block-action">
|
||||||
@@ -1,19 +1,18 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
import IconLine from './IconLine.jsx'
|
import IconLine from './IconLine'
|
||||||
import IconFill from './IconFill.jsx'
|
import IconFill from './IconFill'
|
||||||
import IconSymbol from './IconSymbol.jsx'
|
import IconSymbol from './IconSymbol'
|
||||||
import IconBackground from './IconBackground.jsx'
|
import IconBackground from './IconBackground'
|
||||||
import IconCircle from './IconCircle.jsx'
|
import IconCircle from './IconCircle'
|
||||||
import IconMissing from './IconMissing.jsx'
|
import IconMissing from './IconMissing'
|
||||||
|
|
||||||
export default class IconLayer extends React.Component {
|
type IconLayerProps = {
|
||||||
static propTypes = {
|
type: string
|
||||||
type: PropTypes.string.isRequired,
|
style?: object
|
||||||
style: PropTypes.object,
|
};
|
||||||
}
|
|
||||||
|
|
||||||
|
export default class IconLayer extends React.Component<IconLayerProps> {
|
||||||
render() {
|
render() {
|
||||||
const iconProps = { style: this.props.style }
|
const iconProps = { style: this.props.style }
|
||||||
switch(this.props.type) {
|
switch(this.props.type) {
|
||||||
@@ -1,24 +1,29 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import InputString from './InputString'
|
import InputString from './InputString'
|
||||||
import InputNumber from './InputNumber'
|
import InputNumber from './InputNumber'
|
||||||
|
|
||||||
export default class FieldArray extends React.Component {
|
export type FieldArrayProps = {
|
||||||
static propTypes = {
|
value: string[] | number[]
|
||||||
value: PropTypes.array,
|
type?: string
|
||||||
type: PropTypes.string,
|
length?: number
|
||||||
length: PropTypes.number,
|
default?: string[] | number[]
|
||||||
default: PropTypes.array,
|
onChange?(...args: unknown[]): unknown
|
||||||
onChange: PropTypes.func,
|
'aria-label'?: string
|
||||||
'aria-label': PropTypes.string,
|
label?: string
|
||||||
}
|
};
|
||||||
|
|
||||||
|
type FieldArrayState = {
|
||||||
|
value: string[] | number[]
|
||||||
|
initialPropsValue: unknown[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class FieldArray extends React.Component<FieldArrayProps, FieldArrayState> {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
value: [],
|
value: [],
|
||||||
default: [],
|
default: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor (props) {
|
constructor (props: FieldArrayProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
value: this.props.value.slice(0),
|
value: this.props.value.slice(0),
|
||||||
@@ -27,8 +32,8 @@ export default class FieldArray extends React.Component {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static getDerivedStateFromProps(props, state) {
|
static getDerivedStateFromProps(props: FieldArrayProps, state: FieldArrayState) {
|
||||||
const value = [];
|
const value: any[] = [];
|
||||||
const initialPropsValue = state.initialPropsValue.slice(0);
|
const initialPropsValue = state.initialPropsValue.slice(0);
|
||||||
|
|
||||||
Array(props.length).fill(null).map((_, i) => {
|
Array(props.length).fill(null).map((_, i) => {
|
||||||
@@ -47,24 +52,24 @@ export default class FieldArray extends React.Component {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
isComplete (value) {
|
isComplete(value: unknown[]) {
|
||||||
return Array(this.props.length).fill(null).every((_, i) => {
|
return Array(this.props.length).fill(null).every((_, i) => {
|
||||||
const val = value[i]
|
const val = value[i]
|
||||||
return !(val === undefined || val === "");
|
return !(val === undefined || val === "");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
changeValue(idx, newValue) {
|
changeValue(idx: number, newValue: string) {
|
||||||
const value = this.state.value.slice(0);
|
const value = this.state.value.slice(0);
|
||||||
value[idx] = newValue;
|
value[idx] = newValue;
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
value,
|
value,
|
||||||
}, () => {
|
}, () => {
|
||||||
if (this.isComplete(value)) {
|
if (this.isComplete(value) && this.props.onChange) {
|
||||||
this.props.onChange(value);
|
this.props.onChange(value);
|
||||||
}
|
}
|
||||||
else {
|
else if (this.props.onChange){
|
||||||
// Unset until complete
|
// Unset until complete
|
||||||
this.props.onChange(undefined);
|
this.props.onChange(undefined);
|
||||||
}
|
}
|
||||||
@@ -85,8 +90,8 @@ export default class FieldArray extends React.Component {
|
|||||||
if(this.props.type === 'number') {
|
if(this.props.type === 'number') {
|
||||||
return <InputNumber
|
return <InputNumber
|
||||||
key={i}
|
key={i}
|
||||||
default={containsValues ? undefined : this.props.default[i]}
|
default={containsValues || !this.props.default ? undefined : this.props.default[i] as number}
|
||||||
value={value[i]}
|
value={value[i] as number}
|
||||||
required={containsValues ? true : false}
|
required={containsValues ? true : false}
|
||||||
onChange={this.changeValue.bind(this, i)}
|
onChange={this.changeValue.bind(this, i)}
|
||||||
aria-label={this.props['aria-label'] || this.props.label}
|
aria-label={this.props['aria-label'] || this.props.label}
|
||||||
@@ -94,8 +99,8 @@ export default class FieldArray extends React.Component {
|
|||||||
} else {
|
} else {
|
||||||
return <InputString
|
return <InputString
|
||||||
key={i}
|
key={i}
|
||||||
default={containsValues ? undefined : this.props.default[i]}
|
default={containsValues || !this.props.default ? undefined : this.props.default[i] as string}
|
||||||
value={value[i]}
|
value={value[i] as string}
|
||||||
required={containsValues ? true : false}
|
required={containsValues ? true : false}
|
||||||
onChange={this.changeValue.bind(this, i)}
|
onChange={this.changeValue.bind(this, i)}
|
||||||
aria-label={this.props['aria-label'] || this.props.label}
|
aria-label={this.props['aria-label'] || this.props.label}
|
||||||
@@ -1,24 +1,25 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import Autocomplete from 'react-autocomplete'
|
import Autocomplete from 'react-autocomplete'
|
||||||
|
|
||||||
|
|
||||||
const MAX_HEIGHT = 140;
|
const MAX_HEIGHT = 140;
|
||||||
|
|
||||||
export default class InputAutocomplete extends React.Component {
|
export type InputAutocompleteProps = {
|
||||||
static propTypes = {
|
value?: string
|
||||||
value: PropTypes.string,
|
options: any[]
|
||||||
options: PropTypes.array,
|
onChange(...args: unknown[]): unknown
|
||||||
onChange: PropTypes.func,
|
keepMenuWithinWindowBounds?: boolean
|
||||||
keepMenuWithinWindowBounds: PropTypes.bool,
|
'aria-label'?: string
|
||||||
'aria-label': PropTypes.string,
|
};
|
||||||
}
|
|
||||||
|
|
||||||
|
export default class InputAutocomplete extends React.Component<InputAutocompleteProps> {
|
||||||
state = {
|
state = {
|
||||||
maxHeight: MAX_HEIGHT
|
maxHeight: MAX_HEIGHT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
autocompleteMenuEl: HTMLDivElement | null = null;
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
onChange: () => {},
|
onChange: () => {},
|
||||||
options: [],
|
options: [],
|
||||||
@@ -26,7 +27,7 @@ export default class InputAutocomplete extends React.Component {
|
|||||||
|
|
||||||
calcMaxHeight() {
|
calcMaxHeight() {
|
||||||
if(this.props.keepMenuWithinWindowBounds) {
|
if(this.props.keepMenuWithinWindowBounds) {
|
||||||
const maxHeight = window.innerHeight - this.autocompleteMenuEl.getBoundingClientRect().top;
|
const maxHeight = window.innerHeight - this.autocompleteMenuEl!.getBoundingClientRect().top;
|
||||||
const limitedMaxHeight = Math.min(maxHeight, MAX_HEIGHT);
|
const limitedMaxHeight = Math.min(maxHeight, MAX_HEIGHT);
|
||||||
|
|
||||||
if(limitedMaxHeight != this.state.maxHeight) {
|
if(limitedMaxHeight != this.state.maxHeight) {
|
||||||
@@ -45,7 +46,7 @@ export default class InputAutocomplete extends React.Component {
|
|||||||
this.calcMaxHeight();
|
this.calcMaxHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
onChange (v) {
|
onChange(v: string) {
|
||||||
this.props.onChange(v === "" ? undefined : v);
|
this.props.onChange(v === "" ? undefined : v);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +65,7 @@ export default class InputAutocomplete extends React.Component {
|
|||||||
}}
|
}}
|
||||||
wrapperProps={{
|
wrapperProps={{
|
||||||
className: "maputnik-autocomplete",
|
className: "maputnik-autocomplete",
|
||||||
style: null
|
style: {}
|
||||||
}}
|
}}
|
||||||
inputProps={{
|
inputProps={{
|
||||||
'aria-label': this.props['aria-label'],
|
'aria-label': this.props['aria-label'],
|
||||||
@@ -75,11 +76,12 @@ export default class InputAutocomplete extends React.Component {
|
|||||||
items={this.props.options}
|
items={this.props.options}
|
||||||
getItemValue={(item) => item[0]}
|
getItemValue={(item) => item[0]}
|
||||||
onSelect={v => this.onChange(v)}
|
onSelect={v => this.onChange(v)}
|
||||||
onChange={(e, v) => this.onChange(v)}
|
onChange={(_e, v) => this.onChange(v)}
|
||||||
shouldItemRender={(item, value="") => {
|
shouldItemRender={(item, value="") => {
|
||||||
if (typeof(value) === "string") {
|
if (typeof(value) === "string") {
|
||||||
return item[0].toLowerCase().indexOf(value.toLowerCase()) > -1
|
return item[0].toLowerCase().indexOf(value.toLowerCase()) > -1
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
}}
|
}}
|
||||||
renderItem={(item, isHighlighted) => (
|
renderItem={(item, isHighlighted) => (
|
||||||
<div
|
<div
|
||||||
@@ -1,21 +1,20 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
|
|
||||||
export default class InputButton extends React.Component {
|
type InputButtonProps = {
|
||||||
static propTypes = {
|
"data-wd-key"?: string
|
||||||
"data-wd-key": PropTypes.string,
|
"aria-label"?: string
|
||||||
"aria-label": PropTypes.string,
|
onClick?(...args: unknown[]): unknown
|
||||||
onClick: PropTypes.func,
|
style?: object
|
||||||
style: PropTypes.object,
|
className?: string
|
||||||
className: PropTypes.string,
|
children?: React.ReactNode
|
||||||
children: PropTypes.node,
|
disabled?: boolean
|
||||||
disabled: PropTypes.bool,
|
type?: typeof HTMLButtonElement.prototype.type
|
||||||
type: PropTypes.string,
|
id?: string
|
||||||
id: PropTypes.string,
|
title?: string
|
||||||
title: PropTypes.string,
|
};
|
||||||
}
|
|
||||||
|
|
||||||
|
export default class InputButton extends React.Component<InputButtonProps> {
|
||||||
render() {
|
render() {
|
||||||
return <button
|
return <button
|
||||||
id={this.props.id}
|
id={this.props.id}
|
||||||
@@ -32,4 +31,3 @@ export default class InputButton extends React.Component {
|
|||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,13 +1,12 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
export default class InputCheckbox extends React.Component {
|
export type InputCheckboxProps = {
|
||||||
static propTypes = {
|
value?: boolean
|
||||||
value: PropTypes.bool,
|
style?: object
|
||||||
style: PropTypes.object,
|
onChange(...args: unknown[]): unknown
|
||||||
onChange: PropTypes.func,
|
};
|
||||||
}
|
|
||||||
|
|
||||||
|
export default class InputCheckbox extends React.Component<InputCheckboxProps> {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
value: false,
|
value: false,
|
||||||
}
|
}
|
||||||
@@ -36,4 +35,3 @@ export default class InputCheckbox extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,36 +1,37 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import Color from 'color'
|
import Color from 'color'
|
||||||
import ChromePicker from 'react-color/lib/components/chrome/Chrome'
|
import ChromePicker from 'react-color/lib/components/chrome/Chrome'
|
||||||
import PropTypes from 'prop-types'
|
import {ColorResult} from 'react-color';
|
||||||
import lodash from 'lodash';
|
import lodash from 'lodash';
|
||||||
|
|
||||||
function formatColor(color) {
|
function formatColor(color: ColorResult): string {
|
||||||
const rgb = color.rgb
|
const rgb = color.rgb
|
||||||
return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${rgb.a})`
|
return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${rgb.a})`
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** Number fields with support for min, max and units and documentation*/
|
export type InputColorProps = {
|
||||||
export default class InputColor extends React.Component {
|
onChange(...args: unknown[]): unknown
|
||||||
static propTypes = {
|
name?: string
|
||||||
onChange: PropTypes.func.isRequired,
|
value?: string
|
||||||
name: PropTypes.string,
|
doc?: string
|
||||||
value: PropTypes.string,
|
style?: object
|
||||||
doc: PropTypes.string,
|
default?: string
|
||||||
style: PropTypes.object,
|
'aria-label'?: string
|
||||||
default: PropTypes.string,
|
};
|
||||||
'aria-label': PropTypes.string,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/*** Number fields with support for min, max and units and documentation*/
|
||||||
|
export default class InputColor extends React.Component<InputColorProps> {
|
||||||
state = {
|
state = {
|
||||||
pickerOpened: false
|
pickerOpened: false
|
||||||
}
|
}
|
||||||
|
colorInput: HTMLInputElement | null = null;
|
||||||
|
|
||||||
constructor () {
|
constructor (props: InputColorProps) {
|
||||||
super();
|
super(props);
|
||||||
this.onChangeNoCheck = lodash.throttle(this.onChangeNoCheck, 1000/30);
|
this.onChangeNoCheck = lodash.throttle(this.onChangeNoCheck, 1000/30);
|
||||||
}
|
}
|
||||||
|
|
||||||
onChangeNoCheck (v) {
|
onChangeNoCheck(v: string) {
|
||||||
this.props.onChange(v);
|
this.props.onChange(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,31 +69,31 @@ export default class InputColor extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onChange (v) {
|
onChange (v: string) {
|
||||||
this.props.onChange(v === "" ? undefined : v);
|
this.props.onChange(v === "" ? undefined : v);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const offset = this.calcPickerOffset()
|
const offset = this.calcPickerOffset()
|
||||||
var currentColor = this.color.object()
|
const currentColor = this.color.object();
|
||||||
currentColor = {
|
const currentChromeColor = {
|
||||||
r: currentColor.r,
|
r: currentColor.r,
|
||||||
g: currentColor.g,
|
g: currentColor.g,
|
||||||
b: currentColor.b,
|
b: currentColor.b,
|
||||||
// Rename alpha -> a for ChromePicker
|
// Rename alpha -> a for ChromePicker
|
||||||
a: currentColor.alpha
|
a: currentColor.alpha!
|
||||||
}
|
}
|
||||||
|
|
||||||
const picker = <div
|
const picker = <div
|
||||||
className="maputnik-color-picker-offset"
|
className="maputnik-color-picker-offset"
|
||||||
style={{
|
style={{
|
||||||
position: 'fixed',
|
position: 'fixed',
|
||||||
zIndex: 1,
|
zIndex: 1,
|
||||||
left: offset.left,
|
left: offset.left,
|
||||||
top: offset.top,
|
top: offset.top,
|
||||||
}}>
|
}}>
|
||||||
<ChromePicker
|
<ChromePicker
|
||||||
color={currentColor}
|
color={currentChromeColor}
|
||||||
onChange={c => this.onChangeNoCheck(formatColor(c))}
|
onChange={c => this.onChangeNoCheck(formatColor(c))}
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
@@ -1,30 +1,34 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import capitalize from 'lodash.capitalize'
|
||||||
|
import {MdDelete} from 'react-icons/md'
|
||||||
|
|
||||||
import InputString from './InputString'
|
import InputString from './InputString'
|
||||||
import InputNumber from './InputNumber'
|
import InputNumber from './InputNumber'
|
||||||
import InputButton from './InputButton'
|
import InputButton from './InputButton'
|
||||||
import {MdDelete} from 'react-icons/md'
|
|
||||||
import FieldDocLabel from './FieldDocLabel'
|
import FieldDocLabel from './FieldDocLabel'
|
||||||
import InputEnum from './InputEnum'
|
import InputEnum from './InputEnum'
|
||||||
import capitalize from 'lodash.capitalize'
|
|
||||||
import InputUrl from './InputUrl'
|
import InputUrl from './InputUrl'
|
||||||
|
|
||||||
|
|
||||||
export default class FieldDynamicArray extends React.Component {
|
export type FieldDynamicArrayProps = {
|
||||||
static propTypes = {
|
value?: (string | number)[]
|
||||||
value: PropTypes.array,
|
type?: 'url' | 'number' | 'enum'
|
||||||
type: PropTypes.string,
|
default?: (string | number)[]
|
||||||
default: PropTypes.array,
|
onChange?(...args: unknown[]): unknown
|
||||||
onChange: PropTypes.func,
|
style?: object
|
||||||
style: PropTypes.object,
|
fieldSpec?: {
|
||||||
fieldSpec: PropTypes.object,
|
values?: any
|
||||||
'aria-label': PropTypes.string,
|
|
||||||
}
|
}
|
||||||
|
'aria-label'?: string
|
||||||
|
label: string
|
||||||
|
};
|
||||||
|
|
||||||
changeValue(idx, newValue) {
|
|
||||||
|
export default class FieldDynamicArray extends React.Component<FieldDynamicArrayProps> {
|
||||||
|
changeValue(idx: number, newValue: string | number) {
|
||||||
const values = this.values.slice(0)
|
const values = this.values.slice(0)
|
||||||
values[idx] = newValue
|
values[idx] = newValue
|
||||||
this.props.onChange(values)
|
if (this.props.onChange) this.props.onChange(values)
|
||||||
}
|
}
|
||||||
|
|
||||||
get values() {
|
get values() {
|
||||||
@@ -41,20 +45,20 @@ export default class FieldDynamicArray extends React.Component {
|
|||||||
}
|
}
|
||||||
else if (this.props.type === 'enum') {
|
else if (this.props.type === 'enum') {
|
||||||
const {fieldSpec} = this.props;
|
const {fieldSpec} = this.props;
|
||||||
const defaultValue = Object.keys(fieldSpec.values)[0];
|
const defaultValue = Object.keys(fieldSpec!.values)[0];
|
||||||
values.push(defaultValue);
|
values.push(defaultValue);
|
||||||
} else {
|
} else {
|
||||||
values.push("")
|
values.push("")
|
||||||
}
|
}
|
||||||
|
|
||||||
this.props.onChange(values)
|
if (this.props.onChange) this.props.onChange(values)
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteValue(valueIdx) {
|
deleteValue(valueIdx: number) {
|
||||||
const values = this.values.slice(0)
|
const values = this.values.slice(0)
|
||||||
values.splice(valueIdx, 1)
|
values.splice(valueIdx, 1)
|
||||||
|
|
||||||
this.props.onChange(values.length > 0 ? values : undefined);
|
if (this.props.onChange) this.props.onChange(values.length > 0 ? values : undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@@ -63,30 +67,30 @@ export default class FieldDynamicArray extends React.Component {
|
|||||||
let input;
|
let input;
|
||||||
if(this.props.type === 'url') {
|
if(this.props.type === 'url') {
|
||||||
input = <InputUrl
|
input = <InputUrl
|
||||||
value={v}
|
value={v as string}
|
||||||
onChange={this.changeValue.bind(this, i)}
|
onChange={this.changeValue.bind(this, i)}
|
||||||
aria-label={this.props['aria-label'] || this.props.label}
|
aria-label={this.props['aria-label'] || this.props.label}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
else if (this.props.type === 'number') {
|
else if (this.props.type === 'number') {
|
||||||
input = <InputNumber
|
input = <InputNumber
|
||||||
value={v}
|
value={v as number}
|
||||||
onChange={this.changeValue.bind(this, i)}
|
onChange={this.changeValue.bind(this, i)}
|
||||||
aria-label={this.props['aria-label'] || this.props.label}
|
aria-label={this.props['aria-label'] || this.props.label}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
else if (this.props.type === 'enum') {
|
else if (this.props.type === 'enum') {
|
||||||
const options = Object.keys(this.props.fieldSpec.values).map(v => [v, capitalize(v)]);
|
const options = Object.keys(this.props.fieldSpec?.values).map(v => [v, capitalize(v)]);
|
||||||
input = <InputEnum
|
input = <InputEnum
|
||||||
options={options}
|
options={options}
|
||||||
value={v}
|
value={v as string}
|
||||||
onChange={this.changeValue.bind(this, i)}
|
onChange={this.changeValue.bind(this, i)}
|
||||||
aria-label={this.props['aria-label'] || this.props.label}
|
aria-label={this.props['aria-label'] || this.props.label}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
input = <InputString
|
input = <InputString
|
||||||
value={v}
|
value={v as string}
|
||||||
onChange={this.changeValue.bind(this, i)}
|
onChange={this.changeValue.bind(this, i)}
|
||||||
aria-label={this.props['aria-label'] || this.props.label}
|
aria-label={this.props['aria-label'] || this.props.label}
|
||||||
/>
|
/>
|
||||||
@@ -120,11 +124,11 @@ export default class FieldDynamicArray extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DeleteValueInputButton extends React.Component {
|
type DeleteValueInputButtonProps = {
|
||||||
static propTypes = {
|
onClick?(...args: unknown[]): unknown
|
||||||
onClick: PropTypes.func,
|
};
|
||||||
}
|
|
||||||
|
|
||||||
|
class DeleteValueInputButton extends React.Component<DeleteValueInputButtonProps> {
|
||||||
render() {
|
render() {
|
||||||
return <InputButton
|
return <InputButton
|
||||||
className="maputnik-delete-stop"
|
className="maputnik-delete-stop"
|
||||||
@@ -133,7 +137,7 @@ class DeleteValueInputButton extends React.Component {
|
|||||||
>
|
>
|
||||||
<FieldDocLabel
|
<FieldDocLabel
|
||||||
label={<MdDelete />}
|
label={<MdDelete />}
|
||||||
doc={"Remove array item."}
|
fieldSpec={{doc:" Remove array item."}}
|
||||||
/>
|
/>
|
||||||
</InputButton>
|
</InputButton>
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import InputSelect from './InputSelect'
|
import InputSelect from './InputSelect'
|
||||||
import InputMultiInput from './InputMultiInput'
|
import InputMultiInput from './InputMultiInput'
|
||||||
|
|
||||||
|
|
||||||
function optionsLabelLength(options) {
|
function optionsLabelLength(options: any[]) {
|
||||||
let sum = 0;
|
let sum = 0;
|
||||||
options.forEach(([_, label]) => {
|
options.forEach(([_, label]) => {
|
||||||
sum += label.length
|
sum += label.length
|
||||||
@@ -13,18 +12,20 @@ function optionsLabelLength(options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export default class InputEnum extends React.Component {
|
export type InputEnumProps = {
|
||||||
static propTypes = {
|
"data-wd-key"?: string
|
||||||
"data-wd-key": PropTypes.string,
|
value?: string
|
||||||
value: PropTypes.string,
|
style?: object
|
||||||
style: PropTypes.object,
|
default?: string
|
||||||
default: PropTypes.string,
|
name?: string
|
||||||
name: PropTypes.string,
|
onChange(...args: unknown[]): unknown
|
||||||
onChange: PropTypes.func,
|
options: any[]
|
||||||
options: PropTypes.array,
|
'aria-label'?: string
|
||||||
'aria-label': PropTypes.string,
|
label?: string
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export default class InputEnum extends React.Component<InputEnumProps> {
|
||||||
render() {
|
render() {
|
||||||
const {options, value, onChange, name, label} = this.props;
|
const {options, value, onChange, name, label} = this.props;
|
||||||
|
|
||||||
@@ -32,14 +33,14 @@ export default class InputEnum extends React.Component {
|
|||||||
return <InputMultiInput
|
return <InputMultiInput
|
||||||
name={name}
|
name={name}
|
||||||
options={options}
|
options={options}
|
||||||
value={value || this.props.default}
|
value={(value || this.props.default)!}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
aria-label={this.props['aria-label'] || label}
|
aria-label={this.props['aria-label'] || label}
|
||||||
/>
|
/>
|
||||||
} else {
|
} else {
|
||||||
return <InputSelect
|
return <InputSelect
|
||||||
options={options}
|
options={options}
|
||||||
value={value || this.props.default}
|
value={(value || this.props.default)!}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
aria-label={this.props['aria-label'] || label}
|
aria-label={this.props['aria-label'] || label}
|
||||||
/>
|
/>
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import InputAutocomplete from './InputAutocomplete'
|
import InputAutocomplete from './InputAutocomplete'
|
||||||
|
|
||||||
export default class FieldFont extends React.Component {
|
export type FieldFontProps = {
|
||||||
static propTypes = {
|
name: string
|
||||||
value: PropTypes.array,
|
value?: string[]
|
||||||
default: PropTypes.array,
|
default?: string[]
|
||||||
fonts: PropTypes.array,
|
fonts?: unknown[]
|
||||||
style: PropTypes.object,
|
style?: object
|
||||||
onChange: PropTypes.func.isRequired,
|
onChange(...args: unknown[]): unknown
|
||||||
'aria-label': PropTypes.string,
|
'aria-label'?: string
|
||||||
}
|
};
|
||||||
|
|
||||||
|
export default class FieldFont extends React.Component<FieldFontProps> {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
fonts: []
|
fonts: []
|
||||||
}
|
}
|
||||||
@@ -28,7 +28,7 @@ export default class FieldFont extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
changeFont(idx, newValue) {
|
changeFont(idx: number, newValue: string) {
|
||||||
const changedValues = this.values.slice(0)
|
const changedValues = this.values.slice(0)
|
||||||
changedValues[idx] = newValue
|
changedValues[idx] = newValue
|
||||||
const filteredValues = changedValues
|
const filteredValues = changedValues
|
||||||
@@ -46,7 +46,7 @@ export default class FieldFont extends React.Component {
|
|||||||
<InputAutocomplete
|
<InputAutocomplete
|
||||||
aria-label={this.props['aria-label'] || this.props.name}
|
aria-label={this.props['aria-label'] || this.props.name}
|
||||||
value={value}
|
value={value}
|
||||||
options={this.props.fonts.map(f => [f, f])}
|
options={this.props.fonts?.map(f => [f, f])}
|
||||||
onChange={this.changeFont.bind(this, i)}
|
onChange={this.changeFont.bind(this, i)}
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
@@ -1,47 +1,45 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
|
import CodeMirror, { ModeSpec } from 'codemirror';
|
||||||
import Block from './Block'
|
|
||||||
import FieldString from './FieldString'
|
|
||||||
import CodeMirror from 'codemirror';
|
|
||||||
|
|
||||||
import 'codemirror/mode/javascript/javascript'
|
import 'codemirror/mode/javascript/javascript'
|
||||||
import 'codemirror/addon/lint/lint'
|
import 'codemirror/addon/lint/lint'
|
||||||
import 'codemirror/addon/edit/matchbrackets'
|
import 'codemirror/addon/edit/matchbrackets'
|
||||||
import 'codemirror/lib/codemirror.css'
|
import 'codemirror/lib/codemirror.css'
|
||||||
import 'codemirror/addon/lint/lint.css'
|
import 'codemirror/addon/lint/lint.css'
|
||||||
import jsonlint from 'jsonlint'
|
|
||||||
import stringifyPretty from 'json-stringify-pretty-compact'
|
import stringifyPretty from 'json-stringify-pretty-compact'
|
||||||
import '../util/codemirror-mgl';
|
import '../util/codemirror-mgl';
|
||||||
|
|
||||||
|
|
||||||
export default class InputJson extends React.Component {
|
export type InputJsonProps = {
|
||||||
static propTypes = {
|
layer: any
|
||||||
layer: PropTypes.any.isRequired,
|
maxHeight?: number
|
||||||
maxHeight: PropTypes.number,
|
onChange?(...args: unknown[]): unknown
|
||||||
onChange: PropTypes.func,
|
lineNumbers?: boolean
|
||||||
lineNumbers: PropTypes.bool,
|
lineWrapping?: boolean
|
||||||
lineWrapping: PropTypes.bool,
|
getValue(data: any): string
|
||||||
getValue: PropTypes.func,
|
gutters?: string[]
|
||||||
gutters: PropTypes.array,
|
className?: string
|
||||||
className: PropTypes.string,
|
onFocus?(...args: unknown[]): unknown
|
||||||
onFocus: PropTypes.func,
|
onBlur?(...args: unknown[]): unknown
|
||||||
onBlur: PropTypes.func,
|
onJSONValid?(...args: unknown[]): unknown
|
||||||
onJSONValid: PropTypes.func,
|
onJSONInvalid?(...args: unknown[]): unknown
|
||||||
onJSONInvalid: PropTypes.func,
|
mode?: ModeSpec<any>
|
||||||
mode: PropTypes.object,
|
lint?: boolean | object
|
||||||
lint: PropTypes.oneOfType([
|
};
|
||||||
PropTypes.bool,
|
|
||||||
PropTypes.object,
|
|
||||||
]),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
type InputJsonState = {
|
||||||
|
isEditing: boolean
|
||||||
|
showMessage: boolean
|
||||||
|
prevValue: string
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class InputJson extends React.Component<InputJsonProps, InputJsonState> {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
lineNumbers: true,
|
lineNumbers: true,
|
||||||
lineWrapping: false,
|
lineWrapping: false,
|
||||||
gutters: ["CodeMirror-lint-markers"],
|
gutters: ["CodeMirror-lint-markers"],
|
||||||
getValue: (data) => {
|
getValue: (data: any) => {
|
||||||
return stringifyPretty(data, {indent: 2, maxLength: 40});
|
return stringifyPretty(data, {indent: 2, maxLength: 40});
|
||||||
},
|
},
|
||||||
onFocus: () => {},
|
onFocus: () => {},
|
||||||
@@ -49,8 +47,12 @@ export default class InputJson extends React.Component {
|
|||||||
onJSONInvalid: () => {},
|
onJSONInvalid: () => {},
|
||||||
onJSONValid: () => {},
|
onJSONValid: () => {},
|
||||||
}
|
}
|
||||||
|
_keyEvent: string;
|
||||||
|
_doc: CodeMirror.Editor | undefined;
|
||||||
|
_el: HTMLDivElement | null = null;
|
||||||
|
_cancelNextChange: boolean = false;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props: InputJsonProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this._keyEvent = "keyboard";
|
this._keyEvent = "keyboard";
|
||||||
this.state = {
|
this.state = {
|
||||||
@@ -61,7 +63,7 @@ export default class InputJson extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
this._doc = CodeMirror(this._el, {
|
this._doc = CodeMirror(this._el!, {
|
||||||
value: this.props.getValue(this.props.layer),
|
value: this.props.getValue(this.props.layer),
|
||||||
mode: this.props.mode || {
|
mode: this.props.mode || {
|
||||||
name: "mgl",
|
name: "mgl",
|
||||||
@@ -84,12 +86,12 @@ export default class InputJson extends React.Component {
|
|||||||
this._doc.on('blur', this.onBlur);
|
this._doc.on('blur', this.onBlur);
|
||||||
}
|
}
|
||||||
|
|
||||||
onPointerDown = (cm, e) => {
|
onPointerDown = () => {
|
||||||
this._keyEvent = "pointer";
|
this._keyEvent = "pointer";
|
||||||
}
|
}
|
||||||
|
|
||||||
onFocus = (cm, e) => {
|
onFocus = () => {
|
||||||
this.props.onFocus();
|
if (this.props.onFocus) this.props.onFocus();
|
||||||
this.setState({
|
this.setState({
|
||||||
isEditing: true,
|
isEditing: true,
|
||||||
showMessage: (this._keyEvent === "keyboard"),
|
showMessage: (this._keyEvent === "keyboard"),
|
||||||
@@ -98,7 +100,7 @@ export default class InputJson extends React.Component {
|
|||||||
|
|
||||||
onBlur = () => {
|
onBlur = () => {
|
||||||
this._keyEvent = "keyboard";
|
this._keyEvent = "keyboard";
|
||||||
this.props.onBlur();
|
if (this.props.onBlur) this.props.onBlur();
|
||||||
this.setState({
|
this.setState({
|
||||||
isEditing: false,
|
isEditing: false,
|
||||||
showMessage: false,
|
showMessage: false,
|
||||||
@@ -106,29 +108,29 @@ export default class InputJson extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnMount () {
|
componentWillUnMount () {
|
||||||
this._doc.off('change', this.onChange);
|
this._doc!.off('change', this.onChange);
|
||||||
this._doc.off('focus', this.onFocus);
|
this._doc!.off('focus', this.onFocus);
|
||||||
this._doc.off('blur', this.onBlur);
|
this._doc!.off('blur', this.onBlur);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps: InputJsonProps) {
|
||||||
if (!this.state.isEditing && prevProps.layer !== this.props.layer) {
|
if (!this.state.isEditing && prevProps.layer !== this.props.layer) {
|
||||||
this._cancelNextChange = true;
|
this._cancelNextChange = true;
|
||||||
this._doc.setValue(
|
this._doc!.setValue(
|
||||||
this.props.getValue(this.props.layer),
|
this.props.getValue(this.props.layer),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onChange = (e) => {
|
onChange = (_e: unknown) => {
|
||||||
if (this._cancelNextChange) {
|
if (this._cancelNextChange) {
|
||||||
this._cancelNextChange = false;
|
this._cancelNextChange = false;
|
||||||
this.setState({
|
this.setState({
|
||||||
prevValue: this._doc.getValue(),
|
prevValue: this._doc!.getValue(),
|
||||||
})
|
})
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const newCode = this._doc.getValue();
|
const newCode = this._doc!.getValue();
|
||||||
|
|
||||||
if (this.state.prevValue !== newCode) {
|
if (this.state.prevValue !== newCode) {
|
||||||
let parsedLayer, err;
|
let parsedLayer, err;
|
||||||
@@ -139,12 +141,12 @@ export default class InputJson extends React.Component {
|
|||||||
console.warn(_err)
|
console.warn(_err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err) {
|
if (err && this.props.onJSONInvalid) {
|
||||||
this.props.onJSONInvalid();
|
this.props.onJSONInvalid();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.props.onChange(parsedLayer)
|
if (this.props.onChange) this.props.onChange(parsedLayer)
|
||||||
this.props.onJSONValid();
|
if (this.props.onJSONValid) this.props.onJSONValid();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,7 +157,7 @@ export default class InputJson extends React.Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {showMessage} = this.state;
|
const {showMessage} = this.state;
|
||||||
const style = {};
|
const style = {} as {maxHeight?: number};
|
||||||
if (this.props.maxHeight) {
|
if (this.props.maxHeight) {
|
||||||
style.maxHeight = this.props.maxHeight;
|
style.maxHeight = this.props.maxHeight;
|
||||||
}
|
}
|
||||||
@@ -1,16 +1,15 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import InputButton from './InputButton'
|
|
||||||
|
|
||||||
export default class InputMultiInput extends React.Component {
|
export type InputMultiInputProps = {
|
||||||
static propTypes = {
|
name?: string
|
||||||
name: PropTypes.string.isRequired,
|
value: string
|
||||||
value: PropTypes.string.isRequired,
|
options: any[]
|
||||||
options: PropTypes.array.isRequired,
|
onChange(...args: unknown[]): unknown
|
||||||
onChange: PropTypes.func.isRequired,
|
'aria-label'?: string
|
||||||
}
|
};
|
||||||
|
|
||||||
|
export default class InputMultiInput extends React.Component<InputMultiInputProps> {
|
||||||
render() {
|
render() {
|
||||||
let options = this.props.options
|
let options = this.props.options
|
||||||
if(options.length > 0 && !Array.isArray(options[0])) {
|
if(options.length > 0 && !Array.isArray(options[0])) {
|
||||||
@@ -25,7 +24,7 @@ export default class InputMultiInput extends React.Component {
|
|||||||
>
|
>
|
||||||
<input type="radio"
|
<input type="radio"
|
||||||
name={this.props.name}
|
name={this.props.name}
|
||||||
onChange={e => this.props.onChange(val)}
|
onChange={_e => this.props.onChange(val)}
|
||||||
value={val}
|
value={val}
|
||||||
checked={val === selectedValue}
|
checked={val === selectedValue}
|
||||||
/>
|
/>
|
||||||
@@ -1,27 +1,35 @@
|
|||||||
import React from 'react'
|
import React, { BaseSyntheticEvent } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
let IDX = 0;
|
let IDX = 0;
|
||||||
|
|
||||||
export default class InputNumber extends React.Component {
|
export type InputNumberProps = {
|
||||||
static propTypes = {
|
value?: number
|
||||||
value: PropTypes.number,
|
default?: number
|
||||||
default: PropTypes.number,
|
min?: number
|
||||||
min: PropTypes.number,
|
max?: number
|
||||||
max: PropTypes.number,
|
onChange?(...args: unknown[]): unknown
|
||||||
onChange: PropTypes.func,
|
allowRange?: boolean
|
||||||
allowRange: PropTypes.bool,
|
rangeStep?: number
|
||||||
rangeStep: PropTypes.number,
|
wdKey?: string
|
||||||
wdKey: PropTypes.string,
|
required?: boolean
|
||||||
required: PropTypes.bool,
|
"aria-label"?: string
|
||||||
"aria-label": PropTypes.string,
|
};
|
||||||
}
|
|
||||||
|
|
||||||
|
type InputNumberState = {
|
||||||
|
uuid: number
|
||||||
|
editing: boolean
|
||||||
|
editingRange?: boolean
|
||||||
|
value?: number
|
||||||
|
dirtyValue?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class InputNumber extends React.Component<InputNumberProps, InputNumberState> {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
rangeStep: 1
|
rangeStep: 1
|
||||||
}
|
}
|
||||||
|
_keyboardEvent: boolean = false;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props: InputNumberProps) {
|
||||||
super(props)
|
super(props)
|
||||||
this.state = {
|
this.state = {
|
||||||
uuid: IDX++,
|
uuid: IDX++,
|
||||||
@@ -31,7 +39,7 @@ export default class InputNumber extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static getDerivedStateFromProps(props, state) {
|
static getDerivedStateFromProps(props: InputNumberProps, state: InputNumberState) {
|
||||||
if (!state.editing && props.value !== state.value) {
|
if (!state.editing && props.value !== state.value) {
|
||||||
return {
|
return {
|
||||||
value: props.value,
|
value: props.value,
|
||||||
@@ -41,16 +49,15 @@ export default class InputNumber extends React.Component {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
changeValue(newValue) {
|
changeValue(newValue: number | string | undefined) {
|
||||||
const value = (newValue === "" || newValue === undefined) ?
|
const value = (newValue === "" || newValue === undefined) ?
|
||||||
undefined :
|
undefined : +newValue;
|
||||||
parseFloat(newValue);
|
|
||||||
|
|
||||||
const hasChanged = this.props.value !== value;
|
const hasChanged = this.props.value !== value;
|
||||||
if(this.isValid(value) && hasChanged) {
|
if(this.isValid(value) && hasChanged) {
|
||||||
this.props.onChange(value)
|
if (this.props.onChange) this.props.onChange(value)
|
||||||
this.setState({
|
this.setState({
|
||||||
value: newValue,
|
value: value,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else if (!this.isValid(value) && hasChanged) {
|
else if (!this.isValid(value) && hasChanged) {
|
||||||
@@ -60,25 +67,25 @@ export default class InputNumber extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
dirtyValue: newValue === "" ? undefined : newValue,
|
dirtyValue: newValue === "" ? undefined : value,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
isValid(v) {
|
isValid(v: number | string | undefined) {
|
||||||
if (v === undefined) {
|
if (v === undefined) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const value = parseFloat(v)
|
const value = +v;
|
||||||
if(isNaN(value)) {
|
if(isNaN(value)) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!isNaN(this.props.min) && value < this.props.min) {
|
if(!isNaN(this.props.min!) && value < this.props.min!) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!isNaN(this.props.max) && value > this.props.max) {
|
if(!isNaN(this.props.max!) && value > this.props.max!) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,7 +95,7 @@ export default class InputNumber extends React.Component {
|
|||||||
resetValue = () => {
|
resetValue = () => {
|
||||||
this.setState({editing: false});
|
this.setState({editing: false});
|
||||||
// Reset explicitly to default value if value has been cleared
|
// Reset explicitly to default value if value has been cleared
|
||||||
if(this.state.value === "") {
|
if(!this.state.value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,8 +111,8 @@ export default class InputNumber extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onChangeRange = (e) => {
|
onChangeRange = (e: BaseSyntheticEvent<Event, HTMLInputElement, HTMLInputElement>) => {
|
||||||
let value = parseFloat(e.target.value, 10);
|
let value = parseFloat(e.target.value);
|
||||||
const step = this.props.rangeStep;
|
const step = this.props.rangeStep;
|
||||||
let dirtyValue = value;
|
let dirtyValue = value;
|
||||||
|
|
||||||
@@ -119,11 +126,11 @@ export default class InputNumber extends React.Component {
|
|||||||
// for example we might go from 13 to 13.23, however because we know
|
// for example we might go from 13 to 13.23, however because we know
|
||||||
// that came from a keyboard event we always want to increase by a
|
// that came from a keyboard event we always want to increase by a
|
||||||
// single step value.
|
// single step value.
|
||||||
if (value < this.state.dirtyValue) {
|
if (value < this.state.dirtyValue!) {
|
||||||
value = this.state.value - step;
|
value = this.state.value! - step;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
value = this.state.value + step
|
value = this.state.value! + step
|
||||||
}
|
}
|
||||||
dirtyValue = value;
|
dirtyValue = value;
|
||||||
}
|
}
|
||||||
@@ -140,10 +147,10 @@ export default class InputNumber extends React.Component {
|
|||||||
this._keyboardEvent = false;
|
this._keyboardEvent = false;
|
||||||
|
|
||||||
// Clamp between min/max
|
// Clamp between min/max
|
||||||
value = Math.max(this.props.min, Math.min(this.props.max, value));
|
value = Math.max(this.props.min!, Math.min(this.props.max!, value));
|
||||||
|
|
||||||
this.setState({value, dirtyValue});
|
this.setState({value, dirtyValue});
|
||||||
this.props.onChange(value);
|
if (this.props.onChange) this.props.onChange(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@@ -196,15 +203,15 @@ export default class InputNumber extends React.Component {
|
|||||||
type="text"
|
type="text"
|
||||||
spellCheck="false"
|
spellCheck="false"
|
||||||
className="maputnik-number"
|
className="maputnik-number"
|
||||||
placeholder={this.props.default}
|
placeholder={this.props.default?.toString()}
|
||||||
value={inputValue === undefined ? "" : inputValue}
|
value={inputValue === undefined ? "" : inputValue}
|
||||||
onFocus={e => {
|
onFocus={_e => {
|
||||||
this.setState({editing: true});
|
this.setState({editing: true});
|
||||||
}}
|
}}
|
||||||
onChange={e => {
|
onChange={e => {
|
||||||
this.changeValue(e.target.value);
|
this.changeValue(e.target.value);
|
||||||
}}
|
}}
|
||||||
onBlur={e => {
|
onBlur={_e => {
|
||||||
this.setState({editing: false});
|
this.setState({editing: false});
|
||||||
this.resetValue()
|
this.resetValue()
|
||||||
}}
|
}}
|
||||||
@@ -218,7 +225,7 @@ export default class InputNumber extends React.Component {
|
|||||||
aria-label={this.props['aria-label']}
|
aria-label={this.props['aria-label']}
|
||||||
spellCheck="false"
|
spellCheck="false"
|
||||||
className="maputnik-number"
|
className="maputnik-number"
|
||||||
placeholder={this.props.default}
|
placeholder={this.props.default?.toString()}
|
||||||
value={value === undefined ? "" : value}
|
value={value === undefined ? "" : value}
|
||||||
onChange={e => this.changeValue(e.target.value)}
|
onChange={e => this.changeValue(e.target.value)}
|
||||||
onFocus={() => {
|
onFocus={() => {
|
||||||
@@ -1,22 +1,20 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
export default class InputSelect extends React.Component {
|
|
||||||
static propTypes = {
|
|
||||||
value: PropTypes.string.isRequired,
|
|
||||||
"data-wd-key": PropTypes.string,
|
|
||||||
options: PropTypes.array.isRequired,
|
|
||||||
style: PropTypes.object,
|
|
||||||
onChange: PropTypes.func.isRequired,
|
|
||||||
title: PropTypes.string,
|
|
||||||
'aria-label': PropTypes.string,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
export type InputSelectProps = {
|
||||||
|
value: string
|
||||||
|
"data-wd-key"?: string
|
||||||
|
options: [string, any][] | string[]
|
||||||
|
style?: object
|
||||||
|
onChange(...args: unknown[]): unknown
|
||||||
|
title?: string
|
||||||
|
'aria-label'?: string
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class InputSelect extends React.Component<InputSelectProps> {
|
||||||
render() {
|
render() {
|
||||||
let options = this.props.options
|
let options = this.props.options;
|
||||||
if(options.length > 0 && !Array.isArray(options[0])) {
|
if(options.length > 0 && !Array.isArray(options[0])) {
|
||||||
options = options.map(v => [v, v])
|
options = options.map((v) => [v, v]) as [string, any][];
|
||||||
}
|
}
|
||||||
|
|
||||||
return <select
|
return <select
|
||||||
@@ -1,139 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
import InputColor from './InputColor'
|
|
||||||
import InputNumber from './InputNumber'
|
|
||||||
import InputCheckbox from './InputCheckbox'
|
|
||||||
import InputString from './InputString'
|
|
||||||
import InputSelect from './InputSelect'
|
|
||||||
import InputMultiInput from './InputMultiInput'
|
|
||||||
import InputArray from './InputArray'
|
|
||||||
import InputDynamicArray from './InputDynamicArray'
|
|
||||||
import InputFont from './InputFont'
|
|
||||||
import InputAutocomplete from './InputAutocomplete'
|
|
||||||
import InputEnum from './InputEnum'
|
|
||||||
import capitalize from 'lodash.capitalize'
|
|
||||||
|
|
||||||
const iconProperties = ['background-pattern', 'fill-pattern', 'line-pattern', 'fill-extrusion-pattern', 'icon-image']
|
|
||||||
|
|
||||||
function labelFromFieldName(fieldName) {
|
|
||||||
let label = fieldName.split('-').slice(1).join(' ')
|
|
||||||
if(label.length > 0) {
|
|
||||||
label = label.charAt(0).toUpperCase() + label.slice(1);
|
|
||||||
}
|
|
||||||
return label
|
|
||||||
}
|
|
||||||
|
|
||||||
function optionsLabelLength(options) {
|
|
||||||
let sum = 0;
|
|
||||||
options.forEach(([_, label]) => {
|
|
||||||
sum += label.length
|
|
||||||
})
|
|
||||||
return sum
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Display any field from the Maplibre GL style spec and
|
|
||||||
* choose the correct field component based on the @{fieldSpec}
|
|
||||||
* to display @{value}. */
|
|
||||||
export default class SpecField extends React.Component {
|
|
||||||
static propTypes = {
|
|
||||||
onChange: PropTypes.func.isRequired,
|
|
||||||
fieldName: PropTypes.string.isRequired,
|
|
||||||
fieldSpec: PropTypes.object.isRequired,
|
|
||||||
value: PropTypes.oneOfType([
|
|
||||||
PropTypes.string,
|
|
||||||
PropTypes.number,
|
|
||||||
PropTypes.array,
|
|
||||||
PropTypes.bool
|
|
||||||
]),
|
|
||||||
/** Override the style of the field */
|
|
||||||
style: PropTypes.object,
|
|
||||||
'aria-label': PropTypes.string,
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const commonProps = {
|
|
||||||
error: this.props.error,
|
|
||||||
fieldSpec: this.props.fieldSpec,
|
|
||||||
label: this.props.label,
|
|
||||||
action: this.props.action,
|
|
||||||
style: this.props.style,
|
|
||||||
value: this.props.value,
|
|
||||||
default: this.props.fieldSpec.default,
|
|
||||||
name: this.props.fieldName,
|
|
||||||
onChange: newValue => this.props.onChange(this.props.fieldName, newValue),
|
|
||||||
'aria-label': this.props['aria-label'],
|
|
||||||
}
|
|
||||||
|
|
||||||
function childNodes() {
|
|
||||||
switch(this.props.fieldSpec.type) {
|
|
||||||
case 'number': return (
|
|
||||||
<InputNumber
|
|
||||||
{...commonProps}
|
|
||||||
min={this.props.fieldSpec.minimum}
|
|
||||||
max={this.props.fieldSpec.maximum}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
case 'enum':
|
|
||||||
const options = Object.keys(this.props.fieldSpec.values).map(v => [v, capitalize(v)])
|
|
||||||
|
|
||||||
return <InputEnum
|
|
||||||
{...commonProps}
|
|
||||||
options={options}
|
|
||||||
/>
|
|
||||||
case 'resolvedImage':
|
|
||||||
case 'formatted':
|
|
||||||
case 'string':
|
|
||||||
if (iconProperties.indexOf(this.props.fieldName) >= 0) {
|
|
||||||
const options = this.props.fieldSpec.values || [];
|
|
||||||
return <InputAutocomplete
|
|
||||||
{...commonProps}
|
|
||||||
options={options.map(f => [f, f])}
|
|
||||||
/>
|
|
||||||
} else {
|
|
||||||
return <InputString
|
|
||||||
{...commonProps}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
case 'color': return (
|
|
||||||
<InputColor
|
|
||||||
{...commonProps}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
case 'boolean': return (
|
|
||||||
<InputCheckbox
|
|
||||||
{...commonProps}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
case 'array':
|
|
||||||
if(this.props.fieldName === 'text-font') {
|
|
||||||
return <InputFont
|
|
||||||
{...commonProps}
|
|
||||||
fonts={this.props.fieldSpec.values}
|
|
||||||
/>
|
|
||||||
} else {
|
|
||||||
if (this.props.fieldSpec.length) {
|
|
||||||
return <InputArray
|
|
||||||
{...commonProps}
|
|
||||||
type={this.props.fieldSpec.value}
|
|
||||||
length={this.props.fieldSpec.length}
|
|
||||||
/>
|
|
||||||
} else {
|
|
||||||
return <InputDynamicArray
|
|
||||||
{...commonProps}
|
|
||||||
fieldSpec={this.props.fieldSpec}
|
|
||||||
type={this.props.fieldSpec.value}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default: return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div data-wd-key={"spec-field:"+this.props.fieldName}>
|
|
||||||
{childNodes.call(this)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
import React, { ReactElement } from 'react'
|
||||||
|
|
||||||
|
import InputColor, { InputColorProps } from './InputColor'
|
||||||
|
import InputNumber, { InputNumberProps } from './InputNumber'
|
||||||
|
import InputCheckbox, { InputCheckboxProps } from './InputCheckbox'
|
||||||
|
import InputString, { InputStringProps } from './InputString'
|
||||||
|
import InputArray, { FieldArrayProps } from './InputArray'
|
||||||
|
import InputDynamicArray, { FieldDynamicArrayProps } from './InputDynamicArray'
|
||||||
|
import InputFont, { FieldFontProps } from './InputFont'
|
||||||
|
import InputAutocomplete, { InputAutocompleteProps } from './InputAutocomplete'
|
||||||
|
import InputEnum, { InputEnumProps } from './InputEnum'
|
||||||
|
import capitalize from 'lodash.capitalize'
|
||||||
|
|
||||||
|
const iconProperties = ['background-pattern', 'fill-pattern', 'line-pattern', 'fill-extrusion-pattern', 'icon-image']
|
||||||
|
|
||||||
|
export type SpecFieldProps = {
|
||||||
|
onChange(...args: unknown[]): unknown
|
||||||
|
fieldName: string
|
||||||
|
fieldSpec: {
|
||||||
|
default?: unknown
|
||||||
|
type: 'number' | 'enum' | 'resolvedImage' | 'formatted' | 'string' | 'color' | 'boolean' | 'array'
|
||||||
|
minimum?: number
|
||||||
|
maximum?: number
|
||||||
|
values?: unknown[]
|
||||||
|
length?: number
|
||||||
|
value?: string
|
||||||
|
}
|
||||||
|
value?: string | number | unknown[] | boolean
|
||||||
|
/** Override the style of the field */
|
||||||
|
style?: object
|
||||||
|
'aria-label'?: string
|
||||||
|
error: unknown[]
|
||||||
|
label: string
|
||||||
|
action: ReactElement
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Display any field from the Maplibre GL style spec and
|
||||||
|
* choose the correct field component based on the @{fieldSpec}
|
||||||
|
* to display @{value}. */
|
||||||
|
export default class SpecField extends React.Component<SpecFieldProps> {
|
||||||
|
|
||||||
|
childNodes() {
|
||||||
|
const commonProps = {
|
||||||
|
error: this.props.error,
|
||||||
|
fieldSpec: this.props.fieldSpec,
|
||||||
|
label: this.props.label,
|
||||||
|
action: this.props.action,
|
||||||
|
style: this.props.style,
|
||||||
|
value: this.props.value,
|
||||||
|
default: this.props.fieldSpec.default,
|
||||||
|
name: this.props.fieldName,
|
||||||
|
onChange: (newValue: string) => this.props.onChange(this.props.fieldName, newValue),
|
||||||
|
'aria-label': this.props['aria-label'],
|
||||||
|
}
|
||||||
|
switch(this.props.fieldSpec.type) {
|
||||||
|
case 'number': return (
|
||||||
|
<InputNumber
|
||||||
|
{...commonProps as InputNumberProps}
|
||||||
|
min={this.props.fieldSpec.minimum}
|
||||||
|
max={this.props.fieldSpec.maximum}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
case 'enum':
|
||||||
|
const options = Object.keys(this.props.fieldSpec.values || []).map(v => [v, capitalize(v)])
|
||||||
|
|
||||||
|
return <InputEnum
|
||||||
|
{...commonProps as Omit<InputEnumProps, "options">}
|
||||||
|
options={options}
|
||||||
|
/>
|
||||||
|
case 'resolvedImage':
|
||||||
|
case 'formatted':
|
||||||
|
case 'string':
|
||||||
|
if (iconProperties.indexOf(this.props.fieldName) >= 0) {
|
||||||
|
const options = this.props.fieldSpec.values || [];
|
||||||
|
return <InputAutocomplete
|
||||||
|
{...commonProps as Omit<InputAutocompleteProps, "options">}
|
||||||
|
options={options.map(f => [f, f])}
|
||||||
|
/>
|
||||||
|
} else {
|
||||||
|
return <InputString
|
||||||
|
{...commonProps as InputStringProps}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
case 'color': return (
|
||||||
|
<InputColor
|
||||||
|
{...commonProps as InputColorProps}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
case 'boolean': return (
|
||||||
|
<InputCheckbox
|
||||||
|
{...commonProps as InputCheckboxProps}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
case 'array':
|
||||||
|
if(this.props.fieldName === 'text-font') {
|
||||||
|
return <InputFont
|
||||||
|
{...commonProps as FieldFontProps}
|
||||||
|
fonts={this.props.fieldSpec.values}
|
||||||
|
/>
|
||||||
|
} else {
|
||||||
|
if (this.props.fieldSpec.length) {
|
||||||
|
return <InputArray
|
||||||
|
{...commonProps as FieldArrayProps}
|
||||||
|
type={this.props.fieldSpec.value}
|
||||||
|
length={this.props.fieldSpec.length}
|
||||||
|
/>
|
||||||
|
} else {
|
||||||
|
return <InputDynamicArray
|
||||||
|
{...commonProps as FieldDynamicArrayProps}
|
||||||
|
fieldSpec={this.props.fieldSpec}
|
||||||
|
type={this.props.fieldSpec.value as FieldDynamicArrayProps['type']}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default: return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div data-wd-key={"spec-field:"+this.props.fieldName}>
|
||||||
|
{this.childNodes()}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,26 +1,30 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
export default class InputString extends React.Component {
|
export type InputStringProps = {
|
||||||
static propTypes = {
|
"data-wd-key"?: string
|
||||||
"data-wd-key": PropTypes.string,
|
value?: string
|
||||||
value: PropTypes.string,
|
style?: object
|
||||||
style: PropTypes.object,
|
default?: string
|
||||||
default: PropTypes.string,
|
onChange?(...args: unknown[]): unknown
|
||||||
onChange: PropTypes.func,
|
onInput?(...args: unknown[]): unknown
|
||||||
onInput: PropTypes.func,
|
multi?: boolean
|
||||||
multi: PropTypes.bool,
|
required?: boolean
|
||||||
required: PropTypes.bool,
|
disabled?: boolean
|
||||||
disabled: PropTypes.bool,
|
spellCheck?: boolean
|
||||||
spellCheck: PropTypes.bool,
|
'aria-label'?: string
|
||||||
'aria-label': PropTypes.string,
|
};
|
||||||
}
|
|
||||||
|
|
||||||
|
type InputStringState = {
|
||||||
|
editing: boolean
|
||||||
|
value?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class InputString extends React.Component<InputStringProps, InputStringState> {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
onInput: () => {},
|
onInput: () => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props: InputStringProps) {
|
||||||
super(props)
|
super(props)
|
||||||
this.state = {
|
this.state = {
|
||||||
editing: false,
|
editing: false,
|
||||||
@@ -28,7 +32,7 @@ export default class InputString extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static getDerivedStateFromProps(props, state) {
|
static getDerivedStateFromProps(props: InputStringProps, state: InputStringState) {
|
||||||
if (!state.editing) {
|
if (!state.editing) {
|
||||||
return {
|
return {
|
||||||
value: props.value
|
value: props.value
|
||||||
@@ -68,22 +72,22 @@ export default class InputString extends React.Component {
|
|||||||
style: this.props.style,
|
style: this.props.style,
|
||||||
value: this.state.value === undefined ? "" : this.state.value,
|
value: this.state.value === undefined ? "" : this.state.value,
|
||||||
placeholder: this.props.default,
|
placeholder: this.props.default,
|
||||||
onChange: e => {
|
onChange: (e: React.BaseSyntheticEvent<Event, HTMLInputElement, HTMLInputElement>) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
editing: true,
|
editing: true,
|
||||||
value: e.target.value
|
value: e.target.value
|
||||||
}, () => {
|
}, () => {
|
||||||
this.props.onInput(this.state.value);
|
if (this.props.onInput) this.props.onInput(this.state.value);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
onBlur: () => {
|
onBlur: () => {
|
||||||
if(this.state.value!==this.props.value) {
|
if(this.state.value!==this.props.value) {
|
||||||
this.setState({editing: false});
|
this.setState({editing: false});
|
||||||
this.props.onChange(this.state.value);
|
if (this.props.onChange) this.props.onChange(this.state.value);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onKeyDown: (e) => {
|
onKeyDown: (e) => {
|
||||||
if (e.keyCode === 13) {
|
if (e.keyCode === 13 && this.props.onChange) {
|
||||||
this.props.onChange(this.state.value);
|
this.props.onChange(this.state.value);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1,16 +1,15 @@
|
|||||||
import React, {Fragment} from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import InputString from './InputString'
|
import InputString from './InputString'
|
||||||
import SmallError from './SmallError'
|
import SmallError from './SmallError'
|
||||||
|
|
||||||
|
|
||||||
function validate (url) {
|
function validate(url: string) {
|
||||||
if (url === "") {
|
if (url === "") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let error;
|
let error;
|
||||||
const getProtocol = (url) => {
|
const getProtocol = (url: string) => {
|
||||||
try {
|
try {
|
||||||
const urlObj = new URL(url);
|
const urlObj = new URL(url);
|
||||||
return urlObj.protocol;
|
return urlObj.protocol;
|
||||||
@@ -48,38 +47,44 @@ function validate (url) {
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class FieldUrl extends React.Component {
|
export type FieldUrlProps = {
|
||||||
static propTypes = {
|
"data-wd-key"?: string
|
||||||
"data-wd-key": PropTypes.string,
|
value: string
|
||||||
value: PropTypes.string,
|
style?: object
|
||||||
style: PropTypes.object,
|
default?: string
|
||||||
default: PropTypes.string,
|
onChange(...args: unknown[]): unknown
|
||||||
onChange: PropTypes.func,
|
onInput?(...args: unknown[]): unknown
|
||||||
onInput: PropTypes.func,
|
multi?: boolean
|
||||||
multi: PropTypes.bool,
|
required?: boolean
|
||||||
required: PropTypes.bool,
|
'aria-label'?: string
|
||||||
'aria-label': PropTypes.string,
|
type?: string
|
||||||
}
|
className?: string
|
||||||
|
};
|
||||||
|
|
||||||
|
type FieldUrlState = {
|
||||||
|
error?: React.ReactNode
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class FieldUrl extends React.Component<FieldUrlProps, FieldUrlState> {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
onInput: () => {},
|
onInput: () => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor (props) {
|
constructor (props: FieldUrlProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
error: validate(props.value)
|
error: validate(props.value)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
onInput = (url) => {
|
onInput = (url: string) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
error: validate(url)
|
error: validate(url)
|
||||||
});
|
});
|
||||||
this.props.onInput(url);
|
if (this.props.onInput) this.props.onInput(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
onChange = (url) => {
|
onChange = (url: string) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
error: validate(url)
|
error: validate(url)
|
||||||
});
|
});
|
||||||
@@ -1,22 +1,21 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import {MdClose} from 'react-icons/md'
|
import {MdClose} from 'react-icons/md'
|
||||||
import AriaModal from 'react-aria-modal'
|
import AriaModal from 'react-aria-modal'
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
|
|
||||||
|
|
||||||
export default class Modal extends React.Component {
|
type ModalProps = {
|
||||||
static propTypes = {
|
"data-wd-key"?: string
|
||||||
"data-wd-key": PropTypes.string,
|
isOpen: boolean
|
||||||
isOpen: PropTypes.bool.isRequired,
|
title: string
|
||||||
title: PropTypes.string.isRequired,
|
onOpenToggle(...args: unknown[]): unknown
|
||||||
onOpenToggle: PropTypes.func.isRequired,
|
underlayClickExits?: boolean
|
||||||
children: PropTypes.node,
|
underlayProps?: any
|
||||||
underlayClickExits: PropTypes.bool,
|
className?: string
|
||||||
underlayProps: PropTypes.object,
|
};
|
||||||
className: PropTypes.string,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
export default class Modal extends React.Component<ModalProps> {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
underlayClickExits: true
|
underlayClickExits: true
|
||||||
}
|
}
|
||||||
@@ -24,7 +23,7 @@ export default class Modal extends React.Component {
|
|||||||
// See <https://github.com/maputnik/editor/issues/416>
|
// See <https://github.com/maputnik/editor/issues/416>
|
||||||
onClose = () => {
|
onClose = () => {
|
||||||
if (document.activeElement) {
|
if (document.activeElement) {
|
||||||
document.activeElement.blur();
|
(document.activeElement as HTMLElement).blur();
|
||||||
}
|
}
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -37,6 +36,7 @@ export default class Modal extends React.Component {
|
|||||||
return <AriaModal
|
return <AriaModal
|
||||||
titleText={this.props.title}
|
titleText={this.props.title}
|
||||||
underlayClickExits={this.props.underlayClickExits}
|
underlayClickExits={this.props.underlayClickExits}
|
||||||
|
// @ts-ignore
|
||||||
underlayProps={this.props.underlayProps}
|
underlayProps={this.props.underlayProps}
|
||||||
data-wd-key={this.props["data-wd-key"]}
|
data-wd-key={this.props["data-wd-key"]}
|
||||||
verticallyCenter={true}
|
verticallyCenter={true}
|
||||||
@@ -1,19 +1,19 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
import InputButton from './InputButton'
|
import InputButton from './InputButton'
|
||||||
import Modal from './Modal'
|
import Modal from './Modal'
|
||||||
|
|
||||||
|
|
||||||
export default class ModalLoading extends React.Component {
|
type ModalLoadingProps = {
|
||||||
static propTypes = {
|
isOpen: boolean
|
||||||
isOpen: PropTypes.bool.isRequired,
|
onCancel(...args: unknown[]): unknown
|
||||||
onCancel: PropTypes.func.isRequired,
|
title: string
|
||||||
title: PropTypes.string.isRequired,
|
message: React.ReactNode
|
||||||
message: PropTypes.node.isRequired,
|
};
|
||||||
}
|
|
||||||
|
|
||||||
underlayOnClick(e) {
|
|
||||||
|
export default class ModalLoading extends React.Component<ModalLoadingProps> {
|
||||||
|
underlayOnClick(e: Event) {
|
||||||
// This stops click events falling through to underlying modals.
|
// This stops click events falling through to underlying modals.
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
}
|
}
|
||||||
@@ -24,9 +24,9 @@ export default class ModalLoading extends React.Component {
|
|||||||
isOpen={this.props.isOpen}
|
isOpen={this.props.isOpen}
|
||||||
underlayClickExits={false}
|
underlayClickExits={false}
|
||||||
underlayProps={{
|
underlayProps={{
|
||||||
onClick: (e) => underlayProps(e)
|
// @ts-ignore
|
||||||
|
onClick: (e: Event) => underlayProps(e)
|
||||||
}}
|
}}
|
||||||
closeable={false}
|
|
||||||
title={this.props.title}
|
title={this.props.title}
|
||||||
onOpenToggle={() => this.props.onCancel()}
|
onOpenToggle={() => this.props.onCancel()}
|
||||||
>
|
>
|
||||||
@@ -1,25 +1,24 @@
|
|||||||
import React from 'react'
|
import React, { FormEvent } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import {MdFileUpload} from 'react-icons/md'
|
||||||
|
import {MdAddCircleOutline} from 'react-icons/md'
|
||||||
|
import FileReaderInput, { Result } from 'react-file-reader-input'
|
||||||
|
|
||||||
import ModalLoading from './ModalLoading'
|
import ModalLoading from './ModalLoading'
|
||||||
import Modal from './Modal'
|
import Modal from './Modal'
|
||||||
import InputButton from './InputButton'
|
import InputButton from './InputButton'
|
||||||
import FileReaderInput from 'react-file-reader-input'
|
|
||||||
import InputUrl from './InputUrl'
|
import InputUrl from './InputUrl'
|
||||||
|
|
||||||
import {MdFileUpload} from 'react-icons/md'
|
|
||||||
import {MdAddCircleOutline} from 'react-icons/md'
|
|
||||||
|
|
||||||
import style from '../libs/style'
|
import style from '../libs/style'
|
||||||
import publicStyles from '../config/styles.json'
|
import publicStyles from '../config/styles.json'
|
||||||
|
|
||||||
class PublicStyle extends React.Component {
|
type PublicStyleProps = {
|
||||||
static propTypes = {
|
url: string
|
||||||
url: PropTypes.string.isRequired,
|
thumbnailUrl: string
|
||||||
thumbnailUrl: PropTypes.string.isRequired,
|
title: string
|
||||||
title: PropTypes.string.isRequired,
|
onSelect(...args: unknown[]): unknown
|
||||||
onSelect: PropTypes.func.isRequired,
|
};
|
||||||
}
|
|
||||||
|
|
||||||
|
class PublicStyle extends React.Component<PublicStyleProps> {
|
||||||
render() {
|
render() {
|
||||||
return <div className="maputnik-public-style">
|
return <div className="maputnik-public-style">
|
||||||
<InputButton
|
<InputButton
|
||||||
@@ -43,14 +42,21 @@ class PublicStyle extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class ModalOpen extends React.Component {
|
type ModalOpenProps = {
|
||||||
static propTypes = {
|
isOpen: boolean
|
||||||
isOpen: PropTypes.bool.isRequired,
|
onOpenToggle(...args: unknown[]): unknown
|
||||||
onOpenToggle: PropTypes.func.isRequired,
|
onStyleOpen(...args: unknown[]): unknown
|
||||||
onStyleOpen: PropTypes.func.isRequired,
|
};
|
||||||
}
|
|
||||||
|
|
||||||
constructor(props) {
|
type ModalOpenState = {
|
||||||
|
styleUrl: string
|
||||||
|
error?: string | null
|
||||||
|
activeRequest?: any
|
||||||
|
activeRequestUrl?: string | null
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class ModalOpen extends React.Component<ModalOpenProps, ModalOpenState> {
|
||||||
|
constructor(props: ModalOpenProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
styleUrl: ""
|
styleUrl: ""
|
||||||
@@ -63,7 +69,7 @@ export default class ModalOpen extends React.Component {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
onCancelActiveRequest(e) {
|
onCancelActiveRequest(e: Event) {
|
||||||
// Else the click propagates to the underlying modal
|
// Else the click propagates to the underlying modal
|
||||||
if(e) e.stopPropagation();
|
if(e) e.stopPropagation();
|
||||||
|
|
||||||
@@ -76,12 +82,12 @@ export default class ModalOpen extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onStyleSelect = (styleUrl) => {
|
onStyleSelect = (styleUrl: string) => {
|
||||||
this.clearError();
|
this.clearError();
|
||||||
|
|
||||||
let canceled;
|
let canceled: boolean = false;
|
||||||
|
|
||||||
const activeRequest = fetch(styleUrl, {
|
fetch(styleUrl, {
|
||||||
mode: 'cors',
|
mode: 'cors',
|
||||||
credentials: "same-origin"
|
credentials: "same-origin"
|
||||||
})
|
})
|
||||||
@@ -123,13 +129,13 @@ export default class ModalOpen extends React.Component {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
onSubmitUrl = (e) => {
|
onSubmitUrl = (e: FormEvent<HTMLFormElement>) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.onStyleSelect(this.state.styleUrl);
|
this.onStyleSelect(this.state.styleUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
onUpload = (_, files) => {
|
onUpload = (_: any, files: Result[]) => {
|
||||||
const [e, file] = files[0];
|
const [_e, file] = files[0];
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
|
|
||||||
this.clearError();
|
this.clearError();
|
||||||
@@ -138,11 +144,11 @@ export default class ModalOpen extends React.Component {
|
|||||||
reader.onload = e => {
|
reader.onload = e => {
|
||||||
let mapStyle;
|
let mapStyle;
|
||||||
try {
|
try {
|
||||||
mapStyle = JSON.parse(e.target.result)
|
mapStyle = JSON.parse(e.target?.result as string)
|
||||||
}
|
}
|
||||||
catch(err) {
|
catch(err) {
|
||||||
this.setState({
|
this.setState({
|
||||||
error: err.toString()
|
error: (err as Error).toString()
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -161,7 +167,7 @@ export default class ModalOpen extends React.Component {
|
|||||||
this.props.onOpenToggle();
|
this.props.onOpenToggle();
|
||||||
}
|
}
|
||||||
|
|
||||||
onChangeUrl = (url) => {
|
onChangeUrl = (url: string) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
styleUrl: url,
|
styleUrl: url,
|
||||||
});
|
});
|
||||||
@@ -200,7 +206,7 @@ export default class ModalOpen extends React.Component {
|
|||||||
<section className="maputnik-modal-section">
|
<section className="maputnik-modal-section">
|
||||||
<h1>Upload Style</h1>
|
<h1>Upload Style</h1>
|
||||||
<p>Upload a JSON style from your computer.</p>
|
<p>Upload a JSON style from your computer.</p>
|
||||||
<FileReaderInput onChange={this.onUpload} tabIndex="-1" aria-label="Style file">
|
<FileReaderInput onChange={this.onUpload} tabIndex={-1} aria-label="Style file">
|
||||||
<InputButton className="maputnik-upload-button"><MdFileUpload /> Upload</InputButton>
|
<InputButton className="maputnik-upload-button"><MdFileUpload /> Upload</InputButton>
|
||||||
</FileReaderInput>
|
</FileReaderInput>
|
||||||
</section>
|
</section>
|
||||||
@@ -246,7 +252,7 @@ export default class ModalOpen extends React.Component {
|
|||||||
<ModalLoading
|
<ModalLoading
|
||||||
isOpen={!!this.state.activeRequest}
|
isOpen={!!this.state.activeRequest}
|
||||||
title={'Loading style'}
|
title={'Loading style'}
|
||||||
onCancel={(e) => this.onCancelActiveRequest(e)}
|
onCancel={(e: Event) => this.onCancelActiveRequest(e)}
|
||||||
message={"Loading: "+this.state.activeRequestUrl}
|
message={"Loading: "+this.state.activeRequestUrl}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import {LightSpecification, StyleSpecification, TransitionSpecification, latest} from '@maplibre/maplibre-gl-style-spec'
|
||||||
|
|
||||||
import {latest} from '@maplibre/maplibre-gl-style-spec'
|
|
||||||
import Block from './Block'
|
|
||||||
import FieldArray from './FieldArray'
|
import FieldArray from './FieldArray'
|
||||||
import FieldNumber from './FieldNumber'
|
import FieldNumber from './FieldNumber'
|
||||||
import FieldString from './FieldString'
|
import FieldString from './FieldString'
|
||||||
@@ -13,16 +11,16 @@ import FieldColor from './FieldColor'
|
|||||||
import Modal from './Modal'
|
import Modal from './Modal'
|
||||||
import fieldSpecAdditional from '../libs/field-spec-additional'
|
import fieldSpecAdditional from '../libs/field-spec-additional'
|
||||||
|
|
||||||
export default class ModalSettings extends React.Component {
|
type ModalSettingsProps = {
|
||||||
static propTypes = {
|
mapStyle: StyleSpecification
|
||||||
mapStyle: PropTypes.object.isRequired,
|
onStyleChanged(...args: unknown[]): unknown
|
||||||
onStyleChanged: PropTypes.func.isRequired,
|
onChangeMetadataProperty(...args: unknown[]): unknown
|
||||||
onChangeMetadataProperty: PropTypes.func.isRequired,
|
isOpen: boolean
|
||||||
isOpen: PropTypes.bool.isRequired,
|
onOpenToggle(...args: unknown[]): unknown
|
||||||
onOpenToggle: PropTypes.func.isRequired,
|
};
|
||||||
}
|
|
||||||
|
|
||||||
changeTransitionProperty(property, value) {
|
export default class ModalSettings extends React.Component<ModalSettingsProps> {
|
||||||
|
changeTransitionProperty(property: keyof TransitionSpecification, value: number | undefined) {
|
||||||
const transition = {
|
const transition = {
|
||||||
...this.props.mapStyle.transition,
|
...this.props.mapStyle.transition,
|
||||||
}
|
}
|
||||||
@@ -40,7 +38,7 @@ export default class ModalSettings extends React.Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
changeLightProperty(property, value) {
|
changeLightProperty(property: keyof LightSpecification, value: any) {
|
||||||
const light = {
|
const light = {
|
||||||
...this.props.mapStyle.light,
|
...this.props.mapStyle.light,
|
||||||
}
|
}
|
||||||
@@ -49,6 +47,7 @@ export default class ModalSettings extends React.Component {
|
|||||||
delete light[property];
|
delete light[property];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// @ts-ignore
|
||||||
light[property] = value;
|
light[property] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,22 +57,24 @@ export default class ModalSettings extends React.Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
changeStyleProperty(property, value) {
|
changeStyleProperty(property: keyof StyleSpecification | "owner", value: any) {
|
||||||
const changedStyle = {
|
const changedStyle = {
|
||||||
...this.props.mapStyle,
|
...this.props.mapStyle,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (value === undefined) {
|
if (value === undefined) {
|
||||||
|
// @ts-ignore
|
||||||
delete changedStyle[property];
|
delete changedStyle[property];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// @ts-ignore
|
||||||
changedStyle[property] = value;
|
changedStyle[property] = value;
|
||||||
}
|
}
|
||||||
this.props.onStyleChanged(changedStyle);
|
this.props.onStyleChanged(changedStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const metadata = this.props.mapStyle.metadata || {}
|
const metadata = this.props.mapStyle.metadata || {} as any;
|
||||||
const {onChangeMetadataProperty, mapStyle} = this.props;
|
const {onChangeMetadataProperty, mapStyle} = this.props;
|
||||||
const inputProps = { }
|
const inputProps = { }
|
||||||
|
|
||||||
@@ -98,14 +99,14 @@ export default class ModalSettings extends React.Component {
|
|||||||
label={"Owner"}
|
label={"Owner"}
|
||||||
fieldSpec={{doc: "Owner ID of the style. Used by Mapbox or future style APIs."}}
|
fieldSpec={{doc: "Owner ID of the style. Used by Mapbox or future style APIs."}}
|
||||||
data-wd-key="modal:settings.owner"
|
data-wd-key="modal:settings.owner"
|
||||||
value={this.props.mapStyle.owner}
|
value={(this.props.mapStyle as any).owner}
|
||||||
onChange={this.changeStyleProperty.bind(this, "owner")}
|
onChange={this.changeStyleProperty.bind(this, "owner")}
|
||||||
/>
|
/>
|
||||||
<FieldUrl {...inputProps}
|
<FieldUrl {...inputProps}
|
||||||
fieldSpec={latest.$root.sprite}
|
fieldSpec={latest.$root.sprite}
|
||||||
label="Sprite URL"
|
label="Sprite URL"
|
||||||
data-wd-key="modal:settings.sprite"
|
data-wd-key="modal:settings.sprite"
|
||||||
value={this.props.mapStyle.sprite}
|
value={this.props.mapStyle.sprite as string}
|
||||||
onChange={this.changeStyleProperty.bind(this, "sprite")}
|
onChange={this.changeStyleProperty.bind(this, "sprite")}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -113,7 +114,7 @@ export default class ModalSettings extends React.Component {
|
|||||||
label="Glyphs URL"
|
label="Glyphs URL"
|
||||||
fieldSpec={latest.$root.glyphs}
|
fieldSpec={latest.$root.glyphs}
|
||||||
data-wd-key="modal:settings.glyphs"
|
data-wd-key="modal:settings.glyphs"
|
||||||
value={this.props.mapStyle.glyphs}
|
value={this.props.mapStyle.glyphs as string}
|
||||||
onChange={this.changeStyleProperty.bind(this, "glyphs")}
|
onChange={this.changeStyleProperty.bind(this, "glyphs")}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -138,7 +139,7 @@ export default class ModalSettings extends React.Component {
|
|||||||
fieldSpec={latest.$root.center}
|
fieldSpec={latest.$root.center}
|
||||||
length={2}
|
length={2}
|
||||||
type="number"
|
type="number"
|
||||||
value={mapStyle.center}
|
value={mapStyle.center || []}
|
||||||
default={latest.$root.center.default || [0, 0]}
|
default={latest.$root.center.default || [0, 0]}
|
||||||
onChange={this.changeStyleProperty.bind(this, "center")}
|
onChange={this.changeStyleProperty.bind(this, "center")}
|
||||||
/>
|
/>
|
||||||
@@ -175,7 +176,7 @@ export default class ModalSettings extends React.Component {
|
|||||||
label={"Light anchor"}
|
label={"Light anchor"}
|
||||||
fieldSpec={latest.light.anchor}
|
fieldSpec={latest.light.anchor}
|
||||||
name="light-anchor"
|
name="light-anchor"
|
||||||
value={light.anchor}
|
value={light.anchor as string}
|
||||||
options={Object.keys(latest.light.anchor.values)}
|
options={Object.keys(latest.light.anchor.values)}
|
||||||
default={latest.light.anchor.default}
|
default={latest.light.anchor.default}
|
||||||
onChange={this.changeLightProperty.bind(this, "anchor")}
|
onChange={this.changeLightProperty.bind(this, "anchor")}
|
||||||
@@ -185,7 +186,7 @@ export default class ModalSettings extends React.Component {
|
|||||||
{...inputProps}
|
{...inputProps}
|
||||||
label={"Light color"}
|
label={"Light color"}
|
||||||
fieldSpec={latest.light.color}
|
fieldSpec={latest.light.color}
|
||||||
value={light.color}
|
value={light.color as string}
|
||||||
default={latest.light.color.default}
|
default={latest.light.color.default}
|
||||||
onChange={this.changeLightProperty.bind(this, "color")}
|
onChange={this.changeLightProperty.bind(this, "color")}
|
||||||
/>
|
/>
|
||||||
@@ -194,7 +195,7 @@ export default class ModalSettings extends React.Component {
|
|||||||
{...inputProps}
|
{...inputProps}
|
||||||
label={"Light intensity"}
|
label={"Light intensity"}
|
||||||
fieldSpec={latest.light.intensity}
|
fieldSpec={latest.light.intensity}
|
||||||
value={light.intensity}
|
value={light.intensity as number}
|
||||||
default={latest.light.intensity.default}
|
default={latest.light.intensity.default}
|
||||||
onChange={this.changeLightProperty.bind(this, "intensity")}
|
onChange={this.changeLightProperty.bind(this, "intensity")}
|
||||||
/>
|
/>
|
||||||
@@ -205,7 +206,7 @@ export default class ModalSettings extends React.Component {
|
|||||||
fieldSpec={latest.light.position}
|
fieldSpec={latest.light.position}
|
||||||
type="number"
|
type="number"
|
||||||
length={latest.light.position.length}
|
length={latest.light.position.length}
|
||||||
value={light.position}
|
value={light.position as number[]}
|
||||||
default={latest.light.position.default}
|
default={latest.light.position.default}
|
||||||
onChange={this.changeLightProperty.bind(this, "position")}
|
onChange={this.changeLightProperty.bind(this, "position")}
|
||||||
/>
|
/>
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
import Modal from './Modal'
|
import Modal from './Modal'
|
||||||
|
|
||||||
|
|
||||||
export default class ModalShortcuts extends React.Component {
|
type ModalShortcutsProps = {
|
||||||
static propTypes = {
|
isOpen: boolean
|
||||||
isOpen: PropTypes.bool.isRequired,
|
onOpenToggle(...args: unknown[]): unknown
|
||||||
onOpenToggle: PropTypes.func.isRequired,
|
};
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
export default class ModalShortcuts extends React.Component<ModalShortcutsProps> {
|
||||||
render() {
|
render() {
|
||||||
const help = [
|
const help = [
|
||||||
{
|
{
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
import InputButton from './InputButton'
|
import InputButton from './InputButton'
|
||||||
import Modal from './Modal'
|
import Modal from './Modal'
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
import logoImage from 'maputnik-design/logos/logo-color.svg'
|
import logoImage from 'maputnik-design/logos/logo-color.svg'
|
||||||
|
|
||||||
export default class ModalSurvey extends React.Component {
|
type ModalSurveyProps = {
|
||||||
static propTypes = {
|
isOpen: boolean
|
||||||
isOpen: PropTypes.bool.isRequired,
|
onOpenToggle(...args: unknown[]): unknown
|
||||||
onOpenToggle: PropTypes.func.isRequired,
|
};
|
||||||
}
|
|
||||||
|
|
||||||
|
export default class ModalSurvey extends React.Component<ModalSurveyProps> {
|
||||||
onClick = () => {
|
onClick = () => {
|
||||||
window.open('https://gregorywolanski.typeform.com/to/cPgaSY', '_blank');
|
window.open('https://gregorywolanski.typeform.com/to/cPgaSY', '_blank');
|
||||||
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
export default class ScrollContainer extends React.Component {
|
|
||||||
static propTypes = {
|
|
||||||
children: PropTypes.node
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return <div className="maputnik-scroll-container">
|
|
||||||
{this.props.children}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
type ScrollContainerProps = {
|
||||||
|
children?: React.ReactNode
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class ScrollContainer extends React.Component<ScrollContainerProps> {
|
||||||
|
render() {
|
||||||
|
return <div className="maputnik-scroll-container">
|
||||||
|
{this.props.children}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,18 +1,17 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
import {otherFilterOps} from '../libs/filterops'
|
import {otherFilterOps} from '../libs/filterops'
|
||||||
import InputString from './InputString'
|
import InputString from './InputString'
|
||||||
import InputAutocomplete from './InputAutocomplete'
|
import InputAutocomplete from './InputAutocomplete'
|
||||||
import InputSelect from './InputSelect'
|
import InputSelect from './InputSelect'
|
||||||
|
|
||||||
function tryParseInt(v) {
|
function tryParseInt(v: string | number) {
|
||||||
if (v === '') return v
|
if (v === '') return v
|
||||||
if (isNaN(v)) return v
|
if (isNaN(v as number)) return v
|
||||||
return parseFloat(v)
|
return parseFloat(v as string)
|
||||||
}
|
}
|
||||||
|
|
||||||
function tryParseBool(v) {
|
function tryParseBool(v: string | boolean) {
|
||||||
const isString = (typeof(v) === "string");
|
const isString = (typeof(v) === "string");
|
||||||
if(!isString) {
|
if(!isString) {
|
||||||
return v;
|
return v;
|
||||||
@@ -29,24 +28,24 @@ function tryParseBool(v) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseFilter(v) {
|
function parseFilter(v: string | boolean | number) {
|
||||||
v = tryParseInt(v);
|
v = tryParseInt(v as any);
|
||||||
v = tryParseBool(v);
|
v = tryParseBool(v as any);
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class SingleFilterEditor extends React.Component {
|
type SingleFilterEditorProps = {
|
||||||
static propTypes = {
|
filter: any[]
|
||||||
filter: PropTypes.array.isRequired,
|
onChange(...args: unknown[]): unknown
|
||||||
onChange: PropTypes.func.isRequired,
|
properties?: {[key: string]: string}
|
||||||
properties: PropTypes.object,
|
};
|
||||||
}
|
|
||||||
|
|
||||||
|
export default class SingleFilterEditor extends React.Component<SingleFilterEditorProps> {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
properties: {},
|
properties: {},
|
||||||
}
|
}
|
||||||
|
|
||||||
onFilterPartChanged(filterOp, propertyName, filterArgs) {
|
onFilterPartChanged(filterOp: string, propertyName: string, filterArgs: string[]) {
|
||||||
let newFilter = [filterOp, propertyName, ...filterArgs.map(parseFilter)]
|
let newFilter = [filterOp, propertyName, ...filterArgs.map(parseFilter)]
|
||||||
if(filterOp === 'has' || filterOp === '!has') {
|
if(filterOp === 'has' || filterOp === '!has') {
|
||||||
newFilter = [filterOp, propertyName]
|
newFilter = [filterOp, propertyName]
|
||||||
@@ -67,15 +66,15 @@ export default class SingleFilterEditor extends React.Component {
|
|||||||
<InputAutocomplete
|
<InputAutocomplete
|
||||||
aria-label="key"
|
aria-label="key"
|
||||||
value={propertyName}
|
value={propertyName}
|
||||||
options={Object.keys(this.props.properties).map(propName => [propName, propName])}
|
options={Object.keys(this.props.properties!).map(propName => [propName, propName])}
|
||||||
onChange={newPropertyName => this.onFilterPartChanged(filterOp, newPropertyName, filterArgs)}
|
onChange={(newPropertyName: string) => this.onFilterPartChanged(filterOp, newPropertyName, filterArgs)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="maputnik-filter-editor-operator">
|
<div className="maputnik-filter-editor-operator">
|
||||||
<InputSelect
|
<InputSelect
|
||||||
aria-label="function"
|
aria-label="function"
|
||||||
value={filterOp}
|
value={filterOp}
|
||||||
onChange={newFilterOp => this.onFilterPartChanged(newFilterOp, propertyName, filterArgs)}
|
onChange={(newFilterOp: string) => this.onFilterPartChanged(newFilterOp, propertyName, filterArgs)}
|
||||||
options={otherFilterOps}
|
options={otherFilterOps}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -84,12 +83,11 @@ export default class SingleFilterEditor extends React.Component {
|
|||||||
<InputString
|
<InputString
|
||||||
aria-label="value"
|
aria-label="value"
|
||||||
value={filterArgs.join(',')}
|
value={filterArgs.join(',')}
|
||||||
onChange={ v=> this.onFilterPartChanged(filterOp, propertyName, v.split(','))}
|
onChange={(v: string) => this.onFilterPartChanged(filterOp, propertyName, v.split(','))}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import './SmallError.scss';
|
import './SmallError.scss';
|
||||||
|
|
||||||
|
|
||||||
export default class SmallError extends React.Component {
|
type SmallErrorProps = {
|
||||||
static propTypes = {
|
children?: React.ReactNode
|
||||||
children: PropTypes.node,
|
};
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
export default class SmallError extends React.Component<SmallErrorProps> {
|
||||||
render () {
|
render () {
|
||||||
return (
|
return (
|
||||||
<div className="SmallError">
|
<div className="SmallError">
|
||||||
@@ -16,4 +16,3 @@ export default class SmallError extends React.Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,13 +1,12 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import Block from './Block'
|
import Block from './Block'
|
||||||
import InputSpec from './InputSpec'
|
import InputSpec, { SpecFieldProps as InputFieldSpecProps } from './InputSpec'
|
||||||
import Fieldset from './Fieldset'
|
import Fieldset from './Fieldset'
|
||||||
|
|
||||||
|
|
||||||
const typeMap = {
|
const typeMap = {
|
||||||
color: () => Block,
|
color: () => Block,
|
||||||
enum: ({fieldSpec}) => (Object.keys(fieldSpec.values).length <= 3 ? Fieldset : Block),
|
enum: ({fieldSpec}: any) => (Object.keys(fieldSpec.values).length <= 3 ? Fieldset : Block),
|
||||||
boolean: () => Block,
|
boolean: () => Block,
|
||||||
array: () => Fieldset,
|
array: () => Fieldset,
|
||||||
resolvedImage: () => Block,
|
resolvedImage: () => Block,
|
||||||
@@ -16,12 +15,11 @@ const typeMap = {
|
|||||||
formatted: () => Block,
|
formatted: () => Block,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class SpecField extends React.Component {
|
type SpecFieldProps = InputFieldSpecProps & {
|
||||||
static propTypes = {
|
name?: string
|
||||||
...InputSpec.propTypes,
|
};
|
||||||
name: PropTypes.string,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
export default class SpecField extends React.Component<SpecFieldProps> {
|
||||||
render() {
|
render() {
|
||||||
const {props} = this;
|
const {props} = this;
|
||||||
|
|
||||||
Reference in New Issue
Block a user