@dxos/react-ui-form 0.8.2-main.2f9c567 → 0.8.2-main.30e4dbb

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 (72) hide show
  1. package/dist/lib/browser/index.mjs +672 -543
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node/index.cjs +564 -442
  5. package/dist/lib/node/index.cjs.map +4 -4
  6. package/dist/lib/node/meta.json +1 -1
  7. package/dist/lib/node-esm/index.mjs +672 -543
  8. package/dist/lib/node-esm/index.mjs.map +4 -4
  9. package/dist/lib/node-esm/meta.json +1 -1
  10. package/dist/types/src/components/ControlSection/ControlSection.d.ts.map +1 -1
  11. package/dist/types/src/components/FieldEditor/FieldEditor.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/Defaults.d.ts.map +1 -1
  14. package/dist/types/src/components/Form/Form.d.ts +1 -2
  15. package/dist/types/src/components/Form/Form.d.ts.map +1 -1
  16. package/dist/types/src/components/Form/Form.stories.d.ts.map +1 -1
  17. package/dist/types/src/components/Form/FormActions.d.ts.map +1 -1
  18. package/dist/types/src/components/Form/FormContent.d.ts +1 -1
  19. package/dist/types/src/components/Form/FormContent.d.ts.map +1 -1
  20. package/dist/types/src/components/Form/FormContext.d.ts.map +1 -1
  21. package/dist/types/src/components/Form/Input.d.ts.map +1 -1
  22. package/dist/types/src/components/Form/RefField.d.ts +6 -18
  23. package/dist/types/src/components/Form/RefField.d.ts.map +1 -1
  24. package/dist/types/src/components/Form/custom/GeoPointInput.d.ts.map +1 -1
  25. package/dist/types/src/components/Form/custom/SelectOptionsInput.d.ts.map +1 -1
  26. package/dist/types/src/components/Form/custom/TupleInput.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/Form/index.d.ts +0 -1
  30. package/dist/types/src/components/Form/index.d.ts.map +1 -1
  31. package/dist/types/src/components/ViewEditor/Test.stories.d.ts.map +1 -1
  32. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts.map +1 -1
  33. package/dist/types/src/components/deprecated/Form.d.ts.map +1 -1
  34. package/dist/types/src/components/deprecated/Form.stories.d.ts.map +1 -1
  35. package/dist/types/src/components/deprecated/FormInput.d.ts.map +1 -1
  36. package/dist/types/src/components/testing.d.ts.map +1 -1
  37. package/dist/types/src/hooks/index.d.ts +1 -0
  38. package/dist/types/src/hooks/index.d.ts.map +1 -1
  39. package/dist/types/src/hooks/useForm.d.ts.map +1 -1
  40. package/dist/types/src/hooks/useQueryRefOptions.d.ts +23 -0
  41. package/dist/types/src/hooks/useQueryRefOptions.d.ts.map +1 -0
  42. package/dist/types/src/hooks/useRefQueryLookupHandler.d.ts +1 -1
  43. package/dist/types/src/hooks/useRefQueryLookupHandler.d.ts.map +1 -1
  44. package/dist/types/src/util/field.d.ts.map +1 -1
  45. package/dist/types/src/util/formatting.d.ts.map +1 -1
  46. package/dist/types/src/util/index.d.ts +2 -0
  47. package/dist/types/src/util/index.d.ts.map +1 -1
  48. package/dist/types/src/util/refs.d.ts +9 -0
  49. package/dist/types/src/util/refs.d.ts.map +1 -0
  50. package/dist/types/src/util/schema.d.ts +3 -0
  51. package/dist/types/src/util/schema.d.ts.map +1 -0
  52. package/dist/types/tsconfig.tsbuildinfo +1 -1
  53. package/package.json +25 -24
  54. package/src/components/ControlSection/ControlSection.stories.tsx +1 -1
  55. package/src/components/FieldEditor/FieldEditor.stories.tsx +1 -1
  56. package/src/components/Form/ArrayField.tsx +2 -2
  57. package/src/components/Form/Form.stories.tsx +2 -1
  58. package/src/components/Form/Form.tsx +1 -2
  59. package/src/components/Form/FormContent.tsx +44 -16
  60. package/src/components/Form/FormContext.tsx +3 -1
  61. package/src/components/Form/Input.tsx +3 -9
  62. package/src/components/Form/RefField.tsx +144 -99
  63. package/src/components/Form/custom/SelectOptionsInput.stories.tsx +1 -1
  64. package/src/components/Form/factory.tsx +1 -1
  65. package/src/components/Form/index.ts +0 -1
  66. package/src/components/ViewEditor/ViewEditor.stories.tsx +1 -1
  67. package/src/hooks/index.ts +2 -1
  68. package/src/hooks/useQueryRefOptions.ts +53 -0
  69. package/src/hooks/useRefQueryLookupHandler.ts +2 -4
  70. package/src/util/index.ts +3 -1
  71. package/src/util/refs.ts +38 -0
  72. package/src/util/schema.ts +14 -0
@@ -181,8 +181,8 @@ var ControlFrameItem = ({ title, description, children }) => {
181
181
  };
182
182
 
183
183
  // packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx
184
- import React14, { useCallback as useCallback7, useEffect as useEffect8, useMemo as useMemo7, useState as useState5 } from "react";
185
- import { FormatEnum as FormatEnum2, FormatEnums, formatToType } from "@dxos/echo-schema";
184
+ import React14, { useCallback as useCallback8, useEffect as useEffect8, useMemo as useMemo8, useState as useState5 } from "react";
185
+ import { FormatEnum as FormatEnum5, FormatEnums, formatToType } from "@dxos/echo-schema";
186
186
  import { log as log3 } from "@dxos/log";
187
187
  import { useTranslation as useTranslation6 } from "@dxos/react-ui";
188
188
  import { getFormatSchema, getSchemaProperties as getSchemaProperties3, sortProperties } from "@dxos/schema";
@@ -201,15 +201,15 @@ var InputHeader = ({ children, error }) => {
201
201
  return /* @__PURE__ */ React3.createElement("div", {
202
202
  role: "none",
203
203
  className: "flex justify-between items-center mb-1"
204
- }, children, error && /* @__PURE__ */ React3.createElement(Tooltip.Root, null, /* @__PURE__ */ React3.createElement(Tooltip.Trigger, {
205
- asChild: true
204
+ }, children, error && /* @__PURE__ */ React3.createElement(Tooltip.Trigger, {
205
+ asChild: true,
206
+ content: error,
207
+ side: "bottom"
206
208
  }, /* @__PURE__ */ React3.createElement(Icon, {
207
209
  icon: "ph--warning--regular",
208
210
  size: 4,
209
211
  classNames: errorText
210
- })), /* @__PURE__ */ React3.createElement(Tooltip.Content, {
211
- side: "bottom"
212
- }, /* @__PURE__ */ React3.createElement(Tooltip.Arrow, null), error)));
212
+ })));
213
213
  };
214
214
 
215
215
  // packages/ui/react-ui-form/src/components/Form/custom/GeoPointInput.tsx
