ink-form
Version:
Complex user-friendly form component for React Ink
97 lines (96 loc) • 4.49 kB
JavaScript
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."))))));
}
};