@dxos/react-ui-form 0.8.2-staging.7ac8446 → 0.8.3-main.672df60

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 (115) hide show
  1. package/dist/lib/browser/index.mjs +1817 -1309
  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 +1773 -1273
  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 +1817 -1309
  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.d.ts → ControlSection/ControlSection.d.ts} +9 -6
  11. package/dist/types/src/components/ControlSection/ControlSection.d.ts.map +1 -0
  12. package/dist/types/src/components/ControlSection/ControlSection.stories.d.ts +8 -0
  13. package/dist/types/src/components/ControlSection/ControlSection.stories.d.ts.map +1 -0
  14. package/dist/types/src/components/ControlSection/index.d.ts +2 -0
  15. package/dist/types/src/components/ControlSection/index.d.ts.map +1 -0
  16. package/dist/types/src/components/FieldEditor/FieldEditor.d.ts.map +1 -1
  17. package/dist/types/src/components/FieldEditor/FieldEditor.test.d.ts +2 -0
  18. package/dist/types/src/components/FieldEditor/FieldEditor.test.d.ts.map +1 -0
  19. package/dist/types/src/components/Form/ArrayField.d.ts.map +1 -1
  20. package/dist/types/src/components/Form/Defaults.d.ts +4 -4
  21. package/dist/types/src/components/Form/Defaults.d.ts.map +1 -1
  22. package/dist/types/src/components/Form/Form.d.ts +6 -4
  23. package/dist/types/src/components/Form/Form.d.ts.map +1 -1
  24. package/dist/types/src/components/Form/Form.stories.d.ts +38 -36
  25. package/dist/types/src/components/Form/Form.stories.d.ts.map +1 -1
  26. package/dist/types/src/components/Form/FormActions.d.ts +1 -1
  27. package/dist/types/src/components/Form/FormActions.d.ts.map +1 -1
  28. package/dist/types/src/components/Form/FormContent.d.ts +16 -12
  29. package/dist/types/src/components/Form/FormContent.d.ts.map +1 -1
  30. package/dist/types/src/components/Form/FormContext.d.ts +2 -2
  31. package/dist/types/src/components/Form/FormContext.d.ts.map +1 -1
  32. package/dist/types/src/components/Form/Input.d.ts.map +1 -1
  33. package/dist/types/src/components/Form/RefField.d.ts +12 -0
  34. package/dist/types/src/components/Form/RefField.d.ts.map +1 -0
  35. package/dist/types/src/components/Form/custom/GeoPointInput.d.ts.map +1 -1
  36. package/dist/types/src/components/Form/custom/SelectOptionsInput.d.ts.map +1 -1
  37. package/dist/types/src/components/Form/custom/SelectOptionsInput.stories.d.ts.map +1 -1
  38. package/dist/types/src/components/Form/custom/TupleInput.d.ts.map +1 -1
  39. package/dist/types/src/components/Form/factory.d.ts +1 -1
  40. package/dist/types/src/components/Form/factory.d.ts.map +1 -1
  41. package/dist/types/src/components/Form/index.d.ts.map +1 -1
  42. package/dist/types/src/components/ViewEditor/Test.stories.d.ts.map +1 -1
  43. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts +2 -2
  44. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts.map +1 -1
  45. package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts +5 -3
  46. package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts.map +1 -1
  47. package/dist/types/src/components/ViewEditor/ViewEditor.test.d.ts +2 -0
  48. package/dist/types/src/components/ViewEditor/ViewEditor.test.d.ts.map +1 -0
  49. package/dist/types/src/components/deprecated/Form.d.ts +2 -2
  50. package/dist/types/src/components/deprecated/Form.d.ts.map +1 -1
  51. package/dist/types/src/components/deprecated/Form.stories.d.ts.map +1 -1
  52. package/dist/types/src/components/deprecated/FormInput.d.ts.map +1 -1
  53. package/dist/types/src/components/index.d.ts.map +1 -1
  54. package/dist/types/src/components/testing.d.ts.map +1 -1
  55. package/dist/types/src/hooks/index.d.ts +2 -0
  56. package/dist/types/src/hooks/index.d.ts.map +1 -1
  57. package/dist/types/src/hooks/useForm.d.ts +2 -2
  58. package/dist/types/src/hooks/useForm.d.ts.map +1 -1
  59. package/dist/types/src/hooks/useQueryRefOptions.d.ts +23 -0
  60. package/dist/types/src/hooks/useQueryRefOptions.d.ts.map +1 -0
  61. package/dist/types/src/hooks/useRefQueryLookupHandler.d.ts +8 -0
  62. package/dist/types/src/hooks/useRefQueryLookupHandler.d.ts.map +1 -0
  63. package/dist/types/src/translations.d.ts +5 -0
  64. package/dist/types/src/translations.d.ts.map +1 -1
  65. package/dist/types/src/util/field.d.ts.map +1 -1
  66. package/dist/types/src/util/formatting.d.ts.map +1 -1
  67. package/dist/types/src/util/index.d.ts +2 -0
  68. package/dist/types/src/util/index.d.ts.map +1 -1
  69. package/dist/types/src/util/refs.d.ts +9 -0
  70. package/dist/types/src/util/refs.d.ts.map +1 -0
  71. package/dist/types/src/util/schema.d.ts +3 -0
  72. package/dist/types/src/util/schema.d.ts.map +1 -0
  73. package/dist/types/src/vitest-setup.d.ts +2 -0
  74. package/dist/types/src/vitest-setup.d.ts.map +1 -0
  75. package/dist/types/tsconfig.tsbuildinfo +1 -1
  76. package/package.json +28 -25
  77. package/src/components/ControlSection/ControlSection.stories.tsx +29 -0
  78. package/src/components/{ControlSection.tsx → ControlSection/ControlSection.tsx} +40 -16
  79. package/src/components/ControlSection/index.ts +5 -0
  80. package/src/components/FieldEditor/FieldEditor.stories.tsx +1 -1
  81. package/src/components/FieldEditor/FieldEditor.test.tsx +49 -0
  82. package/src/components/FieldEditor/FieldEditor.tsx +3 -2
  83. package/src/components/Form/ArrayField.tsx +63 -50
  84. package/src/components/Form/Defaults.tsx +77 -48
  85. package/src/components/Form/Form.stories.tsx +134 -109
  86. package/src/components/Form/Form.tsx +8 -5
  87. package/src/components/Form/FormActions.tsx +15 -18
  88. package/src/components/Form/FormContent.tsx +116 -46
  89. package/src/components/Form/FormContext.tsx +24 -10
  90. package/src/components/Form/Input.tsx +4 -10
  91. package/src/components/Form/RefField.tsx +217 -0
  92. package/src/components/Form/custom/GeoPointInput.tsx +2 -2
  93. package/src/components/Form/custom/SelectOptionsInput.stories.tsx +6 -5
  94. package/src/components/Form/custom/SelectOptionsInput.tsx +2 -2
  95. package/src/components/Form/factory.tsx +1 -1
  96. package/src/components/Form/index.ts +0 -1
  97. package/src/components/ViewEditor/ViewEditor.stories.tsx +19 -9
  98. package/src/components/ViewEditor/ViewEditor.test.tsx +166 -0
  99. package/src/components/ViewEditor/ViewEditor.tsx +63 -30
  100. package/src/components/deprecated/Form.stories.tsx +6 -6
  101. package/src/components/deprecated/Form.tsx +6 -6
  102. package/src/components/deprecated/FormInput.tsx +1 -1
  103. package/src/components/index.ts +1 -0
  104. package/src/components/testing.tsx +5 -9
  105. package/src/hooks/index.ts +3 -1
  106. package/src/hooks/useForm.ts +4 -3
  107. package/src/hooks/useQueryRefOptions.ts +53 -0
  108. package/src/hooks/useRefQueryLookupHandler.ts +39 -0
  109. package/src/translations.ts +9 -2
  110. package/src/util/formatting.ts +15 -3
  111. package/src/util/index.ts +3 -1
  112. package/src/util/refs.ts +38 -0
  113. package/src/util/schema.ts +14 -0
  114. package/src/vitest-setup.ts +11 -0
  115. package/dist/types/src/components/ControlSection.d.ts.map +0 -1
@@ -6,6 +6,7 @@ var translations_default = [
6
6
  [translationKey]: {
7
7
  "fields label": "Fields",
8
8
  "hidden fields label": "Hidden Fields",
9
+ "empty readonly ref field label": "(none)",
9
10
  // TODO(burdon): Standardize field/property.
10
11
  "button add property": "Add property",
11
12
  "field property label": "Property",
@@ -15,6 +16,8 @@ var translations_default = [
15
16
  "add field": "Add field",
16
17
  "delete field": "Delete field",
17
18
  "field limit reached": "Maximum number of fields reached",
19
+ "boolean input true value": "Yes",
20
+ "boolean input false value": "No",
18
21
  // TODO(burdon): Factor out?
19
22
  "button cancel": "Cancel",
20
23
  "button save": "Save",
@@ -44,416 +47,517 @@ var translations_default = [
44
47
  "format number": "Number",
45
48
  "format uri": "URI",
46
49
  "format uuid": "UUID",
47
- // Placeholders
50
+ // Placeholders.
48
51
  "placeholder latitude": "Latitude",
49
52
  "placeholder longitude": "Longitude",
50
- // SelectOptionsInput
53
+ // SelectOptionsInput.
51
54
  "select option label": "Label",
52
55
  "select option label placeholder": "Option label",
53
56
  "select option color": "Color",
54
57
  "select option delete": "Delete",
55
- "select option add": "Add option"
58
+ "select option add": "Add option",
59
+ // System schema message.
60
+ "system schema title": "System Schema",
61
+ "system schema description": "This schema is managed by the system and cannot be modified."
56
62
  }
57
63
  }
58
64
  }
59
65
  ];
60
66
 
61
67
  // packages/ui/react-ui-form/src/components/deprecated/FormInput.tsx
68
+ import { useSignals as _useSignals } from "@preact-signals/safe-react/tracking";
62
69
  import React from "react";
63
70
  import { Input } from "@dxos/react-ui";
64
71
  import { mx, textBlockWidth } from "@dxos/react-ui-theme";
65
72
  var DeprecatedFormContainer = ({ children, classNames }) => {
66
- return /* @__PURE__ */ React.createElement("div", {
67
- role: "none",
68
- className: "w-full p-4 justify-center overflow-x-hidden overflow-y-auto"
69
- }, /* @__PURE__ */ React.createElement("div", {
70
- role: "form",
71
- className: mx("flex flex-col", textBlockWidth, classNames)
72
- }, children));
73
+ var _effect = _useSignals();
74
+ try {
75
+ return /* @__PURE__ */ React.createElement("div", {
76
+ role: "none",
77
+ className: "container-max-width p-4 justify-center overflow-x-hidden overflow-y-auto"
78
+ }, /* @__PURE__ */ React.createElement("div", {
79
+ role: "form",
80
+ className: mx("flex flex-col", textBlockWidth, classNames)
81
+ }, children));
82
+ } finally {
83
+ _effect.f();
84
+ }
73
85
  };
74
86
  var DeprecatedFormInput = ({ label, description, secondary, children }) => {
75
- const primary = /* @__PURE__ */ React.createElement("div", {
76
- role: "none",
77
- className: "flex w-full gap-4 py-1"
78
- }, /* @__PURE__ */ React.createElement(Input.Root, null, /* @__PURE__ */ React.createElement("div", {
79
- role: "none",
80
- className: "flex flex-col w-full"
81
- }, /* @__PURE__ */ React.createElement(Input.Label, {
82
- classNames: "flex min-bs-[--rail-action] items-center",
83
- style: {
84
- fontSize: "unset"
85
- }
86
- }, label), description && /* @__PURE__ */ React.createElement(Input.DescriptionAndValidation, {
87
- classNames: "mbs-0.5"
88
- }, /* @__PURE__ */ React.createElement(Input.Description, null, description))), /* @__PURE__ */ React.createElement("div", {
89
- role: "none"
90
- }, /* @__PURE__ */ React.createElement("div", {
91
- role: "none",
92
- className: "flex min-bs-[--rail-action] items-center"
93
- }, children))));
94
- if (secondary) {
95
- return /* @__PURE__ */ React.createElement("div", {
87
+ var _effect = _useSignals();
88
+ try {
89
+ const primary = /* @__PURE__ */ React.createElement("div", {
90
+ role: "none",
91
+ className: "flex w-full gap-4 py-1"
92
+ }, /* @__PURE__ */ React.createElement(Input.Root, null, /* @__PURE__ */ React.createElement("div", {
93
+ role: "none",
94
+ className: "flex flex-col w-full"
95
+ }, /* @__PURE__ */ React.createElement(Input.Label, {
96
+ classNames: "flex min-bs-[--rail-action] items-center",
97
+ style: {
98
+ fontSize: "unset"
99
+ }
100
+ }, label), description && /* @__PURE__ */ React.createElement(Input.DescriptionAndValidation, {
101
+ classNames: "mbs-0.5"
102
+ }, /* @__PURE__ */ React.createElement(Input.Description, null, description))), /* @__PURE__ */ React.createElement("div", {
96
103
  role: "none"
97
- }, primary, secondary);
104
+ }, /* @__PURE__ */ React.createElement("div", {
105
+ role: "none",
106
+ className: "flex min-bs-[--rail-action] items-center"
107
+ }, children))));
108
+ if (secondary) {
109
+ return /* @__PURE__ */ React.createElement("div", {
110
+ role: "none"
111
+ }, primary, secondary);
112
+ }
113
+ return primary;
114
+ } finally {
115
+ _effect.f();
98
116
  }
99
- return primary;
100
117
  };
101
118
 
102
- // packages/ui/react-ui-form/src/components/ControlSection.tsx
119
+ // packages/ui/react-ui-form/src/components/ControlSection/ControlSection.tsx
120
+ import { useSignals as _useSignals2 } from "@preact-signals/safe-react/tracking";
103
121
  import React2 from "react";
104
- import { toLocalizedString, useTranslation, Input as Input2 } from "@dxos/react-ui";
105
- var ControlSectionHeading = ({ title, description }) => {
106
- const { t } = useTranslation(translationKey);
107
- return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement("h2", {
108
- className: "pli-4 container-max-width text-xl mbs-6 mbe-4"
109
- }, toLocalizedString(title, t)), description && /* @__PURE__ */ React2.createElement("p", {
110
- className: "pli-4 mlb-4 container-max-width text-description"
111
- }, toLocalizedString(description, t)));
122
+ import { Button, Input as Input2, toLocalizedString, useTranslation } from "@dxos/react-ui";
123
+ import { mx as mx2 } from "@dxos/react-ui-theme";
124
+ var ControlPage = ({ children, classNames, ...props }) => {
125
+ var _effect = _useSignals2();
126
+ try {
127
+ return /* @__PURE__ */ React2.createElement("div", {
128
+ role: "none",
129
+ className: mx2("pli-2", classNames),
130
+ ...props
131
+ }, children);
132
+ } finally {
133
+ _effect.f();
134
+ }
112
135
  };
113
136
  var ControlSection = ({ title, description, children }) => {
114
- return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(ControlSectionHeading, {
115
- title,
116
- description
117
- }), children);
137
+ var _effect = _useSignals2();
138
+ try {
139
+ return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(ControlSectionHeading, {
140
+ title,
141
+ description
142
+ }), children);
143
+ } finally {
144
+ _effect.f();
145
+ }
146
+ };
147
+ var ControlSectionHeading = ({ title, description }) => {
148
+ var _effect = _useSignals2();
149
+ try {
150
+ const { t } = useTranslation(translationKey);
151
+ return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement("h2", {
152
+ className: "pli-4 container-max-width text-xl mbs-6 mbe-4"
153
+ }, toLocalizedString(title, t)), description && /* @__PURE__ */ React2.createElement("p", {
154
+ className: "pli-4 mlb-4 container-max-width text-description"
155
+ }, toLocalizedString(description, t)));
156
+ } finally {
157
+ _effect.f();
158
+ }
159
+ };
160
+ var ControlGroupButton = ({ classNames, ...props }) => {
161
+ var _effect = _useSignals2();
162
+ try {
163
+ return /* @__PURE__ */ React2.createElement(Button, {
164
+ ...props,
165
+ classNames: [
166
+ "md:col-span-2",
167
+ classNames
168
+ ]
169
+ });
170
+ } finally {
171
+ _effect.f();
172
+ }
173
+ };
174
+ var ControlGroup = ({ children, classNames }) => {
175
+ var _effect = _useSignals2();
176
+ try {
177
+ return /* @__PURE__ */ React2.createElement("div", {
178
+ role: "none",
179
+ className: mx2("group container-max-width grid grid-cols-1 md:grid-cols-[1fr_min-content] gap-4", classNames)
180
+ }, children);
181
+ } finally {
182
+ _effect.f();
183
+ }
184
+ };
185
+ var ControlFrame = ({ children }) => {
186
+ var _effect = _useSignals2();
187
+ try {
188
+ return /* @__PURE__ */ React2.createElement("div", {
189
+ role: "none",
190
+ className: "p-4 border border-separator rounded-lg container-max-width grid grid-cols-1 md:grid-cols-[1fr_1fr] gap-2 md:gap-8"
191
+ }, children);
192
+ } finally {
193
+ _effect.f();
194
+ }
118
195
  };
119
- var ControlGroup = ({ children }) => /* @__PURE__ */ React2.createElement("div", {
120
- role: "none",
121
- className: "group container-max-width grid grid-cols-1 md:grid-cols-[1fr_min-content] gap-4"
122
- }, children);
123
- var ControlFrame = ({ children }) => /* @__PURE__ */ React2.createElement("div", {
124
- role: "none",
125
- className: "p-4 border border-separator rounded-lg container-max-width grid grid-cols-1 md:grid-cols-[1fr_1fr] gap-2 md:gap-8"
126
- }, children);
127
- var controlItemClasses = "p-4 border border-separator rounded-lg container-max-width grid md:col-span-2 grid-cols-subgrid items-center";
128
- var controlItemTitleClasses = "text-lg font-normal mbe-2";
196
+ var controlItemClasses = "p-4 border border-separator rounded-lg container-max-width grid md:col-span-2 grid-cols-subgrid items-center gap-2";
197
+ var controlItemTitleClasses = "text-lg font-normal";
129
198
  var controlItemDescriptionClasses = "text-base mlb-2 md:mbe-0 text-description";
130
199
  var ControlItem = ({ title, description, children }) => {
131
- const { t } = useTranslation(translationKey);
132
- return /* @__PURE__ */ React2.createElement("div", {
133
- className: controlItemClasses
134
- }, /* @__PURE__ */ React2.createElement("div", {
135
- role: "none"
136
- }, /* @__PURE__ */ React2.createElement("h3", {
137
- className: controlItemTitleClasses
138
- }, toLocalizedString(title, t)), description && /* @__PURE__ */ React2.createElement("p", {
139
- className: controlItemDescriptionClasses
140
- }, toLocalizedString(description, t))), children);
200
+ var _effect = _useSignals2();
201
+ try {
202
+ const { t } = useTranslation(translationKey);
203
+ return /* @__PURE__ */ React2.createElement("div", {
204
+ className: controlItemClasses
205
+ }, /* @__PURE__ */ React2.createElement("div", {
206
+ role: "none"
207
+ }, /* @__PURE__ */ React2.createElement("h3", {
208
+ className: controlItemTitleClasses
209
+ }, toLocalizedString(title, t)), description && /* @__PURE__ */ React2.createElement("p", {
210
+ className: controlItemDescriptionClasses
211
+ }, toLocalizedString(description, t))), children);
212
+ } finally {
213
+ _effect.f();
214
+ }
141
215
  };
