@dxos/react-ui-form 0.7.3-staging.cc8dd3e → 0.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/browser/index.mjs +191 -31
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +191 -30
- package/dist/lib/node/index.cjs.map +3 -3
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +191 -31
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/components/Form/Defaults.d.ts +4 -4
- package/dist/types/src/components/Form/Defaults.d.ts.map +1 -1
- package/dist/types/src/components/Form/Form.d.ts +8 -0
- package/dist/types/src/components/Form/Form.d.ts.map +1 -1
- package/dist/types/src/components/Form/Form.stories.d.ts +11 -0
- package/dist/types/src/components/Form/Form.stories.d.ts.map +1 -1
- package/dist/types/src/components/Form/Input.d.ts +5 -4
- package/dist/types/src/components/Form/Input.d.ts.map +1 -1
- package/dist/types/src/hooks/useForm.d.ts +7 -6
- package/dist/types/src/hooks/useForm.d.ts.map +1 -1
- package/package.json +23 -23
- package/src/components/Form/Defaults.tsx +28 -13
- package/src/components/Form/Form.stories.tsx +42 -10
- package/src/components/Form/Form.tsx +204 -28
- package/src/components/Form/Input.tsx +5 -4
- package/src/components/ViewEditor/ViewEditor.tsx +2 -2
- package/src/hooks/useForm.ts +36 -18
|
@@ -60,7 +60,7 @@ export const ViewEditor = ({
|
|
|
60
60
|
name: view.name,
|
|
61
61
|
// TODO(burdon): Need to warn user of possible consequences of editing.
|
|
62
62
|
// TODO(burdon): Settings should have domain name owned by user.
|
|
63
|
-
typename: view.query.
|
|
63
|
+
typename: view.query.type,
|
|
64
64
|
};
|
|
65
65
|
}, [view]);
|
|
66
66
|
|
|
@@ -68,7 +68,7 @@ export const ViewEditor = ({
|
|
|
68
68
|
({ name, typename }: ViewMetaType) => {
|
|
69
69
|
requestAnimationFrame(() => {
|
|
70
70
|
view.name = name;
|
|
71
|
-
view.query.
|
|
71
|
+
view.query.type = typename;
|
|
72
72
|
schema.updateTypename(typename);
|
|
73
73
|
});
|
|
74
74
|
},
|
package/src/hooks/useForm.ts
CHANGED
|
@@ -11,6 +11,9 @@ import { log } from '@dxos/log';
|
|
|
11
11
|
import { validateSchema, type ValidationError } from '@dxos/schema';
|
|
12
12
|
import { type MaybePromise } from '@dxos/util';
|
|
13
13
|
|
|
14
|
+
// TODO(ZaymonFC): Where should this live?
|
|
15
|
+
export type FormPath<T extends object = {}> = PropertyKey<T> | `${PropertyKey<T>}.${number}`;
|
|
16
|
+
|
|
14
17
|
/**
|
|
15
18
|
* Return type from `useForm` hook.
|
|
16
19
|
*/
|
|
@@ -20,9 +23,9 @@ export type FormHandler<T extends BaseObject> = {
|
|
|
20
23
|
//
|
|
21
24
|
|
|
22
25
|
values: T;
|
|
23
|
-
errors: Record<
|
|
24
|
-
touched: Record<
|
|
25
|
-
changed: Record<
|
|
26
|
+
errors: Record<FormPath<T>, string>;
|
|
27
|
+
touched: Record<FormPath<T>, boolean>;
|
|
28
|
+
changed: Record<FormPath<T>, boolean>;
|
|
26
29
|
canSave: boolean;
|
|
27
30
|
handleSave: () => void;
|
|
28
31
|
|
|
@@ -30,9 +33,9 @@ export type FormHandler<T extends BaseObject> = {
|
|
|
30
33
|
// Form input component helpers.
|
|
31
34
|
//
|
|
32
35
|
|
|
33
|
-
getStatus: (property:
|
|
34
|
-
getValue: <V>(property:
|
|
35
|
-
onValueChange: <V>(property:
|
|
36
|
+
getStatus: (property: FormPath<T>) => { status?: 'error'; error?: string };
|
|
37
|
+
getValue: <V>(property: FormPath<T>) => V;
|
|
38
|
+
onValueChange: <V>(property: FormPath<T>, type: SimpleType, value: V) => void;
|
|
36
39
|
onBlur: (event: FocusEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
|
|
37
40
|
};
|
|
38
41
|
|
|
@@ -95,9 +98,9 @@ export const useForm = <T extends BaseObject>({
|
|
|
95
98
|
setValues(initialValues);
|
|
96
99
|
}, [initialValues]);
|
|
97
100
|
|
|
98
|
-
const [touched, setTouched] = useState<Record<
|
|
99
|
-
const [changed, setChanged] = useState<Record<
|
|
100
|
-
const [errors, setErrors] = useState<Record<
|
|
101
|
+
const [touched, setTouched] = useState<Record<FormPath<T>, boolean>>(createKeySet(initialValues, false));
|
|
102
|
+
const [changed, setChanged] = useState<Record<FormPath<T>, boolean>>(createKeySet(initialValues, false));
|
|
103
|
+
const [errors, setErrors] = useState<Record<FormPath<T>, string>>({} as Record<FormPath<T>, string>);
|
|
101
104
|
const [saving, setSaving] = useState(false);
|
|
102
105
|
|
|
103
106
|
//
|
|
@@ -157,7 +160,7 @@ export const useForm = <T extends BaseObject>({
|
|
|
157
160
|
//
|
|
158
161
|
|
|
159
162
|
const getStatus = useCallback<FormHandler<T>['getStatus']>(
|
|
160
|
-
(property:
|
|
163
|
+
(property: FormPath<T>) => ({
|
|
161
164
|
status: errors[property] ? 'error' : undefined,
|
|
162
165
|
error: errors[property] ? errors[property] : undefined,
|
|
163
166
|
}),
|
|
@@ -165,12 +168,12 @@ export const useForm = <T extends BaseObject>({
|
|
|
165
168
|
);
|
|
166
169
|
|
|
167
170
|
// TODO(burdon): Use path to extract hierarchical value.
|
|
168
|
-
const getValue = <V>(property:
|
|
169
|
-
return values
|
|
171
|
+
const getValue = <V>(property: FormPath<T>): V => {
|
|
172
|
+
return getByPath(values, property);
|
|
170
173
|
};
|
|
171
174
|
|
|
172
175
|
// TODO(burdon): Use path to set hierarchical value.
|
|
173
|
-
const onValueChange = (property:
|
|
176
|
+
const onValueChange = (property: FormPath<T>, type: SimpleType, value: any) => {
|
|
174
177
|
let parsedValue = value;
|
|
175
178
|
try {
|
|
176
179
|
if (type === 'number') {
|
|
@@ -181,7 +184,7 @@ export const useForm = <T extends BaseObject>({
|
|
|
181
184
|
parsedValue = undefined;
|
|
182
185
|
}
|
|
183
186
|
|
|
184
|
-
const newValues =
|
|
187
|
+
const newValues = setByPath(values, property, parsedValue);
|
|
185
188
|
setValues(newValues);
|
|
186
189
|
setChanged((prev) => ({ ...prev, [property]: true }));
|
|
187
190
|
onValuesChanged?.(newValues);
|
|
@@ -227,19 +230,34 @@ export const useForm = <T extends BaseObject>({
|
|
|
227
230
|
} satisfies FormHandler<T>;
|
|
228
231
|
};
|
|
229
232
|
|
|
230
|
-
const createKeySet = <T extends BaseObject, V>(obj: T, value: V): Record<
|
|
233
|
+
const createKeySet = <T extends BaseObject, V>(obj: T, value: V): Record<FormPath<T>, V> => {
|
|
231
234
|
invariant(obj);
|
|
232
|
-
return Object.keys(obj).reduce((acc, key) => ({ ...acc, [key]: value }), {} as Record<
|
|
235
|
+
return Object.keys(obj).reduce((acc, key) => ({ ...acc, [key]: value }), {} as Record<FormPath<T>, V>);
|
|
233
236
|
};
|
|
234
237
|
|
|
235
238
|
const flatMap = <T extends BaseObject>(errors: ValidationError[]) => {
|
|
236
239
|
return errors.reduce(
|
|
237
240
|
(result, { path, message }) => {
|
|
238
241
|
if (!(path in result)) {
|
|
239
|
-
result[path as
|
|
242
|
+
result[path as FormPath<T>] = message;
|
|
240
243
|
}
|
|
241
244
|
return result;
|
|
242
245
|
},
|
|
243
|
-
{} as Record<
|
|
246
|
+
{} as Record<FormPath<T>, string>,
|
|
244
247
|
);
|
|
245
248
|
};
|
|
249
|
+
|
|
250
|
+
// TODO(ZaymonFC): Move to util?
|
|
251
|
+
const getByPath = <T extends object, V>(obj: T, path: FormPath<T>): V => {
|
|
252
|
+
const [key, index] = path.split('.');
|
|
253
|
+
return index === undefined ? (obj[key as keyof T] as V) : ((obj[key as keyof T] as any[])[parseInt(index)] as V);
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
const setByPath = <T extends object>(obj: T, path: FormPath<T>, value: any): T => {
|
|
257
|
+
const [key, index] = path.split('.');
|
|
258
|
+
const newValue =
|
|
259
|
+
index === undefined
|
|
260
|
+
? value
|
|
261
|
+
: [...(obj[key as keyof T] as any[])].map((v, i) => (i === parseInt(index) ? value : v));
|
|
262
|
+
return { ...obj, [key]: newValue };
|
|
263
|
+
};
|