@dxos/react-ui-form 0.7.5-labs.ea4b4c2 → 0.7.5-labs.f400bbc

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 (61) hide show
  1. package/dist/lib/browser/index.mjs +299 -115
  2. package/dist/lib/browser/index.mjs.map +3 -3
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node/index.cjs +324 -139
  5. package/dist/lib/node/index.cjs.map +3 -3
  6. package/dist/lib/node/meta.json +1 -1
  7. package/dist/lib/node-esm/index.mjs +299 -115
  8. package/dist/lib/node-esm/index.mjs.map +3 -3
  9. package/dist/lib/node-esm/meta.json +1 -1
  10. package/dist/types/src/components/FieldEditor/FieldEditor.d.ts +1 -2
  11. package/dist/types/src/components/FieldEditor/FieldEditor.d.ts.map +1 -1
  12. package/dist/types/src/components/Form/ArrayField.d.ts +1 -2
  13. package/dist/types/src/components/Form/ArrayField.d.ts.map +1 -1
  14. package/dist/types/src/components/Form/Defaults.d.ts +5 -5
  15. package/dist/types/src/components/Form/Defaults.d.ts.map +1 -1
  16. package/dist/types/src/components/Form/Form.d.ts +2 -2
  17. package/dist/types/src/components/Form/Form.d.ts.map +1 -1
  18. package/dist/types/src/components/Form/FormActions.d.ts +1 -2
  19. package/dist/types/src/components/Form/FormActions.d.ts.map +1 -1
  20. package/dist/types/src/components/Form/FormContent.d.ts +2 -3
  21. package/dist/types/src/components/Form/FormContent.d.ts.map +1 -1
  22. package/dist/types/src/components/Form/FormContext.d.ts +4 -1
  23. package/dist/types/src/components/Form/FormContext.d.ts.map +1 -1
  24. package/dist/types/src/components/Form/Input.d.ts +2 -2
  25. package/dist/types/src/components/Form/Input.d.ts.map +1 -1
  26. package/dist/types/src/components/Form/custom/GeoPointInput.d.ts +1 -2
  27. package/dist/types/src/components/Form/custom/GeoPointInput.d.ts.map +1 -1
  28. package/dist/types/src/components/Form/custom/SelectOptionsInput.d.ts +1 -2
  29. package/dist/types/src/components/Form/custom/SelectOptionsInput.d.ts.map +1 -1
  30. package/dist/types/src/components/Form/custom/TupleInput.d.ts +1 -2
  31. package/dist/types/src/components/Form/custom/TupleInput.d.ts.map +1 -1
  32. package/dist/types/src/components/Form/factory.d.ts.map +1 -1
  33. package/dist/types/src/components/ViewEditor/Test.stories.d.ts +1 -2
  34. package/dist/types/src/components/ViewEditor/Test.stories.d.ts.map +1 -1
  35. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts +1 -2
  36. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts.map +1 -1
  37. package/dist/types/src/components/deprecated/Form.d.ts +1 -2
  38. package/dist/types/src/components/deprecated/Form.d.ts.map +1 -1
  39. package/dist/types/src/components/deprecated/Form.stories.d.ts +1 -2
  40. package/dist/types/src/components/deprecated/Form.stories.d.ts.map +1 -1
  41. package/dist/types/src/components/deprecated/FormInput.d.ts +2 -2
  42. package/dist/types/src/components/deprecated/FormInput.d.ts.map +1 -1
  43. package/dist/types/src/components/testing.d.ts +3 -3
  44. package/dist/types/src/components/testing.d.ts.map +1 -1
  45. package/dist/types/src/hooks/useForm.d.ts +1 -0
  46. package/dist/types/src/hooks/useForm.d.ts.map +1 -1
  47. package/dist/types/src/util/field.d.ts.map +1 -1
  48. package/dist/types/src/util/formatting.d.ts.map +1 -1
  49. package/package.json +25 -24
  50. package/src/components/Form/Defaults.tsx +59 -3
  51. package/src/components/Form/Form.tsx +8 -5
  52. package/src/components/Form/FormContent.tsx +9 -12
  53. package/src/components/Form/FormContext.tsx +58 -10
  54. package/src/components/Form/custom/GeoPointInput.tsx +42 -12
  55. package/src/components/Form/custom/SelectOptionsInput.tsx +7 -9
  56. package/src/components/Form/factory.tsx +4 -2
  57. package/src/components/ViewEditor/ViewEditor.tsx +2 -2
  58. package/src/hooks/useForm.ts +69 -40
  59. package/src/translations.ts +1 -1
  60. package/src/util/field.ts +19 -1
  61. package/src/util/formatting.ts +29 -1
