@dxos/react-ui-form 0.7.4 → 0.7.5-main.937ce75

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.
Files changed (47) hide show
  1. package/dist/lib/browser/index.mjs +246 -209
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node/index.cjs +340 -302
  5. package/dist/lib/node/index.cjs.map +4 -4
  6. package/dist/lib/node/meta.json +1 -1
  7. package/dist/lib/node-esm/index.mjs +246 -209
  8. package/dist/lib/node-esm/index.mjs.map +4 -4
  9. package/dist/lib/node-esm/meta.json +1 -1
  10. package/dist/types/src/components/FieldEditor/FieldEditor.d.ts +2 -2
  11. package/dist/types/src/components/FieldEditor/FieldEditor.d.ts.map +1 -1
  12. package/dist/types/src/components/Form/Form.d.ts +1 -1
  13. package/dist/types/src/components/Form/Form.d.ts.map +1 -1
  14. package/dist/types/src/components/Form/Form.stories.d.ts +5 -0
  15. package/dist/types/src/components/Form/Form.stories.d.ts.map +1 -1
  16. package/dist/types/src/components/Form/Input.d.ts +3 -3
  17. package/dist/types/src/components/Form/Input.d.ts.map +1 -1
  18. package/dist/types/src/components/Form/{Custom.d.ts → custom/GeoPointInput.d.ts} +3 -3
  19. package/dist/types/src/components/Form/custom/GeoPointInput.d.ts.map +1 -0
  20. package/dist/types/src/components/Form/custom/TupleInput.d.ts +7 -0
  21. package/dist/types/src/components/Form/custom/TupleInput.d.ts.map +1 -0
  22. package/dist/types/src/components/Form/custom/index.d.ts +3 -0
  23. package/dist/types/src/components/Form/custom/index.d.ts.map +1 -0
  24. package/dist/types/src/components/Form/factory.d.ts.map +1 -1
  25. package/dist/types/src/components/Form/index.d.ts +2 -2
  26. package/dist/types/src/components/Form/index.d.ts.map +1 -1
  27. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts +4 -4
  28. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts.map +1 -1
  29. package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts.map +1 -1
  30. package/dist/types/src/hooks/useForm.d.ts +9 -10
  31. package/dist/types/src/hooks/useForm.d.ts.map +1 -1
  32. package/dist/types/tsconfig.tsbuildinfo +1 -0
  33. package/package.json +24 -24
  34. package/src/components/FieldEditor/FieldEditor.stories.tsx +2 -2
  35. package/src/components/FieldEditor/FieldEditor.tsx +75 -50
  36. package/src/components/Form/Form.stories.tsx +33 -1
  37. package/src/components/Form/Form.tsx +3 -4
  38. package/src/components/Form/Input.tsx +3 -3
  39. package/src/components/Form/{Custom.tsx → custom/GeoPointInput.tsx} +4 -16
  40. package/src/components/Form/custom/TupleInput.tsx +53 -0
  41. package/src/components/Form/custom/index.ts +6 -0
  42. package/src/components/Form/factory.tsx +2 -2
  43. package/src/components/Form/index.ts +3 -2
  44. package/src/components/ViewEditor/ViewEditor.stories.tsx +6 -5
  45. package/src/components/ViewEditor/ViewEditor.tsx +4 -4
  46. package/src/hooks/useForm.ts +32 -52
  47. package/dist/types/src/components/Form/Custom.d.ts.map +0 -1
@@ -82,27 +82,16 @@ var DeprecatedFormInput = ({ label, description, secondary, children }) => {
82
82
  };
83
83
 
84
84
  // packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx
85
- import React6, { useCallback as useCallback2, useEffect as useEffect3, useState as useState2 } from "react";
85
+ import React7, { useCallback as useCallback2, useEffect as useEffect3, useMemo as useMemo3, useState as useState2 } from "react";
86
86
  import { FormatEnum as FormatEnum2, FormatEnums, formatToType } from "@dxos/echo-schema";
87
87
  import { log as log3 } from "@dxos/log";
88
88
  import { useTranslation as useTranslation3 } from "@dxos/react-ui";
89
89
  import { getFormatSchema, getSchemaProperties as getSchemaProperties2, sortProperties } from "@dxos/schema";
90
90
 
91
- // packages/ui/react-ui-form/src/components/Form/Form.tsx
92
- import { pipe } from "effect";
93
- import { capitalize } from "effect/String";
94
- import React5, { useEffect as useEffect2, useMemo as useMemo2 } from "react";
95
- import { AST, S } from "@dxos/echo-schema";
96
- import { findNode, getDiscriminatedType, isDiscriminatedUnion, SimpleType } from "@dxos/effect";
97
- import { log as log2 } from "@dxos/log";
98
- import { IconButton, useTranslation as useTranslation2 } from "@dxos/react-ui";
99
- import { mx } from "@dxos/react-ui-theme";
100
- import { getSchemaProperties } from "@dxos/schema";
101
- import { isNotFalsy } from "@dxos/util";
102
-
103
- // packages/ui/react-ui-form/src/components/Form/Defaults.tsx
91
+ // packages/ui/react-ui-form/src/components/Form/custom/GeoPointInput.tsx
104
92
  import React3 from "react";
105
- import { Input as Input2, Select } from "@dxos/react-ui";
93
+ import { Input as Input2, useTranslation } from "@dxos/react-ui";
94
+ import { safeParseFloat } from "@dxos/util";
106
95
 
107
96
  // packages/ui/react-ui-form/src/components/Form/Input.tsx
108
97
  import React2 from "react";
@@ -123,120 +112,156 @@ var InputHeader = ({ children, error }) => {
123
112
  }, /* @__PURE__ */ React2.createElement(Tooltip.Arrow, null), error)));
124
113
  };
125
114
 
