UNPKG

@limetech/lime-elements

Version:
102 lines (101 loc) 3.47 kB
import React from "react"; import { isEmpty } from "lodash-es"; export class CodeEditor extends React.Component { constructor(props) { super(props); this.state = { validationError: '', modified: false }; this.handleChange = this.handleChange.bind(this); } render() { const props = this.props; let value = '{}'; try { value = JSON.stringify(props.formData, null, ' '); } catch (_a) { // N/A } const { validationError, modified } = this.state; const { errorSchema, formData, required } = props; const hasSchemaErrors = !isEmpty(errorSchema); const hasValue = formData !== undefined && formData !== null; const shouldShowSchemaErrors = hasSchemaErrors && (modified || hasValue || !required); const isInvalid = validationError.length > 0 || shouldShowSchemaErrors; let helperText; if (validationError) { helperText = validationError; } else if (shouldShowSchemaErrors) { helperText = findFirstError(errorSchema); } return React.createElement('limel-code-editor', { value: value, language: 'json', lineNumbers: true, fold: true, lint: true, onChange: this.handleChange, invalid: isInvalid, helperText: helperText, }); } componentDidUpdate(prevProps) { if (prevProps.formData !== this.props.formData && (this.state.validationError !== '' || this.state.modified)) { this.setState({ validationError: '', modified: false }); } } handleChange(event) { const props = this.props; event.stopPropagation(); if (!props.onChange) { return; } let value; try { value = JSON.parse(event.nativeEvent.detail); } catch (error) { const validationError = error instanceof SyntaxError ? `Invalid JSON: ${error.message}` : 'Should be a valid JSON document'; this.setState({ validationError, modified: true }); return; } props.onChange(value); this.setState({ validationError: '', modified: true }); } } /** * Recursively finds the first error message in a potentially nested errorSchema. * Checks for __errors at the current level, then recurses into nested objects. * When an error is found in a nested property, the property name is prepended * to the message for context (e.g. `"method: is a required property"`). * * @param schema - The error schema to search for errors * @returns The first error message found, or undefined if no errors */ function findFirstError(schema) { if (!schema || typeof schema !== 'object') { return undefined; } if ('__errors' in schema && Array.isArray(schema.__errors)) { const errors = schema.__errors; if (errors.length > 0) { return errors[0]; } } for (const key of Object.keys(schema)) { if (key === '__errors') { continue; } const nested = schema[key]; if (nested && typeof nested === 'object') { const found = findFirstError(nested); if (found) { return `${key}: ${found}`; } } } return undefined; }