@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.
@@ -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.typename,
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.typename = typename;
71
+ view.query.type = typename;
72
72
  schema.updateTypename(typename);
73
73
  });
74
74
  },
@@ -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<PropertyKey<T>, string>;
24
- touched: Record<PropertyKey<T>, boolean>;
25
- changed: Record<PropertyKey<T>, boolean>;
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: PropertyKey<T>) => { status?: 'error'; error?: string };
34
- getValue: <V>(property: PropertyKey<T>) => V;
35
- onValueChange: <V>(property: PropertyKey<T>, type: SimpleType, value: V) => void;
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<PropertyKey<T>, boolean>>(createKeySet(initialValues, false));
99
- const [changed, setChanged] = useState<Record<PropertyKey<T>, boolean>>(createKeySet(initialValues, false));
100
- const [errors, setErrors] = useState<Record<PropertyKey<T>, string>>({} as Record<PropertyKey<T>, string>);
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: PropertyKey<T>) => ({
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: PropertyKey<T>): V => {
169
- return values[property] as V;
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: PropertyKey<T>, type: SimpleType, value: any) => {
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 = { ...values, [property]: parsedValue };
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<PropertyKey<T>, V> => {
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<PropertyKey<T>, V>);
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 PropertyKey<T>] = message;
242
+ result[path as FormPath<T>] = message;
240
243
  }
241
244
  return result;
242
245
  },
243
- {} as Record<PropertyKey<T>, string>,
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
+ };