142
216
  var ControlItemInput = ({ title, description, children }) => {
143
- const { t } = useTranslation(translationKey);
144
- return /* @__PURE__ */ React2.createElement(Input2.Root, null, /* @__PURE__ */ React2.createElement("div", {
145
- className: controlItemClasses
146
- }, /* @__PURE__ */ React2.createElement("div", {
147
- role: "none"
148
- }, /* @__PURE__ */ React2.createElement(Input2.Label, {
149
- classNames: controlItemTitleClasses
150
- }, toLocalizedString(title, t)), description && /* @__PURE__ */ React2.createElement(Input2.DescriptionAndValidation, null, /* @__PURE__ */ React2.createElement(Input2.Description, {
151
- classNames: controlItemDescriptionClasses
152
- }, toLocalizedString(description, t)))), children));
217
+ var _effect = _useSignals2();
218
+ try {
219
+ const { t } = useTranslation(translationKey);
220
+ return /* @__PURE__ */ React2.createElement(Input2.Root, null, /* @__PURE__ */ React2.createElement("div", {
221
+ className: controlItemClasses
222
+ }, /* @__PURE__ */ React2.createElement("div", {
223
+ role: "none"
224
+ }, /* @__PURE__ */ React2.createElement(Input2.Label, {
225
+ classNames: controlItemTitleClasses
226
+ }, toLocalizedString(title, t)), description && /* @__PURE__ */ React2.createElement(Input2.DescriptionAndValidation, null, /* @__PURE__ */ React2.createElement(Input2.Description, {
227
+ classNames: controlItemDescriptionClasses
228
+ }, toLocalizedString(description, t)))), children));
229
+ } finally {
230
+ _effect.f();
231
+ }
153
232
  };
154
233
  var ControlFrameItem = ({ title, description, children }) => {
155
- const { t } = useTranslation(translationKey);
156
- return /* @__PURE__ */ React2.createElement("div", {
157
- role: "group",
158
- className: "min-is-0"
159
- }, /* @__PURE__ */ React2.createElement("h3", {
160
- className: "text-lg mbe-2"
161
- }, toLocalizedString(title, t)), description && /* @__PURE__ */ React2.createElement("p", {
162
- className: "mlb-2 md:mbe-0 text-description"
163
- }, toLocalizedString(description, t)), children);
234
+ var _effect = _useSignals2();
235
+ try {
236
+ const { t } = useTranslation(translationKey);
237
+ return /* @__PURE__ */ React2.createElement("div", {
238
+ role: "group",
239
+ className: "min-is-0"
240
+ }, /* @__PURE__ */ React2.createElement("h3", {
241
+ className: "text-lg mbe-2"
242
+ }, toLocalizedString(title, t)), description && /* @__PURE__ */ React2.createElement("p", {
243
+ className: "mlb-2 md:mbe-0 text-description"
244
+ }, toLocalizedString(description, t)), children);
245
+ } finally {
246
+ _effect.f();
247
+ }
164
248
  };
165
249
 
166
250
  // packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx
167
- import React13, { useCallback as useCallback6, useEffect as useEffect7, useMemo as useMemo7, useState as useState4 } from "react";
168
- import { FormatEnum as FormatEnum2, FormatEnums, formatToType } from "@dxos/echo-schema";
169
- import { log as log2 } from "@dxos/log";
170
- import { useTranslation as useTranslation6 } from "@dxos/react-ui";
251
+ import { useSignals as _useSignals14 } from "@preact-signals/safe-react/tracking";
252
+ import React14, { useCallback as useCallback9, useEffect as useEffect8, useMemo as useMemo7, useState as useState5 } from "react";
253
+ import { FormatEnum as FormatEnum5, FormatEnums, formatToType } from "@dxos/echo-schema";
254
+ import { log as log3 } from "@dxos/log";
255
+ import { useTranslation as useTranslation8 } from "@dxos/react-ui";
171
256
  import { getFormatSchema, getSchemaProperties as getSchemaProperties3, sortProperties } from "@dxos/schema";
172
257
 
173
258
  // packages/ui/react-ui-form/src/components/Form/custom/GeoPointInput.tsx
259
+ import { useSignals as _useSignals4 } from "@preact-signals/safe-react/tracking";
174
260
  import React4, { useCallback, useState, useEffect, useMemo } from "react";
175
261
  import { GeoLocation } from "@dxos/echo-schema";
176
262
  import { Input as Input3, useTranslation as useTranslation2 } from "@dxos/react-ui";
177
263
  import { safeParseFloat } from "@dxos/util";
178
264
 
179
265
  // packages/ui/react-ui-form/src/components/Form/Input.tsx
266
+ import { useSignals as _useSignals3 } from "@preact-signals/safe-react/tracking";
180
267
  import React3 from "react";
181
268
  import { Icon, Tooltip } from "@dxos/react-ui";
182
269
  import { errorText } from "@dxos/react-ui-theme";
183
270
  var InputHeader = ({ children, error }) => {
184
- return /* @__PURE__ */ React3.createElement("div", {
185
- role: "none",
186
- className: "flex justify-between items-center mb-1"
187
- }, children, error && /* @__PURE__ */ React3.createElement(Tooltip.Root, null, /* @__PURE__ */ React3.createElement(Tooltip.Trigger, {
188
- asChild: true
189
- }, /* @__PURE__ */ React3.createElement(Icon, {
190
- icon: "ph--warning--regular",
191
- size: 4,
192
- classNames: errorText
193
- })), /* @__PURE__ */ React3.createElement(Tooltip.Content, {
194
- side: "bottom"
195
- }, /* @__PURE__ */ React3.createElement(Tooltip.Arrow, null), error)));
271
+ var _effect = _useSignals3();
272
+ try {
273
+ return /* @__PURE__ */ React3.createElement("div", {
274
+ role: "none",
275
+ className: "flex justify-between items-center mbs-2 mbe-1 first:mbs-0"
276
+ }, children, error && /* @__PURE__ */ React3.createElement(Tooltip.Trigger, {
277
+ asChild: true,
278
+ content: error,
279
+ side: "bottom"
280
+ }, /* @__PURE__ */ React3.createElement(Icon, {
281
+ icon: "ph--warning--regular",
282
+ size: 4,
283
+ classNames: errorText
284
+ })));
285
+ } finally {
286
+ _effect.f();
287
+ }
196
288
  };
197
289
 
198
290
  // packages/ui/react-ui-form/src/components/Form/custom/GeoPointInput.tsx
