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