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