@dxos/react-ui-form 0.7.5-labs.a279d8c → 0.7.5-main.2567c87

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 (48) hide show
  1. package/dist/lib/browser/index.mjs +408 -425
  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 +467 -469
  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 +408 -425
  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/Form/Defaults.d.ts +6 -5
  11. package/dist/types/src/components/Form/Defaults.d.ts.map +1 -1
  12. package/dist/types/src/components/Form/Form.d.ts +20 -10
  13. package/dist/types/src/components/Form/Form.d.ts.map +1 -1
  14. package/dist/types/src/components/Form/Form.stories.d.ts +1 -2
  15. package/dist/types/src/components/Form/Form.stories.d.ts.map +1 -1
  16. package/dist/types/src/components/Form/Input.d.ts +6 -5
  17. package/dist/types/src/components/Form/Input.d.ts.map +1 -1
  18. package/dist/types/src/components/Form/custom/GeoPointInput.d.ts +2 -1
  19. package/dist/types/src/components/Form/custom/GeoPointInput.d.ts.map +1 -1
  20. package/dist/types/src/components/Form/custom/TupleInput.d.ts +2 -1
  21. package/dist/types/src/components/Form/custom/TupleInput.d.ts.map +1 -1
  22. package/dist/types/src/components/Form/factory.d.ts +2 -2
  23. package/dist/types/src/components/Form/factory.d.ts.map +1 -1
  24. package/dist/types/src/hooks/useForm.d.ts +11 -10
  25. package/dist/types/src/hooks/useForm.d.ts.map +1 -1
  26. package/dist/types/tsconfig.tsbuildinfo +1 -1
  27. package/package.json +26 -26
  28. package/src/components/FieldEditor/FieldEditor.tsx +4 -4
  29. package/src/components/Form/Defaults.tsx +33 -20
  30. package/src/components/Form/Form.stories.tsx +5 -15
  31. package/src/components/Form/Form.tsx +359 -37
  32. package/src/components/Form/Input.tsx +6 -5
  33. package/src/components/Form/custom/GeoPointInput.tsx +15 -6
  34. package/src/components/Form/custom/TupleInput.tsx +9 -5
  35. package/src/components/Form/factory.tsx +5 -2
  36. package/src/hooks/useForm.ts +48 -57
  37. package/dist/types/src/components/Form/ArrayField.d.ts +0 -16
  38. package/dist/types/src/components/Form/ArrayField.d.ts.map +0 -1
  39. package/dist/types/src/components/Form/FormActions.d.ts +0 -7
  40. package/dist/types/src/components/Form/FormActions.d.ts.map +0 -1
  41. package/dist/types/src/components/Form/FormContent.d.ts +0 -26
  42. package/dist/types/src/components/Form/FormContent.d.ts.map +0 -1
  43. package/dist/types/src/components/Form/FormContext.d.ts +0 -20
  44. package/dist/types/src/components/Form/FormContext.d.ts.map +0 -1
  45. package/src/components/Form/ArrayField.tsx +0 -111
  46. package/src/components/Form/FormActions.tsx +0 -41
  47. package/src/components/Form/FormContent.tsx +0 -155
  48. package/src/components/Form/FormContext.tsx +0 -48
@@ -80,11 +80,11 @@ var DeprecatedFormInput = ({ label, description, secondary, children }) => {
80
80
  };
81
81
 
82
82
  // packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx
83
- import React11, { useCallback as useCallback3, useEffect as useEffect2, useMemo as useMemo5, useState as useState2 } from "react";
83
+ import React7, { useCallback as useCallback2, useEffect as useEffect3, useMemo as useMemo3, useState as useState2 } from "react";
84
84
  import { FormatEnum as FormatEnum2, FormatEnums, formatToType } from "@dxos/echo-schema";
85
- import { log as log2 } from "@dxos/log";
86
- import { useTranslation as useTranslation4 } from "@dxos/react-ui";
87
- import { getFormatSchema, getSchemaProperties as getSchemaProperties3, sortProperties } from "@dxos/schema";
85
+ import { log as log3 } from "@dxos/log";
86
+ import { useTranslation as useTranslation3 } from "@dxos/react-ui";
87
+ import { getFormatSchema, getSchemaProperties as getSchemaProperties2, sortProperties } from "@dxos/schema";
88
88
 
89
89
  // packages/ui/react-ui-form/src/components/Form/custom/GeoPointInput.tsx
90
90
  import React3 from "react";
@@ -111,10 +111,10 @@ var InputHeader = ({ children, error }) => {
111
111
  };
112
112
 
113
113
  // packages/ui/react-ui-form/src/components/Form/custom/GeoPointInput.tsx