199
291
  var GeoPointInput = ({ type, label, disabled, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
200
- const { t } = useTranslation2(translationKey);
201
- const { status, error } = getStatus();
202
- const geoPoint = useMemo(() => getValue3() ?? [
203
- 0,
204
- 0
205
- ], [
206
- getValue3
207
- ]);
208
- const geoLocation = useMemo(() => GeoLocation.fromGeoPoint(geoPoint), [
209
- geoPoint
210
- ]);
211
- const [longitudeText, setLongitudeText] = useState(geoLocation.longitude?.toString());
212
- const [latitudeText, setLatitudeText] = useState(geoLocation.latitude?.toString());
213
- useEffect(() => {
214
- const location = GeoLocation.fromGeoPoint(geoPoint);
215
- setLongitudeText(location.longitude.toString());
216
- setLatitudeText(location.latitude.toString());
217
- }, [
218
- geoPoint
219
- ]);
220
- const handleCoordinateChange = useCallback((coordinateType, setText) => (event) => {
221
- const inputText = event.target.value;
222
- setText(inputText);
223
- if (inputText !== "" && inputText !== "-") {
224
- const coord = safeParseFloat(inputText);
225
- if (coord !== void 0 && !isNaN(coord)) {
226
- const currentLocation = GeoLocation.fromGeoPoint(getValue3() ?? [
227
- 0,
228
- 0
229
- ]);
230
- const newLocation = {
231
- ...currentLocation,
232
- [coordinateType]: coord
233
- };
234
- const newValue = GeoLocation.toGeoPoint(newLocation);
235
- onValueChange(type, newValue);
292
+ var _effect = _useSignals4();
293
+ try {
294
+ const { t } = useTranslation2(translationKey);
295
+ const { status, error } = getStatus();
296
+ const geoPoint = useMemo(() => getValue3() ?? [
297
+ 0,
298
+ 0
299
+ ], [
300
+ getValue3
301
+ ]);
302
+ const geoLocation = useMemo(() => GeoLocation.fromGeoPoint(geoPoint), [
303
+ geoPoint
304
+ ]);
305
+ const [longitudeText, setLongitudeText] = useState(geoLocation.longitude?.toString());
306
+ const [latitudeText, setLatitudeText] = useState(geoLocation.latitude?.toString());
307
+ useEffect(() => {
308
+ const location = GeoLocation.fromGeoPoint(geoPoint);
309
+ setLongitudeText(location.longitude.toString());
310
+ setLatitudeText(location.latitude.toString());
311
+ }, [
312
+ geoPoint
313
+ ]);
314
+ const handleCoordinateChange = useCallback((coordinateType, setText) => (event) => {
315
+ const inputText = event.target.value;
316
+ setText(inputText);
317
+ if (inputText !== "" && inputText !== "-") {
318
+ const coord = safeParseFloat(inputText);
319
+ if (coord !== void 0 && !isNaN(coord)) {
320
+ const currentLocation = GeoLocation.fromGeoPoint(getValue3() ?? [
321
+ 0,
322
+ 0
323
+ ]);
324
+ const newLocation = {
325
+ ...currentLocation,
326
+ [coordinateType]: coord
327
+ };
328
+ const newValue = GeoLocation.toGeoPoint(newLocation);
329
+ onValueChange(type, newValue);
330
+ }
236
331
  }
237
- }
238
- }, [
239
- getValue3,
240
- onValueChange,
241
- type
242
- ]);
243
- return /* @__PURE__ */ React4.createElement(Input3.Root, {
244
- validationValence: status
245
- }, /* @__PURE__ */ React4.createElement(InputHeader, {
246
- error
247
- }, /* @__PURE__ */ React4.createElement(Input3.Label, null, label)), /* @__PURE__ */ React4.createElement("div", {
248
- role: "none",
249
- className: "grid grid-cols-2 gap-2"
250
- }, /* @__PURE__ */ React4.createElement(Input3.TextInput, {
251
- type: "text",
252
- pattern: "^-?[0-9]*\\.?[0-9]*$",
253
- disabled,
254
- placeholder: t("placeholder latitude"),
255
- value: latitudeText,
256
- onChange: handleCoordinateChange("latitude", setLatitudeText),
257
- onBlur
258
- }), /* @__PURE__ */ React4.createElement(Input3.TextInput, {
259
- type: "text",
260
- pattern: "^-?[0-9]*\\.?[0-9]*$",
261
- disabled,
262
- placeholder: t("placeholder longitude"),
263
- value: longitudeText,
264
- onChange: handleCoordinateChange("longitude", setLongitudeText),
265
- onBlur
266
- })));
332
+ }, [
333
+ getValue3,
334
+ onValueChange,
335
+ type
336
+ ]);
337
+ return /* @__PURE__ */ React4.createElement(Input3.Root, {
338
+ validationValence: status
339
+ }, /* @__PURE__ */ React4.createElement(InputHeader, {
340
+ error
341
+ }, /* @__PURE__ */ React4.createElement(Input3.Label, null, label)), /* @__PURE__ */ React4.createElement("div", {
342
+ role: "none",
343
+ className: "grid grid-cols-2 gap-2"
344
+ }, /* @__PURE__ */ React4.createElement(Input3.TextInput, {
345
+ type: "text",
346
+ pattern: "^-?[0-9]*\\.?[0-9]*$",
347
+ disabled,
348
+ placeholder: t("placeholder latitude"),
349
+ value: latitudeText,
350
+ onChange: handleCoordinateChange("latitude", setLatitudeText),
351
+ onBlur
352
+ }), /* @__PURE__ */ React4.createElement(Input3.TextInput, {
353
+ type: "text",
354
+ pattern: "^-?[0-9]*\\.?[0-9]*$",
355
+ disabled,
356
+ placeholder: t("placeholder longitude"),
357
+ value: longitudeText,
358
+ onChange: handleCoordinateChange("longitude", setLongitudeText),
359
+ onBlur
360
+ })));
361
+ } finally {
362
+ _effect.f();
363
+ }
267
364
  };
268
365
 
269
366
  // packages/ui/react-ui-form/src/components/Form/custom/SelectOptionsInput.tsx
367
+ import { useSignals as _useSignals5 } from "@preact-signals/safe-react/tracking";
270
368
  import React5, { useCallback as useCallback2, useEffect as useEffect2, useState as useState2, useRef } from "react";
271
369
  import { PublicKey } from "@dxos/keys";
272
370
  import { Icon as Icon2, IconButton, Input as Input4, Tag, Toolbar, useTranslation as useTranslation3 } from "@dxos/react-ui";
273
371
  import { List } from "@dxos/react-ui-list";
274
372
  import { HuePicker } from "@dxos/react-ui-pickers";
275
- import { hues, mx as mx2 } from "@dxos/react-ui-theme";
373
+ import { hues, mx as mx3 } from "@dxos/react-ui-theme";
276
374
  var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3, onValueChange }) => {
277
- const [selected, setSelectedId] = useState2(null);
278
- const [isNewOption, setIsNewOption] = useState2(false);
279
- const inputRef = useRef(null);
280
- const { t } = useTranslation3(translationKey);
281
- const { status, error } = getStatus();
282
- const options = getValue3();
283
- useEffect2(() => {
284
- if (options === void 0) {
285
- onValueChange(type, []);
286
- }
287
- }, [
288
- options,
289
- onValueChange,
290
- type
291
- ]);
292
- const randomHue = () => {
293
- const usedHues = new Set(options?.map((option) => option.color) ?? []);
294
- const unusedHues = hues.filter((hue) => !usedHues.has(hue));
295
- if (unusedHues.length > 0) {
296
- return unusedHues[Math.floor(Math.random() * unusedHues.length)];
297
- }
298
- const lastThree = new Set(options?.slice(-3).map((option) => option.color) ?? []);
299
- const availableHues = hues.filter((hue) => !lastThree.has(hue));
300
- return availableHues[Math.floor(Math.random() * availableHues.length)] ?? hues[Math.floor(Math.random() * hues.length)];
301
- };
302
- const handleAdd = useCallback2(() => {
303
- const newId = PublicKey.random().truncate();
304
- const newOption = {
305
- id: newId,
306
- title: "",
307
- color: randomHue()
375
+ var _effect = _useSignals5();
376
+ try {
377
+ const [selected, setSelectedId] = useState2(null);
378
+ const [isNewOption, setIsNewOption] = useState2(false);
379
+ const inputRef = useRef(null);
380
+ const { t } = useTranslation3(translationKey);
381
+ const { status, error } = getStatus();
382
+ const options = getValue3();
383
+ useEffect2(() => {
384
+ if (options === void 0) {
385
+ onValueChange(type, []);
386
+ }
387
+ }, [
388
+ options,
389
+ onValueChange,
390
+ type
391
+ ]);
392
+ const randomHue = () => {
393
+ const usedHues = new Set(options?.map((option) => option.color) ?? []);
394
+ const unusedHues = hues.filter((hue) => !usedHues.has(hue));
395
+ if (unusedHues.length > 0) {
396
+ return unusedHues[Math.floor(Math.random() * unusedHues.length)];
397
+ }
398
+ const lastThree = new Set(options?.slice(-3).map((option) => option.color) ?? []);
399
+ const availableHues = hues.filter((hue) => !lastThree.has(hue));
400
+ return availableHues[Math.floor(Math.random() * availableHues.length)] ?? hues[Math.floor(Math.random() * hues.length)];
308
401
  };
309
- onValueChange(type, [
310
- ...options ?? [],
311
- newOption
402
+ const handleAdd = useCallback2(() => {
403
+ const newId = PublicKey.random().truncate();
404
+ const newOption = {
405
+ id: newId,
406
+ title: "",
407
+ color: randomHue()
408
+ };
409
+ onValueChange(type, [
410
+ ...options ?? [],
411
+ newOption
412
+ ]);
413
+ setSelectedId(newId);
414
+ setIsNewOption(true);
415
+ }, [
416
+ options,
417
+ type,
418
+ onValueChange
312
419
  ]);
313
- setSelectedId(newId);
314
- setIsNewOption(true);
315
- }, [
316
- options,
317
- type,
318
- onValueChange
319
- ]);
320
- const handleDelete = useCallback2((id) => {
321
- const newOptions = options?.filter((option) => option.id !== id) ?? [];
322
- onValueChange(type, newOptions);
323
- setSelectedId(null);
324
- }, [
325
- options,
326
- type,
327
- onValueChange
328
- ]);
329
- const handleMove = useCallback2((from, to) => {
330
- if (!options) {
331
- return;
332
- }
333
- const newOptions = [
334
- ...options
335
- ];
336
- const [removed] = newOptions.splice(from, 1);
337
- newOptions.splice(to, 0, removed);
338
- onValueChange(type, newOptions);
339
- }, [
340
- options,
341
- type,
342
- onValueChange
343
- ]);
344
- const handleClick = useCallback2((id) => {
345
- setSelectedId((current) => current === id ? null : id);
346
- }, []);
347
- const handleTitleChange = useCallback2((id) => (e) => {
348
- const newOptions = options?.map((o) => o.id === id ? {
349
- ...o,
350
- title: e.target.value
351
- } : o);
352
- onValueChange(type, newOptions ?? []);
353
- }, [
354
- options,
355
- type,
356
- onValueChange
357
- ]);
358
- const handleKeyDown = useCallback2((e) => {
359
- if (e.key === "Enter") {
420
+ const handleDelete = useCallback2((id) => {
421
+ const newOptions = options?.filter((option) => option.id !== id) ?? [];
422
+ onValueChange(type, newOptions);
360
423
  setSelectedId(null);
361
- }
362
- }, []);
363
- const handleColorChange = useCallback2((id) => (hue) => {
364
- const newOptions = options?.map((o) => o.id === id ? {
365
- ...o,
366
- color: hue
367
- } : o);
368
- onValueChange(type, newOptions ?? []);
369
- }, [
370
- options,
371
- type,
372
- onValueChange
373
- ]);
374
- useEffect2(() => {
375
- if (selected && isNewOption && inputRef.current) {
376
- inputRef.current.focus();
377
- setIsNewOption(false);
378
- }
379
- }, [
380
- selected,
381
- isNewOption
382
- ]);
383
- return /* @__PURE__ */ React5.createElement(Input4.Root, {
384
- validationValence: status
385
- }, /* @__PURE__ */ React5.createElement(InputHeader, {
386
- error
387
- }, /* @__PURE__ */ React5.createElement(Input4.Label, null, label)), /* @__PURE__ */ React5.createElement("div", {
388
- role: "none"
389
- }, options && /* @__PURE__ */ React5.createElement(List.Root, {
390
- items: options,
391
- isItem: (item) => true,
392
- onMove: handleMove
393
- }, ({ items }) => /* @__PURE__ */ React5.createElement("div", {
394
- role: "list",
395
- className: "w-full overflow-auto"
396
- }, items?.map((item) => /* @__PURE__ */ React5.createElement("div", {
397
- key: item.id
398
- }, /* @__PURE__ */ React5.createElement(List.Item, {
399
- role: "button",
400
- item,
401
- classNames: mx2("p-1 plb-2", "flex flex-col", "cursor-pointer", "hover:bg-hoverOverlay"),
402
- "aria-expanded": selected === item.id
403
- }, /* @__PURE__ */ React5.createElement("div", {
404
- className: "flex items-center"
405
- }, /* @__PURE__ */ React5.createElement(List.ItemDragHandle, null), /* @__PURE__ */ React5.createElement(List.ItemTitle, {
406
- onClick: () => handleClick(item.id),
407
- classNames: "flex-1"
408
- }, /* @__PURE__ */ React5.createElement(Tag, {
409
- palette: item.color
410
- }, item.title || "\u200B")), /* @__PURE__ */ React5.createElement(Icon2, {
411
- icon: selected === item.id ? "ph--caret-down--regular" : "ph--caret-right--regular",
412
- onClick: () => handleClick(item.id)
413
- })), selected === item.id && /* @__PURE__ */ React5.createElement("div", {
414
- className: "mis-4 mbs-2 flex flex-col gap-1"
415
- }, /* @__PURE__ */ React5.createElement(Input4.Label, {
416
- classNames: "text-xs"
417
- }, t("select option label")), /* @__PURE__ */ React5.createElement("div", {
418
- className: "flex flex-row items-center gap-1"
419
- }, /* @__PURE__ */ React5.createElement(Input4.TextInput, {
420
- placeholder: t("select option label placeholder"),
421
- ref: selected === item.id ? inputRef : void 0,
422
- value: item.title,
423
- onChange: handleTitleChange(item.id),
424
- onKeyDown: handleKeyDown,
425
- classNames: "flex-1",
426
- "data-no-submit": true
427
- }), /* @__PURE__ */ React5.createElement(Toolbar.Root, {
428
- classNames: "p-0 m-0 !is-auto"
429
- }, /* @__PURE__ */ React5.createElement(HuePicker, {
430
- value: item.color,
431
- onChange: handleColorChange(item.id),
432
- rootVariant: "toolbar-button"
433
- })), /* @__PURE__ */ React5.createElement(IconButton, {
434
- icon: "ph--trash--fill",
435
- iconOnly: true,
436
- label: t("select option delete"),
437
- onClick: () => handleDelete(item.id)
438
- })))))), /* @__PURE__ */ React5.createElement("div", {
439
- role: "listitem"
440
- }, /* @__PURE__ */ React5.createElement("div", {
441
- role: "button",
442
- className: mx2("p-1 plb-2", "flex flex-col", "cursor-pointer", "hover:bg-hoverOverlay"),
443
- onClick: handleAdd
444
- }, /* @__PURE__ */ React5.createElement("div", {
445
- className: "flex items-center gap-1"
446
- }, /* @__PURE__ */ React5.createElement(Icon2, {
447
- icon: "ph--plus--regular"
448
- }), /* @__PURE__ */ React5.createElement("span", {
449
- className: "text-sm"
450
- }, t("select option add")))))))));
424
+ }, [
425
+ options,
426
+ type,
427
+ onValueChange
428
+ ]);
429
+ const handleMove = useCallback2((from, to) => {
430
+ if (!options) {
431
+ return;
432
+ }
433
+ const newOptions = [
434
+ ...options
435
+ ];
436
+ const [removed] = newOptions.splice(from, 1);
437
+ newOptions.splice(to, 0, removed);
438
+ onValueChange(type, newOptions);
439
+ }, [
440
+ options,
441
+ type,
442
+ onValueChange
443
+ ]);
444
+ const handleClick = useCallback2((id) => {
445
+ setSelectedId((current) => current === id ? null : id);
446
+ }, []);
447
+ const handleTitleChange = useCallback2((id) => (e) => {
448
+ const newOptions = options?.map((o) => o.id === id ? {
449
+ ...o,
450
+ title: e.target.value
451
+ } : o);
452
+ onValueChange(type, newOptions ?? []);
453
+ }, [
454
+ options,
455
+ type,
456
+ onValueChange
457
+ ]);
458
+ const handleKeyDown = useCallback2((e) => {
459
+ if (e.key === "Enter") {
460
+ setSelectedId(null);
461
+ }
462
+ }, []);
463
+ const handleColorChange = useCallback2((id) => (hue) => {
464
+ const newOptions = options?.map((o) => o.id === id ? {
465
+ ...o,
466
+ color: hue
467
+ } : o);
468
+ onValueChange(type, newOptions ?? []);
469
+ }, [
470
+ options,
471
+ type,
472
+ onValueChange
473
+ ]);
474
+ useEffect2(() => {
475
+ if (selected && isNewOption && inputRef.current) {
476
+ inputRef.current.focus();
477
+ setIsNewOption(false);
478
+ }
479
+ }, [
480
+ selected,
481
+ isNewOption
482
+ ]);
483
+ return /* @__PURE__ */ React5.createElement(Input4.Root, {
484
+ validationValence: status
485
+ }, /* @__PURE__ */ React5.createElement(InputHeader, {
486
+ error
487
+ }, /* @__PURE__ */ React5.createElement(Input4.Label, null, label)), /* @__PURE__ */ React5.createElement("div", {
488
+ role: "none"
489
+ }, options && /* @__PURE__ */ React5.createElement(List.Root, {
490
+ items: options,
491
+ isItem: (item) => true,
492
+ onMove: handleMove
493
+ }, ({ items }) => /* @__PURE__ */ React5.createElement("div", {
494
+ role: "list",
495
+ className: "w-full overflow-auto"
496
+ }, items?.map((item) => /* @__PURE__ */ React5.createElement("div", {
497
+ key: item.id
498
+ }, /* @__PURE__ */ React5.createElement(List.Item, {
499
+ role: "button",
500
+ item,
501
+ classNames: mx3("p-1 plb-2", "flex flex-col", "cursor-pointer", "hover:bg-hoverOverlay"),
502
+ "aria-expanded": selected === item.id
503
+ }, /* @__PURE__ */ React5.createElement("div", {
504
+ className: "flex items-center"
505
+ }, /* @__PURE__ */ React5.createElement(List.ItemDragHandle, null), /* @__PURE__ */ React5.createElement(List.ItemTitle, {
506
+ onClick: () => handleClick(item.id),
507
+ classNames: "flex-1"
508
+ }, /* @__PURE__ */ React5.createElement(Tag, {
509
+ palette: item.color
510
+ }, item.title || "\u200B")), /* @__PURE__ */ React5.createElement(Icon2, {
511
+ icon: selected === item.id ? "ph--caret-down--regular" : "ph--caret-right--regular",
512
+ onClick: () => handleClick(item.id)
513
+ })), selected === item.id && /* @__PURE__ */ React5.createElement("div", {
514
+ className: "mis-4 mbs-2 flex flex-col gap-1"
515
+ }, /* @__PURE__ */ React5.createElement(Input4.Label, {
516
+ classNames: "text-xs"
517
+ }, t("select option label")), /* @__PURE__ */ React5.createElement("div", {
518
+ className: "flex flex-row items-center gap-1"
519
+ }, /* @__PURE__ */ React5.createElement(Input4.TextInput, {
520
+ placeholder: t("select option label placeholder"),
521
+ ref: selected === item.id ? inputRef : void 0,
522
+ value: item.title,
523
+ onChange: handleTitleChange(item.id),
524
+ onKeyDown: handleKeyDown,
525
+ classNames: "flex-1",
526
+ "data-no-submit": true
527
+ }), /* @__PURE__ */ React5.createElement(Toolbar.Root, {
528
+ classNames: "p-0 m-0 !is-auto"
529
+ }, /* @__PURE__ */ React5.createElement(HuePicker, {
530
+ value: item.color,
531
+ onChange: handleColorChange(item.id),
532
+ rootVariant: "toolbar-button"
533
+ })), /* @__PURE__ */ React5.createElement(IconButton, {
534
+ icon: "ph--trash--fill",
535
+ iconOnly: true,
536
+ label: t("select option delete"),
537
+ onClick: () => handleDelete(item.id)
538
+ })))))), /* @__PURE__ */ React5.createElement("div", {
539
+ role: "listitem"
540
+ }, /* @__PURE__ */ React5.createElement("div", {
541
+ role: "button",
542
+ className: mx3("p-1 plb-2", "flex flex-col", "cursor-pointer", "hover:bg-hoverOverlay"),
543
+ onClick: handleAdd
544
+ }, /* @__PURE__ */ React5.createElement("div", {
545
+ className: "flex items-center gap-1"
546
+ }, /* @__PURE__ */ React5.createElement(Icon2, {
547
+ icon: "ph--plus--regular"
548
+ }), /* @__PURE__ */ React5.createElement("span", {
549
+ className: "text-sm"
550
+ }, t("select option add")))))))));
551
+ } finally {
552
+ _effect.f();
553
+ }
451
554
  };
452
555
 
453
556
  // packages/ui/react-ui-form/src/components/Form/custom/TupleInput.tsx
557
+ import { useSignals as _useSignals6 } from "@preact-signals/safe-react/tracking";
454
558
  import React6 from "react";
455
559
  import { Input as Input5 } from "@dxos/react-ui";
456
- import { mx as mx3 } from "@dxos/react-ui-theme";
560
+ import { mx as mx4 } from "@dxos/react-ui-theme";
457
561
  import { safeParseFloat as safeParseFloat2 } from "@dxos/util";
458
562
  var gridCols = [
459
563
  "grid-cols-1",
@@ -462,149 +566,188 @@ var gridCols = [
462
566
  "grid-cols-4"
463
567
  ];
464
568
  var TupleInput = ({ binding, type, label, disabled, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
465
- const { status, error } = getStatus();
466
- const values = getValue3() ?? {};
467
- return /* @__PURE__ */ React6.createElement(Input5.Root, {
468
- validationValence: status
469
- }, /* @__PURE__ */ React6.createElement(InputHeader, {
470
- error
471
- }, /* @__PURE__ */ React6.createElement(Input5.Label, null, label)), /* @__PURE__ */ React6.createElement("div", {
472
- className: mx3("grid gap-2", gridCols[binding.length - 1])
473
- }, binding.map((prop) => /* @__PURE__ */ React6.createElement(Input5.TextInput, {
474
- key: prop,
475
- type: "number",
476
- disabled,
477
- value: values[prop],
478
- onChange: (event) => onValueChange(type, {
479
- ...values,
480
- [prop]: safeParseFloat2(event.target.value, 0)
481
- }),
482
- onBlur
483
- }))));
569
+ var _effect = _useSignals6();
570
+ try {
571
+ const { status, error } = getStatus();
572
+ const values = getValue3() ?? {};
573
+ return /* @__PURE__ */ React6.createElement(Input5.Root, {
574
+ validationValence: status
575
+ }, /* @__PURE__ */ React6.createElement(InputHeader, {
576
+ error
577
+ }, /* @__PURE__ */ React6.createElement(Input5.Label, null, label)), /* @__PURE__ */ React6.createElement("div", {
578
+ className: mx4("grid gap-2", gridCols[binding.length - 1])
579
+ }, binding.map((prop) => /* @__PURE__ */ React6.createElement(Input5.TextInput, {
580
+ key: prop,
581
+ type: "number",
582
+ disabled,
583
+ value: values[prop],
584
+ onChange: (event) => onValueChange(type, {
585
+ ...values,
586
+ [prop]: safeParseFloat2(event.target.value, 0)
587
+ }),
588
+ onBlur
589
+ }))));
590
+ } finally {
591
+ _effect.f();
592
+ }
484
593
  };
485
594
 
486
595
  // packages/ui/react-ui-form/src/components/Form/Defaults.tsx
596
+ import { useSignals as _useSignals7 } from "@preact-signals/safe-react/tracking";
487
597
  import React7, { useCallback as useCallback3, useEffect as useEffect3, useRef as useRef2 } from "react";
488
- import { Input as Input6, Select } from "@dxos/react-ui";
598
+ import { Input as Input6, Select, useTranslation as useTranslation4 } from "@dxos/react-ui";
489
599
  var TextInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
490
- const { status, error } = getStatus();
491
- return /* @__PURE__ */ React7.createElement(Input6.Root, {
492
- validationValence: status
493
- }, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
494
- error
495
- }, /* @__PURE__ */ React7.createElement(Input6.Label, null, label)), /* @__PURE__ */ React7.createElement(Input6.TextInput, {
496
- disabled,
497
- placeholder,
498
- value: getValue3() ?? "",
499
- onChange: (event) => onValueChange(type, event.target.value),
500
- onBlur
501
- }), inputOnly && /* @__PURE__ */ React7.createElement(Input6.Validation, null, error));
600
+ var _effect = _useSignals7();
601
+ try {
602
+ const { status, error } = getStatus();
603
+ return disabled && !getValue3() ? null : disabled && inputOnly ? /* @__PURE__ */ React7.createElement("p", null, getValue3() ?? "") : /* @__PURE__ */ React7.createElement(Input6.Root, {
604
+ validationValence: status
605
+ }, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
606
+ error
607
+ }, /* @__PURE__ */ React7.createElement(Input6.Label, null, label)), disabled ? /* @__PURE__ */ React7.createElement("p", null, getValue3() ?? "") : /* @__PURE__ */ React7.createElement(Input6.TextInput, {
608
+ disabled,
609
+ placeholder,
610
+ value: getValue3() ?? "",
611
+ onChange: (event) => onValueChange(type, event.target.value),
612
+ onBlur
613
+ }), inputOnly && /* @__PURE__ */ React7.createElement(Input6.Validation, null, error));
614
+ } finally {
615
+ _effect.f();
616
+ }
502
617
  };
503
618
  var NumberInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
504
- const { status, error } = getStatus();
505
- return /* @__PURE__ */ React7.createElement(Input6.Root, {
506
- validationValence: status
507
- }, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
508
- error
509
- }, /* @__PURE__ */ React7.createElement(Input6.Label, null, label)), /* @__PURE__ */ React7.createElement(Input6.TextInput, {
510
- type: "number",
511
- disabled,
512
- placeholder,
513
- value: getValue3() ?? 0,
514
- onChange: (event) => onValueChange(type, event.target.value),
515
- onBlur
516
- }), inputOnly && /* @__PURE__ */ React7.createElement(Input6.DescriptionAndValidation, null, error));
619
+ var _effect = _useSignals7();
620
+ try {
621
+ const { status, error } = getStatus();
622
+ return disabled && !getValue3() ? null : disabled && inputOnly ? /* @__PURE__ */ React7.createElement("p", null, getValue3() ?? "") : /* @__PURE__ */ React7.createElement(Input6.Root, {
623
+ validationValence: status
624
+ }, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
625
+ error
626
+ }, /* @__PURE__ */ React7.createElement(Input6.Label, null, label)), disabled ? /* @__PURE__ */ React7.createElement("p", null, getValue3() ?? "") : /* @__PURE__ */ React7.createElement(Input6.TextInput, {
627
+ type: "number",
628
+ disabled,
629
+ placeholder,
630
+ value: getValue3() ?? 0,
631
+ onChange: (event) => onValueChange(type, event.target.value),
632
+ onBlur
633
+ }), inputOnly && /* @__PURE__ */ React7.createElement(Input6.DescriptionAndValidation, null, error));
634
+ } finally {
635
+ _effect.f();
636
+ }
517
637
  };
518
- var BooleanInput = ({ type, label, inputOnly, getStatus, getValue: getValue3, onValueChange }) => {
519
- const { status, error } = getStatus();
520
- const checked = Boolean(getValue3());
521
- return /* @__PURE__ */ React7.createElement(Input6.Root, {
522
- validationValence: status
523
- }, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
524
- error
525
- }, /* @__PURE__ */ React7.createElement(Input6.Label, null, label)), /* @__PURE__ */ React7.createElement(Input6.Switch, {
526
- checked,
527
- onCheckedChange: (value) => onValueChange(type, value)
528
- }), inputOnly && /* @__PURE__ */ React7.createElement(Input6.DescriptionAndValidation, null, error));
638
+ var BooleanInput = ({ type, label, inputOnly, getStatus, getValue: getValue3, onValueChange, disabled }) => {
639
+ var _effect = _useSignals7();
640
+ try {
641
+ const { status, error } = getStatus();
642
+ const checked = Boolean(getValue3());
643
+ const { t } = useTranslation4(translationKey);
644
+ return /* @__PURE__ */ React7.createElement(Input6.Root, {
645
+ validationValence: status
646
+ }, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
647
+ error
648
+ }, /* @__PURE__ */ React7.createElement(Input6.Label, null, label)), disabled ? /* @__PURE__ */ React7.createElement("p", null, t(checked ? "boolean input true value" : "boolean input false value")) : /* @__PURE__ */ React7.createElement(Input6.Switch, {
649
+ checked,
650
+ onCheckedChange: (value) => onValueChange(type, value)
651
+ }), inputOnly && /* @__PURE__ */ React7.createElement(Input6.DescriptionAndValidation, null, error));
652
+ } finally {
653
+ _effect.f();
654
+ }
529
655
  };
530
656
  var SelectInput = ({ type, label, inputOnly, disabled, placeholder, options, getStatus, getValue: getValue3, onValueChange }) => {
531
- const { status, error } = getStatus();
532
- return /* @__PURE__ */ React7.createElement(Input6.Root, {
533
- validationValence: status
534
- }, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
535
- error
536
- }, /* @__PURE__ */ React7.createElement(Input6.Label, null, label)), /* @__PURE__ */ React7.createElement(Select.Root, {
537
- value: getValue3(),
538
- onValueChange: (value) => onValueChange(type, value)
539
- }, /* @__PURE__ */ React7.createElement(Select.TriggerButton, {
540
- classNames: "is-full",
541
- disabled,
542
- placeholder
543
- }), /* @__PURE__ */ React7.createElement(Select.Portal, null, /* @__PURE__ */ React7.createElement(Select.Content, null, /* @__PURE__ */ React7.createElement(Select.Viewport, null, options?.map(({ value, label: label2 }) => (
544
- // NOTE: Numeric values are converted to and from strings.
545
- /* @__PURE__ */ React7.createElement(Select.Option, {
546
- key: String(value),
547
- value: String(value)
548
- }, label2 ?? String(value))
549
- )))))), inputOnly && /* @__PURE__ */ React7.createElement(Input6.DescriptionAndValidation, null, error));
657
+ var _effect = _useSignals7();
658
+ try {
659
+ const { status, error } = getStatus();
660
+ const value = getValue3();
661
+ const handleValueChange = useCallback3((value2) => onValueChange(type, value2), [
662
+ type,
663
+ onValueChange
664
+ ]);
665
+ return disabled && !value ? null : /* @__PURE__ */ React7.createElement(Input6.Root, {
666
+ validationValence: status
667
+ }, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
668
+ error
669
+ }, /* @__PURE__ */ React7.createElement(Input6.Label, null, label)), disabled ? /* @__PURE__ */ React7.createElement("p", null, options?.find(({ value: optionValue }) => optionValue === value)?.label ?? String(value)) : /* @__PURE__ */ React7.createElement(Select.Root, {
670
+ value,
671
+ onValueChange: handleValueChange
672
+ }, /* @__PURE__ */ React7.createElement(Select.TriggerButton, {
673
+ classNames: "is-full",
674
+ disabled,
675
+ placeholder
676
+ }), /* @__PURE__ */ React7.createElement(Select.Portal, null, /* @__PURE__ */ React7.createElement(Select.Content, null, /* @__PURE__ */ React7.createElement(Select.Viewport, null, options?.map(({ value: value2, label: label2 }) => (
677
+ // NOTE: Numeric values are converted to and from strings.
678
+ /* @__PURE__ */ React7.createElement(Select.Option, {
679
+ key: String(value2),
680
+ value: String(value2)
681
+ }, label2 ?? String(value2))
682
+ )))))), inputOnly && /* @__PURE__ */ React7.createElement(Input6.DescriptionAndValidation, null, error));
683
+ } finally {
684
+ _effect.f();
685
+ }
550
686
  };
