@dxos/react-ui-form 0.7.5-main.9d26e3a → 0.7.5-main.e9bb01b

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 (70) hide show
  1. package/dist/lib/browser/index.mjs +743 -466
  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 +777 -515
  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 +743 -466
  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/FieldEditor/FieldEditor.d.ts.map +1 -1
  11. package/dist/types/src/components/Form/ArrayField.d.ts +16 -0
  12. package/dist/types/src/components/Form/ArrayField.d.ts.map +1 -0
  13. package/dist/types/src/components/Form/Defaults.d.ts +5 -6
  14. package/dist/types/src/components/Form/Defaults.d.ts.map +1 -1
  15. package/dist/types/src/components/Form/Form.d.ts +13 -16
  16. package/dist/types/src/components/Form/Form.d.ts.map +1 -1
  17. package/dist/types/src/components/Form/Form.stories.d.ts +2 -1
  18. package/dist/types/src/components/Form/Form.stories.d.ts.map +1 -1
  19. package/dist/types/src/components/Form/FormActions.d.ts +7 -0
  20. package/dist/types/src/components/Form/FormActions.d.ts.map +1 -0
  21. package/dist/types/src/components/Form/FormContent.d.ts +26 -0
  22. package/dist/types/src/components/Form/FormContent.d.ts.map +1 -0
  23. package/dist/types/src/components/Form/FormContext.d.ts +20 -0
  24. package/dist/types/src/components/Form/FormContext.d.ts.map +1 -0
  25. package/dist/types/src/components/Form/Input.d.ts +5 -6
  26. package/dist/types/src/components/Form/Input.d.ts.map +1 -1
  27. package/dist/types/src/components/Form/custom/GeoPointInput.d.ts +1 -2
  28. package/dist/types/src/components/Form/custom/GeoPointInput.d.ts.map +1 -1
  29. package/dist/types/src/components/Form/custom/SelectOptionsInput.d.ts +4 -0
  30. package/dist/types/src/components/Form/custom/SelectOptionsInput.d.ts.map +1 -0
  31. package/dist/types/src/components/Form/custom/SelectOptionsInput.stories.d.ts +7 -0
  32. package/dist/types/src/components/Form/custom/SelectOptionsInput.stories.d.ts.map +1 -0
  33. package/dist/types/src/components/Form/custom/TupleInput.d.ts +1 -2
  34. package/dist/types/src/components/Form/custom/TupleInput.d.ts.map +1 -1
  35. package/dist/types/src/components/Form/custom/index.d.ts +1 -0
  36. package/dist/types/src/components/Form/custom/index.d.ts.map +1 -1
  37. package/dist/types/src/components/Form/factory.d.ts +2 -2
  38. package/dist/types/src/components/Form/factory.d.ts.map +1 -1
  39. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts +2 -1
  40. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts.map +1 -1
  41. package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts.map +1 -1
  42. package/dist/types/src/components/deprecated/FormInput.d.ts +5 -0
  43. package/dist/types/src/components/deprecated/FormInput.d.ts.map +1 -1
  44. package/dist/types/src/hooks/useForm.d.ts +9 -10
  45. package/dist/types/src/hooks/useForm.d.ts.map +1 -1
  46. package/dist/types/src/translations.d.ts +6 -0
  47. package/dist/types/src/translations.d.ts.map +1 -1
  48. package/dist/types/tsconfig.tsbuildinfo +1 -1
  49. package/package.json +25 -24
  50. package/src/components/FieldEditor/FieldEditor.stories.tsx +1 -1
  51. package/src/components/FieldEditor/FieldEditor.tsx +58 -40
  52. package/src/components/Form/ArrayField.tsx +111 -0
  53. package/src/components/Form/Defaults.tsx +18 -33
  54. package/src/components/Form/Form.stories.tsx +15 -5
  55. package/src/components/Form/Form.tsx +39 -330
  56. package/src/components/Form/FormActions.tsx +41 -0
  57. package/src/components/Form/FormContent.tsx +173 -0
  58. package/src/components/Form/FormContext.tsx +48 -0
  59. package/src/components/Form/Input.tsx +5 -6
  60. package/src/components/Form/custom/GeoPointInput.tsx +6 -15
  61. package/src/components/Form/custom/SelectOptionsInput.stories.tsx +58 -0
  62. package/src/components/Form/custom/SelectOptionsInput.tsx +192 -0
  63. package/src/components/Form/custom/TupleInput.tsx +5 -9
  64. package/src/components/Form/custom/index.ts +1 -0
  65. package/src/components/Form/factory.tsx +2 -5
  66. package/src/components/ViewEditor/ViewEditor.stories.tsx +25 -4
  67. package/src/components/ViewEditor/ViewEditor.tsx +14 -6
  68. package/src/components/deprecated/FormInput.tsx +19 -3
  69. package/src/hooks/useForm.ts +54 -47
  70. package/src/translations.ts +8 -0
@@ -29,14 +29,15 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
29
29
  var node_exports = {};
