UNPKG

ink-form

Version:

Complex user-friendly form component for React Ink

97 lines (96 loc) 4.49 kB
import React, { useState } from 'react'; import { Box, useFocus, Text, useInput } from 'ink'; import { getManager } from './managers/managers.js'; import { DescriptionRenderer } from './DescriptionRenderer.js'; export const FormFieldRenderer = props => { const manager = getManager(props.field.type, props.customManagers); const [error, setError] = useState(); const [currentValue, setCurrentValue] = useState(props.value ?? props.field.initialValue); const isEditing = !!props.editingField && props.editingField === (props.field.label ?? props.field.name); const hide = !isEditing && !!props.editingField; const save = (newValue) => { if (!error) { if (newValue) { props.onChange(newValue); setCurrentValue(newValue); } else { props.onChange(currentValue); } props.onSetEditingField(undefined); } }; const cancel = () => { setCurrentValue(props.value); props.onSetEditingField(undefined); setError(undefined); }; const { isFocused } = useFocus({}); useInput((input, key) => { if (!isEditing && key.return && !key.ctrl && !key.meta) { props.onSetEditingField(props.field.label ?? props.field.name); } else if (isEditing && key.escape) { cancel(); } else if (isEditing && key.return && (!manager?.needCtrlToReturnSave || key.ctrl)) { save(); } }, { isActive: isFocused }); if (hide) { return null; } if (!isEditing) { const RenderValue = manager?.renderValue ?? (() => React.createElement(React.Fragment, null, props.value)); return (React.createElement(Box, { marginX: 2, paddingX: 1, borderStyle: "round", borderColor: isFocused ? 'blue' : undefined }, React.createElement(Box, { flexGrow: 1 }, React.createElement(Text, { underline: isFocused, color: isFocused ? 'blue' : undefined }, props.field.label ?? props.field.name), props.field.required && React.createElement(Text, { color: "red" }, "*"), React.createElement(Text, null, ": "), React.createElement(Text, { dimColor: true }, React.createElement(RenderValue, { value: props.value, field: props.field }))), isFocused && (React.createElement(Box, null, React.createElement(Text, null, "Press enter to edit"))))); } else { let component; const rendererProps = { ...props, onError: setError, onClearError: () => setError(undefined), onChange: setCurrentValue, value: currentValue, onSave: save, onCancel: cancel, error, }; if (!manager) { component = React.createElement(Text, { color: "red" }, "No formfield manager for form field of type ", props.field.type, " available."); } else { const Field = manager.renderField; component = React.createElement(Field, { ...rendererProps }); } return (React.createElement(Box, { paddingX: 3, paddingY: 1, flexDirection: "column" }, React.createElement(Box, null, React.createElement(Text, null, props.field.label ?? props.field.name), props.field.required && React.createElement(Text, { color: "red" }, "*"), React.createElement(Text, null, ": ")), React.createElement(Box, null, component), props.field.description && (React.createElement(Box, null, React.createElement(Text, { dimColor: true }, React.createElement(DescriptionRenderer, { description: props.field.description })))), error && (React.createElement(Box, null, React.createElement(Text, { color: "red" }, "Error: ", error))), React.createElement(Box, { marginTop: 2 }, React.createElement(Text, { dimColor: true }, error ? (React.createElement(React.Fragment, null, "Press ESC to cancel.")) : (React.createElement(React.Fragment, null, "Press ", manager?.needCtrlToReturnSave ? 'CTRL+Enter' : 'Enter', " to complete field, or ESC to cancel.")))))); } };