551
687
  var MarkdownInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
552
- const { status, error } = getStatus();
553
- const textareaRef = useRef2(null);
554
- const adjustHeight = useCallback3(() => {
555
- const textarea = textareaRef.current;
556
- if (textarea) {
557
- textarea.style.blockSize = "auto";
558
- textarea.style.blockSize = `${textarea.scrollHeight + 2}px`;
559
- }
560
- }, []);
561
- useEffect3(() => {
562
- adjustHeight();
563
- }, [
564
- adjustHeight
565
- ]);
566
- useEffect3(() => {
567
- adjustHeight();
568
- }, [
569
- getValue3(),
570
- adjustHeight
571
- ]);
572
- return /* @__PURE__ */ React7.createElement(Input6.Root, {
573
- validationValence: status
574
- }, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
575
- error
576
- }, /* @__PURE__ */ React7.createElement(Input6.Label, null, label)), /* @__PURE__ */ React7.createElement(Input6.TextArea, {
577
- ref: textareaRef,
578
- disabled,
579
- placeholder,
580
- value: getValue3() ?? "",
581
- classNames: "min-bs-auto max-h-40 overflow-auto",
582
- onChange: (event) => onValueChange(type, event.target.value),
583
- onBlur,
584
- style: {
585
- resize: "none"
586
- },
587
- spellCheck: false
588
- }), inputOnly && /* @__PURE__ */ React7.createElement(Input6.Validation, null, error));
688
+ var _effect = _useSignals7();
689
+ try {
690
+ const { status, error } = getStatus();
691
+ const textareaRef = useRef2(null);
692
+ const adjustHeight = useCallback3(() => {
693
+ const textarea = textareaRef.current;
694
+ if (textarea) {
695
+ textarea.style.blockSize = "auto";
696
+ textarea.style.blockSize = `${textarea.scrollHeight + 2}px`;
697
+ }
698
+ }, []);
699
+ useEffect3(() => {
700
+ adjustHeight();
701
+ }, [
702
+ adjustHeight
703
+ ]);
704
+ useEffect3(() => {
705
+ adjustHeight();
706
+ }, [
707
+ getValue3(),
708
+ adjustHeight
709
+ ]);
710
+ return /* @__PURE__ */ React7.createElement(Input6.Root, {
711
+ validationValence: status
712
+ }, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
713
+ error
714
+ }, /* @__PURE__ */ React7.createElement(Input6.Label, null, label)), disabled ? /* @__PURE__ */ React7.createElement("p", null, getValue3() ?? "") : /* @__PURE__ */ React7.createElement(Input6.TextArea, {
715
+ ref: textareaRef,
716
+ disabled,
717
+ placeholder,
718
+ value: getValue3() ?? "",
719
+ classNames: "min-bs-auto max-h-40 overflow-auto",
720
+ onChange: (event) => onValueChange(type, event.target.value),
721
+ onBlur,
722
+ style: {
723
+ resize: "none"
724
+ },
725
+ spellCheck: false
726
+ }), inputOnly && /* @__PURE__ */ React7.createElement(Input6.Validation, null, error));
727
+ } finally {
728
+ _effect.f();
729
+ }
589
730
  };
590
731
 
591
732
  // packages/ui/react-ui-form/src/components/Form/Form.tsx
592
- import React12, { useEffect as useEffect6, useMemo as useMemo6, useRef as useRef3 } from "react";
733
+ import { useSignals as _useSignals13 } from "@preact-signals/safe-react/tracking";
734
+ import React13, { useEffect as useEffect7, useMemo as useMemo6, useRef as useRef3 } from "react";
593
735
  import { mx as mx7 } from "@dxos/react-ui-theme";
594
736
 
595
737
  // packages/ui/react-ui-form/src/components/Form/FormActions.tsx
738
+ import { useSignals as _useSignals9 } from "@preact-signals/safe-react/tracking";
596
739
  import React9 from "react";
597
- import { IconButton as IconButton2, useTranslation as useTranslation4 } from "@dxos/react-ui";
598
- import { mx as mx4 } from "@dxos/react-ui-theme";
740
+ import { IconButton as IconButton2, useTranslation as useTranslation5 } from "@dxos/react-ui";
599
741
 
600
742
  // packages/ui/react-ui-form/src/components/Form/FormContext.tsx
601
- import React8, { createContext, useContext, useEffect as useEffect5, useMemo as useMemo3 } from "react";
743
+ import { useSignals as _useSignals8 } from "@preact-signals/safe-react/tracking";
744
+ import React8, { createContext, useContext, useEffect as useEffect6, useMemo as useMemo3, useCallback as useCallback6 } from "react";
602
745
  import { raise } from "@dxos/debug";
603
746
  import { getValue as getValue2 } from "@dxos/echo-schema";
604
747
  import { createJsonPath as createJsonPath2 } from "@dxos/effect";
605
748
 
606
749
  // packages/ui/react-ui-form/src/hooks/useForm.ts
607
- import { SchemaAST as AST } from "effect";
750
+ import { SchemaAST } from "effect";
608
751
  import { useCallback as useCallback4, useEffect as useEffect4, useMemo as useMemo2, useState as useState3 } from "react";
609
752
  import { getValue, setValue } from "@dxos/echo-schema";
610
753
  import { createJsonPath, fromEffectValidationPath } from "@dxos/effect";
@@ -613,12 +756,12 @@ import { log } from "@dxos/log";
613
756
  import { validateSchema } from "@dxos/schema";
614
757
  var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/hooks/useForm.ts";