@@ -35,6 +35,7 @@ __export(node_exports, {
35
35
  Form: () => Form,
36
36
  GeoPointInput: () => GeoPointInput,
37
37
  InputHeader: () => InputHeader,
38
+ MarkdownInput: () => MarkdownInput,
38
39
  NumberInput: () => NumberInput,
39
40
  SelectInput: () => SelectInput,
40
41
  SelectOptionInput: () => SelectOptionInput,
@@ -71,6 +72,7 @@ var import_invariant = require("@dxos/invariant");
71
72
  var import_log2 = require("@dxos/log");
72
73
  var import_schema2 = require("@dxos/schema");
73
74
  var import_react5 = __toESM(require("react"));
75
+ var import_echo_schema4 = require("@dxos/echo-schema");
74
76
  var import_react_ui3 = require("@dxos/react-ui");
75
77
  var import_util = require("@dxos/util");
76
78
  var import_react6 = __toESM(require("react"));
@@ -96,7 +98,7 @@ var import_react_ui_theme6 = require("@dxos/react-ui-theme");
96
98
  var import_effect3 = require("effect");
97
99
  var import_String = require("effect/String");
98
100
  var import_react12 = __toESM(require("react"));
99
- var import_echo_schema4 = require("@dxos/echo-schema");
101
+ var import_echo_schema5 = require("@dxos/echo-schema");
100
102
  var import_effect4 = require("@dxos/effect");
101
103
  var import_react_ui_theme7 = require("@dxos/react-ui-theme");
102
104
  var import_schema3 = require("@dxos/schema");
@@ -104,21 +106,21 @@ var import_util3 = require("@dxos/util");
104
106
  var import_effect5 = require("effect");
105
107
  var import_String2 = require("effect/String");
106
108
  var import_react13 = __toESM(require("react"));
107
- var import_echo_schema5 = require("@dxos/echo-schema");
109
+ var import_echo_schema6 = require("@dxos/echo-schema");
108
110
  var import_effect6 = require("@dxos/effect");
109
111
  var import_invariant2 = require("@dxos/invariant");
110
112
  var import_react_ui9 = require("@dxos/react-ui");
111
113
  var import_react_ui_theme8 = require("@dxos/react-ui-theme");
112
114
  var import_schema4 = require("@dxos/schema");
113
- var import_echo_schema6 = require("@dxos/echo-schema");
114
- var import_react14 = __toESM(require("react"));
115
115
  var import_echo_schema7 = require("@dxos/echo-schema");
116
+ var import_react14 = __toESM(require("react"));
117
+ var import_echo_schema8 = require("@dxos/echo-schema");
116
118
  var import_react_ui10 = require("@dxos/react-ui");
117
119
  var import_react_ui_list2 = require("@dxos/react-ui-list");
118
120
  var import_react_ui_theme9 = require("@dxos/react-ui-theme");
119
121
  var import_schema5 = require("@dxos/schema");
120
- var import_echo_schema8 = require("@dxos/echo-schema");
121
122
  var import_echo_schema9 = require("@dxos/echo-schema");
123
+ var import_echo_schema10 = require("@dxos/echo-schema");
122
124
  var translationKey = "react-ui-form";
123
125
  var translations_default = [
124
126
  {
@@ -149,7 +151,7 @@ var translations_default = [
149
151
  "format hostname": "Hostname",
150
152
  "format integer": "Integer",
151
153
  "format json": "JSON",
152
- "format latlng": "LatLng",
154
+ "format latlng": "Geopoint",
153
155
  "format markdown": "Markdown",
154
156
  "format percent": "Percent",
155
157
  "format ref": "Reference",
@@ -216,7 +218,7 @@ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/ho
216
218
  var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, onSave }) => {
217
219
  (0, import_invariant.invariant)(import_effect2.AST.isTypeLiteral(schema.ast), void 0, {
218
220
  F: __dxlog_file,
219
- L: 91,
221
+ L: 92,
220
222
  S: void 0,
221
223
  A: [
222
224
  "AST.isTypeLiteral(schema.ast)",
@@ -259,7 +261,12 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
259
261
  values,
260
262
  schemaDirty
261
263
  ]);
262
- const canSave = (0, import_react4.useMemo)(() => !saving && // Check if any error paths that are touched have errors
264
+ const formIsValid = (0, import_react4.useMemo)(() => {
265
+ return Object.keys(errors).length === 0;
266
+ }, [
267
+ errors
268
+ ]);
269
+ const canSave = (0, import_react4.useMemo)(() => !saving && // Check if any error paths that are touched have errors.
263
270
  !Object.entries(touched).some(([path, isTouched]) => isTouched && Object.keys(errors).some((errorPath) => errorPath === path || errorPath.startsWith(`${path}.`) || errorPath.startsWith(`${path}[`))), [
264
271
  touched,
265
272
  errors,
@@ -292,10 +299,12 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
292
299
  }, [
293
300
  errors
294
301
  ]);
295
- const getFormValue = (path) => {
302
+ const getFormValue = (0, import_react4.useCallback)((path) => {
296
303
  return (0, import_echo_schema3.getValue)(values, (0, import_effect2.createJsonPath)(path));
297
- };
298
- const onValueChange = (path, type, value) => {
304
+ }, [
305
+ values
306
+ ]);
307
+ const onValueChange = (0, import_react4.useCallback)((path, type, value) => {
299
308
  const jsonPath = (0, import_effect2.createJsonPath)(path);
300
309
  let parsedValue = value;
301
310
  try {
@@ -305,7 +314,7 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
305
314
  } catch (err) {
306
315
  import_log2.log.catch(err, void 0, {
307
316
  F: __dxlog_file,
308
- L: 193,
317
+ L: 202,
309
318
  S: void 0,
310
319
  C: (f, a) => f(...a)
311
320
  });
@@ -326,7 +335,13 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
326
335
  changed
327
336
  });
328
337
  }
329
- };
338
+ }, [
339
+ values,
340
+ onValuesChanged,
341
+ validate,
342
+ onValid,
343
+ changed
344
+ ]);
330
345
  const onTouched = (0, import_react4.useCallback)((path) => {
331
346
  const jsonPath = (0, import_effect2.createJsonPath)(path);
332
347
  setTouched((touched2) => ({
@@ -338,25 +353,39 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
338
353
  validate,
339
354
  values
340
355
  ]);
341
- return {
356
+ return (0, import_react4.useMemo)(() => ({
342
357
  // State.
343
358
  values,
344
359
  errors,
345
360
  touched,
346
361
  changed,
347
362
  canSave,
363
+ formIsValid,
364
+ // Actions.
348
365
  handleSave,
349
366
  // Field utils.
350
367
  getStatus,
351
368
  getValue: getFormValue,
352
369
  onValueChange,
353
370
  onTouched
354
- };
371
+ }), [
372
+ values,
373
+ errors,
374
+ touched,
375
+ changed,
376
+ canSave,
377
+ formIsValid,
378
+ handleSave,
379
+ getStatus,
380
+ getFormValue,
381
+ onValueChange,
382
+ onTouched
383
+ ]);
355
384
  };
356
385
  var createKeySet = (obj, value) => {
357
386
  (0, import_invariant.invariant)(obj, void 0, {
358
387
  F: __dxlog_file,
359
- L: 235,
388
+ L: 264,
360
389
  S: void 0,
361
390
  A: [
362
391
  "obj",
@@ -388,17 +417,56 @@ var useFormValues = (path = []) => {
388
417
  };
389
418
  var useInputProps = (path = []) => {
390
419
  const { getStatus, getValue: getFormValue, onValueChange, onTouched } = useFormContext();
391
- return {
392
- getStatus: () => getStatus(path),
393
- getValue: () => getFormValue(path),
394
- onValueChange: (type, value) => onValueChange(path, type, value),
395
- onBlur: () => onTouched(path)
396
- };
420
+ const stablePath = (0, import_react3.useMemo)(() => path, [
421
+ Array.isArray(path) ? path.join(".") : path
422
+ ]);
423
+ return (0, import_react3.useMemo)(() => ({
424
+ getStatus: () => getStatus(stablePath),
425
+ getValue: () => getFormValue(stablePath),
426
+ onValueChange: (type, value) => onValueChange(stablePath, type, value),
427
+ onBlur: () => onTouched(stablePath)
428
+ }), [
429
+ getStatus,
430
+ getFormValue,
431
+ onValueChange,
432
+ onTouched,
433
+ stablePath
434
+ ]);
397
435
  };
398
- var FormProvider = ({ children, ...formOptions }) => {
399
- const formHandler = useForm(formOptions);
436
+ var FormProvider = ({ children, formRef, autoSave, ...formOptions }) => {
437
+ const form = useForm(formOptions);
438
+ (0, import_react3.useEffect)(() => {
439
+ if (!formRef?.current) {
440
+ return;
441
+ }
442
+ const handleKeyDown = (event) => {
443
+ const keyIsEnter = event.key === "Enter";
444
+ const modifierUsed = event.ctrlKey || event.altKey || event.metaKey || event.shiftKey;
445
+ const inputIsTextarea = event.target.tagName.toLowerCase() === "textarea";
446
+ const inputOptOut = event.target.hasAttribute("data-no-submit");
447
+ const shouldSubmitRegularInput = !inputIsTextarea && keyIsEnter && !modifierUsed;
448
+ const shouldSubmitTextarea = inputIsTextarea && keyIsEnter && event.metaKey;
449
+ if ((shouldSubmitRegularInput || shouldSubmitTextarea) && !inputOptOut) {
450
+ if (!autoSave && form.canSave) {
451
+ form.handleSave();
452
+ }
453
+ if (autoSave && form.formIsValid) {
454
+ event.target.blur();
455
+ }
456
+ }
457
+ };
458
+ const formElement = formRef.current;
459
+ formElement.addEventListener("keydown", handleKeyDown);
460
+ return () => formElement.removeEventListener("keydown", handleKeyDown);
461
+ }, [
462
+ formRef,
463
+ form.canSave,
464
+ form.formIsValid,
465
+ form.handleSave,
466
+ autoSave
467
+ ]);
400
468
  return /* @__PURE__ */ import_react3.default.createElement(FormContext.Provider, {
401
- value: formHandler
469
+ value: form
402
470
  }, children);
403
471
  };
404
472
  var InputHeader = ({ children, error }) => {
@@ -418,32 +486,69 @@ var InputHeader = ({ children, error }) => {
418
486
  var GeoPointInput = ({ type, label, disabled, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
419
487
  const { t } = (0, import_react_ui3.useTranslation)(translationKey);
420
488
  const { status, error } = getStatus();
421
- const [lng = 0, lat = 0] = getValue3() ?? [];
489
+ const geoPoint = (0, import_react5.useMemo)(() => getValue3() ?? [
490
+ 0,
491
+ 0
492
+ ], [
493
+ getValue3
494
+ ]);
495
+ const geoLocation = (0, import_react5.useMemo)(() => import_echo_schema4.GeoLocation.fromGeoPoint(geoPoint), [
496
+ geoPoint
497
+ ]);
498
+ const [longitudeText, setLongitudeText] = (0, import_react5.useState)(geoLocation.longitude?.toString());
499
+ const [latitudeText, setLatitudeText] = (0, import_react5.useState)(geoLocation.latitude?.toString());
500
+ (0, import_react5.useEffect)(() => {
501
+ const location = import_echo_schema4.GeoLocation.fromGeoPoint(geoPoint);
502
+ setLongitudeText(location.longitude.toString());
503
+ setLatitudeText(location.latitude.toString());
504
+ }, [
505
+ geoPoint
506
+ ]);
507
+ const handleCoordinateChange = (0, import_react5.useCallback)((coordinateType, setText) => (event) => {
508
+ const inputText = event.target.value;
509
+ setText(inputText);
510
+ if (inputText !== "" && inputText !== "-") {
511
+ const coord = (0, import_util.safeParseFloat)(inputText);
512
+ if (coord !== void 0 && !isNaN(coord)) {
513
+ const currentLocation = import_echo_schema4.GeoLocation.fromGeoPoint(getValue3() ?? [
514
+ 0,
515
+ 0
516
+ ]);
517
+ const newLocation = {
518
+ ...currentLocation,
519
+ [coordinateType]: coord
520
+ };
521
+ const newValue = import_echo_schema4.GeoLocation.toGeoPoint(newLocation);
522
+ onValueChange(type, newValue);
523
+ }
524
+ }
525
+ }, [
526
+ getValue3,
527
+ onValueChange,
528
+ type
529
+ ]);
422
530
  return /* @__PURE__ */ import_react5.default.createElement(import_react_ui3.Input.Root, {
423
531
  validationValence: status
424
532
  }, /* @__PURE__ */ import_react5.default.createElement(InputHeader, {
425
533
  error
426
534
  }, /* @__PURE__ */ import_react5.default.createElement(import_react_ui3.Input.Label, null, label)), /* @__PURE__ */ import_react5.default.createElement("div", {
535
+ role: "none",
427
536
  className: "grid grid-cols-2 gap-2"
428
537
  }, /* @__PURE__ */ import_react5.default.createElement(import_react_ui3.Input.TextInput, {
429
- type: "number",
538
+ type: "text",
539
+ pattern: "^-?[0-9]*\\.?[0-9]*$",
430
540
  disabled,
431
- placeholder: t("placeholder longitude"),
432
- value: lng,
433
- onChange: (event) => onValueChange(type, [
434
- lat,
435
- (0, import_util.safeParseFloat)(event.target.value, 0)
436
- ]),
541
+ placeholder: t("placeholder latitude"),
542
+ value: latitudeText,
543
+ onChange: handleCoordinateChange("latitude", setLatitudeText),
437
544
  onBlur
438
545
  }), /* @__PURE__ */ import_react5.default.createElement(import_react_ui3.Input.TextInput, {
439
- type: "number",
546
+ type: "text",
547
+ pattern: "^-?[0-9]*\\.?[0-9]*$",
440
548
  disabled,
441
- placeholder: t("placeholder latitude"),
442
- value: lat,
443
- onChange: (event) => onValueChange(type, [
444
- (0, import_util.safeParseFloat)(event.target.value, 0),
445
- lng
446
- ]),
549
+ placeholder: t("placeholder longitude"),
550
+ value: longitudeText,
551
+ onChange: handleCoordinateChange("longitude", setLongitudeText),
447
552
  onBlur
448
553
  })));
449
554
  };
@@ -465,14 +570,13 @@ var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3
465
570
  ]);
466
571
  const randomHue = () => {
467
572
  const usedHues = new Set(options?.map((option) => option.color) ?? []);
468
- const hueKeys = Object.keys(import_react_ui_theme3.hueTokenThemes);
469
- const unusedHues = hueKeys.filter((hue) => !usedHues.has(hue));
573
+ const unusedHues = import_react_ui_theme3.hues.filter((hue) => !usedHues.has(hue));
470
574
  if (unusedHues.length > 0) {
471
575
  return unusedHues[Math.floor(Math.random() * unusedHues.length)];
472
576
  }
473
577
  const lastThree = new Set(options?.slice(-3).map((option) => option.color) ?? []);
474
- const availableHues = hueKeys.filter((hue) => !lastThree.has(hue));
475
- return availableHues[Math.floor(Math.random() * availableHues.length)] ?? hueKeys[Math.floor(Math.random() * hueKeys.length)];
578
+ const availableHues = import_react_ui_theme3.hues.filter((hue) => !lastThree.has(hue));
579
+ return availableHues[Math.floor(Math.random() * availableHues.length)] ?? import_react_ui_theme3.hues[Math.floor(Math.random() * import_react_ui_theme3.hues.length)];
476
580
  };
477
581
  const handleAdd = (0, import_react7.useCallback)(() => {
478
582
  const newId = import_keys.PublicKey.random().truncate();
@@ -597,12 +701,13 @@ var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3
597
701
  value: item.title,
598
702
  onChange: handleTitleChange(item.id),
599
703
  onKeyDown: handleKeyDown,
600
- classNames: "flex-1"
704
+ classNames: "flex-1",
705
+ "data-no-submit": true
601
706
  }), /* @__PURE__ */ import_react7.default.createElement(import_react_ui5.Toolbar.Root, {
602
707
  classNames: "p-0 m-0 !is-auto"
603
- }, /* @__PURE__ */ import_react7.default.createElement(import_react_ui_pickers.HuePickerToolbarButton, {
604
- hue: item.color,
605
- onChangeHue: handleColorChange(item.id)
708
+ }, /* @__PURE__ */ import_react7.default.createElement(import_react_ui_pickers.HuePicker, {
709
+ value: item.color,
710
+ onChange: handleColorChange(item.id)
606
711
  })), /* @__PURE__ */ import_react7.default.createElement(import_react_ui5.IconButton, {
607
712
  icon: "ph--trash--fill",
608
713
  iconOnly: true,
@@ -711,6 +816,45 @@ var SelectInput = ({ type, label, inputOnly, disabled, placeholder, options, get
711
816
  }, label2 ?? String(value))
712
817
  )))))), inputOnly && /* @__PURE__ */ import_react9.default.createElement(import_react_ui7.Input.DescriptionAndValidation, null, error));
713
818
  };
819
+ var MarkdownInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
820
+ const { status, error } = getStatus();
821
+ const textareaRef = (0, import_react9.useRef)(null);
822
+ const adjustHeight = (0, import_react9.useCallback)(() => {
823
+ const textarea = textareaRef.current;
824
+ if (textarea) {
825
+ textarea.style.blockSize = "auto";
826
+ textarea.style.blockSize = `${textarea.scrollHeight + 2}px`;
827
+ }
828
+ }, []);
829
+ (0, import_react9.useEffect)(() => {
830
+ adjustHeight();
831
+ }, [
832
+ adjustHeight
833
+ ]);
834
+ (0, import_react9.useEffect)(() => {
835
+ adjustHeight();
836
+ }, [
837
+ getValue3(),
838
+ adjustHeight
839
+ ]);
840
+ return /* @__PURE__ */ import_react9.default.createElement(import_react_ui7.Input.Root, {
841
+ validationValence: status
842
+ }, !inputOnly && /* @__PURE__ */ import_react9.default.createElement(InputHeader, {
843
+ error
844
+ }, /* @__PURE__ */ import_react9.default.createElement(import_react_ui7.Input.Label, null, label)), /* @__PURE__ */ import_react9.default.createElement(import_react_ui7.Input.TextArea, {
845
+ ref: textareaRef,
846
+ disabled,
847
+ placeholder,
848
+ value: getValue3() ?? "",
849
+ classNames: "min-bs-auto max-h-40 overflow-auto",
850
+ onChange: (event) => onValueChange(type, event.target.value),
851
+ onBlur,
852
+ style: {
853
+ resize: "none"
854
+ },
855
+ spellCheck: false
856
+ }), inputOnly && /* @__PURE__ */ import_react9.default.createElement(import_react_ui7.Input.Validation, null, error));
857
+ };
714
858
  var FormActions = ({ onCancel, readonly }) => {
715
859
  const { t } = (0, import_react_ui8.useTranslation)(translationKey);
716
860
  const { canSave, handleSave } = useFormContext();
@@ -750,11 +894,11 @@ var ArrayField = ({ property, readonly, path, inputProps, Custom, lookupComponen
750
894
  ]
751
895
  });
752
896
  const label = title ?? (0, import_effect5.pipe)(name, import_String2.capitalize);
753
- const tupleType = (0, import_effect6.findNode)(ast, import_echo_schema5.AST.isTupleType);
897
+ const tupleType = (0, import_effect6.findNode)(ast, import_echo_schema6.AST.isTupleType);
754
898
  const elementType = tupleType?.rest[0]?.type;
755
899
  const getDefaultObjectValue = (typeNode) => {
756
900
  const baseNode = (0, import_effect6.findNode)(typeNode, import_effect6.isDiscriminatedUnion);
757
- const typeLiteral = baseNode ? (0, import_effect6.getDiscriminatedType)(baseNode, {}) : (0, import_effect6.findNode)(typeNode, import_echo_schema5.AST.isTypeLiteral);
901
+ const typeLiteral = baseNode ? (0, import_effect6.getDiscriminatedType)(baseNode, {}) : (0, import_effect6.findNode)(typeNode, import_echo_schema6.AST.isTypeLiteral);
758
902
  if (!typeLiteral) {
759
903
  return {};
760
904
  }
@@ -840,8 +984,10 @@ var ArrayField = ({ property, readonly, path, inputProps, Custom, lookupComponen
840
984
  };
841
985
  var getInputComponent = (type, format) => {
842
986
  switch (format) {
843
- case import_echo_schema6.FormatEnum.LatLng:
987
+ case import_echo_schema7.FormatEnum.GeoPoint:
844
988
  return GeoPointInput;
989
+ case import_echo_schema7.FormatEnum.Markdown:
990
+ return MarkdownInput;
845
991
  }
846
992
  switch (type) {
847
993
  case "string":
@@ -865,7 +1011,7 @@ var FormField = ({ property, path, readonly, inline, lookupComponent, Custom })
865
1011
  ]);
866
1012
  const FoundComponent = lookupComponent?.({
867
1013
  prop: name,
868
- schema: import_echo_schema4.S.make(ast),
1014
+ schema: import_echo_schema5.S.make(ast),
869
1015
  inputProps: {
870
1016
  type,
871
1017
  format,
@@ -883,20 +1029,15 @@ var FormField = ({ property, path, readonly, inline, lookupComponent, Custom })
883
1029
  const jsonPath = (0, import_effect4.createJsonPath)(path ?? []);
884
1030
  const CustomComponent = Custom?.[jsonPath];
885
1031
  if (CustomComponent) {
886
- return (
887
- // TODO(ZaymonFC): We should try to remove this div wrapper.
888
- /* @__PURE__ */ import_react12.default.createElement("div", {
889
- role: "none"
890
- }, /* @__PURE__ */ import_react12.default.createElement(CustomComponent, {
891
- type,
892
- format,
893
- label,
894
- inputOnly: inline,
895
- placeholder,
896
- disabled: readonly,
897
- ...inputProps
898
- }))
899
- );
1032
+ return /* @__PURE__ */ import_react12.default.createElement(CustomComponent, {
1033
+ type,
1034
+ format,
1035
+ label,
1036
+ inputOnly: inline,
1037
+ placeholder,
1038
+ disabled: readonly,
1039
+ ...inputProps
1040
+ });
900
1041
  }
901
1042
  if (array) {
902
1043
  return /* @__PURE__ */ import_react12.default.createElement(ArrayField, {
@@ -940,12 +1081,12 @@ var FormField = ({ property, path, readonly, inline, lookupComponent, Custom })
940
1081
  }
941
1082
  if (type === "object") {
942
1083
  const baseNode = (0, import_effect4.findNode)(ast, import_effect4.isDiscriminatedUnion);
943
- const typeLiteral = baseNode ? (0, import_effect4.getDiscriminatedType)(baseNode, inputProps.getValue()) : (0, import_effect4.findNode)(ast, import_echo_schema4.AST.isTypeLiteral);
1084
+ const typeLiteral = baseNode ? (0, import_effect4.getDiscriminatedType)(baseNode, inputProps.getValue()) : (0, import_effect4.findNode)(ast, import_echo_schema5.AST.isTypeLiteral);
944
1085
  if (typeLiteral) {
945
1086
  return /* @__PURE__ */ import_react12.default.createElement("div", {
946
1087
  role: "none"
947
1088
  }, !inline && /* @__PURE__ */ import_react12.default.createElement("div", null, label), /* @__PURE__ */ import_react12.default.createElement(FormFields, {
948
- schema: import_echo_schema4.S.make(typeLiteral),
1089
+ schema: import_echo_schema5.S.make(typeLiteral),
949
1090
  path,
950
1091
  readonly,
951
1092
  Custom
@@ -984,13 +1125,14 @@ var FormFields = ({ schema, path, filter, sort, readonly, lookupComponent, Custo
984
1125
  }).filter(import_util3.isNotFalsy));
985
1126
  };
986
1127
  var Form = ({ classNames, schema, values: initialValues, path = [], autoFocus, readonly, filter, sort, autoSave, testId, onValuesChanged, onValidate, onSave, onCancel, lookupComponent, Custom }) => {
1128
+ const formRef = (0, import_react10.useRef)(null);
987
1129
  const onValid = (0, import_react10.useMemo)(() => autoSave ? onSave : void 0, [
988
1130
  autoSave,
989
1131
  onSave
990
1132
  ]);
991
1133
  (0, import_react10.useEffect)(() => {
992
- if (autoFocus) {
993
- const input = document.querySelector("input");
1134
+ if (autoFocus && formRef.current) {
1135
+ const input = formRef.current.querySelector("input");
994
1136
  if (input) {
995
1137
  input.focus();
996
1138
  }
@@ -999,13 +1141,16 @@ var Form = ({ classNames, schema, values: initialValues, path = [], autoFocus, r
999
1141
  autoFocus
1000
1142
  ]);
1001
1143
  return /* @__PURE__ */ import_react10.default.createElement(FormProvider, {
1144
+ formRef,
1002
1145
  schema,
1146
+ autoSave,
1003
1147
  initialValues,
1004
1148
  onValuesChanged,
1005
1149
  onValidate,
1006
1150
  onValid,
1007
1151
  onSave
1008
1152
  }, /* @__PURE__ */ import_react10.default.createElement("div", {
1153
+ ref: formRef,
1009
1154
  role: "none",
1010
1155
  className: (0, import_react_ui_theme5.mx)("p-2", classNames),
1011
1156
  "data-testid": testId
@@ -1180,14 +1325,14 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
1180
1325
  });
1181
1326
  };
1182
1327
  var grid = "grid grid-cols-[32px_1fr_32px] min-bs-[2.5rem]";
1183
- var ViewMetaSchema = import_echo_schema7.S.Struct({
1184
- name: import_echo_schema7.S.String.annotations({
1185
- [import_echo_schema7.AST.TitleAnnotationId]: "View"
1328
+ var ViewMetaSchema = import_echo_schema8.S.Struct({
1329
+ name: import_echo_schema8.S.String.annotations({
1330
+ [import_echo_schema8.AST.TitleAnnotationId]: "View"
1186
1331
  }),
1187
- typename: import_echo_schema7.Format.DXN.annotations({
1188
- [import_echo_schema7.AST.TitleAnnotationId]: "Typename"
1332
+ typename: import_echo_schema8.Format.URL.annotations({
1333
+ [import_echo_schema8.AST.TitleAnnotationId]: "Typename"
1189
1334
  })
1190
- }).pipe(import_echo_schema7.S.mutable);
1335
+ }).pipe(import_echo_schema8.S.mutable);
1191
1336
  var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading = false, onTypenameChanged, onDelete }) => {
1192
1337
  const { t } = (0, import_react_ui10.useTranslation)(translationKey);
1193
1338
  const projection = (0, import_react14.useMemo)(() => new import_schema5.ViewProjection(schema, view), [
@@ -1243,7 +1388,6 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
1243
1388
  role: "none",
1244
1389
  className: (0, import_react_ui_theme9.mx)("flex flex-col w-full divide-y divide-separator", classNames)
1245
1390
  }, /* @__PURE__ */ import_react14.default.createElement(Form, {
1246
- autoFocus: true,
1247
1391
  autoSave: true,
1248
1392
  schema: ViewMetaSchema,
1249
1393
  values: viewValues,
@@ -1255,7 +1399,7 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
1255
1399
  className: (0, import_react_ui_theme9.mx)(import_react_ui_theme9.inputTextLabel)
1256
1400
  }, t("fields label"))), /* @__PURE__ */ import_react14.default.createElement(import_react_ui_list2.List.Root, {
1257
1401
  items: view.fields,
1258
- isItem: import_echo_schema7.S.is(import_schema5.FieldSchema),
1402
+ isItem: import_echo_schema8.S.is(import_schema5.FieldSchema),
1259
1403
  getId: (field2) => field2.id,
1260
1404
  onMove: handleMove
1261
1405
  }, ({ items: fields }) => /* @__PURE__ */ import_react14.default.createElement(import_react14.default.Fragment, null, showHeading && /* @__PURE__ */ import_react14.default.createElement("div", {
@@ -1298,7 +1442,7 @@ var parseValue = ({ type, format, value }) => {
1298
1442
  }
1299
1443
  const parseScalar = (type2) => {
1300
1444
  switch (type2) {
1301
- case import_echo_schema8.TypeEnum.Boolean: {
1445
+ case import_echo_schema9.TypeEnum.Boolean: {
1302
1446
  if (typeof value === "string") {
1303
1447
  const lowercaseValue = value.toLowerCase();
1304
1448
  if (lowercaseValue === "0" || lowercaseValue === "false") {
@@ -1309,13 +1453,13 @@ var parseValue = ({ type, format, value }) => {
1309
1453
  }
1310
1454
  return Boolean(value);
1311
1455
  }
1312
- case import_echo_schema8.TypeEnum.Number: {
1456
+ case import_echo_schema9.TypeEnum.Number: {
1313
1457
  const cleaned = typeof value === "string" ? value.replace(/[^0-9.-]+/g, "") : value;
1314
1458
  const num = Number(cleaned);
1315
1459
  return Number.isNaN(num) ? null : num;
1316
1460
  }
1317
- case import_echo_schema8.TypeEnum.String:
1318
- case import_echo_schema8.TypeEnum.Ref:
1461
+ case import_echo_schema9.TypeEnum.String:
1462
+ case import_echo_schema9.TypeEnum.Ref:
1319
1463
  return String(value);
1320
1464
  default: {
1321
1465
  return value;
@@ -1326,25 +1470,45 @@ var parseValue = ({ type, format, value }) => {
1326
1470
  return parseScalar(type);
1327
1471
  }
1328
1472
  switch (format) {
1329
- case import_echo_schema8.FormatEnum.Boolean:
1330
- return parseScalar(import_echo_schema8.TypeEnum.Boolean);
1331
- case import_echo_schema8.FormatEnum.Number:
1332
- case import_echo_schema8.FormatEnum.Percent:
1333
- case import_echo_schema8.FormatEnum.Currency:
1334
- return parseScalar(import_echo_schema8.TypeEnum.Number);
1335
- case import_echo_schema8.FormatEnum.String:
1336
- case import_echo_schema8.FormatEnum.Markdown: {
1337
- return parseScalar(import_echo_schema8.TypeEnum.String);
1473
+ case import_echo_schema9.FormatEnum.Boolean:
1474
+ return parseScalar(import_echo_schema9.TypeEnum.Boolean);
1475
+ case import_echo_schema9.FormatEnum.Number:
1476
+ case import_echo_schema9.FormatEnum.Percent:
1477
+ case import_echo_schema9.FormatEnum.Currency:
1478
+ return parseScalar(import_echo_schema9.TypeEnum.Number);
1479
+ case import_echo_schema9.FormatEnum.String:
1480
+ case import_echo_schema9.FormatEnum.Markdown: {
1481
+ return parseScalar(import_echo_schema9.TypeEnum.String);
1338
1482
  }
1339
- case import_echo_schema8.FormatEnum.Ref:
1340
- throw new Error(`unexpected format: ${import_echo_schema8.FormatEnum.Ref}`);
1341
- case import_echo_schema8.FormatEnum.DateTime:
1342
- case import_echo_schema8.FormatEnum.Date:
1343
- case import_echo_schema8.FormatEnum.Time:
1344
- case import_echo_schema8.FormatEnum.Timestamp: {
1483
+ case import_echo_schema9.FormatEnum.Ref:
1484
+ throw new Error(`unexpected format: ${import_echo_schema9.FormatEnum.Ref}`);
1485
+ case import_echo_schema9.FormatEnum.DateTime:
1486
+ case import_echo_schema9.FormatEnum.Date:
1487
+ case import_echo_schema9.FormatEnum.Time:
1488
+ case import_echo_schema9.FormatEnum.Timestamp: {
1345
1489
  const date = new Date(value);
1346
1490
  return isNaN(date.getTime()) ? null : date;
1347
1491
  }
1492
+ case import_echo_schema9.FormatEnum.GeoPoint: {
1493
+ if (typeof value === "string") {
1494
+ const cleaned = value.replace(/[^0-9.,-]+/g, "");
1495
+ const parts = cleaned.split(",");
1496
+ if (parts.length === 2) {
1497
+ const lat = parseFloat(parts[0]);
1498
+ const long = parseFloat(parts[1]);
1499
+ if (!isNaN(lat) && !isNaN(long)) {
1500
+ return import_echo_schema9.GeoLocation.toGeoPoint({
1501
+ latitude: lat,
1502
+ longitude: long
1503
+ });
1504
+ }
1505
+ }
1506
+ }
1507
+ return [
1508
+ 0,
1509
+ 0
1510
+ ];
1511
+ }
1348
1512
  default: {
1349
1513
  return value;
1350
1514
  }
@@ -1353,19 +1517,19 @@ var parseValue = ({ type, format, value }) => {
1353
1517
  var cellClassesForFieldType = ({ type, format }) => {
1354
1518
  if (!format) {
1355
1519
  switch (type) {
1356
- case import_echo_schema8.TypeEnum.Number:
1520
+ case import_echo_schema9.TypeEnum.Number:
1357
1521
  return [
1358
1522
  "text-right",
1359
1523
  "font-mono"
1360
1524
  ];
1361
- case import_echo_schema8.TypeEnum.Boolean:
1525
+ case import_echo_schema9.TypeEnum.Boolean:
1362
1526
  return [
1363
1527
  "text-right",
1364
1528
  "font-mono"
1365
1529
  ];
1366
- case import_echo_schema8.TypeEnum.String:
1530
+ case import_echo_schema9.TypeEnum.String:
1367
1531
  return void 0;
1368
- case import_echo_schema8.TypeEnum.Ref:
1532
+ case import_echo_schema9.TypeEnum.Ref:
1369
1533
  return void 0;
1370
1534
  default: {
1371
1535
  return void 0;
@@ -1373,20 +1537,20 @@ var cellClassesForFieldType = ({ type, format }) => {
1373
1537
  }
1374
1538
  }
1375
1539
  switch (format) {
1376
- case import_echo_schema8.FormatEnum.Markdown:
1540
+ case import_echo_schema9.FormatEnum.Markdown:
1377
1541
  return void 0;
1378
- case import_echo_schema8.FormatEnum.Timestamp:
1379
- case import_echo_schema8.FormatEnum.DateTime:
1380
- case import_echo_schema8.FormatEnum.Date:
1381
- case import_echo_schema8.FormatEnum.Time:
1542
+ case import_echo_schema9.FormatEnum.Timestamp:
1543
+ case import_echo_schema9.FormatEnum.DateTime:
1544
+ case import_echo_schema9.FormatEnum.Date:
1545
+ case import_echo_schema9.FormatEnum.Time:
1382
1546
  return [
1383
1547
  "font-mono"
1384
1548
  ];
1385
- case import_echo_schema8.FormatEnum.Currency:
1549
+ case import_echo_schema9.FormatEnum.Currency:
1386
1550
  return [
1387
1551
  "text-right"
1388
1552
  ];
1389
- case import_echo_schema8.FormatEnum.JSON:
1553
+ case import_echo_schema9.FormatEnum.JSON:
1390
1554
  return [
1391
1555
  "font-mono"
1392
1556
  ];
@@ -1404,12 +1568,12 @@ var pathNotUniqueError = (path) => ({
1404
1568
  var formatForDisplay = ({ type, format, value, locale = void 0 }) => {
1405
1569
  const formatScalar = (type2) => {
1406
1570
  switch (type2) {
1407
- case import_echo_schema9.TypeEnum.Boolean:
1571
+ case import_echo_schema10.TypeEnum.Boolean:
1408
1572
  return value.toLocaleString().toUpperCase();
1409
- case import_echo_schema9.TypeEnum.Number:
1573
+ case import_echo_schema10.TypeEnum.Number:
1410
1574
  return value.toLocaleString(locale);
1411
- case import_echo_schema9.TypeEnum.String:
1412
- case import_echo_schema9.TypeEnum.Ref:
1575
+ case import_echo_schema10.TypeEnum.String:
1576
+ case import_echo_schema10.TypeEnum.Ref:
1413
1577
  return String(value);
1414
1578
  default: {
1415
1579
  return String(value);
@@ -1420,20 +1584,20 @@ var formatForDisplay = ({ type, format, value, locale = void 0 }) => {
1420
1584
  return formatScalar(type);
1421
1585
  }
1422
1586
  switch (format) {
1423
- case import_echo_schema9.FormatEnum.Boolean: {
1424
- return formatScalar(import_echo_schema9.TypeEnum.Boolean);
1587
+ case import_echo_schema10.FormatEnum.Boolean: {
1588
+ return formatScalar(import_echo_schema10.TypeEnum.Boolean);
1425
1589
  }
1426
- case import_echo_schema9.FormatEnum.Number: {
1427
- return formatScalar(import_echo_schema9.TypeEnum.Number);
1590
+ case import_echo_schema10.FormatEnum.Number: {
1591
+ return formatScalar(import_echo_schema10.TypeEnum.Number);
1428
1592
  }
1429
- case import_echo_schema9.FormatEnum.String:
1430
- case import_echo_schema9.FormatEnum.Ref: {
1431
- return formatScalar(import_echo_schema9.TypeEnum.String);
1593
+ case import_echo_schema10.FormatEnum.String:
1594
+ case import_echo_schema10.FormatEnum.Ref: {
1595
+ return formatScalar(import_echo_schema10.TypeEnum.String);
1432
1596
  }
1433
- case import_echo_schema9.FormatEnum.Percent: {
1597
+ case import_echo_schema10.FormatEnum.Percent: {
1434
1598
  return `${value * 100}%`;
1435
1599
  }
1436
- case import_echo_schema9.FormatEnum.Currency: {
1600
+ case import_echo_schema10.FormatEnum.Currency: {
1437
1601
  return value.toLocaleString(locale, {
1438
1602
  style: "currency",
1439
1603
  currency: "USD",
@@ -1441,18 +1605,28 @@ var formatForDisplay = ({ type, format, value, locale = void 0 }) => {
1441
1605
  maximumFractionDigits: 2
1442
1606
  });
1443
1607
  }
1444
- case import_echo_schema9.FormatEnum.DateTime:
1445
- case import_echo_schema9.FormatEnum.Date:
1446
- case import_echo_schema9.FormatEnum.Time: {
1608
+ case import_echo_schema10.FormatEnum.DateTime:
1609
+ case import_echo_schema10.FormatEnum.Date:
1610
+ case import_echo_schema10.FormatEnum.Time: {
1447
1611
  const date = new Date(value);
1448
- if (format === import_echo_schema9.FormatEnum.DateTime) {
1612
+ if (format === import_echo_schema10.FormatEnum.DateTime) {
1449
1613
  return date.toLocaleString(locale);
1450
- } else if (format === import_echo_schema9.FormatEnum.Date) {
1614
+ } else if (format === import_echo_schema10.FormatEnum.Date) {
1451
1615
  return date.toLocaleDateString(locale);
1452
1616
  } else {
1453
1617
  return date.toLocaleTimeString(locale);
1454
1618
  }
1455
1619
  }
1620
+ case import_echo_schema10.FormatEnum.GeoPoint: {
1621
+ if (value === null || value === void 0) {
1622
+ return "";
1623
+ }
1624
+ if (Array.isArray(value) && value.length >= 2 && value.every(Number.isFinite)) {
1625
+ const { latitude, longitude } = import_echo_schema10.GeoLocation.fromGeoPoint(value);
1626
+ return `${latitude},${longitude}`;
1627
+ }
1628
+ return String(value);
1629
+ }
1456
1630
  default: {
1457
1631
  if (value === null || value === "undefined") {
1458
1632
  return "";
@@ -1464,10 +1638,10 @@ var formatForDisplay = ({ type, format, value, locale = void 0 }) => {
1464
1638
  var formatForEditing = ({ type, format, value, locale = void 0 }) => {
1465
1639
  const formatScalar = (type2) => {
1466
1640
  switch (type2) {
1467
- case import_echo_schema9.TypeEnum.Boolean:
1468
- case import_echo_schema9.TypeEnum.Number:
1469
- case import_echo_schema9.TypeEnum.String:
1470
- case import_echo_schema9.TypeEnum.Ref:
1641
+ case import_echo_schema10.TypeEnum.Boolean:
1642
+ case import_echo_schema10.TypeEnum.Number:
1643
+ case import_echo_schema10.TypeEnum.String:
1644
+ case import_echo_schema10.TypeEnum.Ref:
1471
1645
  return String(value);
1472
1646
  default:
1473
1647
  return String(value);
@@ -1477,30 +1651,40 @@ var formatForEditing = ({ type, format, value, locale = void 0 }) => {
1477
1651
  return formatScalar(type);
1478
1652
  }
1479
1653
  switch (format) {
1480
- case import_echo_schema9.FormatEnum.Boolean:
1481
- case import_echo_schema9.FormatEnum.Number:
1482
- case import_echo_schema9.FormatEnum.String:
1483
- case import_echo_schema9.FormatEnum.Ref: {
1654
+ case import_echo_schema10.FormatEnum.Boolean:
1655
+ case import_echo_schema10.FormatEnum.Number:
1656
+ case import_echo_schema10.FormatEnum.String:
1657
+ case import_echo_schema10.FormatEnum.Ref: {
1484
1658
  return formatScalar(type);
1485
1659
  }
1486
- case import_echo_schema9.FormatEnum.Percent: {
1660
+ case import_echo_schema10.FormatEnum.Percent: {
1487
1661
  return String(value * 100);
1488
1662
  }
1489
- case import_echo_schema9.FormatEnum.Currency: {
1663
+ case import_echo_schema10.FormatEnum.Currency: {
1490
1664
  return String(value);
1491
1665
  }
1492
- case import_echo_schema9.FormatEnum.DateTime: {
1666
+ case import_echo_schema10.FormatEnum.DateTime: {
1493
1667
  const date = new Date(value);
1494
1668
  return date.toISOString();
1495
1669
  }
1496
- case import_echo_schema9.FormatEnum.Date: {
1670
+ case import_echo_schema10.FormatEnum.Date: {
1497
1671
  const date = new Date(value);
1498
1672
  return date.toISOString().split("T")[0];
1499
1673
  }
1500
- case import_echo_schema9.FormatEnum.Time: {
1674
+ case import_echo_schema10.FormatEnum.Time: {
1501
1675
  const date = new Date(value);
1502
1676
  return date.toISOString().split("T")[1].split(".")[0];
1503
1677
  }
1678
+ case import_echo_schema10.FormatEnum.GeoPoint: {
1679
+ if (value === null || value === void 0) {
1680
+ return "";
1681
+ }
1682
+ if (Array.isArray(value) && value.length >= 2 && value.every(Number.isFinite)) {
1683
+ const { latitude, longitude } = import_echo_schema10.GeoLocation.fromGeoPoint(value);
1684
+ return `${latitude},${longitude}`;
1685
+ }
1686
+ return String(value);
1687
+ }
1504
1688
  default: {
1505
1689
  return String(value);
1506
1690
  }
@@ -1515,6 +1699,7 @@ var formatForEditing = ({ type, format, value, locale = void 0 }) => {
1515
1699
  Form,
1516
1700
  GeoPointInput,
1517
1701
  InputHeader,
1702
+ MarkdownInput,
1518
1703
  NumberInput,
1519
1704
  SelectInput,
1520
1705
  SelectOptionInput,