react-codemirror
react-codemirror copied to clipboard
How do you map changes between a CodeMirror component and an array of objects?
I have an array of objects that are represented in a CodeMirror
component. I'm trying to work out how to map changes in the CodeMirror
to the object. I'm using a RangeSet
to hold the underlying object. I was expecting I could use RangeSet.map()
to apply the changes from the CodeMirror
onto the object RangeSet
. I'm not seeing that happen.
Is there an example that can help me understand how to handle this use case in a good way?
type Text = { type: "text"; textValue: string };
type Field = {
type: "field";
textValue: string;
field: {
fieldId: string;
};
};
export type TextWithField = (Text | Field)[];
class TextOrFieldRange extends RangeValue {
type: "text" | "field";
textOrField: Text | Field;
theRange;
constructor(
from: number,
to: number,
type: "text" | "field",
textOrField: Text | Field
) {
super();
this.type = type;
this.textOrField = { ...textOrField };
this.theRange = this.range(from, to);
}
eq(other: RangeValue): boolean {
return (
other instanceof TextOrFieldRange &&
this.type === other.type &&
this.theRange.from === other.theRange.from &&
this.theRange.to === other.theRange.to
);
}
}
const InputWithFields = ({
textWithFields,
setTextWithFields,
}: {
textWithFields: TextWithField;
setTextWithFields: (textWithFields: TextWithField) => void;
}) => {
const rangeBuilder = new RangeSetBuilder<TextOrFieldRange>();
let combinedText = "";
const fieldRanges: [number, number][] = [];
textWithFields.forEach((item) => {
const start = combinedText.length;
combinedText += item.textValue;
const end = combinedText.length;
rangeBuilder.add(
start,
end,
new TextOrFieldRange(start, combinedText.length, item.type, item)
);
item.type == "field" && fieldRanges.push([start, end]);
});
const combinedRanges = rangeBuilder.finish();
const handleTextChange = (value: string, viewUpdate: ViewUpdate) => {
const newRanges = combinedRanges.map(viewUpdate.changes.desc);
const iterator = newRanges.iter();
const newTextWithFields: TextWithField = [];
while (iterator.value !== null) {
newTextWithFields.push(iterator.value.textOrField);
iterator.next();
}
setTextWithFields(newTextWithFields);
};
const highlightRanges = rangeHighlighter(fieldRanges);
return (
<CodeMirror
value={combinedText}
onChange={handleTextChange}
theme="none"
basicSetup={false}
editable={true}
extensions={[...extensions, highlightRanges]}
maxWidth="100%"
height="100px"
/>
);
};