615
758
  var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, onSave }) => {
616
- invariant(AST.isTypeLiteral(schema.ast), void 0, {
759
+ invariant(SchemaAST.isTypeLiteral(schema.ast), void 0, {
617
760
  F: __dxlog_file,
618
761
  L: 93,
619
762
  S: void 0,
620
763
  A: [
621
- "AST.isTypeLiteral(schema.ast)",
764
+ "SchemaAST.isTypeLiteral(schema.ast)",
622
765
  ""
623
766
  ]
624
767
  });
@@ -719,7 +862,7 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
719
862
  } catch (err) {
720
863
  log.catch(err, void 0, {
721
864
  F: __dxlog_file,
722
- L: 212,
865
+ L: 213,
723
866
  S: void 0,
724
867
  C: (f, a) => f(...a)
725
868
  });
@@ -790,7 +933,7 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
790
933
  var createKeySet = (obj, value) => {
791
934
  invariant(obj, void 0, {
792
935
  F: __dxlog_file,
793
- L: 274,
936
+ L: 275,
794
937
  S: void 0,
795
938
  A: [
796
939
  "obj",
@@ -812,6 +955,80 @@ var flatMap = (errors) => {
812
955
  }, {});
813
956
  };
814
957
 
958
+ // packages/ui/react-ui-form/src/hooks/useRefQueryLookupHandler.ts
959
+ import { useCallback as useCallback5 } from "react";
960
+ import { getObjectDXN } from "@dxos/echo-schema";
961
+ import { Filter } from "@dxos/react-client/echo";
962
+ import { isNonNullable } from "@dxos/util";
963
+ var useRefQueryLookupHandler = ({ space }) => {
964
+ return useCallback5(async (typeInfo) => {
965
+ if (!space) {
966
+ return [];
967
+ }
968
+ const query = space.db.query(Filter.typename(typeInfo.typename));
969
+ const { objects } = await query.run();
970
+ return objects.map((object) => {
971
+ const dxn = getObjectDXN(object);
972
+ if (!dxn) {
973
+ return void 0;
974
+ }
975
+ const item = {
976
+ dxn,
977
+ label: object?.name ?? object?.id ?? ""
978
+ };
979
+ return item;
980
+ }).filter(isNonNullable);
981
+ }, [
982
+ space
983
+ ]);
984
+ };
985
+
986
+ // packages/ui/react-ui-form/src/hooks/useQueryRefOptions.ts
987
+ import { useEffect as useEffect5, useState as useState4 } from "react";
988
+ import { log as log2 } from "@dxos/log";
989
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/hooks/useQueryRefOptions.ts";
990
+ var useQueryRefOptions = ({ refTypeInfo, onQueryRefOptions }) => {
991
+ const [options, setOptions] = useState4([]);
992
+ const [loading, setLoading] = useState4(false);
993
+ useEffect5(() => {
994
+ if (!refTypeInfo || !onQueryRefOptions) {
995
+ return;
996
+ }
997
+ const fetchOptions = async () => {
998
+ setLoading(true);
999
+ try {
1000
+ const fetchedOptions = await onQueryRefOptions(refTypeInfo);
1001
+ setOptions(fetchedOptions.map((option) => {
1002
+ const dxn = option.dxn.toString();
1003
+ return {
1004
+ id: dxn,
1005
+ label: option.label ?? dxn,
1006
+ hue: "neutral"
1007
+ };
1008
+ }));
1009
+ } catch (error) {
1010
+ log2.error("Failed to fetch ref options:", error, {
1011
+ F: __dxlog_file2,
1012
+ L: 42,
1013
+ S: void 0,
1014
+ C: (f, a) => f(...a)
1015
+ });
1016
+ setOptions([]);
1017
+ } finally {
1018
+ setLoading(false);
1019
+ }
1020
+ };
1021
+ void fetchOptions();
1022
+ }, [
1023
+ refTypeInfo,
1024
+ onQueryRefOptions
1025
+ ]);
1026
+ return {
1027
+ options,
1028
+ loading
1029
+ };
1030
+ };
1031
+
815
1032
  // packages/ui/react-ui-form/src/components/Form/FormContext.tsx
816
1033
  var FormContext = /* @__PURE__ */ createContext(void 0);
817
1034
  var useFormContext = () => {
@@ -841,16 +1058,14 @@ var useInputProps = (path = []) => {
841
1058
  ]);
842
1059
  };
843
1060
  var FormProvider = ({ children, formRef, autoSave, ...formOptions }) => {
844
- const form = useForm(formOptions);
845
- useEffect5(() => {
846
- if (!formRef?.current) {
847
- return;
848
- }
849
- const handleKeyDown = (event) => {
1061
+ var _effect = _useSignals8();
1062
+ try {
1063
+ const form = useForm(formOptions);
1064
+ const handleKeyDown = useCallback6((event) => {
850
1065
  const keyIsEnter = event.key === "Enter";
851
1066
  const modifierUsed = event.ctrlKey || event.altKey || event.metaKey || event.shiftKey;
852
1067
  const inputIsTextarea = event.target.tagName.toLowerCase() === "textarea";
853
- const inputOptOut = event.target.hasAttribute("data-no-submit");
1068
+ const inputOptOut = event.target.hasAttribute("data-no-submit") || event.target.closest("[data-no-submit]") !== null;
854
1069
  const shouldSubmitRegularInput = !inputIsTextarea && keyIsEnter && !modifierUsed;
855
1070
  const shouldSubmitTextarea = inputIsTextarea && keyIsEnter && event.metaKey;
856
1071
  if ((shouldSubmitRegularInput || shouldSubmitTextarea) && !inputOptOut) {
@@ -861,852 +1076,199 @@ var FormProvider = ({ children, formRef, autoSave, ...formOptions }) => {
861
1076
  event.target.blur();
862
1077
  }
863
1078
  }
864
- };
865
- const formElement = formRef.current;
866
- formElement.addEventListener("keydown", handleKeyDown);
867
- return () => formElement.removeEventListener("keydown", handleKeyDown);
868
- }, [
869
- formRef,
870
- form.canSave,
871
- form.formIsValid,
872
- form.handleSave,
873
- autoSave
874
- ]);
875
- return /* @__PURE__ */ React8.createElement(FormContext.Provider, {
876
- value: form
877
- }, children);
1079
+ }, [
1080
+ form,
1081
+ autoSave
1082
+ ]);
1083
+ useEffect6(() => {
1084
+ if (!formRef?.current) {
1085
+ return;
1086
+ }
1087
+ const formElement = formRef.current;
1088
+ formElement.addEventListener("keydown", handleKeyDown);
1089
+ return () => formElement.removeEventListener("keydown", handleKeyDown);
1090
+ }, [
1091
+ formRef,
1092
+ form.canSave,
1093
+ form.formIsValid,
1094
+ form.handleSave,
1095
+ autoSave
1096
+ ]);
1097
+ return /* @__PURE__ */ React8.createElement(FormContext.Provider, {
1098
+ value: form
1099
+ }, children);
1100
+ } finally {
1101
+ _effect.f();
1102
+ }
878
1103
  };
879
1104
 
880
1105
  // packages/ui/react-ui-form/src/components/Form/FormActions.tsx
881
- var FormActions = ({ onCancel, readonly }) => {
882
- const { t } = useTranslation4(translationKey);
883
- const { canSave, handleSave } = useFormContext();
884
- return /* @__PURE__ */ React9.createElement("div", {
885
- role: "none",
886
- className: "mt-2 flex justify-center"
887
- }, /* @__PURE__ */ React9.createElement("div", {
888
- role: "none",
889
- className: mx4(onCancel && !readonly && "grid grid-cols-2 gap-2")
890
- }, onCancel && !readonly && /* @__PURE__ */ React9.createElement(IconButton2, {
891
- "data-testid": "cancel-button",
892
- icon: "ph--x--regular",
893
- label: t("button cancel"),
894
- onClick: onCancel
895
- }), handleSave && /* @__PURE__ */ React9.createElement(IconButton2, {
896
- type: "submit",
897
- "data-testid": "save-button",
898
- disabled: !canSave,
899
- icon: "ph--check--regular",
900
- label: t("button save"),
901
- onClick: handleSave
902
- })));
1106
+ var FormActions = ({ readonly, onCancel }) => {
1107
+ var _effect = _useSignals9();
1108
+ try {
1109
+ const { t } = useTranslation5(translationKey);
1110
+ const { canSave, handleSave } = useFormContext();
1111
+ return /* @__PURE__ */ React9.createElement("div", {
1112
+ role: "none",
1113
+ className: "flex [&_button]:grow gap-1 pli-2 pbe-2"
1114
+ }, onCancel && !readonly && /* @__PURE__ */ React9.createElement(IconButton2, {
1115
+ "data-testid": "cancel-button",
1116
+ icon: "ph--x--regular",
1117
+ label: t("button cancel"),
1118
+ onClick: onCancel
1119
+ }), handleSave && /* @__PURE__ */ React9.createElement(IconButton2, {
1120
+ type: "submit",
1121
+ "data-testid": "save-button",
1122
+ disabled: !canSave,
1123
+ icon: "ph--check--regular",
1124
+ label: t("button save"),
1125
+ onClick: handleSave
1126
+ }));
1127
+ } finally {
1128
+ _effect.f();
1129
+ }
903
1130
  };
904
1131
 
905
1132
  // packages/ui/react-ui-form/src/components/Form/FormContent.tsx
906
- import { pipe as pipe2 } from "effect";
1133
+ import { useSignals as _useSignals12 } from "@preact-signals/safe-react/tracking";
1134
+ import { Schema, SchemaAST as SchemaAST4, pipe as pipe2 } from "effect";
907
1135
  import { capitalize as capitalize2 } from "effect/String";
908
- import React11, { useMemo as useMemo5 } from "react";
909
- import { AST as AST3, S } from "@dxos/echo-schema";
910
- import { createJsonPath as createJsonPath3, findNode as findNode2, getDiscriminatedType as getDiscriminatedType2, isDiscriminatedUnion as isDiscriminatedUnion2 } from "@dxos/effect";
1136
+ import React12, { useMemo as useMemo5 } from "react";
1137
+ import { createJsonPath as createJsonPath3, findNode as findNode3, getDiscriminatedType as getDiscriminatedType2, isDiscriminatedUnion as isDiscriminatedUnion2 } from "@dxos/effect";
911
1138
  import { mx as mx6 } from "@dxos/react-ui-theme";
912
1139
  import { getSchemaProperties as getSchemaProperties2 } from "@dxos/schema";
913
1140
  import { isNotFalsy } from "@dxos/util";
914
1141
 
915
1142
  // packages/ui/react-ui-form/src/components/Form/ArrayField.tsx
916
- import { pipe } from "effect";
1143
+ import { useSignals as _useSignals10 } from "@preact-signals/safe-react/tracking";
1144
+ import { SchemaAST as SchemaAST3, pipe } from "effect";
917
1145
  import { capitalize } from "effect/String";
918
- import React10, { useCallback as useCallback5, useMemo as useMemo4 } from "react";
919
- import { AST as AST2 } from "@dxos/echo-schema";
920
- import { findNode, getDiscriminatedType, isDiscriminatedUnion, SimpleType } from "@dxos/effect";
1146
+ import React10, { Fragment, useCallback as useCallback7 } from "react";
1147
+ import { findNode as findNode2, getDiscriminatedType, isDiscriminatedUnion, SimpleType } from "@dxos/effect";
921
1148
  import { invariant as invariant2 } from "@dxos/invariant";
922
- import { IconButton as IconButton3, useTranslation as useTranslation5 } from "@dxos/react-ui";
923
- import { mx as mx5 } from "@dxos/react-ui-theme";
1149
+ import { IconButton as IconButton3, useTranslation as useTranslation6 } from "@dxos/react-ui";
924
1150
  import { getSchemaProperties } from "@dxos/schema";
925
- var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/Form/ArrayField.tsx";
926
- var padding = "px-2";
927
- var ArrayField = ({ property, readonly, path, inputProps, Custom, lookupComponent }) => {
928
- const { t } = useTranslation5(translationKey);
929
- const { ast, name, type, title } = property;
930
- const values = useFormValues(path ?? []);
931
- invariant2(Array.isArray(values), `Values at path ${path?.join(".")} must be an array.`, {
932
- F: __dxlog_file2,
933
- L: 37,
934
- S: void 0,
935
- A: [
936
- "Array.isArray(values)",
937
- "`Values at path ${path?.join('.')} must be an array.`"
938
- ]
939
- });
940
- const label = title ?? pipe(name, capitalize);
941
- const tupleType = findNode(ast, AST2.isTupleType);
942
- const elementType = tupleType?.rest[0]?.type;
943
- const getDefaultObjectValue = (typeNode) => {
944
- const baseNode = findNode(typeNode, isDiscriminatedUnion);
945
- const typeLiteral = baseNode ? getDiscriminatedType(baseNode, {}) : findNode(typeNode, AST2.isTypeLiteral);
946
- if (!typeLiteral) {
947
- return {};
1151
+
1152
+ // packages/ui/react-ui-form/src/util/field.ts
1153
+ import { FormatEnum, GeoLocation as GeoLocation2, TypeEnum } from "@dxos/echo-schema";
1154
+ var parseValue = ({ type, format, value }) => {
1155
+ if (value === void 0 || value === null || value === "") {
1156
+ return void 0;
1157
+ }
1158
+ const parseScalar = (type2) => {
1159
+ switch (type2) {
1160
+ case TypeEnum.Boolean: {
1161
+ if (typeof value === "string") {
1162
+ const lowercaseValue = value.toLowerCase();
1163
+ if (lowercaseValue === "0" || lowercaseValue === "false") {
1164
+ return false;
1165
+ } else if (lowercaseValue === "1" || lowercaseValue === "true") {
1166
+ return true;
1167
+ }
1168
+ }
1169
+ return Boolean(value);
1170
+ }
1171
+ case TypeEnum.Number: {
1172
+ const cleaned = typeof value === "string" ? value.replace(/[^0-9.-]+/g, "") : value;
1173
+ const num = Number(cleaned);
1174
+ return Number.isNaN(num) ? null : num;
1175
+ }
1176
+ case TypeEnum.String:
1177
+ case TypeEnum.Ref:
1178
+ return String(value);
1179
+ default: {
1180
+ return value;
1181
+ }
948
1182
  }
949
- return Object.fromEntries(getSchemaProperties(typeLiteral, {}).map((prop) => [
950
- prop.name,
951
- prop.defaultValue
952
- ]));
953
1183
  };
954
- const newValue = useMemo4(() => {
955
- if (type === "object" && elementType) {
956
- return getDefaultObjectValue(elementType);
957
- } else {
958
- return SimpleType.getDefaultValue(type);
1184
+ if (!format) {
1185
+ return parseScalar(type);
1186
+ }
1187
+ switch (format) {
1188
+ case FormatEnum.Boolean:
1189
+ return parseScalar(TypeEnum.Boolean);
1190
+ case FormatEnum.Number:
1191
+ case FormatEnum.Percent:
1192
+ case FormatEnum.Currency:
1193
+ return parseScalar(TypeEnum.Number);
1194
+ case FormatEnum.String:
1195
+ case FormatEnum.Markdown: {
1196
+ return parseScalar(TypeEnum.String);
1197
+ }
1198
+ case FormatEnum.Ref:
1199
+ throw new Error(`unexpected format: ${FormatEnum.Ref}`);
1200
+ case FormatEnum.DateTime:
1201
+ case FormatEnum.Date:
1202
+ case FormatEnum.Time:
1203
+ case FormatEnum.Timestamp: {
1204
+ const date = new Date(value);
1205
+ return isNaN(date.getTime()) ? null : date;
1206
+ }
1207
+ case FormatEnum.GeoPoint: {
1208
+ if (typeof value === "string") {
1209
+ const cleaned = value.replace(/[^0-9.,-]+/g, "");
1210
+ const parts = cleaned.split(",");
1211
+ if (parts.length === 2) {
1212
+ const lat = parseFloat(parts[0]);
1213
+ const long = parseFloat(parts[1]);
1214
+ if (!isNaN(lat) && !isNaN(long)) {
1215
+ return GeoLocation2.toGeoPoint({
1216
+ latitude: lat,
1217
+ longitude: long
1218
+ });
1219
+ }
1220
+ }
1221
+ }
1222
+ return [
1223
+ 0,
1224
+ 0
1225
+ ];
1226
+ }
1227
+ default: {
1228
+ return value;
959
1229
  }
960
- }, [
961
- type,
962
- elementType
963
- ]);
964
- const handleAdd = useCallback5(() => {
965
- inputProps.onValueChange(type, [
966
- ...values,
967
- newValue
968
- ]);
969
- }, [
970
- type,
971
- elementType,
972
- inputProps,
973
- newValue,
974
- values
975
- ]);
976
- const handleRemove = useCallback5((index) => {
977
- const newValues = values.filter((_, i) => i !== index);
978
- inputProps.onValueChange(type, newValues);
979
- }, [
980
- type,
981
- inputProps,
982
- values
983
- ]);
984
- if (!elementType) {
985
- return null;
986
1230
  }
987
- return /* @__PURE__ */ React10.createElement("div", {
988
- role: "none",
989
- className: mx5(padding)
990
- }, /* @__PURE__ */ React10.createElement(InputHeader, null, label), /* @__PURE__ */ React10.createElement("div", {
991
- role: "none",
992
- className: "flex flex-col gap-1"
993
- }, values.map((_value, index) => /* @__PURE__ */ React10.createElement("div", {
994
- key: index,
995
- role: "none",
996
- className: "flex items-center gap-1"
997
- }, /* @__PURE__ */ React10.createElement("div", {
998
- role: "none",
999
- className: "flex-1"
1000
- }, /* @__PURE__ */ React10.createElement(FormField, {
1001
- property: {
1002
- ...property,
1003
- array: false,
1004
- ast: elementType
1005
- },
1006
- path: [
1007
- ...path ?? [],
1008
- index
1009
- ],
1010
- readonly,
1011
- inline: true,
1012
- Custom,
1013
- lookupComponent
1014
- })), /* @__PURE__ */ React10.createElement(IconButton3, {
1015
- icon: "ph--trash--regular",
1016
- iconOnly: true,
1017
- label: t("button remove"),
1018
- onClick: () => handleRemove(index)
1019
- })))), /* @__PURE__ */ React10.createElement("div", {
1020
- role: "none",
1021
- className: "flex justify-between items-center plb-1"
1022
- }, /* @__PURE__ */ React10.createElement(IconButton3, {
1023
- icon: "ph--plus--regular",
1024
- iconOnly: true,
1025
- label: t("button add"),
1026
- onClick: handleAdd
1027
- })));
1028
1231
  };
1029
-
1030
- // packages/ui/react-ui-form/src/components/Form/factory.tsx
1031
- import { FormatEnum } from "@dxos/echo-schema";
1032
- var getInputComponent = (type, format) => {
1232
+ var cellClassesForFieldType = ({ type, format }) => {
1233
+ if (!format) {
1234
+ switch (type) {
1235
+ case TypeEnum.Number:
1236
+ return [
1237
+ "text-right",
1238
+ "font-mono"
1239
+ ];
1240
+ case TypeEnum.Boolean:
1241
+ return [
1242
+ "text-right",
1243
+ "font-mono"
1244
+ ];
1245
+ case TypeEnum.String:
1246
+ return void 0;
1247
+ case TypeEnum.Ref:
1248
+ return void 0;
1249
+ default: {
1250
+ return void 0;
1251
+ }
1252
+ }
1253
+ }
1033
1254
  switch (format) {
1034
- case FormatEnum.GeoPoint:
1035
- return GeoPointInput;
1036
1255
  case FormatEnum.Markdown:
1037
- return MarkdownInput;
1038
- }
1039
- switch (type) {
1040
- case "string":
1041
- return TextInput;
1042
- case "number":
1043
- return NumberInput;
1044
- case "boolean":
1045
- return BooleanInput;
1046
- }
1047
- };
1048
-
1049
- // packages/ui/react-ui-form/src/components/Form/FormContent.tsx
1050
- var FormField = ({ property, path, readonly, inline, lookupComponent, Custom }) => {
1051
- const inputProps = useInputProps(path);
1052
- const { ast, name, type, format, title, description, options, examples, array } = property;
1053
- const label = useMemo5(() => title ?? pipe2(name, capitalize2), [
1054
- title,
1055
- name
1056
- ]);
1057
- const placeholder = useMemo5(() => examples?.length ? `Example: "${examples[0]}"` : description, [
1058
- examples,
1059
- description
1060
- ]);
1061
- const FoundComponent = lookupComponent?.({
1062
- prop: name,
1063
- schema: S.make(ast),
1064
- inputProps: {
1065
- type,
1066
- format,
1067
- label,
1068
- disabled: readonly,
1069
- placeholder,
1070
- ...inputProps
1071
- }
1072
- });
1073
- if (FoundComponent) {
1074
- return /* @__PURE__ */ React11.createElement("div", {
1075
- role: "none"
1076
- }, FoundComponent);
1077
- }
1078
- const jsonPath = createJsonPath3(path ?? []);
1079
- const CustomComponent = Custom?.[jsonPath];
1080
- if (CustomComponent) {
1081
- return /* @__PURE__ */ React11.createElement(CustomComponent, {
1082
- type,
1083
- format,
1084
- label,
1085
- inputOnly: inline,
1086
- placeholder,
1087
- disabled: readonly,
1088
- ...inputProps
1089
- });
1090
- }
1091
- if (array) {
1092
- return /* @__PURE__ */ React11.createElement(ArrayField, {
1093
- property,
1094
- path,
1095
- inputProps,
1096
- readonly,
1097
- Custom
1098
- });
1099
- }
1100
- const InputComponent = getInputComponent(type, format);
1101
- if (InputComponent) {
1102
- return /* @__PURE__ */ React11.createElement("div", {
1103
- role: "none"
1104
- }, /* @__PURE__ */ React11.createElement(InputComponent, {
1105
- type,
1106
- format,
1107
- label,
1108
- inputOnly: inline,
1109
- placeholder,
1110
- disabled: readonly,
1111
- ...inputProps
1112
- }));
1113
- }
1114
- if (options) {
1115
- return /* @__PURE__ */ React11.createElement("div", {
1116
- role: "none"
1117
- }, /* @__PURE__ */ React11.createElement(SelectInput, {
1118
- type,
1119
- format,
1120
- disabled: readonly,
1121
- inputOnly: inline,
1122
- label,
1123
- options: options.map((option) => ({
1124
- value: option,
1125
- label: String(option)
1126
- })),
1127
- placeholder,
1128
- ...inputProps
1129
- }));
1130
- }
1131
- if (type === "object") {
1132
- const baseNode = findNode2(ast, isDiscriminatedUnion2);
1133
- const typeLiteral = baseNode ? getDiscriminatedType2(baseNode, inputProps.getValue()) : findNode2(ast, AST3.isTypeLiteral);
1134
- if (typeLiteral) {
1135
- return /* @__PURE__ */ React11.createElement("div", {
1136
- role: "none"
1137
- }, !inline && /* @__PURE__ */ React11.createElement("div", null, label), /* @__PURE__ */ React11.createElement(FormFields, {
1138
- schema: S.make(typeLiteral),
1139
- path,
1140
- readonly,
1141
- Custom
1142
- }));
1143
- }
1144
- }
1145
- return null;
1146
- };
1147
- var FormFields = ({ schema, path, filter, sort, readonly, lookupComponent, Custom }) => {
1148
- const values = useFormValues(path);
1149
- const properties = useMemo5(() => {
1150
- const props = getSchemaProperties2(schema.ast, values);
1151
- const filtered = filter ? filter(props) : props;
1152
- return sort ? filtered.sort((a, b) => sort.indexOf(a.name) - sort.indexOf(b.name)) : filtered;
1153
- }, [
1154
- schema,
1155
- values,
1156
- filter,
1157
- sort
1158
- ]);
1159
- return /* @__PURE__ */ React11.createElement("div", {
1160
- role: "form",
1161
- className: mx6("flex flex-col w-full gap-2")
1162
- }, properties.map((property) => {
1163
- return /* @__PURE__ */ React11.createElement(FormField, {
1164
- key: property.name,
1165
- property,
1166
- path: [
1167
- ...path ?? [],
1168
- property.name
1169
- ],
1170
- readonly,
1171
- lookupComponent,
1172
- Custom
1173
- });
1174
- }).filter(isNotFalsy));
1175
- };
1176
-
1177
- // packages/ui/react-ui-form/src/components/Form/Form.tsx
1178
- var Form = ({ classNames, schema, values: initialValues, path = [], autoFocus, readonly, filter, sort, autoSave, testId, onValuesChanged, onValidate, onSave, onCancel, lookupComponent, Custom }) => {
1179
- const formRef = useRef3(null);
1180
- const onValid = useMemo6(() => autoSave ? onSave : void 0, [
1181
- autoSave,
1182
- onSave
1183
- ]);
1184
- useEffect6(() => {
1185
- if (autoFocus && formRef.current) {
1186
- const input = formRef.current.querySelector("input");
1187
- if (input) {
1188
- input.focus();
1189
- }
1190
- }
1191
- }, [
1192
- autoFocus
1193
- ]);
1194
- return /* @__PURE__ */ React12.createElement(FormProvider, {
1195
- formRef,
1196
- schema,
1197
- autoSave,
1198
- initialValues,
1199
- onValuesChanged,
1200
- onValidate,
1201
- onValid,
1202
- onSave
1203
- }, /* @__PURE__ */ React12.createElement("div", {
1204
- ref: formRef,
1205
- role: "none",
1206
- className: mx7("p-2", classNames),
1207
- "data-testid": testId
1208
- }, /* @__PURE__ */ React12.createElement(FormFields, {
1209
- schema,
1210
- path,
1211
- readonly,
1212
- filter,
1213
- sort,
1214
- lookupComponent,
1215
- Custom
1216
- }), (onCancel || onSave) && !autoSave && /* @__PURE__ */ React12.createElement(FormActions, {
1217
- onCancel,
1218
- readonly
1219
- })));
1220
- };
1221
-
1222
- // packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx
1223
- var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx";
1224
- var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
1225
- const { t } = useTranslation6(translationKey);
1226
- const [props, setProps] = useState4(projection.getFieldProjection(field.id).props);
1227
- useEffect7(() => setProps(projection.getFieldProjection(field.id).props), [
1228
- field,
1229
- projection
1230
- ]);
1231
- const [schemas, setSchemas] = useState4([]);
1232
- useEffect7(() => {
1233
- if (!registry) {
1234
- return;
1235
- }
1236
- const subscription = registry.query().subscribe((query) => setSchemas(query.results), {
1237
- fire: true
1238
- });
1239
- const t2 = setTimeout(async () => {
1240
- const schemas2 = await registry.query().run();
1241
- setSchemas(schemas2);
1242
- });
1243
- return () => {
1244
- clearTimeout(t2);
1245
- subscription?.();
1246
- };
1247
- }, [
1248
- registry
1249
- ]);
1250
- const [referenceSchema, setReferenceSchema] = useState4();
1251
- useEffect7(() => {
1252
- setReferenceSchema(schemas.find((schema) => schema.typename === props?.referenceSchema));
1253
- }, [
1254
- schemas,
1255
- props?.referenceSchema
1256
- ]);
1257
- const [{ fieldSchema }, setFieldSchema] = useState4({
1258
- fieldSchema: getFormatSchema(props?.format)
1259
- });
1260
- const handleValuesChanged = useCallback6((_props) => {
1261
- setFieldSchema((prev) => {
1262
- const fieldSchema2 = getFormatSchema(_props.format);
1263
- if (prev.fieldSchema === fieldSchema2) {
1264
- return prev;
1265
- }
1266
- return {
1267
- fieldSchema: fieldSchema2
1268
- };
1269
- });
1270
- setReferenceSchema((prev) => {
1271
- if (_props.referenceSchema !== prev?.typename) {
1272
- const newSchema = schemas.find((schema) => schema.typename === _props.referenceSchema);
1273
- if (newSchema) {
1274
- return newSchema;
1275
- }
1276
- }
1277
- return prev;
1278
- });
1279
- setProps((props2) => {
1280
- const type = formatToType[_props.format];
1281
- if (props2.type !== type) {
1282
- return {
1283
- ...props2,
1284
- ..._props,
1285
- type
1286
- };
1287
- }
1288
- return _props;
1289
- });
1290
- }, [
1291
- schemas,
1292
- props.format,
1293
- props.referenceSchema
1294
- ]);
1295
- const handleValidate = useCallback6(({ property }) => {
1296
- if (property && view.fields.find((f) => f.path === property && f.path !== field.path)) {
1297
- return [
1298
- {
1299
- path: "property",
1300
- message: `property is not unique: '${property}'`
1301
- }
1302
- ];
1303
- }
1304
- }, [
1305
- view.fields,
1306
- field
1307
- ]);
1308
- const handleSave = useCallback6((props2) => {
1309
- projection.setFieldProjection({
1310
- field,
1311
- props: props2
1312
- });
1313
- onSave();
1314
- }, [
1315
- projection,
1316
- field,
1317
- onSave
1318
- ]);
1319
- const handleCancel = useCallback6(() => {
1320
- requestAnimationFrame(() => onCancel?.());
1321
- onSave();
1322
- }, [
1323
- onSave
1324
- ]);
1325
- const Custom = useMemo7(() => ({
1326
- ["format"]: (props2) => /* @__PURE__ */ React13.createElement(SelectInput, {
1327
- ...props2,
1328
- options: FormatEnums.filter((value) => value !== FormatEnum2.None).map((value) => ({
1329
- value,
1330
- label: t(`format ${value}`)
1331
- }))
1332
- }),
1333
- ["referenceSchema"]: (props2) => /* @__PURE__ */ React13.createElement(SelectInput, {
1334
- ...props2,
1335
- options: schemas.map((schema) => ({
1336
- value: schema.typename
1337
- }))
1338
- }),
1339
- ["referencePath"]: (props2) => /* @__PURE__ */ React13.createElement(SelectInput, {
1340
- ...props2,
1341
- options: referenceSchema ? getSchemaProperties3(referenceSchema.ast).sort(sortProperties).map((p) => ({
1342
- value: p.name
1343
- })) : []
1344
- }),
1345
- ["options"]: (props2) => /* @__PURE__ */ React13.createElement(SelectOptionInput, props2)
1346
- }), [
1347
- t,
1348
- schemas,
1349
- referenceSchema
1350
- ]);
1351
- const propIsNotType = useCallback6((props2) => props2.filter((p) => p.name !== "type"), []);
1352
- if (!fieldSchema) {
1353
- log2.warn("invalid format", {
1354
- props
1355
- }, {
1356
- F: __dxlog_file3,
1357
- L: 174,
1358
- S: void 0,
1359
- C: (f, a) => f(...a)
1360
- });
1361
- return null;
1362
- }
1363
- return /* @__PURE__ */ React13.createElement(Form, {
1364
- key: field.id,
1365
- autoFocus: true,
1366
- values: props,
1367
- schema: fieldSchema,
1368
- filter: propIsNotType,
1369
- sort: [
1370
- "property",
1371
- "format"
1372
- ],
1373
- onValuesChanged: handleValuesChanged,
1374
- onValidate: handleValidate,
1375
- onSave: handleSave,
1376
- onCancel: handleCancel,
1377
- Custom
1378
- });
1379
- };
1380
-
1381
- // packages/ui/react-ui-form/src/components/ViewEditor/ViewEditor.tsx
1382
- import React14, { useCallback as useCallback7, useMemo as useMemo8, useState as useState5 } from "react";
1383
- import { AST as AST4, Format, S as S2 } from "@dxos/echo-schema";
1384
- import { invariant as invariant3 } from "@dxos/invariant";
1385
- import { IconButton as IconButton4, useTranslation as useTranslation7 } from "@dxos/react-ui";
1386
- import { List as List2 } from "@dxos/react-ui-list";
1387
- import { ghostHover, inputTextLabel, mx as mx8 } from "@dxos/react-ui-theme";
1388
- import { FieldSchema, ViewProjection, VIEW_FIELD_LIMIT } from "@dxos/schema";
1389
- var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/ViewEditor/ViewEditor.tsx";
1390
- var grid = "grid grid-cols-[32px_1fr_32px] min-bs-[2.5rem]";
1391
- var ViewMetaSchema = S2.Struct({
1392
- name: S2.String.annotations({
1393
- [AST4.TitleAnnotationId]: "View"
1394
- }),
1395
- typename: Format.URL.annotations({
1396
- [AST4.TitleAnnotationId]: "Typename"
1397
- })
1398
- }).pipe(S2.mutable);
1399
- var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading = false, onTypenameChanged, onDelete }) => {
1400
- const { t } = useTranslation7(translationKey);
1401
- const projection = useMemo8(() => new ViewProjection(schema.jsonSchema, view), [
1402
- schema,
1403
- view
1404
- ]);
1405
- const [field, setField] = useState5();
1406
- const viewValues = useMemo8(() => {
1407
- return {
1408
- name: view.name,
1409
- // TODO(burdon): Need to warn user of possible consequences of editing.
1410
- // TODO(burdon): Settings should have domain name owned by user.
1411
- typename: view.query.typename
1412
- };
1413
- }, [
1414
- view
1415
- ]);
1416
- const handleSelect = useCallback7((field2) => {
1417
- setField((f) => f === field2 ? void 0 : field2);
1418
- }, []);
1419
- const handleAdd = useCallback7(() => {
1420
- invariant3(!schema.readonly, void 0, {
1421
- F: __dxlog_file4,
1422
- L: 76,
1423
- S: void 0,
1424
- A: [
1425
- "!schema.readonly",
1426
- ""
1427
- ]
1428
- });
1429
- const field2 = projection.createFieldProjection();
1430
- setField(field2);
1431
- }, [
1432
- schema,
1433
- view
1434
- ]);
1435
- const handleUpdate = useCallback7(({ name, typename }) => {
1436
- invariant3(!schema.readonly, void 0, {
1437
- F: __dxlog_file4,
1438
- L: 83,
1439
- S: void 0,
1440
- A: [
1441
- "!schema.readonly",
1442
- ""
1443
- ]
1444
- });
1445
- requestAnimationFrame(() => {
1446
- if (view.name !== name) {
1447
- view.name = name;
1448
- }
1449
- if (view.query.typename !== typename) {
1450
- onTypenameChanged?.(typename);
1451
- }
1452
- });
1453
- }, [
1454
- schema,
1455
- view,
1456
- onTypenameChanged
1457
- ]);
1458
- const handleDelete = useCallback7((fieldId) => {
1459
- invariant3(!schema.readonly, void 0, {
1460
- F: __dxlog_file4,
1461
- L: 99,
1462
- S: void 0,
1463
- A: [
1464
- "!schema.readonly",
1465
- ""
1466
- ]
1467
- });
1468
- if (fieldId === field?.id) {
1469
- setField(void 0);
1470
- }
1471
- onDelete?.(fieldId);
1472
- }, [
1473
- schema,
1474
- field,
1475
- onDelete
1476
- ]);
1477
- const handleMove = useCallback7((fromIndex, toIndex) => {
1478
- invariant3(!schema.readonly, void 0, {
1479
- F: __dxlog_file4,
1480
- L: 111,
1481
- S: void 0,
1482
- A: [
1483
- "!schema.readonly",
1484
- ""
1485
- ]
1486
- });
1487
- const fields = [
1488
- ...view.fields
1489
- ];
1490
- const [moved] = fields.splice(fromIndex, 1);
1491
- fields.splice(toIndex, 0, moved);
1492
- view.fields = fields;
1493
- }, [
1494
- schema,
1495
- view.fields
1496
- ]);
1497
- const handleClose = useCallback7(() => setField(void 0), []);
1498
- const hiddenProperties = projection.getHiddenProperties();
1499
- const handleHide = useCallback7((fieldId) => {
1500
- setField(void 0);
1501
- projection.hideFieldProjection(fieldId);
1502
- }, [
1503
- projection
1504
- ]);
1505
- const handleShow = useCallback7((property) => {
1506
- setField(void 0);
1507
- projection.showFieldProjection(property);
1508
- }, [
1509
- projection
1510
- ]);
1511
- return /* @__PURE__ */ React14.createElement("div", {
1512
- role: "none",
1513
- className: mx8("flex flex-col w-full divide-y divide-separator", classNames)
1514
- }, /* @__PURE__ */ React14.createElement(Form, {
1515
- autoSave: true,
1516
- schema: ViewMetaSchema,
1517
- values: viewValues,
1518
- onSave: schema.readonly ? void 0 : handleUpdate
1519
- }), /* @__PURE__ */ React14.createElement("div", null, /* @__PURE__ */ React14.createElement("div", {
1520
- role: "none",
1521
- className: "p-2"
1522
- }, /* @__PURE__ */ React14.createElement("label", {
1523
- className: mx8(inputTextLabel)
1524
- }, t("fields label"))), /* @__PURE__ */ React14.createElement(List2.Root, {
1525
- items: view.fields,
1526
- isItem: S2.is(FieldSchema),
1527
- getId: (field2) => field2.id,
1528
- onMove: schema.readonly ? void 0 : handleMove
1529
- }, ({ items: fields }) => /* @__PURE__ */ React14.createElement(React14.Fragment, null, showHeading && /* @__PURE__ */ React14.createElement("div", {
1530
- role: "heading",
1531
- className: grid
1532
- }, /* @__PURE__ */ React14.createElement("div", null), /* @__PURE__ */ React14.createElement("div", {
1533
- className: "flex items-center text-sm"
1534
- }, t("field path label"))), /* @__PURE__ */ React14.createElement("div", {
1535
- role: "list",
1536
- className: "flex flex-col w-full"
1537
- }, fields?.map((field2) => /* @__PURE__ */ React14.createElement(List2.Item, {
1538
- key: field2.id,
1539
- item: field2,
1540
- classNames: mx8(grid, ghostHover, "cursor-pointer")
1541
- }, /* @__PURE__ */ React14.createElement(List2.ItemDragHandle, null), /* @__PURE__ */ React14.createElement(List2.ItemTitle, {
1542
- onClick: () => handleSelect(field2)
1543
- }, field2.path), /* @__PURE__ */ React14.createElement("div", {
1544
- className: "flex items-center gap-2 -ml-4"
1545
- }, /* @__PURE__ */ React14.createElement(List2.ItemButton, {
1546
- icon: "ph--eye-slash--regular",
1547
- disabled: view.fields.length <= 1,
1548
- onClick: () => handleHide(field2.id)
1549
- }), !schema.readonly && /* @__PURE__ */ React14.createElement(List2.ItemDeleteButton, {
1550
- icon: "ph--trash--regular",
1551
- disabled: view.fields.length <= 1,
1552
- onClick: () => handleDelete(field2.id)
1553
- }))))))), hiddenProperties.length > 0 && /* @__PURE__ */ React14.createElement("div", null, /* @__PURE__ */ React14.createElement("div", {
1554
- role: "none",
1555
- className: "p-2"
1556
- }, /* @__PURE__ */ React14.createElement("label", {
1557
- className: mx8(inputTextLabel)
1558
- }, t("hidden fields label"))), /* @__PURE__ */ React14.createElement(List2.Root, {
1559
- items: hiddenProperties,
1560
- isItem: (item) => typeof item === "string",
1561
- getId: (property) => property
1562
- }, ({ items: properties }) => /* @__PURE__ */ React14.createElement("div", {
1563
- role: "list",
1564
- className: "flex flex-col w-full"
1565
- }, properties?.map((property) => /* @__PURE__ */ React14.createElement(List2.Item, {
1566
- key: property,
1567
- item: property,
1568
- classNames: mx8(grid, ghostHover, "cursor-pointer")
1569
- }, /* @__PURE__ */ React14.createElement("div", null), /* @__PURE__ */ React14.createElement(List2.ItemTitle, null, property), /* @__PURE__ */ React14.createElement(List2.ItemButton, {
1570
- icon: "ph--eye--regular",
1571
- onClick: () => handleShow(property)
1572
- }))))))), field && /* @__PURE__ */ React14.createElement(FieldEditor, {
1573
- key: field.id,
1574
- view,
1575
- projection,
1576
- field,
1577
- registry,
1578
- onSave: handleClose
1579
- }), !readonly && !field && /* @__PURE__ */ React14.createElement("div", {
1580
- className: "flex p-2 justify-center"
1581
- }, /* @__PURE__ */ React14.createElement(IconButton4, {
1582
- icon: "ph--plus--regular",
1583
- label: t("button add property"),
1584
- onClick: schema.readonly ? void 0 : handleAdd,
1585
- // TODO(burdon): Show field limit in ux (not tooltip).
1586
- disabled: view.fields.length >= VIEW_FIELD_LIMIT
1587
- })));
1588
- };
1589
-
1590
- // packages/ui/react-ui-form/src/util/field.ts
1591
- import { FormatEnum as FormatEnum3, GeoLocation as GeoLocation2, TypeEnum } from "@dxos/echo-schema";
1592
- var parseValue = ({ type, format, value }) => {
1593
- if (value === void 0 || value === null || value === "") {
1594
- return void 0;
1595
- }
1596
- const parseScalar = (type2) => {
1597
- switch (type2) {
1598
- case TypeEnum.Boolean: {
1599
- if (typeof value === "string") {
1600
- const lowercaseValue = value.toLowerCase();
1601
- if (lowercaseValue === "0" || lowercaseValue === "false") {
1602
- return false;
1603
- } else if (lowercaseValue === "1" || lowercaseValue === "true") {
1604
- return true;
1605
- }
1606
- }
1607
- return Boolean(value);
1608
- }
1609
- case TypeEnum.Number: {
1610
- const cleaned = typeof value === "string" ? value.replace(/[^0-9.-]+/g, "") : value;
1611
- const num = Number(cleaned);
1612
- return Number.isNaN(num) ? null : num;
1613
- }
1614
- case TypeEnum.String:
1615
- case TypeEnum.Ref:
1616
- return String(value);
1617
- default: {
1618
- return value;
1619
- }
1620
- }
1621
- };
1622
- if (!format) {
1623
- return parseScalar(type);
1624
- }
1625
- switch (format) {
1626
- case FormatEnum3.Boolean:
1627
- return parseScalar(TypeEnum.Boolean);
1628
- case FormatEnum3.Number:
1629
- case FormatEnum3.Percent:
1630
- case FormatEnum3.Currency:
1631
- return parseScalar(TypeEnum.Number);
1632
- case FormatEnum3.String:
1633
- case FormatEnum3.Markdown: {
1634
- return parseScalar(TypeEnum.String);
1635
- }
1636
- case FormatEnum3.Ref:
1637
- throw new Error(`unexpected format: ${FormatEnum3.Ref}`);
1638
- case FormatEnum3.DateTime:
1639
- case FormatEnum3.Date:
1640
- case FormatEnum3.Time:
1641
- case FormatEnum3.Timestamp: {
1642
- const date = new Date(value);
1643
- return isNaN(date.getTime()) ? null : date;
1644
- }
1645
- case FormatEnum3.GeoPoint: {
1646
- if (typeof value === "string") {
1647
- const cleaned = value.replace(/[^0-9.,-]+/g, "");
1648
- const parts = cleaned.split(",");
1649
- if (parts.length === 2) {
1650
- const lat = parseFloat(parts[0]);
1651
- const long = parseFloat(parts[1]);
1652
- if (!isNaN(lat) && !isNaN(long)) {
1653
- return GeoLocation2.toGeoPoint({
1654
- latitude: lat,
1655
- longitude: long
1656
- });
1657
- }
1658
- }
1659
- }
1660
- return [
1661
- 0,
1662
- 0
1663
- ];
1664
- }
1665
- default: {
1666
- return value;
1667
- }
1668
- }
1669
- };
1670
- var cellClassesForFieldType = ({ type, format }) => {
1671
- if (!format) {
1672
- switch (type) {
1673
- case TypeEnum.Number:
1674
- return [
1675
- "text-right",
1676
- "font-mono"
1677
- ];
1678
- case TypeEnum.Boolean:
1679
- return [
1680
- "text-right",
1681
- "font-mono"
1682
- ];
1683
- case TypeEnum.String:
1684
- return void 0;
1685
- case TypeEnum.Ref:
1686
- return void 0;
1687
- default: {
1688
- return void 0;
1689
- }
1690
- }
1691
- }
1692
- switch (format) {
1693
- case FormatEnum3.Markdown:
1694
1256
  return void 0;
1695
- case FormatEnum3.Time:
1696
- case FormatEnum3.Timestamp:
1697
- case FormatEnum3.DateTime:
1698
- case FormatEnum3.Date:
1699
- case FormatEnum3.Duration:
1257
+ case FormatEnum.Time:
1258
+ case FormatEnum.Timestamp:
1259
+ case FormatEnum.DateTime:
1260
+ case FormatEnum.Date:
1261
+ case FormatEnum.Duration:
1700
1262
  return [
1701
1263
  "font-mono",
1702
1264
  "text-right"
1703
1265
  ];
1704
- case FormatEnum3.Currency:
1266
+ case FormatEnum.Currency:
1705
1267
  return [
1706
1268
  "text-right"
1707
1269
  ];
1708
- case FormatEnum3.JSON:
1709
- case FormatEnum3.DID:
1270
+ case FormatEnum.JSON:
1271
+ case FormatEnum.DID:
1710
1272
  return [
1711
1273
  "font-mono"
1712
1274
  ];
@@ -1721,7 +1283,7 @@ var pathNotUniqueError = (path) => ({
1721
1283
 
1722
1284
  // packages/ui/react-ui-form/src/util/formatting.ts
1723
1285
  import { format as formatDate } from "date-fns/format";
1724
- import { FormatEnum as FormatEnum4, GeoLocation as GeoLocation3, TypeEnum as TypeEnum2 } from "@dxos/echo-schema";
1286
+ import { FormatEnum as FormatEnum2, GeoLocation as GeoLocation3, TypeEnum as TypeEnum2 } from "@dxos/echo-schema";
1725
1287
  var formatForDisplay = ({ type, format, value, locale = void 0 }) => {
1726
1288
  const formatScalar = (type2) => {
1727
1289
  switch (type2) {
@@ -1741,20 +1303,20 @@ var formatForDisplay = ({ type, format, value, locale = void 0 }) => {
1741
1303
  return formatScalar(type);
1742
1304
  }
1743
1305
  switch (format) {
1744
- case FormatEnum4.Boolean: {
1306
+ case FormatEnum2.Boolean: {
1745
1307
  return formatScalar(TypeEnum2.Boolean);
1746
1308
  }
1747
- case FormatEnum4.Number: {
1309
+ case FormatEnum2.Number: {
1748
1310
  return formatScalar(TypeEnum2.Number);
1749
1311
  }
1750
- case FormatEnum4.String:
1751
- case FormatEnum4.Ref: {
1312
+ case FormatEnum2.String:
1313
+ case FormatEnum2.Ref: {
1752
1314
  return formatScalar(TypeEnum2.String);
1753
1315
  }
1754
- case FormatEnum4.Percent: {
1316
+ case FormatEnum2.Percent: {
1755
1317
  return `${value * 100}%`;
1756
1318
  }
1757
- case FormatEnum4.Currency: {
1319
+ case FormatEnum2.Currency: {
1758
1320
  return value.toLocaleString(locale, {
1759
1321
  style: "currency",
1760
1322
  currency: "USD",
@@ -1762,16 +1324,28 @@ var formatForDisplay = ({ type, format, value, locale = void 0 }) => {
1762
1324
  maximumFractionDigits: 2
1763
1325
  });
1764
1326
  }
1765
- case FormatEnum4.Date: {
1766
- return formatDate(new Date(value), "yyyy-MM-dd");
1327
+ case FormatEnum2.Date: {
1328
+ try {
1329
+ return formatDate(new Date(value), "yyyy-MM-dd");
1330
+ } catch (error) {
1331
+ return "Invalid Date";
1332
+ }
1767
1333
  }
1768
- case FormatEnum4.Time: {
1769
- return formatDate(new Date(value), "HH:mm:ss");
1334
+ case FormatEnum2.Time: {
1335
+ try {
1336
+ return formatDate(new Date(value), "HH:mm:ss");
1337
+ } catch (error) {
1338
+ return "Invalid Time";
1339
+ }
1770
1340
  }
1771
- case FormatEnum4.DateTime: {
1772
- return formatDate(new Date(value), "yyyy-MM-dd HH:mm:ss");
1341
+ case FormatEnum2.DateTime: {
1342
+ try {
1343
+ return formatDate(new Date(value), "yyyy-MM-dd HH:mm:ss");
1344
+ } catch (error) {
1345
+ return "Invalid DateTime";
1346
+ }
1773
1347
  }
1774
- case FormatEnum4.GeoPoint: {
1348
+ case FormatEnum2.GeoPoint: {
1775
1349
  if (value === null || value === void 0) {
1776
1350
  return "";
1777
1351
  }
@@ -1805,31 +1379,31 @@ var formatForEditing = ({ type, format, value, locale = void 0 }) => {
1805
1379
  return formatScalar(type);
1806
1380
  }
1807
1381
  switch (format) {
1808
- case FormatEnum4.Boolean:
1809
- case FormatEnum4.Number:
1810
- case FormatEnum4.String:
1811
- case FormatEnum4.Ref: {
1382
+ case FormatEnum2.Boolean:
1383
+ case FormatEnum2.Number:
1384
+ case FormatEnum2.String:
1385
+ case FormatEnum2.Ref: {
1812
1386
  return formatScalar(type);
1813
1387
  }
1814
- case FormatEnum4.Percent: {
1388
+ case FormatEnum2.Percent: {
1815
1389
  return String(value * 100);
1816
1390
  }
1817
- case FormatEnum4.Currency: {
1391
+ case FormatEnum2.Currency: {
1818
1392
  return String(value);
1819
1393
  }
1820
- case FormatEnum4.DateTime: {
1394
+ case FormatEnum2.DateTime: {
1821
1395
  const date = new Date(value);
1822
1396
  return date.toISOString();
1823
1397
  }
1824
- case FormatEnum4.Date: {
1398
+ case FormatEnum2.Date: {
1825
1399
  const date = new Date(value);
1826
1400
  return date.toISOString().split("T")[0];
1827
1401
  }
1828
- case FormatEnum4.Time: {
1402
+ case FormatEnum2.Time: {
1829
1403
  const date = new Date(value);
1830
1404
  return date.toISOString().split("T")[1].split(".")[0];
1831
1405
  }
1832
- case FormatEnum4.GeoPoint: {
1406
+ case FormatEnum2.GeoPoint: {
1833
1407
  if (value === null || value === void 0) {
1834
1408
  return "";
1835
1409
  }
@@ -1844,13 +1418,943 @@ var formatForEditing = ({ type, format, value, locale = void 0 }) => {
1844
1418
  }
1845
1419
  }
1846
1420
  };
1421
+
1422
+ // packages/ui/react-ui-form/src/util/refs.ts
1423
+ import { FormatEnum as FormatEnum3, ReferenceAnnotationId } from "@dxos/echo-schema";
1424
+ import { findAnnotation } from "@dxos/effect";
1425
+
1426
+ // packages/ui/react-ui-form/src/util/schema.ts
1427
+ import { SchemaAST as SchemaAST2 } from "effect";
1428
+ import { findNode } from "@dxos/effect";
1429
+ var findArrayElementType = (ast) => {
1430
+ const tupleType = findNode(ast, SchemaAST2.isTupleType);
1431
+ const elementType = tupleType?.rest[0]?.type;
1432
+ return elementType;
1433
+ };
1434
+
1435
+ // packages/ui/react-ui-form/src/util/refs.ts
1436
+ var getRefProps = (property) => {
1437
+ const { ast, format, array } = property;
1438
+ if (format === FormatEnum3.Ref) {
1439
+ return {
1440
+ ast,
1441
+ isArray: false
1442
+ };
1443
+ }
1444
+ if (array) {
1445
+ const elementType = findArrayElementType(ast);
1446
+ if (elementType) {
1447
+ const annotation = findAnnotation(elementType, ReferenceAnnotationId);
1448
+ if (annotation) {
1449
+ return {
1450
+ ast: elementType,
1451
+ isArray: true
1452
+ };
1453
+ }
1454
+ }
1455
+ }
1456
+ return void 0;
1457
+ };
1458
+
1459
+ // packages/ui/react-ui-form/src/components/Form/ArrayField.tsx
1460
+ var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/Form/ArrayField.tsx";
1461
+ var ArrayField = ({ property, readonly, path, inputProps, Custom, lookupComponent }) => {
1462
+ var _effect = _useSignals10();
1463
+ try {
1464
+ const { t } = useTranslation6(translationKey);
1465
+ const { ast, name, type, title } = property;
1466
+ const values = useFormValues(path ?? []) ?? [];
1467
+ invariant2(Array.isArray(values), `Values at path ${path?.join(".")} must be an array.`, {
1468
+ F: __dxlog_file3,
1469
+ L: 36,
1470
+ S: void 0,
1471
+ A: [
1472
+ "Array.isArray(values)",
1473
+ "`Values at path ${path?.join('.')} must be an array.`"
1474
+ ]
1475
+ });
1476
+ const label = title ?? pipe(name, capitalize);
1477
+ const elementType = findArrayElementType(ast);
1478
+ const getDefaultObjectValue = (typeNode) => {
1479
+ const baseNode = findNode2(typeNode, isDiscriminatedUnion);
1480
+ const typeLiteral = baseNode ? getDiscriminatedType(baseNode, {}) : findNode2(typeNode, SchemaAST3.isTypeLiteral);
1481
+ if (!typeLiteral) {
1482
+ return {};
1483
+ }
1484
+ return Object.fromEntries(getSchemaProperties(typeLiteral, {}).map((prop) => [
1485
+ prop.name,
1486
+ prop.defaultValue
1487
+ ]));
1488
+ };
1489
+ const getDefaultValue = () => type === "object" && elementType ? getDefaultObjectValue(elementType) : SimpleType.getDefaultValue(type);
1490
+ const handleAdd = useCallback7(() => {
1491
+ inputProps.onValueChange(type, [
1492
+ ...values,
1493
+ getDefaultValue()
1494
+ ]);
1495
+ }, [
1496
+ type,
1497
+ elementType,
1498
+ inputProps,
1499
+ values
1500
+ ]);
1501
+ const handleRemove = useCallback7((index) => {
1502
+ const newValues = values.filter((_, i) => i !== index);
1503
+ inputProps.onValueChange(type, newValues);
1504
+ }, [
1505
+ type,
1506
+ inputProps,
1507
+ values
1508
+ ]);
1509
+ if (!elementType) {
1510
+ return null;
1511
+ }
1512
+ return readonly && values.length < 1 ? null : /* @__PURE__ */ React10.createElement(React10.Fragment, null, /* @__PURE__ */ React10.createElement(InputHeader, null, label), /* @__PURE__ */ React10.createElement("div", {
1513
+ role: "none",
1514
+ className: readonly ? "flex flex-wrap gap-1 mlb-1" : values.length > 0 ? "grid gap-1 grid-cols-[1fr_min-content] mlb-1" : "hidden"
1515
+ }, values.map((_value, index) => {
1516
+ const field = /* @__PURE__ */ React10.createElement(FormField, {
1517
+ property: {
1518
+ ...property,
1519
+ array: false,
1520
+ ast: elementType
1521
+ },
1522
+ path: [
1523
+ ...path ?? [],
1524
+ index
1525
+ ],
1526
+ readonly,
1527
+ inline: true,
1528
+ Custom,
1529
+ lookupComponent
1530
+ });
1531
+ return readonly ? field : /* @__PURE__ */ React10.createElement(Fragment, {
1532
+ key: index
1533
+ }, /* @__PURE__ */ React10.createElement("div", {
1534
+ role: "none"
1535
+ }, field), /* @__PURE__ */ React10.createElement(IconButton3, {
1536
+ icon: "ph--trash--regular",
1537
+ iconOnly: true,
1538
+ label: t("button remove"),
1539
+ onClick: () => handleRemove(index),
1540
+ classNames: "self-center"
1541
+ }));
1542
+ })), !readonly && /* @__PURE__ */ React10.createElement(IconButton3, {
1543
+ classNames: "is-full mlb-1 flex",
1544
+ icon: "ph--plus--regular",
1545
+ label: t("add field"),
1546
+ onClick: handleAdd
1547
+ }));
1548
+ } finally {
1549
+ _effect.f();
1550
+ }
1551
+ };
1552
+
1553
+ // packages/ui/react-ui-form/src/components/Form/RefField.tsx
1554
+ import { useSignals as _useSignals11 } from "@preact-signals/safe-react/tracking";
1555
+ import React11, { useCallback as useCallback8, useMemo as useMemo4 } from "react";
1556
+ import { Expando, getTypeAnnotation, Ref, ReferenceAnnotationId as ReferenceAnnotationId2 } from "@dxos/echo-schema";
1557
+ import { findAnnotation as findAnnotation2 } from "@dxos/effect";
1558
+ import { DXN } from "@dxos/keys";
1559
+ import { DxRefTag } from "@dxos/lit-ui/react";
1560
+ import { Input as Input7, useTranslation as useTranslation7 } from "@dxos/react-ui";
1561
+ import { TagPicker } from "@dxos/react-ui-tag-picker";
1562
+ import { descriptionText, mx as mx5 } from "@dxos/react-ui-theme";
1563
+ import { isNonNullable as isNonNullable2 } from "@dxos/util";
1564
+ var RefField = ({ type, label, disabled, placeholder, inputOnly, array, ast, getValue: getValue3, onBlur, onQueryRefOptions, onValueChange, ...restInputProps }) => {
1565
+ var _effect = _useSignals11();
1566
+ try {
1567
+ const { t } = useTranslation7(translationKey);
1568
+ const refTypeInfo = useMemo4(() => ast ? findAnnotation2(ast, ReferenceAnnotationId2) : void 0, [
1569
+ ast
1570
+ ]);
1571
+ const { options: availableOptions, loading: _loading } = useQueryRefOptions({
1572
+ refTypeInfo,
1573
+ onQueryRefOptions
1574
+ });
1575
+ if (refTypeInfo && refTypeInfo?.typename === getTypeAnnotation(Expando)?.typename || !onQueryRefOptions) {
1576
+ return /* @__PURE__ */ React11.createElement(RefFieldFallback, {
1577
+ type,
1578
+ label,
1579
+ placeholder,
1580
+ disabled,
1581
+ inputOnly,
1582
+ getValue: getValue3,
1583
+ onBlur,
1584
+ onValueChange,
1585
+ ...restInputProps
1586
+ });
1587
+ }
1588
+ const handleGetValue = useCallback8(() => {
1589
+ const formValue = getValue3();
1590
+ const unknownToRefOption = (val) => {
1591
+ if (Ref.isRef(val)) {
1592
+ const dxnString = val.dxn.toString();
1593
+ const matchingOption = availableOptions.find((option2) => option2.id === dxnString);
1594
+ if (matchingOption) {
1595
+ return matchingOption;
1596
+ }
1597
+ }
1598
+ return void 0;
1599
+ };
1600
+ if (array && Array.isArray(formValue)) {
1601
+ return formValue.map(unknownToRefOption).filter(isNonNullable2) ?? [];
1602
+ }
1603
+ const option = unknownToRefOption(formValue);
1604
+ if (option) {
1605
+ return [
1606
+ option
1607
+ ];
1608
+ }
1609
+ return [];
1610
+ }, [
1611
+ getValue3,
1612
+ availableOptions,
1613
+ array
1614
+ ]);
1615
+ const handleSearch = useCallback8((text, ids) => availableOptions.filter((option) => !ids.includes(option.id)).filter((option) => option.label.toLowerCase().includes(text.toLowerCase())).map((option) => ({
1616
+ id: option.id,
1617
+ label: option.label,
1618
+ hue: option.hue
1619
+ })), [
1620
+ availableOptions
1621
+ ]);
1622
+ const handleUpdate = useCallback8((ids) => {
1623
+ if (ids.length === 0) {
1624
+ onValueChange("object", void 0);
1625
+ return;
1626
+ }
1627
+ const refs = ids.map((id) => {
1628
+ const item = availableOptions.find((option) => option.id === id);
1629
+ if (item) {
1630
+ const dxn = DXN.parse(item.id);
1631
+ return Ref.fromDXN(dxn);
1632
+ }
1633
+ return null;
1634
+ }).filter(isNonNullable2);
1635
+ if (array) {
1636
+ onValueChange("object", refs);
1637
+ } else {
1638
+ onValueChange("object", refs[0]);
1639
+ }
1640
+ }, [
1641
+ availableOptions,
1642
+ array,
1643
+ onValueChange
1644
+ ]);
1645
+ const tagPickerMode = useMemo4(() => array ? "multi-select" : "single-select", [
1646
+ array
1647
+ ]);
1648
+ if (!refTypeInfo) {
1649
+ return null;
1650
+ }
1651
+ const { status, error } = restInputProps.getStatus();
1652
+ const items = handleGetValue();
1653
+ return disabled && items.length < 1 ? null : /* @__PURE__ */ React11.createElement(Input7.Root, {
1654
+ validationValence: status
1655
+ }, !inputOnly && /* @__PURE__ */ React11.createElement(InputHeader, {
1656
+ error
1657
+ }, /* @__PURE__ */ React11.createElement(Input7.Label, null, label)), /* @__PURE__ */ React11.createElement("div", {
1658
+ "data-no-submit": true
1659
+ }, disabled ? items.length < 1 ? /* @__PURE__ */ React11.createElement("p", {
1660
+ className: mx5(descriptionText, "mbe-2")
1661
+ }, t("empty readonly ref field label")) : items.map((item) => /* @__PURE__ */ React11.createElement(DxRefTag, {
1662
+ key: item.id,
1663
+ refid: item.id,
1664
+ rootclassname: "mie-1",
1665
+ style: {
1666
+ marginInlineEnd: ".25rem"
1667
+ }
1668
+ }, item.label)) : /* @__PURE__ */ React11.createElement(TagPicker, {
1669
+ readonly: disabled,
1670
+ items,
1671
+ mode: tagPickerMode,
1672
+ onBlur: (event) => onBlur(event),
1673
+ onUpdate: handleUpdate,
1674
+ onSearch: handleSearch,
1675
+ classNames: "rounded-sm bg-inputSurface p-1.5"
1676
+ })), inputOnly && /* @__PURE__ */ React11.createElement(Input7.DescriptionAndValidation, null, error));
1677
+ } finally {
1678
+ _effect.f();
1679
+ }
1680
+ };
1681
+ var RefFieldFallback = ({ type, label, disabled, placeholder, inputOnly, getValue: getValue3, onValueChange, ...restInputProps }) => {
1682
+ var _effect = _useSignals11();
1683
+ try {
1684
+ const handleOnValueChange = (_type, dxnString) => {
1685
+ const dxn = DXN.tryParse(dxnString);
1686
+ if (dxn) {
1687
+ onValueChange?.("object", Ref.fromDXN(dxn));
1688
+ } else if (dxnString === "") {
1689
+ onValueChange?.("object", void 0);
1690
+ } else {
1691
+ onValueChange?.("string", dxnString);
1692
+ }
1693
+ };
1694
+ const handleGetValue = () => {
1695
+ const formValue = getValue3();
1696
+ if (typeof formValue === "string") {
1697
+ return formValue;
1698
+ }
1699
+ if (Ref.isRef(formValue)) {
1700
+ return formValue.dxn.toString();
1701
+ }
1702
+ return void 0;
1703
+ };
1704
+ return /* @__PURE__ */ React11.createElement(TextInput, {
1705
+ type,
1706
+ label,
1707
+ disabled,
1708
+ placeholder,
1709
+ inputOnly,
1710
+ getValue: handleGetValue,
1711
+ onValueChange: handleOnValueChange,
1712
+ ...restInputProps
1713
+ });
1714
+ } finally {
1715
+ _effect.f();
1716
+ }
1717
+ };
1718
+
1719
+ // packages/ui/react-ui-form/src/components/Form/factory.tsx
1720
+ import { FormatEnum as FormatEnum4 } from "@dxos/echo-schema";
1721
+ var getInputComponent = (type, format) => {
1722
+ switch (format) {
1723
+ case FormatEnum4.GeoPoint:
1724
+ return GeoPointInput;
1725
+ case FormatEnum4.Markdown:
1726
+ return MarkdownInput;
1727
+ }
1728
+ switch (type) {
1729
+ case "string":
1730
+ return TextInput;
1731
+ case "number":
1732
+ return NumberInput;
1733
+ case "boolean":
1734
+ return BooleanInput;
1735
+ }
1736
+ };
1737
+
1738
+ // packages/ui/react-ui-form/src/components/Form/FormContent.tsx
1739
+ var FormField = ({ property, path, readonly, inline, onQueryRefOptions, lookupComponent, Custom }) => {
1740
+ var _effect = _useSignals12();
1741
+ try {
1742
+ const inputProps = useInputProps(path);
1743
+ const { ast, name, type, format, title, description, options, examples, array } = property;
1744
+ const label = useMemo5(() => title ?? pipe2(name, capitalize2), [
1745
+ title,
1746
+ name
1747
+ ]);
1748
+ const placeholder = useMemo5(() => examples?.length ? `Example: "${examples[0]}"` : description, [
1749
+ examples,
1750
+ description
1751
+ ]);
1752
+ const FoundComponent = lookupComponent?.({
1753
+ prop: name,
1754
+ schema: Schema.make(ast),
1755
+ inputProps: {
1756
+ type,
1757
+ format,
1758
+ label,
1759
+ disabled: readonly,
1760
+ placeholder,
1761
+ ...inputProps
1762
+ }
1763
+ });
1764
+ if (FoundComponent) {
1765
+ return FoundComponent;
1766
+ }
1767
+ const jsonPath = createJsonPath3(path ?? []);
1768
+ const CustomComponent = Custom?.[jsonPath];
1769
+ if (CustomComponent) {
1770
+ return /* @__PURE__ */ React12.createElement(CustomComponent, {
1771
+ type,
1772
+ format,
1773
+ label,
1774
+ inputOnly: inline,
1775
+ placeholder,
1776
+ disabled: readonly,
1777
+ ...inputProps
1778
+ });
1779
+ }
1780
+ const refProps = getRefProps(property);
1781
+ if (refProps) {
1782
+ return /* @__PURE__ */ React12.createElement(RefField, {
1783
+ ast: refProps.ast,
1784
+ array: refProps.isArray,
1785
+ type,
1786
+ format,
1787
+ label,
1788
+ placeholder,
1789
+ disabled: readonly,
1790
+ inputOnly: inline,
1791
+ onQueryRefOptions,
1792
+ ...inputProps
1793
+ });
1794
+ }
1795
+ if (array) {
1796
+ return /* @__PURE__ */ React12.createElement(ArrayField, {
1797
+ property,
1798
+ path,
1799
+ inputProps,
1800
+ readonly,
1801
+ Custom
1802
+ });
1803
+ }
1804
+ const InputComponent = getInputComponent(type, format);
1805
+ if (InputComponent) {
1806
+ return /* @__PURE__ */ React12.createElement(InputComponent, {
1807
+ type,
1808
+ format,
1809
+ label,
1810
+ inputOnly: inline,
1811
+ placeholder,
1812
+ disabled: readonly,
1813
+ ...inputProps
1814
+ });
1815
+ }
1816
+ if (options) {
1817
+ return /* @__PURE__ */ React12.createElement(SelectInput, {
1818
+ type,
1819
+ format,
1820
+ disabled: readonly,
1821
+ inputOnly: inline,
1822
+ label,
1823
+ options: options.map((option) => ({
1824
+ value: option,
1825
+ label: String(option)
1826
+ })),
1827
+ placeholder,
1828
+ ...inputProps
1829
+ });
1830
+ }
1831
+ if (type === "object") {
1832
+ const baseNode = findNode3(ast, isDiscriminatedUnion2);
1833
+ const typeLiteral = baseNode ? getDiscriminatedType2(baseNode, inputProps.getValue()) : findNode3(ast, SchemaAST4.isTypeLiteral);
1834
+ if (typeLiteral) {
1835
+ return /* @__PURE__ */ React12.createElement(React12.Fragment, null, !inline && /* @__PURE__ */ React12.createElement("h3", {
1836
+ className: "text-lg mbs-2 mbe-1 first:mbs-0"
1837
+ }, label), /* @__PURE__ */ React12.createElement(FormFields, {
1838
+ schema: Schema.make(typeLiteral),
1839
+ path,
1840
+ readonly,
1841
+ onQueryRefOptions,
1842
+ Custom,
1843
+ lookupComponent
1844
+ }));
1845
+ }
1846
+ }
1847
+ return null;
1848
+ } finally {
1849
+ _effect.f();
1850
+ }
1851
+ };
1852
+ var FormFields = ({ classNames, Custom, schema, path, filter, sort, readonly, lookupComponent, onQueryRefOptions }) => {
1853
+ var _effect = _useSignals12();
1854
+ try {
1855
+ const values = useFormValues(path);
1856
+ const properties = useMemo5(() => {
1857
+ const props = getSchemaProperties2(schema.ast, values);
1858
+ const filtered = filter ? filter(props) : props;
1859
+ return sort ? filtered.sort((a, b) => sort.indexOf(a.name) - sort.indexOf(b.name)) : filtered;
1860
+ }, [
1861
+ schema,
1862
+ values,
1863
+ filter,
1864
+ sort
1865
+ ]);
1866
+ return (
1867
+ // TODO(burdon): Consistent padding (with composite forms).
1868
+ /* @__PURE__ */ React12.createElement("div", {
1869
+ role: "form",
1870
+ className: mx6("p-2 is-full", classNames)
1871
+ }, properties.map((property) => {
1872
+ return /* @__PURE__ */ React12.createElement(FormField, {
1873
+ key: property.name,
1874
+ property,
1875
+ path: [
1876
+ ...path ?? [],
1877
+ property.name
1878
+ ],
1879
+ readonly,
1880
+ onQueryRefOptions,
1881
+ lookupComponent,
1882
+ Custom
1883
+ });
1884
+ }).filter(isNotFalsy))
1885
+ );
1886
+ } finally {
1887
+ _effect.f();
1888
+ }
1889
+ };
1890
+
1891
+ // packages/ui/react-ui-form/src/components/Form/Form.tsx
1892
+ var Form = ({ classNames, schema, values: initialValues, path = [], autoFocus, readonly, filter, sort, autoSave, testId, onValuesChanged, onValidate, onSave, onCancel, onQueryRefOptions, lookupComponent, Custom }) => {
1893
+ var _effect = _useSignals13();
1894
+ try {
1895
+ const formRef = useRef3(null);
1896
+ const onValid = useMemo6(() => autoSave ? onSave : void 0, [
1897
+ autoSave,
1898
+ onSave
1899
+ ]);
1900
+ useEffect7(() => {
1901
+ if (autoFocus && formRef.current) {
1902
+ const input = formRef.current.querySelector("input");
1903
+ if (input) {
1904
+ input.focus();
1905
+ }
1906
+ }
1907
+ }, [
1908
+ autoFocus
1909
+ ]);
1910
+ return /* @__PURE__ */ React13.createElement(FormProvider, {
1911
+ formRef,
1912
+ schema,
1913
+ autoSave,
1914
+ initialValues,
1915
+ onValuesChanged,
1916
+ onValidate,
1917
+ onValid,
1918
+ onSave
1919
+ }, /* @__PURE__ */ React13.createElement("div", {
1920
+ ref: formRef,
1921
+ role: "none",
1922
+ className: mx7("flex flex-col gap-4", classNames),
1923
+ "data-testid": testId
1924
+ }, /* @__PURE__ */ React13.createElement(FormFields, {
1925
+ schema,
1926
+ path,
1927
+ readonly,
1928
+ filter,
1929
+ sort,
1930
+ onQueryRefOptions,
1931
+ lookupComponent,
1932
+ Custom
1933
+ }), (onCancel || onSave) && !autoSave && /* @__PURE__ */ React13.createElement(FormActions, {
1934
+ onCancel,
1935
+ readonly
1936
+ })));
1937
+ } finally {
1938
+ _effect.f();
1939
+ }
1940
+ };
1941
+
1942
+ // packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx
1943
+ var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx";
1944
+ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
1945
+ var _effect = _useSignals14();
1946
+ try {
1947
+ const { t } = useTranslation8(translationKey);
1948
+ const [props, setProps] = useState5(projection.getFieldProjection(field.id).props);
1949
+ useEffect8(() => setProps(projection.getFieldProjection(field.id).props), [
1950
+ field,
1951
+ projection
1952
+ ]);
1953
+ const [schemas, setSchemas] = useState5([]);
1954
+ useEffect8(() => {
1955
+ if (!registry) {
1956
+ return;
1957
+ }
1958
+ const subscription = registry.query().subscribe((query) => setSchemas(query.results), {
1959
+ fire: true
1960
+ });
1961
+ const t2 = setTimeout(async () => {
1962
+ const schemas2 = await registry.query().run();
1963
+ setSchemas(schemas2);
1964
+ });
1965
+ return () => {
1966
+ clearTimeout(t2);
1967
+ subscription?.();
1968
+ };
1969
+ }, [
1970
+ registry
1971
+ ]);
1972
+ const [referenceSchema, setReferenceSchema] = useState5();
1973
+ useEffect8(() => {
1974
+ setReferenceSchema(schemas.find((schema) => schema.typename === props?.referenceSchema));
1975
+ }, [
1976
+ schemas,
1977
+ props?.referenceSchema
1978
+ ]);
1979
+ const [{ fieldSchema }, setFieldSchema] = useState5({
1980
+ fieldSchema: getFormatSchema(props?.format)
1981
+ });
1982
+ const handleValuesChanged = useCallback9((_props) => {
1983
+ setFieldSchema((prev) => {
1984
+ const fieldSchema2 = getFormatSchema(_props.format);
1985
+ if (prev.fieldSchema === fieldSchema2) {
1986
+ return prev;
1987
+ }
1988
+ return {
1989
+ fieldSchema: fieldSchema2
1990
+ };
1991
+ });
1992
+ setReferenceSchema((prev) => {
1993
+ if (_props.referenceSchema !== prev?.typename) {
1994
+ const newSchema = schemas.find((schema) => schema.typename === _props.referenceSchema);
1995
+ if (newSchema) {
1996
+ return newSchema;
1997
+ }
1998
+ }
1999
+ return prev;
2000
+ });
2001
+ setProps((props2) => {
2002
+ const type = formatToType[_props.format];
2003
+ if (props2.type !== type) {
2004
+ return {
2005
+ ...props2,
2006
+ ..._props,
2007
+ type
2008
+ };
2009
+ }
2010
+ return _props;
2011
+ });
2012
+ }, [
2013
+ schemas,
2014
+ props.format,
2015
+ props.referenceSchema
2016
+ ]);
2017
+ const handleValidate = useCallback9(({ property }) => {
2018
+ if (property && view.fields.find((f) => f.path === property && f.path !== field.path)) {
2019
+ return [
2020
+ {
2021
+ path: "property",
2022
+ message: `property is not unique: '${property}'`
2023
+ }
2024
+ ];
2025
+ }
2026
+ }, [
2027
+ view.fields,
2028
+ field
2029
+ ]);
2030
+ const handleSave = useCallback9((props2) => {
2031
+ projection.setFieldProjection({
2032
+ field,
2033
+ props: props2
2034
+ });
2035
+ onSave();
2036
+ }, [
2037
+ projection,
2038
+ field,
2039
+ onSave
2040
+ ]);
2041
+ const handleCancel = useCallback9(() => {
2042
+ requestAnimationFrame(() => onCancel?.());
2043
+ onSave();
2044
+ }, [
2045
+ onSave
2046
+ ]);
2047
+ const custom = useMemo7(() => ({
2048
+ ["format"]: (props2) => /* @__PURE__ */ React14.createElement(SelectInput, {
2049
+ ...props2,
2050
+ options: FormatEnums.filter((value) => value !== FormatEnum5.None).map((value) => ({
2051
+ value,
2052
+ label: t(`format ${value}`)
2053
+ }))
2054
+ }),
2055
+ ["referenceSchema"]: (props2) => /* @__PURE__ */ React14.createElement(SelectInput, {
2056
+ ...props2,
2057
+ options: schemas.map((schema) => ({
2058
+ value: schema.typename
2059
+ }))
2060
+ }),
2061
+ ["referencePath"]: (props2) => /* @__PURE__ */ React14.createElement(SelectInput, {
2062
+ ...props2,
2063
+ options: referenceSchema ? getSchemaProperties3(referenceSchema.ast).sort(sortProperties).map((p) => ({
2064
+ value: p.name
2065
+ })) : []
2066
+ }),
2067
+ ["options"]: (props2) => /* @__PURE__ */ React14.createElement(SelectOptionInput, props2)
2068
+ }), [
2069
+ t,
2070
+ schemas,
2071
+ referenceSchema
2072
+ ]);
2073
+ const propIsNotType = useCallback9((props2) => props2.filter((p) => p.name !== "type"), []);
2074
+ if (!fieldSchema) {
2075
+ log3.warn("invalid format", {
2076
+ props
2077
+ }, {
2078
+ F: __dxlog_file4,
2079
+ L: 175,
2080
+ S: void 0,
2081
+ C: (f, a) => f(...a)
2082
+ });
2083
+ return null;
2084
+ }
2085
+ return /* @__PURE__ */ React14.createElement(Form, {
2086
+ key: field.id,
2087
+ autoFocus: true,
2088
+ values: props,
2089
+ schema: fieldSchema,
2090
+ filter: propIsNotType,
2091
+ sort: [
2092
+ "property",
2093
+ "format"
2094
+ ],
2095
+ onValuesChanged: handleValuesChanged,
2096
+ onValidate: handleValidate,
2097
+ onSave: handleSave,
2098
+ onCancel: handleCancel,
2099
+ Custom: custom
2100
+ });
2101
+ } finally {
2102
+ _effect.f();
2103
+ }
2104
+ };
2105
+
2106
+ // packages/ui/react-ui-form/src/components/ViewEditor/ViewEditor.tsx
2107
+ import { useSignals as _useSignals15 } from "@preact-signals/safe-react/tracking";
2108
+ import { Schema as Schema2 } from "effect";
2109
+ import React15, { useCallback as useCallback10, useMemo as useMemo8, useState as useState6 } from "react";
2110
+ import { EchoSchema, Format, isMutable, toJsonSchema } from "@dxos/echo-schema";
2111
+ import { invariant as invariant3 } from "@dxos/invariant";
2112
+ import { Icon as Icon3, IconButton as IconButton4, Message, useTranslation as useTranslation9 } from "@dxos/react-ui";
2113
+ import { List as List2 } from "@dxos/react-ui-list";
2114
+ import { ghostHover, inputTextLabel, mx as mx8 } from "@dxos/react-ui-theme";
2115
+ import { FieldSchema, ViewProjection, VIEW_FIELD_LIMIT } from "@dxos/schema";
2116
+ var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/ViewEditor/ViewEditor.tsx";
2117
+ var grid = "grid grid-cols-[32px_1fr_32px] min-bs-[2.5rem]";
2118
+ var ViewMetaSchema = Schema2.Struct({
2119
+ name: Schema2.String.annotations({
2120
+ title: "View"
2121
+ }),
2122
+ typename: Format.URL.annotations({
2123
+ title: "Typename"
2124
+ })
2125
+ }).pipe(Schema2.mutable);
2126
+ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading = false, onTypenameChanged, onDelete }) => {
2127
+ var _effect = _useSignals15();
2128
+ try {
2129
+ const { t } = useTranslation9(translationKey);
2130
+ const projection = useMemo8(() => {
2131
+ const jsonSchema = schema instanceof EchoSchema ? schema.jsonSchema : toJsonSchema(schema);
2132
+ return new ViewProjection(jsonSchema, view);
2133
+ }, [
2134
+ schema,
2135
+ view
2136
+ ]);
2137
+ const [field, setField] = useState6();
2138
+ const immutable = readonly || !isMutable(schema);
2139
+ const viewValues = useMemo8(() => {
2140
+ return {
2141
+ name: view.name,
2142
+ // TODO(burdon): Need to warn user of possible consequences of editing.
2143
+ // TODO(burdon): Settings should have domain name owned by user.
2144
+ typename: view.query.typename
2145
+ };
2146
+ }, [
2147
+ view
2148
+ ]);
2149
+ const handleSelect = useCallback10((field2) => {
2150
+ if (immutable) {
2151
+ return;
2152
+ }
2153
+ setField((f) => f === field2 ? void 0 : field2);
2154
+ }, [
2155
+ immutable
2156
+ ]);
2157
+ const handleAdd = useCallback10(() => {
2158
+ invariant3(!immutable, void 0, {
2159
+ F: __dxlog_file5,
2160
+ L: 88,
2161
+ S: void 0,
2162
+ A: [
2163
+ "!immutable",
2164
+ ""
2165
+ ]
2166
+ });
2167
+ const field2 = projection.createFieldProjection();
2168
+ setField(field2);
2169
+ }, [
2170
+ schema,
2171
+ view
2172
+ ]);
2173
+ const handleUpdate = useCallback10(({ name, typename }) => {
2174
+ invariant3(!immutable, void 0, {
2175
+ F: __dxlog_file5,
2176
+ L: 95,
2177
+ S: void 0,
2178
+ A: [
2179
+ "!immutable",
2180
+ ""
2181
+ ]
2182
+ });
2183
+ requestAnimationFrame(() => {
2184
+ if (view.name !== name) {
2185
+ view.name = name;
2186
+ }
2187
+ if (view.query.typename !== typename && !immutable) {
2188
+ onTypenameChanged?.(typename);
2189
+ }
2190
+ });
2191
+ }, [
2192
+ schema,
2193
+ view,
2194
+ onTypenameChanged,
2195
+ immutable
2196
+ ]);
2197
+ const handleDelete = useCallback10((fieldId) => {
2198
+ invariant3(!immutable, void 0, {
2199
+ F: __dxlog_file5,
2200
+ L: 111,
2201
+ S: void 0,
2202
+ A: [
2203
+ "!immutable",
2204
+ ""
2205
+ ]
2206
+ });
2207
+ if (fieldId === field?.id) {
2208
+ setField(void 0);
2209
+ }
2210
+ onDelete?.(fieldId);
2211
+ }, [
2212
+ schema,
2213
+ field,
2214
+ onDelete
2215
+ ]);
2216
+ const handleMove = useCallback10((fromIndex, toIndex) => {
2217
+ invariant3(!immutable, void 0, {
2218
+ F: __dxlog_file5,
2219
+ L: 123,
2220
+ S: void 0,
2221
+ A: [
2222
+ "!immutable",
2223
+ ""
2224
+ ]
2225
+ });
2226
+ const fields = [
2227
+ ...view.fields
2228
+ ];
2229
+ const [moved] = fields.splice(fromIndex, 1);
2230
+ fields.splice(toIndex, 0, moved);
2231
+ view.fields = fields;
2232
+ }, [
2233
+ schema,
2234
+ view.fields
2235
+ ]);
2236
+ const handleClose = useCallback10(() => setField(void 0), []);
2237
+ const hiddenProperties = projection.getHiddenProperties();
2238
+ const handleHide = useCallback10((fieldId) => {
2239
+ setField(void 0);
2240
+ projection.hideFieldProjection(fieldId);
2241
+ }, [
2242
+ projection
2243
+ ]);
2244
+ const handleShow = useCallback10((property) => {
2245
+ setField(void 0);
2246
+ projection.showFieldProjection(property);
2247
+ }, [
2248
+ projection
2249
+ ]);
2250
+ return /* @__PURE__ */ React15.createElement("div", {
2251
+ role: "none",
2252
+ className: mx8("overflow-y-auto", classNames)
2253
+ }, immutable && /* @__PURE__ */ React15.createElement("div", {
2254
+ role: "none",
2255
+ className: "mbe-2"
2256
+ }, /* @__PURE__ */ React15.createElement(Message.Root, {
2257
+ valence: "neutral",
2258
+ className: "rounded"
2259
+ }, /* @__PURE__ */ React15.createElement(Message.Title, null, /* @__PURE__ */ React15.createElement(Icon3, {
2260
+ icon: "ph--info--regular",
2261
+ size: 5,
2262
+ classNames: "inline"
2263
+ }), " ", t("system schema title")), /* @__PURE__ */ React15.createElement(Message.Body, null, t("system schema description")))), /* @__PURE__ */ React15.createElement(Form, {
2264
+ autoSave: true,
2265
+ schema: ViewMetaSchema,
2266
+ values: viewValues,
2267
+ onSave: handleUpdate,
2268
+ classNames: "min-bs-0 overflow-y-auto"
2269
+ }), /* @__PURE__ */ React15.createElement("div", {
2270
+ role: "none",
2271
+ className: "min-bs-0 overflow-y-auto"
2272
+ }, /* @__PURE__ */ React15.createElement("div", {
2273
+ role: "none",
2274
+ className: "p-2"
2275
+ }, /* @__PURE__ */ React15.createElement("label", {
2276
+ className: mx8(inputTextLabel)
2277
+ }, t("fields label"))), /* @__PURE__ */ React15.createElement(List2.Root, {
2278
+ items: view.fields,
2279
+ isItem: Schema2.is(FieldSchema),
2280
+ getId: (field2) => field2.id,
2281
+ onMove: immutable ? void 0 : handleMove
2282
+ }, ({ items: fields }) => /* @__PURE__ */ React15.createElement(React15.Fragment, null, showHeading && /* @__PURE__ */ React15.createElement("div", {
2283
+ role: "heading",
2284
+ className: grid
2285
+ }, /* @__PURE__ */ React15.createElement("div", null), /* @__PURE__ */ React15.createElement("div", {
2286
+ className: "flex items-center text-sm"
2287
+ }, t("field path label"))), /* @__PURE__ */ React15.createElement("div", {
2288
+ role: "list",
2289
+ className: "flex flex-col w-full"
2290
+ }, fields?.map((field2) => /* @__PURE__ */ React15.createElement(List2.Item, {
2291
+ key: field2.id,
2292
+ item: field2,
2293
+ classNames: mx8(grid, ghostHover, !immutable && "cursor-pointer")
2294
+ }, /* @__PURE__ */ React15.createElement(List2.ItemDragHandle, null), /* @__PURE__ */ React15.createElement(List2.ItemTitle, {
2295
+ onClick: () => handleSelect(field2)
2296
+ }, field2.path), /* @__PURE__ */ React15.createElement("div", {
2297
+ className: "flex items-center gap-2 -ml-4"
2298
+ }, /* @__PURE__ */ React15.createElement(List2.ItemButton, {
2299
+ icon: "ph--eye-slash--regular",
2300
+ disabled: view.fields.length <= 1,
2301
+ onClick: () => handleHide(field2.id),
2302
+ "data-testid": "hide-field-button"
2303
+ }), !immutable && /* @__PURE__ */ React15.createElement(List2.ItemDeleteButton, {
2304
+ icon: "ph--trash--regular",
2305
+ disabled: view.fields.length <= 1,
2306
+ onClick: () => handleDelete(field2.id)
2307
+ }))))))), hiddenProperties.length > 0 && /* @__PURE__ */ React15.createElement("div", null, /* @__PURE__ */ React15.createElement("div", {
2308
+ role: "none",
2309
+ className: "p-2"
2310
+ }, /* @__PURE__ */ React15.createElement("label", {
2311
+ className: mx8(inputTextLabel)
2312
+ }, t("hidden fields label"))), /* @__PURE__ */ React15.createElement(List2.Root, {
2313
+ items: hiddenProperties,
2314
+ isItem: (item) => typeof item === "string",
2315
+ getId: (property) => property
2316
+ }, ({ items: properties }) => /* @__PURE__ */ React15.createElement("div", {
2317
+ role: "list",
2318
+ className: "flex flex-col w-full"
2319
+ }, properties?.map((property) => /* @__PURE__ */ React15.createElement(List2.Item, {
2320
+ key: property,
2321
+ item: property,
2322
+ classNames: mx8(grid, ghostHover, !immutable && "cursor-pointer")
2323
+ }, /* @__PURE__ */ React15.createElement("div", null), /* @__PURE__ */ React15.createElement(List2.ItemTitle, null, property), /* @__PURE__ */ React15.createElement(List2.ItemButton, {
2324
+ icon: "ph--eye--regular",
2325
+ onClick: () => handleShow(property),
2326
+ "data-testid": "show-field-button"
2327
+ }))))))), field && /* @__PURE__ */ React15.createElement(FieldEditor, {
2328
+ key: field.id,
2329
+ view,
2330
+ projection,
2331
+ field,
2332
+ registry,
2333
+ onSave: handleClose
2334
+ }), !readonly && !field && /* @__PURE__ */ React15.createElement("div", {
2335
+ role: "none",
2336
+ className: "p-2"
2337
+ }, /* @__PURE__ */ React15.createElement(IconButton4, {
2338
+ icon: "ph--plus--regular",
2339
+ label: t("button add property"),
2340
+ onClick: immutable ? void 0 : handleAdd,
2341
+ // TODO(burdon): Show field limit in ux (not tooltip).
2342
+ disabled: view.fields.length >= VIEW_FIELD_LIMIT,
2343
+ classNames: "flex is-full"
2344
+ })));
2345
+ } finally {
2346
+ _effect.f();
2347
+ }
2348
+ };
1847
2349
  export {
1848
2350
  BooleanInput,
1849
2351
  ControlFrame,
1850
2352
  ControlFrameItem,
1851
2353
  ControlGroup,
2354
+ ControlGroupButton,
1852
2355
  ControlItem,
1853
2356
  ControlItemInput,
2357
+ ControlPage,
1854
2358
  ControlSection,
1855
2359
  ControlSectionHeading,
1856
2360
  DeprecatedFormContainer,
@@ -1869,14 +2373,18 @@ export {
1869
2373
  ViewEditor,
1870
2374
  cellClassesForFieldType,
1871
2375
  controlItemClasses,
2376
+ findArrayElementType,
1872
2377
  formatForDisplay,
1873
2378
  formatForEditing,
2379
+ getRefProps,
1874
2380
  parseValue,
1875
2381
  pathNotUniqueError,
1876
2382
  translations_default as translations,
1877
2383
  useForm,
1878
2384
  useFormContext,
1879
2385
  useFormValues,
1880
- useInputProps
2386
+ useInputProps,
2387
+ useQueryRefOptions,
2388
+ useRefQueryLookupHandler
1881
2389
  };
1882
2390
  //# sourceMappingURL=index.mjs.map