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