@dxos/react-ui-form 0.8.4-main.dedc0f3 → 0.8.4-main.e8ec1fe

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 (89) hide show
  1. package/dist/lib/browser/index.mjs +480 -300
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node-esm/index.mjs +480 -300
  5. package/dist/lib/node-esm/index.mjs.map +4 -4
  6. package/dist/lib/node-esm/meta.json +1 -1
  7. package/dist/types/src/components/ControlSection/ControlSection.stories.d.ts +5 -5
  8. package/dist/types/src/components/ControlSection/ControlSection.stories.d.ts.map +1 -1
  9. package/dist/types/src/components/FieldEditor/FieldEditor.d.ts.map +1 -1
  10. package/dist/types/src/components/FieldEditor/FieldEditor.stories.d.ts +5 -5
  11. package/dist/types/src/components/FieldEditor/FieldEditor.stories.d.ts.map +1 -1
  12. package/dist/types/src/components/Form/ArrayField.d.ts.map +1 -1
  13. package/dist/types/src/components/Form/Form.d.ts +4 -3
  14. package/dist/types/src/components/Form/Form.d.ts.map +1 -1
  15. package/dist/types/src/components/Form/Form.stories.d.ts +15 -15
  16. package/dist/types/src/components/Form/Form.stories.d.ts.map +1 -1
  17. package/dist/types/src/components/Form/FormContent.d.ts +5 -5
  18. package/dist/types/src/components/Form/FormContent.d.ts.map +1 -1
  19. package/dist/types/src/components/Form/FormContext.d.ts +2 -2
  20. package/dist/types/src/components/Form/FormContext.d.ts.map +1 -1
  21. package/dist/types/src/components/Form/Input.d.ts +1 -1
  22. package/dist/types/src/components/Form/Input.d.ts.map +1 -1
  23. package/dist/types/src/components/Form/RefField.d.ts +10 -6
  24. package/dist/types/src/components/Form/RefField.d.ts.map +1 -1
  25. package/dist/types/src/components/Form/custom/SelectOptionsInput.stories.d.ts +5 -5
  26. package/dist/types/src/components/Form/custom/SelectOptionsInput.stories.d.ts.map +1 -1
  27. package/dist/types/src/components/Form/factory.d.ts +1 -1
  28. package/dist/types/src/components/Form/factory.d.ts.map +1 -1
  29. package/dist/types/src/components/ObjectPicker/ObjectPicker.d.ts +41 -0
  30. package/dist/types/src/components/ObjectPicker/ObjectPicker.d.ts.map +1 -0
  31. package/dist/types/src/components/ObjectPicker/ObjectPicker.stories.d.ts +81 -0
  32. package/dist/types/src/components/ObjectPicker/ObjectPicker.stories.d.ts.map +1 -0
  33. package/dist/types/src/components/ObjectPicker/index.d.ts +2 -0
  34. package/dist/types/src/components/ObjectPicker/index.d.ts.map +1 -0
  35. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts +20 -7
  36. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts.map +1 -1
  37. package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts +10 -10
  38. package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts.map +1 -1
  39. package/dist/types/src/components/index.d.ts +1 -0
  40. package/dist/types/src/components/index.d.ts.map +1 -1
  41. package/dist/types/src/hooks/useForm.d.ts +2 -2
  42. package/dist/types/src/hooks/useForm.d.ts.map +1 -1
  43. package/dist/types/src/hooks/useQueryRefOptions.d.ts +9 -3
  44. package/dist/types/src/hooks/useQueryRefOptions.d.ts.map +1 -1
  45. package/dist/types/src/hooks/useRefQueryLookupHandler.d.ts.map +1 -1
  46. package/dist/types/src/translations.d.ts +4 -4
  47. package/dist/types/src/util/field.d.ts +1 -1
  48. package/dist/types/src/util/field.d.ts.map +1 -1
  49. package/dist/types/src/util/formatting.d.ts +1 -1
  50. package/dist/types/src/util/formatting.d.ts.map +1 -1
  51. package/dist/types/src/util/refs.d.ts +1 -1
  52. package/dist/types/src/util/refs.d.ts.map +1 -1
  53. package/dist/types/src/util/schema.d.ts +1 -1
  54. package/dist/types/src/util/schema.d.ts.map +1 -1
  55. package/dist/types/tsconfig.tsbuildinfo +1 -1
  56. package/package.json +40 -39
  57. package/src/components/ControlSection/ControlSection.stories.tsx +4 -5
  58. package/src/components/ControlSection/ControlSection.tsx +1 -1
  59. package/src/components/FieldEditor/FieldEditor.stories.tsx +6 -5
  60. package/src/components/FieldEditor/FieldEditor.tsx +5 -2
  61. package/src/components/Form/ArrayField.tsx +4 -3
  62. package/src/components/Form/Defaults.tsx +1 -1
  63. package/src/components/Form/Form.stories.tsx +35 -35
  64. package/src/components/Form/Form.tsx +16 -6
  65. package/src/components/Form/FormActions.tsx +2 -2
  66. package/src/components/Form/FormContent.tsx +82 -22
  67. package/src/components/Form/FormContext.tsx +3 -3
  68. package/src/components/Form/Input.tsx +1 -1
  69. package/src/components/Form/RefField.tsx +48 -64
  70. package/src/components/Form/custom/GeoPointInput.tsx +1 -1
  71. package/src/components/Form/custom/SelectOptionsInput.stories.tsx +5 -6
  72. package/src/components/Form/custom/SelectOptionsInput.tsx +2 -2
  73. package/src/components/Form/factory.tsx +1 -1
  74. package/src/components/ObjectPicker/ObjectPicker.stories.tsx +207 -0
  75. package/src/components/ObjectPicker/ObjectPicker.tsx +161 -0
  76. package/src/components/ObjectPicker/index.ts +5 -0
  77. package/src/components/ViewEditor/ViewEditor.stories.tsx +107 -59
  78. package/src/components/ViewEditor/ViewEditor.test.tsx +6 -5
  79. package/src/components/ViewEditor/ViewEditor.tsx +275 -231
  80. package/src/components/index.ts +1 -0
  81. package/src/components/testing.tsx +2 -2
  82. package/src/hooks/useForm.ts +7 -4
  83. package/src/hooks/useQueryRefOptions.ts +15 -6
  84. package/src/hooks/useRefQueryLookupHandler.ts +3 -3
  85. package/src/translations.ts +4 -4
  86. package/src/util/field.ts +1 -1
  87. package/src/util/formatting.ts +1 -1
  88. package/src/util/refs.ts +7 -7
  89. package/src/util/schema.ts +2 -4