114
- var GeoPointInput = ({ type, label, disabled, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
114
+ var GeoPointInput = ({ property, type, label, disabled, getStatus, getValue: getValue2, onValueChange, onBlur }) => {
115
115
  const { t } = useTranslation(translationKey);
116
- const { status, error } = getStatus();
117
- const [lng = 0, lat = 0] = getValue3() ?? [];
116
+ const { status, error } = getStatus?.(property);
117
+ const [lng = 0, lat = 0] = getValue2(property) ?? [];
118
118
  return /* @__PURE__ */ React3.createElement(Input2.Root, {
119
119
  validationValence: status
120
120
  }, /* @__PURE__ */ React3.createElement(InputHeader, {
@@ -126,7 +126,7 @@ var GeoPointInput = ({ type, label, disabled, getStatus, getValue: getValue3, on
126
126
  disabled,
127
127
  placeholder: t("placeholder longitude"),
128
128
  value: lng,
129
- onChange: (event) => onValueChange(type, [
129
+ onChange: (event) => onValueChange(property, type, [
130
130
  lat,
131
131
  safeParseFloat(event.target.value, 0)
132
132
  ]),
@@ -136,7 +136,7 @@ var GeoPointInput = ({ type, label, disabled, getStatus, getValue: getValue3, on
136
136
  disabled,
137
137
  placeholder: t("placeholder latitude"),
138
138
  value: lat,
139
- onChange: (event) => onValueChange(type, [
139
+ onChange: (event) => onValueChange(property, type, [
140
140
  safeParseFloat(event.target.value, 0),
141
141
  lng
142
142
  ]),
@@ -155,9 +155,9 @@ var gridCols = [
155
155
  "grid-cols-3",
156
156
  "grid-cols-4"
157
157
  ];
158
- var TupleInput = ({ binding, type, label, disabled, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
159
- const { status, error } = getStatus();
160
- const values = getValue3() ?? {};
158
+ var TupleInput = ({ binding, property, type, label, disabled, getStatus, getValue: getValue2, onValueChange, onBlur }) => {
159
+ const { status, error } = getStatus?.(property);
160
+ const values = getValue2(property) ?? {};
161
161
  return /* @__PURE__ */ React4.createElement(Input3.Root, {
162
162
  validationValence: status
163
163
  }, /* @__PURE__ */ React4.createElement(InputHeader, {
@@ -169,7 +169,7 @@ var TupleInput = ({ binding, type, label, disabled, getStatus, getValue: getValu
169
169
  type: "number",
170
170
  disabled,
171
171
  value: values[prop],
172
- onChange: (event) => onValueChange(type, {
172
+ onChange: (event) => onValueChange(property, type, {
173
173
  ...values,
174
174
  [prop]: safeParseFloat2(event.target.value, 0)
175
175
  }),
@@ -180,8 +180,8 @@ var TupleInput = ({ binding, type, label, disabled, getStatus, getValue: getValu
180
180
  // packages/ui/react-ui-form/src/components/Form/Defaults.tsx
181
181
  import React5 from "react";
182
182
  import { Input as Input4, Select } from "@dxos/react-ui";
183
- var TextInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
184
- const { status, error } = getStatus();
183
+ var TextInput = ({ property, type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue2, onValueChange, onBlur }) => {
184
+ const { status, error } = getStatus?.(property);
185
185
  return /* @__PURE__ */ React5.createElement(Input4.Root, {
186
186
  validationValence: status
187
187
  }, !inputOnly && /* @__PURE__ */ React5.createElement(InputHeader, {
@@ -189,13 +189,13 @@ var TextInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, get
189
189
  }, /* @__PURE__ */ React5.createElement(Input4.Label, null, label)), /* @__PURE__ */ React5.createElement(Input4.TextInput, {
190
190
  disabled,
191
191
  placeholder,
192
- value: getValue3() ?? "",
193
- onChange: (event) => onValueChange(type, event.target.value),
192
+ value: getValue2(property) ?? "",
193
+ onChange: (event) => onValueChange(property, type, event.target.value),
194
194
  onBlur
195
195
  }), inputOnly && /* @__PURE__ */ React5.createElement(Input4.Validation, null, error));
196
196
  };
197
- var NumberInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
198
- const { status, error } = getStatus();
197
+ var NumberInput = ({ property, type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue2, onValueChange, onBlur }) => {
198
+ const { status, error } = getStatus?.(property);
199
199
  return /* @__PURE__ */ React5.createElement(Input4.Root, {
200
200
  validationValence: status
201
201
  }, !inputOnly && /* @__PURE__ */ React5.createElement(InputHeader, {
@@ -204,31 +204,31 @@ var NumberInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, g
204
204
  type: "number",
205
205
  disabled,
206
206
  placeholder,
207
- value: getValue3() ?? 0,
208
- onChange: (event) => onValueChange(type, event.target.value),
207
+ value: getValue2(property) ?? 0,
208
+ onChange: (event) => onValueChange(property, type, event.target.value),
209
209
  onBlur
210
210
  }), inputOnly && /* @__PURE__ */ React5.createElement(Input4.DescriptionAndValidation, null, error));
211
211
  };
212
- var BooleanInput = ({ type, label, inputOnly, getStatus, getValue: getValue3, onValueChange }) => {
213
- const { status, error } = getStatus();
212
+ var BooleanInput = ({ property, type, label, inputOnly, getStatus, getValue: getValue2, onValueChange }) => {
213
+ const { status, error } = getStatus?.(property);
214
214
  return /* @__PURE__ */ React5.createElement(Input4.Root, {
215
215
  validationValence: status
216
216
  }, !inputOnly && /* @__PURE__ */ React5.createElement(InputHeader, {
217
217
  error
218
218
  }, /* @__PURE__ */ React5.createElement(Input4.Label, null, label)), /* @__PURE__ */ React5.createElement(Input4.Switch, {
219
- checked: getValue3(),
220
- onCheckedChange: (value) => onValueChange(type, value)
219
+ checked: getValue2(property),
220
+ onCheckedChange: (value) => onValueChange(property, type, value)
221
221
  }), inputOnly && /* @__PURE__ */ React5.createElement(Input4.DescriptionAndValidation, null, error));
222
222
  };
223
- var SelectInput = ({ type, label, inputOnly, disabled, placeholder, options, getStatus, getValue: getValue3, onValueChange }) => {
224
- const { status, error } = getStatus();
223
+ var SelectInput = ({ property, type, label, inputOnly, disabled, placeholder, options, getStatus, getValue: getValue2, onValueChange }) => {
224
+ const { status, error } = getStatus?.(property);
225
225
  return /* @__PURE__ */ React5.createElement(Input4.Root, {
226
226
  validationValence: status
227
227
  }, !inputOnly && /* @__PURE__ */ React5.createElement(InputHeader, {
228
228
  error
229
229
  }, /* @__PURE__ */ React5.createElement(Input4.Label, null, label)), /* @__PURE__ */ React5.createElement(Select.Root, {
230
- value: getValue3(),
231
- onValueChange: (value) => onValueChange(type, value)
230
+ value: getValue2(property),
231
+ onValueChange: (value) => onValueChange(property, type, value)
232
232
  }, /* @__PURE__ */ React5.createElement(Select.TriggerButton, {
233
233
  classNames: "is-full",
234
234
  disabled,
@@ -243,38 +243,42 @@ var SelectInput = ({ type, label, inputOnly, disabled, placeholder, options, get
243
243
  };
244
244
 
245
245
  // packages/ui/react-ui-form/src/components/Form/Form.tsx
246
- import React10, { useMemo as useMemo4 } from "react";
247
- import { mx as mx5 } from "@dxos/react-ui-theme";
248
-
249
- // packages/ui/react-ui-form/src/components/Form/FormActions.tsx
250
- import React7 from "react";
246
+ import { pipe } from "effect";
247
+ import { capitalize } from "effect/String";
248
+ import React6, { useEffect as useEffect2, useMemo as useMemo2 } from "react";
249
+ import { AST, S } from "@dxos/echo-schema";
250
+ import { findNode, getDiscriminatedType, isDiscriminatedUnion, SimpleType } from "@dxos/effect";
251
+ import { log as log2 } from "@dxos/log";
251
252
  import { IconButton, useTranslation as useTranslation2 } from "@dxos/react-ui";
252
253
  import { mx as mx2 } from "@dxos/react-ui-theme";
254
+ import { getSchemaProperties } from "@dxos/schema";
255
+ import { isNotFalsy } from "@dxos/util";
253
256
 
254
- // packages/ui/react-ui-form/src/components/Form/FormContext.tsx
255
- import React6, { createContext, useContext } from "react";
256
- import { raise } from "@dxos/debug";
257
- import { getValue as getValue2 } from "@dxos/echo-schema";
258
- import { createJsonPath as createJsonPath2 } from "@dxos/effect";
257
+ // packages/ui/react-ui-form/src/components/Form/factory.tsx
258
+ import { FormatEnum } from "@dxos/echo-schema";
259
+ var getInputComponent = (type, format) => {
260
+ switch (format) {
261
+ case FormatEnum.LatLng:
262
+ return GeoPointInput;
263
+ }
264
+ switch (type) {
265
+ case "string":
266
+ return TextInput;
267
+ case "number":
268
+ return NumberInput;
269
+ case "boolean":
270
+ return BooleanInput;
271
+ }
272
+ };
259
273
 
260
274
  // packages/ui/react-ui-form/src/hooks/useForm.ts
261
275
  import { useCallback, useEffect, useMemo, useState } from "react";
262
276
  import { getValue, setValue } from "@dxos/echo-schema";
263
- import { AST, createJsonPath, fromEffectValidationPath } from "@dxos/effect";
264
277
  import { invariant } from "@dxos/invariant";
265
278
  import { log } from "@dxos/log";
266
279
  import { validateSchema } from "@dxos/schema";
267
280
  var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/hooks/useForm.ts";
268
281
  var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, onSave }) => {
269
- invariant(AST.isTypeLiteral(schema.ast), void 0, {
270
- F: __dxlog_file,
271
- L: 91,
272
- S: void 0,
273
- A: [
274
- "AST.isTypeLiteral(schema.ast)",
275
- ""
276
- ]
277
- });
278
282
  const [values, setValues] = useState(initialValues);
279
283
  useEffect(() => {
280
284
  setValues(initialValues);
@@ -311,8 +315,8 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
311
315
  values,
312
316
  schemaDirty
313
317
  ]);
314
- const canSave = useMemo(() => !saving && // Check if any error paths that are touched have errors
315
- !Object.entries(touched).some(([path, isTouched]) => isTouched && Object.keys(errors).some((errorPath) => errorPath === path || errorPath.startsWith(`${path}.`) || errorPath.startsWith(`${path}[`))), [
318
+ const canSave = useMemo(() => !saving && Object.keys(values).every((property) => touched[property] === false || !errors[property]), [
319
+ values,
316
320
  touched,
317
321
  errors,
318
322
  saving
@@ -334,21 +338,17 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
334
338
  onSave,
335
339
  changed
336
340
  ]);
337
- const getStatus = useCallback((path) => {
338
- const jsonPath = Array.isArray(path) ? createJsonPath(path) : path;
339
- const matchingError = Object.entries(errors).find(([errorPath]) => errorPath === jsonPath || errorPath.startsWith(`${jsonPath}.`) || errorPath.startsWith(`${jsonPath}[`));
340
- return {
341
- status: matchingError ? "error" : void 0,
342
- error: matchingError ? matchingError[1] : void 0
343
- };
344
- }, [
341
+ const getStatus = useCallback((property) => ({
342
+ status: errors[property] ? "error" : void 0,
343
+ error: errors[property] ? errors[property] : void 0
344
+ }), [
345
+ touched,
345
346
  errors
346
347
  ]);
347
- const getFormValue = (path) => {
348
- return getValue(values, createJsonPath(path));
348
+ const getFormValue = (property) => {
349
+ return getValue(values, property);
349
350
  };
350
- const onValueChange = (path, type, value) => {
351
- const jsonPath = createJsonPath(path);
351
+ const onValueChange = (property, type, value) => {
352
352
  let parsedValue = value;
353
353
  try {
354
354
  if (type === "number") {
@@ -357,19 +357,19 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
357
357
  } catch (err) {
358
358
  log.catch(err, void 0, {
359
359
  F: __dxlog_file,
360
- L: 194,
360
+ L: 178,
361
361
  S: void 0,
362
362
  C: (f, a) => f(...a)
363
363
  });
364
364
  parsedValue = void 0;
365
365
  }
366
366
  const newValues = {
367
- ...setValue(values, jsonPath, parsedValue)
367
+ ...setValue(values, property, parsedValue)
368
368
  };
369
369
  setValues(newValues);
370
370
  setChanged((prev) => ({
371
371
  ...prev,
372
- [jsonPath]: true
372
+ [property]: true
373
373
  }));
374
374
  onValuesChanged?.(newValues);
375
375
  const isValid = validate(newValues);
@@ -379,12 +379,15 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
379
379
  });
380
380
  }
381
381
  };
382
- const onTouched = useCallback((path) => {
383
- const jsonPath = createJsonPath(path);
382
+ const onBlur = useCallback((event) => {
383
+ const { name } = event.target;
384
384
  setTouched((touched2) => ({
385
385
  ...touched2,
386
- [jsonPath]: true
386
+ [name]: true
387
387
  }));
388
+ if (event.relatedTarget?.getAttribute("type") === "submit") {
389
+ setTouched(createKeySet(values, true));
390
+ }
388
391
  validate(values);
389
392
  }, [
390
393
  validate,
@@ -402,13 +405,13 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
402
405
  getStatus,
403
406
  getValue: getFormValue,
404
407
  onValueChange,
405
- onTouched
408
+ onBlur
406
409
  };
407
410
  };
408
411
  var createKeySet = (obj, value) => {
409
412
  invariant(obj, void 0, {
410
413
  F: __dxlog_file,
411
- L: 236,
414
+ L: 229,
412
415
  S: void 0,
413
416
  A: [
414
417
  "obj",
@@ -422,359 +425,338 @@ var createKeySet = (obj, value) => {
422
425
  };
423
426
  var flatMap = (errors) => {
424
427
  return errors.reduce((result, { path, message }) => {
425
- const jsonPath = fromEffectValidationPath(path);
426
- if (!(jsonPath in result)) {
427
- result[jsonPath] = message;
428
+ if (!(path in result)) {
429
+ result[path] = message;
428
430
  }
429
431
  return result;
430
432
  }, {});
431
433
  };
432
434
 
433
- // packages/ui/react-ui-form/src/components/Form/FormContext.tsx
434
- var FormContext = /* @__PURE__ */ createContext(void 0);
435
- var useFormContext = () => {
436
- return useContext(FormContext) ?? raise(new Error("Missing FormContext"));
437
- };
438
- var useFormValues = (path = []) => {
439
- const { values: formValues } = useFormContext();
440
- const jsonPath = createJsonPath2(path);
441
- return getValue2(formValues, jsonPath);
442
- };
443
- var useInputProps = (path = []) => {
444
- const { getStatus, getValue: getFormValue, onValueChange, onTouched } = useFormContext();
445
- return {
446
- getStatus: () => getStatus(path),
447
- getValue: () => getFormValue(path),
448
- onValueChange: (type, value) => onValueChange(path, type, value),
449
- onBlur: () => onTouched(path)
450
- };
451
- };
452
- var FormProvider = ({ children, ...formOptions }) => {
453
- const formHandler = useForm(formOptions);
454
- return /* @__PURE__ */ React6.createElement(FormContext.Provider, {
455
- value: formHandler
456
- }, children);
457
- };
458
-
459
- // packages/ui/react-ui-form/src/components/Form/FormActions.tsx
460
- var FormActions = ({ onCancel, readonly }) => {
461
- const { t } = useTranslation2(translationKey);
462
- const { canSave, handleSave } = useFormContext();
463
- return /* @__PURE__ */ React7.createElement("div", {
464
- role: "none",
465
- className: "flex justify-center"
466
- }, /* @__PURE__ */ React7.createElement("div", {
467
- role: "none",
468
- className: mx2(onCancel && !readonly && "grid grid-cols-2 gap-2")
469
- }, onCancel && !readonly && /* @__PURE__ */ React7.createElement(IconButton, {
470
- "data-testid": "cancel-button",
471
- icon: "ph--x--regular",
472
- label: t("button cancel"),
473
- onClick: onCancel
474
- }), handleSave && /* @__PURE__ */ React7.createElement(IconButton, {
475
- type: "submit",
476
- "data-testid": "save-button",
477
- disabled: !canSave,
478
- icon: "ph--check--regular",
479
- label: t("button save"),
480
- onClick: handleSave
481
- })));
482
- };
483
-
484
- // packages/ui/react-ui-form/src/components/Form/FormContent.tsx
485
- import { pipe as pipe2 } from "effect";
486
- import { capitalize as capitalize2 } from "effect/String";
487
- import React9, { useMemo as useMemo3 } from "react";
488
- import { AST as AST3, S } from "@dxos/echo-schema";
489
- import { createJsonPath as createJsonPath3, findNode as findNode2, getDiscriminatedType as getDiscriminatedType2, isDiscriminatedUnion as isDiscriminatedUnion2 } from "@dxos/effect";
490
- import { mx as mx4 } from "@dxos/react-ui-theme";
491
- import { getSchemaProperties as getSchemaProperties2 } from "@dxos/schema";
492
- import { isNotFalsy } from "@dxos/util";
493
-
494
- // packages/ui/react-ui-form/src/components/Form/ArrayField.tsx
495
- import { pipe } from "effect";
496
- import { capitalize } from "effect/String";
497
- import React8, { useCallback as useCallback2, useMemo as useMemo2 } from "react";
498
- import { AST as AST2 } from "@dxos/echo-schema";
499
- import { findNode, getDiscriminatedType, isDiscriminatedUnion, SimpleType } from "@dxos/effect";
500
- import { invariant as invariant2 } from "@dxos/invariant";
501
- import { IconButton as IconButton2, useTranslation as useTranslation3 } from "@dxos/react-ui";
502
- import { mx as mx3 } from "@dxos/react-ui-theme";
503
- import { getSchemaProperties } from "@dxos/schema";
504
- var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/Form/ArrayField.tsx";
435
+ // packages/ui/react-ui-form/src/components/Form/Form.tsx
436
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/Form/Form.tsx";
505
437
  var padding = "px-2";
506
- var ArrayField = ({ property, readonly, path, inputProps, Custom, lookupComponent }) => {
507
- const { t } = useTranslation3(translationKey);
508
- const { ast, name, type, title } = property;
509
- const values = useFormValues(path ?? []);
510
- invariant2(Array.isArray(values), void 0, {
511
- F: __dxlog_file2,
512
- L: 37,
513
- S: void 0,
514
- A: [
515
- "Array.isArray(values)",
516
- ""
517
- ]
518
- });
519
- const label = title ?? pipe(name, capitalize);
520
- const tupleType = findNode(ast, AST2.isTupleType);
521
- const elementType = tupleType?.rest[0]?.type;
522
- const getDefaultObjectValue = (typeNode) => {
523
- const baseNode = findNode(typeNode, isDiscriminatedUnion);
524
- const typeLiteral = baseNode ? getDiscriminatedType(baseNode, {}) : findNode(typeNode, AST2.isTypeLiteral);
525
- if (!typeLiteral) {
526
- return {};
527
- }
528
- return Object.fromEntries(getSchemaProperties(typeLiteral, {}).map((prop) => [
529
- prop.name,
530
- prop.defaultValue
531
- ]));
532
- };
533
- const newValue = useMemo2(() => {
534
- if (type === "object" && elementType) {
535
- return getDefaultObjectValue(elementType);
536
- } else {
537
- return SimpleType.getDefaultValue(type);
538
- }
539
- }, [
540
- type,
541
- elementType
438
+ var Form = ({ classNames, schema, values: initialValues, path = [], readonly, filter, sort, autoSave, testId, onValuesChanged, onValidate, onSave, onCancel, lookupComponent, Custom }) => {
439
+ const onValid = useMemo2(() => autoSave ? onSave : void 0, [
440
+ autoSave,
441
+ onSave
542
442
  ]);
543
- const handleAdd = useCallback2(() => {
544
- inputProps.onValueChange(type, [
545
- ...values,
546
- newValue
547
- ]);
443
+ const { canSave, values, errors, handleSave, ...inputProps } = useForm({
444
+ schema,
445
+ initialValues,
446
+ onValuesChanged,
447
+ onValidate,
448
+ onValid,
449
+ onSave
450
+ });
451
+ const properties = useMemo2(() => {
452
+ const props = getSchemaProperties(schema.ast, values);
453
+ const filtered = filter ? filter(props) : props;
454
+ const findIndex = (props2, prop) => {
455
+ const idx = props2.findIndex((p) => p === prop);
456
+ return idx === -1 ? Infinity : idx;
457
+ };
458
+ return sort ? filtered.sort(({ name: a }, { name: b }) => findIndex(sort, a) - findIndex(sort, b)) : filtered;
548
459
  }, [
549
- type,
550
- elementType,
551
- inputProps,
552
- newValue,
460
+ schema,
461
+ filter,
553
462
  values
554
463
  ]);
555
- const handleRemove = useCallback2((index) => {
556
- const newValues = values.filter((_, i) => i !== index);
557
- inputProps.onValueChange(type, newValues);
464
+ useEffect2(() => {
465
+ if (errors && Object.keys(errors).length) {
466
+ log2.warn("validation", {
467
+ errors
468
+ }, {
469
+ F: __dxlog_file2,
470
+ L: 106,
471
+ S: void 0,
472
+ C: (f, a) => f(...a)
473
+ });
474
+ }
558
475
  }, [
559
- type,
560
- inputProps,
561
- values
476
+ errors
562
477
  ]);
563
- if (!elementType) {
478
+ return /* @__PURE__ */ React6.createElement("div", {
479
+ role: "form",
480
+ className: mx2("flex flex-col w-full gap-2 py-2", classNames),
481
+ "data-testid": testId
482
+ }, properties.map((property) => {
483
+ const { ast, name, type, format, title, description, examples, options, array } = property;
484
+ const key = [
485
+ ...path,
486
+ name
487
+ ];
488
+ const label = title ?? pipe(name, capitalize);
489
+ const placeholder = examples?.length ? `Example: "${examples[0]}"` : description;
490
+ const FoundComponent = lookupComponent?.({
491
+ prop: name,
492
+ schema: S.make(ast),
493
+ inputProps: {
494
+ property: name,
495
+ type,
496
+ format,
497
+ label,
498
+ disabled: readonly,
499
+ placeholder,
500
+ ...inputProps
501
+ }
502
+ });
503
+ if (FoundComponent) {
504
+ return /* @__PURE__ */ React6.createElement("div", {
505
+ key: name,
506
+ role: "none",
507
+ className: padding
508
+ }, FoundComponent);
509
+ }
510
+ let InputComponent = Custom?.[key.join(".")];
511
+ if (!InputComponent) {
512
+ if (options) {
513
+ return /* @__PURE__ */ React6.createElement("div", {
514
+ key: name,
515
+ role: "none",
516
+ className: padding
517
+ }, /* @__PURE__ */ React6.createElement(SelectInput, {
518
+ type,
519
+ format,
520
+ property: name,
521
+ disabled: readonly,
522
+ label,
523
+ options: options.map((option) => ({
524
+ value: option,
525
+ label: String(option)
526
+ })),
527
+ placeholder,
528
+ ...inputProps
529
+ }));
530
+ }
531
+ InputComponent = getInputComponent(type, format);
532
+ if (array) {
533
+ return /* @__PURE__ */ React6.createElement(ArrayField, {
534
+ key: name,
535
+ name,
536
+ type,
537
+ array: true,
538
+ label,
539
+ ast,
540
+ values,
541
+ format,
542
+ readonly,
543
+ placeholder,
544
+ inputProps,
545
+ Custom
546
+ });
547
+ }
548
+ }
549
+ if (!InputComponent) {
550
+ if (type === "object") {
551
+ const baseNode = findNode(ast, isDiscriminatedUnion);
552
+ const typeLiteral = baseNode ? getDiscriminatedType(baseNode, values[name]) : findNode(ast, AST.isTypeLiteral);
553
+ if (typeLiteral) {
554
+ const schema2 = S.make(typeLiteral);
555
+ return /* @__PURE__ */ React6.createElement("div", {
556
+ key: name,
557
+ role: "none"
558
+ }, /* @__PURE__ */ React6.createElement("div", {
559
+ className: padding
560
+ }, label), /* @__PURE__ */ React6.createElement(Form, {
561
+ schema: schema2,
562
+ path: key,
563
+ values: values[name] ?? {},
564
+ onValuesChanged: (childValues) => {
565
+ inputProps.onValueChange(name, "object", childValues);
566
+ },
567
+ Custom
568
+ }));
569
+ }
570
+ }
571
+ log2("no renderer for property", {
572
+ name,
573
+ type
574
+ }, {
575
+ F: __dxlog_file2,
576
+ L: 213,
577
+ S: void 0,
578
+ C: (f, a) => f(...a)
579
+ });
580
+ return null;
581
+ }
582
+ return /* @__PURE__ */ React6.createElement("div", {
583
+ key: name,
584
+ role: "none",
585
+ className: padding
586
+ }, /* @__PURE__ */ React6.createElement(InputComponent, {
587
+ type,
588
+ format,
589
+ property: name,
590
+ disabled: readonly,
591
+ label,
592
+ placeholder,
593
+ ...inputProps
594
+ }));
595
+ }).filter(isNotFalsy), (onCancel || onSave) && !autoSave && /* @__PURE__ */ React6.createElement(FormActions, {
596
+ onCancel,
597
+ onSubmit: handleSave,
598
+ canSubmit: canSave,
599
+ readonly
600
+ }));
601
+ };
602
+ var ArrayField = ({ name, type, label, ast, values, format, readonly, placeholder, inputProps, Custom }) => {
603
+ const { t } = useTranslation2(translationKey);
604
+ const arrayValues = values[name] ?? [];
605
+ const key = [
606
+ name
607
+ ];
608
+ const tupleType = findNode(ast, AST.isTupleType);
609
+ const elementType = tupleType?.rest[0]?.type;
610
+ if (type === "object" && elementType) {
611
+ const baseNode = findNode(elementType, isDiscriminatedUnion);
612
+ const typeLiteral = baseNode ? getDiscriminatedType(baseNode, values[name]) : findNode(elementType, AST.isTypeLiteral);
613
+ if (typeLiteral) {
614
+ const schema = S.make(typeLiteral);
615
+ return /* @__PURE__ */ React6.createElement("div", {
616
+ key: name,
617
+ role: "none",
618
+ className: mx2(padding)
619
+ }, /* @__PURE__ */ React6.createElement(InputHeader, null, label), /* @__PURE__ */ React6.createElement("div", {
620
+ role: "none",
621
+ className: "flex flex-col gap-1"
622
+ }, arrayValues.map((value, index) => {
623
+ return /* @__PURE__ */ React6.createElement("div", {
624
+ key: index,
625
+ role: "none",
626
+ className: "flex items-center gap-1"
627
+ }, /* @__PURE__ */ React6.createElement("div", {
628
+ role: "none",
629
+ className: "flex-1"
630
+ }, /* @__PURE__ */ React6.createElement(Form, {
631
+ schema,
632
+ path: [
633
+ ...key,
634
+ `[${index}]`
635
+ ],
636
+ values: value,
637
+ onValuesChanged: (childValues) => {
638
+ const newValues = [
639
+ ...arrayValues
640
+ ];
641
+ newValues[index] = childValues;
642
+ inputProps.onValueChange(name, "object", newValues);
643
+ },
644
+ Custom
645
+ })), /* @__PURE__ */ React6.createElement(IconButton, {
646
+ icon: "ph--trash--regular",
647
+ iconOnly: true,
648
+ label: t("button remove"),
649
+ onClick: () => {
650
+ const newValues = arrayValues.filter((_, i) => i !== index);
651
+ inputProps.onValueChange(name, type, newValues);
652
+ }
653
+ }));
654
+ })), /* @__PURE__ */ React6.createElement("div", {
655
+ role: "none",
656
+ className: "flex justify-between items-center plb-1"
657
+ }, /* @__PURE__ */ React6.createElement(IconButton, {
658
+ icon: "ph--plus--regular",
659
+ iconOnly: true,
660
+ label: t("button add"),
661
+ onClick: () => {
662
+ const newValues = [
663
+ ...arrayValues,
664
+ {}
665
+ ];
666
+ inputProps.onValueChange(name, type, newValues);
667
+ }
668
+ })));
669
+ }
670
+ return /* @__PURE__ */ React6.createElement("div", {
671
+ key: name,
672
+ role: "none"
673
+ }, "Nested form not supported in arrays, yet.");
674
+ }
675
+ const InputComponent = getInputComponent(type, format);
676
+ if (!InputComponent) {
564
677
  return null;
565
678
  }
566
- return /* @__PURE__ */ React8.createElement("div", {
679
+ return /* @__PURE__ */ React6.createElement("div", {
567
680
  role: "none",
568
- className: mx3(padding)
569
- }, /* @__PURE__ */ React8.createElement(InputHeader, null, label), /* @__PURE__ */ React8.createElement("div", {
681
+ key: "meta-input",
682
+ className: mx2(padding)
683
+ }, /* @__PURE__ */ React6.createElement(InputHeader, null, label), /* @__PURE__ */ React6.createElement("div", {
570
684
  role: "none",
571
685
  className: "flex flex-col gap-1"
572
- }, values.map((_value, index) => /* @__PURE__ */ React8.createElement("div", {
686
+ }, arrayValues.map((_, index) => /* @__PURE__ */ React6.createElement("div", {
573
687
  key: index,
574
688
  role: "none",
575
- className: "flex items-center gap-1"
576
- }, /* @__PURE__ */ React8.createElement("div", {
689
+ className: "flex items-start gap-1"
690
+ }, /* @__PURE__ */ React6.createElement("div", {
577
691
  role: "none",
578
692
  className: "flex-1"
579
- }, /* @__PURE__ */ React8.createElement(FormField, {
580
- property: {
581
- ...property,
582
- array: false,
583
- ast: elementType
584
- },
585
- path: [
586
- ...path ?? [],
587
- index
588
- ],
589
- readonly,
590
- inline: true,
591
- Custom,
592
- lookupComponent
593
- })), /* @__PURE__ */ React8.createElement(IconButton2, {
693
+ }, /* @__PURE__ */ React6.createElement(InputComponent, {
694
+ type,
695
+ format,
696
+ label,
697
+ inputOnly: true,
698
+ property: `${name}[${index}]`,
699
+ disabled: readonly,
700
+ placeholder,
701
+ ...inputProps
702
+ })), /* @__PURE__ */ React6.createElement(IconButton, {
594
703
  icon: "ph--trash--regular",
595
704
  iconOnly: true,
596
705
  label: t("button remove"),
597
- onClick: () => handleRemove(index)
598
- })))), /* @__PURE__ */ React8.createElement("div", {
706
+ onClick: () => {
707
+ const newValues = arrayValues.filter((_2, i) => i !== index);
708
+ inputProps.onValueChange(name, type, newValues);
709
+ }
710
+ })))), /* @__PURE__ */ React6.createElement("div", {
599
711
  role: "none",
600
712
  className: "flex justify-between items-center plb-1"
601
- }, /* @__PURE__ */ React8.createElement(IconButton2, {
713
+ }, /* @__PURE__ */ React6.createElement(IconButton, {
602
714
  icon: "ph--plus--regular",
603
715
  iconOnly: true,
604
716
  label: t("button add"),
605
- onClick: handleAdd
606
- })));
607
- };
608
-
609
- // packages/ui/react-ui-form/src/components/Form/factory.tsx
610
- import { FormatEnum } from "@dxos/echo-schema";
611
- var getInputComponent = (type, format) => {
612
- switch (format) {
613
- case FormatEnum.LatLng:
614
- return GeoPointInput;
615
- }
616
- switch (type) {
617
- case "string":
618
- return TextInput;
619
- case "number":
620
- return NumberInput;
621
- case "boolean":
622
- return BooleanInput;
623
- }
624
- };
625
-
626
- // packages/ui/react-ui-form/src/components/Form/FormContent.tsx
627
- var FormField = ({ property, path, readonly, inline, lookupComponent, Custom }) => {
628
- const inputProps = useInputProps(path);
629
- const { ast, name, type, format, title, description, options, examples, array } = property;
630
- const label = useMemo3(() => title ?? pipe2(name, capitalize2), [
631
- title,
632
- name
633
- ]);
634
- const placeholder = useMemo3(() => examples?.length ? `Example: "${examples[0]}"` : description, [
635
- examples,
636
- description
637
- ]);
638
- if (array) {
639
- return /* @__PURE__ */ React9.createElement(ArrayField, {
640
- property,
641
- path,
642
- inputProps,
643
- readonly,
644
- Custom
645
- });
646
- }
647
- const FoundComponent = lookupComponent?.({
648
- prop: name,
649
- schema: S.make(ast),
650
- inputProps: {
651
- type,
652
- format,
653
- label,
654
- disabled: readonly,
655
- placeholder,
656
- ...inputProps
657
- }
658
- });
659
- if (FoundComponent) {
660
- return /* @__PURE__ */ React9.createElement("div", null, FoundComponent);
661
- }
662
- const jsonPath = createJsonPath3(path ?? []);
663
- const InputComponent = Custom?.[jsonPath] || getInputComponent(type, format);
664
- if (InputComponent) {
665
- return /* @__PURE__ */ React9.createElement("div", null, /* @__PURE__ */ React9.createElement(InputComponent, {
666
- type,
667
- format,
668
- label,
669
- inputOnly: inline,
670
- placeholder,
671
- disabled: readonly,
672
- ...inputProps
673
- }));
674
- }
675
- if (options) {
676
- return /* @__PURE__ */ React9.createElement("div", {
677
- role: "none"
678
- }, /* @__PURE__ */ React9.createElement(SelectInput, {
679
- type,
680
- format,
681
- disabled: readonly,
682
- inputOnly: inline,
683
- label,
684
- options: options.map((option) => ({
685
- value: option,
686
- label: String(option)
687
- })),
688
- placeholder,
689
- ...inputProps
690
- }));
691
- }
692
- if (type === "object") {
693
- const baseNode = findNode2(ast, isDiscriminatedUnion2);
694
- const typeLiteral = baseNode ? getDiscriminatedType2(baseNode, inputProps.getValue()) : findNode2(ast, AST3.isTypeLiteral);
695
- if (typeLiteral) {
696
- return /* @__PURE__ */ React9.createElement("div", null, !inline && /* @__PURE__ */ React9.createElement("div", null, label), /* @__PURE__ */ React9.createElement(FormFields, {
697
- schema: S.make(typeLiteral),
698
- path,
699
- readonly,
700
- Custom
701
- }));
717
+ onClick: () => {
718
+ const newValues = [
719
+ ...arrayValues,
720
+ SimpleType.getDefaultValue(type)
721
+ ];
722
+ inputProps.onValueChange(name, type, newValues);
702
723
  }
703
- }
704
- return null;
705
- };
706
- var FormFields = ({ schema, path, filter, sort, readonly, lookupComponent, Custom }) => {
707
- const values = useFormValues(path);
708
- const properties = useMemo3(() => {
709
- const props = getSchemaProperties2(schema.ast, values);
710
- const filtered = filter ? filter(props) : props;
711
- return sort ? filtered.sort((a, b) => sort.indexOf(a.name) - sort.indexOf(b.name)) : filtered;
712
- }, [
713
- schema,
714
- values,
715
- filter,
716
- sort
717
- ]);
718
- return /* @__PURE__ */ React9.createElement("div", {
719
- role: "form",
720
- className: mx4("flex flex-col w-full gap-2 py-2")
721
- }, properties.map((property) => {
722
- return /* @__PURE__ */ React9.createElement(FormField, {
723
- key: property.name,
724
- property,
725
- path: [
726
- ...path ?? [],
727
- property.name
728
- ],
729
- readonly,
730
- lookupComponent,
731
- Custom
732
- });
733
- }).filter(isNotFalsy));
724
+ })));
734
725
  };
735
-
736
- // packages/ui/react-ui-form/src/components/Form/Form.tsx
737
- var Form = ({ classNames, schema, values: initialValues, path = [], readonly, filter, sort, autoSave, testId, onValuesChanged, onValidate, onSave, onCancel, lookupComponent, Custom }) => {
738
- const onValid = useMemo4(() => autoSave ? onSave : void 0, [
739
- autoSave,
740
- onSave
741
- ]);
742
- return /* @__PURE__ */ React10.createElement(FormProvider, {
743
- schema,
744
- initialValues,
745
- onValuesChanged,
746
- onValidate,
747
- onValid,
748
- onSave
749
- }, /* @__PURE__ */ React10.createElement("div", {
726
+ var FormActions = ({ onCancel, onSubmit, canSubmit, readonly }) => {
727
+ const { t } = useTranslation2(translationKey);
728
+ return /* @__PURE__ */ React6.createElement("div", {
750
729
  role: "none",
751
- className: mx5("p-2", classNames),
752
- "data-testid": testId
753
- }, /* @__PURE__ */ React10.createElement(FormFields, {
754
- schema,
755
- path,
756
- readonly,
757
- filter,
758
- sort,
759
- lookupComponent,
760
- Custom
761
- }), (onCancel || onSave) && !autoSave && /* @__PURE__ */ React10.createElement(FormActions, {
762
- onCancel,
763
- readonly
730
+ className: "flex justify-center"
731
+ }, /* @__PURE__ */ React6.createElement("div", {
732
+ role: "none",
733
+ className: mx2(onCancel && !readonly && "grid grid-cols-2 gap-2")
734
+ }, onCancel && !readonly && /* @__PURE__ */ React6.createElement(IconButton, {
735
+ "data-testid": "cancel-button",
736
+ icon: "ph--x--regular",
737
+ label: t("button cancel"),
738
+ onClick: onCancel
739
+ }), onSubmit && /* @__PURE__ */ React6.createElement(IconButton, {
740
+ type: "submit",
741
+ "data-testid": "save-button",
742
+ disabled: !canSubmit,
743
+ icon: "ph--check--regular",
744
+ label: t("button save"),
745
+ onClick: onSubmit
764
746
  })));
765
747
  };
766
748
 
767
749
  // packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx
768
750
  var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx";
769
751
  var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
770
- const { t } = useTranslation4(translationKey);
752
+ const { t } = useTranslation3(translationKey);
771
753
  const [props, setProps] = useState2(projection.getFieldProjection(field.id).props);
772
- useEffect2(() => setProps(projection.getFieldProjection(field.id).props), [
754
+ useEffect3(() => setProps(projection.getFieldProjection(field.id).props), [
773
755
  field,
774
756
  projection
775
757
  ]);
776
758
  const [schemas, setSchemas] = useState2([]);
777
- useEffect2(() => {
759
+ useEffect3(() => {
778
760
  if (!registry) {
779
761
  return;
780
762
  }
@@ -793,7 +775,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
793
775
  registry
794
776
  ]);
795
777
  const [referenceSchema, setReferenceSchema] = useState2();
796
- useEffect2(() => {
778
+ useEffect3(() => {
797
779
  setReferenceSchema(schemas.find((schema) => schema.typename === props?.referenceSchema));
798
780
  }, [
799
781
  schemas,
@@ -802,7 +784,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
802
784
  const [{ fieldSchema }, setFieldSchema] = useState2({
803
785
  fieldSchema: getFormatSchema(props?.format)
804
786
  });
805
- const handleValuesChanged = useCallback3((_props) => {
787
+ const handleValuesChanged = useCallback2((_props) => {
806
788
  setFieldSchema((prev) => {
807
789
  const fieldSchema2 = getFormatSchema(_props.format);
808
790
  if (prev.fieldSchema === fieldSchema2) {
@@ -837,7 +819,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
837
819
  props.format,
838
820
  props.referenceSchema
839
821
  ]);
840
- const handleValidate = useCallback3(({ property }) => {
822
+ const handleValidate = useCallback2(({ property }) => {
841
823
  if (property && view.fields.find((f) => f.path === property && f.path !== field.path)) {
842
824
  return [
843
825
  {
@@ -850,7 +832,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
850
832
  view.fields,
851
833
  field
852
834
  ]);
853
- const handleSave = useCallback3((props2) => {
835
+ const handleSave = useCallback2((props2) => {
854
836
  projection.setFieldProjection({
855
837
  field,
856
838
  props: props2
@@ -861,29 +843,29 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
861
843
  field,
862
844
  onSave
863
845
  ]);
864
- const handleCancel = useCallback3(() => {
846
+ const handleCancel = useCallback2(() => {
865
847
  requestAnimationFrame(() => onCancel?.());
866
848
  onSave();
867
849
  }, [
868
850
  onSave
869
851
  ]);
870
- const Custom = useMemo5(() => ({
871
- ["format"]: (props2) => /* @__PURE__ */ React11.createElement(SelectInput, {
852
+ const Custom = useMemo3(() => ({
853
+ ["format"]: (props2) => /* @__PURE__ */ React7.createElement(SelectInput, {
872
854
  ...props2,
873
855
  options: FormatEnums.filter((value) => value !== FormatEnum2.None).map((value) => ({
874
856
  value,
875
857
  label: t(`format ${value}`)
876
858
  }))
877
859
  }),
878
- ["referenceSchema"]: (props2) => /* @__PURE__ */ React11.createElement(SelectInput, {
860
+ ["referenceSchema"]: (props2) => /* @__PURE__ */ React7.createElement(SelectInput, {
879
861
  ...props2,
880
862
  options: schemas.map((schema) => ({
881
863
  value: schema.typename
882
864
  }))
883
865
  }),
884
- ["referencePath"]: (props2) => /* @__PURE__ */ React11.createElement(SelectInput, {
866
+ ["referencePath"]: (props2) => /* @__PURE__ */ React7.createElement(SelectInput, {
885
867
  ...props2,
886
- options: referenceSchema ? getSchemaProperties3(referenceSchema.ast).sort(sortProperties).map((p) => ({
868
+ options: referenceSchema ? getSchemaProperties2(referenceSchema.ast).sort(sortProperties).map((p) => ({
887
869
  value: p.name
888
870
  })) : []
889
871
  })
@@ -892,9 +874,9 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
892
874
  schemas,
893
875
  referenceSchema
894
876
  ]);
895
- const propIsNotType = useCallback3((props2) => props2.filter((p) => p.name !== "type"), []);
877
+ const propIsNotType = useCallback2((props2) => props2.filter((p) => p.name !== "type"), []);
896
878
  if (!fieldSchema) {
897
- log2.warn("invalid format", {
879
+ log3.warn("invalid format", {
898
880
  props
899
881
  }, {
900
882
  F: __dxlog_file3,
@@ -904,7 +886,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
904
886
  });
905
887
  return null;
906
888
  }
907
- return /* @__PURE__ */ React11.createElement(Form, {
889
+ return /* @__PURE__ */ React7.createElement(Form, {
908
890
  key: field.id,
909
891
  autoFocus: true,
910
892
  values: props,
@@ -923,30 +905,30 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
923
905
  };
924
906
 
925
907
  // packages/ui/react-ui-form/src/components/ViewEditor/ViewEditor.tsx
926
- import React12, { useCallback as useCallback4, useMemo as useMemo6, useState as useState3 } from "react";
927
- import { AST as AST4, Format, S as S2 } from "@dxos/echo-schema";
928
- import { IconButton as IconButton3, useTranslation as useTranslation5 } from "@dxos/react-ui";
908
+ import React8, { useCallback as useCallback3, useMemo as useMemo4, useState as useState3 } from "react";
909
+ import { AST as AST2, Format, S as S2 } from "@dxos/echo-schema";
910
+ import { IconButton as IconButton2, useTranslation as useTranslation4 } from "@dxos/react-ui";
929
911
  import { List } from "@dxos/react-ui-list";
930
- import { ghostHover, inputTextLabel, mx as mx6 } from "@dxos/react-ui-theme";
912
+ import { ghostHover, inputTextLabel, mx as mx3 } from "@dxos/react-ui-theme";
931
913
  import { FieldSchema, ViewProjection, VIEW_FIELD_LIMIT } from "@dxos/schema";
932
914
  import { arrayMove } from "@dxos/util";
933
915
  var grid = "grid grid-cols-[32px_1fr_32px] min-bs-[2.5rem]";
934
916
  var ViewMetaSchema = S2.Struct({
935
917
  name: S2.String.annotations({
936
- [AST4.TitleAnnotationId]: "View"
918
+ [AST2.TitleAnnotationId]: "View"
937
919
  }),
938
920
  typename: Format.DXN.annotations({
939
- [AST4.TitleAnnotationId]: "Typename"
921
+ [AST2.TitleAnnotationId]: "Typename"
940
922
  })
941
923
  }).pipe(S2.mutable);
942
924
  var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading = false, onTypenameChanged, onDelete }) => {
943
- const { t } = useTranslation5(translationKey);
944
- const projection = useMemo6(() => new ViewProjection(schema, view), [
925
+ const { t } = useTranslation4(translationKey);
926
+ const projection = useMemo4(() => new ViewProjection(schema, view), [
945
927
  schema,
946
928
  view
947
929
  ]);
948
930
  const [field, setField] = useState3();
949
- const viewValues = useMemo6(() => {
931
+ const viewValues = useMemo4(() => {
950
932
  return {
951
933
  name: view.name,
952
934
  // TODO(burdon): Need to warn user of possible consequences of editing.
@@ -956,7 +938,7 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
956
938
  }, [
957
939
  view
958
940
  ]);
959
- const handleViewUpdate = useCallback4(({ name, typename }) => {
941
+ const handleViewUpdate = useCallback3(({ name, typename }) => {
960
942
  requestAnimationFrame(() => {
961
943
  if (view.name !== name) {
962
944
  view.name = name;
@@ -970,67 +952,67 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
970
952
  schema,
971
953
  onTypenameChanged
972
954
  ]);
973
- const handleSelect = useCallback4((field2) => {
955
+ const handleSelect = useCallback3((field2) => {
974
956
  setField((f) => f === field2 ? void 0 : field2);
975
957
  }, []);
976
- const handleAdd = useCallback4(() => {
958
+ const handleAdd = useCallback3(() => {
977
959
  const field2 = projection.createFieldProjection();
978
960
  setField(field2);
979
961
  }, [
980
962
  view
981
963
  ]);
982
- const handleMove = useCallback4((fromIndex, toIndex) => {
964
+ const handleMove = useCallback3((fromIndex, toIndex) => {
983
965
  arrayMove(view.fields, fromIndex, toIndex);
984
966
  }, [
985
967
  view.fields
986
968
  ]);
987
- const handleClose = useCallback4(() => setField(void 0), []);
988
- return /* @__PURE__ */ React12.createElement("div", {
969
+ const handleClose = useCallback3(() => setField(void 0), []);
970
+ return /* @__PURE__ */ React8.createElement("div", {
989
971
  role: "none",
990
- className: mx6("flex flex-col w-full divide-y divide-separator", classNames)
991
- }, /* @__PURE__ */ React12.createElement(Form, {
972
+ className: mx3("flex flex-col w-full divide-y divide-separator", classNames)
973
+ }, /* @__PURE__ */ React8.createElement(Form, {
992
974
  autoFocus: true,
993
975
  autoSave: true,
994
976
  schema: ViewMetaSchema,
995
977
  values: viewValues,
996
978
  onSave: handleViewUpdate
997
- }), /* @__PURE__ */ React12.createElement("div", null, /* @__PURE__ */ React12.createElement("div", {
979
+ }), /* @__PURE__ */ React8.createElement("div", null, /* @__PURE__ */ React8.createElement("div", {
998
980
  role: "none",
999
981
  className: "p-2"
1000
- }, /* @__PURE__ */ React12.createElement("label", {
1001
- className: mx6(inputTextLabel)
1002
- }, t("fields label"))), /* @__PURE__ */ React12.createElement(List.Root, {
982
+ }, /* @__PURE__ */ React8.createElement("label", {
983
+ className: mx3(inputTextLabel)
984
+ }, t("fields label"))), /* @__PURE__ */ React8.createElement(List.Root, {
1003
985
  items: view.fields,
1004
986
  isItem: S2.is(FieldSchema),
1005
987
  getId: (field2) => field2.id,
1006
988
  onMove: handleMove
1007
- }, ({ items: fields }) => /* @__PURE__ */ React12.createElement(React12.Fragment, null, showHeading && /* @__PURE__ */ React12.createElement("div", {
989
+ }, ({ items: fields }) => /* @__PURE__ */ React8.createElement(React8.Fragment, null, showHeading && /* @__PURE__ */ React8.createElement("div", {
1008
990
  role: "heading",
1009
991
  className: grid
1010
- }, /* @__PURE__ */ React12.createElement("div", null), /* @__PURE__ */ React12.createElement("div", {
992
+ }, /* @__PURE__ */ React8.createElement("div", null), /* @__PURE__ */ React8.createElement("div", {
1011
993
  className: "flex items-center text-sm"
1012
- }, t("field path label"))), /* @__PURE__ */ React12.createElement("div", {
994
+ }, t("field path label"))), /* @__PURE__ */ React8.createElement("div", {
1013
995
  role: "list",
1014
996
  className: "flex flex-col w-full"
1015
- }, fields?.map((field2) => /* @__PURE__ */ React12.createElement(List.Item, {
997
+ }, fields?.map((field2) => /* @__PURE__ */ React8.createElement(List.Item, {
1016
998
  key: field2.id,
1017
999
  item: field2,
1018
- classNames: mx6(grid, ghostHover, "cursor-pointer")
1019
- }, /* @__PURE__ */ React12.createElement(List.ItemDragHandle, null), /* @__PURE__ */ React12.createElement(List.ItemTitle, {
1000
+ classNames: mx3(grid, ghostHover, "cursor-pointer")
1001
+ }, /* @__PURE__ */ React8.createElement(List.ItemDragHandle, null), /* @__PURE__ */ React8.createElement(List.ItemTitle, {
1020
1002
  onClick: () => handleSelect(field2)
1021
- }, field2.path), /* @__PURE__ */ React12.createElement(List.ItemDeleteButton, {
1003
+ }, field2.path), /* @__PURE__ */ React8.createElement(List.ItemDeleteButton, {
1022
1004
  disabled: view.fields.length <= 1,
1023
1005
  onClick: () => onDelete(field2.id)
1024
- }))))))), field && /* @__PURE__ */ React12.createElement(FieldEditor, {
1006
+ }))))))), field && /* @__PURE__ */ React8.createElement(FieldEditor, {
1025
1007
  key: field.id,
1026
1008
  view,
1027
1009
  projection,
1028
1010
  field,
1029
1011
  registry,
1030
1012
  onSave: handleClose
1031
- }), !readonly && !field && /* @__PURE__ */ React12.createElement("div", {
1013
+ }), !readonly && !field && /* @__PURE__ */ React8.createElement("div", {
1032
1014
  className: "flex p-2 justify-center"
1033
- }, /* @__PURE__ */ React12.createElement(IconButton3, {
1015
+ }, /* @__PURE__ */ React8.createElement(IconButton2, {
1034
1016
  icon: "ph--plus--regular",
1035
1017
  label: t("button add property"),
1036
1018
  onClick: handleAdd,
@@ -1263,6 +1245,7 @@ export {
1263
1245
  DeprecatedFormInput,
1264
1246
  FieldEditor,
1265
1247
  Form,
1248
+ FormActions,
1266
1249
  GeoPointInput,
1267
1250
  InputHeader,
1268
1251
  NumberInput,