126
- // packages/ui/react-ui-form/src/components/Form/Defaults.tsx
127
- var TextInput = ({ property, type, label, inputOnly, disabled, placeholder, getStatus, getValue, onValueChange, onBlur }) => {
115
+ // packages/ui/react-ui-form/src/components/Form/custom/GeoPointInput.tsx
116
+ var GeoPointInput = ({ property, type, label, disabled, getStatus, getValue: getValue2, onValueChange, onBlur }) => {
117
+ const { t } = useTranslation(translationKey);
128
118
  const { status, error } = getStatus?.(property);
119
+ const [lng = 0, lat = 0] = getValue2(property) ?? [];
129
120
  return /* @__PURE__ */ React3.createElement(Input2.Root, {
130
121
  validationValence: status
131
- }, !inputOnly && /* @__PURE__ */ React3.createElement(InputHeader, {
122
+ }, /* @__PURE__ */ React3.createElement(InputHeader, {
123
+ error
124
+ }, /* @__PURE__ */ React3.createElement(Input2.Label, null, label)), /* @__PURE__ */ React3.createElement("div", {
125
+ className: "grid grid-cols-2 gap-2"
126
+ }, /* @__PURE__ */ React3.createElement(Input2.TextInput, {
127
+ type: "number",
128
+ disabled,
129
+ placeholder: t("placeholder longitude"),
130
+ value: lng,
131
+ onChange: (event) => onValueChange(property, type, [
132
+ lat,
133
+ safeParseFloat(event.target.value, 0)
134
+ ]),
135
+ onBlur
136
+ }), /* @__PURE__ */ React3.createElement(Input2.TextInput, {
137
+ type: "number",
138
+ disabled,
139
+ placeholder: t("placeholder latitude"),
140
+ value: lat,
141
+ onChange: (event) => onValueChange(property, type, [
142
+ safeParseFloat(event.target.value, 0),
143
+ lng
144
+ ]),
145
+ onBlur
146
+ })));
147
+ };
148
+
149
+ // packages/ui/react-ui-form/src/components/Form/custom/TupleInput.tsx
150
+ import React4 from "react";
151
+ import { Input as Input3 } from "@dxos/react-ui";
152
+ import { mx } from "@dxos/react-ui-theme";
153
+ import { safeParseFloat as safeParseFloat2 } from "@dxos/util";
154
+ var gridCols = [
155
+ "grid-cols-1",
156
+ "grid-cols-2",
157
+ "grid-cols-3",
158
+ "grid-cols-4"
159
+ ];
160
+ var TupleInput = ({ binding, property, type, label, disabled, getStatus, getValue: getValue2, onValueChange, onBlur }) => {
161
+ const { status, error } = getStatus?.(property);
162
+ const values = getValue2(property) ?? {};
163
+ return /* @__PURE__ */ React4.createElement(Input3.Root, {
164
+ validationValence: status
165
+ }, /* @__PURE__ */ React4.createElement(InputHeader, {
166
+ error
167
+ }, /* @__PURE__ */ React4.createElement(Input3.Label, null, label)), /* @__PURE__ */ React4.createElement("div", {
168
+ className: mx("grid gap-2", gridCols[binding.length - 1])
169
+ }, binding.map((prop) => /* @__PURE__ */ React4.createElement(Input3.TextInput, {
170
+ key: prop,
171
+ type: "number",
172
+ disabled,
173
+ value: values[prop],
174
+ onChange: (event) => onValueChange(property, type, {
175
+ ...values,
176
+ [prop]: safeParseFloat2(event.target.value, 0)
177
+ }),
178
+ onBlur
179
+ }))));
180
+ };
181
+
182
+ // packages/ui/react-ui-form/src/components/Form/Defaults.tsx
183
+ import React5 from "react";
184
+ import { Input as Input4, Select } from "@dxos/react-ui";
185
+ var TextInput = ({ property, type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue2, onValueChange, onBlur }) => {
186
+ const { status, error } = getStatus?.(property);
187
+ return /* @__PURE__ */ React5.createElement(Input4.Root, {
188
+ validationValence: status
189
+ }, !inputOnly && /* @__PURE__ */ React5.createElement(InputHeader, {
132
190
  error
133
- }, /* @__PURE__ */ React3.createElement(Input2.Label, null, label)), /* @__PURE__ */ React3.createElement(Input2.TextInput, {
191
+ }, /* @__PURE__ */ React5.createElement(Input4.Label, null, label)), /* @__PURE__ */ React5.createElement(Input4.TextInput, {
134
192
  disabled,
135
193
  placeholder,
136
- value: getValue(property) ?? "",
194
+ value: getValue2(property) ?? "",
137
195
  onChange: (event) => onValueChange(property, type, event.target.value),
138
196
  onBlur
139
- }), inputOnly && /* @__PURE__ */ React3.createElement(Input2.Validation, null, error));
197
+ }), inputOnly && /* @__PURE__ */ React5.createElement(Input4.Validation, null, error));
140
198
  };
