import React from "react"; import { isString } from "lodash"; import BaseControl, { ControlProps } from "./BaseControl"; import { StyledDynamicInput } from "./StyledControls"; import CodeEditor, { CodeEditorExpected, } from "components/editorComponents/CodeEditor"; import { EditorModes, EditorSize, EditorTheme, TabBehaviour, } from "components/editorComponents/CodeEditor/EditorConfig"; import { getDynamicBindings, isDynamicValue } from "utils/DynamicBindingUtils"; import styled from "styled-components"; import { JSONFormWidgetProps } from "widgets/JSONFormWidget/widget"; import { ARRAY_ITEM_KEY, DataType, FIELD_TYPE_TO_POTENTIAL_DATA, getBindingTemplate, ROOT_SCHEMA_KEY, Schema, SchemaItem, } from "widgets/JSONFormWidget/constants"; const PromptMessage = styled.span` line-height: 17px; `; const CurlyBraces = styled.span` color: ${(props) => props.theme.colors.codeMirror.background.hoverState}; background-color: #ffffff; border-radius: 2px; padding: 2px; margin: 0px 2px; font-size: 10px; `; // Auxiliary function for processArray, which returns the value for an object field function processObject(schema: Schema, defaultValue?: any) { const obj: Record = {}; Object.values(schema).forEach((schemaItem) => { obj[schemaItem.accessor] = processSchemaItemAutocomplete( schemaItem, defaultValue, ); }); return obj; } // Auxiliary function for processArray, which returns the value for an array field function processArray(schema: Schema, defaultValue?: any): any[] { if (schema[ARRAY_ITEM_KEY]) { return [ processSchemaItemAutocomplete(schema[ARRAY_ITEM_KEY], defaultValue), ]; } return []; } /** * This function takes a schemaItem, traverses through it and creates an object out of it. This * object would look like the form data and this object would be used for autocomplete. * Eg - { * fieldType: object, * children: { * name: { * accessor: "name" * fieldType: "string" * }, * age: { * accessor: "आयु" * fieldType: "number" * } * } * } * * @returns * { * name: "", * आयु: 0 * } * * @param schema * @param defaultValue Values that the autocomplete should show for a particular field */ function processSchemaItemAutocomplete( schemaItem: SchemaItem, defaultValue?: any, ) { if (schemaItem.dataType === DataType.OBJECT) { return processObject(schemaItem.children, defaultValue); } if (schemaItem.dataType === DataType.ARRAY) { return processArray(schemaItem.children, defaultValue); } return defaultValue || FIELD_TYPE_TO_POTENTIAL_DATA[schemaItem.fieldType]; } export function InputText(props: { label: string; value: string; onChange: (event: React.ChangeEvent | string) => void; evaluatedValue?: any; expected?: CodeEditorExpected; placeholder?: string; dataTreePath?: string; additionalDynamicData: Record>; theme: EditorTheme; }) { const { additionalDynamicData, dataTreePath, evaluatedValue, expected, onChange, placeholder, theme, value, } = props; return ( Access the current form using {"{{"} sourceData.fieldName {"}}"} } size={EditorSize.EXTENDED} tabBehaviour={TabBehaviour.INDENT} theme={theme} /> ); } export const stringToJS = (string: string): string => { const { jsSnippets, stringSegments } = getDynamicBindings(string); const js = stringSegments .map((segment, index) => { if (jsSnippets[index] && jsSnippets[index].length > 0) { return jsSnippets[index]; } else { return `\`${segment}\``; } }) .join(" + "); return js; }; export const JSToString = (js: string): string => { const segments = js.split(" + "); return segments .map((segment) => { if (segment.charAt(0) === "`") { return segment.substring(1, segment.length - 1); } else return "{{" + segment + "}}"; }) .join(""); }; class JSONFormComputeControl extends BaseControl { getInputComputedValue = (propertyValue: string) => { const { widgetName } = this.props.widgetProperties; const { prefixTemplate, suffixTemplate } = getBindingTemplate(widgetName); const value = propertyValue.substring( prefixTemplate.length, propertyValue.length - suffixTemplate.length, ); return JSToString(value); }; getComputedValue = (value: string) => { const { widgetName } = this.props.widgetProperties; const stringToEvaluate = stringToJS(value); const { prefixTemplate, suffixTemplate } = getBindingTemplate(widgetName); if (stringToEvaluate === "") { return stringToEvaluate; } return `${prefixTemplate}${stringToEvaluate}${suffixTemplate}`; }; onTextChange = (event: React.ChangeEvent | string) => { const value = isString(event) ? event : event.target?.value; const output = this.getComputedValue(value); this.updateProperty(this.props.propertyName, output); }; render() { const { dataTreePath, defaultValue, expected, label, placeholderText, propertyValue, theme, widgetProperties, } = this.props; const { schema } = widgetProperties; const rootSchemaItem = schema[ROOT_SCHEMA_KEY] || {}; const { sourceData } = rootSchemaItem; const baseSchemaStructure = processSchemaItemAutocomplete(rootSchemaItem); const fieldStateStructure = processSchemaItemAutocomplete(rootSchemaItem, { isVisible: true, isDisabled: true, isRequired: true, isValid: true, }); const value = (() => { if (propertyValue && isDynamicValue(propertyValue)) { return this.getInputComputedValue(propertyValue); } return propertyValue || defaultValue; })(); if (value && !propertyValue) { this.onTextChange(value); } return ( ); } static getControlType() { return "JSON_FORM_COMPUTE_VALUE"; } } export interface JSONFormComputeControlProps extends ControlProps { defaultValue?: string; widgetProperties: JSONFormWidgetProps; placeholderText?: string; } export default JSONFormComputeControl;