Skip to content

Commit 1fcfb95

Browse files
committed
[objarr] Input errors
1 parent c6f98a3 commit 1fcfb95

4 files changed

Lines changed: 82 additions & 45 deletions

File tree

site/demos/10_ui_components/08_EditableValueView.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ We can style its container and the button that lets you change type:
5555
margin-right: 0.5rem;
5656
}
5757
}
58+
input.invalid {
59+
background: #fdd;
60+
}
5861
```
5962

6063
And finally, we can enable the `editable` prop on the original ValuesInHtmlTable

site/demos/10_ui_components/09_EditableCellView.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ We can style its container and the button that lets you change type:
5252
margin-right: 0.5rem;
5353
}
5454
}
55+
input.invalid {
56+
background: #fdd;
57+
}
5558
```
5659

5760
And finally, we can enable the `editable` prop on the original TableInHtmlTable

src/common/other.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,18 @@ export const errorNew = (message: string) => {
106106
throw new Error(message);
107107
};
108108

109+
export const tryReturn = <Return>(
110+
tryF: () => Return,
111+
catchReturn?: Return,
112+
): Return | void => {
113+
try {
114+
return tryF();
115+
} catch {
116+
/*! istanbul ignore next */
117+
return catchReturn;
118+
}
119+
};
120+
109121
export const tryCatch = async <Return>(
110122
action: () => Return | Promise<Return>,
111123
then1?: (error: any) => void,

src/ui-react-dom/common/components.tsx

Lines changed: 64 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
} from '../../common/cell.ts';
1010
import {jsonParse, jsonString} from '../../common/json.ts';
1111
import {isObject, objToArray} from '../../common/obj.ts';
12-
import {isArray, isFalse, isUndefined} from '../../common/other.ts';
12+
import {isArray, isFalse, isUndefined, tryReturn} from '../../common/other.ts';
1313
import {getProps, useCallback, useState} from '../../common/react.ts';
1414
import {
1515
_VALUE,
@@ -131,36 +131,37 @@ export const HtmlTable = ({
131131
</table>
132132
);
133133

134-
export const EditableThing = <Thing extends Cell | Value>({
134+
export const EditableThing = ({
135135
thing,
136136
onThingChange,
137137
className,
138138
hasSchema,
139139
showType = true,
140140
}: {
141-
readonly thing: Thing | undefined;
142-
readonly onThingChange: (thing: Thing) => void;
141+
readonly thing: Cell | Value | undefined;
142+
readonly onThingChange: (thing: Cell | Value) => void;
143143
readonly className: string;
144144
readonly hasSchema: (() => boolean) | undefined;
145145
readonly showType?: boolean;
146146
}) => {
147147
const [thingType, setThingType] = useState<CellOrValueType>();
148-
const [currentThing, setCurrentThing] = useState<
149-
string | number | boolean | null
150-
>();
148+
const [currentThing, setCurrentThing] = useState<Cell | Value>();
151149
const [stringThing, setStringThing] = useState<string>();
152150
const [numberThing, setNumberThing] = useState<number>();
153151
const [booleanThing, setBooleanThing] = useState<boolean>();
154-
const [objectThingJson, setObjectThingJson] = useState<string>(EMPTY_STRING);
155-
const [arrayThingJson, setArrayThingJson] = useState<string>(EMPTY_STRING);
152+
const [objectThing, setObjectThing] = useState<string>('{}');
153+
const [arrayThing, setArrayThing] = useState<string>('[]');
154+
155+
const [objectClassName, setObjectClassName] = useState<string>('');
156+
const [arrayClassName, setArrayClassName] = useState<string>('');
156157

157158
if (currentThing !== thing) {
158159
setThingType(getCellOrValueType(thing));
159-
setCurrentThing(thing as string | number | boolean | null);
160+
setCurrentThing(thing);
160161
if (isObject(thing)) {
161-
setObjectThingJson(jsonString(thing));
162+
setObjectThing(jsonString(thing));
162163
} else if (isArray(thing)) {
163-
setArrayThingJson(jsonString(thing));
164+
setArrayThing(jsonString(thing));
164165
} else {
165166
setStringThing(String(thing));
166167
setNumberThing(Number(thing) || 0);
@@ -169,10 +170,32 @@ export const EditableThing = <Thing extends Cell | Value>({
169170
}
170171

171172
const handleThingChange = useCallback(
172-
(thing: string | number | boolean, setTypedThing: (thing: any) => void) => {
173+
<T extends Cell | Value>(thing: T, setTypedThing: (thing: T) => void) => {
173174
setTypedThing(thing);
174175
setCurrentThing(thing);
175-
onThingChange(thing as Thing);
176+
onThingChange(thing);
177+
},
178+
[onThingChange],
179+
);
180+
181+
const handleJsonThingChange = useCallback(
182+
(
183+
value: string,
184+
setTypedThing: (value: string) => void,
185+
isThing: (thing: any) => boolean,
186+
setTypedClassName: (className: string) => void,
187+
) => {
188+
setTypedThing(value);
189+
try {
190+
const object = jsonParse(value);
191+
if (isThing(object)) {
192+
setCurrentThing(object);
193+
onThingChange(object);
194+
setTypedClassName('');
195+
}
196+
} catch {
197+
setTypedClassName('invalid');
198+
}
176199
},
177200
[onThingChange],
178201
);
@@ -192,21 +215,21 @@ export const EditableThing = <Thing extends Cell | Value>({
192215
stringThing,
193216
numberThing,
194217
booleanThing,
195-
(objectThingJson ? jsonParse(objectThingJson) : {}) as any,
196-
(arrayThingJson ? jsonParse(arrayThingJson) : []) as any,
218+
tryReturn(() => jsonParse(objectThing), {}),
219+
tryReturn(() => jsonParse(arrayThing), []),
197220
);
198221
setThingType(nextType);
199222
setCurrentThing(thing);
200-
onThingChange(thing as Thing);
223+
onThingChange(thing);
201224
}
202225
}, [
203226
hasSchema,
204227
onThingChange,
205228
stringThing,
206229
numberThing,
207230
booleanThing,
208-
objectThingJson,
209-
arrayThingJson,
231+
objectThing,
232+
arrayThing,
210233
thingType,
211234
]);
212235

@@ -250,38 +273,34 @@ export const EditableThing = <Thing extends Cell | Value>({
250273
[handleThingChange],
251274
)}
252275
/>,
253-
<textarea
276+
<input
254277
key={thingType}
255-
value={objectThingJson}
278+
value={objectThing}
279+
className={objectClassName}
256280
onChange={useCallback(
257-
(event: FormEvent<HTMLTextAreaElement>) => {
258-
const str = event[CURRENT_TARGET][_VALUE];
259-
setObjectThingJson(str);
260-
try {
261-
const parsed = jsonParse(str);
262-
if (isObject(parsed)) {
263-
onThingChange(parsed as Thing);
264-
}
265-
} catch {}
266-
},
267-
[onThingChange],
281+
(event: FormEvent<HTMLInputElement>) =>
282+
handleJsonThingChange(
283+
event[CURRENT_TARGET][_VALUE],
284+
setObjectThing,
285+
isObject,
286+
setObjectClassName,
287+
),
288+
[handleJsonThingChange],
268289
)}
269290
/>,
270-
<textarea
291+
<input
271292
key={thingType}
272-
value={arrayThingJson}
293+
value={arrayThing}
294+
className={arrayClassName}
273295
onChange={useCallback(
274-
(event: FormEvent<HTMLTextAreaElement>) => {
275-
const str = event[CURRENT_TARGET][_VALUE];
276-
setArrayThingJson(str);
277-
try {
278-
const parsed = jsonParse(str);
279-
if (isArray(parsed)) {
280-
onThingChange(parsed as Thing);
281-
}
282-
} catch {}
283-
},
284-
[onThingChange],
296+
(event: FormEvent<HTMLInputElement>) =>
297+
handleJsonThingChange(
298+
event[CURRENT_TARGET][_VALUE],
299+
setArrayThing,
300+
isArray,
301+
setArrayClassName,
302+
),
303+
[handleJsonThingChange],
285304
)}
286305
/>,
287306
);

0 commit comments

Comments
 (0)