import React from "react"; import classnames from "classnames"; import { type WithTranslation, withTranslation } from "react-i18next"; import { type EditorView } from "@codemirror/view"; import stringifyPretty from "json-stringify-pretty-compact"; import {createEditor} from "../libs/codemirror-mgl"; import type { StylePropertySpecification } from "maplibre-gl"; export type InputJsonProps = { value: object maxHeight?: number lineNumbers?: boolean lineWrapping?: boolean gutters?: string[] className?: string onChange(object: object): void onFocus?(...args: unknown[]): unknown onBlur?(...args: unknown[]): unknown onJSONValid?(): void onJSONInvalid?(_err: Error): void lintType: "layer" | "style" | "expression" | "json" spec?: StylePropertySpecification | undefined }; type InputJsonInternalProps = InputJsonProps & WithTranslation; type InputJsonState = { isEditing: boolean prevValue: string }; class InputJsonInternal extends React.Component { static defaultProps = { lineNumbers: true, lineWrapping: false, gutters: ["CodeMirror-lint-markers"], onFocus: () => {}, onBlur: () => {}, onJSONInvalid: () => {}, onJSONValid: () => {}, }; _keyEvent: string; _doc: EditorView | undefined; _el: HTMLDivElement | null = null; _cancelNextChange: boolean = false; constructor(props: InputJsonInternalProps) { super(props); this._keyEvent = "keyboard"; this.state = { isEditing: false, prevValue: this.getPrettyJson(this.props.value), }; } getPrettyJson(data: any) { return stringifyPretty(data, {indent: 2, maxLength: 40}); } componentDidMount () { this._doc = createEditor( this._el!, this.getPrettyJson(this.props.value), this.props.lintType || "layer", (value:string) => this.props.onChange(value ? JSON.parse(value) : {}), this.props.spec ); /*CodeMirror(this._el!, { value: this.props.getValue!(this.props.layer), mode: this.props.mode || { name: "mgl", }, lineWrapping: this.props.lineWrapping, tabSize: 2, theme: "maputnik", viewportMargin: Infinity, lineNumbers: this.props.lineNumbers, lint: this.props.lint || { context: "layer" }, matchBrackets: true, gutters: this.props.gutters, scrollbarStyle: "null", }); this._doc.on("change", this.onChange); this._doc.on("focus", this.onFocus); this._doc.on("blur", this.onBlur); */ this._doc.dispatch(); } onPointerDown = () => { this._keyEvent = "pointer"; }; onFocus = () => { if (this.props.onFocus) this.props.onFocus(); this.setState({ isEditing: true, showMessage: (this._keyEvent === "keyboard"), }); }; onBlur = () => { this._keyEvent = "keyboard"; if (this.props.onBlur) this.props.onBlur(); this.setState({ isEditing: false, showMessage: false, }); }; componentWillUnMount () { //this._doc!.off("change", this.onChange); //this._doc!.off("focus", this.onFocus); //this._doc!.off("blur", this.onBlur); } componentDidUpdate(_prevProps: InputJsonProps) { //if (!this.state.isEditing && prevProps.layer !== this.props.layer) { // this._cancelNextChange = true; // this._doc!.setValue( // this.props.getValue!(this.props.layer), // ); //} } onChange = (_e: unknown) => { /* if (this._cancelNextChange) { this._cancelNextChange = false; this.setState({ prevValue: this._doc!.getValue(), }); return; } const newCode = this._doc!.getValue(); if (this.state.prevValue !== newCode) { let parsedLayer, err; try { parsedLayer = JSON.parse(newCode); } catch(_err) { err = _err; console.warn(_err); } if (err && this.props.onJSONInvalid) { this.props.onJSONInvalid(); } else { if (this.props.onChange) this.props.onChange(parsedLayer); if (this.props.onJSONValid) this.props.onJSONValid(); } } this.setState({ prevValue: newCode, }); */ }; render() { const style = {} as {maxHeight?: number}; if (this.props.maxHeight) { style.maxHeight = this.props.maxHeight; } return