141
- var NumberInput = ({ property, type, label, inputOnly, disabled, placeholder, getStatus, getValue, onValueChange, onBlur }) => {
199
+ var NumberInput = ({ property, type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue2, onValueChange, onBlur }) => {
142
200
  const { status, error } = getStatus?.(property);
143
- return /* @__PURE__ */ React3.createElement(Input2.Root, {
201
+ return /* @__PURE__ */ React5.createElement(Input4.Root, {
144
202
  validationValence: status
145
- }, !inputOnly && /* @__PURE__ */ React3.createElement(InputHeader, {
203
+ }, !inputOnly && /* @__PURE__ */ React5.createElement(InputHeader, {
146
204
  error
147
- }, /* @__PURE__ */ React3.createElement(Input2.Label, null, label)), /* @__PURE__ */ React3.createElement(Input2.TextInput, {
205
+ }, /* @__PURE__ */ React5.createElement(Input4.Label, null, label)), /* @__PURE__ */ React5.createElement(Input4.TextInput, {
148
206
  type: "number",
149
207
  disabled,
150
208
  placeholder,
151
- value: getValue(property) ?? 0,
209
+ value: getValue2(property) ?? 0,
152
210
  onChange: (event) => onValueChange(property, type, event.target.value),
153
211
  onBlur
154
- }), inputOnly && /* @__PURE__ */ React3.createElement(Input2.DescriptionAndValidation, null, error));
212
+ }), inputOnly && /* @__PURE__ */ React5.createElement(Input4.DescriptionAndValidation, null, error));
155
213
  };
156
- var BooleanInput = ({ property, type, label, inputOnly, getStatus, getValue, onValueChange }) => {
214
+ var BooleanInput = ({ property, type, label, inputOnly, getStatus, getValue: getValue2, onValueChange }) => {
157
215
  const { status, error } = getStatus?.(property);
158
- return /* @__PURE__ */ React3.createElement(Input2.Root, {
216
+ return /* @__PURE__ */ React5.createElement(Input4.Root, {
159
217
  validationValence: status
160
- }, !inputOnly && /* @__PURE__ */ React3.createElement(InputHeader, {
218
+ }, !inputOnly && /* @__PURE__ */ React5.createElement(InputHeader, {
161
219
  error
162
- }, /* @__PURE__ */ React3.createElement(Input2.Label, null, label)), /* @__PURE__ */ React3.createElement(Input2.Switch, {
163
- checked: getValue(property),
220
+ }, /* @__PURE__ */ React5.createElement(Input4.Label, null, label)), /* @__PURE__ */ React5.createElement(Input4.Switch, {
221
+ checked: getValue2(property),
164
222
  onCheckedChange: (value) => onValueChange(property, type, value)
165
- }), inputOnly && /* @__PURE__ */ React3.createElement(Input2.DescriptionAndValidation, null, error));
223
+ }), inputOnly && /* @__PURE__ */ React5.createElement(Input4.DescriptionAndValidation, null, error));
166
224
  };
167
- var SelectInput = ({ property, type, label, inputOnly, disabled, placeholder, options, getStatus, getValue, onValueChange }) => {
225
+ var SelectInput = ({ property, type, label, inputOnly, disabled, placeholder, options, getStatus, getValue: getValue2, onValueChange }) => {
168
226
  const { status, error } = getStatus?.(property);
169
- return /* @__PURE__ */ React3.createElement(Input2.Root, {
227
+ return /* @__PURE__ */ React5.createElement(Input4.Root, {
170
228
  validationValence: status
171
- }, !inputOnly && /* @__PURE__ */ React3.createElement(InputHeader, {
229
+ }, !inputOnly && /* @__PURE__ */ React5.createElement(InputHeader, {
172
230
  error
173
- }, /* @__PURE__ */ React3.createElement(Input2.Label, null, label)), /* @__PURE__ */ React3.createElement(Select.Root, {
174
- value: getValue(property),
231
+ }, /* @__PURE__ */ React5.createElement(Input4.Label, null, label)), /* @__PURE__ */ React5.createElement(Select.Root, {
232
+ value: getValue2(property),
175
233
  onValueChange: (value) => onValueChange(property, type, value)
176
- }, /* @__PURE__ */ React3.createElement(Select.TriggerButton, {
234
+ }, /* @__PURE__ */ React5.createElement(Select.TriggerButton, {
177
235
  classNames: "is-full",
178
236
  disabled,
179
237
  placeholder
180
- }), /* @__PURE__ */ React3.createElement(Select.Portal, null, /* @__PURE__ */ React3.createElement(Select.Content, null, /* @__PURE__ */ React3.createElement(Select.Viewport, null, options?.map(({ value, label: label2 }) => (
238
+ }), /* @__PURE__ */ React5.createElement(Select.Portal, null, /* @__PURE__ */ React5.createElement(Select.Content, null, /* @__PURE__ */ React5.createElement(Select.Viewport, null, options?.map(({ value, label: label2 }) => (
181
239
  // NOTE: Numeric values are converted to and from strings.
182
- /* @__PURE__ */ React3.createElement(Select.Option, {
240
+ /* @__PURE__ */ React5.createElement(Select.Option, {
183
241
  key: String(value),
184
242
  value: String(value)
185
243
  }, label2 ?? String(value))
186
- )))))), inputOnly && /* @__PURE__ */ React3.createElement(Input2.DescriptionAndValidation, null, error));
244
+ )))))), inputOnly && /* @__PURE__ */ React5.createElement(Input4.DescriptionAndValidation, null, error));
187
245
  };
188
246
 
189
- // packages/ui/react-ui-form/src/components/Form/factory.tsx
190
- import { FormatEnum } from "@dxos/echo-schema";
191
-
192
- // packages/ui/react-ui-form/src/components/Form/Custom.tsx
193
- import React4 from "react";
194
- import { Input as Input3, useTranslation } from "@dxos/react-ui";
195
- var GeiPointInput = ({ property, type, label, disabled, getStatus, getValue, onValueChange, onBlur }) => {
196
- const { t } = useTranslation(translationKey);
197
- const { status, error } = getStatus?.(property);
198
- const [lng = 0, lat = 0] = getValue(property) ?? [];
199
- return /* @__PURE__ */ React4.createElement(Input3.Root, {
200
- validationValence: status
201
- }, /* @__PURE__ */ React4.createElement(InputHeader, {
202
- error
203
- }, /* @__PURE__ */ React4.createElement(Input3.Label, null, label)), /* @__PURE__ */ React4.createElement("div", {
204
- className: "grid grid-cols-2 gap-2"
205
- }, /* @__PURE__ */ React4.createElement(Input3.TextInput, {
206
- type: "number",
207
- disabled,
208
- placeholder: t("placeholder longitude"),
209
- value: lng,
210
- onChange: (event) => onValueChange(property, type, [
211
- lat,
212
- safeParseFloat(event.target.value, 0)
213
- ]),
214
- onBlur
215
- }), /* @__PURE__ */ React4.createElement(Input3.TextInput, {
216
- type: "number",
217
- disabled,
218
- placeholder: t("placeholder latitude"),
219
- value: lat,
220
- onChange: (event) => onValueChange(property, type, [
221
- safeParseFloat(event.target.value, 0),
222
- lng
223
- ]),
224
- onBlur
225
- })));
226
- };
227
- var safeParseFloat = (str, defaultValue) => {
228
- try {
229
- return parseFloat(str);
230
- } catch {
231
- return defaultValue ?? 0;
232
- }
233
- };
247
+ // packages/ui/react-ui-form/src/components/Form/Form.tsx
248
+ import { pipe } from "effect";
249
+ import { capitalize } from "effect/String";
250
+ import React6, { useEffect as useEffect2, useMemo as useMemo2 } from "react";
251
+ import { AST, S } from "@dxos/echo-schema";
252
+ import { findNode, getDiscriminatedType, isDiscriminatedUnion, SimpleType } from "@dxos/effect";
253
+ import { log as log2 } from "@dxos/log";
254
+ import { IconButton, useTranslation as useTranslation2 } from "@dxos/react-ui";
255
+ import { mx as mx2 } from "@dxos/react-ui-theme";
256
+ import { getSchemaProperties } from "@dxos/schema";
257
+ import { isNotFalsy } from "@dxos/util";
234
258
 
235
259
  // packages/ui/react-ui-form/src/components/Form/factory.tsx
260
+ import { FormatEnum } from "@dxos/echo-schema";
236
261
  var getInputComponent = (type, format) => {
237
262
  switch (format) {
238
263
  case FormatEnum.LatLng:
239
- return GeiPointInput;
264
+ return GeoPointInput;
240
265
  }
241
266
  switch (type) {
242
267
  case "string":
@@ -250,6 +275,7 @@ var getInputComponent = (type, format) => {
250
275
 
251
276
  // packages/ui/react-ui-form/src/hooks/useForm.ts
252
277
  import { useCallback, useEffect, useMemo, useState } from "react";
278
+ import { getValue, setValue } from "@dxos/echo-schema";
253
279
  import { invariant } from "@dxos/invariant";
254
280
  import { log } from "@dxos/log";
255
281
  import { validateSchema } from "@dxos/schema";
@@ -268,10 +294,12 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
268
294
  const validate = useCallback((values2) => {
269
295
  let errors2 = validateSchema(schema, values2) ?? [];
270
296
  if (errors2.length === 0 && onValidate) {
271
- errors2 = onValidate(values2) ?? [];
297
+ const validatedValues = values2;
298
+ errors2 = onValidate(validatedValues) ?? [];
272
299
  }
273
300
  setErrors(flatMap(errors2));
274
- return errors2.length === 0;
301
+ const valid = errors2.length === 0;
302
+ return valid;
275
303
  }, [
276
304
  schema,
277
305
  onValidate
@@ -309,7 +337,8 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
309
337
  }, [
310
338
  values,
311
339
  validate,
312
- onSave
340
+ onSave,
341
+ changed
313
342
  ]);
314
343
  const getStatus = useCallback((property) => ({
315
344
  status: errors[property] ? "error" : void 0,
@@ -318,8 +347,8 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
318
347
  touched,
319
348
  errors
320
349
  ]);
321
- const getValue = (property) => {
322
- return getByPath(values, property);
350
+ const getFormValue = (property) => {
351
+ return getValue(values, property);
323
352
  };
324
353
  const onValueChange = (property, type, value) => {
325
354
  let parsedValue = value;
@@ -330,13 +359,15 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
330
359
  } catch (err) {
331
360
  log.catch(err, void 0, {
332
361
  F: __dxlog_file,
333
- L: 183,
362
+ L: 178,
334
363
  S: void 0,
335
364
  C: (f, a) => f(...a)
336
365
  });
337
366
  parsedValue = void 0;
338
367
  }
339
- const newValues = setByPath(values, property, parsedValue);
368
+ const newValues = {
369
+ ...setValue(values, property, parsedValue)
370
+ };
340
371
  setValues(newValues);
341
372
  setChanged((prev) => ({
342
373
  ...prev,
@@ -374,7 +405,7 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
374
405
  handleSave,
375
406
  // Field utils.
376
407
  getStatus,
377
- getValue,
408
+ getValue: getFormValue,
378
409
  onValueChange,
379
410
  onBlur
380
411
  };
@@ -382,7 +413,7 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
382
413
  var createKeySet = (obj, value) => {
383
414
  invariant(obj, void 0, {
384
415
  F: __dxlog_file,
385
- L: 234,
416
+ L: 229,
386
417
  S: void 0,
387
418
  A: [
388
419
  "obj",
@@ -402,20 +433,6 @@ var flatMap = (errors) => {
402
433
  return result;
403
434
  }, {});
404
435
  };
405
- var getByPath = (obj, path) => {
406
- const [key, index] = path.split(".");
407
- return index === void 0 ? obj[key] : obj[key][parseInt(index)];
408
- };
409
- var setByPath = (obj, path, value) => {
410
- const [key, index] = path.split(".");
411
- const newValue = index === void 0 ? value : [
412
- ...obj[key]
413
- ].map((v, i) => i === parseInt(index) ? value : v);
414
- return {
415
- ...obj,
416
- [key]: newValue
417
- };
418
- };
419
436
 
420
437
  // packages/ui/react-ui-form/src/components/Form/Form.tsx
421
438
  var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/Form/Form.tsx";
@@ -452,7 +469,7 @@ var Form = ({ classNames, schema, values: initialValues, path = [], readonly, fi
452
469
  errors
453
470
  }, {
454
471
  F: __dxlog_file2,
455
- L: 100,
472
+ L: 99,
456
473
  S: void 0,
457
474
  C: (f, a) => f(...a)
458
475
  });
@@ -460,9 +477,9 @@ var Form = ({ classNames, schema, values: initialValues, path = [], readonly, fi
460
477
  }, [
461
478
  errors
462
479
  ]);
463
- return /* @__PURE__ */ React5.createElement("div", {
480
+ return /* @__PURE__ */ React6.createElement("div", {
464
481
  role: "form",
465
- className: mx("flex flex-col w-full gap-2 py-2", classNames),
482
+ className: mx2("flex flex-col w-full gap-2 py-2", classNames),
466
483
  "data-testid": testId
467
484
  }, properties.map((property) => {
468
485
  const { ast, name, type, format, title, description, examples, options, array } = property;
@@ -475,11 +492,11 @@ var Form = ({ classNames, schema, values: initialValues, path = [], readonly, fi
475
492
  let InputComponent = Custom?.[key.join(".")];
476
493
  if (!InputComponent) {
477
494
  if (options) {
478
- return /* @__PURE__ */ React5.createElement("div", {
495
+ return /* @__PURE__ */ React6.createElement("div", {
479
496
  key: name,
480
497
  role: "none",
481
498
  className: padding
482
- }, /* @__PURE__ */ React5.createElement(SelectInput, {
499
+ }, /* @__PURE__ */ React6.createElement(SelectInput, {
483
500
  type,
484
501
  format,
485
502
  property: name,
@@ -495,7 +512,7 @@ var Form = ({ classNames, schema, values: initialValues, path = [], readonly, fi
495
512
  }
496
513
  InputComponent = getInputComponent(type, format);
497
514
  if (array) {
498
- return /* @__PURE__ */ React5.createElement(ArrayField, {
515
+ return /* @__PURE__ */ React6.createElement(ArrayField, {
499
516
  key: name,
500
517
  name,
501
518
  type,
@@ -517,12 +534,12 @@ var Form = ({ classNames, schema, values: initialValues, path = [], readonly, fi
517
534
  const typeLiteral = baseNode ? getDiscriminatedType(baseNode, values[name]) : findNode(ast, AST.isTypeLiteral);
518
535
  if (typeLiteral) {
519
536
  const schema2 = S.make(typeLiteral);
520
- return /* @__PURE__ */ React5.createElement("div", {
537
+ return /* @__PURE__ */ React6.createElement("div", {
521
538
  key: name,
522
539
  role: "none"
523
- }, /* @__PURE__ */ React5.createElement("div", {
540
+ }, /* @__PURE__ */ React6.createElement("div", {
524
541
  className: padding
525
- }, label), /* @__PURE__ */ React5.createElement(Form, {
542
+ }, label), /* @__PURE__ */ React6.createElement(Form, {
526
543
  schema: schema2,
527
544
  path: key,
528
545
  values: values[name] ?? {},
@@ -538,17 +555,17 @@ var Form = ({ classNames, schema, values: initialValues, path = [], readonly, fi
538
555
  type
539
556
  }, {
540
557
  F: __dxlog_file2,
541
- L: 185,
558
+ L: 184,
542
559
  S: void 0,
543
560
  C: (f, a) => f(...a)
544
561
  });
545
562
  return null;
546
563
  }
547
- return /* @__PURE__ */ React5.createElement("div", {
564
+ return /* @__PURE__ */ React6.createElement("div", {
548
565
  key: name,
549
566
  role: "none",
550
567
  className: padding
551
- }, /* @__PURE__ */ React5.createElement(InputComponent, {
568
+ }, /* @__PURE__ */ React6.createElement(InputComponent, {
552
569
  type,
553
570
  format,
554
571
  property: name,
@@ -557,7 +574,7 @@ var Form = ({ classNames, schema, values: initialValues, path = [], readonly, fi
557
574
  placeholder,
558
575
  ...inputProps
559
576
  }));
560
- }).filter(isNotFalsy), (onCancel || onSave) && !autoSave && /* @__PURE__ */ React5.createElement(FormActions, {
577
+ }).filter(isNotFalsy), (onCancel || onSave) && !autoSave && /* @__PURE__ */ React6.createElement(FormActions, {
561
578
  onCancel,
562
579
  onSubmit: handleSave,
563
580
  canSubmit: canSave,
@@ -577,26 +594,26 @@ var ArrayField = ({ name, type, label, ast, values, format, readonly, placeholde
577
594
  const typeLiteral = baseNode ? getDiscriminatedType(baseNode, values[name]) : findNode(elementType, AST.isTypeLiteral);
578
595
  if (typeLiteral) {
579
596
  const schema = S.make(typeLiteral);
580
- return /* @__PURE__ */ React5.createElement("div", {
597
+ return /* @__PURE__ */ React6.createElement("div", {
581
598
  key: name,
582
599
  role: "none",
583
- className: mx(padding)
584
- }, /* @__PURE__ */ React5.createElement(InputHeader, null, label), /* @__PURE__ */ React5.createElement("div", {
600
+ className: mx2(padding)
601
+ }, /* @__PURE__ */ React6.createElement(InputHeader, null, label), /* @__PURE__ */ React6.createElement("div", {
585
602
  role: "none",
586
603
  className: "flex flex-col gap-1"
587
604
  }, arrayValues.map((value, index) => {
588
- return /* @__PURE__ */ React5.createElement("div", {
605
+ return /* @__PURE__ */ React6.createElement("div", {
589
606
  key: index,
590
607
  role: "none",
591
608
  className: "flex items-center gap-1"
592
- }, /* @__PURE__ */ React5.createElement("div", {
609
+ }, /* @__PURE__ */ React6.createElement("div", {
593
610
  role: "none",
594
611
  className: "flex-1"
595
- }, /* @__PURE__ */ React5.createElement(Form, {
612
+ }, /* @__PURE__ */ React6.createElement(Form, {
596
613
  schema,
597
614
  path: [
598
615
  ...key,
599
- index.toString()
616
+ `[${index}]`
600
617
  ],
601
618
  values: value,
602
619
  onValuesChanged: (childValues) => {
@@ -607,7 +624,7 @@ var ArrayField = ({ name, type, label, ast, values, format, readonly, placeholde
607
624
  inputProps.onValueChange(name, "object", newValues);
608
625
  },
609
626
  Custom
610
- })), /* @__PURE__ */ React5.createElement(IconButton, {
627
+ })), /* @__PURE__ */ React6.createElement(IconButton, {
611
628
  icon: "ph--trash--regular",
612
629
  iconOnly: true,
613
630
  label: t("button remove"),
@@ -616,10 +633,10 @@ var ArrayField = ({ name, type, label, ast, values, format, readonly, placeholde
616
633
  inputProps.onValueChange(name, type, newValues);
617
634
  }
618
635
  }));
619
- })), /* @__PURE__ */ React5.createElement("div", {
636
+ })), /* @__PURE__ */ React6.createElement("div", {
620
637
  role: "none",
621
638
  className: "flex justify-between items-center plb-1"
622
- }, /* @__PURE__ */ React5.createElement(IconButton, {
639
+ }, /* @__PURE__ */ React6.createElement(IconButton, {
623
640
  icon: "ph--plus--regular",
624
641
  iconOnly: true,
625
642
  label: t("button add"),
@@ -632,7 +649,7 @@ var ArrayField = ({ name, type, label, ast, values, format, readonly, placeholde
632
649
  }
633
650
  })));
634
651
  }
635
- return /* @__PURE__ */ React5.createElement("div", {
652
+ return /* @__PURE__ */ React6.createElement("div", {
636
653
  key: name,
637
654
  role: "none"
638
655
  }, "Nested form not supported in arrays, yet.");
@@ -641,30 +658,30 @@ var ArrayField = ({ name, type, label, ast, values, format, readonly, placeholde
641
658
  if (!InputComponent) {
642
659
  return null;
643
660
  }
644
- return /* @__PURE__ */ React5.createElement("div", {
661
+ return /* @__PURE__ */ React6.createElement("div", {
645
662
  role: "none",
646
663
  key: "meta-input",
647
- className: mx(padding)
648
- }, /* @__PURE__ */ React5.createElement(InputHeader, null, label), /* @__PURE__ */ React5.createElement("div", {
664
+ className: mx2(padding)
665
+ }, /* @__PURE__ */ React6.createElement(InputHeader, null, label), /* @__PURE__ */ React6.createElement("div", {
649
666
  role: "none",
650
667
  className: "flex flex-col gap-1"
651
- }, arrayValues.map((_, index) => /* @__PURE__ */ React5.createElement("div", {
668
+ }, arrayValues.map((_, index) => /* @__PURE__ */ React6.createElement("div", {
652
669
  key: index,
653
670
  role: "none",
654
671
  className: "flex items-start gap-1"
655
- }, /* @__PURE__ */ React5.createElement("div", {
672
+ }, /* @__PURE__ */ React6.createElement("div", {
656
673
  role: "none",
657
674
  className: "flex-1"
658
- }, /* @__PURE__ */ React5.createElement(InputComponent, {
675
+ }, /* @__PURE__ */ React6.createElement(InputComponent, {
659
676
  type,
660
677
  format,
661
678
  label,
662
679
  inputOnly: true,
663
- property: `${name}.${index}`,
680
+ property: `${name}[${index}]`,
664
681
  disabled: readonly,
665
682
  placeholder,
666
683
  ...inputProps
667
- })), /* @__PURE__ */ React5.createElement(IconButton, {
684
+ })), /* @__PURE__ */ React6.createElement(IconButton, {
668
685
  icon: "ph--trash--regular",
669
686
  iconOnly: true,
670
687
  label: t("button remove"),
@@ -672,10 +689,10 @@ var ArrayField = ({ name, type, label, ast, values, format, readonly, placeholde
672
689
  const newValues = arrayValues.filter((_2, i) => i !== index);
673
690
  inputProps.onValueChange(name, type, newValues);
674
691
  }
675
- })))), /* @__PURE__ */ React5.createElement("div", {
692
+ })))), /* @__PURE__ */ React6.createElement("div", {
676
693
  role: "none",
677
694
  className: "flex justify-between items-center plb-1"
678
- }, /* @__PURE__ */ React5.createElement(IconButton, {
695
+ }, /* @__PURE__ */ React6.createElement(IconButton, {
679
696
  icon: "ph--plus--regular",
680
697
  iconOnly: true,
681
698
  label: t("button add"),
@@ -690,18 +707,18 @@ var ArrayField = ({ name, type, label, ast, values, format, readonly, placeholde
690
707
  };
691
708
  var FormActions = ({ onCancel, onSubmit, canSubmit, readonly }) => {
692
709
  const { t } = useTranslation2(translationKey);
693
- return /* @__PURE__ */ React5.createElement("div", {
710
+ return /* @__PURE__ */ React6.createElement("div", {
694
711
  role: "none",
695
712
  className: "flex justify-center"
696
- }, /* @__PURE__ */ React5.createElement("div", {
713
+ }, /* @__PURE__ */ React6.createElement("div", {
697
714
  role: "none",
698
- className: mx(onCancel && !readonly && "grid grid-cols-2 gap-2")
699
- }, onCancel && !readonly && /* @__PURE__ */ React5.createElement(IconButton, {
715
+ className: mx2(onCancel && !readonly && "grid grid-cols-2 gap-2")
716
+ }, onCancel && !readonly && /* @__PURE__ */ React6.createElement(IconButton, {
700
717
  "data-testid": "cancel-button",
701
718
  icon: "ph--x--regular",
702
719
  label: t("button cancel"),
703
720
  onClick: onCancel
704
- }), onSubmit && /* @__PURE__ */ React5.createElement(IconButton, {
721
+ }), onSubmit && /* @__PURE__ */ React6.createElement(IconButton, {
705
722
  type: "submit",
706
723
  "data-testid": "save-button",
707
724
  disabled: !canSubmit,
@@ -725,9 +742,11 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
725
742
  if (!registry) {
726
743
  return;
727
744
  }
728
- const subscription = registry.subscribe(setSchemas);
745
+ const subscription = registry.query().subscribe((query) => setSchemas(query.results), {
746
+ fire: true
747
+ });
729
748
  const t2 = setTimeout(async () => {
730
- const schemas2 = await registry.query();
749
+ const schemas2 = await registry.query().run();
731
750
  setSchemas(schemas2);
732
751
  });
733
752
  return () => {
@@ -737,9 +756,9 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
737
756
  }, [
738
757
  registry
739
758
  ]);
740
- const [schema, setSchema] = useState2();
759
+ const [referenceSchema, setReferenceSchema] = useState2();
741
760
  useEffect3(() => {
742
- setSchema(schemas.find((schema2) => schema2.typename === props?.referenceSchema));
761
+ setReferenceSchema(schemas.find((schema) => schema.typename === props?.referenceSchema));
743
762
  }, [
744
763
  schemas,
745
764
  props?.referenceSchema
@@ -748,14 +767,24 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
748
767
  fieldSchema: getFormatSchema(props?.format)
749
768
  });
750
769
  const handleValuesChanged = useCallback2((_props) => {
751
- if (_props.format !== props.format) {
752
- setFieldSchema({
753
- fieldSchema: getFormatSchema(_props.format)
754
- });
755
- }
756
- if (_props.referenceSchema !== props.referenceSchema) {
757
- setSchema(schemas.find((schema2) => schema2.typename === _props.referenceSchema));
758
- }
770
+ setFieldSchema((prev) => {
771
+ const fieldSchema2 = getFormatSchema(_props.format);
772
+ if (prev.fieldSchema === fieldSchema2) {
773
+ return prev;
774
+ }
775
+ return {
776
+ fieldSchema: fieldSchema2
777
+ };
778
+ });
779
+ setReferenceSchema((prev) => {
780
+ if (_props.referenceSchema !== prev?.typename) {
781
+ const newSchema = schemas.find((schema) => schema.typename === _props.referenceSchema);
782
+ if (newSchema) {
783
+ return newSchema;
784
+ }
785
+ }
786
+ return prev;
787
+ });
759
788
  setProps((props2) => {
760
789
  const type = formatToType[_props.format];
761
790
  if (props2.type !== type) {
@@ -769,7 +798,8 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
769
798
  });
770
799
  }, [
771
800
  schemas,
772
- props
801
+ props.format,
802
+ props.referenceSchema
773
803
  ]);
774
804
  const handleValidate = useCallback2(({ property }) => {
775
805
  if (property && view.fields.find((f) => f.path === property && f.path !== field.path)) {
@@ -801,23 +831,49 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
801
831
  }, [
802
832
  onSave
803
833
  ]);
834
+ const Custom = useMemo3(() => ({
835
+ ["format"]: (props2) => /* @__PURE__ */ React7.createElement(SelectInput, {
836
+ ...props2,
837
+ options: FormatEnums.filter((value) => value !== FormatEnum2.None).map((value) => ({
838
+ value,
839
+ label: t(`format ${value}`)
840
+ }))
841
+ }),
842
+ ["referenceSchema"]: (props2) => /* @__PURE__ */ React7.createElement(SelectInput, {
843
+ ...props2,
844
+ options: schemas.map((schema) => ({
845
+ value: schema.typename
846
+ }))
847
+ }),
848
+ ["referencePath"]: (props2) => /* @__PURE__ */ React7.createElement(SelectInput, {
849
+ ...props2,
850
+ options: referenceSchema ? getSchemaProperties2(referenceSchema.ast).sort(sortProperties).map((p) => ({
851
+ value: p.name
852
+ })) : []
853
+ })
854
+ }), [
855
+ t,
856
+ schemas,
857
+ referenceSchema
858
+ ]);
859
+ const propIsNotType = useCallback2((props2) => props2.filter((p) => p.name !== "type"), []);
804
860
  if (!fieldSchema) {
805
861
  log3.warn("invalid format", {
806
862
  props
807
863
  }, {
808
864
  F: __dxlog_file3,
809
- L: 118,
865
+ L: 173,
810
866
  S: void 0,
811
867
  C: (f, a) => f(...a)
812
868
  });
813
869
  return null;
814
870
  }
815
- return /* @__PURE__ */ React6.createElement(Form, {
871
+ return /* @__PURE__ */ React7.createElement(Form, {
816
872
  key: field.id,
817
873
  autoFocus: true,
818
874
  values: props,
819
875
  schema: fieldSchema,
820
- filter: (props2) => props2.filter((p) => p.name !== "type"),
876
+ filter: propIsNotType,
821
877
  sort: [
822
878
  "property",
823
879
  "format"
@@ -826,36 +882,16 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
826
882
  onValidate: handleValidate,
827
883
  onSave: handleSave,
828
884
  onCancel: handleCancel,
829
- Custom: {
830
- ["format"]: (props2) => /* @__PURE__ */ React6.createElement(SelectInput, {
831
- ...props2,
832
- options: FormatEnums.filter((value) => value !== FormatEnum2.None).map((value) => ({
833
- value,
834
- label: t(`format ${value}`)
835
- }))
836
- }),
837
- ["referenceSchema"]: (props2) => /* @__PURE__ */ React6.createElement(SelectInput, {
838
- ...props2,
839
- options: schemas.map((schema2) => ({
840
- value: schema2.typename
841
- }))
842
- }),
843
- ["referencePath"]: (props2) => /* @__PURE__ */ React6.createElement(SelectInput, {
844
- ...props2,
845
- options: schema ? getSchemaProperties2(schema.schema.ast).sort(sortProperties).map((p) => ({
846
- value: p.name
847
- })) : []
848
- })
849
- }
885
+ Custom
850
886
  });
851
887
  };
852
888
 
853
889
  // packages/ui/react-ui-form/src/components/ViewEditor/ViewEditor.tsx
854
- import React7, { useCallback as useCallback3, useMemo as useMemo3, useState as useState3 } from "react";
890
+ import React8, { useCallback as useCallback3, useMemo as useMemo4, useState as useState3 } from "react";
855
891
  import { AST as AST2, Format, S as S2 } from "@dxos/echo-schema";
856
892
  import { IconButton as IconButton2, useTranslation as useTranslation4 } from "@dxos/react-ui";
857
893
  import { List } from "@dxos/react-ui-list";
858
- import { ghostHover, inputTextLabel, mx as mx2 } from "@dxos/react-ui-theme";
894
+ import { ghostHover, inputTextLabel, mx as mx3 } from "@dxos/react-ui-theme";
859
895
  import { FieldSchema, ViewProjection, VIEW_FIELD_LIMIT } from "@dxos/schema";
860
896
  import { arrayMove } from "@dxos/util";
861
897
  var grid = "grid grid-cols-[32px_1fr_32px] min-bs-[2.5rem]";
@@ -869,12 +905,12 @@ var ViewMetaSchema = S2.Struct({
869
905
  }).pipe(S2.mutable);
870
906
  var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading = false, onDelete }) => {
871
907
  const { t } = useTranslation4(translationKey);
872
- const projection = useMemo3(() => new ViewProjection(schema, view), [
908
+ const projection = useMemo4(() => new ViewProjection(schema, view), [
873
909
  schema,
874
910
  view
875
911
  ]);
876
912
  const [field, setField] = useState3();
877
- const viewValues = useMemo3(() => {
913
+ const viewValues = useMemo4(() => {
878
914
  return {
879
915
  name: view.name,
880
916
  // TODO(burdon): Need to warn user of possible consequences of editing.
@@ -909,52 +945,52 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
909
945
  view.fields
910
946
  ]);
911
947
  const handleClose = useCallback3(() => setField(void 0), []);
912
- return /* @__PURE__ */ React7.createElement("div", {
948
+ return /* @__PURE__ */ React8.createElement("div", {
913
949
  role: "none",
914
- className: mx2("flex flex-col w-full divide-y divide-separator", classNames)
915
- }, /* @__PURE__ */ React7.createElement(Form, {
950
+ className: mx3("flex flex-col w-full divide-y divide-separator", classNames)
951
+ }, /* @__PURE__ */ React8.createElement(Form, {
916
952
  autoFocus: true,
917
953
  autoSave: true,
918
954
  schema: ViewMetaSchema,
919
955
  values: viewValues,
920
956
  onSave: handleViewUpdate
921
- }), /* @__PURE__ */ React7.createElement("div", null, /* @__PURE__ */ React7.createElement("div", {
957
+ }), /* @__PURE__ */ React8.createElement("div", null, /* @__PURE__ */ React8.createElement("div", {
922
958
  role: "none",
923
959
  className: "p-2"
924
- }, /* @__PURE__ */ React7.createElement("label", {
925
- className: mx2(inputTextLabel)
926
- }, t("fields label"))), /* @__PURE__ */ React7.createElement(List.Root, {
960
+ }, /* @__PURE__ */ React8.createElement("label", {
961
+ className: mx3(inputTextLabel)
962
+ }, t("fields label"))), /* @__PURE__ */ React8.createElement(List.Root, {
927
963
  items: view.fields,
928
964
  isItem: S2.is(FieldSchema),
929
965
  getId: (field2) => field2.id,
930
966
  onMove: handleMove
931
- }, ({ items: fields }) => /* @__PURE__ */ React7.createElement(React7.Fragment, null, showHeading && /* @__PURE__ */ React7.createElement("div", {
967
+ }, ({ items: fields }) => /* @__PURE__ */ React8.createElement(React8.Fragment, null, showHeading && /* @__PURE__ */ React8.createElement("div", {
932
968
  role: "heading",
933
969
  className: grid
934
- }, /* @__PURE__ */ React7.createElement("div", null), /* @__PURE__ */ React7.createElement("div", {
970
+ }, /* @__PURE__ */ React8.createElement("div", null), /* @__PURE__ */ React8.createElement("div", {
935
971
  className: "flex items-center text-sm"
936
- }, t("field path label"))), /* @__PURE__ */ React7.createElement("div", {
972
+ }, t("field path label"))), /* @__PURE__ */ React8.createElement("div", {
937
973
  role: "list",
938
974
  className: "flex flex-col w-full"
939
- }, fields?.map((field2) => /* @__PURE__ */ React7.createElement(List.Item, {
975
+ }, fields?.map((field2) => /* @__PURE__ */ React8.createElement(List.Item, {
940
976
  key: field2.id,
941
977
  item: field2,
942
- classNames: mx2(grid, ghostHover, "cursor-pointer")
943
- }, /* @__PURE__ */ React7.createElement(List.ItemDragHandle, null), /* @__PURE__ */ React7.createElement(List.ItemTitle, {
978
+ classNames: mx3(grid, ghostHover, "cursor-pointer")
979
+ }, /* @__PURE__ */ React8.createElement(List.ItemDragHandle, null), /* @__PURE__ */ React8.createElement(List.ItemTitle, {
944
980
  onClick: () => handleSelect(field2)
945
- }, field2.path), /* @__PURE__ */ React7.createElement(List.ItemDeleteButton, {
981
+ }, field2.path), /* @__PURE__ */ React8.createElement(List.ItemDeleteButton, {
946
982
  disabled: view.fields.length <= 1,
947
983
  onClick: () => onDelete(field2.id)
948
- }))))))), field && /* @__PURE__ */ React7.createElement(FieldEditor, {
984
+ }))))))), field && /* @__PURE__ */ React8.createElement(FieldEditor, {
949
985
  key: field.id,
950
986
  view,
951
987
  projection,
952
988
  field,
953
989
  registry,
954
990
  onSave: handleClose
955
- }), !readonly && !field && /* @__PURE__ */ React7.createElement("div", {
991
+ }), !readonly && !field && /* @__PURE__ */ React8.createElement("div", {
956
992
  className: "flex p-2 justify-center"
957
- }, /* @__PURE__ */ React7.createElement(IconButton2, {
993
+ }, /* @__PURE__ */ React8.createElement(IconButton2, {
958
994
  icon: "ph--plus--regular",
959
995
  label: t("button add property"),
960
996
  onClick: handleAdd,
@@ -1188,11 +1224,12 @@ export {
1188
1224
  FieldEditor,
1189
1225
  Form,
1190
1226
  FormActions,
1191
- GeiPointInput,
1227
+ GeoPointInput,
1192
1228
  InputHeader,
1193
1229
  NumberInput,
1194
1230
  SelectInput,
1195
1231
  TextInput,
1232
+ TupleInput,
1196
1233
  ViewEditor,
1197
1234
  cellClassesForFieldType,
1198
1235
  cellClassesForRowSelection,