@@ -611,7 +611,7 @@ var MarkdownInput = ({ type, label, inputOnly, disabled, placeholder, getStatus,
611
611
  };
612
612
 
613
613
  // packages/ui/react-ui-form/src/components/Form/Form.tsx
614
- import React13, { useEffect as useEffect7, useMemo as useMemo6, useRef as useRef3 } from "react";
614
+ import React13, { useEffect as useEffect7, useMemo as useMemo7, useRef as useRef3 } from "react";
615
615
  import { mx as mx8 } from "@dxos/react-ui-theme";
616
616
 
617
617
  // packages/ui/react-ui-form/src/components/Form/FormActions.tsx
@@ -620,7 +620,7 @@ import { IconButton as IconButton2, useTranslation as useTranslation4 } from "@d
620
620
  import { mx as mx5 } from "@dxos/react-ui-theme";
621
621
 
622
622
  // packages/ui/react-ui-form/src/components/Form/FormContext.tsx
623
- import React8, { createContext, useContext, useEffect as useEffect5, useMemo as useMemo3 } from "react";
623
+ import React8, { createContext, useContext, useEffect as useEffect6, useMemo as useMemo3 } from "react";
624
624
  import { raise } from "@dxos/debug";
625
625
  import { getValue as getValue2 } from "@dxos/echo-schema";
626
626
  import { createJsonPath as createJsonPath2 } from "@dxos/effect";
@@ -863,6 +863,52 @@ var useRefQueryLookupHandler = ({ space }) => {
863
863
  return handleRefQueryLookup;
864
864
  };
865
865
 
866
+ // packages/ui/react-ui-form/src/hooks/useQueryRefOptions.ts
867
+ import { useEffect as useEffect5, useState as useState4 } from "react";
868
+ import { log as log2 } from "@dxos/log";
869
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/hooks/useQueryRefOptions.ts";
870
+ var useQueryRefOptions = ({ refTypeInfo, onQueryRefOptions }) => {
871
+ const [options, setOptions] = useState4([]);
872
+ const [loading, setLoading] = useState4(false);
873
+ useEffect5(() => {
874
+ if (!refTypeInfo || !onQueryRefOptions) {
875
+ return;
876
+ }
877
+ const fetchOptions = async () => {
878
+ setLoading(true);
879
+ try {
880
+ const fetchedOptions = await onQueryRefOptions(refTypeInfo);
881
+ setOptions(fetchedOptions.map((option) => {
882
+ const dxn = option.dxn.toString();
883
+ return {
884
+ id: dxn,
885
+ label: option.label ?? dxn,
886
+ hue: "neutral"
887
+ };
888
+ }));
889
+ } catch (error) {
890
+ log2.error("Failed to fetch ref options:", error, {
891
+ F: __dxlog_file2,
892
+ L: 42,
893
+ S: void 0,
894
+ C: (f, a) => f(...a)
895
+ });
896
+ setOptions([]);
897
+ } finally {
898
+ setLoading(false);
899
+ }
900
+ };
901
+ void fetchOptions();
902
+ }, [
903
+ refTypeInfo,
904
+ onQueryRefOptions
905
+ ]);
906
+ return {
907
+ options,
908
+ loading
909
+ };
910
+ };
911
+
866
912
  // packages/ui/react-ui-form/src/components/Form/FormContext.tsx
867
913
  var FormContext = /* @__PURE__ */ createContext(void 0);
868
914
  var useFormContext = () => {
@@ -893,7 +939,7 @@ var useInputProps = (path = []) => {
893
939
  };
894
940
  var FormProvider = ({ children, formRef, autoSave, ...formOptions }) => {
895
941
  const form = useForm(formOptions);
896
- useEffect5(() => {
942
+ useEffect6(() => {
897
943
  if (!formRef?.current) {
898
944
  return;
899
945
  }
@@ -901,7 +947,7 @@ var FormProvider = ({ children, formRef, autoSave, ...formOptions }) => {
901
947
  const keyIsEnter = event.key === "Enter";
902
948
  const modifierUsed = event.ctrlKey || event.altKey || event.metaKey || event.shiftKey;
903
949
  const inputIsTextarea = event.target.tagName.toLowerCase() === "textarea";
904
- const inputOptOut = event.target.hasAttribute("data-no-submit");
950
+ const inputOptOut = event.target.hasAttribute("data-no-submit") || event.target.closest("[data-no-submit]") !== null;
905
951
  const shouldSubmitRegularInput = !inputIsTextarea && keyIsEnter && !modifierUsed;
906
952
  const shouldSubmitTextarea = inputIsTextarea && keyIsEnter && event.metaKey;
907
953
  if ((shouldSubmitRegularInput || shouldSubmitTextarea) && !inputOptOut) {
@@ -954,258 +1000,605 @@ var FormActions = ({ onCancel, readonly }) => {
954
1000
  };
955
1001
 
956
1002
  // packages/ui/react-ui-form/src/components/Form/FormContent.tsx
957
- import { Schema, SchemaAST as SchemaAST3, pipe as pipe2 } from "effect";
1003
+ import { Schema, SchemaAST as SchemaAST4, pipe as pipe2 } from "effect";
958
1004
  import { capitalize as capitalize2 } from "effect/String";
959
- import React12, { useMemo as useMemo5 } from "react";
960
- import { createJsonPath as createJsonPath3, findNode as findNode2, getDiscriminatedType as getDiscriminatedType2, isDiscriminatedUnion as isDiscriminatedUnion2 } from "@dxos/effect";
1005
+ import React12, { useMemo as useMemo6 } from "react";
1006
+ import { createJsonPath as createJsonPath3, findNode as findNode3, getDiscriminatedType as getDiscriminatedType2, isDiscriminatedUnion as isDiscriminatedUnion2 } from "@dxos/effect";
961
1007
  import { mx as mx7 } from "@dxos/react-ui-theme";
962
1008
  import { getSchemaProperties as getSchemaProperties2 } from "@dxos/schema";
963
1009
  import { isNotFalsy } from "@dxos/util";
964
1010
 
965
1011
  // packages/ui/react-ui-form/src/components/Form/ArrayField.tsx
966
- import { SchemaAST as SchemaAST2, pipe } from "effect";
1012
+ import { SchemaAST as SchemaAST3, pipe } from "effect";
967
1013
  import { capitalize } from "effect/String";
968
1014
  import React10, { useCallback as useCallback6, useMemo as useMemo4 } from "react";
969
- import { findNode, getDiscriminatedType, isDiscriminatedUnion, SimpleType } from "@dxos/effect";
1015
+ import { findNode as findNode2, getDiscriminatedType, isDiscriminatedUnion, SimpleType } from "@dxos/effect";
970
1016
  import { invariant as invariant2 } from "@dxos/invariant";
971
1017
  import { IconButton as IconButton3, useTranslation as useTranslation5 } from "@dxos/react-ui";
972
1018
  import { mx as mx6 } from "@dxos/react-ui-theme";
973
1019
  import { getSchemaProperties } from "@dxos/schema";
974
- var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/Form/ArrayField.tsx";
975
- var padding = "px-2";
976
- var ArrayField = ({ property, readonly, path, inputProps, Custom, lookupComponent }) => {
977
- const { t } = useTranslation5(translationKey);
978
- const { ast, name, type, title } = property;
979
- const values = useFormValues(path ?? []) ?? [];
980
- invariant2(Array.isArray(values), `Values at path ${path?.join(".")} must be an array.`, {
981
- F: __dxlog_file2,
982
- L: 38,
983
- S: void 0,
984
- A: [
985
- "Array.isArray(values)",
986
- "`Values at path ${path?.join('.')} must be an array.`"
987
- ]
988
- });
989
- const label = title ?? pipe(name, capitalize);
990
- const tupleType = findNode(ast, SchemaAST2.isTupleType);
991
- const elementType = tupleType?.rest[0]?.type;
992
- const getDefaultObjectValue = (typeNode) => {
993
- const baseNode = findNode(typeNode, isDiscriminatedUnion);
994
- const typeLiteral = baseNode ? getDiscriminatedType(baseNode, {}) : findNode(typeNode, SchemaAST2.isTypeLiteral);
995
- if (!typeLiteral) {
996
- return {};
997
- }
998
- return Object.fromEntries(getSchemaProperties(typeLiteral, {}).map((prop) => [
999
- prop.name,
1000
- prop.defaultValue
1001
- ]));
1002
- };
1003
- const newValue = useMemo4(() => {
1004
- if (type === "object" && elementType) {
1005
- return getDefaultObjectValue(elementType);
1006
- } else {
1007
- return SimpleType.getDefaultValue(type);
1008
- }
1009
- }, [
1010
- type,
1011
- elementType
1012
- ]);
1013
- const handleAdd = useCallback6(() => {
1014
- inputProps.onValueChange(type, [
1015
- ...values,
1016
- newValue
1017
- ]);
1018
- }, [
1019
- type,
1020
- elementType,
1021
- inputProps,
1022
- newValue,
1023
- values
1024
- ]);
1025
- const handleRemove = useCallback6((index) => {
1026
- const newValues = values.filter((_, i) => i !== index);
1027
- inputProps.onValueChange(type, newValues);
1028
- }, [
1029
- type,
1030
- inputProps,
1031
- values
1032
- ]);
1033
- if (!elementType) {
1034
- return null;
1035
- }
1036
- return /* @__PURE__ */ React10.createElement("div", {
1037
- role: "none",
1038
- className: mx6(padding)
1039
- }, /* @__PURE__ */ React10.createElement(InputHeader, null, label), /* @__PURE__ */ React10.createElement("div", {
1040
- role: "none",
1041
- className: "flex flex-col gap-1"
1042
- }, values.map((_value, index) => /* @__PURE__ */ React10.createElement("div", {
1043
- key: index,
1044
- role: "none",
1045
- className: "flex items-center gap-1"
1046
- }, /* @__PURE__ */ React10.createElement("div", {
1047
- role: "none",
1048
- className: "flex-1"
1049
- }, /* @__PURE__ */ React10.createElement(FormField, {
1050
- property: {
1051
- ...property,
1052
- array: false,
1053
- ast: elementType
1054
- },
1055
- path: [
1056
- ...path ?? [],
1057
- index
1058
- ],
1059
- readonly,
1060
- inline: true,
1061
- Custom,
1062
- lookupComponent
1063
- })), /* @__PURE__ */ React10.createElement(IconButton3, {
1064
- icon: "ph--trash--regular",
1065
- iconOnly: true,
1066
- label: t("button remove"),
1067
- onClick: () => handleRemove(index)
1068
- })))), /* @__PURE__ */ React10.createElement("div", {
1069
- role: "none",
1070
- className: "flex justify-between items-center plb-1"
1071
- }, /* @__PURE__ */ React10.createElement(IconButton3, {
1072
- icon: "ph--plus--regular",
1073
- iconOnly: true,
1074
- label: t("button add"),
1075
- onClick: handleAdd
1076
- })));
1077
- };
1078
1020
 
1079
- // packages/ui/react-ui-form/src/components/Form/RefField.tsx
1080
- import React11, { useEffect as useEffect6, useState as useState4 } from "react";
1081
- import { Expando, getTypeAnnotation, Ref, ReferenceAnnotationId } from "@dxos/echo-schema";
1082
- import { findAnnotation } from "@dxos/effect";
1083
- import { DXN } from "@dxos/keys";
1084
- import { refFromDXN } from "@dxos/live-object";
1085
- import { log as log2 } from "@dxos/log";
1086
- var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/Form/RefField.tsx";
1087
- var RefField = ({ ast, type, label, readonly, placeholder, inline, onQueryRefOptions, inputProps }) => {
1088
- const { getValue: getValue3, onValueChange, ...restInputProps } = inputProps;
1089
- const refTypeInfo = findAnnotation(ast, ReferenceAnnotationId);
1090
- const [refOptions, setRefOptions] = useState4([]);
1091
- const [loading, setLoading] = useState4(false);
1092
- useEffect6(() => {
1093
- if (!refTypeInfo || !onQueryRefOptions) {
1094
- return;
1095
- }
1096
- const fetchOptions = async () => {
1097
- setLoading(true);
1098
- try {
1099
- const options = await onQueryRefOptions(refTypeInfo);
1100
- setRefOptions(options.map((option) => ({
1101
- label: option.label,
1102
- value: option.dxn.toString()
1103
- })));
1104
- } catch (error) {
1105
- log2.error("Failed to fetch ref options:", error, {
1106
- F: __dxlog_file3,
1107
- L: 69,
1108
- S: void 0,
1109
- C: (f, a) => f(...a)
1110
- });
1111
- setRefOptions([]);
1112
- } finally {
1113
- setLoading(false);
1114
- }
1115
- };
1116
- void fetchOptions();
1117
- }, [
1118
- refTypeInfo,
1119
- onQueryRefOptions
1120
- ]);
1121
- if (!refTypeInfo) {
1122
- return null;
1021
+ // packages/ui/react-ui-form/src/util/field.ts
1022
+ import { FormatEnum, GeoLocation as GeoLocation2, TypeEnum } from "@dxos/echo-schema";
1023
+ var parseValue = ({ type, format, value }) => {
1024
+ if (value === void 0 || value === null || value === "") {
1025
+ return void 0;
1123
1026
  }
1124
- if (refTypeInfo.typename === getTypeAnnotation(Expando)?.typename || !onQueryRefOptions) {
1125
- const handleOnValueChange = (_type, dxnString) => {
1126
- const dxn = DXN.tryParse(dxnString);
1127
- if (dxn) {
1128
- onValueChange?.("object", refFromDXN(dxn));
1129
- } else if (dxnString === "") {
1130
- onValueChange?.("object", void 0);
1131
- } else {
1132
- onValueChange?.("string", dxnString);
1027
+ const parseScalar = (type2) => {
1028
+ switch (type2) {
1029
+ case TypeEnum.Boolean: {
1030
+ if (typeof value === "string") {
1031
+ const lowercaseValue = value.toLowerCase();
1032
+ if (lowercaseValue === "0" || lowercaseValue === "false") {
1033
+ return false;
1034
+ } else if (lowercaseValue === "1" || lowercaseValue === "true") {
1035
+ return true;
1036
+ }
1037
+ }
1038
+ return Boolean(value);
1133
1039
  }
1134
- };
1135
- const handleGetValue2 = () => {
1136
- const formValue = getValue3();
1137
- if (typeof formValue === "string") {
1138
- return formValue;
1040
+ case TypeEnum.Number: {
1041
+ const cleaned = typeof value === "string" ? value.replace(/[^0-9.-]+/g, "") : value;
1042
+ const num = Number(cleaned);
1043
+ return Number.isNaN(num) ? null : num;
1139
1044
  }
1140
- if (Ref.isRef(formValue)) {
1141
- return formValue.dxn.toString();
1045
+ case TypeEnum.String:
1046
+ case TypeEnum.Ref:
1047
+ return String(value);
1048
+ default: {
1049
+ return value;
1142
1050
  }
1143
- return void 0;
1144
- };
1145
- return /* @__PURE__ */ React11.createElement(TextInput, {
1146
- type,
1147
- label,
1148
- disabled: readonly,
1149
- placeholder,
1150
- inputOnly: inline,
1151
- getValue: handleGetValue2,
1152
- onValueChange: handleOnValueChange,
1153
- ...restInputProps
1154
- });
1155
- }
1156
- const handleGetValue = () => {
1157
- const formValue = getValue3();
1158
- if (Ref.isRef(formValue)) {
1159
- return formValue.dxn.toString();
1160
1051
  }
1161
- return void 0;
1162
1052
  };
1163
- const handleValueChanged = (_type, dxnString) => {
1164
- const dxn = DXN.parse(dxnString);
1165
- const ref = refFromDXN(dxn);
1166
- onValueChange("object", ref);
1167
- };
1168
- return /* @__PURE__ */ React11.createElement(SelectInput, {
1169
- type,
1170
- label,
1171
- disabled: readonly || loading,
1172
- placeholder: loading ? "Loading options..." : placeholder,
1173
- inputOnly: inline,
1174
- getValue: handleGetValue,
1175
- onValueChange: handleValueChanged,
1176
- options: refOptions,
1177
- ...restInputProps
1178
- });
1179
- };
1180
-
1181
- // packages/ui/react-ui-form/src/components/Form/factory.tsx
1182
- import { FormatEnum } from "@dxos/echo-schema";
1183
- var getInputComponent = (type, format) => {
1184
- switch (format) {
1185
- case FormatEnum.GeoPoint:
1186
- return GeoPointInput;
1187
- case FormatEnum.Markdown:
1188
- return MarkdownInput;
1053
+ if (!format) {
1054
+ return parseScalar(type);
1189
1055
  }
1190
- switch (type) {
1191
- case "string":
1192
- return TextInput;
1193
- case "number":
1194
- return NumberInput;
1195
- case "boolean":
1196
- return BooleanInput;
1056
+ switch (format) {
1057
+ case FormatEnum.Boolean:
1058
+ return parseScalar(TypeEnum.Boolean);
1059
+ case FormatEnum.Number:
1060
+ case FormatEnum.Percent:
1061
+ case FormatEnum.Currency:
1062
+ return parseScalar(TypeEnum.Number);
1063
+ case FormatEnum.String:
1064
+ case FormatEnum.Markdown: {
1065
+ return parseScalar(TypeEnum.String);
1066
+ }
1067
+ case FormatEnum.Ref:
1068
+ throw new Error(`unexpected format: ${FormatEnum.Ref}`);
1069
+ case FormatEnum.DateTime:
1070
+ case FormatEnum.Date:
1071
+ case FormatEnum.Time:
1072
+ case FormatEnum.Timestamp: {
1073
+ const date = new Date(value);
1074
+ return isNaN(date.getTime()) ? null : date;
1075
+ }
1076
+ case FormatEnum.GeoPoint: {
1077
+ if (typeof value === "string") {
1078
+ const cleaned = value.replace(/[^0-9.,-]+/g, "");
1079
+ const parts = cleaned.split(",");
1080
+ if (parts.length === 2) {
1081
+ const lat = parseFloat(parts[0]);
1082
+ const long = parseFloat(parts[1]);
1083
+ if (!isNaN(lat) && !isNaN(long)) {
1084
+ return GeoLocation2.toGeoPoint({
1085
+ latitude: lat,
1086
+ longitude: long
1087
+ });
1088
+ }
1089
+ }
1090
+ }
1091
+ return [
1092
+ 0,
1093
+ 0
1094
+ ];
1095
+ }
1096
+ default: {
1097
+ return value;
1098
+ }
1197
1099
  }
1198
1100
  };
1199
-
1200
- // packages/ui/react-ui-form/src/components/Form/FormContent.tsx
1201
- var FormField = ({ property, path, readonly, inline, onQueryRefOptions, lookupComponent, Custom }) => {
1101
+ var cellClassesForFieldType = ({ type, format }) => {
1102
+ if (!format) {
1103
+ switch (type) {
1104
+ case TypeEnum.Number:
1105
+ return [
1106
+ "text-right",
1107
+ "font-mono"
1108
+ ];
1109
+ case TypeEnum.Boolean:
1110
+ return [
1111
+ "text-right",
1112
+ "font-mono"
1113
+ ];
1114
+ case TypeEnum.String:
1115
+ return void 0;
1116
+ case TypeEnum.Ref:
1117
+ return void 0;
1118
+ default: {
1119
+ return void 0;
1120
+ }
1121
+ }
1122
+ }
1123
+ switch (format) {
1124
+ case FormatEnum.Markdown:
1125
+ return void 0;
1126
+ case FormatEnum.Time:
1127
+ case FormatEnum.Timestamp:
1128
+ case FormatEnum.DateTime:
1129
+ case FormatEnum.Date:
1130
+ case FormatEnum.Duration:
1131
+ return [
1132
+ "font-mono",
1133
+ "text-right"
1134
+ ];
1135
+ case FormatEnum.Currency:
1136
+ return [
1137
+ "text-right"
1138
+ ];
1139
+ case FormatEnum.JSON:
1140
+ case FormatEnum.DID:
1141
+ return [
1142
+ "font-mono"
1143
+ ];
1144
+ default:
1145
+ return void 0;
1146
+ }
1147
+ };
1148
+ var pathNotUniqueError = (path) => ({
1149
+ path: "path",
1150
+ message: `'${path}' is already present`
1151
+ });
1152
+
1153
+ // packages/ui/react-ui-form/src/util/formatting.ts
1154
+ import { format as formatDate } from "date-fns/format";
1155
+ import { FormatEnum as FormatEnum2, GeoLocation as GeoLocation3, TypeEnum as TypeEnum2 } from "@dxos/echo-schema";
1156
+ var formatForDisplay = ({ type, format, value, locale = void 0 }) => {
1157
+ const formatScalar = (type2) => {
1158
+ switch (type2) {
1159
+ case TypeEnum2.Boolean:
1160
+ return value.toLocaleString().toUpperCase();
1161
+ case TypeEnum2.Number:
1162
+ return value.toLocaleString(locale);
1163
+ case TypeEnum2.String:
1164
+ case TypeEnum2.Ref:
1165
+ return String(value);
1166
+ default: {
1167
+ return String(value);
1168
+ }
1169
+ }
1170
+ };
1171
+ if (!format) {
1172
+ return formatScalar(type);
1173
+ }
1174
+ switch (format) {
1175
+ case FormatEnum2.Boolean: {
1176
+ return formatScalar(TypeEnum2.Boolean);
1177
+ }
1178
+ case FormatEnum2.Number: {
1179
+ return formatScalar(TypeEnum2.Number);
1180
+ }
1181
+ case FormatEnum2.String:
1182
+ case FormatEnum2.Ref: {
1183
+ return formatScalar(TypeEnum2.String);
1184
+ }
1185
+ case FormatEnum2.Percent: {
1186
+ return `${value * 100}%`;
1187
+ }
1188
+ case FormatEnum2.Currency: {
1189
+ return value.toLocaleString(locale, {
1190
+ style: "currency",
1191
+ currency: "USD",
1192
+ minimumFractionDigits: 2,
1193
+ maximumFractionDigits: 2
1194
+ });
1195
+ }
1196
+ case FormatEnum2.Date: {
1197
+ try {
1198
+ return formatDate(new Date(value), "yyyy-MM-dd");
1199
+ } catch (error) {
1200
+ return "Invalid Date";
1201
+ }
1202
+ }
1203
+ case FormatEnum2.Time: {
1204
+ try {
1205
+ return formatDate(new Date(value), "HH:mm:ss");
1206
+ } catch (error) {
1207
+ return "Invalid Time";
1208
+ }
1209
+ }
1210
+ case FormatEnum2.DateTime: {
1211
+ try {
1212
+ return formatDate(new Date(value), "yyyy-MM-dd HH:mm:ss");
1213
+ } catch (error) {
1214
+ return "Invalid DateTime";
1215
+ }
1216
+ }
1217
+ case FormatEnum2.GeoPoint: {
1218
+ if (value === null || value === void 0) {
1219
+ return "";
1220
+ }
1221
+ if (Array.isArray(value) && value.length >= 2 && value.every(Number.isFinite)) {
1222
+ const { latitude, longitude } = GeoLocation3.fromGeoPoint(value);
1223
+ return `${latitude},${longitude}`;
1224
+ }
1225
+ return String(value);
1226
+ }
1227
+ default: {
1228
+ if (value === null || value === "undefined") {
1229
+ return "";
1230
+ }
1231
+ return String(value);
1232
+ }
1233
+ }
1234
+ };
1235
+ var formatForEditing = ({ type, format, value, locale = void 0 }) => {
1236
+ const formatScalar = (type2) => {
1237
+ switch (type2) {
1238
+ case TypeEnum2.Boolean:
1239
+ case TypeEnum2.Number:
1240
+ case TypeEnum2.String:
1241
+ case TypeEnum2.Ref:
1242
+ return String(value);
1243
+ default:
1244
+ return String(value);
1245
+ }
1246
+ };
1247
+ if (!format) {
1248
+ return formatScalar(type);
1249
+ }
1250
+ switch (format) {
1251
+ case FormatEnum2.Boolean:
1252
+ case FormatEnum2.Number:
1253
+ case FormatEnum2.String:
1254
+ case FormatEnum2.Ref: {
1255
+ return formatScalar(type);
1256
+ }
1257
+ case FormatEnum2.Percent: {
1258
+ return String(value * 100);
1259
+ }
1260
+ case FormatEnum2.Currency: {
1261
+ return String(value);
1262
+ }
1263
+ case FormatEnum2.DateTime: {
1264
+ const date = new Date(value);
1265
+ return date.toISOString();
1266
+ }
1267
+ case FormatEnum2.Date: {
1268
+ const date = new Date(value);
1269
+ return date.toISOString().split("T")[0];
1270
+ }
1271
+ case FormatEnum2.Time: {
1272
+ const date = new Date(value);
1273
+ return date.toISOString().split("T")[1].split(".")[0];
1274
+ }
1275
+ case FormatEnum2.GeoPoint: {
1276
+ if (value === null || value === void 0) {
1277
+ return "";
1278
+ }
1279
+ if (Array.isArray(value) && value.length >= 2 && value.every(Number.isFinite)) {
1280
+ const { latitude, longitude } = GeoLocation3.fromGeoPoint(value);
1281
+ return `${latitude},${longitude}`;
1282
+ }
1283
+ return String(value);
1284
+ }
1285
+ default: {
1286
+ return String(value);
1287
+ }
1288
+ }
1289
+ };
1290
+
1291
+ // packages/ui/react-ui-form/src/util/refs.ts
1292
+ import { FormatEnum as FormatEnum3, ReferenceAnnotationId } from "@dxos/echo-schema";
1293
+ import { findAnnotation } from "@dxos/effect";
1294
+
1295
+ // packages/ui/react-ui-form/src/util/schema.ts
1296
+ import { SchemaAST as SchemaAST2 } from "effect";
1297
+ import { findNode } from "@dxos/effect";
1298
+ var findArrayElementType = (ast) => {
1299
+ const tupleType = findNode(ast, SchemaAST2.isTupleType);
1300
+ const elementType = tupleType?.rest[0]?.type;
1301
+ return elementType;
1302
+ };
1303
+
1304
+ // packages/ui/react-ui-form/src/util/refs.ts
1305
+ var getRefProps = (property) => {
1306
+ const { ast, format, array } = property;
1307
+ if (format === FormatEnum3.Ref) {
1308
+ return {
1309
+ ast,
1310
+ isArray: false
1311
+ };
1312
+ }
1313
+ if (array) {
1314
+ const elementType = findArrayElementType(ast);
1315
+ if (elementType) {
1316
+ const annotation = findAnnotation(elementType, ReferenceAnnotationId);
1317
+ if (annotation) {
1318
+ return {
1319
+ ast: elementType,
1320
+ isArray: true
1321
+ };
1322
+ }
1323
+ }
1324
+ }
1325
+ return void 0;
1326
+ };
1327
+
1328
+ // packages/ui/react-ui-form/src/components/Form/ArrayField.tsx
1329
+ var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/Form/ArrayField.tsx";
1330
+ var padding = "px-2";
1331
+ var ArrayField = ({ property, readonly, path, inputProps, Custom, lookupComponent }) => {
1332
+ const { t } = useTranslation5(translationKey);
1333
+ const { ast, name, type, title } = property;
1334
+ const values = useFormValues(path ?? []) ?? [];
1335
+ invariant2(Array.isArray(values), `Values at path ${path?.join(".")} must be an array.`, {
1336
+ F: __dxlog_file3,
1337
+ L: 39,
1338
+ S: void 0,
1339
+ A: [
1340
+ "Array.isArray(values)",
1341
+ "`Values at path ${path?.join('.')} must be an array.`"
1342
+ ]
1343
+ });
1344
+ const label = title ?? pipe(name, capitalize);
1345
+ const elementType = findArrayElementType(ast);
1346
+ const getDefaultObjectValue = (typeNode) => {
1347
+ const baseNode = findNode2(typeNode, isDiscriminatedUnion);
1348
+ const typeLiteral = baseNode ? getDiscriminatedType(baseNode, {}) : findNode2(typeNode, SchemaAST3.isTypeLiteral);
1349
+ if (!typeLiteral) {
1350
+ return {};
1351
+ }
1352
+ return Object.fromEntries(getSchemaProperties(typeLiteral, {}).map((prop) => [
1353
+ prop.name,
1354
+ prop.defaultValue
1355
+ ]));
1356
+ };
1357
+ const newValue = useMemo4(() => {
1358
+ if (type === "object" && elementType) {
1359
+ return getDefaultObjectValue(elementType);
1360
+ } else {
1361
+ return SimpleType.getDefaultValue(type);
1362
+ }
1363
+ }, [
1364
+ type,
1365
+ elementType
1366
+ ]);
1367
+ const handleAdd = useCallback6(() => {
1368
+ inputProps.onValueChange(type, [
1369
+ ...values,
1370
+ newValue
1371
+ ]);
1372
+ }, [
1373
+ type,
1374
+ elementType,
1375
+ inputProps,
1376
+ newValue,
1377
+ values
1378
+ ]);
1379
+ const handleRemove = useCallback6((index) => {
1380
+ const newValues = values.filter((_, i) => i !== index);
1381
+ inputProps.onValueChange(type, newValues);
1382
+ }, [
1383
+ type,
1384
+ inputProps,
1385
+ values
1386
+ ]);
1387
+ if (!elementType) {
1388
+ return null;
1389
+ }
1390
+ return /* @__PURE__ */ React10.createElement("div", {
1391
+ role: "none",
1392
+ className: mx6(padding)
1393
+ }, /* @__PURE__ */ React10.createElement(InputHeader, null, label), /* @__PURE__ */ React10.createElement("div", {
1394
+ role: "none",
1395
+ className: "flex flex-col gap-1"
1396
+ }, values.map((_value, index) => /* @__PURE__ */ React10.createElement("div", {
1397
+ key: index,
1398
+ role: "none",
1399
+ className: "flex items-center gap-1"
1400
+ }, /* @__PURE__ */ React10.createElement("div", {
1401
+ role: "none",
1402
+ className: "flex-1"
1403
+ }, /* @__PURE__ */ React10.createElement(FormField, {
1404
+ property: {
1405
+ ...property,
1406
+ array: false,
1407
+ ast: elementType
1408
+ },
1409
+ path: [
1410
+ ...path ?? [],
1411
+ index
1412
+ ],
1413
+ readonly,
1414
+ inline: true,
1415
+ Custom,
1416
+ lookupComponent
1417
+ })), /* @__PURE__ */ React10.createElement(IconButton3, {
1418
+ icon: "ph--trash--regular",
1419
+ iconOnly: true,
1420
+ label: t("button remove"),
1421
+ onClick: () => handleRemove(index)
1422
+ })))), /* @__PURE__ */ React10.createElement("div", {
1423
+ role: "none",
1424
+ className: "flex justify-between items-center plb-1"
1425
+ }, /* @__PURE__ */ React10.createElement(IconButton3, {
1426
+ icon: "ph--plus--regular",
1427
+ iconOnly: true,
1428
+ label: t("button add"),
1429
+ onClick: handleAdd
1430
+ })));
1431
+ };
1432
+
1433
+ // packages/ui/react-ui-form/src/components/Form/RefField.tsx
1434
+ import React11, { useCallback as useCallback7, useMemo as useMemo5 } from "react";
1435
+ import { Expando, getTypeAnnotation, Ref, ReferenceAnnotationId as ReferenceAnnotationId2 } from "@dxos/echo-schema";
1436
+ import { findAnnotation as findAnnotation2 } from "@dxos/effect";
1437
+ import { DXN } from "@dxos/keys";
1438
+ import { Input as Input7 } from "@dxos/react-ui";
1439
+ import { TagPicker } from "@dxos/react-ui-tag-picker";
1440
+ import { isNonNullable as isNonNullable2 } from "@dxos/util";
1441
+ var RefField = ({ type, label, disabled, placeholder, inputOnly, array, ast, getValue: getValue3, onBlur, onQueryRefOptions, onValueChange, ...restInputProps }) => {
1442
+ const refTypeInfo = useMemo5(() => ast ? findAnnotation2(ast, ReferenceAnnotationId2) : void 0, [
1443
+ ast
1444
+ ]);
1445
+ const { options: availableOptions, loading: _loading } = useQueryRefOptions({
1446
+ refTypeInfo,
1447
+ onQueryRefOptions
1448
+ });
1449
+ if (refTypeInfo && refTypeInfo?.typename === getTypeAnnotation(Expando)?.typename || !onQueryRefOptions) {
1450
+ return /* @__PURE__ */ React11.createElement(RefFieldFallback, {
1451
+ type,
1452
+ label,
1453
+ placeholder,
1454
+ disabled,
1455
+ inputOnly,
1456
+ getValue: getValue3,
1457
+ onBlur,
1458
+ onValueChange,
1459
+ ...restInputProps
1460
+ });
1461
+ }
1462
+ const handleGetValue = useCallback7(() => {
1463
+ const formValue = getValue3();
1464
+ const unknownToRefOption = (val) => {
1465
+ if (Ref.isRef(val)) {
1466
+ const dxnString = val.dxn.toString();
1467
+ const matchingOption = availableOptions.find((option2) => option2.id === dxnString);
1468
+ if (matchingOption) {
1469
+ return matchingOption;
1470
+ }
1471
+ }
1472
+ return void 0;
1473
+ };
1474
+ if (array && Array.isArray(formValue)) {
1475
+ return formValue.map(unknownToRefOption).filter(isNonNullable2) ?? [];
1476
+ }
1477
+ const option = unknownToRefOption(formValue);
1478
+ if (option) {
1479
+ return [
1480
+ option
1481
+ ];
1482
+ }
1483
+ return [];
1484
+ }, [
1485
+ getValue3,
1486
+ availableOptions,
1487
+ array
1488
+ ]);
1489
+ const handleSearch = useCallback7((text, ids) => availableOptions.filter((option) => !ids.includes(option.id)).filter((option) => option.label.toLowerCase().includes(text.toLowerCase())).map((option) => ({
1490
+ id: option.id,
1491
+ label: option.label,
1492
+ hue: option.hue
1493
+ })), [
1494
+ availableOptions
1495
+ ]);
1496
+ const handleUpdate = useCallback7((ids) => {
1497
+ if (ids.length === 0) {
1498
+ onValueChange("object", void 0);
1499
+ return;
1500
+ }
1501
+ const refs = ids.map((id) => {
1502
+ const item = availableOptions.find((option) => option.id === id);
1503
+ if (item) {
1504
+ const dxn = DXN.parse(item.id);
1505
+ return Ref.fromDXN(dxn);
1506
+ }
1507
+ return null;
1508
+ }).filter(isNonNullable2);
1509
+ if (array) {
1510
+ onValueChange("object", refs);
1511
+ } else {
1512
+ onValueChange("object", refs[0]);
1513
+ }
1514
+ }, [
1515
+ availableOptions,
1516
+ array,
1517
+ onValueChange
1518
+ ]);
1519
+ const tagPickerMode = useMemo5(() => array ? "multi-select" : "single-select", [
1520
+ array
1521
+ ]);
1522
+ if (!refTypeInfo) {
1523
+ return null;
1524
+ }
1525
+ const { status, error } = restInputProps.getStatus();
1526
+ return /* @__PURE__ */ React11.createElement(Input7.Root, {
1527
+ validationValence: status
1528
+ }, !inputOnly && /* @__PURE__ */ React11.createElement(InputHeader, {
1529
+ error
1530
+ }, /* @__PURE__ */ React11.createElement(Input7.Label, null, label)), /* @__PURE__ */ React11.createElement("div", {
1531
+ "data-no-submit": true
1532
+ }, /* @__PURE__ */ React11.createElement(TagPicker, {
1533
+ items: handleGetValue(),
1534
+ mode: tagPickerMode,
1535
+ onBlur: (event) => onBlur(event),
1536
+ onUpdate: handleUpdate,
1537
+ onSearch: handleSearch,
1538
+ classNames: "rounded-sm bg-input p-1.5"
1539
+ })), inputOnly && /* @__PURE__ */ React11.createElement(Input7.DescriptionAndValidation, null, error));
1540
+ };
1541
+ var RefFieldFallback = ({ type, label, disabled, placeholder, inputOnly, getValue: getValue3, onValueChange, ...restInputProps }) => {
1542
+ const handleOnValueChange = (_type, dxnString) => {
1543
+ const dxn = DXN.tryParse(dxnString);
1544
+ if (dxn) {
1545
+ onValueChange?.("object", Ref.fromDXN(dxn));
1546
+ } else if (dxnString === "") {
1547
+ onValueChange?.("object", void 0);
1548
+ } else {
1549
+ onValueChange?.("string", dxnString);
1550
+ }
1551
+ };
1552
+ const handleGetValue = () => {
1553
+ const formValue = getValue3();
1554
+ if (typeof formValue === "string") {
1555
+ return formValue;
1556
+ }
1557
+ if (Ref.isRef(formValue)) {
1558
+ return formValue.dxn.toString();
1559
+ }
1560
+ return void 0;
1561
+ };
1562
+ return /* @__PURE__ */ React11.createElement(TextInput, {
1563
+ type,
1564
+ label,
1565
+ disabled,
1566
+ placeholder,
1567
+ inputOnly,
1568
+ getValue: handleGetValue,
1569
+ onValueChange: handleOnValueChange,
1570
+ ...restInputProps
1571
+ });
1572
+ };
1573
+
1574
+ // packages/ui/react-ui-form/src/components/Form/factory.tsx
1575
+ import { FormatEnum as FormatEnum4 } from "@dxos/echo-schema";
1576
+ var getInputComponent = (type, format) => {
1577
+ switch (format) {
1578
+ case FormatEnum4.GeoPoint:
1579
+ return GeoPointInput;
1580
+ case FormatEnum4.Markdown:
1581
+ return MarkdownInput;
1582
+ }
1583
+ switch (type) {
1584
+ case "string":
1585
+ return TextInput;
1586
+ case "number":
1587
+ return NumberInput;
1588
+ case "boolean":
1589
+ return BooleanInput;
1590
+ }
1591
+ };
1592
+
1593
+ // packages/ui/react-ui-form/src/components/Form/FormContent.tsx
1594
+ var FormField = ({ property, path, readonly, inline, onQueryRefOptions, lookupComponent, Custom }) => {
1202
1595
  const inputProps = useInputProps(path);
1203
1596
  const { ast, name, type, format, title, description, options, examples, array } = property;
1204
- const label = useMemo5(() => title ?? pipe2(name, capitalize2), [
1597
+ const label = useMemo6(() => title ?? pipe2(name, capitalize2), [
1205
1598
  title,
1206
1599
  name
1207
1600
  ]);
1208
- const placeholder = useMemo5(() => examples?.length ? `Example: "${examples[0]}"` : description, [
1601
+ const placeholder = useMemo6(() => examples?.length ? `Example: "${examples[0]}"` : description, [
1209
1602
  examples,
1210
1603
  description
1211
1604
  ]);
@@ -1239,6 +1632,21 @@ var FormField = ({ property, path, readonly, inline, onQueryRefOptions, lookupCo
1239
1632
  ...inputProps
1240
1633
  });
1241
1634
  }
1635
+ const refProps = getRefProps(property);
1636
+ if (refProps) {
1637
+ return /* @__PURE__ */ React12.createElement(RefField, {
1638
+ ast: refProps.ast,
1639
+ array: refProps.isArray,
1640
+ type,
1641
+ format,
1642
+ label,
1643
+ placeholder,
1644
+ disabled: readonly,
1645
+ inputOnly: inline,
1646
+ onQueryRefOptions,
1647
+ ...inputProps
1648
+ });
1649
+ }
1242
1650
  if (array) {
1243
1651
  return /* @__PURE__ */ React12.createElement(ArrayField, {
1244
1652
  property,
@@ -1279,21 +1687,9 @@ var FormField = ({ property, path, readonly, inline, onQueryRefOptions, lookupCo
1279
1687
  ...inputProps
1280
1688
  }));
1281
1689
  }
1282
- if (format === "ref") {
1283
- return /* @__PURE__ */ React12.createElement(RefField, {
1284
- ast,
1285
- type,
1286
- label,
1287
- readonly,
1288
- placeholder,
1289
- inline,
1290
- onQueryRefOptions,
1291
- inputProps
1292
- });
1293
- }
1294
1690
  if (type === "object") {
1295
- const baseNode = findNode2(ast, isDiscriminatedUnion2);
1296
- const typeLiteral = baseNode ? getDiscriminatedType2(baseNode, inputProps.getValue()) : findNode2(ast, SchemaAST3.isTypeLiteral);
1691
+ const baseNode = findNode3(ast, isDiscriminatedUnion2);
1692
+ const typeLiteral = baseNode ? getDiscriminatedType2(baseNode, inputProps.getValue()) : findNode3(ast, SchemaAST4.isTypeLiteral);
1297
1693
  if (typeLiteral) {
1298
1694
  return /* @__PURE__ */ React12.createElement("div", {
1299
1695
  role: "none"
@@ -1313,7 +1709,7 @@ var FormField = ({ property, path, readonly, inline, onQueryRefOptions, lookupCo
1313
1709
  };
1314
1710
  var FormFields = ({ schema, path, filter, sort, readonly, onQueryRefOptions, lookupComponent, Custom }) => {
1315
1711
  const values = useFormValues(path);
1316
- const properties = useMemo5(() => {
1712
+ const properties = useMemo6(() => {
1317
1713
  const props = getSchemaProperties2(schema.ast, values);
1318
1714
  const filtered = filter ? filter(props) : props;
1319
1715
  return sort ? filtered.sort((a, b) => sort.indexOf(a.name) - sort.indexOf(b.name)) : filtered;
@@ -1345,7 +1741,7 @@ var FormFields = ({ schema, path, filter, sort, readonly, onQueryRefOptions, loo
1345
1741
  // packages/ui/react-ui-form/src/components/Form/Form.tsx
1346
1742
  var Form = ({ classNames, schema, values: initialValues, path = [], autoFocus, readonly, filter, sort, autoSave, testId, onValuesChanged, onValidate, onSave, onCancel, onQueryRefOptions, lookupComponent, Custom }) => {
1347
1743
  const formRef = useRef3(null);
1348
- const onValid = useMemo6(() => autoSave ? onSave : void 0, [
1744
+ const onValid = useMemo7(() => autoSave ? onSave : void 0, [
1349
1745
  autoSave,
1350
1746
  onSave
1351
1747
  ]);
@@ -1426,7 +1822,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
1426
1822
  const [{ fieldSchema }, setFieldSchema] = useState5({
1427
1823
  fieldSchema: getFormatSchema(props?.format)
1428
1824
  });
1429
- const handleValuesChanged = useCallback7((_props) => {
1825
+ const handleValuesChanged = useCallback8((_props) => {
1430
1826
  setFieldSchema((prev) => {
1431
1827
  const fieldSchema2 = getFormatSchema(_props.format);
1432
1828
  if (prev.fieldSchema === fieldSchema2) {
@@ -1461,7 +1857,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
1461
1857
  props.format,
1462
1858
  props.referenceSchema
1463
1859
  ]);
1464
- const handleValidate = useCallback7(({ property }) => {
1860
+ const handleValidate = useCallback8(({ property }) => {
1465
1861
  if (property && view.fields.find((f) => f.path === property && f.path !== field.path)) {
1466
1862
  return [
1467
1863
  {
@@ -1474,7 +1870,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
1474
1870
  view.fields,
1475
1871
  field
1476
1872
  ]);
1477
- const handleSave = useCallback7((props2) => {
1873
+ const handleSave = useCallback8((props2) => {
1478
1874
  projection.setFieldProjection({
1479
1875
  field,
1480
1876
  props: props2
@@ -1485,16 +1881,16 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
1485
1881
  field,
1486
1882
  onSave
1487
1883
  ]);
1488
- const handleCancel = useCallback7(() => {
1884
+ const handleCancel = useCallback8(() => {
1489
1885
  requestAnimationFrame(() => onCancel?.());
1490
1886
  onSave();
1491
1887
  }, [
1492
1888
  onSave
1493
1889
  ]);
1494
- const Custom = useMemo7(() => ({
1890
+ const Custom = useMemo8(() => ({
1495
1891
  ["format"]: (props2) => /* @__PURE__ */ React14.createElement(SelectInput, {
1496
1892
  ...props2,
1497
- options: FormatEnums.filter((value) => value !== FormatEnum2.None).map((value) => ({
1893
+ options: FormatEnums.filter((value) => value !== FormatEnum5.None).map((value) => ({
1498
1894
  value,
1499
1895
  label: t(`format ${value}`)
1500
1896
  }))
@@ -1517,7 +1913,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
1517
1913
  schemas,
1518
1914
  referenceSchema
1519
1915
  ]);
1520
- const propIsNotType = useCallback7((props2) => props2.filter((p) => p.name !== "type"), []);
1916
+ const propIsNotType = useCallback8((props2) => props2.filter((p) => p.name !== "type"), []);
1521
1917
  if (!fieldSchema) {
1522
1918
  log3.warn("invalid format", {
1523
1919
  props
@@ -1548,8 +1944,8 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
1548
1944
  };
1549
1945
 
1550
1946
  // packages/ui/react-ui-form/src/components/ViewEditor/ViewEditor.tsx
1551
- import { Schema as Schema2, SchemaAST as SchemaAST4 } from "effect";
1552
- import React15, { useCallback as useCallback8, useMemo as useMemo8, useState as useState6 } from "react";
1947
+ import { Schema as Schema2, SchemaAST as SchemaAST5 } from "effect";
1948
+ import React15, { useCallback as useCallback9, useMemo as useMemo9, useState as useState6 } from "react";
1553
1949
  import { Format } from "@dxos/echo-schema";
1554
1950
  import { invariant as invariant3 } from "@dxos/invariant";
1555
1951
  import { IconButton as IconButton4, useTranslation as useTranslation7 } from "@dxos/react-ui";
@@ -1560,20 +1956,20 @@ var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/c
1560
1956
  var grid = "grid grid-cols-[32px_1fr_32px] min-bs-[2.5rem]";
1561
1957
  var ViewMetaSchema = Schema2.Struct({
1562
1958
  name: Schema2.String.annotations({
1563
- [SchemaAST4.TitleAnnotationId]: "View"
1959
+ [SchemaAST5.TitleAnnotationId]: "View"
1564
1960
  }),
1565
1961
  typename: Format.URL.annotations({
1566
- [SchemaAST4.TitleAnnotationId]: "Typename"
1962
+ [SchemaAST5.TitleAnnotationId]: "Typename"
1567
1963
  })
1568
1964
  }).pipe(Schema2.mutable);
1569
1965
  var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading = false, onTypenameChanged, onDelete }) => {
1570
1966
  const { t } = useTranslation7(translationKey);
1571
- const projection = useMemo8(() => new ViewProjection(schema.jsonSchema, view), [
1967
+ const projection = useMemo9(() => new ViewProjection(schema.jsonSchema, view), [
1572
1968
  schema,
1573
1969
  view
1574
1970
  ]);
1575
1971
  const [field, setField] = useState6();
1576
- const viewValues = useMemo8(() => {
1972
+ const viewValues = useMemo9(() => {
1577
1973
  return {
1578
1974
  name: view.name,
1579
1975
  // TODO(burdon): Need to warn user of possible consequences of editing.
@@ -1583,10 +1979,10 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
1583
1979
  }, [
1584
1980
  view
1585
1981
  ]);
1586
- const handleSelect = useCallback8((field2) => {
1982
+ const handleSelect = useCallback9((field2) => {
1587
1983
  setField((f) => f === field2 ? void 0 : field2);
1588
1984
  }, []);
1589
- const handleAdd = useCallback8(() => {
1985
+ const handleAdd = useCallback9(() => {
1590
1986
  invariant3(!schema.readonly, void 0, {
1591
1987
  F: __dxlog_file5,
1592
1988
  L: 77,
@@ -1602,7 +1998,7 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
1602
1998
  schema,
1603
1999
  view
1604
2000
  ]);
1605
- const handleUpdate = useCallback8(({ name, typename }) => {
2001
+ const handleUpdate = useCallback9(({ name, typename }) => {
1606
2002
  invariant3(!schema.readonly, void 0, {
1607
2003
  F: __dxlog_file5,
1608
2004
  L: 84,
@@ -1625,7 +2021,7 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
1625
2021
  view,
1626
2022
  onTypenameChanged
1627
2023
  ]);
1628
- const handleDelete = useCallback8((fieldId) => {
2024
+ const handleDelete = useCallback9((fieldId) => {
1629
2025
  invariant3(!schema.readonly, void 0, {
1630
2026
  F: __dxlog_file5,
1631
2027
  L: 100,
@@ -1644,7 +2040,7 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
1644
2040
  field,
1645
2041
  onDelete
1646
2042
  ]);
1647
- const handleMove = useCallback8((fromIndex, toIndex) => {
2043
+ const handleMove = useCallback9((fromIndex, toIndex) => {
1648
2044
  invariant3(!schema.readonly, void 0, {
1649
2045
  F: __dxlog_file5,
1650
2046
  L: 112,
@@ -1664,15 +2060,15 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
1664
2060
  schema,
1665
2061
  view.fields
1666
2062
  ]);
1667
- const handleClose = useCallback8(() => setField(void 0), []);
2063
+ const handleClose = useCallback9(() => setField(void 0), []);
1668
2064
  const hiddenProperties = projection.getHiddenProperties();
1669
- const handleHide = useCallback8((fieldId) => {
2065
+ const handleHide = useCallback9((fieldId) => {
1670
2066
  setField(void 0);
1671
2067
  projection.hideFieldProjection(fieldId);
1672
2068
  }, [
1673
2069
  projection
1674
2070
  ]);
1675
- const handleShow = useCallback8((property) => {
2071
+ const handleShow = useCallback9((property) => {
1676
2072
  setField(void 0);
1677
2073
  projection.showFieldProjection(property);
1678
2074
  }, [
@@ -1760,276 +2156,6 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
1760
2156
  disabled: view.fields.length >= VIEW_FIELD_LIMIT
1761
2157
  })));
1762
2158
  };
1763
-
1764
- // packages/ui/react-ui-form/src/util/field.ts
1765
- import { FormatEnum as FormatEnum3, GeoLocation as GeoLocation2, TypeEnum } from "@dxos/echo-schema";
1766
- var parseValue = ({ type, format, value }) => {
1767
- if (value === void 0 || value === null || value === "") {
1768
- return void 0;
1769
- }
1770
- const parseScalar = (type2) => {
1771
- switch (type2) {
1772
- case TypeEnum.Boolean: {
1773
- if (typeof value === "string") {
1774
- const lowercaseValue = value.toLowerCase();
1775
- if (lowercaseValue === "0" || lowercaseValue === "false") {
1776
- return false;
1777
- } else if (lowercaseValue === "1" || lowercaseValue === "true") {
1778
- return true;
1779
- }
1780
- }
1781
- return Boolean(value);
1782
- }
1783
- case TypeEnum.Number: {
1784
- const cleaned = typeof value === "string" ? value.replace(/[^0-9.-]+/g, "") : value;
1785
- const num = Number(cleaned);
1786
- return Number.isNaN(num) ? null : num;
1787
- }
1788
- case TypeEnum.String:
1789
- case TypeEnum.Ref:
1790
- return String(value);
1791
- default: {
1792
- return value;
1793
- }
1794
- }
1795
- };
1796
- if (!format) {
1797
- return parseScalar(type);
1798
- }
1799
- switch (format) {
1800
- case FormatEnum3.Boolean:
1801
- return parseScalar(TypeEnum.Boolean);
1802
- case FormatEnum3.Number:
1803
- case FormatEnum3.Percent:
1804
- case FormatEnum3.Currency:
1805
- return parseScalar(TypeEnum.Number);
1806
- case FormatEnum3.String:
1807
- case FormatEnum3.Markdown: {
1808
- return parseScalar(TypeEnum.String);
1809
- }
1810
- case FormatEnum3.Ref:
1811
- throw new Error(`unexpected format: ${FormatEnum3.Ref}`);
1812
- case FormatEnum3.DateTime:
1813
- case FormatEnum3.Date:
1814
- case FormatEnum3.Time:
1815
- case FormatEnum3.Timestamp: {
1816
- const date = new Date(value);
1817
- return isNaN(date.getTime()) ? null : date;
1818
- }
1819
- case FormatEnum3.GeoPoint: {
1820
- if (typeof value === "string") {
1821
- const cleaned = value.replace(/[^0-9.,-]+/g, "");
1822
- const parts = cleaned.split(",");
1823
- if (parts.length === 2) {
1824
- const lat = parseFloat(parts[0]);
1825
- const long = parseFloat(parts[1]);
1826
- if (!isNaN(lat) && !isNaN(long)) {
1827
- return GeoLocation2.toGeoPoint({
1828
- latitude: lat,
1829
- longitude: long
1830
- });
1831
- }
1832
- }
1833
- }
1834
- return [
1835
- 0,
1836
- 0
1837
- ];
1838
- }
1839
- default: {
1840
- return value;
1841
- }
1842
- }
1843
- };
1844
- var cellClassesForFieldType = ({ type, format }) => {
1845
- if (!format) {
1846
- switch (type) {
1847
- case TypeEnum.Number:
1848
- return [
1849
- "text-right",
1850
- "font-mono"
1851
- ];
1852
- case TypeEnum.Boolean:
1853
- return [
1854
- "text-right",
1855
- "font-mono"
1856
- ];
1857
- case TypeEnum.String:
1858
- return void 0;
1859
- case TypeEnum.Ref:
1860
- return void 0;
1861
- default: {
1862
- return void 0;
1863
- }
1864
- }
1865
- }
1866
- switch (format) {
1867
- case FormatEnum3.Markdown:
1868
- return void 0;
1869
- case FormatEnum3.Time:
1870
- case FormatEnum3.Timestamp:
1871
- case FormatEnum3.DateTime:
1872
- case FormatEnum3.Date:
1873
- case FormatEnum3.Duration:
1874
- return [
1875
- "font-mono",
1876
- "text-right"
1877
- ];
1878
- case FormatEnum3.Currency:
1879
- return [
1880
- "text-right"
1881
- ];
1882
- case FormatEnum3.JSON:
1883
- case FormatEnum3.DID:
1884
- return [
1885
- "font-mono"
1886
- ];
1887
- default:
1888
- return void 0;
1889
- }
1890
- };
1891
- var pathNotUniqueError = (path) => ({
1892
- path: "path",
1893
- message: `'${path}' is already present`
1894
- });
1895
-
1896
- // packages/ui/react-ui-form/src/util/formatting.ts
1897
- import { format as formatDate } from "date-fns/format";
1898
- import { FormatEnum as FormatEnum4, GeoLocation as GeoLocation3, TypeEnum as TypeEnum2 } from "@dxos/echo-schema";
1899
- var formatForDisplay = ({ type, format, value, locale = void 0 }) => {
1900
- const formatScalar = (type2) => {
1901
- switch (type2) {
1902
- case TypeEnum2.Boolean:
1903
- return value.toLocaleString().toUpperCase();
1904
- case TypeEnum2.Number:
1905
- return value.toLocaleString(locale);
1906
- case TypeEnum2.String:
1907
- case TypeEnum2.Ref:
1908
- return String(value);
1909
- default: {
1910
- return String(value);
1911
- }
1912
- }
1913
- };
1914
- if (!format) {
1915
- return formatScalar(type);
1916
- }
1917
- switch (format) {
1918
- case FormatEnum4.Boolean: {
1919
- return formatScalar(TypeEnum2.Boolean);
1920
- }
1921
- case FormatEnum4.Number: {
1922
- return formatScalar(TypeEnum2.Number);
1923
- }
1924
- case FormatEnum4.String:
1925
- case FormatEnum4.Ref: {
1926
- return formatScalar(TypeEnum2.String);
1927
- }
1928
- case FormatEnum4.Percent: {
1929
- return `${value * 100}%`;
1930
- }
1931
- case FormatEnum4.Currency: {
1932
- return value.toLocaleString(locale, {
1933
- style: "currency",
1934
- currency: "USD",
1935
- minimumFractionDigits: 2,
1936
- maximumFractionDigits: 2
1937
- });
1938
- }
1939
- case FormatEnum4.Date: {
1940
- try {
1941
- return formatDate(new Date(value), "yyyy-MM-dd");
1942
- } catch (error) {
1943
- return "Invalid Date";
1944
- }
1945
- }
1946
- case FormatEnum4.Time: {
1947
- try {
1948
- return formatDate(new Date(value), "HH:mm:ss");
1949
- } catch (error) {
1950
- return "Invalid Time";
1951
- }
1952
- }
1953
- case FormatEnum4.DateTime: {
1954
- try {
1955
- return formatDate(new Date(value), "yyyy-MM-dd HH:mm:ss");
1956
- } catch (error) {
1957
- return "Invalid DateTime";
1958
- }
1959
- }
1960
- case FormatEnum4.GeoPoint: {
1961
- if (value === null || value === void 0) {
1962
- return "";
1963
- }
1964
- if (Array.isArray(value) && value.length >= 2 && value.every(Number.isFinite)) {
1965
- const { latitude, longitude } = GeoLocation3.fromGeoPoint(value);
1966
- return `${latitude},${longitude}`;
1967
- }
1968
- return String(value);
1969
- }
1970
- default: {
1971
- if (value === null || value === "undefined") {
1972
- return "";
1973
- }
1974
- return String(value);
1975
- }
1976
- }
1977
- };
1978
- var formatForEditing = ({ type, format, value, locale = void 0 }) => {
1979
- const formatScalar = (type2) => {
1980
- switch (type2) {
1981
- case TypeEnum2.Boolean:
1982
- case TypeEnum2.Number:
1983
- case TypeEnum2.String:
1984
- case TypeEnum2.Ref:
1985
- return String(value);
1986
- default:
1987
- return String(value);
1988
- }
1989
- };
1990
- if (!format) {
1991
- return formatScalar(type);
1992
- }
1993
- switch (format) {
1994
- case FormatEnum4.Boolean:
1995
- case FormatEnum4.Number:
1996
- case FormatEnum4.String:
1997
- case FormatEnum4.Ref: {
1998
- return formatScalar(type);
1999
- }
2000
- case FormatEnum4.Percent: {
2001
- return String(value * 100);
2002
- }
2003
- case FormatEnum4.Currency: {
2004
- return String(value);
2005
- }
2006
- case FormatEnum4.DateTime: {
2007
- const date = new Date(value);
2008
- return date.toISOString();
2009
- }
2010
- case FormatEnum4.Date: {
2011
- const date = new Date(value);
2012
- return date.toISOString().split("T")[0];
2013
- }
2014
- case FormatEnum4.Time: {
2015
- const date = new Date(value);
2016
- return date.toISOString().split("T")[1].split(".")[0];
2017
- }
2018
- case FormatEnum4.GeoPoint: {
2019
- if (value === null || value === void 0) {
2020
- return "";
2021
- }
2022
- if (Array.isArray(value) && value.length >= 2 && value.every(Number.isFinite)) {
2023
- const { latitude, longitude } = GeoLocation3.fromGeoPoint(value);
2024
- return `${latitude},${longitude}`;
2025
- }
2026
- return String(value);
2027
- }
2028
- default: {
2029
- return String(value);
2030
- }
2031
- }
2032
- };
2033
2159
  export {
2034
2160
  BooleanInput,
2035
2161
  ControlFrame,
@@ -2057,8 +2183,10 @@ export {
2057
2183
  ViewEditor,
2058
2184
  cellClassesForFieldType,
2059
2185
  controlItemClasses,
2186
+ findArrayElementType,
2060
2187
  formatForDisplay,
2061
2188
  formatForEditing,
2189
+ getRefProps,
2062
2190
  parseValue,
2063
2191
  pathNotUniqueError,
2064
2192
  translations_default as translations,
@@ -2066,6 +2194,7 @@ export {
2066
2194
  useFormContext,
2067
2195
  useFormValues,
2068
2196
  useInputProps,
2197
+ useQueryRefOptions,
2069
2198
  useRefQueryLookupHandler
2070
2199
  };
2071
2200
  //# sourceMappingURL=index.mjs.map