mirror of
https://github.com/maputnik/editor.git
synced 2026-08-24 05:57:25 +00:00
Migration of jsx files to tsx 1 (#848)
In this PR I have changed some of the jsx files to tsx file. I'm starting off with the "leafs" so that migration of the rest will be easier, hopefully. What I'm basically doing is taking a jsx file, copy paste it into: https://mskelton.dev/ratchet And after that I'm fixing the types as needed. It's not a very long process. Hopefully more PRs will follow and this will be over soon. I don't plan to migrate the storybook as I generally don't understand why is it useful, I'll open an issue to see if anyone thinks differently.
This commit is contained in:
@@ -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>;
|
||||||
@@ -80,4 +88,4 @@ export default class Doc extends React.Component {
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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}
|
||||||
@@ -31,5 +30,4 @@ export default class InputButton extends React.Component {
|
|||||||
{this.props.children}
|
{this.props.children}
|
||||||
</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,
|
||||||
}
|
}
|
||||||
@@ -35,5 +34,4 @@ export default class InputCheckbox extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
</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">
|
||||||
@@ -15,5 +15,4 @@ export default class SmallError extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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