@@ -10,7 +10,7 @@ var translations = [
10
10
  "hidden fields label": "Hidden Fields",
11
11
  "empty readonly ref field label": "(none)",
12
12
  // TODO(burdon): Standardize field/property.
13
- "button add property": "Add property",
13
+ "add property button": "Add property",
14
14
  "field property label": "Property",
15
15
  "field property placeholder": "Property name",
16
16
  "field format label": "Type",
@@ -23,11 +23,11 @@ var translations = [
23
23
  "show field label": "Show field",
24
24
  "hide field label": "Hide field",
25
25
  "delete field label": "Delete field",
26
+ "ref field combobox input placeholder": "Search\u2026",
26
27
  "ref field placeholder_one": "Select\u2026",
27
28
  "ref field placeholder_other": "Select items\u2026",
28
29
  // TODO(burdon): Factor out?
29
- "button cancel": "Cancel",
30
- "button save": "Save",
30
+ "save button": "Save",
31
31
  // FormatEnum
32
32
  "format boolean": "Boolean",
33
33
  "format currency": "Currency",
@@ -41,7 +41,7 @@ var translations = [
41
41
  "format hostname": "Hostname",
42
42
  "format integer": "Integer",
43
43
  "format json": "JSON",
44
- "format latlng": "Geopoint",
44
+ "format lnglat": "Geopoint",
45
45
  "format markdown": "Markdown",
46
46
  "format percent": "Percent",
47
47
  "format ref": "Reference",
@@ -84,7 +84,8 @@ var ControlPage = ({ children, classNames, ...props }) => {
84
84
  var _effect = _useSignals();
85
85
  try {
86
86
  return /* @__PURE__ */ React.createElement(StackItem.Content, {
87
- classNames: "block overflow-y-auto [--control-spacing:var(--dx-trimMd)]"
87
+ scrollable: true,
88
+ classNames: "[--control-spacing:var(--dx-trimMd)]"
88
89
  }, /* @__PURE__ */ React.createElement("div", {
89
90
  role: "none",
90
91
  className: mx("pli-cardSpacingInline pbe-trimLg", classNames),
@@ -214,17 +215,17 @@ var ControlFrameItem = ({ title, description, children }) => {
214
215
  };
215
216
 
216
217
  // src/components/FieldEditor/FieldEditor.tsx
217
- import { useSignals as _useSignals13 } from "@preact-signals/safe-react/tracking";
218
- import React13, { useCallback as useCallback9, useEffect as useEffect8, useMemo as useMemo7, useState as useState6 } from "react";
219
- import { FormatEnum as FormatEnum5, FormatEnums, formatToType } from "@dxos/echo-schema";
218
+ import { useSignals as _useSignals14 } from "@preact-signals/safe-react/tracking";
219
+ import React14, { useCallback as useCallback12, useEffect as useEffect8, useMemo as useMemo7, useState as useState6 } from "react";
220
+ import { FormatEnum as FormatEnum5, FormatEnums, formatToType } from "@dxos/echo/internal";
220
221
  import { log as log3 } from "@dxos/log";
221
- import { useAsyncEffect, useTranslation as useTranslation8 } from "@dxos/react-ui";
222
- import { getFormatSchema, getSchemaProperties as getSchemaProperties3, sortProperties } from "@dxos/schema";
222
+ import { useAsyncEffect, useTranslation as useTranslation9 } from "@dxos/react-ui";
223
+ import { formatToAdditionalPropertyAttributes, getFormatSchema, getSchemaProperties as getSchemaProperties3, sortProperties } from "@dxos/schema";
223
224
 
224
225
  // src/components/Form/custom/GeoPointInput.tsx
225
226
  import { useSignals as _useSignals3 } from "@preact-signals/safe-react/tracking";
226
227
  import React3, { useCallback, useEffect, useMemo, useState } from "react";
227
- import { GeoLocation } from "@dxos/echo-schema";
228
+ import { GeoLocation } from "@dxos/echo/internal";
228
229
  import { Input as Input3, useTranslation as useTranslation2 } from "@dxos/react-ui";
229
230
  import { safeParseFloat } from "@dxos/util";
230
231
 
@@ -472,7 +473,7 @@ var SelectOptionInput = ({ type, label, readonly, getStatus, getValue: getValue3
472
473
  readonly: !!readonly
473
474
  }, ({ items }) => /* @__PURE__ */ React4.createElement("div", {
474
475
  role: "list",
475
- className: "w-full overflow-auto"
476
+ className: "is-full overflow-auto"
476
477
  }, items?.map((item) => /* @__PURE__ */ React4.createElement("div", {
477
478
  key: item.id
478
479
  }, /* @__PURE__ */ React4.createElement(List.Item, {
@@ -637,7 +638,7 @@ var BooleanInput = ({ type, label, inputOnly, getStatus, getValue: getValue3, on
637
638
  }), readonly === "static" ? /* @__PURE__ */ React6.createElement("p", null, t(checked ? "boolean input true value" : "boolean input false value")) : /* @__PURE__ */ React6.createElement(Input6.Switch, {
638
639
  disabled: !!readonly,
639
640
  checked,
640
- onCheckedChange: (value) => onValueChange(type, value)
641
+ onCheckedChange: (value2) => onValueChange(type, value2)
641
642
  }), inputOnly && /* @__PURE__ */ React6.createElement(Input6.DescriptionAndValidation, null, error));
642
643
  } finally {
643
644
  _effect.f();
@@ -647,29 +648,29 @@ var SelectInput = ({ type, label, inputOnly, readonly, placeholder, options, get
647
648
  var _effect = _useSignals6();
648
649
  try {
649
650
  const { status, error } = getStatus();
650
- const value = getValue3();
651
- const handleValueChange = useCallback3((value2) => onValueChange(type, value2), [
651
+ const value2 = getValue3();
652
+ const handleValueChange = useCallback3((value3) => onValueChange(type, value3), [
652
653
  type,
653
654
  onValueChange
654
655
  ]);
655
- return readonly && !value ? null : /* @__PURE__ */ React6.createElement(Input6.Root, {
656
+ return readonly && !value2 ? null : /* @__PURE__ */ React6.createElement(Input6.Root, {
656
657
  validationValence: status
657
658
  }, !inputOnly && /* @__PURE__ */ React6.createElement(InputHeader, {
658
659
  error,
659
660
  label
660
- }), readonly === "static" ? /* @__PURE__ */ React6.createElement("p", null, options?.find(({ value: optionValue }) => optionValue === value)?.label ?? String(value)) : /* @__PURE__ */ React6.createElement(Select.Root, {
661
- value,
661
+ }), readonly === "static" ? /* @__PURE__ */ React6.createElement("p", null, options?.find(({ value: optionValue }) => optionValue === value2)?.label ?? String(value2)) : /* @__PURE__ */ React6.createElement(Select.Root, {
662
+ value: value2,
662
663
  onValueChange: handleValueChange
663
664
  }, /* @__PURE__ */ React6.createElement(Select.TriggerButton, {
664
665
  classNames: "is-full",
665
666
  disabled: !!readonly,
666
667
  placeholder
667
- }), /* @__PURE__ */ React6.createElement(Select.Portal, null, /* @__PURE__ */ React6.createElement(Select.Content, null, /* @__PURE__ */ React6.createElement(Select.Viewport, null, options?.map(({ value: value2, label: label2 }) => (
668
+ }), /* @__PURE__ */ React6.createElement(Select.Portal, null, /* @__PURE__ */ React6.createElement(Select.Content, null, /* @__PURE__ */ React6.createElement(Select.Viewport, null, options?.map(({ value: value3, label: label2 }) => (
668
669
  // NOTE: Numeric values are converted to and from strings.
669
670
  /* @__PURE__ */ React6.createElement(Select.Option, {
670
- key: String(value2),
671
- value: String(value2)
672
- }, label2 ?? String(value2))
671
+ key: String(value3),
672
+ value: String(value3)
673
+ }, label2 ?? String(value3))
673
674
  ))), /* @__PURE__ */ React6.createElement(Select.Arrow, null)))), inputOnly && /* @__PURE__ */ React6.createElement(Input6.DescriptionAndValidation, null, error));
674
675
  } finally {
675
676
  _effect.f();
@@ -708,7 +709,7 @@ var MarkdownInput = ({ type, label, inputOnly, readonly, placeholder, getStatus,
708
709
  disabled: !!readonly,
709
710
  placeholder,
710
711
  value: getValue3() ?? "",
711
- classNames: "min-bs-auto max-h-40 overflow-auto",
712
+ classNames: "min-bs-auto max-bs-40 overflow-auto",
712
713
  onChange: (event) => onValueChange(type, event.target.value),
713
714
  onBlur,
714
715
  style: {
@@ -722,9 +723,9 @@ var MarkdownInput = ({ type, label, inputOnly, readonly, placeholder, getStatus,
722
723
  };
723
724
 
724
725
  // src/components/Form/Form.tsx
725
- import { useSignals as _useSignals12 } from "@preact-signals/safe-react/tracking";
726
+ import { useSignals as _useSignals13 } from "@preact-signals/safe-react/tracking";
726
727
  import { useFocusFinders } from "@fluentui/react-tabster";
727
- import React12, { useEffect as useEffect7, useMemo as useMemo6, useRef as useRef3 } from "react";
728
+ import React13, { useCallback as useCallback11, useEffect as useEffect7, useRef as useRef3 } from "react";
728
729
  import { cardDialogOverflow, cardSpacing as cardSpacing2 } from "@dxos/react-ui-stack";
729
730
 
730
731
  // src/components/Form/FormActions.tsx
@@ -736,15 +737,15 @@ import { mx as mx4 } from "@dxos/react-ui-theme";
736
737
 
737
738
  // src/components/Form/FormContext.tsx
738
739
  import { useSignals as _useSignals7 } from "@preact-signals/safe-react/tracking";
739
- import React7, { createContext, useCallback as useCallback6, useContext, useEffect as useEffect6, useMemo as useMemo3 } from "react";
740
+ import React7, { createContext, useCallback as useCallback7, useContext, useEffect as useEffect6, useMemo as useMemo3 } from "react";
740
741
  import { raise } from "@dxos/debug";
741
- import { getValue as getValue2 } from "@dxos/echo-schema";
742
+ import { getValue as getValue2 } from "@dxos/echo/internal";
742
743
  import { createJsonPath as createJsonPath2 } from "@dxos/effect";
743
744
 
744
745
  // src/hooks/useForm.ts
745
- import { SchemaAST } from "effect";
746
+ import * as SchemaAST from "effect/SchemaAST";
746
747
  import { useCallback as useCallback4, useEffect as useEffect4, useMemo as useMemo2, useState as useState3 } from "react";
747
- import { getValue, setValue } from "@dxos/echo-schema";
748
+ import { getValue, setValue } from "@dxos/echo/internal";
748
749
  import { createJsonPath, fromEffectValidationPath } from "@dxos/effect";
749
750
  import { invariant } from "@dxos/invariant";
750
751
  import { log } from "@dxos/log";
@@ -753,7 +754,7 @@ var __dxlog_file = "/__w/dxos/dxos/packages/ui/react-ui-form/src/hooks/useForm.t
753
754
  var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, onSave }) => {
754
755
  invariant(SchemaAST.isTypeLiteral(schema.ast), void 0, {
755
756
  F: __dxlog_file,
756
- L: 95,
757
+ L: 96,
757
758
  S: void 0,
758
759
  A: [
759
760
  "SchemaAST.isTypeLiteral(schema.ast)",
@@ -847,17 +848,17 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
847
848
  }, [
848
849
  values
849
850
  ]);
850
- const onValueChange = useCallback4((path, type, value) => {
851
+ const onValueChange = useCallback4((path, type, value2) => {
851
852
  const jsonPath = createJsonPath(path);
852
- let parsedValue = value;
853
+ let parsedValue = value2;
853
854
  try {
854
855
  if (type === "number") {
855
- parsedValue = parseFloat(value) || 0;
856
+ parsedValue = parseFloat(value2) || 0;
856
857
  }
857
858
  } catch (err) {
858
859
  log.catch(err, void 0, {
859
860
  F: __dxlog_file,
860
- L: 215,
861
+ L: 217,
861
862
  S: void 0,
862
863
  C: (f, a) => f(...a)
863
864
  });
@@ -867,15 +868,16 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
867
868
  ...setValue(values, jsonPath, parsedValue)
868
869
  };
869
870
  setValues(newValues);
870
- setChanged((prev) => ({
871
- ...prev,
871
+ const newChanged = {
872
+ ...changed,
872
873
  [jsonPath]: true
873
- }));
874
+ };
875
+ setChanged(newChanged);
874
876
  onValuesChanged?.(newValues);
875
877
  const isValid = validate(newValues);
876
878
  if (isValid && onValid) {
877
879
  onValid(newValues, {
878
- changed
880
+ changed: newChanged
879
881
  });
880
882
  }
881
883
  }, [
@@ -925,10 +927,10 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
925
927
  onTouched
926
928
  ]);
927
929
  };
928
- var createKeySet = (obj, value) => {
930
+ var createKeySet = (obj, value2) => {
929
931
  invariant(obj, void 0, {
930
932
  F: __dxlog_file,
931
- L: 277,
933
+ L: 280,
932
934
  S: void 0,
933
935
  A: [
934
936
  "obj",
@@ -937,7 +939,7 @@ var createKeySet = (obj, value) => {
937
939
  });
938
940
  return Object.keys(obj).reduce((acc, key) => ({
939
941
  ...acc,
940
- [key]: value
942
+ [key]: value2
941
943
  }), {});
942
944
  };
943
945
  var flatMap = (errors) => {
@@ -952,7 +954,8 @@ var flatMap = (errors) => {
952
954
 
953
955
  // src/hooks/useRefQueryLookupHandler.ts
954
956
  import { useCallback as useCallback5 } from "react";
955
- import { getObjectDXN } from "@dxos/echo-schema";
957
+ import { Obj } from "@dxos/echo";
958
+ import { getObjectDXN } from "@dxos/echo/internal";
956
959
  import { Filter } from "@dxos/react-client/echo";
957
960
  import { isNonNullable } from "@dxos/util";
958
961
  var useRefQueryLookupHandler = ({ space }) => {
@@ -969,7 +972,7 @@ var useRefQueryLookupHandler = ({ space }) => {
969
972
  }
970
973
  const item = {
971
974
  dxn,
972
- label: object?.name ?? object?.id ?? ""
975
+ label: Obj.getLabel(object) ?? object?.id ?? ""
973
976
  };
974
977
  return item;
975
978
  }).filter(isNonNullable);
@@ -979,12 +982,14 @@ var useRefQueryLookupHandler = ({ space }) => {
979
982
  };
980
983
 
981
984
  // src/hooks/useQueryRefOptions.ts
982
- import { useEffect as useEffect5, useState as useState4 } from "react";
985
+ import { useCallback as useCallback6, useEffect as useEffect5, useState as useState4 } from "react";
983
986
  import { log as log2 } from "@dxos/log";
984
987
  var __dxlog_file2 = "/__w/dxos/dxos/packages/ui/react-ui-form/src/hooks/useQueryRefOptions.ts";
985
988
  var useQueryRefOptions = ({ refTypeInfo, onQueryRefOptions }) => {
986
989
  const [options, setOptions] = useState4([]);
987
990
  const [loading, setLoading] = useState4(false);
991
+ const [state, setState] = useState4({});
992
+ const update = useCallback6(() => setState({}), []);
988
993
  useEffect5(() => {
989
994
  if (!refTypeInfo || !onQueryRefOptions) {
990
995
  return;
@@ -1004,7 +1009,7 @@ var useQueryRefOptions = ({ refTypeInfo, onQueryRefOptions }) => {
1004
1009
  } catch (error) {
1005
1010
  log2.error("Failed to fetch ref options:", error, {
1006
1011
  F: __dxlog_file2,
1007
- L: 42,
1012
+ L: 51,
1008
1013
  S: void 0,
1009
1014
  C: (f, a) => f(...a)
1010
1015
  });
@@ -1016,10 +1021,12 @@ var useQueryRefOptions = ({ refTypeInfo, onQueryRefOptions }) => {
1016
1021
  void fetchOptions();
1017
1022
  }, [
1018
1023
  refTypeInfo,
1019
- onQueryRefOptions
1024
+ onQueryRefOptions,
1025
+ state
1020
1026
  ]);
1021
1027
  return {
1022
1028
  options,
1029
+ update,
1023
1030
  loading
1024
1031
  };
1025
1032
  };
@@ -1042,7 +1049,7 @@ var useInputProps = (path = []) => {
1042
1049
  return useMemo3(() => ({
1043
1050
  getStatus: () => getStatus(stablePath),
1044
1051
  getValue: () => getFormValue(stablePath),
1045
- onValueChange: (type, value) => onValueChange(stablePath, type, value),
1052
+ onValueChange: (type, value2) => onValueChange(stablePath, type, value2),
1046
1053
  onBlur: () => onTouched(stablePath)
1047
1054
  }), [
1048
1055
  getStatus,
@@ -1056,7 +1063,7 @@ var FormProvider = ({ children, formRef, autoSave, ...formOptions }) => {
1056
1063
  var _effect = _useSignals7();
1057
1064
  try {
1058
1065
  const form = useForm(formOptions);
1059
- const handleKeyDown = useCallback6((event) => {
1066
+ const handleKeyDown = useCallback7((event) => {
1060
1067
  const keyIsEnter = event.key === "Enter";
1061
1068
  const modifierUsed = event.ctrlKey || event.altKey || event.metaKey || event.shiftKey;
1062
1069
  const inputIsTextarea = event.target.tagName.toLowerCase() === "textarea";
@@ -1072,7 +1079,9 @@ var FormProvider = ({ children, formRef, autoSave, ...formOptions }) => {
1072
1079
  }
1073
1080
  }
1074
1081
  }, [
1075
- form,
1082
+ form.canSave,
1083
+ form.formIsValid,
1084
+ form.handleSave,
1076
1085
  autoSave
1077
1086
  ]);
1078
1087
  useEffect6(() => {
@@ -1109,14 +1118,14 @@ var FormActions = ({ readonly, onCancel, outerSpacing = true }) => {
1109
1118
  }, onCancel && !readonly && /* @__PURE__ */ React8.createElement(IconButton2, {
1110
1119
  "data-testid": "cancel-button",
1111
1120
  icon: "ph--x--regular",
1112
- label: t("button cancel"),
1121
+ label: t("cancel button"),
1113
1122
  onClick: onCancel
1114
1123
  }), handleSave && /* @__PURE__ */ React8.createElement(IconButton2, {
1115
1124
  type: "submit",
1116
1125
  "data-testid": "save-button",
1117
1126
  disabled: !canSave,
1118
1127
  icon: "ph--check--regular",
1119
- label: t("button save"),
1128
+ label: t("save button"),
1120
1129
  onClick: handleSave
1121
1130
  }));
1122
1131
  } finally {
@@ -1125,44 +1134,46 @@ var FormActions = ({ readonly, onCancel, outerSpacing = true }) => {
1125
1134
  };
1126
1135
 
1127
1136
  // src/components/Form/FormContent.tsx
1128
- import { useSignals as _useSignals11 } from "@preact-signals/safe-react/tracking";
1129
- import { Schema, SchemaAST as SchemaAST4, pipe as pipe2 } from "effect";
1130
- import { capitalize as capitalize2 } from "effect/String";
1131
- import React11, { forwardRef, useMemo as useMemo5 } from "react";
1137
+ import { useSignals as _useSignals12 } from "@preact-signals/safe-react/tracking";
1138
+ import * as Function2 from "effect/Function";
1139
+ import * as Schema from "effect/Schema";
1140
+ import * as SchemaAST4 from "effect/SchemaAST";
1141
+ import * as StringEffect from "effect/String";
1142
+ import React12, { Component, forwardRef as forwardRef2, useMemo as useMemo6 } from "react";
1132
1143
  import { createJsonPath as createJsonPath3, findNode as findNode3, getDiscriminatedType as getDiscriminatedType2, isDiscriminatedUnion as isDiscriminatedUnion2 } from "@dxos/effect";
1133
1144
  import { mx as mx6 } from "@dxos/react-ui-theme";
1134
1145
  import { getSchemaProperties as getSchemaProperties2 } from "@dxos/schema";
1135
- import { isNotFalsy } from "@dxos/util";
1146
+ import { isTruthy } from "@dxos/util";
1136
1147
 
1137
1148
  // src/util/field.ts
1138
- import { FormatEnum, GeoLocation as GeoLocation2, TypeEnum } from "@dxos/echo-schema";
1139
- var parseValue = ({ type, format, value }) => {
1140
- if (value === void 0 || value === null || value === "") {
1149
+ import { FormatEnum, GeoLocation as GeoLocation2, TypeEnum } from "@dxos/echo/internal";
1150
+ var parseValue = ({ type, format, value: value2 }) => {
1151
+ if (value2 === void 0 || value2 === null || value2 === "") {
1141
1152
  return void 0;
1142
1153
  }
1143
1154
  const parseScalar = (type2) => {
1144
1155
  switch (type2) {
1145
1156
  case TypeEnum.Boolean: {
1146
- if (typeof value === "string") {
1147
- const lowercaseValue = value.toLowerCase();
1157
+ if (typeof value2 === "string") {
1158
+ const lowercaseValue = value2.toLowerCase();
1148
1159
  if (lowercaseValue === "0" || lowercaseValue === "false") {
1149
1160
  return false;
1150
1161
  } else if (lowercaseValue === "1" || lowercaseValue === "true") {
1151
1162
  return true;
1152
1163
  }
1153
1164
  }
1154
- return Boolean(value);
1165
+ return Boolean(value2);
1155
1166
  }
1156
1167
  case TypeEnum.Number: {
1157
- const cleaned = typeof value === "string" ? value.replace(/[^0-9.-]+/g, "") : value;
1168
+ const cleaned = typeof value2 === "string" ? value2.replace(/[^0-9.-]+/g, "") : value2;
1158
1169
  const num = Number(cleaned);
1159
1170
  return Number.isNaN(num) ? null : num;
1160
1171
  }
1161
1172
  case TypeEnum.String:
1162
1173
  case TypeEnum.Ref:
1163
- return String(value);
1174
+ return String(value2);
1164
1175
  default: {
1165
- return value;
1176
+ return value2;
1166
1177
  }
1167
1178
  }
1168
1179
  };
@@ -1186,12 +1197,12 @@ var parseValue = ({ type, format, value }) => {
1186
1197
  case FormatEnum.Date:
1187
1198
  case FormatEnum.Time:
1188
1199
  case FormatEnum.Timestamp: {
1189
- const date = new Date(value);
1200
+ const date = new Date(value2);
1190
1201
  return isNaN(date.getTime()) ? null : date;
1191
1202
  }
1192
1203
  case FormatEnum.GeoPoint: {
1193
- if (typeof value === "string") {
1194
- const cleaned = value.replace(/[^0-9.,-]+/g, "");
1204
+ if (typeof value2 === "string") {
1205
+ const cleaned = value2.replace(/[^0-9.,-]+/g, "");
1195
1206
  const parts = cleaned.split(",");
1196
1207
  if (parts.length === 2) {
1197
1208
  const lat = parseFloat(parts[0]);
@@ -1210,7 +1221,7 @@ var parseValue = ({ type, format, value }) => {
1210
1221
  ];
1211
1222
  }
1212
1223
  default: {
1213
- return value;
1224
+ return value2;
1214
1225
  }
1215
1226
  }
1216
1227
  };
@@ -1257,19 +1268,19 @@ var pathNotUniqueError = (path) => ({
1257
1268
 
1258
1269
  // src/util/formatting.ts
1259
1270
  import { format as formatDate } from "date-fns/format";
1260
- import { FormatEnum as FormatEnum2, GeoLocation as GeoLocation3, TypeEnum as TypeEnum2 } from "@dxos/echo-schema";
1261
- var formatForDisplay = ({ type, format, value, locale = void 0 }) => {
1271
+ import { FormatEnum as FormatEnum2, GeoLocation as GeoLocation3, TypeEnum as TypeEnum2 } from "@dxos/echo/internal";
1272
+ var formatForDisplay = ({ type, format, value: value2, locale = void 0 }) => {
1262
1273
  const formatScalar = (type2) => {
1263
1274
  switch (type2) {
1264
1275
  case TypeEnum2.Boolean:
1265
- return value.toLocaleString().toUpperCase();
1276
+ return value2.toLocaleString().toUpperCase();
1266
1277
  case TypeEnum2.Number:
1267
- return value.toLocaleString(locale);
1278
+ return value2.toLocaleString(locale);
1268
1279
  case TypeEnum2.String:
1269
1280
  case TypeEnum2.Ref:
1270
- return String(value);
1281
+ return String(value2);
1271
1282
  default: {
1272
- return String(value);
1283
+ return String(value2);
1273
1284
  }
1274
1285
  }
1275
1286
  };
@@ -1288,10 +1299,10 @@ var formatForDisplay = ({ type, format, value, locale = void 0 }) => {
1288
1299
  return formatScalar(TypeEnum2.String);
1289
1300
  }
1290
1301
  case FormatEnum2.Percent: {
1291
- return `${value * 100}%`;
1302
+ return `${value2 * 100}%`;
1292
1303
  }
1293
1304
  case FormatEnum2.Currency: {
1294
- return value.toLocaleString(locale, {
1305
+ return value2.toLocaleString(locale, {
1295
1306
  style: "currency",
1296
1307
  currency: "USD",
1297
1308
  minimumFractionDigits: 2,
@@ -1300,53 +1311,53 @@ var formatForDisplay = ({ type, format, value, locale = void 0 }) => {
1300
1311
  }
1301
1312
  case FormatEnum2.Date: {
1302
1313
  try {
1303
- return formatDate(new Date(value), "yyyy-MM-dd");
1314
+ return formatDate(new Date(value2), "yyyy-MM-dd");
1304
1315
  } catch (error) {
1305
1316
  return "Invalid Date";
1306
1317
  }
1307
1318
  }
1308
1319
  case FormatEnum2.Time: {
1309
1320
  try {
1310
- return formatDate(new Date(value), "HH:mm:ss");
1321
+ return formatDate(new Date(value2), "HH:mm:ss");
1311
1322
  } catch (error) {
1312
1323
  return "Invalid Time";
1313
1324
  }
1314
1325
  }
1315
1326
  case FormatEnum2.DateTime: {
1316
1327
  try {
1317
- return formatDate(new Date(value), "yyyy-MM-dd HH:mm:ss");
1328
+ return formatDate(new Date(value2), "yyyy-MM-dd HH:mm:ss");
1318
1329
  } catch (error) {
1319
1330
  return "Invalid DateTime";
1320
1331
  }
1321
1332
  }
1322
1333
  case FormatEnum2.GeoPoint: {
1323
- if (value === null || value === void 0) {
1334
+ if (value2 === null || value2 === void 0) {
1324
1335
  return "";
1325
1336
  }
1326
- if (Array.isArray(value) && value.length >= 2 && value.every(Number.isFinite)) {
1327
- const { latitude, longitude } = GeoLocation3.fromGeoPoint(value);
1337
+ if (Array.isArray(value2) && value2.length >= 2 && value2.every(Number.isFinite)) {
1338
+ const { latitude, longitude } = GeoLocation3.fromGeoPoint(value2);
1328
1339
  return `${latitude},${longitude}`;
1329
1340
  }
1330
- return String(value);
1341
+ return String(value2);
1331
1342
  }
1332
1343
  default: {
1333
- if (value === null || value === "undefined") {
1344
+ if (value2 === null || value2 === "undefined") {
1334
1345
  return "";
1335
1346
  }
1336
- return String(value);
1347
+ return String(value2);
1337
1348
  }
1338
1349
  }
1339
1350
  };
1340
- var formatForEditing = ({ type, format, value, locale = void 0 }) => {
1351
+ var formatForEditing = ({ type, format, value: value2, locale = void 0 }) => {
1341
1352
  const formatScalar = (type2) => {
1342
1353
  switch (type2) {
1343
1354
  case TypeEnum2.Boolean:
1344
1355
  case TypeEnum2.Number:
1345
1356
  case TypeEnum2.String:
1346
1357
  case TypeEnum2.Ref:
1347
- return String(value);
1358
+ return String(value2);
1348
1359
  default:
1349
- return String(value);
1360
+ return String(value2);
1350
1361
  }
1351
1362
  };
1352
1363
  if (!format) {
@@ -1360,61 +1371,54 @@ var formatForEditing = ({ type, format, value, locale = void 0 }) => {
1360
1371
  return formatScalar(type);
1361
1372
  }
1362
1373
  case FormatEnum2.Percent: {
1363
- return String(value * 100);
1374
+ return String(value2 * 100);
1364
1375
  }
1365
1376
  case FormatEnum2.Currency: {
1366
- return String(value);
1377
+ return String(value2);
1367
1378
  }
1368
1379
  case FormatEnum2.DateTime: {
1369
- const date = new Date(value);
1380
+ const date = new Date(value2);
1370
1381
  return date.toISOString();
1371
1382
  }
1372
1383
  case FormatEnum2.Date: {
1373
- const date = new Date(value);
1384
+ const date = new Date(value2);
1374
1385
  return date.toISOString().split("T")[0];
1375
1386
  }
1376
1387
  case FormatEnum2.Time: {
1377
- const date = new Date(value);
1388
+ const date = new Date(value2);
1378
1389
  return date.toISOString().split("T")[1].split(".")[0];
1379
1390
  }
1380
1391
  case FormatEnum2.GeoPoint: {
1381
- if (value === null || value === void 0) {
1392
+ if (value2 === null || value2 === void 0) {
1382
1393
  return "";
1383
1394
  }
1384
- if (Array.isArray(value) && value.length >= 2 && value.every(Number.isFinite)) {
1385
- const { latitude, longitude } = GeoLocation3.fromGeoPoint(value);
1395
+ if (Array.isArray(value2) && value2.length >= 2 && value2.every(Number.isFinite)) {
1396
+ const { latitude, longitude } = GeoLocation3.fromGeoPoint(value2);
1386
1397
  return `${latitude},${longitude}`;
1387
1398
  }
1388
- return String(value);
1399
+ return String(value2);
1389
1400
  }
1390
1401
  default: {
1391
- return String(value);
1402
+ return String(value2);
1392
1403
  }
1393
1404
  }
1394
1405
  };
1395
1406
 
1396
1407
  // src/util/refs.ts
1397
- import { FormatEnum as FormatEnum3, ReferenceAnnotationId } from "@dxos/echo-schema";
1408
+ import { FormatEnum as FormatEnum3, ReferenceAnnotationId } from "@dxos/echo/internal";
1398
1409
  import { findAnnotation } from "@dxos/effect";
1399
1410
 
1400
1411
  // src/util/schema.ts
1401
- import { SchemaAST as SchemaAST2 } from "effect";
1412
+ import * as SchemaAST2 from "effect/SchemaAST";
1402
1413
  import { findNode } from "@dxos/effect";
1403
1414
  var findArrayElementType = (ast) => {
1404
1415
  const tupleType = findNode(ast, SchemaAST2.isTupleType);
1405
- const elementType = tupleType?.rest[0]?.type;
1406
- return elementType;
1416
+ return tupleType?.rest[0]?.type;
1407
1417
  };
1408
1418
 
1409
1419
  // src/util/refs.ts
1410
1420
  var getRefProps = (property) => {
1411
1421
  const { ast, format, array } = property;
1412
- if (format === FormatEnum3.Ref) {
1413
- return {
1414
- ast,
1415
- isArray: false
1416
- };
1417
- }
1418
1422
  if (array) {
1419
1423
  const elementType = findArrayElementType(ast);
1420
1424
  if (elementType) {
@@ -1427,14 +1431,21 @@ var getRefProps = (property) => {
1427
1431
  }
1428
1432
  }
1429
1433
  }
1434
+ if (format === FormatEnum3.Ref) {
1435
+ return {
1436
+ ast,
1437
+ isArray: false
1438
+ };
1439
+ }
1430
1440
  return void 0;
1431
1441
  };
1432
1442
 
1433
1443
  // src/components/Form/ArrayField.tsx
1434
1444
  import { useSignals as _useSignals9 } from "@preact-signals/safe-react/tracking";
1435
- import { SchemaAST as SchemaAST3, pipe } from "effect";
1436
- import { capitalize } from "effect/String";
1437
- import React9, { Fragment, useCallback as useCallback7 } from "react";
1445
+ import * as Function from "effect/Function";
1446
+ import * as SchemaAST3 from "effect/SchemaAST";
1447
+ import * as String2 from "effect/String";
1448
+ import React9, { Fragment, useCallback as useCallback8 } from "react";
1438
1449
  import { SimpleType, findNode as findNode2, getDiscriminatedType, isDiscriminatedUnion } from "@dxos/effect";
1439
1450
  import { invariant as invariant2 } from "@dxos/invariant";
1440
1451
  import { IconButton as IconButton3, useTranslation as useTranslation6 } from "@dxos/react-ui";
@@ -1448,14 +1459,14 @@ var ArrayField = ({ property, readonly, path, inputProps, Custom, lookupComponen
1448
1459
  const values = useFormValues(path ?? []) ?? [];
1449
1460
  invariant2(Array.isArray(values), `Values at path ${path?.join(".")} must be an array.`, {
1450
1461
  F: __dxlog_file3,
1451
- L: 36,
1462
+ L: 37,
1452
1463
  S: void 0,
1453
1464
  A: [
1454
1465
  "Array.isArray(values)",
1455
1466
  "`Values at path ${path?.join('.')} must be an array.`"
1456
1467
  ]
1457
1468
  });
1458
- const label = title ?? pipe(name, capitalize);
1469
+ const label = title ?? Function.pipe(name, String2.capitalize);
1459
1470
  const elementType = findArrayElementType(ast);
1460
1471
  const getDefaultObjectValue = (typeNode) => {
1461
1472
  const baseNode = findNode2(typeNode, isDiscriminatedUnion);
@@ -1469,7 +1480,7 @@ var ArrayField = ({ property, readonly, path, inputProps, Custom, lookupComponen
1469
1480
  ]));
1470
1481
  };
1471
1482
  const getDefaultValue = () => type === "object" && elementType ? getDefaultObjectValue(elementType) : SimpleType.getDefaultValue(type);
1472
- const handleAdd = useCallback7(() => {
1483
+ const handleAdd = useCallback8(() => {
1473
1484
  inputProps.onValueChange(type, [
1474
1485
  ...values,
1475
1486
  getDefaultValue()
@@ -1480,7 +1491,7 @@ var ArrayField = ({ property, readonly, path, inputProps, Custom, lookupComponen
1480
1491
  inputProps,
1481
1492
  values
1482
1493
  ]);
1483
- const handleRemove = useCallback7((index) => {
1494
+ const handleRemove = useCallback8((index) => {
1484
1495
  const newValues = values.filter((_, i) => i !== index);
1485
1496
  inputProps.onValueChange(type, newValues);
1486
1497
  }, [
@@ -1536,7 +1547,7 @@ var ArrayField = ({ property, readonly, path, inputProps, Custom, lookupComponen
1536
1547
  };
1537
1548
 
1538
1549
  // src/components/Form/factory.tsx
1539
- import { FormatEnum as FormatEnum4 } from "@dxos/echo-schema";
1550
+ import { FormatEnum as FormatEnum4 } from "@dxos/echo/internal";
1540
1551
  var getInputComponent = (type, format) => {
1541
1552
  switch (format) {
1542
1553
  case FormatEnum4.GeoPoint:
@@ -1555,33 +1566,129 @@ var getInputComponent = (type, format) => {
1555
1566
  };
1556
1567
 
1557
1568
  // src/components/Form/RefField.tsx
1558
- import { useSignals as _useSignals10 } from "@preact-signals/safe-react/tracking";
1559
- import React10, { useCallback as useCallback8, useMemo as useMemo4, useState as useState5 } from "react";
1560
- import { Expando, Ref, ReferenceAnnotationId as ReferenceAnnotationId2, getTypeAnnotation } from "@dxos/echo-schema";
1569
+ import { useSignals as _useSignals11 } from "@preact-signals/safe-react/tracking";
1570
+ import "@dxos/lit-ui/dx-tag-picker.pcss";
1571
+ import React11, { useCallback as useCallback10, useMemo as useMemo5 } from "react";
1572
+ import { Expando, Ref, ReferenceAnnotationId as ReferenceAnnotationId2, getTypeAnnotation } from "@dxos/echo/internal";
1561
1573
  import { findAnnotation as findAnnotation2 } from "@dxos/effect";
1562
1574
  import { DXN } from "@dxos/keys";
1563
- import { DxAnchor } from "@dxos/lit-ui/react";
1564
- import { Button as Button2, Icon as Icon2, Input as Input7, useTranslation as useTranslation7 } from "@dxos/react-ui";
1565
- import { PopoverCombobox } from "@dxos/react-ui-searchlist";
1566
- import { TagPickerItem } from "@dxos/react-ui-tag-picker";
1575
+ import { DxAnchor, DxTagPickerItem } from "@dxos/lit-ui/react";
1576
+ import { Button as Button2, Icon as Icon3, Input as Input7, useTranslation as useTranslation8 } from "@dxos/react-ui";
1567
1577
  import { descriptionText, mx as mx5 } from "@dxos/react-ui-theme";
1568
1578
  import { isNonNullable as isNonNullable2 } from "@dxos/util";
1579
+
1580
+ // src/components/ObjectPicker/ObjectPicker.tsx
1581
+ import { useSignals as _useSignals10 } from "@preact-signals/safe-react/tracking";
1582
+ import React10, { forwardRef, useCallback as useCallback9, useMemo as useMemo4, useState as useState5 } from "react";
1583
+ import { Icon as Icon2, Popover, useTranslation as useTranslation7 } from "@dxos/react-ui";
1584
+ import { Combobox } from "@dxos/react-ui-searchlist";
1585
+ var ObjectPickerContent = /* @__PURE__ */ forwardRef(({ options, selectedIds, createSchema, createOptionLabel, createOptionIcon, createInitialValuePath, onSelect, onCreate, ...props }, ref) => {
1586
+ var _effect = _useSignals10();
1587
+ try {
1588
+ const { t } = useTranslation7(translationKey);
1589
+ const [searchString, setSearchString] = useState5("");
1590
+ const [showForm, setShowForm] = useState5(false);
1591
+ const handleFormSave = useCallback9((values) => {
1592
+ onCreate?.(values);
1593
+ setShowForm(false);
1594
+ setSearchString("");
1595
+ }, [
1596
+ onCreate
1597
+ ]);
1598
+ const handleFormCancel = useCallback9(() => {
1599
+ setShowForm(false);
1600
+ setSearchString("");
1601
+ }, []);
1602
+ const handleClick = useCallback9((event) => {
1603
+ if (createSchema && event.target.closest('[data-value="__create__"]')) {
1604
+ event.stopPropagation();
1605
+ event.preventDefault();
1606
+ setShowForm(true);
1607
+ }
1608
+ }, [
1609
+ createSchema
1610
+ ]);
1611
+ const handleKeyDown = useCallback9((event) => {
1612
+ if (event.key === "Enter" && createSchema && event.currentTarget.querySelector('[role="option"][aria-selected="true"][data-value="__create__"]')) {
1613
+ event.stopPropagation();
1614
+ event.preventDefault();
1615
+ setShowForm(true);
1616
+ }
1617
+ }, [
1618
+ createSchema
1619
+ ]);
1620
+ const labelById = useMemo4(() => options.reduce((acc, option) => {
1621
+ acc[option.id.toLowerCase()] = option.label.toLowerCase();
1622
+ return acc;
1623
+ }, {}), [
1624
+ options
1625
+ ]);
1626
+ return /* @__PURE__ */ React10.createElement(Combobox.Content, {
1627
+ ...props,
1628
+ ref,
1629
+ filter: (value2, search) => value2 === "__create__" || labelById[value2]?.includes(search.toLowerCase()) ? 1 : 0,
1630
+ onClickCapture: handleClick,
1631
+ onKeyDownCapture: handleKeyDown
1632
+ }, showForm && createSchema ? /* @__PURE__ */ React10.createElement(Popover.Viewport, null, /* @__PURE__ */ React10.createElement(Form, {
1633
+ schema: createSchema,
1634
+ values: createInitialValuePath ? {
1635
+ [createInitialValuePath]: searchString
1636
+ } : {},
1637
+ onSave: handleFormSave,
1638
+ onCancel: handleFormCancel,
1639
+ testId: "create-referenced-object-form"
1640
+ })) : /* @__PURE__ */ React10.createElement(React10.Fragment, null, /* @__PURE__ */ React10.createElement(Combobox.Input, {
1641
+ placeholder: t("ref field combobox input placeholder"),
1642
+ value: searchString,
1643
+ onValueChange: setSearchString,
1644
+ autoFocus: true
1645
+ }), /* @__PURE__ */ React10.createElement(Combobox.List, null, options.map((option) => /* @__PURE__ */ React10.createElement(Combobox.Item, {
1646
+ key: option.id,
1647
+ value: option.id,
1648
+ onSelect: () => onSelect(option.id),
1649
+ classNames: "flex items-center gap-2"
1650
+ }, /* @__PURE__ */ React10.createElement("span", {
1651
+ className: "grow"
1652
+ }, option.label), selectedIds?.includes(option.id) && /* @__PURE__ */ React10.createElement(Icon2, {
1653
+ icon: "ph--check--regular"
1654
+ }))), searchString.length > 0 && createOptionLabel && createOptionIcon && createSchema && onCreate && /* @__PURE__ */ React10.createElement(Combobox.Item, {
1655
+ value: "__create__",
1656
+ classNames: "flex items-center gap-2"
1657
+ }, /* @__PURE__ */ React10.createElement(Icon2, {
1658
+ icon: createOptionIcon
1659
+ }), t(createOptionLabel[0], {
1660
+ ns: createOptionLabel[1].ns,
1661
+ text: searchString
1662
+ })))), /* @__PURE__ */ React10.createElement(Combobox.Arrow, null));
1663
+ } finally {
1664
+ _effect.f();
1665
+ }
1666
+ });
1667
+ ObjectPickerContent.displayName = "ObjectPickerContent";
1668
+ var ObjectPicker = {
1669
+ Root: Combobox.Root,
1670
+ Trigger: Combobox.Trigger,
1671
+ VirtualTrigger: Combobox.VirtualTrigger,
1672
+ Content: ObjectPickerContent
1673
+ };
1674
+
1675
+ // src/components/Form/RefField.tsx
1569
1676
  var isRefSnapShot = (val) => {
1570
1677
  return typeof val === "object" && typeof val?.["/"] === "string";
1571
1678
  };
1572
- var RefField = ({ type, label, readonly, placeholder, inputOnly, array, ast, getValue: getValue3, onBlur, onQueryRefOptions, createOptionLabel, createOptionIcon, onCreateFromQuery, onValueChange, ...restInputProps }) => {
1573
- var _effect = _useSignals10();
1679
+ var RefField = ({ type, label, readonly, placeholder, inputOnly, array, ast, getValue: getValue3, createOptionLabel, createOptionIcon, onBlur, onCreate, createSchema, createInitialValuePath, onQueryRefOptions, onValueChange, ...restInputProps }) => {
1680
+ var _effect = _useSignals11();
1574
1681
  try {
1575
- const { t } = useTranslation7(translationKey);
1576
- const refTypeInfo = useMemo4(() => ast ? findAnnotation2(ast, ReferenceAnnotationId2) : void 0, [
1682
+ const { t } = useTranslation8(translationKey);
1683
+ const refTypeInfo = useMemo5(() => ast ? findAnnotation2(ast, ReferenceAnnotationId2) : void 0, [
1577
1684
  ast
1578
1685
  ]);
1579
- const { options: availableOptions, loading: _loading } = useQueryRefOptions({
1686
+ const { options: availableOptions, update: updateOptions, loading: _loading } = useQueryRefOptions({
1580
1687
  refTypeInfo,
1581
1688
  onQueryRefOptions
1582
1689
  });
1583
1690
  if (refTypeInfo && refTypeInfo?.typename === getTypeAnnotation(Expando)?.typename || !onQueryRefOptions) {
1584
- return /* @__PURE__ */ React10.createElement(RefFieldFallback, {
1691
+ return /* @__PURE__ */ React11.createElement(RefFieldFallback, {
1585
1692
  type,
1586
1693
  label,
1587
1694
  placeholder,
@@ -1593,7 +1700,7 @@ var RefField = ({ type, label, readonly, placeholder, inputOnly, array, ast, get
1593
1700
  ...restInputProps
1594
1701
  });
1595
1702
  }
1596
- const handleGetValue = useCallback8(() => {
1703
+ const handleGetValue = useCallback10(() => {
1597
1704
  const formValue = getValue3();
1598
1705
  const unknownToRefOption = (val) => {
1599
1706
  const isRef = Ref.isRef(val);
@@ -1621,7 +1728,7 @@ var RefField = ({ type, label, readonly, placeholder, inputOnly, array, ast, get
1621
1728
  availableOptions,
1622
1729
  array
1623
1730
  ]);
1624
- const handleUpdate = useCallback8((ids) => {
1731
+ const handleUpdate = useCallback10((ids) => {
1625
1732
  if (ids.length === 0) {
1626
1733
  onValueChange("object", void 0);
1627
1734
  return;
@@ -1644,22 +1751,22 @@ var RefField = ({ type, label, readonly, placeholder, inputOnly, array, ast, get
1644
1751
  array,
1645
1752
  onValueChange
1646
1753
  ]);
1754
+ const handleCreate = useCallback10((values) => {
1755
+ onCreate?.(values);
1756
+ updateOptions();
1757
+ }, [
1758
+ onCreate,
1759
+ updateOptions
1760
+ ]);
1647
1761
  if (!refTypeInfo) {
1648
1762
  return null;
1649
1763
  }
1650
1764
  const { status, error } = restInputProps.getStatus();
1651
1765
  const items = handleGetValue();
1652
- const selectedIds = useMemo4(() => items.map((i) => i.id), [
1766
+ const selectedIds = useMemo5(() => items.map((i) => i.id), [
1653
1767
  items
1654
1768
  ]);
1655
- const labelById = useMemo4(() => availableOptions.reduce((acc, option) => {
1656
- acc[option.id.toLowerCase()] = option.label.toLowerCase();
1657
- return acc;
1658
- }, {}), [
1659
- availableOptions
1660
- ]);
1661
- const [query, setQuery] = useState5("");
1662
- const toggleSelect = useCallback8((id) => {
1769
+ const toggleSelect = useCallback10((id) => {
1663
1770
  if (array) {
1664
1771
  const nextIds = selectedIds.includes(id) ? selectedIds.filter((x) => x !== id) : [
1665
1772
  ...selectedIds,
@@ -1680,28 +1787,28 @@ var RefField = ({ type, label, readonly, placeholder, inputOnly, array, ast, get
1680
1787
  selectedIds,
1681
1788
  handleUpdate
1682
1789
  ]);
1683
- return readonly && items.length < 1 ? null : /* @__PURE__ */ React10.createElement(Input7.Root, {
1790
+ return readonly && items.length < 1 ? null : /* @__PURE__ */ React11.createElement(Input7.Root, {
1684
1791
  validationValence: status
1685
- }, !inputOnly && /* @__PURE__ */ React10.createElement(InputHeader, {
1792
+ }, !inputOnly && /* @__PURE__ */ React11.createElement(InputHeader, {
1686
1793
  error,
1687
1794
  label
1688
- }), /* @__PURE__ */ React10.createElement("div", {
1795
+ }), /* @__PURE__ */ React11.createElement("div", {
1689
1796
  "data-no-submit": true
1690
- }, readonly ? items.length < 1 ? /* @__PURE__ */ React10.createElement("p", {
1797
+ }, readonly ? items.length < 1 ? /* @__PURE__ */ React11.createElement("p", {
1691
1798
  className: mx5(descriptionText, "mbe-2")
1692
- }, t("empty readonly ref field label")) : items.map((item) => /* @__PURE__ */ React10.createElement(DxAnchor, {
1799
+ }, t("empty readonly ref field label")) : items.map((item) => /* @__PURE__ */ React11.createElement(DxAnchor, {
1693
1800
  key: item.id,
1694
1801
  refid: item.id,
1695
1802
  rootclassname: "mie-1"
1696
- }, item.label)) : /* @__PURE__ */ React10.createElement(PopoverCombobox.Root, null, /* @__PURE__ */ React10.createElement(PopoverCombobox.Trigger, {
1803
+ }, item.label)) : /* @__PURE__ */ React11.createElement(ObjectPicker.Root, null, /* @__PURE__ */ React11.createElement(ObjectPicker.Trigger, {
1697
1804
  asChild: true
1698
- }, /* @__PURE__ */ React10.createElement(Button2, {
1805
+ }, /* @__PURE__ */ React11.createElement(Button2, {
1699
1806
  variant: "ghost",
1700
1807
  classNames: "is-full text-start gap-2"
1701
- }, /* @__PURE__ */ React10.createElement("div", {
1808
+ }, /* @__PURE__ */ React11.createElement("div", {
1702
1809
  role: "none",
1703
1810
  className: "grow"
1704
- }, items?.length ? items?.map((item) => /* @__PURE__ */ React10.createElement(TagPickerItem, {
1811
+ }, items?.length ? items?.map((item) => /* @__PURE__ */ React11.createElement(DxTagPickerItem, {
1705
1812
  key: item.id,
1706
1813
  itemId: item.id,
1707
1814
  label: item.label,
@@ -1714,45 +1821,29 @@ var RefField = ({ type, label, readonly, placeholder, inputOnly, array, ast, get
1714
1821
  toggleSelect(item.id);
1715
1822
  }
1716
1823
  }
1717
- })) : /* @__PURE__ */ React10.createElement("span", {
1824
+ })) : /* @__PURE__ */ React11.createElement("span", {
1718
1825
  className: "text-description"
1719
1826
  }, placeholder ?? t("ref field placeholder", {
1720
1827
  count: array ? 99 : 1
1721
- }))), /* @__PURE__ */ React10.createElement(Icon2, {
1828
+ }))), /* @__PURE__ */ React11.createElement(Icon3, {
1722
1829
  size: 3,
1723
1830
  icon: "ph--caret-down--bold"
1724
- }))), /* @__PURE__ */ React10.createElement(PopoverCombobox.Content, {
1725
- filter: (value, search) => value === "__create__" || labelById[value]?.includes(search.toLowerCase()) ? 1 : 0
1726
- }, /* @__PURE__ */ React10.createElement(PopoverCombobox.Input, {
1727
- placeholder: "Search...",
1728
- value: query,
1729
- onValueChange: (v) => setQuery(v),
1730
- autoFocus: true
1731
- }), /* @__PURE__ */ React10.createElement(PopoverCombobox.List, null, availableOptions.map((option) => /* @__PURE__ */ React10.createElement(PopoverCombobox.Item, {
1732
- key: option.id,
1733
- value: option.id,
1734
- onSelect: () => toggleSelect(option.id),
1735
- classNames: "flex items-center gap-2"
1736
- }, /* @__PURE__ */ React10.createElement("span", {
1737
- className: "grow"
1738
- }, option.label), selectedIds.includes(option.id) && /* @__PURE__ */ React10.createElement(Icon2, {
1739
- icon: "ph--check--regular"
1740
- }))), query.length > 0 && createOptionLabel && createOptionIcon && onCreateFromQuery && /* @__PURE__ */ React10.createElement(PopoverCombobox.Item, {
1741
- value: "__create__",
1742
- onSelect: () => onCreateFromQuery?.(refTypeInfo, query),
1743
- classNames: "flex items-center gap-2"
1744
- }, /* @__PURE__ */ React10.createElement(Icon2, {
1745
- icon: createOptionIcon
1746
- }), t(createOptionLabel[0], {
1747
- ns: createOptionLabel[1].ns,
1748
- text: query
1749
- }))), /* @__PURE__ */ React10.createElement(PopoverCombobox.Arrow, null)))), inputOnly && /* @__PURE__ */ React10.createElement(Input7.DescriptionAndValidation, null, error));
1831
+ }))), /* @__PURE__ */ React11.createElement(ObjectPicker.Content, {
1832
+ options: availableOptions,
1833
+ selectedIds,
1834
+ onSelect: toggleSelect,
1835
+ createSchema,
1836
+ createOptionLabel,
1837
+ createOptionIcon,
1838
+ createInitialValuePath,
1839
+ onCreate: handleCreate
1840
+ }))), inputOnly && /* @__PURE__ */ React11.createElement(Input7.DescriptionAndValidation, null, error));
1750
1841
  } finally {
1751
1842
  _effect.f();
1752
1843
  }
1753
1844
  };
1754
1845
  var RefFieldFallback = ({ type, label, readonly, placeholder, inputOnly, getValue: getValue3, onValueChange, ...restInputProps }) => {
1755
- var _effect = _useSignals10();
1846
+ var _effect = _useSignals11();
1756
1847
  try {
1757
1848
  const handleOnValueChange = (_type, dxnString) => {
1758
1849
  const dxn = DXN.tryParse(dxnString);
@@ -1774,7 +1865,7 @@ var RefFieldFallback = ({ type, label, readonly, placeholder, inputOnly, getValu
1774
1865
  }
1775
1866
  return void 0;
1776
1867
  };
1777
- return /* @__PURE__ */ React10.createElement(TextInput, {
1868
+ return /* @__PURE__ */ React11.createElement(TextInput, {
1778
1869
  type,
1779
1870
  label,
1780
1871
  readonly,
@@ -1790,16 +1881,16 @@ var RefFieldFallback = ({ type, label, readonly, placeholder, inputOnly, getValu
1790
1881
  };
1791
1882
 
1792
1883
  // src/components/Form/FormContent.tsx
1793
- var FormField = ({ property, path, readonly, inline, projection, onQueryRefOptions, createOptionLabel, createOptionIcon, onCreateFromQuery, lookupComponent, Custom }) => {
1794
- var _effect = _useSignals11();
1884
+ var FormField = ({ property, path, readonly, inline, projection, onQueryRefOptions, createOptionLabel, createOptionIcon, onCreate, createSchema, createInitialValuePath, lookupComponent, Custom }) => {
1885
+ var _effect = _useSignals12();
1795
1886
  try {
1796
1887
  const { ast, name, type, format, title, description, options, examples, array } = property;
1797
1888
  const inputProps = useInputProps(path);
1798
- const label = useMemo5(() => title ?? pipe2(name, capitalize2), [
1889
+ const label = useMemo6(() => title ?? Function2.pipe(name, StringEffect.capitalize), [
1799
1890
  title,
1800
1891
  name
1801
1892
  ]);
1802
- const placeholder = useMemo5(() => examples?.length ? `Example: "${examples[0]}"` : description, [
1893
+ const placeholder = useMemo6(() => examples?.length ? `Example: "${examples[0]}"` : description, [
1803
1894
  examples,
1804
1895
  description
1805
1896
  ]);
@@ -1821,7 +1912,7 @@ var FormField = ({ property, path, readonly, inline, projection, onQueryRefOptio
1821
1912
  const jsonPath = createJsonPath3(path ?? []);
1822
1913
  const CustomComponent = Custom?.[jsonPath];
1823
1914
  if (CustomComponent) {
1824
- return /* @__PURE__ */ React11.createElement(CustomComponent, {
1915
+ return /* @__PURE__ */ React12.createElement(CustomComponent, {
1825
1916
  type,
1826
1917
  format,
1827
1918
  label,
@@ -1833,7 +1924,7 @@ var FormField = ({ property, path, readonly, inline, projection, onQueryRefOptio
1833
1924
  }
1834
1925
  const refProps = getRefProps(property);
1835
1926
  if (refProps) {
1836
- return /* @__PURE__ */ React11.createElement(RefField, {
1927
+ return /* @__PURE__ */ React12.createElement(RefField, {
1837
1928
  ast: refProps.ast,
1838
1929
  array: refProps.isArray,
1839
1930
  type,
@@ -1845,12 +1936,14 @@ var FormField = ({ property, path, readonly, inline, projection, onQueryRefOptio
1845
1936
  onQueryRefOptions,
1846
1937
  createOptionLabel,
1847
1938
  createOptionIcon,
1848
- onCreateFromQuery,
1939
+ onCreate,
1940
+ createSchema,
1941
+ createInitialValuePath,
1849
1942
  ...inputProps
1850
1943
  });
1851
1944
  }
1852
1945
  if (array) {
1853
- return /* @__PURE__ */ React11.createElement(ArrayField, {
1946
+ return /* @__PURE__ */ React12.createElement(ArrayField, {
1854
1947
  property,
1855
1948
  path,
1856
1949
  inputProps,
@@ -1860,7 +1953,7 @@ var FormField = ({ property, path, readonly, inline, projection, onQueryRefOptio
1860
1953
  }
1861
1954
  const InputComponent = getInputComponent(type, format);
1862
1955
  if (InputComponent) {
1863
- return /* @__PURE__ */ React11.createElement(InputComponent, {
1956
+ return /* @__PURE__ */ React12.createElement(InputComponent, {
1864
1957
  type,
1865
1958
  format,
1866
1959
  label,
@@ -1871,7 +1964,7 @@ var FormField = ({ property, path, readonly, inline, projection, onQueryRefOptio
1871
1964
  });
1872
1965
  }
1873
1966
  if (options) {
1874
- return /* @__PURE__ */ React11.createElement(SelectInput, {
1967
+ return /* @__PURE__ */ React12.createElement(SelectInput, {
1875
1968
  type,
1876
1969
  format,
1877
1970
  readonly,
@@ -1889,9 +1982,9 @@ var FormField = ({ property, path, readonly, inline, projection, onQueryRefOptio
1889
1982
  const baseNode = findNode3(ast, isDiscriminatedUnion2);
1890
1983
  const typeLiteral = baseNode ? getDiscriminatedType2(baseNode, inputProps.getValue()) : findNode3(ast, SchemaAST4.isTypeLiteral);
1891
1984
  if (typeLiteral) {
1892
- return /* @__PURE__ */ React11.createElement(React11.Fragment, null, !inline && /* @__PURE__ */ React11.createElement("h3", {
1985
+ return /* @__PURE__ */ React12.createElement(React12.Fragment, null, !inline && /* @__PURE__ */ React12.createElement("h3", {
1893
1986
  className: mx6("text-lg mlb-inputSpacingBlock first:mbs-0")
1894
- }, label), /* @__PURE__ */ React11.createElement(FormFields, {
1987
+ }, label), /* @__PURE__ */ React12.createElement(FormFields, {
1895
1988
  schema: Schema.make(typeLiteral),
1896
1989
  path,
1897
1990
  readonly,
@@ -1899,7 +1992,7 @@ var FormField = ({ property, path, readonly, inline, projection, onQueryRefOptio
1899
1992
  onQueryRefOptions,
1900
1993
  createOptionLabel,
1901
1994
  createOptionIcon,
1902
- onCreateFromQuery,
1995
+ onCreate,
1903
1996
  Custom,
1904
1997
  lookupComponent
1905
1998
  }));
@@ -1910,11 +2003,11 @@ var FormField = ({ property, path, readonly, inline, projection, onQueryRefOptio
1910
2003
  _effect.f();
1911
2004
  }
1912
2005
  };
1913
- var FormFields = /* @__PURE__ */ forwardRef(({ classNames, schema, path, filter, sort, projection, readonly, lookupComponent, Custom, onQueryRefOptions, ...props }, forwardRef2) => {
1914
- var _effect = _useSignals11();
2006
+ var FormFields = /* @__PURE__ */ forwardRef2(({ classNames, schema, path, filter, sort, projection, readonly, lookupComponent, Custom, onQueryRefOptions, ...props }, forwardRef4) => {
2007
+ var _effect = _useSignals12();
1915
2008
  try {
1916
2009
  const values = useFormValues(path);
1917
- const properties = useMemo5(() => {
2010
+ const properties = useMemo6(() => {
1918
2011
  const props2 = getSchemaProperties2(schema.ast, values);
1919
2012
  if (projection) {
1920
2013
  const fieldProjections = projection.getFieldProjections();
@@ -1942,13 +2035,18 @@ var FormFields = /* @__PURE__ */ forwardRef(({ classNames, schema, path, filter,
1942
2035
  sort,
1943
2036
  projection?.fields
1944
2037
  ]);
1945
- return /* @__PURE__ */ React11.createElement("div", {
2038
+ return /* @__PURE__ */ React12.createElement("div", {
1946
2039
  role: "form",
1947
2040
  className: mx6("is-full", classNames),
1948
- ref: forwardRef2
2041
+ ref: forwardRef4
1949
2042
  }, properties.map((property) => {
1950
- return /* @__PURE__ */ React11.createElement(FormField, {
2043
+ return /* @__PURE__ */ React12.createElement(ErrorBoundary, {
1951
2044
  key: property.name,
2045
+ path: [
2046
+ ...path ?? [],
2047
+ property.name
2048
+ ]
2049
+ }, /* @__PURE__ */ React12.createElement(FormField, {
1952
2050
  property,
1953
2051
  path: [
1954
2052
  ...path ?? [],
@@ -1960,16 +2058,46 @@ var FormFields = /* @__PURE__ */ forwardRef(({ classNames, schema, path, filter,
1960
2058
  lookupComponent,
1961
2059
  Custom,
1962
2060
  ...props
1963
- });
1964
- }).filter(isNotFalsy));
2061
+ }));
2062
+ }).filter(isTruthy));
1965
2063
  } finally {
1966
2064
  _effect.f();
1967
2065
  }
1968
2066
  });
2067
+ var ErrorBoundary = class extends Component {
2068
+ static getDerivedStateFromError(error) {
2069
+ return {
2070
+ error
2071
+ };
2072
+ }
2073
+ state = {
2074
+ error: void 0
2075
+ };
2076
+ componentDidUpdate(prevProps) {
2077
+ if (prevProps.path !== this.props.path) {
2078
+ this.resetError();
2079
+ }
2080
+ }
2081
+ render() {
2082
+ if (this.state.error) {
2083
+ return /* @__PURE__ */ React12.createElement("div", {
2084
+ className: "flex gap-2 border border-roseFill font-mono text-sm"
2085
+ }, /* @__PURE__ */ React12.createElement("span", {
2086
+ className: "bg-roseFill text-surfaceText pli-1 font-thin"
2087
+ }, "ERROR"), String(this.props.path?.join(".")));
2088
+ }
2089
+ return this.props.children;
2090
+ }
2091
+ resetError() {
2092
+ this.setState({
2093
+ error: void 0
2094
+ });
2095
+ }
2096
+ };
1969
2097
 
1970
2098
  // src/components/Form/Form.tsx
1971
- var Form = ({ classNames, testId, values: initialValues, autoFocus, readonly, autoSave, outerSpacing = true, schema, onCancel, onValuesChanged, onValidate, onSave, ...props }) => {
1972
- var _effect = _useSignals12();
2099
+ var Form = ({ classNames, id, testId, values: initialValues, autoFocus, readonly, autoSave, outerSpacing = true, schema, onCancel, onValuesChanged, onValidate, onSave, ...props }) => {
2100
+ var _effect = _useSignals13();
1973
2101
  try {
1974
2102
  const formRef = useRef3(null);
1975
2103
  const { findFirstFocusable } = useFocusFinders();
@@ -1983,11 +2111,15 @@ var Form = ({ classNames, testId, values: initialValues, autoFocus, readonly, au
1983
2111
  }, [
1984
2112
  autoFocus
1985
2113
  ]);
1986
- const handleValid = useMemo6(() => autoSave ? onSave : void 0, [
2114
+ const handleValid = useCallback11(async (values, meta) => {
2115
+ if (autoSave) {
2116
+ await onSave?.(values, meta);
2117
+ }
2118
+ }, [
1987
2119
  autoSave,
1988
2120
  onSave
1989
2121
  ]);
1990
- return /* @__PURE__ */ React12.createElement(FormProvider, {
2122
+ return /* @__PURE__ */ React13.createElement(FormProvider, {
1991
2123
  formRef,
1992
2124
  schema,
1993
2125
  autoSave,
@@ -1996,11 +2128,14 @@ var Form = ({ classNames, testId, values: initialValues, autoFocus, readonly, au
1996
2128
  onValidate,
1997
2129
  onValid: handleValid,
1998
2130
  onSave
1999
- }, /* @__PURE__ */ React12.createElement("div", {
2131
+ }, /* @__PURE__ */ React13.createElement("div", {
2000
2132
  role: "none",
2001
2133
  className: "contents",
2134
+ ...id && {
2135
+ "data-object-id": id
2136
+ },
2002
2137
  "data-testid": testId
2003
- }, /* @__PURE__ */ React12.createElement(FormFields, {
2138
+ }, /* @__PURE__ */ React13.createElement(FormFields, {
2004
2139
  ...props,
2005
2140
  ref: formRef,
2006
2141
  classNames: [
@@ -2010,7 +2145,7 @@ var Form = ({ classNames, testId, values: initialValues, autoFocus, readonly, au
2010
2145
  ],
2011
2146
  readonly,
2012
2147
  schema
2013
- }), (onCancel || onSave) && !autoSave && !readonly && /* @__PURE__ */ React12.createElement(FormActions, {
2148
+ }), (onCancel || onSave) && !autoSave && !readonly && /* @__PURE__ */ React13.createElement(FormActions, {
2014
2149
  readonly,
2015
2150
  onCancel,
2016
2151
  outerSpacing
@@ -2023,9 +2158,9 @@ var Form = ({ classNames, testId, values: initialValues, autoFocus, readonly, au
2023
2158
  // src/components/FieldEditor/FieldEditor.tsx
2024
2159
  var __dxlog_file4 = "/__w/dxos/dxos/packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx";
2025
2160
  var FieldEditor = ({ readonly, projection, field, registry, onSave, onCancel, outerSpacing }) => {
2026
- var _effect = _useSignals13();
2161
+ var _effect = _useSignals14();
2027
2162
  try {
2028
- const { t } = useTranslation8(translationKey);
2163
+ const { t } = useTranslation9(translationKey);
2029
2164
  const [props, setProps] = useState6(projection.getFieldProjection(field.id).props);
2030
2165
  useEffect8(() => setProps(projection.getFieldProjection(field.id).props), [
2031
2166
  field,
@@ -2055,7 +2190,7 @@ var FieldEditor = ({ readonly, projection, field, registry, onSave, onCancel, ou
2055
2190
  const [{ fieldSchema }, setFieldSchema] = useState6({
2056
2191
  fieldSchema: getFormatSchema(props?.format)
2057
2192
  });
2058
- const handleValuesChanged = useCallback9((_props) => {
2193
+ const handleValuesChanged = useCallback12((_props) => {
2059
2194
  setFieldSchema((prev) => {
2060
2195
  const fieldSchema2 = getFormatSchema(_props.format);
2061
2196
  if (prev.fieldSchema === fieldSchema2) {
@@ -2076,10 +2211,12 @@ var FieldEditor = ({ readonly, projection, field, registry, onSave, onCancel, ou
2076
2211
  });
2077
2212
  setProps((props2) => {
2078
2213
  const type = formatToType[_props.format];
2214
+ const additionalProps = formatToAdditionalPropertyAttributes[_props.format];
2079
2215
  if (props2.type !== type) {
2080
2216
  return {
2081
2217
  ...props2,
2082
2218
  ..._props,
2219
+ ...additionalProps,
2083
2220
  type
2084
2221
  };
2085
2222
  }
@@ -2090,7 +2227,7 @@ var FieldEditor = ({ readonly, projection, field, registry, onSave, onCancel, ou
2090
2227
  props.format,
2091
2228
  props.referenceSchema
2092
2229
  ]);
2093
- const handleValidate = useCallback9(({ property }) => {
2230
+ const handleValidate = useCallback12(({ property }) => {
2094
2231
  if (property && projection.fields.find((f) => f.path === property && f.path !== field.path)) {
2095
2232
  return [
2096
2233
  {
@@ -2103,7 +2240,7 @@ var FieldEditor = ({ readonly, projection, field, registry, onSave, onCancel, ou
2103
2240
  projection.fields,
2104
2241
  field
2105
2242
  ]);
2106
- const handleSave = useCallback9((props2) => {
2243
+ const handleSave = useCallback12((props2) => {
2107
2244
  projection.setFieldProjection({
2108
2245
  field,
2109
2246
  props: props2
@@ -2114,51 +2251,51 @@ var FieldEditor = ({ readonly, projection, field, registry, onSave, onCancel, ou
2114
2251
  field,
2115
2252
  onSave
2116
2253
  ]);
2117
- const handleCancel = useCallback9(() => {
2254
+ const handleCancel = useCallback12(() => {
2118
2255
  requestAnimationFrame(() => onCancel?.());
2119
2256
  onSave();
2120
2257
  }, [
2121
2258
  onSave
2122
2259
  ]);
2123
2260
  const custom = useMemo7(() => ({
2124
- ["format"]: (props2) => /* @__PURE__ */ React13.createElement(SelectInput, {
2261
+ ["format"]: (props2) => /* @__PURE__ */ React14.createElement(SelectInput, {
2125
2262
  ...props2,
2126
- options: FormatEnums.filter((value) => value !== FormatEnum5.None).map((value) => ({
2127
- value,
2128
- label: t(`format ${value}`)
2263
+ options: FormatEnums.filter((value2) => value2 !== FormatEnum5.None).map((value2) => ({
2264
+ value: value2,
2265
+ label: t(`format ${value2}`)
2129
2266
  }))
2130
2267
  }),
2131
- ["referenceSchema"]: (props2) => /* @__PURE__ */ React13.createElement(SelectInput, {
2268
+ ["referenceSchema"]: (props2) => /* @__PURE__ */ React14.createElement(SelectInput, {
2132
2269
  ...props2,
2133
2270
  options: schemas.map((schema) => ({
2134
2271
  value: schema.typename
2135
2272
  }))
2136
2273
  }),
2137
- ["referencePath"]: (props2) => /* @__PURE__ */ React13.createElement(SelectInput, {
2274
+ ["referencePath"]: (props2) => /* @__PURE__ */ React14.createElement(SelectInput, {
2138
2275
  ...props2,
2139
2276
  options: referenceSchema ? getSchemaProperties3(referenceSchema.ast).sort(sortProperties).map((p) => ({
2140
2277
  value: p.name
2141
2278
  })) : []
2142
2279
  }),
2143
- ["options"]: (props2) => /* @__PURE__ */ React13.createElement(SelectOptionInput, props2)
2280
+ ["options"]: (props2) => /* @__PURE__ */ React14.createElement(SelectOptionInput, props2)
2144
2281
  }), [
2145
2282
  t,
2146
2283
  schemas,
2147
2284
  referenceSchema
2148
2285
  ]);
2149
- const propIsNotType = useCallback9((props2) => props2.filter((p) => p.name !== "type"), []);
2286
+ const propIsNotType = useCallback12((props2) => props2.filter((p) => p.name !== "type"), []);
2150
2287
  if (!fieldSchema) {
2151
2288
  log3.warn("invalid format", {
2152
2289
  props
2153
2290
  }, {
2154
2291
  F: __dxlog_file4,
2155
- L: 177,
2292
+ L: 180,
2156
2293
  S: void 0,
2157
2294
  C: (f, a) => f(...a)
2158
2295
  });
2159
2296
  return null;
2160
2297
  }
2161
- return /* @__PURE__ */ React13.createElement(Form, {
2298
+ return /* @__PURE__ */ React14.createElement(Form, {
2162
2299
  key: field.id,
2163
2300
  autoFocus: true,
2164
2301
  readonly,
@@ -2182,67 +2319,93 @@ var FieldEditor = ({ readonly, projection, field, registry, onSave, onCancel, ou
2182
2319
  };
2183
2320
 
2184
2321
  // src/components/ViewEditor/ViewEditor.tsx
2185
- import { useSignals as _useSignals14 } from "@preact-signals/safe-react/tracking";
2186
- import { Match, Schema as Schema2 } from "effect";
2187
- import React14, { useCallback as useCallback10, useMemo as useMemo8, useState as useState7 } from "react";
2188
- import { EchoSchema, Format, isMutable, toJsonSchema } from "@dxos/echo-schema";
2322
+ import { useSignals as _useSignals15 } from "@preact-signals/safe-react/tracking";
2323
+ import * as Array2 from "effect/Array";
2324
+ import * as Match from "effect/Match";
2325
+ import * as Option from "effect/Option";
2326
+ import * as Schema2 from "effect/Schema";
2327
+ import React15, { forwardRef as forwardRef3, useCallback as useCallback13, useImperativeHandle, useMemo as useMemo8, useState as useState7 } from "react";
2328
+ import { QueryAST } from "@dxos/echo";
2329
+ import { EchoSchema, Format, isMutable, toJsonSchema } from "@dxos/echo/internal";
2330
+ import { Filter as Filter2, Query } from "@dxos/echo-db";
2189
2331
  import { invariant as invariant3 } from "@dxos/invariant";
2190
- import { getSpace } from "@dxos/react-client/echo";
2191
- import { Callout, IconButton as IconButton4, useTranslation as useTranslation9 } from "@dxos/react-ui";
2192
- import { QueryEditor, QuerySerializer, createExpression } from "@dxos/react-ui-components";
2332
+ import { Callout, IconButton as IconButton4, Input as Input8, useTranslation as useTranslation10 } from "@dxos/react-ui";
2333
+ import { QueryForm } from "@dxos/react-ui-components";
2193
2334
  import { List as List2 } from "@dxos/react-ui-list";
2194
2335
  import { cardSpacing as cardSpacing3 } from "@dxos/react-ui-stack";
2195
2336
  import { inputTextLabel, mx as mx7, subtleHover as subtleHover2 } from "@dxos/react-ui-theme";
2196
- import { FieldSchema, ProjectionModel, VIEW_FIELD_LIMIT, typenameFromQuery } from "@dxos/schema";
2337
+ import { FieldSchema, ProjectionModel, VIEW_FIELD_LIMIT, getTypenameFromQuery } from "@dxos/schema";
2197
2338
  var __dxlog_file5 = "/__w/dxos/dxos/packages/ui/react-ui-form/src/components/ViewEditor/ViewEditor.tsx";
2198
2339
  var listGrid = "grid grid-cols-[min-content_1fr_min-content_min-content_min-content]";
2199
2340
  var listItemGrid = "grid grid-cols-subgrid col-span-5";
2200
- var ViewEditor = ({ classNames, schema, view, kind = "basic", registry, readonly, showHeading = false, onQueryChanged, onDelete, outerSpacing = true }) => {
2201
- var _effect = _useSignals14();
2341
+ var ViewEditor = /* @__PURE__ */ forwardRef3(({ classNames, schema, view, mode = "schema", registry, readonly, showHeading = false, types, tags, onQueryChanged, onDelete, outerSpacing = true }, forwardedRef) => {
2342
+ var _effect = _useSignals15();
2202
2343
  try {
2203
- const space = getSpace(view);
2204
2344
  const schemaReadonly = !isMutable(schema);
2205
- const { t } = useTranslation9(translationKey);
2345
+ const { t } = useTranslation10(translationKey);
2206
2346
  const projectionModel = useMemo8(() => {
2207
2347
  const jsonSchema = schema instanceof EchoSchema ? schema.jsonSchema : toJsonSchema(schema);
2208
2348
  return new ProjectionModel(jsonSchema, view.projection);
2209
2349
  }, [
2210
2350
  schema,
2211
- view.projection
2351
+ JSON.stringify(view.projection)
2352
+ ]);
2353
+ useImperativeHandle(forwardedRef, () => projectionModel, [
2354
+ projectionModel
2212
2355
  ]);
2213
2356
  const [expandedField, setExpandedField] = useState7();
2214
- const serializedQuery = Match.value(kind).pipe(Match.when("basic", () => typenameFromQuery(view.query)), Match.when("advanced", () => {
2215
- if (view.query.type !== "select") {
2216
- return "";
2217
- }
2218
- const serializer = new QuerySerializer();
2219
- return serializer.serialize(createExpression(view.query.filter));
2220
- }), Match.exhaustive);
2357
+ const queueTarget = Match.value(view.query.ast).pipe(Match.when({
2358
+ type: "options"
2359
+ }, ({ options }) => {
2360
+ return Option.fromNullable(options.queues).pipe(Option.flatMap((queues) => Array2.head(queues)), Option.getOrUndefined);
2361
+ }), Match.orElse(() => void 0));
2221
2362
  const viewSchema = useMemo8(() => {
2222
- return Schema2.Struct({
2223
- query: kind === "basic" ? Format.URL.annotations({
2363
+ const base = Schema2.Struct({
2364
+ query: mode === "schema" ? Format.URL.annotations({
2224
2365
  title: "Record type"
2225
- }) : Schema2.String.annotations({
2366
+ }) : QueryAST.Query.annotations({
2226
2367
  title: "Query"
2227
2368
  })
2228
- }).pipe(Schema2.mutable);
2369
+ });
2370
+ if (mode === "query" || mode === "named-query") {
2371
+ const name = Schema2.Struct({
2372
+ name: Schema2.optional(Schema2.String.annotations({
2373
+ title: "Name"
2374
+ }))
2375
+ });
2376
+ return Schema2.Struct({
2377
+ ...mode === "named-query" ? {
2378
+ ...name.fields,
2379
+ ...base.fields
2380
+ } : base.fields,
2381
+ target: Schema2.optional(Schema2.String.annotations({
2382
+ title: "Target Queue"
2383
+ }))
2384
+ }).pipe(Schema2.mutable);
2385
+ }
2386
+ return base.pipe(Schema2.mutable);
2229
2387
  }, [
2230
- kind
2388
+ mode
2231
2389
  ]);
2232
2390
  const viewValues = useMemo8(() => ({
2233
- query: serializedQuery
2391
+ name: view.name,
2392
+ query: mode === "schema" ? getTypenameFromQuery(view.query.ast) : view.query.ast,
2393
+ target: queueTarget
2234
2394
  }), [
2235
- serializedQuery
2395
+ view.name,
2396
+ mode,
2397
+ view.query.ast,
2398
+ queueTarget
2236
2399
  ]);
2237
- const handleToggleField = useCallback10((field) => {
2400
+ const handleToggleField = useCallback13((field) => {
2238
2401
  setExpandedField((prevExpandedFieldId) => prevExpandedFieldId === field.id ? void 0 : field.id);
2239
2402
  }, [
2240
2403
  readonly
2241
2404
  ]);
2242
- const handleAdd = useCallback10(() => {
2405
+ const handleAdd = useCallback13(() => {
2243
2406
  invariant3(!readonly, void 0, {
2244
2407
  F: __dxlog_file5,
2245
- L: 106,
2408
+ L: 134,
2246
2409
  S: void 0,
2247
2410
  A: [
2248
2411
  "!readonly",
@@ -2256,10 +2419,10 @@ var ViewEditor = ({ classNames, schema, view, kind = "basic", registry, readonly
2256
2419
  projectionModel,
2257
2420
  readonly
2258
2421
  ]);
2259
- const handleUpdate = useCallback10(({ query }) => {
2422
+ const handleUpdate = useCallback13((values) => {
2260
2423
  invariant3(!readonly, void 0, {
2261
2424
  F: __dxlog_file5,
2262
- L: 113,
2425
+ L: 141,
2263
2426
  S: void 0,
2264
2427
  A: [
2265
2428
  "!readonly",
@@ -2267,19 +2430,24 @@ var ViewEditor = ({ classNames, schema, view, kind = "basic", registry, readonly
2267
2430
  ]
2268
2431
  });
2269
2432
  requestAnimationFrame(() => {
2270
- if (serializedQuery !== query && !readonly) {
2271
- onQueryChanged?.(query);
2433
+ if ("name" in values && view.name !== values.name) {
2434
+ view.name = values.name;
2435
+ return;
2272
2436
  }
2437
+ const query = mode === "schema" ? Query.select(Filter2.typename(values.query)).ast : values.query;
2438
+ onQueryChanged?.(query, values.target);
2273
2439
  });
2274
2440
  }, [
2275
- serializedQuery,
2276
2441
  onQueryChanged,
2277
- readonly
2442
+ readonly,
2443
+ view,
2444
+ queueTarget,
2445
+ mode
2278
2446
  ]);
2279
- const handleDelete = useCallback10((fieldId) => {
2447
+ const handleDelete = useCallback13((fieldId) => {
2280
2448
  invariant3(!readonly, void 0, {
2281
2449
  F: __dxlog_file5,
2282
- L: 125,
2450
+ L: 157,
2283
2451
  S: void 0,
2284
2452
  A: [
2285
2453
  "!readonly",
@@ -2295,10 +2463,10 @@ var ViewEditor = ({ classNames, schema, view, kind = "basic", registry, readonly
2295
2463
  onDelete,
2296
2464
  readonly
2297
2465
  ]);
2298
- const handleMove = useCallback10((fromIndex, toIndex) => {
2466
+ const handleMove = useCallback13((fromIndex, toIndex) => {
2299
2467
  invariant3(!readonly, void 0, {
2300
2468
  F: __dxlog_file5,
2301
- L: 137,
2469
+ L: 169,
2302
2470
  S: void 0,
2303
2471
  A: [
2304
2472
  "!readonly",
@@ -2315,41 +2483,37 @@ var ViewEditor = ({ classNames, schema, view, kind = "basic", registry, readonly
2315
2483
  view.projection.fields,
2316
2484
  readonly
2317
2485
  ]);
2318
- const handleClose = useCallback10(() => setExpandedField(void 0), []);
2319
- const handleHide = useCallback10((fieldId) => {
2486
+ const handleClose = useCallback13(() => setExpandedField(void 0), []);
2487
+ const handleHide = useCallback13((fieldId) => {
2320
2488
  setExpandedField(void 0);
2321
2489
  projectionModel.hideFieldProjection(fieldId);
2322
2490
  }, [
2323
2491
  projectionModel
2324
2492
  ]);
2325
- const handleShow = useCallback10((property) => {
2493
+ const handleShow = useCallback13((property) => {
2326
2494
  setExpandedField(void 0);
2327
2495
  projectionModel.showFieldProjection(property);
2328
2496
  }, [
2329
2497
  projectionModel
2330
2498
  ]);
2331
- const custom = useMemo8(() => kind === "advanced" ? {
2332
- ["query"]: (props) => {
2333
- const handleChange = useCallback10((text) => props.onValueChange("string", text), [
2334
- props.onValueChange
2335
- ]);
2336
- return /* @__PURE__ */ React14.createElement(QueryEditor, {
2337
- space,
2338
- initialValue: props.getValue(),
2339
- onChange: handleChange
2340
- });
2341
- }
2342
- } : {}, []);
2343
- return /* @__PURE__ */ React14.createElement("div", {
2499
+ const custom = useMemo8(() => mode === "query" ? customFields({
2500
+ types,
2501
+ tags
2502
+ }) : void 0, [
2503
+ types,
2504
+ tags,
2505
+ mode
2506
+ ]);
2507
+ return /* @__PURE__ */ React15.createElement("div", {
2344
2508
  role: "none",
2345
2509
  className: mx7(classNames)
2346
- }, schemaReadonly && /* @__PURE__ */ React14.createElement(Callout.Root, {
2510
+ }, schemaReadonly && mode === "schema" && /* @__PURE__ */ React15.createElement(Callout.Root, {
2347
2511
  valence: "info",
2348
2512
  classNames: [
2349
2513
  "mlb-cardSpacingBlock",
2350
2514
  outerSpacing && "mli-cardSpacingInline"
2351
2515
  ]
2352
- }, /* @__PURE__ */ React14.createElement(Callout.Title, null, t("system schema description"))), /* @__PURE__ */ React14.createElement(Form, {
2516
+ }, /* @__PURE__ */ React15.createElement(Callout.Title, null, t("system schema description"))), /* @__PURE__ */ React15.createElement(Form, {
2353
2517
  autoSave: true,
2354
2518
  schema: viewSchema,
2355
2519
  values: viewValues,
@@ -2357,51 +2521,51 @@ var ViewEditor = ({ classNames, schema, view, kind = "basic", registry, readonly
2357
2521
  onSave: handleUpdate,
2358
2522
  outerSpacing,
2359
2523
  Custom: custom
2360
- }), /* @__PURE__ */ React14.createElement("div", {
2524
+ }), /* @__PURE__ */ React15.createElement("div", {
2361
2525
  role: "none",
2362
2526
  className: outerSpacing ? cardSpacing3 : "mlb-cardSpacingBlock"
2363
- }, /* @__PURE__ */ React14.createElement("h2", {
2527
+ }, /* @__PURE__ */ React15.createElement("h2", {
2364
2528
  className: mx7(inputTextLabel)
2365
- }, t("fields label")), /* @__PURE__ */ React14.createElement(List2.Root, {
2529
+ }, t("fields label")), /* @__PURE__ */ React15.createElement(List2.Root, {
2366
2530
  items: view.projection.fields,
2367
2531
  isItem: Schema2.is(FieldSchema),
2368
2532
  getId: (field) => field.id,
2369
2533
  onMove: readonly ? void 0 : handleMove,
2370
2534
  readonly
2371
- }, ({ items: fields }) => /* @__PURE__ */ React14.createElement(React14.Fragment, null, showHeading && /* @__PURE__ */ React14.createElement("h3", {
2535
+ }, ({ items: fields }) => /* @__PURE__ */ React15.createElement(React15.Fragment, null, showHeading && /* @__PURE__ */ React15.createElement("h3", {
2372
2536
  className: "text-sm"
2373
- }, t("field path label")), /* @__PURE__ */ React14.createElement("div", {
2537
+ }, t("field path label")), /* @__PURE__ */ React15.createElement("div", {
2374
2538
  role: "list",
2375
2539
  className: listGrid
2376
2540
  }, fields?.map((field) => {
2377
2541
  const hidden = field.visible === false;
2378
- return /* @__PURE__ */ React14.createElement(List2.Item, {
2542
+ return /* @__PURE__ */ React15.createElement(List2.Item, {
2379
2543
  key: field.id,
2380
2544
  item: field,
2381
2545
  classNames: listItemGrid,
2382
2546
  "aria-expanded": expandedField === field.id
2383
- }, /* @__PURE__ */ React14.createElement("div", {
2547
+ }, /* @__PURE__ */ React15.createElement("div", {
2384
2548
  role: "none",
2385
2549
  className: mx7(subtleHover2, listItemGrid, "rounded-sm cursor-pointer min-bs-10")
2386
- }, /* @__PURE__ */ React14.createElement(List2.ItemDragHandle, {
2550
+ }, /* @__PURE__ */ React15.createElement(List2.ItemDragHandle, {
2387
2551
  disabled: readonly
2388
- }), /* @__PURE__ */ React14.createElement(List2.ItemTitle, {
2552
+ }), /* @__PURE__ */ React15.createElement(List2.ItemTitle, {
2389
2553
  classNames: hidden && "text-subdued",
2390
2554
  onClick: () => handleToggleField(field)
2391
- }, field.path), /* @__PURE__ */ React14.createElement(List2.ItemButton, {
2555
+ }, field.path), /* @__PURE__ */ React15.createElement(List2.ItemButton, {
2392
2556
  label: t(hidden ? "show field label" : "hide field label"),
2393
2557
  "data-testid": hidden ? "show-field-button" : "hide-field-button",
2394
2558
  icon: hidden ? "ph--eye-closed--regular" : "ph--eye--regular",
2395
2559
  autoHide: false,
2396
2560
  disabled: readonly || !hidden && projectionModel.fields.length <= 1,
2397
2561
  onClick: () => hidden ? handleShow(field.path) : handleHide(field.id)
2398
- }), /* @__PURE__ */ React14.createElement(List2.ItemDeleteButton, {
2562
+ }), mode === "schema" && /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement(List2.ItemDeleteButton, {
2399
2563
  label: t("delete field label"),
2400
2564
  autoHide: false,
2401
2565
  disabled: readonly || schemaReadonly || view.projection.fields.length <= 1,
2402
2566
  onClick: () => handleDelete(field.id),
2403
2567
  "data-testid": "field.delete"
2404
- }), /* @__PURE__ */ React14.createElement(IconButton4, {
2568
+ }), /* @__PURE__ */ React15.createElement(IconButton4, {
2405
2569
  iconOnly: true,
2406
2570
  variant: "ghost",
2407
2571
  label: t("toggle expand label", {
@@ -2409,22 +2573,22 @@ var ViewEditor = ({ classNames, schema, view, kind = "basic", registry, readonly
2409
2573
  }),
2410
2574
  icon: expandedField === field.id ? "ph--caret-down--regular" : "ph--caret-right--regular",
2411
2575
  onClick: () => handleToggleField(field)
2412
- })), expandedField === field.id && /* @__PURE__ */ React14.createElement("div", {
2576
+ }))), expandedField === field.id && mode === "schema" && /* @__PURE__ */ React15.createElement("div", {
2413
2577
  role: "none",
2414
2578
  className: "col-span-5 mbs-1 mbe-1 border border-separator rounded-md"
2415
- }, /* @__PURE__ */ React14.createElement(FieldEditor, {
2579
+ }, /* @__PURE__ */ React15.createElement(FieldEditor, {
2416
2580
  readonly: readonly || schemaReadonly ? "disabled-input" : false,
2417
2581
  projection: projectionModel,
2418
2582
  field,
2419
2583
  registry,
2420
2584
  onSave: handleClose
2421
2585
  })));
2422
- }))))), !readonly && !expandedField && /* @__PURE__ */ React14.createElement("div", {
2586
+ }))))), !readonly && !expandedField && mode === "schema" && /* @__PURE__ */ React15.createElement("div", {
2423
2587
  role: "none",
2424
2588
  className: outerSpacing ? cardSpacing3 : "mlb-cardSpacingBlock"
2425
- }, /* @__PURE__ */ React14.createElement(IconButton4, {
2589
+ }, /* @__PURE__ */ React15.createElement(IconButton4, {
2426
2590
  icon: "ph--plus--regular",
2427
- label: t("button add property"),
2591
+ label: t("add property button"),
2428
2592
  onClick: readonly ? void 0 : handleAdd,
2429
2593
  // TODO(burdon): Show field limit in ux (not tooltip).
2430
2594
  disabled: view.projection.fields.length >= VIEW_FIELD_LIMIT,
@@ -2433,7 +2597,22 @@ var ViewEditor = ({ classNames, schema, view, kind = "basic", registry, readonly
2433
2597
  } finally {
2434
2598
  _effect.f();
2435
2599
  }
2436
- };
2600
+ });
2601
+ var customFields = ({ types, tags }) => ({
2602
+ query: (props) => {
2603
+ const handleChange = useCallback13((query) => props.onValueChange("object", query.ast), [
2604
+ props.onValueChange
2605
+ ]);
2606
+ return /* @__PURE__ */ React15.createElement(Input8.Root, null, /* @__PURE__ */ React15.createElement(InputHeader, {
2607
+ label: props.label
2608
+ }), /* @__PURE__ */ React15.createElement(QueryForm, {
2609
+ initialQuery: props.getValue(),
2610
+ types,
2611
+ tags,
2612
+ onChange: handleChange
2613
+ }));
2614
+ }
2615
+ });
2437
2616
  export {
2438
2617
  BooleanInput,
2439
2618
  ControlFrame,
@@ -2452,6 +2631,7 @@ export {
2452
2631
  InputHeader,
2453
2632
  MarkdownInput,
2454
2633
  NumberInput,
2634
+ ObjectPicker,
2455
2635
  SelectInput,
2456
2636
  SelectOptionInput,
2457
2637
  TextInput,