30
30
  __export(node_exports, {
31
31
  BooleanInput: () => BooleanInput,
32
+ DeprecatedFormContainer: () => DeprecatedFormContainer,
32
33
  DeprecatedFormInput: () => DeprecatedFormInput,
33
34
  FieldEditor: () => FieldEditor,
34
35
  Form: () => Form,
35
- FormActions: () => FormActions,
36
36
  GeoPointInput: () => GeoPointInput,
37
37
  InputHeader: () => InputHeader,
38
38
  NumberInput: () => NumberInput,
39
39
  SelectInput: () => SelectInput,
40
+ SelectOptionInput: () => SelectOptionInput,
40
41
  TextInput: () => TextInput,
41
42
  TupleInput: () => TupleInput,
42
43
  ViewEditor: () => ViewEditor,
@@ -52,6 +53,7 @@ __export(node_exports, {
52
53
  module.exports = __toCommonJS(node_exports);
53
54
  var import_react = __toESM(require("react"));
54
55
  var import_react_ui = require("@dxos/react-ui");
56
+ var import_react_ui_theme = require("@dxos/react-ui-theme");
55
57
  var import_react2 = __toESM(require("react"));
56
58
  var import_echo_schema = require("@dxos/echo-schema");
57
59
  var import_log = require("@dxos/log");
@@ -62,38 +64,60 @@ var import_react_ui3 = require("@dxos/react-ui");
62
64
  var import_util = require("@dxos/util");
63
65
  var import_react4 = __toESM(require("react"));
64
66
  var import_react_ui4 = require("@dxos/react-ui");
65
- var import_react_ui_theme = require("@dxos/react-ui-theme");
67
+ var import_react_ui_theme2 = require("@dxos/react-ui-theme");
66
68
  var import_react5 = __toESM(require("react"));
69
+ var import_keys = require("@dxos/keys");
67
70
  var import_react_ui5 = require("@dxos/react-ui");
68
- var import_react_ui_theme2 = require("@dxos/react-ui-theme");
69
- var import_util2 = require("@dxos/util");
71
+ var import_react_ui_list = require("@dxos/react-ui-list");
72
+ var import_react_ui_pickers = require("@dxos/react-ui-pickers");
73
+ var import_react_ui_theme3 = require("@dxos/react-ui-theme");
70
74
  var import_react6 = __toESM(require("react"));
71
75
  var import_react_ui6 = require("@dxos/react-ui");
72
- var import_effect = require("effect");
73
- var import_String = require("effect/String");
76
+ var import_react_ui_theme4 = require("@dxos/react-ui-theme");
77
+ var import_util2 = require("@dxos/util");
74
78
  var import_react7 = __toESM(require("react"));
79
+ var import_react_ui7 = require("@dxos/react-ui");
80
+ var import_react8 = __toESM(require("react"));
81
+ var import_react_ui_theme5 = require("@dxos/react-ui-theme");
82
+ var import_react9 = __toESM(require("react"));
83
+ var import_react_ui8 = require("@dxos/react-ui");
84
+ var import_react_ui_theme6 = require("@dxos/react-ui-theme");
85
+ var import_react10 = __toESM(require("react"));
86
+ var import_debug = require("@dxos/debug");
75
87
  var import_echo_schema2 = require("@dxos/echo-schema");
88
+ var import_effect = require("@dxos/effect");
89
+ var import_react11 = require("react");
90
+ var import_echo_schema3 = require("@dxos/echo-schema");
76
91
  var import_effect2 = require("@dxos/effect");
92
+ var import_invariant = require("@dxos/invariant");
77
93
  var import_log2 = require("@dxos/log");
78
- var import_react_ui7 = require("@dxos/react-ui");
79
- var import_react_ui_theme3 = require("@dxos/react-ui-theme");
80
94
  var import_schema2 = require("@dxos/schema");
81
- var import_util3 = require("@dxos/util");
82
- var import_echo_schema3 = require("@dxos/echo-schema");
83
- var import_react8 = require("react");
95
+ var import_effect3 = require("effect");
96
+ var import_String = require("effect/String");
97
+ var import_react12 = __toESM(require("react"));
84
98
  var import_echo_schema4 = require("@dxos/echo-schema");
85
- var import_invariant = require("@dxos/invariant");
86
- var import_log3 = require("@dxos/log");
99
+ var import_effect4 = require("@dxos/effect");
100
+ var import_react_ui_theme7 = require("@dxos/react-ui-theme");
87
101
  var import_schema3 = require("@dxos/schema");
88
- var import_react9 = __toESM(require("react"));
102
+ var import_util3 = require("@dxos/util");
103
+ var import_effect5 = require("effect");
104
+ var import_String2 = require("effect/String");
105
+ var import_react13 = __toESM(require("react"));
89
106
  var import_echo_schema5 = require("@dxos/echo-schema");
90
- var import_react_ui8 = require("@dxos/react-ui");
91
- var import_react_ui_list = require("@dxos/react-ui-list");
92
- var import_react_ui_theme4 = require("@dxos/react-ui-theme");
107
+ var import_effect6 = require("@dxos/effect");
108
+ var import_invariant2 = require("@dxos/invariant");
109
+ var import_react_ui9 = require("@dxos/react-ui");
110
+ var import_react_ui_theme8 = require("@dxos/react-ui-theme");
93
111
  var import_schema4 = require("@dxos/schema");
94
- var import_util4 = require("@dxos/util");
95
112
  var import_echo_schema6 = require("@dxos/echo-schema");
113
+ var import_react14 = __toESM(require("react"));
96
114
  var import_echo_schema7 = require("@dxos/echo-schema");
115
+ var import_react_ui10 = require("@dxos/react-ui");
116
+ var import_react_ui_list2 = require("@dxos/react-ui-list");
117
+ var import_react_ui_theme9 = require("@dxos/react-ui-theme");
118
+ var import_schema5 = require("@dxos/schema");
119
+ var import_echo_schema8 = require("@dxos/echo-schema");
120
+ var import_echo_schema9 = require("@dxos/echo-schema");
97
121
  var translationKey = "react-ui-form";
98
122
  var translations_default = [
99
123
  {
@@ -130,6 +154,7 @@ var translations_default = [
130
154
  "format ref": "Reference",
131
155
  "format regex": "RegExp",
132
156
  "format string": "String",
157
+ "format single-select": "Select",
133
158
  "format text": "Long text",
134
159
  "format time": "Time",
135
160
  "format timestamp": "Timestamp",
@@ -139,11 +164,26 @@ var translations_default = [
139
164
  "format uuid": "UUID",
140
165
  // Placeholders
141
166
  "placeholder latitude": "Latitude",
142
- "placeholder longitude": "Longitude"
167
+ "placeholder longitude": "Longitude",
168
+ // SelectOptionsInput
169
+ "select option label": "Label",
170
+ "select option label placeholder": "Option label",
171
+ "select option color": "Color",
172
+ "select option delete": "Delete",
173
+ "select option add": "Add option"
143
174
  }
144
175
  }
145
176
  }
146
177
  ];
178
+ var DeprecatedFormContainer = ({ children, classNames }) => {
179
+ return /* @__PURE__ */ import_react.default.createElement("div", {
180
+ role: "none",
181
+ className: "w-full p-4 justify-center overflow-x-hidden overflow-y-auto"
182
+ }, /* @__PURE__ */ import_react.default.createElement("div", {
183
+ role: "form",
184
+ className: (0, import_react_ui_theme.mx)("flex flex-col", import_react_ui_theme.textBlockWidth, classNames)
185
+ }, children));
186
+ };
147
187
  var DeprecatedFormInput = ({ label, description, secondary, children }) => {
148
188
  const primary = /* @__PURE__ */ import_react.default.createElement("div", {
149
189
  role: "none",
@@ -152,14 +192,17 @@ var DeprecatedFormInput = ({ label, description, secondary, children }) => {
152
192
  role: "none",
153
193
  className: "flex flex-col w-full"
154
194
  }, /* @__PURE__ */ import_react.default.createElement(import_react_ui.Input.Label, {
155
- classNames: "flex min-h-[40px] items-center"
195
+ classNames: "flex min-bs-[--rail-action] items-center",
196
+ style: {
197
+ fontSize: "unset"
198
+ }
156
199
  }, label), description && /* @__PURE__ */ import_react.default.createElement(import_react_ui.Input.DescriptionAndValidation, {
157
200
  classNames: "mbs-0.5"
158
201
  }, /* @__PURE__ */ import_react.default.createElement(import_react_ui.Input.Description, null, description))), /* @__PURE__ */ import_react.default.createElement("div", {
159
202
  role: "none"
160
203
  }, /* @__PURE__ */ import_react.default.createElement("div", {
161
204
  role: "none",
162
- className: "flex min-h-[40px] items-center"
205
+ className: "flex min-bs-[--rail-action] items-center"
163
206
  }, children))));
164
207
  if (secondary) {
165
208
  return /* @__PURE__ */ import_react.default.createElement("div", {
@@ -178,15 +221,15 @@ var InputHeader = ({ children, error }) => {
178
221
  }, /* @__PURE__ */ import_react4.default.createElement(import_react_ui4.Icon, {
179
222
  icon: "ph--warning--regular",
180
223
  size: 4,
181
- classNames: import_react_ui_theme.errorText
224
+ classNames: import_react_ui_theme2.errorText
182
225
  })), /* @__PURE__ */ import_react4.default.createElement(import_react_ui4.Tooltip.Content, {
183
226
  side: "bottom"
184
227
  }, /* @__PURE__ */ import_react4.default.createElement(import_react_ui4.Tooltip.Arrow, null), error)));
185
228
  };
186
- var GeoPointInput = ({ property, type, label, disabled, getStatus, getValue: getValue2, onValueChange, onBlur }) => {
229
+ var GeoPointInput = ({ type, label, disabled, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
187
230
  const { t } = (0, import_react_ui3.useTranslation)(translationKey);
188
- const { status, error } = getStatus?.(property);
189
- const [lng = 0, lat = 0] = getValue2(property) ?? [];
231
+ const { status, error } = getStatus();
232
+ const [lng = 0, lat = 0] = getValue3() ?? [];
190
233
  return /* @__PURE__ */ import_react3.default.createElement(import_react_ui3.Input.Root, {
191
234
  validationValence: status
192
235
  }, /* @__PURE__ */ import_react3.default.createElement(InputHeader, {
@@ -198,7 +241,7 @@ var GeoPointInput = ({ property, type, label, disabled, getStatus, getValue: get
198
241
  disabled,
199
242
  placeholder: t("placeholder longitude"),
200
243
  value: lng,
201
- onChange: (event) => onValueChange(property, type, [
244
+ onChange: (event) => onValueChange(type, [
202
245
  lat,
203
246
  (0, import_util.safeParseFloat)(event.target.value, 0)
204
247
  ]),
@@ -208,129 +251,290 @@ var GeoPointInput = ({ property, type, label, disabled, getStatus, getValue: get
208
251
  disabled,
209
252
  placeholder: t("placeholder latitude"),
210
253
  value: lat,
211
- onChange: (event) => onValueChange(property, type, [
254
+ onChange: (event) => onValueChange(type, [
212
255
  (0, import_util.safeParseFloat)(event.target.value, 0),
213
256
  lng
214
257
  ]),
215
258
  onBlur
216
259
  })));
217
260
  };
261
+ var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3, onValueChange }) => {
262
+ const [selected, setSelectedId] = (0, import_react5.useState)(null);
263
+ const [isNewOption, setIsNewOption] = (0, import_react5.useState)(false);
264
+ const inputRef = (0, import_react5.useRef)(null);
265
+ const { t } = (0, import_react_ui5.useTranslation)(translationKey);
266
+ const { status, error } = getStatus();
267
+ const options = getValue3();
268
+ (0, import_react5.useEffect)(() => {
269
+ if (options === void 0) {
270
+ onValueChange(type, []);
271
+ }
272
+ }, [
273
+ options,
274
+ onValueChange,
275
+ type
276
+ ]);
277
+ const randomHue = () => {
278
+ const usedHues = new Set(options?.map((option) => option.color) ?? []);
279
+ const hueKeys = Object.keys(import_react_ui_theme3.hueTokenThemes);
280
+ const unusedHues = hueKeys.filter((hue) => !usedHues.has(hue));
281
+ if (unusedHues.length > 0) {
282
+ return unusedHues[Math.floor(Math.random() * unusedHues.length)];
283
+ }
284
+ const lastThree = new Set(options?.slice(-3).map((option) => option.color) ?? []);
285
+ const availableHues = hueKeys.filter((hue) => !lastThree.has(hue));
286
+ return availableHues[Math.floor(Math.random() * availableHues.length)] ?? hueKeys[Math.floor(Math.random() * hueKeys.length)];
287
+ };
288
+ const handleAdd = (0, import_react5.useCallback)(() => {
289
+ const newId = import_keys.PublicKey.random().truncate();
290
+ const newOption = {
291
+ id: newId,
292
+ title: "",
293
+ color: randomHue()
294
+ };
295
+ onValueChange(type, [
296
+ ...options ?? [],
297
+ newOption
298
+ ]);
299
+ setSelectedId(newId);
300
+ setIsNewOption(true);
301
+ }, [
302
+ options,
303
+ type,
304
+ onValueChange
305
+ ]);
306
+ const handleDelete = (0, import_react5.useCallback)((id) => {
307
+ const newOptions = options?.filter((option) => option.id !== id) ?? [];
308
+ onValueChange(type, newOptions);
309
+ setSelectedId(null);
310
+ }, [
311
+ options,
312
+ type,
313
+ onValueChange
314
+ ]);
315
+ const handleMove = (0, import_react5.useCallback)((from, to) => {
316
+ if (!options) {
317
+ return;
318
+ }
319
+ const newOptions = [
320
+ ...options
321
+ ];
322
+ const [removed] = newOptions.splice(from, 1);
323
+ newOptions.splice(to, 0, removed);
324
+ onValueChange(type, newOptions);
325
+ }, [
326
+ options,
327
+ type,
328
+ onValueChange
329
+ ]);
330
+ const handleClick = (0, import_react5.useCallback)((id) => {
331
+ setSelectedId((current) => current === id ? null : id);
332
+ }, []);
333
+ const handleTitleChange = (0, import_react5.useCallback)((id) => (e) => {
334
+ const newOptions = options?.map((o) => o.id === id ? {
335
+ ...o,
336
+ title: e.target.value
337
+ } : o);
338
+ onValueChange(type, newOptions ?? []);
339
+ }, [
340
+ options,
341
+ type,
342
+ onValueChange
343
+ ]);
344
+ const handleKeyDown = (0, import_react5.useCallback)((e) => {
345
+ if (e.key === "Enter") {
346
+ setSelectedId(null);
347
+ }
348
+ }, []);
349
+ const handleColorChange = (0, import_react5.useCallback)((id) => (hue) => {
350
+ const newOptions = options?.map((o) => o.id === id ? {
351
+ ...o,
352
+ color: hue
353
+ } : o);
354
+ onValueChange(type, newOptions ?? []);
355
+ }, [
356
+ options,
357
+ type,
358
+ onValueChange
359
+ ]);
360
+ (0, import_react5.useEffect)(() => {
361
+ if (selected && isNewOption && inputRef.current) {
362
+ inputRef.current.focus();
363
+ setIsNewOption(false);
364
+ }
365
+ }, [
366
+ selected,
367
+ isNewOption
368
+ ]);
369
+ return /* @__PURE__ */ import_react5.default.createElement(import_react_ui5.Input.Root, {
370
+ validationValence: status
371
+ }, /* @__PURE__ */ import_react5.default.createElement(InputHeader, {
372
+ error
373
+ }, /* @__PURE__ */ import_react5.default.createElement(import_react_ui5.Input.Label, null, label)), /* @__PURE__ */ import_react5.default.createElement("div", {
374
+ role: "none"
375
+ }, options && /* @__PURE__ */ import_react5.default.createElement(import_react_ui_list.List.Root, {
376
+ items: options,
377
+ isItem: (item) => true,
378
+ onMove: handleMove
379
+ }, ({ items }) => /* @__PURE__ */ import_react5.default.createElement("div", {
380
+ role: "list",
381
+ className: "w-full overflow-auto"
382
+ }, items?.map((item) => /* @__PURE__ */ import_react5.default.createElement("div", {
383
+ key: item.id
384
+ }, /* @__PURE__ */ import_react5.default.createElement(import_react_ui_list.List.Item, {
385
+ role: "button",
386
+ item,
387
+ classNames: (0, import_react_ui_theme3.mx)("p-1 plb-2", "flex flex-col", "cursor-pointer", "hover:bg-hoverOverlay"),
388
+ "aria-expanded": selected === item.id
389
+ }, /* @__PURE__ */ import_react5.default.createElement("div", {
390
+ className: "flex items-center"
391
+ }, /* @__PURE__ */ import_react5.default.createElement(import_react_ui_list.List.ItemDragHandle, null), /* @__PURE__ */ import_react5.default.createElement(import_react_ui_list.List.ItemTitle, {
392
+ onClick: () => handleClick(item.id),
393
+ classNames: "flex-1"
394
+ }, /* @__PURE__ */ import_react5.default.createElement(import_react_ui5.Tag, {
395
+ palette: item.color
396
+ }, item.title || "\u200B")), /* @__PURE__ */ import_react5.default.createElement(import_react_ui5.Icon, {
397
+ icon: selected === item.id ? "ph--caret-down--regular" : "ph--caret-right--regular",
398
+ onClick: () => handleClick(item.id)
399
+ })), selected === item.id && /* @__PURE__ */ import_react5.default.createElement("div", {
400
+ className: "mis-4 mbs-2 flex flex-col gap-1"
401
+ }, /* @__PURE__ */ import_react5.default.createElement(import_react_ui5.Input.Label, {
402
+ classNames: "text-xs"
403
+ }, t("select option label")), /* @__PURE__ */ import_react5.default.createElement("div", {
404
+ className: "flex flex-row items-center gap-1"
405
+ }, /* @__PURE__ */ import_react5.default.createElement(import_react_ui5.Input.TextInput, {
406
+ placeholder: t("select option label placeholder"),
407
+ ref: selected === item.id ? inputRef : void 0,
408
+ value: item.title,
409
+ onChange: handleTitleChange(item.id),
410
+ onKeyDown: handleKeyDown,
411
+ classNames: "flex-1"
412
+ }), /* @__PURE__ */ import_react5.default.createElement(import_react_ui5.Toolbar.Root, {
413
+ classNames: "p-0 m-0 !is-auto"
414
+ }, /* @__PURE__ */ import_react5.default.createElement(import_react_ui_pickers.HuePickerToolbarButton, {
415
+ hue: item.color,
416
+ onChangeHue: handleColorChange(item.id)
417
+ })), /* @__PURE__ */ import_react5.default.createElement(import_react_ui5.IconButton, {
418
+ icon: "ph--trash--fill",
419
+ iconOnly: true,
420
+ label: t("select option delete"),
421
+ onClick: () => handleDelete(item.id)
422
+ })))))), /* @__PURE__ */ import_react5.default.createElement("div", {
423
+ role: "listitem"
424
+ }, /* @__PURE__ */ import_react5.default.createElement("div", {
425
+ role: "button",
426
+ className: (0, import_react_ui_theme3.mx)("p-1 plb-2", "flex flex-col", "cursor-pointer", "hover:bg-hoverOverlay"),
427
+ onClick: handleAdd
428
+ }, /* @__PURE__ */ import_react5.default.createElement("div", {
429
+ className: "flex items-center gap-1"
430
+ }, /* @__PURE__ */ import_react5.default.createElement(import_react_ui5.Icon, {
431
+ icon: "ph--plus--regular"
432
+ }), /* @__PURE__ */ import_react5.default.createElement("span", {
433
+ className: "text-sm"
434
+ }, t("select option add")))))))));
435
+ };
218
436
  var gridCols = [
219
437
  "grid-cols-1",
220
438
  "grid-cols-2",
221
439
  "grid-cols-3",
222
440
  "grid-cols-4"
223
441
  ];
224
- var TupleInput = ({ binding, property, type, label, disabled, getStatus, getValue: getValue2, onValueChange, onBlur }) => {
225
- const { status, error } = getStatus?.(property);
226
- const values = getValue2(property) ?? {};
227
- return /* @__PURE__ */ import_react5.default.createElement(import_react_ui5.Input.Root, {
442
+ var TupleInput = ({ binding, type, label, disabled, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
443
+ const { status, error } = getStatus();
444
+ const values = getValue3() ?? {};
445
+ return /* @__PURE__ */ import_react6.default.createElement(import_react_ui6.Input.Root, {
228
446
  validationValence: status
229
- }, /* @__PURE__ */ import_react5.default.createElement(InputHeader, {
447
+ }, /* @__PURE__ */ import_react6.default.createElement(InputHeader, {
230
448
  error
231
- }, /* @__PURE__ */ import_react5.default.createElement(import_react_ui5.Input.Label, null, label)), /* @__PURE__ */ import_react5.default.createElement("div", {
232
- className: (0, import_react_ui_theme2.mx)("grid gap-2", gridCols[binding.length - 1])
233
- }, binding.map((prop) => /* @__PURE__ */ import_react5.default.createElement(import_react_ui5.Input.TextInput, {
449
+ }, /* @__PURE__ */ import_react6.default.createElement(import_react_ui6.Input.Label, null, label)), /* @__PURE__ */ import_react6.default.createElement("div", {
450
+ className: (0, import_react_ui_theme4.mx)("grid gap-2", gridCols[binding.length - 1])
451
+ }, binding.map((prop) => /* @__PURE__ */ import_react6.default.createElement(import_react_ui6.Input.TextInput, {
234
452
  key: prop,
235
453
  type: "number",
236
454
  disabled,
237
455
  value: values[prop],
238
- onChange: (event) => onValueChange(property, type, {
456
+ onChange: (event) => onValueChange(type, {
239
457
  ...values,
240
458
  [prop]: (0, import_util2.safeParseFloat)(event.target.value, 0)
241
459
  }),
242
460
  onBlur
243
461
  }))));
244
462
  };
245
- var TextInput = ({ property, type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue2, onValueChange, onBlur }) => {
246
- const { status, error } = getStatus?.(property);
247
- return /* @__PURE__ */ import_react6.default.createElement(import_react_ui6.Input.Root, {
463
+ var TextInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
464
+ const { status, error } = getStatus();
465
+ return /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Input.Root, {
248
466
  validationValence: status
249
- }, !inputOnly && /* @__PURE__ */ import_react6.default.createElement(InputHeader, {
467
+ }, !inputOnly && /* @__PURE__ */ import_react7.default.createElement(InputHeader, {
250
468
  error
251
- }, /* @__PURE__ */ import_react6.default.createElement(import_react_ui6.Input.Label, null, label)), /* @__PURE__ */ import_react6.default.createElement(import_react_ui6.Input.TextInput, {
469
+ }, /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Input.Label, null, label)), /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Input.TextInput, {
252
470
  disabled,
253
471
  placeholder,
254
- value: getValue2(property) ?? "",
255
- onChange: (event) => onValueChange(property, type, event.target.value),
472
+ value: getValue3() ?? "",
473
+ onChange: (event) => onValueChange(type, event.target.value),
256
474
  onBlur
257
- }), inputOnly && /* @__PURE__ */ import_react6.default.createElement(import_react_ui6.Input.Validation, null, error));
475
+ }), inputOnly && /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Input.Validation, null, error));
258
476
  };
259
- var NumberInput = ({ property, type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue2, onValueChange, onBlur }) => {
260
- const { status, error } = getStatus?.(property);
261
- return /* @__PURE__ */ import_react6.default.createElement(import_react_ui6.Input.Root, {
477
+ var NumberInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
478
+ const { status, error } = getStatus();
479
+ return /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Input.Root, {
262
480
  validationValence: status
263
- }, !inputOnly && /* @__PURE__ */ import_react6.default.createElement(InputHeader, {
481
+ }, !inputOnly && /* @__PURE__ */ import_react7.default.createElement(InputHeader, {
264
482
  error
265
- }, /* @__PURE__ */ import_react6.default.createElement(import_react_ui6.Input.Label, null, label)), /* @__PURE__ */ import_react6.default.createElement(import_react_ui6.Input.TextInput, {
483
+ }, /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Input.Label, null, label)), /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Input.TextInput, {
266
484
  type: "number",
267
485
  disabled,
268
486
  placeholder,
269
- value: getValue2(property) ?? 0,
270
- onChange: (event) => onValueChange(property, type, event.target.value),
487
+ value: getValue3() ?? 0,
488
+ onChange: (event) => onValueChange(type, event.target.value),
271
489
  onBlur
272
- }), inputOnly && /* @__PURE__ */ import_react6.default.createElement(import_react_ui6.Input.DescriptionAndValidation, null, error));
490
+ }), inputOnly && /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Input.DescriptionAndValidation, null, error));
273
491
  };
274
- var BooleanInput = ({ property, type, label, inputOnly, getStatus, getValue: getValue2, onValueChange }) => {
275
- const { status, error } = getStatus?.(property);
276
- return /* @__PURE__ */ import_react6.default.createElement(import_react_ui6.Input.Root, {
492
+ var BooleanInput = ({ type, label, inputOnly, getStatus, getValue: getValue3, onValueChange }) => {
493
+ const { status, error } = getStatus();
494
+ return /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Input.Root, {
277
495
  validationValence: status
278
- }, !inputOnly && /* @__PURE__ */ import_react6.default.createElement(InputHeader, {
496
+ }, !inputOnly && /* @__PURE__ */ import_react7.default.createElement(InputHeader, {
279
497
  error
280
- }, /* @__PURE__ */ import_react6.default.createElement(import_react_ui6.Input.Label, null, label)), /* @__PURE__ */ import_react6.default.createElement(import_react_ui6.Input.Switch, {
281
- checked: getValue2(property),
282
- onCheckedChange: (value) => onValueChange(property, type, value)
283
- }), inputOnly && /* @__PURE__ */ import_react6.default.createElement(import_react_ui6.Input.DescriptionAndValidation, null, error));
498
+ }, /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Input.Label, null, label)), /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Input.Switch, {
499
+ checked: getValue3(),
500
+ onCheckedChange: (value) => onValueChange(type, value)
501
+ }), inputOnly && /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Input.DescriptionAndValidation, null, error));
284
502
  };
285
- var SelectInput = ({ property, type, label, inputOnly, disabled, placeholder, options, getStatus, getValue: getValue2, onValueChange }) => {
286
- const { status, error } = getStatus?.(property);
287
- return /* @__PURE__ */ import_react6.default.createElement(import_react_ui6.Input.Root, {
503
+ var SelectInput = ({ type, label, inputOnly, disabled, placeholder, options, getStatus, getValue: getValue3, onValueChange }) => {
504
+ const { status, error } = getStatus();
505
+ return /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Input.Root, {
288
506
  validationValence: status
289
- }, !inputOnly && /* @__PURE__ */ import_react6.default.createElement(InputHeader, {
507
+ }, !inputOnly && /* @__PURE__ */ import_react7.default.createElement(InputHeader, {
290
508
  error
291
- }, /* @__PURE__ */ import_react6.default.createElement(import_react_ui6.Input.Label, null, label)), /* @__PURE__ */ import_react6.default.createElement(import_react_ui6.Select.Root, {
292
- value: getValue2(property),
293
- onValueChange: (value) => onValueChange(property, type, value)
294
- }, /* @__PURE__ */ import_react6.default.createElement(import_react_ui6.Select.TriggerButton, {
509
+ }, /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Input.Label, null, label)), /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Select.Root, {
510
+ value: getValue3(),
511
+ onValueChange: (value) => onValueChange(type, value)
512
+ }, /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Select.TriggerButton, {
295
513
  classNames: "is-full",
296
514
  disabled,
297
515
  placeholder
298
- }), /* @__PURE__ */ import_react6.default.createElement(import_react_ui6.Select.Portal, null, /* @__PURE__ */ import_react6.default.createElement(import_react_ui6.Select.Content, null, /* @__PURE__ */ import_react6.default.createElement(import_react_ui6.Select.Viewport, null, options?.map(({ value, label: label2 }) => (
516
+ }), /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Select.Portal, null, /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Select.Content, null, /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Select.Viewport, null, options?.map(({ value, label: label2 }) => (
299
517
  // NOTE: Numeric values are converted to and from strings.
300
- /* @__PURE__ */ import_react6.default.createElement(import_react_ui6.Select.Option, {
518
+ /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Select.Option, {
301
519
  key: String(value),
302
520
  value: String(value)
303
521
  }, label2 ?? String(value))
304
- )))))), inputOnly && /* @__PURE__ */ import_react6.default.createElement(import_react_ui6.Input.DescriptionAndValidation, null, error));
305
- };
306
- var getInputComponent = (type, format) => {
307
- switch (format) {
308
- case import_echo_schema3.FormatEnum.LatLng:
309
- return GeoPointInput;
310
- }
311
- switch (type) {
312
- case "string":
313
- return TextInput;
314
- case "number":
315
- return NumberInput;
316
- case "boolean":
317
- return BooleanInput;
318
- }
522
+ )))))), inputOnly && /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Input.DescriptionAndValidation, null, error));
319
523
  };
320
524
  var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/hooks/useForm.ts";
321
525
  var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, onSave }) => {
322
- const [values, setValues] = (0, import_react8.useState)(initialValues);
323
- (0, import_react8.useEffect)(() => {
526
+ const [values, setValues] = (0, import_react11.useState)(initialValues);
527
+ (0, import_react11.useEffect)(() => {
324
528
  setValues(initialValues);
325
529
  }, [
326
530
  initialValues
327
531
  ]);
328
- const [touched, setTouched] = (0, import_react8.useState)(createKeySet(initialValues, false));
329
- const [changed, setChanged] = (0, import_react8.useState)(createKeySet(initialValues, false));
330
- const [errors, setErrors] = (0, import_react8.useState)({});
331
- const [saving, setSaving] = (0, import_react8.useState)(false);
332
- const validate = (0, import_react8.useCallback)((values2) => {
333
- let errors2 = (0, import_schema3.validateSchema)(schema, values2) ?? [];
532
+ const [touched, setTouched] = (0, import_react11.useState)(createKeySet(initialValues, false));
533
+ const [changed, setChanged] = (0, import_react11.useState)(createKeySet(initialValues, false));
534
+ const [errors, setErrors] = (0, import_react11.useState)({});
535
+ const [saving, setSaving] = (0, import_react11.useState)(false);
536
+ const validate = (0, import_react11.useCallback)((values2) => {
537
+ let errors2 = (0, import_schema2.validateSchema)(schema, values2) ?? [];
334
538
  if (errors2.length === 0 && onValidate) {
335
539
  const validatedValues = values2;
336
540
  errors2 = onValidate(validatedValues) ?? [];
@@ -342,11 +546,11 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
342
546
  schema,
343
547
  onValidate
344
548
  ]);
345
- const [schemaDirty, setSchemaDirty] = (0, import_react8.useState)(false);
346
- (0, import_react8.useEffect)(() => setSchemaDirty(true), [
549
+ const [schemaDirty, setSchemaDirty] = (0, import_react11.useState)(false);
550
+ (0, import_react11.useEffect)(() => setSchemaDirty(true), [
347
551
  schema
348
552
  ]);
349
- (0, import_react8.useEffect)(() => {
553
+ (0, import_react11.useEffect)(() => {
350
554
  if (schemaDirty) {
351
555
  validate(values);
352
556
  setSchemaDirty(false);
@@ -355,13 +559,13 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
355
559
  values,
356
560
  schemaDirty
357
561
  ]);
358
- const canSave = (0, import_react8.useMemo)(() => !saving && Object.keys(values).every((property) => touched[property] === false || !errors[property]), [
359
- values,
562
+ const canSave = (0, import_react11.useMemo)(() => !saving && // Check if any error paths that are touched have errors
563
+ !Object.entries(touched).some(([path, isTouched]) => isTouched && Object.keys(errors).some((errorPath) => errorPath === path || errorPath.startsWith(`${path}.`) || errorPath.startsWith(`${path}[`))), [
360
564
  touched,
361
565
  errors,
362
566
  saving
363
567
  ]);
364
- const handleSave = (0, import_react8.useCallback)(async () => {
568
+ const handleSave = (0, import_react11.useCallback)(async () => {
365
569
  if (validate(values)) {
366
570
  setSaving(true);
367
571
  try {
@@ -378,38 +582,42 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
378
582
  onSave,
379
583
  changed
380
584
  ]);
381
- const getStatus = (0, import_react8.useCallback)((property) => ({
382
- status: errors[property] ? "error" : void 0,
383
- error: errors[property] ? errors[property] : void 0
384
- }), [
385
- touched,
585
+ const getStatus = (0, import_react11.useCallback)((path) => {
586
+ const jsonPath = Array.isArray(path) ? (0, import_effect2.createJsonPath)(path) : path;
587
+ const matchingError = Object.entries(errors).find(([errorPath]) => errorPath === jsonPath || errorPath.startsWith(`${jsonPath}.`) || errorPath.startsWith(`${jsonPath}[`));
588
+ return {
589
+ status: matchingError ? "error" : void 0,
590
+ error: matchingError ? matchingError[1] : void 0
591
+ };
592
+ }, [
386
593
  errors
387
594
  ]);
388
- const getFormValue = (property) => {
389
- return (0, import_echo_schema4.getValue)(values, property);
595
+ const getFormValue = (path) => {
596
+ return (0, import_echo_schema3.getValue)(values, (0, import_effect2.createJsonPath)(path));
390
597
  };
391
- const onValueChange = (property, type, value) => {
598
+ const onValueChange = (path, type, value) => {
599
+ const jsonPath = (0, import_effect2.createJsonPath)(path);
392
600
  let parsedValue = value;
393
601
  try {
394
602
  if (type === "number") {
395
603
  parsedValue = parseFloat(value) || 0;
396
604
  }
397
605
  } catch (err) {
398
- import_log3.log.catch(err, void 0, {
606
+ import_log2.log.catch(err, void 0, {
399
607
  F: __dxlog_file,
400
- L: 178,
608
+ L: 192,
401
609
  S: void 0,
402
610
  C: (f, a) => f(...a)
403
611
  });
404
612
  parsedValue = void 0;
405
613
  }
406
614
  const newValues = {
407
- ...(0, import_echo_schema4.setValue)(values, property, parsedValue)
615
+ ...(0, import_echo_schema3.setValue)(values, jsonPath, parsedValue)
408
616
  };
409
617
  setValues(newValues);
410
618
  setChanged((prev) => ({
411
619
  ...prev,
412
- [property]: true
620
+ [jsonPath]: true
413
621
  }));
414
622
  onValuesChanged?.(newValues);
415
623
  const isValid = validate(newValues);
@@ -419,15 +627,12 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
419
627
  });
420
628
  }
421
629
  };
422
- const onBlur = (0, import_react8.useCallback)((event) => {
423
- const { name } = event.target;
630
+ const onTouched = (0, import_react11.useCallback)((path) => {
631
+ const jsonPath = (0, import_effect2.createJsonPath)(path);
424
632
  setTouched((touched2) => ({
425
633
  ...touched2,
426
- [name]: true
634
+ [jsonPath]: true
427
635
  }));
428
- if (event.relatedTarget?.getAttribute("type") === "submit") {
429
- setTouched(createKeySet(values, true));
430
- }
431
636
  validate(values);
432
637
  }, [
433
638
  validate,
@@ -445,13 +650,13 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
445
650
  getStatus,
446
651
  getValue: getFormValue,
447
652
  onValueChange,
448
- onBlur
653
+ onTouched
449
654
  };
450
655
  };
451
656
  var createKeySet = (obj, value) => {
452
657
  (0, import_invariant.invariant)(obj, void 0, {
453
658
  F: __dxlog_file,
454
- L: 229,
659
+ L: 234,
455
660
  S: void 0,
456
661
  A: [
457
662
  "obj",
@@ -465,302 +670,336 @@ var createKeySet = (obj, value) => {
465
670
  };
466
671
  var flatMap = (errors) => {
467
672
  return errors.reduce((result, { path, message }) => {
468
- if (!(path in result)) {
469
- result[path] = message;
673
+ const jsonPath = (0, import_effect2.fromEffectValidationPath)(path);
674
+ if (!(jsonPath in result)) {
675
+ result[jsonPath] = message;
470
676
  }
471
677
  return result;
472
678
  }, {});
473
679
  };
474
- var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/Form/Form.tsx";
680
+ var FormContext = /* @__PURE__ */ (0, import_react10.createContext)(void 0);
681
+ var useFormContext = () => {
682
+ return (0, import_react10.useContext)(FormContext) ?? (0, import_debug.raise)(new Error("Missing FormContext"));
683
+ };
684
+ var useFormValues = (path = []) => {
685
+ const { values: formValues } = useFormContext();
686
+ const jsonPath = (0, import_effect.createJsonPath)(path);
687
+ return (0, import_echo_schema2.getValue)(formValues, jsonPath);
688
+ };
689
+ var useInputProps = (path = []) => {
690
+ const { getStatus, getValue: getFormValue, onValueChange, onTouched } = useFormContext();
691
+ return {
692
+ getStatus: () => getStatus(path),
693
+ getValue: () => getFormValue(path),
694
+ onValueChange: (type, value) => onValueChange(path, type, value),
695
+ onBlur: () => onTouched(path)
696
+ };
697
+ };
698
+ var FormProvider = ({ children, ...formOptions }) => {
699
+ const formHandler = useForm(formOptions);
700
+ return /* @__PURE__ */ import_react10.default.createElement(FormContext.Provider, {
701
+ value: formHandler
702
+ }, children);
703
+ };
704
+ var FormActions = ({ onCancel, readonly }) => {
705
+ const { t } = (0, import_react_ui8.useTranslation)(translationKey);
706
+ const { canSave, handleSave } = useFormContext();
707
+ return /* @__PURE__ */ import_react9.default.createElement("div", {
708
+ role: "none",
709
+ className: "flex justify-center"
710
+ }, /* @__PURE__ */ import_react9.default.createElement("div", {
711
+ role: "none",
712
+ className: (0, import_react_ui_theme6.mx)(onCancel && !readonly && "grid grid-cols-2 gap-2")
713
+ }, onCancel && !readonly && /* @__PURE__ */ import_react9.default.createElement(import_react_ui8.IconButton, {
714
+ "data-testid": "cancel-button",
715
+ icon: "ph--x--regular",
716
+ label: t("button cancel"),
717
+ onClick: onCancel
718
+ }), handleSave && /* @__PURE__ */ import_react9.default.createElement(import_react_ui8.IconButton, {
719
+ type: "submit",
720
+ "data-testid": "save-button",
721
+ disabled: !canSave,
722
+ icon: "ph--check--regular",
723
+ label: t("button save"),
724
+ onClick: handleSave
725
+ })));
726
+ };
727
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/Form/ArrayField.tsx";
475
728
  var padding = "px-2";
476
- var Form = ({ classNames, schema, values: initialValues, path = [], readonly, filter, sort, autoSave, testId, onValuesChanged, onValidate, onSave, onCancel, Custom }) => {
477
- const onValid = (0, import_react7.useMemo)(() => autoSave ? onSave : void 0, [
478
- autoSave,
479
- onSave
480
- ]);
481
- const { canSave, values, errors, handleSave, ...inputProps } = useForm({
482
- schema,
483
- initialValues,
484
- onValuesChanged,
485
- onValidate,
486
- onValid,
487
- onSave
729
+ var ArrayField = ({ property, readonly, path, inputProps, Custom, lookupComponent }) => {
730
+ const { t } = (0, import_react_ui9.useTranslation)(translationKey);
731
+ const { ast, name, type, title } = property;
732
+ const values = useFormValues(path ?? []);
733
+ (0, import_invariant2.invariant)(Array.isArray(values), `Values at path ${path?.join(".")} must be an array.`, {
734
+ F: __dxlog_file2,
735
+ L: 37,
736
+ S: void 0,
737
+ A: [
738
+ "Array.isArray(values)",
739
+ "`Values at path ${path?.join('.')} must be an array.`"
740
+ ]
488
741
  });
489
- const properties = (0, import_react7.useMemo)(() => {
490
- const props = (0, import_schema2.getSchemaProperties)(schema.ast, values);
491
- const filtered = filter ? filter(props) : props;
492
- const findIndex = (props2, prop) => {
493
- const idx = props2.findIndex((p) => p === prop);
494
- return idx === -1 ? Infinity : idx;
495
- };
496
- return sort ? filtered.sort(({ name: a }, { name: b }) => findIndex(sort, a) - findIndex(sort, b)) : filtered;
742
+ const label = title ?? (0, import_effect5.pipe)(name, import_String2.capitalize);
743
+ const tupleType = (0, import_effect6.findNode)(ast, import_echo_schema5.AST.isTupleType);
744
+ const elementType = tupleType?.rest[0]?.type;
745
+ const getDefaultObjectValue = (typeNode) => {
746
+ const baseNode = (0, import_effect6.findNode)(typeNode, import_effect6.isDiscriminatedUnion);
747
+ const typeLiteral = baseNode ? (0, import_effect6.getDiscriminatedType)(baseNode, {}) : (0, import_effect6.findNode)(typeNode, import_echo_schema5.AST.isTypeLiteral);
748
+ if (!typeLiteral) {
749
+ return {};
750
+ }
751
+ return Object.fromEntries((0, import_schema4.getSchemaProperties)(typeLiteral, {}).map((prop) => [
752
+ prop.name,
753
+ prop.defaultValue
754
+ ]));
755
+ };
756
+ const newValue = (0, import_react13.useMemo)(() => {
757
+ if (type === "object" && elementType) {
758
+ return getDefaultObjectValue(elementType);
759
+ } else {
760
+ return import_effect6.SimpleType.getDefaultValue(type);
761
+ }
497
762
  }, [
498
- schema,
499
- filter,
763
+ type,
764
+ elementType
765
+ ]);
766
+ const handleAdd = (0, import_react13.useCallback)(() => {
767
+ inputProps.onValueChange(type, [
768
+ ...values,
769
+ newValue
770
+ ]);
771
+ }, [
772
+ type,
773
+ elementType,
774
+ inputProps,
775
+ newValue,
500
776
  values
501
777
  ]);
502
- (0, import_react7.useEffect)(() => {
503
- if (errors && Object.keys(errors).length) {
504
- import_log2.log.warn("validation", {
505
- errors
506
- }, {
507
- F: __dxlog_file2,
508
- L: 99,
509
- S: void 0,
510
- C: (f, a) => f(...a)
511
- });
512
- }
778
+ const handleRemove = (0, import_react13.useCallback)((index) => {
779
+ const newValues = values.filter((_, i) => i !== index);
780
+ inputProps.onValueChange(type, newValues);
513
781
  }, [
514
- errors
782
+ type,
783
+ inputProps,
784
+ values
515
785
  ]);
516
- return /* @__PURE__ */ import_react7.default.createElement("div", {
517
- role: "form",
518
- className: (0, import_react_ui_theme3.mx)("flex flex-col w-full gap-2 py-2", classNames),
519
- "data-testid": testId
520
- }, properties.map((property) => {
521
- const { ast, name, type, format, title, description, examples, options, array } = property;
522
- const key = [
523
- ...path,
524
- name
525
- ];
526
- const label = title ?? (0, import_effect.pipe)(name, import_String.capitalize);
527
- const placeholder = examples?.length ? `Example: "${examples[0]}"` : description;
528
- let InputComponent = Custom?.[key.join(".")];
529
- if (!InputComponent) {
530
- if (options) {
531
- return /* @__PURE__ */ import_react7.default.createElement("div", {
532
- key: name,
533
- role: "none",
534
- className: padding
535
- }, /* @__PURE__ */ import_react7.default.createElement(SelectInput, {
536
- type,
537
- format,
538
- property: name,
539
- disabled: readonly,
540
- label,
541
- options: options.map((option) => ({
542
- value: option,
543
- label: String(option)
544
- })),
545
- placeholder,
546
- ...inputProps
547
- }));
548
- }
549
- InputComponent = getInputComponent(type, format);
550
- if (array) {
551
- return /* @__PURE__ */ import_react7.default.createElement(ArrayField, {
552
- key: name,
553
- name,
554
- type,
555
- array: true,
556
- label,
557
- ast,
558
- values,
559
- format,
560
- readonly,
561
- placeholder,
562
- inputProps,
563
- Custom
564
- });
565
- }
566
- }
567
- if (!InputComponent) {
568
- if (type === "object") {
569
- const baseNode = (0, import_effect2.findNode)(ast, import_effect2.isDiscriminatedUnion);
570
- const typeLiteral = baseNode ? (0, import_effect2.getDiscriminatedType)(baseNode, values[name]) : (0, import_effect2.findNode)(ast, import_echo_schema2.AST.isTypeLiteral);
571
- if (typeLiteral) {
572
- const schema2 = import_echo_schema2.S.make(typeLiteral);
573
- return /* @__PURE__ */ import_react7.default.createElement("div", {
574
- key: name,
575
- role: "none"
576
- }, /* @__PURE__ */ import_react7.default.createElement("div", {
577
- className: padding
578
- }, label), /* @__PURE__ */ import_react7.default.createElement(Form, {
579
- schema: schema2,
580
- path: key,
581
- values: values[name] ?? {},
582
- onValuesChanged: (childValues) => {
583
- inputProps.onValueChange(name, "object", childValues);
584
- },
585
- Custom
586
- }));
587
- }
588
- }
589
- (0, import_log2.log)("no renderer for property", {
590
- name,
591
- type
592
- }, {
593
- F: __dxlog_file2,
594
- L: 184,
595
- S: void 0,
596
- C: (f, a) => f(...a)
597
- });
598
- return null;
599
- }
600
- return /* @__PURE__ */ import_react7.default.createElement("div", {
601
- key: name,
602
- role: "none",
603
- className: padding
604
- }, /* @__PURE__ */ import_react7.default.createElement(InputComponent, {
605
- type,
606
- format,
607
- property: name,
608
- disabled: readonly,
609
- label,
610
- placeholder,
611
- ...inputProps
612
- }));
613
- }).filter(import_util3.isNotFalsy), (onCancel || onSave) && !autoSave && /* @__PURE__ */ import_react7.default.createElement(FormActions, {
614
- onCancel,
615
- onSubmit: handleSave,
616
- canSubmit: canSave,
617
- readonly
618
- }));
619
- };
620
- var ArrayField = ({ name, type, label, ast, values, format, readonly, placeholder, inputProps, Custom }) => {
621
- const { t } = (0, import_react_ui7.useTranslation)(translationKey);
622
- const arrayValues = values[name] ?? [];
623
- const key = [
624
- name
625
- ];
626
- const tupleType = (0, import_effect2.findNode)(ast, import_echo_schema2.AST.isTupleType);
627
- const elementType = tupleType?.rest[0]?.type;
628
- if (type === "object" && elementType) {
629
- const baseNode = (0, import_effect2.findNode)(elementType, import_effect2.isDiscriminatedUnion);
630
- const typeLiteral = baseNode ? (0, import_effect2.getDiscriminatedType)(baseNode, values[name]) : (0, import_effect2.findNode)(elementType, import_echo_schema2.AST.isTypeLiteral);
631
- if (typeLiteral) {
632
- const schema = import_echo_schema2.S.make(typeLiteral);
633
- return /* @__PURE__ */ import_react7.default.createElement("div", {
634
- key: name,
635
- role: "none",
636
- className: (0, import_react_ui_theme3.mx)(padding)
637
- }, /* @__PURE__ */ import_react7.default.createElement(InputHeader, null, label), /* @__PURE__ */ import_react7.default.createElement("div", {
638
- role: "none",
639
- className: "flex flex-col gap-1"
640
- }, arrayValues.map((value, index) => {
641
- return /* @__PURE__ */ import_react7.default.createElement("div", {
642
- key: index,
643
- role: "none",
644
- className: "flex items-center gap-1"
645
- }, /* @__PURE__ */ import_react7.default.createElement("div", {
646
- role: "none",
647
- className: "flex-1"
648
- }, /* @__PURE__ */ import_react7.default.createElement(Form, {
649
- schema,
650
- path: [
651
- ...key,
652
- `[${index}]`
653
- ],
654
- values: value,
655
- onValuesChanged: (childValues) => {
656
- const newValues = [
657
- ...arrayValues
658
- ];
659
- newValues[index] = childValues;
660
- inputProps.onValueChange(name, "object", newValues);
661
- },
662
- Custom
663
- })), /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.IconButton, {
664
- icon: "ph--trash--regular",
665
- iconOnly: true,
666
- label: t("button remove"),
667
- onClick: () => {
668
- const newValues = arrayValues.filter((_, i) => i !== index);
669
- inputProps.onValueChange(name, type, newValues);
670
- }
671
- }));
672
- })), /* @__PURE__ */ import_react7.default.createElement("div", {
673
- role: "none",
674
- className: "flex justify-between items-center plb-1"
675
- }, /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.IconButton, {
676
- icon: "ph--plus--regular",
677
- iconOnly: true,
678
- label: t("button add"),
679
- onClick: () => {
680
- const newValues = [
681
- ...arrayValues,
682
- {}
683
- ];
684
- inputProps.onValueChange(name, type, newValues);
685
- }
686
- })));
687
- }
688
- return /* @__PURE__ */ import_react7.default.createElement("div", {
689
- key: name,
690
- role: "none"
691
- }, "Nested form not supported in arrays, yet.");
692
- }
693
- const InputComponent = getInputComponent(type, format);
694
- if (!InputComponent) {
786
+ if (!elementType) {
695
787
  return null;
696
788
  }
697
- return /* @__PURE__ */ import_react7.default.createElement("div", {
789
+ return /* @__PURE__ */ import_react13.default.createElement("div", {
698
790
  role: "none",
699
- key: "meta-input",
700
- className: (0, import_react_ui_theme3.mx)(padding)
701
- }, /* @__PURE__ */ import_react7.default.createElement(InputHeader, null, label), /* @__PURE__ */ import_react7.default.createElement("div", {
791
+ className: (0, import_react_ui_theme8.mx)(padding)
792
+ }, /* @__PURE__ */ import_react13.default.createElement(InputHeader, null, label), /* @__PURE__ */ import_react13.default.createElement("div", {
702
793
  role: "none",
703
794
  className: "flex flex-col gap-1"
704
- }, arrayValues.map((_, index) => /* @__PURE__ */ import_react7.default.createElement("div", {
795
+ }, values.map((_value, index) => /* @__PURE__ */ import_react13.default.createElement("div", {
705
796
  key: index,
706
797
  role: "none",
707
- className: "flex items-start gap-1"
708
- }, /* @__PURE__ */ import_react7.default.createElement("div", {
798
+ className: "flex items-center gap-1"
799
+ }, /* @__PURE__ */ import_react13.default.createElement("div", {
709
800
  role: "none",
710
801
  className: "flex-1"
711
- }, /* @__PURE__ */ import_react7.default.createElement(InputComponent, {
712
- type,
713
- format,
714
- label,
715
- inputOnly: true,
716
- property: `${name}[${index}]`,
717
- disabled: readonly,
718
- placeholder,
719
- ...inputProps
720
- })), /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.IconButton, {
802
+ }, /* @__PURE__ */ import_react13.default.createElement(FormField, {
803
+ property: {
804
+ ...property,
805
+ array: false,
806
+ ast: elementType
807
+ },
808
+ path: [
809
+ ...path ?? [],
810
+ index
811
+ ],
812
+ readonly,
813
+ inline: true,
814
+ Custom,
815
+ lookupComponent
816
+ })), /* @__PURE__ */ import_react13.default.createElement(import_react_ui9.IconButton, {
721
817
  icon: "ph--trash--regular",
722
818
  iconOnly: true,
723
819
  label: t("button remove"),
724
- onClick: () => {
725
- const newValues = arrayValues.filter((_2, i) => i !== index);
726
- inputProps.onValueChange(name, type, newValues);
727
- }
728
- })))), /* @__PURE__ */ import_react7.default.createElement("div", {
820
+ onClick: () => handleRemove(index)
821
+ })))), /* @__PURE__ */ import_react13.default.createElement("div", {
729
822
  role: "none",
730
823
  className: "flex justify-between items-center plb-1"
731
- }, /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.IconButton, {
824
+ }, /* @__PURE__ */ import_react13.default.createElement(import_react_ui9.IconButton, {
732
825
  icon: "ph--plus--regular",
733
826
  iconOnly: true,
734
827
  label: t("button add"),
735
- onClick: () => {
736
- const newValues = [
737
- ...arrayValues,
738
- import_effect2.SimpleType.getDefaultValue(type)
739
- ];
740
- inputProps.onValueChange(name, type, newValues);
741
- }
828
+ onClick: handleAdd
742
829
  })));
743
830
  };
744
- var FormActions = ({ onCancel, onSubmit, canSubmit, readonly }) => {
745
- const { t } = (0, import_react_ui7.useTranslation)(translationKey);
746
- return /* @__PURE__ */ import_react7.default.createElement("div", {
747
- role: "none",
748
- className: "flex justify-center"
749
- }, /* @__PURE__ */ import_react7.default.createElement("div", {
831
+ var getInputComponent = (type, format) => {
832
+ switch (format) {
833
+ case import_echo_schema6.FormatEnum.LatLng:
834
+ return GeoPointInput;
835
+ }
836
+ switch (type) {
837
+ case "string":
838
+ return TextInput;
839
+ case "number":
840
+ return NumberInput;
841
+ case "boolean":
842
+ return BooleanInput;
843
+ }
844
+ };
845
+ var FormField = ({ property, path, readonly, inline, lookupComponent, Custom }) => {
846
+ const inputProps = useInputProps(path);
847
+ const { ast, name, type, format, title, description, options, examples, array } = property;
848
+ const label = (0, import_react12.useMemo)(() => title ?? (0, import_effect3.pipe)(name, import_String.capitalize), [
849
+ title,
850
+ name
851
+ ]);
852
+ const placeholder = (0, import_react12.useMemo)(() => examples?.length ? `Example: "${examples[0]}"` : description, [
853
+ examples,
854
+ description
855
+ ]);
856
+ const FoundComponent = lookupComponent?.({
857
+ prop: name,
858
+ schema: import_echo_schema4.S.make(ast),
859
+ inputProps: {
860
+ type,
861
+ format,
862
+ label,
863
+ disabled: readonly,
864
+ placeholder,
865
+ ...inputProps
866
+ }
867
+ });
868
+ if (FoundComponent) {
869
+ return /* @__PURE__ */ import_react12.default.createElement("div", {
870
+ role: "none"
871
+ }, FoundComponent);
872
+ }
873
+ const jsonPath = (0, import_effect4.createJsonPath)(path ?? []);
874
+ const CustomComponent = Custom?.[jsonPath];
875
+ if (CustomComponent) {
876
+ return (
877
+ // TODO(ZaymonFC): We should try to remove this div wrapper.
878
+ /* @__PURE__ */ import_react12.default.createElement("div", {
879
+ role: "none"
880
+ }, /* @__PURE__ */ import_react12.default.createElement(CustomComponent, {
881
+ type,
882
+ format,
883
+ label,
884
+ inputOnly: inline,
885
+ placeholder,
886
+ disabled: readonly,
887
+ ...inputProps
888
+ }))
889
+ );
890
+ }
891
+ if (array) {
892
+ return /* @__PURE__ */ import_react12.default.createElement(ArrayField, {
893
+ property,
894
+ path,
895
+ inputProps,
896
+ readonly,
897
+ Custom
898
+ });
899
+ }
900
+ const InputComponent = getInputComponent(type, format);
901
+ if (InputComponent) {
902
+ return /* @__PURE__ */ import_react12.default.createElement("div", {
903
+ role: "none"
904
+ }, /* @__PURE__ */ import_react12.default.createElement(InputComponent, {
905
+ type,
906
+ format,
907
+ label,
908
+ inputOnly: inline,
909
+ placeholder,
910
+ disabled: readonly,
911
+ ...inputProps
912
+ }));
913
+ }
914
+ if (options) {
915
+ return /* @__PURE__ */ import_react12.default.createElement("div", {
916
+ role: "none"
917
+ }, /* @__PURE__ */ import_react12.default.createElement(SelectInput, {
918
+ type,
919
+ format,
920
+ disabled: readonly,
921
+ inputOnly: inline,
922
+ label,
923
+ options: options.map((option) => ({
924
+ value: option,
925
+ label: String(option)
926
+ })),
927
+ placeholder,
928
+ ...inputProps
929
+ }));
930
+ }
931
+ if (type === "object") {
932
+ const baseNode = (0, import_effect4.findNode)(ast, import_effect4.isDiscriminatedUnion);
933
+ const typeLiteral = baseNode ? (0, import_effect4.getDiscriminatedType)(baseNode, inputProps.getValue()) : (0, import_effect4.findNode)(ast, import_echo_schema4.AST.isTypeLiteral);
934
+ if (typeLiteral) {
935
+ return /* @__PURE__ */ import_react12.default.createElement("div", {
936
+ role: "none"
937
+ }, !inline && /* @__PURE__ */ import_react12.default.createElement("div", null, label), /* @__PURE__ */ import_react12.default.createElement(FormFields, {
938
+ schema: import_echo_schema4.S.make(typeLiteral),
939
+ path,
940
+ readonly,
941
+ Custom
942
+ }));
943
+ }
944
+ }
945
+ return null;
946
+ };
947
+ var FormFields = ({ schema, path, filter, sort, readonly, lookupComponent, Custom }) => {
948
+ const values = useFormValues(path);
949
+ const properties = (0, import_react12.useMemo)(() => {
950
+ const props = (0, import_schema3.getSchemaProperties)(schema.ast, values);
951
+ const filtered = filter ? filter(props) : props;
952
+ return sort ? filtered.sort((a, b) => sort.indexOf(a.name) - sort.indexOf(b.name)) : filtered;
953
+ }, [
954
+ schema,
955
+ values,
956
+ filter,
957
+ sort
958
+ ]);
959
+ return /* @__PURE__ */ import_react12.default.createElement("div", {
960
+ role: "form",
961
+ className: (0, import_react_ui_theme7.mx)("flex flex-col w-full gap-2 py-2")
962
+ }, properties.map((property) => {
963
+ return /* @__PURE__ */ import_react12.default.createElement(FormField, {
964
+ key: property.name,
965
+ property,
966
+ path: [
967
+ ...path ?? [],
968
+ property.name
969
+ ],
970
+ readonly,
971
+ lookupComponent,
972
+ Custom
973
+ });
974
+ }).filter(import_util3.isNotFalsy));
975
+ };
976
+ var Form = ({ classNames, schema, values: initialValues, path = [], readonly, filter, sort, autoSave, testId, onValuesChanged, onValidate, onSave, onCancel, lookupComponent, Custom }) => {
977
+ const onValid = (0, import_react8.useMemo)(() => autoSave ? onSave : void 0, [
978
+ autoSave,
979
+ onSave
980
+ ]);
981
+ return /* @__PURE__ */ import_react8.default.createElement(FormProvider, {
982
+ schema,
983
+ initialValues,
984
+ onValuesChanged,
985
+ onValidate,
986
+ onValid,
987
+ onSave
988
+ }, /* @__PURE__ */ import_react8.default.createElement("div", {
750
989
  role: "none",
751
- className: (0, import_react_ui_theme3.mx)(onCancel && !readonly && "grid grid-cols-2 gap-2")
752
- }, onCancel && !readonly && /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.IconButton, {
753
- "data-testid": "cancel-button",
754
- icon: "ph--x--regular",
755
- label: t("button cancel"),
756
- onClick: onCancel
757
- }), onSubmit && /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.IconButton, {
758
- type: "submit",
759
- "data-testid": "save-button",
760
- disabled: !canSubmit,
761
- icon: "ph--check--regular",
762
- label: t("button save"),
763
- onClick: onSubmit
990
+ className: (0, import_react_ui_theme5.mx)("p-2", classNames),
991
+ "data-testid": testId
992
+ }, /* @__PURE__ */ import_react8.default.createElement(FormFields, {
993
+ schema,
994
+ path,
995
+ readonly,
996
+ filter,
997
+ sort,
998
+ lookupComponent,
999
+ Custom
1000
+ }), (onCancel || onSave) && !autoSave && /* @__PURE__ */ import_react8.default.createElement(FormActions, {
1001
+ onCancel,
1002
+ readonly
764
1003
  })));
765
1004
  };
766
1005
  var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx";
@@ -790,9 +1029,9 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
790
1029
  }, [
791
1030
  registry
792
1031
  ]);
793
- const [schema, setSchema] = (0, import_react2.useState)();
1032
+ const [referenceSchema, setReferenceSchema] = (0, import_react2.useState)();
794
1033
  (0, import_react2.useEffect)(() => {
795
- setSchema(schemas.find((schema2) => schema2.typename === props?.referenceSchema));
1034
+ setReferenceSchema(schemas.find((schema) => schema.typename === props?.referenceSchema));
796
1035
  }, [
797
1036
  schemas,
798
1037
  props?.referenceSchema
@@ -810,9 +1049,15 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
810
1049
  fieldSchema: fieldSchema2
811
1050
  };
812
1051
  });
813
- if (_props.referenceSchema !== props.referenceSchema) {
814
- setSchema(schemas.find((schema2) => schema2.typename === _props.referenceSchema));
815
- }
1052
+ setReferenceSchema((prev) => {
1053
+ if (_props.referenceSchema !== prev?.typename) {
1054
+ const newSchema = schemas.find((schema) => schema.typename === _props.referenceSchema);
1055
+ if (newSchema) {
1056
+ return newSchema;
1057
+ }
1058
+ }
1059
+ return prev;
1060
+ });
816
1061
  setProps((props2) => {
817
1062
  const type = import_echo_schema.formatToType[_props.format];
818
1063
  if (props2.type !== type) {
@@ -822,7 +1067,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
822
1067
  type
823
1068
  };
824
1069
  }
825
- return props2;
1070
+ return _props;
826
1071
  });
827
1072
  }, [
828
1073
  schemas,
@@ -859,12 +1104,39 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
859
1104
  }, [
860
1105
  onSave
861
1106
  ]);
1107
+ const Custom = (0, import_react2.useMemo)(() => ({
1108
+ ["format"]: (props2) => /* @__PURE__ */ import_react2.default.createElement(SelectInput, {
1109
+ ...props2,
1110
+ options: import_echo_schema.FormatEnums.filter((value) => value !== import_echo_schema.FormatEnum.None).map((value) => ({
1111
+ value,
1112
+ label: t(`format ${value}`)
1113
+ }))
1114
+ }),
1115
+ ["referenceSchema"]: (props2) => /* @__PURE__ */ import_react2.default.createElement(SelectInput, {
1116
+ ...props2,
1117
+ options: schemas.map((schema) => ({
1118
+ value: schema.typename
1119
+ }))
1120
+ }),
1121
+ ["referencePath"]: (props2) => /* @__PURE__ */ import_react2.default.createElement(SelectInput, {
1122
+ ...props2,
1123
+ options: referenceSchema ? (0, import_schema.getSchemaProperties)(referenceSchema.ast).sort(import_schema.sortProperties).map((p) => ({
1124
+ value: p.name
1125
+ })) : []
1126
+ }),
1127
+ ["options"]: (props2) => /* @__PURE__ */ import_react2.default.createElement(SelectOptionInput, props2)
1128
+ }), [
1129
+ t,
1130
+ schemas,
1131
+ referenceSchema
1132
+ ]);
1133
+ const propIsNotType = (0, import_react2.useCallback)((props2) => props2.filter((p) => p.name !== "type"), []);
862
1134
  if (!fieldSchema) {
863
1135
  import_log.log.warn("invalid format", {
864
1136
  props
865
1137
  }, {
866
1138
  F: __dxlog_file3,
867
- L: 126,
1139
+ L: 174,
868
1140
  S: void 0,
869
1141
  C: (f, a) => f(...a)
870
1142
  });
@@ -875,7 +1147,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
875
1147
  autoFocus: true,
876
1148
  values: props,
877
1149
  schema: fieldSchema,
878
- filter: (props2) => props2.filter((p) => p.name !== "type"),
1150
+ filter: propIsNotType,
879
1151
  sort: [
880
1152
  "property",
881
1153
  "format"
@@ -884,46 +1156,26 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
884
1156
  onValidate: handleValidate,
885
1157
  onSave: handleSave,
886
1158
  onCancel: handleCancel,
887
- Custom: {
888
- ["format"]: (props2) => /* @__PURE__ */ import_react2.default.createElement(SelectInput, {
889
- ...props2,
890
- options: import_echo_schema.FormatEnums.filter((value) => value !== import_echo_schema.FormatEnum.None).map((value) => ({
891
- value,
892
- label: t(`format ${value}`)
893
- }))
894
- }),
895
- ["referenceSchema"]: (props2) => /* @__PURE__ */ import_react2.default.createElement(SelectInput, {
896
- ...props2,
897
- options: schemas.map((schema2) => ({
898
- value: schema2.typename
899
- }))
900
- }),
901
- ["referencePath"]: (props2) => /* @__PURE__ */ import_react2.default.createElement(SelectInput, {
902
- ...props2,
903
- options: schema ? (0, import_schema.getSchemaProperties)(schema.ast).sort(import_schema.sortProperties).map((p) => ({
904
- value: p.name
905
- })) : []
906
- })
907
- }
1159
+ Custom
908
1160
  });
909
1161
  };
910
1162
  var grid = "grid grid-cols-[32px_1fr_32px] min-bs-[2.5rem]";
911
- var ViewMetaSchema = import_echo_schema5.S.Struct({
912
- name: import_echo_schema5.S.String.annotations({
913
- [import_echo_schema5.AST.TitleAnnotationId]: "View"
1163
+ var ViewMetaSchema = import_echo_schema7.S.Struct({
1164
+ name: import_echo_schema7.S.String.annotations({
1165
+ [import_echo_schema7.AST.TitleAnnotationId]: "View"
914
1166
  }),
915
- typename: import_echo_schema5.Format.DXN.annotations({
916
- [import_echo_schema5.AST.TitleAnnotationId]: "Typename"
1167
+ typename: import_echo_schema7.Format.DXN.annotations({
1168
+ [import_echo_schema7.AST.TitleAnnotationId]: "Typename"
917
1169
  })
918
- }).pipe(import_echo_schema5.S.mutable);
919
- var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading = false, onDelete }) => {
920
- const { t } = (0, import_react_ui8.useTranslation)(translationKey);
921
- const projection = (0, import_react9.useMemo)(() => new import_schema4.ViewProjection(schema, view), [
1170
+ }).pipe(import_echo_schema7.S.mutable);
1171
+ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading = false, onTypenameChanged, onDelete }) => {
1172
+ const { t } = (0, import_react_ui10.useTranslation)(translationKey);
1173
+ const projection = (0, import_react14.useMemo)(() => new import_schema5.ViewProjection(schema, view), [
922
1174
  schema,
923
1175
  view
924
1176
  ]);
925
- const [field, setField] = (0, import_react9.useState)();
926
- const viewValues = (0, import_react9.useMemo)(() => {
1177
+ const [field, setField] = (0, import_react14.useState)();
1178
+ const viewValues = (0, import_react14.useMemo)(() => {
927
1179
  return {
928
1180
  name: view.name,
929
1181
  // TODO(burdon): Need to warn user of possible consequences of editing.
@@ -933,82 +1185,91 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
933
1185
  }, [
934
1186
  view
935
1187
  ]);
936
- const handleViewUpdate = (0, import_react9.useCallback)(({ name, typename }) => {
1188
+ const handleViewUpdate = (0, import_react14.useCallback)(({ name, typename }) => {
937
1189
  requestAnimationFrame(() => {
938
- view.name = name;
939
- view.query.type = typename;
940
- schema.updateTypename(typename);
1190
+ if (view.name !== name) {
1191
+ view.name = name;
1192
+ }
1193
+ if (view.query.type !== typename) {
1194
+ onTypenameChanged(typename);
1195
+ }
941
1196
  });
942
1197
  }, [
943
1198
  view,
944
- schema
1199
+ schema,
1200
+ onTypenameChanged
945
1201
  ]);
946
- const handleSelect = (0, import_react9.useCallback)((field2) => {
1202
+ const handleSelect = (0, import_react14.useCallback)((field2) => {
947
1203
  setField((f) => f === field2 ? void 0 : field2);
948
1204
  }, []);
949
- const handleAdd = (0, import_react9.useCallback)(() => {
1205
+ const handleAdd = (0, import_react14.useCallback)(() => {
950
1206
  const field2 = projection.createFieldProjection();
951
1207
  setField(field2);
952
1208
  }, [
953
1209
  view
954
1210
  ]);
955
- const handleMove = (0, import_react9.useCallback)((fromIndex, toIndex) => {
956
- (0, import_util4.arrayMove)(view.fields, fromIndex, toIndex);
1211
+ const handleMove = (0, import_react14.useCallback)((fromIndex, toIndex) => {
1212
+ const fields = [
1213
+ ...view.fields
1214
+ ];
1215
+ const [moved] = fields.splice(fromIndex, 1);
1216
+ fields.splice(toIndex, 0, moved);
1217
+ view.fields = fields;
957
1218
  }, [
958
1219
  view.fields
959
1220
  ]);
960
- const handleClose = (0, import_react9.useCallback)(() => setField(void 0), []);
961
- return /* @__PURE__ */ import_react9.default.createElement("div", {
1221
+ const handleClose = (0, import_react14.useCallback)(() => setField(void 0), []);
1222
+ return /* @__PURE__ */ import_react14.default.createElement("div", {
962
1223
  role: "none",
963
- className: (0, import_react_ui_theme4.mx)("flex flex-col w-full divide-y divide-separator", classNames)
964
- }, /* @__PURE__ */ import_react9.default.createElement(Form, {
1224
+ className: (0, import_react_ui_theme9.mx)("flex flex-col w-full divide-y divide-separator", classNames)
1225
+ }, /* @__PURE__ */ import_react14.default.createElement(Form, {
965
1226
  autoFocus: true,
966
1227
  autoSave: true,
967
1228
  schema: ViewMetaSchema,
968
1229
  values: viewValues,
969
1230
  onSave: handleViewUpdate
970
- }), /* @__PURE__ */ import_react9.default.createElement("div", null, /* @__PURE__ */ import_react9.default.createElement("div", {
1231
+ }), /* @__PURE__ */ import_react14.default.createElement("div", null, /* @__PURE__ */ import_react14.default.createElement("div", {
971
1232
  role: "none",
972
1233
  className: "p-2"
973
- }, /* @__PURE__ */ import_react9.default.createElement("label", {
974
- className: (0, import_react_ui_theme4.mx)(import_react_ui_theme4.inputTextLabel)
975
- }, t("fields label"))), /* @__PURE__ */ import_react9.default.createElement(import_react_ui_list.List.Root, {
1234
+ }, /* @__PURE__ */ import_react14.default.createElement("label", {
1235
+ className: (0, import_react_ui_theme9.mx)(import_react_ui_theme9.inputTextLabel)
1236
+ }, t("fields label"))), /* @__PURE__ */ import_react14.default.createElement(import_react_ui_list2.List.Root, {
976
1237
  items: view.fields,
977
- isItem: import_echo_schema5.S.is(import_schema4.FieldSchema),
1238
+ isItem: import_echo_schema7.S.is(import_schema5.FieldSchema),
978
1239
  getId: (field2) => field2.id,
979
1240
  onMove: handleMove
980
- }, ({ items: fields }) => /* @__PURE__ */ import_react9.default.createElement(import_react9.default.Fragment, null, showHeading && /* @__PURE__ */ import_react9.default.createElement("div", {
1241
+ }, ({ items: fields }) => /* @__PURE__ */ import_react14.default.createElement(import_react14.default.Fragment, null, showHeading && /* @__PURE__ */ import_react14.default.createElement("div", {
981
1242
  role: "heading",
982
1243
  className: grid
983
- }, /* @__PURE__ */ import_react9.default.createElement("div", null), /* @__PURE__ */ import_react9.default.createElement("div", {
1244
+ }, /* @__PURE__ */ import_react14.default.createElement("div", null), /* @__PURE__ */ import_react14.default.createElement("div", {
984
1245
  className: "flex items-center text-sm"
985
- }, t("field path label"))), /* @__PURE__ */ import_react9.default.createElement("div", {
1246
+ }, t("field path label"))), /* @__PURE__ */ import_react14.default.createElement("div", {
986
1247
  role: "list",
987
1248
  className: "flex flex-col w-full"
988
- }, fields?.map((field2) => /* @__PURE__ */ import_react9.default.createElement(import_react_ui_list.List.Item, {
1249
+ }, fields?.map((field2) => /* @__PURE__ */ import_react14.default.createElement(import_react_ui_list2.List.Item, {
989
1250
  key: field2.id,
990
1251
  item: field2,
991
- classNames: (0, import_react_ui_theme4.mx)(grid, import_react_ui_theme4.ghostHover, "cursor-pointer")
992
- }, /* @__PURE__ */ import_react9.default.createElement(import_react_ui_list.List.ItemDragHandle, null), /* @__PURE__ */ import_react9.default.createElement(import_react_ui_list.List.ItemTitle, {
1252
+ classNames: (0, import_react_ui_theme9.mx)(grid, import_react_ui_theme9.ghostHover, "cursor-pointer")
1253
+ }, /* @__PURE__ */ import_react14.default.createElement(import_react_ui_list2.List.ItemDragHandle, null), /* @__PURE__ */ import_react14.default.createElement(import_react_ui_list2.List.ItemTitle, {
993
1254
  onClick: () => handleSelect(field2)
994
- }, field2.path), /* @__PURE__ */ import_react9.default.createElement(import_react_ui_list.List.ItemDeleteButton, {
1255
+ }, field2.path), /* @__PURE__ */ import_react14.default.createElement(import_react_ui_list2.List.ItemDeleteButton, {
995
1256
  disabled: view.fields.length <= 1,
996
1257
  onClick: () => onDelete(field2.id)
997
- }))))))), field && /* @__PURE__ */ import_react9.default.createElement(FieldEditor, {
1258
+ }))))))), field && /* @__PURE__ */ import_react14.default.createElement(FieldEditor, {
998
1259
  key: field.id,
999
1260
  view,
1000
1261
  projection,
1001
1262
  field,
1002
1263
  registry,
1003
1264
  onSave: handleClose
1004
- }), !readonly && !field && /* @__PURE__ */ import_react9.default.createElement("div", {
1265
+ }), !readonly && !field && /* @__PURE__ */ import_react14.default.createElement("div", {
1005
1266
  className: "flex p-2 justify-center"
1006
- }, /* @__PURE__ */ import_react9.default.createElement(import_react_ui8.IconButton, {
1267
+ }, /* @__PURE__ */ import_react14.default.createElement(import_react_ui10.IconButton, {
1007
1268
  icon: "ph--plus--regular",
1008
1269
  label: t("button add property"),
1009
1270
  onClick: handleAdd,
1010
1271
  // TODO(burdon): Show field limit in ux (not tooltip).
1011
- disabled: view.fields.length >= import_schema4.VIEW_FIELD_LIMIT
1272
+ disabled: view.fields.length >= import_schema5.VIEW_FIELD_LIMIT
1012
1273
  })));
1013
1274
  };
1014
1275
  var parseValue = ({ type, format, value }) => {
@@ -1017,7 +1278,7 @@ var parseValue = ({ type, format, value }) => {
1017
1278
  }
1018
1279
  const parseScalar = (type2) => {
1019
1280
  switch (type2) {
1020
- case import_echo_schema6.TypeEnum.Boolean: {
1281
+ case import_echo_schema8.TypeEnum.Boolean: {
1021
1282
  if (typeof value === "string") {
1022
1283
  const lowercaseValue = value.toLowerCase();
1023
1284
  if (lowercaseValue === "0" || lowercaseValue === "false") {
@@ -1028,13 +1289,13 @@ var parseValue = ({ type, format, value }) => {
1028
1289
  }
1029
1290
  return Boolean(value);
1030
1291
  }
1031
- case import_echo_schema6.TypeEnum.Number: {
1292
+ case import_echo_schema8.TypeEnum.Number: {
1032
1293
  const cleaned = typeof value === "string" ? value.replace(/[^0-9.-]+/g, "") : value;
1033
1294
  const num = Number(cleaned);
1034
1295
  return Number.isNaN(num) ? null : num;
1035
1296
  }
1036
- case import_echo_schema6.TypeEnum.String:
1037
- case import_echo_schema6.TypeEnum.Ref:
1297
+ case import_echo_schema8.TypeEnum.String:
1298
+ case import_echo_schema8.TypeEnum.Ref:
1038
1299
  return String(value);
1039
1300
  default: {
1040
1301
  return value;
@@ -1045,22 +1306,22 @@ var parseValue = ({ type, format, value }) => {
1045
1306
  return parseScalar(type);
1046
1307
  }
1047
1308
  switch (format) {
1048
- case import_echo_schema6.FormatEnum.Boolean:
1049
- return parseScalar(import_echo_schema6.TypeEnum.Boolean);
1050
- case import_echo_schema6.FormatEnum.Number:
1051
- case import_echo_schema6.FormatEnum.Percent:
1052
- case import_echo_schema6.FormatEnum.Currency:
1053
- return parseScalar(import_echo_schema6.TypeEnum.Number);
1054
- case import_echo_schema6.FormatEnum.String:
1055
- case import_echo_schema6.FormatEnum.Markdown: {
1056
- return parseScalar(import_echo_schema6.TypeEnum.String);
1309
+ case import_echo_schema8.FormatEnum.Boolean:
1310
+ return parseScalar(import_echo_schema8.TypeEnum.Boolean);
1311
+ case import_echo_schema8.FormatEnum.Number:
1312
+ case import_echo_schema8.FormatEnum.Percent:
1313
+ case import_echo_schema8.FormatEnum.Currency:
1314
+ return parseScalar(import_echo_schema8.TypeEnum.Number);
1315
+ case import_echo_schema8.FormatEnum.String:
1316
+ case import_echo_schema8.FormatEnum.Markdown: {
1317
+ return parseScalar(import_echo_schema8.TypeEnum.String);
1057
1318
  }
1058
- case import_echo_schema6.FormatEnum.Ref:
1059
- throw new Error(`unexpected format: ${import_echo_schema6.FormatEnum.Ref}`);
1060
- case import_echo_schema6.FormatEnum.DateTime:
1061
- case import_echo_schema6.FormatEnum.Date:
1062
- case import_echo_schema6.FormatEnum.Time:
1063
- case import_echo_schema6.FormatEnum.Timestamp: {
1319
+ case import_echo_schema8.FormatEnum.Ref:
1320
+ throw new Error(`unexpected format: ${import_echo_schema8.FormatEnum.Ref}`);
1321
+ case import_echo_schema8.FormatEnum.DateTime:
1322
+ case import_echo_schema8.FormatEnum.Date:
1323
+ case import_echo_schema8.FormatEnum.Time:
1324
+ case import_echo_schema8.FormatEnum.Timestamp: {
1064
1325
  const date = new Date(value);
1065
1326
  return isNaN(date.getTime()) ? null : date;
1066
1327
  }
@@ -1072,19 +1333,19 @@ var parseValue = ({ type, format, value }) => {
1072
1333
  var cellClassesForFieldType = ({ type, format }) => {
1073
1334
  if (!format) {
1074
1335
  switch (type) {
1075
- case import_echo_schema6.TypeEnum.Number:
1336
+ case import_echo_schema8.TypeEnum.Number:
1076
1337
  return [
1077
1338
  "text-right",
1078
1339
  "font-mono"
1079
1340
  ];
1080
- case import_echo_schema6.TypeEnum.Boolean:
1341
+ case import_echo_schema8.TypeEnum.Boolean:
1081
1342
  return [
1082
1343
  "text-right",
1083
1344
  "font-mono"
1084
1345
  ];
1085
- case import_echo_schema6.TypeEnum.String:
1346
+ case import_echo_schema8.TypeEnum.String:
1086
1347
  return void 0;
1087
- case import_echo_schema6.TypeEnum.Ref:
1348
+ case import_echo_schema8.TypeEnum.Ref:
1088
1349
  return void 0;
1089
1350
  default: {
1090
1351
  return void 0;
@@ -1092,20 +1353,20 @@ var cellClassesForFieldType = ({ type, format }) => {
1092
1353
  }
1093
1354
  }
1094
1355
  switch (format) {
1095
- case import_echo_schema6.FormatEnum.Markdown:
1356
+ case import_echo_schema8.FormatEnum.Markdown:
1096
1357
  return void 0;
1097
- case import_echo_schema6.FormatEnum.Timestamp:
1098
- case import_echo_schema6.FormatEnum.DateTime:
1099
- case import_echo_schema6.FormatEnum.Date:
1100
- case import_echo_schema6.FormatEnum.Time:
1358
+ case import_echo_schema8.FormatEnum.Timestamp:
1359
+ case import_echo_schema8.FormatEnum.DateTime:
1360
+ case import_echo_schema8.FormatEnum.Date:
1361
+ case import_echo_schema8.FormatEnum.Time:
1101
1362
  return [
1102
1363
  "font-mono"
1103
1364
  ];
1104
- case import_echo_schema6.FormatEnum.Currency:
1365
+ case import_echo_schema8.FormatEnum.Currency:
1105
1366
  return [
1106
1367
  "text-right"
1107
1368
  ];
1108
- case import_echo_schema6.FormatEnum.JSON:
1369
+ case import_echo_schema8.FormatEnum.JSON:
1109
1370
  return [
1110
1371
  "font-mono"
1111
1372
  ];
@@ -1123,12 +1384,12 @@ var pathNotUniqueError = (path) => ({
1123
1384
  var formatForDisplay = ({ type, format, value, locale = void 0 }) => {
1124
1385
  const formatScalar = (type2) => {
1125
1386
  switch (type2) {
1126
- case import_echo_schema7.TypeEnum.Boolean:
1387
+ case import_echo_schema9.TypeEnum.Boolean:
1127
1388
  return value.toLocaleString().toUpperCase();
1128
- case import_echo_schema7.TypeEnum.Number:
1389
+ case import_echo_schema9.TypeEnum.Number:
1129
1390
  return value.toLocaleString(locale);
1130
- case import_echo_schema7.TypeEnum.String:
1131
- case import_echo_schema7.TypeEnum.Ref:
1391
+ case import_echo_schema9.TypeEnum.String:
1392
+ case import_echo_schema9.TypeEnum.Ref:
1132
1393
  return String(value);
1133
1394
  default: {
1134
1395
  return String(value);
@@ -1139,20 +1400,20 @@ var formatForDisplay = ({ type, format, value, locale = void 0 }) => {
1139
1400
  return formatScalar(type);
1140
1401
  }
1141
1402
  switch (format) {
1142
- case import_echo_schema7.FormatEnum.Boolean: {
1143
- return formatScalar(import_echo_schema7.TypeEnum.Boolean);
1403
+ case import_echo_schema9.FormatEnum.Boolean: {
1404
+ return formatScalar(import_echo_schema9.TypeEnum.Boolean);
1144
1405
  }
1145
- case import_echo_schema7.FormatEnum.Number: {
1146
- return formatScalar(import_echo_schema7.TypeEnum.Number);
1406
+ case import_echo_schema9.FormatEnum.Number: {
1407
+ return formatScalar(import_echo_schema9.TypeEnum.Number);
1147
1408
  }
1148
- case import_echo_schema7.FormatEnum.String:
1149
- case import_echo_schema7.FormatEnum.Ref: {
1150
- return formatScalar(import_echo_schema7.TypeEnum.String);
1409
+ case import_echo_schema9.FormatEnum.String:
1410
+ case import_echo_schema9.FormatEnum.Ref: {
1411
+ return formatScalar(import_echo_schema9.TypeEnum.String);
1151
1412
  }
1152
- case import_echo_schema7.FormatEnum.Percent: {
1413
+ case import_echo_schema9.FormatEnum.Percent: {
1153
1414
  return `${value * 100}%`;
1154
1415
  }
1155
- case import_echo_schema7.FormatEnum.Currency: {
1416
+ case import_echo_schema9.FormatEnum.Currency: {
1156
1417
  return value.toLocaleString(locale, {
1157
1418
  style: "currency",
1158
1419
  currency: "USD",
@@ -1160,13 +1421,13 @@ var formatForDisplay = ({ type, format, value, locale = void 0 }) => {
1160
1421
  maximumFractionDigits: 2
1161
1422
  });
1162
1423
  }
1163
- case import_echo_schema7.FormatEnum.DateTime:
1164
- case import_echo_schema7.FormatEnum.Date:
1165
- case import_echo_schema7.FormatEnum.Time: {
1424
+ case import_echo_schema9.FormatEnum.DateTime:
1425
+ case import_echo_schema9.FormatEnum.Date:
1426
+ case import_echo_schema9.FormatEnum.Time: {
1166
1427
  const date = new Date(value);
1167
- if (format === import_echo_schema7.FormatEnum.DateTime) {
1428
+ if (format === import_echo_schema9.FormatEnum.DateTime) {
1168
1429
  return date.toLocaleString(locale);
1169
- } else if (format === import_echo_schema7.FormatEnum.Date) {
1430
+ } else if (format === import_echo_schema9.FormatEnum.Date) {
1170
1431
  return date.toLocaleDateString(locale);
1171
1432
  } else {
1172
1433
  return date.toLocaleTimeString(locale);
@@ -1183,10 +1444,10 @@ var formatForDisplay = ({ type, format, value, locale = void 0 }) => {
1183
1444
  var formatForEditing = ({ type, format, value, locale = void 0 }) => {
1184
1445
  const formatScalar = (type2) => {
1185
1446
  switch (type2) {
1186
- case import_echo_schema7.TypeEnum.Boolean:
1187
- case import_echo_schema7.TypeEnum.Number:
1188
- case import_echo_schema7.TypeEnum.String:
1189
- case import_echo_schema7.TypeEnum.Ref:
1447
+ case import_echo_schema9.TypeEnum.Boolean:
1448
+ case import_echo_schema9.TypeEnum.Number:
1449
+ case import_echo_schema9.TypeEnum.String:
1450
+ case import_echo_schema9.TypeEnum.Ref:
1190
1451
  return String(value);
1191
1452
  default:
1192
1453
  return String(value);
@@ -1196,27 +1457,27 @@ var formatForEditing = ({ type, format, value, locale = void 0 }) => {
1196
1457
  return formatScalar(type);
1197
1458
  }
1198
1459
  switch (format) {
1199
- case import_echo_schema7.FormatEnum.Boolean:
1200
- case import_echo_schema7.FormatEnum.Number:
1201
- case import_echo_schema7.FormatEnum.String:
1202
- case import_echo_schema7.FormatEnum.Ref: {
1460
+ case import_echo_schema9.FormatEnum.Boolean:
1461
+ case import_echo_schema9.FormatEnum.Number:
1462
+ case import_echo_schema9.FormatEnum.String:
1463
+ case import_echo_schema9.FormatEnum.Ref: {
1203
1464
  return formatScalar(type);
1204
1465
  }
1205
- case import_echo_schema7.FormatEnum.Percent: {
1466
+ case import_echo_schema9.FormatEnum.Percent: {
1206
1467
  return String(value * 100);
1207
1468
  }
1208
- case import_echo_schema7.FormatEnum.Currency: {
1469
+ case import_echo_schema9.FormatEnum.Currency: {
1209
1470
  return String(value);
1210
1471
  }
1211
- case import_echo_schema7.FormatEnum.DateTime: {
1472
+ case import_echo_schema9.FormatEnum.DateTime: {
1212
1473
  const date = new Date(value);
1213
1474
  return date.toISOString();
1214
1475
  }
1215
- case import_echo_schema7.FormatEnum.Date: {
1476
+ case import_echo_schema9.FormatEnum.Date: {
1216
1477
  const date = new Date(value);
1217
1478
  return date.toISOString().split("T")[0];
1218
1479
  }
1219
- case import_echo_schema7.FormatEnum.Time: {
1480
+ case import_echo_schema9.FormatEnum.Time: {
1220
1481
  const date = new Date(value);
1221
1482
  return date.toISOString().split("T")[1].split(".")[0];
1222
1483
  }
@@ -1228,14 +1489,15 @@ var formatForEditing = ({ type, format, value, locale = void 0 }) => {
1228
1489
  // Annotate the CommonJS export names for ESM import in node:
1229
1490
  0 && (module.exports = {
1230
1491
  BooleanInput,
1492
+ DeprecatedFormContainer,
1231
1493
  DeprecatedFormInput,
1232
1494
  FieldEditor,
1233
1495
  Form,
1234
- FormActions,
1235
1496
  GeoPointInput,
1236
1497
  InputHeader,
1237
1498
  NumberInput,
1238
1499
  SelectInput,
1500
+ SelectOptionInput,
1239
1501
  TextInput,
1240
1502
  TupleInput,
1241
1503
  ViewEditor,