@dxos/react-ui-form 0.7.5-main.9d2a38b → 0.7.5-main.ff8607b
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.
- package/dist/lib/browser/index.mjs +703 -462
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +730 -504
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +703 -462
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/components/FieldEditor/FieldEditor.d.ts.map +1 -1
- package/dist/types/src/components/Form/ArrayField.d.ts +16 -0
- package/dist/types/src/components/Form/ArrayField.d.ts.map +1 -0
- package/dist/types/src/components/Form/Defaults.d.ts +5 -6
- package/dist/types/src/components/Form/Defaults.d.ts.map +1 -1
- package/dist/types/src/components/Form/Form.d.ts +11 -20
- package/dist/types/src/components/Form/Form.d.ts.map +1 -1
- package/dist/types/src/components/Form/Form.stories.d.ts +2 -1
- package/dist/types/src/components/Form/Form.stories.d.ts.map +1 -1
- package/dist/types/src/components/Form/FormActions.d.ts +7 -0
- package/dist/types/src/components/Form/FormActions.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormContent.d.ts +26 -0
- package/dist/types/src/components/Form/FormContent.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormContext.d.ts +20 -0
- package/dist/types/src/components/Form/FormContext.d.ts.map +1 -0
- package/dist/types/src/components/Form/Input.d.ts +5 -6
- package/dist/types/src/components/Form/Input.d.ts.map +1 -1
- package/dist/types/src/components/Form/custom/GeoPointInput.d.ts +1 -2
- package/dist/types/src/components/Form/custom/GeoPointInput.d.ts.map +1 -1
- package/dist/types/src/components/Form/custom/SelectOptionsInput.d.ts +4 -0
- package/dist/types/src/components/Form/custom/SelectOptionsInput.d.ts.map +1 -0
- package/dist/types/src/components/Form/custom/SelectOptionsInput.stories.d.ts +7 -0
- package/dist/types/src/components/Form/custom/SelectOptionsInput.stories.d.ts.map +1 -0
- package/dist/types/src/components/Form/custom/TupleInput.d.ts +1 -2
- package/dist/types/src/components/Form/custom/TupleInput.d.ts.map +1 -1
- package/dist/types/src/components/Form/custom/index.d.ts +1 -0
- package/dist/types/src/components/Form/custom/index.d.ts.map +1 -1
- package/dist/types/src/components/Form/factory.d.ts +2 -2
- package/dist/types/src/components/Form/factory.d.ts.map +1 -1
- package/dist/types/src/components/ViewEditor/ViewEditor.d.ts.map +1 -1
- package/dist/types/src/components/deprecated/FormInput.d.ts +5 -0
- package/dist/types/src/components/deprecated/FormInput.d.ts.map +1 -1
- package/dist/types/src/hooks/useForm.d.ts +9 -10
- package/dist/types/src/hooks/useForm.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +6 -0
- package/dist/types/src/translations.d.ts.map +1 -1
- package/package.json +25 -24
- package/src/components/FieldEditor/FieldEditor.stories.tsx +1 -1
- package/src/components/FieldEditor/FieldEditor.tsx +7 -6
- package/src/components/Form/ArrayField.tsx +111 -0
- package/src/components/Form/Defaults.tsx +18 -33
- package/src/components/Form/Form.stories.tsx +15 -5
- package/src/components/Form/Form.tsx +38 -358
- package/src/components/Form/FormActions.tsx +41 -0
- package/src/components/Form/FormContent.tsx +173 -0
- package/src/components/Form/FormContext.tsx +48 -0
- package/src/components/Form/Input.tsx +5 -6
- package/src/components/Form/custom/GeoPointInput.tsx +6 -15
- package/src/components/Form/custom/SelectOptionsInput.stories.tsx +58 -0
- package/src/components/Form/custom/SelectOptionsInput.tsx +192 -0
- package/src/components/Form/custom/TupleInput.tsx +5 -9
- package/src/components/Form/custom/index.ts +1 -0
- package/src/components/Form/factory.tsx +2 -5
- package/src/components/ViewEditor/ViewEditor.tsx +5 -2
- package/src/components/deprecated/FormInput.tsx +19 -3
- package/src/hooks/useForm.ts +54 -47
- package/src/translations.ts +8 -0
|
@@ -35,6 +35,7 @@ var translations_default = [
|
|
|
35
35
|
"format ref": "Reference",
|
|
36
36
|
"format regex": "RegExp",
|
|
37
37
|
"format string": "String",
|
|
38
|
+
"format single-select": "Select",
|
|
38
39
|
"format text": "Long text",
|
|
39
40
|
"format time": "Time",
|
|
40
41
|
"format timestamp": "Timestamp",
|
|
@@ -44,7 +45,13 @@ var translations_default = [
|
|
|
44
45
|
"format uuid": "UUID",
|
|
45
46
|
// Placeholders
|
|
46
47
|
"placeholder latitude": "Latitude",
|
|
47
|
-
"placeholder longitude": "Longitude"
|
|
48
|
+
"placeholder longitude": "Longitude",
|
|
49
|
+
// SelectOptionsInput
|
|
50
|
+
"select option label": "Label",
|
|
51
|
+
"select option label placeholder": "Option label",
|
|
52
|
+
"select option color": "Color",
|
|
53
|
+
"select option delete": "Delete",
|
|
54
|
+
"select option add": "Add option"
|
|
48
55
|
}
|
|
49
56
|
}
|
|
50
57
|
}
|
|
@@ -53,6 +60,16 @@ var translations_default = [
|
|
|
53
60
|
// packages/ui/react-ui-form/src/components/deprecated/FormInput.tsx
|
|
54
61
|
import React from "react";
|
|
55
62
|
import { Input } from "@dxos/react-ui";
|
|
63
|
+
import { mx, textBlockWidth } from "@dxos/react-ui-theme";
|
|
64
|
+
var DeprecatedFormContainer = ({ children, classNames }) => {
|
|
65
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
66
|
+
role: "none",
|
|
67
|
+
className: "w-full p-4 justify-center overflow-x-hidden overflow-y-auto"
|
|
68
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
69
|
+
role: "form",
|
|
70
|
+
className: mx("flex flex-col", textBlockWidth, classNames)
|
|
71
|
+
}, children));
|
|
72
|
+
};
|
|
56
73
|
var DeprecatedFormInput = ({ label, description, secondary, children }) => {
|
|
57
74
|
const primary = /* @__PURE__ */ React.createElement("div", {
|
|
58
75
|
role: "none",
|
|
@@ -61,14 +78,17 @@ var DeprecatedFormInput = ({ label, description, secondary, children }) => {
|
|
|
61
78
|
role: "none",
|
|
62
79
|
className: "flex flex-col w-full"
|
|
63
80
|
}, /* @__PURE__ */ React.createElement(Input.Label, {
|
|
64
|
-
classNames: "flex min-
|
|
81
|
+
classNames: "flex min-bs-[--rail-action] items-center",
|
|
82
|
+
style: {
|
|
83
|
+
fontSize: "unset"
|
|
84
|
+
}
|
|
65
85
|
}, label), description && /* @__PURE__ */ React.createElement(Input.DescriptionAndValidation, {
|
|
66
86
|
classNames: "mbs-0.5"
|
|
67
87
|
}, /* @__PURE__ */ React.createElement(Input.Description, null, description))), /* @__PURE__ */ React.createElement("div", {
|
|
68
88
|
role: "none"
|
|
69
89
|
}, /* @__PURE__ */ React.createElement("div", {
|
|
70
90
|
role: "none",
|
|
71
|
-
className: "flex min-
|
|
91
|
+
className: "flex min-bs-[--rail-action] items-center"
|
|
72
92
|
}, children))));
|
|
73
93
|
if (secondary) {
|
|
74
94
|
return /* @__PURE__ */ React.createElement("div", {
|
|
@@ -80,11 +100,11 @@ var DeprecatedFormInput = ({ label, description, secondary, children }) => {
|
|
|
80
100
|
};
|
|
81
101
|
|
|
82
102
|
// packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx
|
|
83
|
-
import
|
|
103
|
+
import React12, { useCallback as useCallback4, useEffect as useEffect3, useMemo as useMemo5, useState as useState3 } from "react";
|
|
84
104
|
import { FormatEnum as FormatEnum2, FormatEnums, formatToType } from "@dxos/echo-schema";
|
|
85
|
-
import { log as
|
|
86
|
-
import { useTranslation as
|
|
87
|
-
import { getFormatSchema, getSchemaProperties as
|
|
105
|
+
import { log as log2 } from "@dxos/log";
|
|
106
|
+
import { useTranslation as useTranslation5 } from "@dxos/react-ui";
|
|
107
|
+
import { getFormatSchema, getSchemaProperties as getSchemaProperties3, sortProperties } from "@dxos/schema";
|
|
88
108
|
|
|
89
109
|
// packages/ui/react-ui-form/src/components/Form/custom/GeoPointInput.tsx
|
|
90
110
|
import React3 from "react";
|
|
@@ -111,10 +131,10 @@ var InputHeader = ({ children, error }) => {
|
|
|
111
131
|
};
|
|
112
132
|
|
|
113
133
|
// packages/ui/react-ui-form/src/components/Form/custom/GeoPointInput.tsx
|
|
114
|
-
var GeoPointInput = ({
|
|
134
|
+
var GeoPointInput = ({ type, label, disabled, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
|
|
115
135
|
const { t } = useTranslation(translationKey);
|
|
116
|
-
const { status, error } = getStatus
|
|
117
|
-
const [lng = 0, lat = 0] =
|
|
136
|
+
const { status, error } = getStatus();
|
|
137
|
+
const [lng = 0, lat = 0] = getValue3() ?? [];
|
|
118
138
|
return /* @__PURE__ */ React3.createElement(Input2.Root, {
|
|
119
139
|
validationValence: status
|
|
120
140
|
}, /* @__PURE__ */ React3.createElement(InputHeader, {
|
|
@@ -126,7 +146,7 @@ var GeoPointInput = ({ property, type, label, disabled, getStatus, getValue: get
|
|
|
126
146
|
disabled,
|
|
127
147
|
placeholder: t("placeholder longitude"),
|
|
128
148
|
value: lng,
|
|
129
|
-
onChange: (event) => onValueChange(
|
|
149
|
+
onChange: (event) => onValueChange(type, [
|
|
130
150
|
lat,
|
|
131
151
|
safeParseFloat(event.target.value, 0)
|
|
132
152
|
]),
|
|
@@ -136,7 +156,7 @@ var GeoPointInput = ({ property, type, label, disabled, getStatus, getValue: get
|
|
|
136
156
|
disabled,
|
|
137
157
|
placeholder: t("placeholder latitude"),
|
|
138
158
|
value: lat,
|
|
139
|
-
onChange: (event) => onValueChange(
|
|
159
|
+
onChange: (event) => onValueChange(type, [
|
|
140
160
|
safeParseFloat(event.target.value, 0),
|
|
141
161
|
lng
|
|
142
162
|
]),
|
|
@@ -144,10 +164,193 @@ var GeoPointInput = ({ property, type, label, disabled, getStatus, getValue: get
|
|
|
144
164
|
})));
|
|
145
165
|
};
|
|
146
166
|
|
|
167
|
+
// packages/ui/react-ui-form/src/components/Form/custom/SelectOptionsInput.tsx
|
|
168
|
+
import React4, { useCallback, useEffect, useState, useRef } from "react";
|
|
169
|
+
import { PublicKey } from "@dxos/keys";
|
|
170
|
+
import { Icon as Icon2, IconButton, Input as Input3, Tag, Toolbar, useTranslation as useTranslation2 } from "@dxos/react-ui";
|
|
171
|
+
import { List } from "@dxos/react-ui-list";
|
|
172
|
+
import { HuePickerToolbarButton } from "@dxos/react-ui-pickers";
|
|
173
|
+
import { hueTokenThemes, mx as mx2 } from "@dxos/react-ui-theme";
|
|
174
|
+
var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3, onValueChange }) => {
|
|
175
|
+
const [selected, setSelectedId] = useState(null);
|
|
176
|
+
const [isNewOption, setIsNewOption] = useState(false);
|
|
177
|
+
const inputRef = useRef(null);
|
|
178
|
+
const { t } = useTranslation2(translationKey);
|
|
179
|
+
const { status, error } = getStatus();
|
|
180
|
+
const options = getValue3();
|
|
181
|
+
useEffect(() => {
|
|
182
|
+
if (options === void 0) {
|
|
183
|
+
onValueChange(type, []);
|
|
184
|
+
}
|
|
185
|
+
}, [
|
|
186
|
+
options,
|
|
187
|
+
onValueChange,
|
|
188
|
+
type
|
|
189
|
+
]);
|
|
190
|
+
const randomHue = () => {
|
|
191
|
+
const usedHues = new Set(options?.map((option) => option.color) ?? []);
|
|
192
|
+
const hueKeys = Object.keys(hueTokenThemes);
|
|
193
|
+
const unusedHues = hueKeys.filter((hue) => !usedHues.has(hue));
|
|
194
|
+
if (unusedHues.length > 0) {
|
|
195
|
+
return unusedHues[Math.floor(Math.random() * unusedHues.length)];
|
|
196
|
+
}
|
|
197
|
+
const lastThree = new Set(options?.slice(-3).map((option) => option.color) ?? []);
|
|
198
|
+
const availableHues = hueKeys.filter((hue) => !lastThree.has(hue));
|
|
199
|
+
return availableHues[Math.floor(Math.random() * availableHues.length)] ?? hueKeys[Math.floor(Math.random() * hueKeys.length)];
|
|
200
|
+
};
|
|
201
|
+
const handleAdd = useCallback(() => {
|
|
202
|
+
const newId = PublicKey.random().truncate();
|
|
203
|
+
const newOption = {
|
|
204
|
+
id: newId,
|
|
205
|
+
title: "",
|
|
206
|
+
color: randomHue()
|
|
207
|
+
};
|
|
208
|
+
onValueChange(type, [
|
|
209
|
+
...options ?? [],
|
|
210
|
+
newOption
|
|
211
|
+
]);
|
|
212
|
+
setSelectedId(newId);
|
|
213
|
+
setIsNewOption(true);
|
|
214
|
+
}, [
|
|
215
|
+
options,
|
|
216
|
+
type,
|
|
217
|
+
onValueChange
|
|
218
|
+
]);
|
|
219
|
+
const handleDelete = useCallback((id) => {
|
|
220
|
+
const newOptions = options?.filter((option) => option.id !== id) ?? [];
|
|
221
|
+
onValueChange(type, newOptions);
|
|
222
|
+
setSelectedId(null);
|
|
223
|
+
}, [
|
|
224
|
+
options,
|
|
225
|
+
type,
|
|
226
|
+
onValueChange
|
|
227
|
+
]);
|
|
228
|
+
const handleMove = useCallback((from, to) => {
|
|
229
|
+
if (!options) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
const newOptions = [
|
|
233
|
+
...options
|
|
234
|
+
];
|
|
235
|
+
const [removed] = newOptions.splice(from, 1);
|
|
236
|
+
newOptions.splice(to, 0, removed);
|
|
237
|
+
onValueChange(type, newOptions);
|
|
238
|
+
}, [
|
|
239
|
+
options,
|
|
240
|
+
type,
|
|
241
|
+
onValueChange
|
|
242
|
+
]);
|
|
243
|
+
const handleClick = useCallback((id) => {
|
|
244
|
+
setSelectedId((current) => current === id ? null : id);
|
|
245
|
+
}, []);
|
|
246
|
+
const handleTitleChange = useCallback((id) => (e) => {
|
|
247
|
+
const newOptions = options?.map((o) => o.id === id ? {
|
|
248
|
+
...o,
|
|
249
|
+
title: e.target.value
|
|
250
|
+
} : o);
|
|
251
|
+
onValueChange(type, newOptions ?? []);
|
|
252
|
+
}, [
|
|
253
|
+
options,
|
|
254
|
+
type,
|
|
255
|
+
onValueChange
|
|
256
|
+
]);
|
|
257
|
+
const handleKeyDown = useCallback((e) => {
|
|
258
|
+
if (e.key === "Enter") {
|
|
259
|
+
setSelectedId(null);
|
|
260
|
+
}
|
|
261
|
+
}, []);
|
|
262
|
+
const handleColorChange = useCallback((id) => (hue) => {
|
|
263
|
+
const newOptions = options?.map((o) => o.id === id ? {
|
|
264
|
+
...o,
|
|
265
|
+
color: hue
|
|
266
|
+
} : o);
|
|
267
|
+
onValueChange(type, newOptions ?? []);
|
|
268
|
+
}, [
|
|
269
|
+
options,
|
|
270
|
+
type,
|
|
271
|
+
onValueChange
|
|
272
|
+
]);
|
|
273
|
+
useEffect(() => {
|
|
274
|
+
if (selected && isNewOption && inputRef.current) {
|
|
275
|
+
inputRef.current.focus();
|
|
276
|
+
setIsNewOption(false);
|
|
277
|
+
}
|
|
278
|
+
}, [
|
|
279
|
+
selected,
|
|
280
|
+
isNewOption
|
|
281
|
+
]);
|
|
282
|
+
return /* @__PURE__ */ React4.createElement(Input3.Root, {
|
|
283
|
+
validationValence: status
|
|
284
|
+
}, /* @__PURE__ */ React4.createElement(InputHeader, {
|
|
285
|
+
error
|
|
286
|
+
}, /* @__PURE__ */ React4.createElement(Input3.Label, null, label)), /* @__PURE__ */ React4.createElement("div", {
|
|
287
|
+
role: "none"
|
|
288
|
+
}, options && /* @__PURE__ */ React4.createElement(List.Root, {
|
|
289
|
+
items: options,
|
|
290
|
+
isItem: (item) => true,
|
|
291
|
+
onMove: handleMove
|
|
292
|
+
}, ({ items }) => /* @__PURE__ */ React4.createElement("div", {
|
|
293
|
+
role: "list",
|
|
294
|
+
className: "w-full overflow-auto"
|
|
295
|
+
}, items?.map((item) => /* @__PURE__ */ React4.createElement("div", {
|
|
296
|
+
key: item.id
|
|
297
|
+
}, /* @__PURE__ */ React4.createElement(List.Item, {
|
|
298
|
+
role: "button",
|
|
299
|
+
item,
|
|
300
|
+
classNames: mx2("p-1 plb-2", "flex flex-col", "cursor-pointer", "hover:bg-hoverOverlay"),
|
|
301
|
+
"aria-expanded": selected === item.id
|
|
302
|
+
}, /* @__PURE__ */ React4.createElement("div", {
|
|
303
|
+
className: "flex items-center"
|
|
304
|
+
}, /* @__PURE__ */ React4.createElement(List.ItemDragHandle, null), /* @__PURE__ */ React4.createElement(List.ItemTitle, {
|
|
305
|
+
onClick: () => handleClick(item.id),
|
|
306
|
+
classNames: "flex-1"
|
|
307
|
+
}, /* @__PURE__ */ React4.createElement(Tag, {
|
|
308
|
+
palette: item.color
|
|
309
|
+
}, item.title || "\u200B")), /* @__PURE__ */ React4.createElement(Icon2, {
|
|
310
|
+
icon: selected === item.id ? "ph--caret-down--regular" : "ph--caret-right--regular",
|
|
311
|
+
onClick: () => handleClick(item.id)
|
|
312
|
+
})), selected === item.id && /* @__PURE__ */ React4.createElement("div", {
|
|
313
|
+
className: "mis-4 mbs-2 flex flex-col gap-1"
|
|
314
|
+
}, /* @__PURE__ */ React4.createElement(Input3.Label, {
|
|
315
|
+
classNames: "text-xs"
|
|
316
|
+
}, t("select option label")), /* @__PURE__ */ React4.createElement("div", {
|
|
317
|
+
className: "flex flex-row items-center gap-1"
|
|
318
|
+
}, /* @__PURE__ */ React4.createElement(Input3.TextInput, {
|
|
319
|
+
placeholder: t("select option label placeholder"),
|
|
320
|
+
ref: selected === item.id ? inputRef : void 0,
|
|
321
|
+
value: item.title,
|
|
322
|
+
onChange: handleTitleChange(item.id),
|
|
323
|
+
onKeyDown: handleKeyDown,
|
|
324
|
+
classNames: "flex-1"
|
|
325
|
+
}), /* @__PURE__ */ React4.createElement(Toolbar.Root, {
|
|
326
|
+
classNames: "p-0 m-0 !is-auto"
|
|
327
|
+
}, /* @__PURE__ */ React4.createElement(HuePickerToolbarButton, {
|
|
328
|
+
hue: item.color,
|
|
329
|
+
onChangeHue: handleColorChange(item.id)
|
|
330
|
+
})), /* @__PURE__ */ React4.createElement(IconButton, {
|
|
331
|
+
icon: "ph--trash--fill",
|
|
332
|
+
iconOnly: true,
|
|
333
|
+
label: t("select option delete"),
|
|
334
|
+
onClick: () => handleDelete(item.id)
|
|
335
|
+
})))))), /* @__PURE__ */ React4.createElement("div", {
|
|
336
|
+
role: "listitem"
|
|
337
|
+
}, /* @__PURE__ */ React4.createElement("div", {
|
|
338
|
+
role: "button",
|
|
339
|
+
className: mx2("p-1 plb-2", "flex flex-col", "cursor-pointer", "hover:bg-hoverOverlay"),
|
|
340
|
+
onClick: handleAdd
|
|
341
|
+
}, /* @__PURE__ */ React4.createElement("div", {
|
|
342
|
+
className: "flex items-center gap-1"
|
|
343
|
+
}, /* @__PURE__ */ React4.createElement(Icon2, {
|
|
344
|
+
icon: "ph--plus--regular"
|
|
345
|
+
}), /* @__PURE__ */ React4.createElement("span", {
|
|
346
|
+
className: "text-sm"
|
|
347
|
+
}, t("select option add")))))))));
|
|
348
|
+
};
|
|
349
|
+
|
|
147
350
|
// packages/ui/react-ui-form/src/components/Form/custom/TupleInput.tsx
|
|
148
|
-
import
|
|
149
|
-
import { Input as
|
|
150
|
-
import { mx } from "@dxos/react-ui-theme";
|
|
351
|
+
import React5 from "react";
|
|
352
|
+
import { Input as Input4 } from "@dxos/react-ui";
|
|
353
|
+
import { mx as mx3 } from "@dxos/react-ui-theme";
|
|
151
354
|
import { safeParseFloat as safeParseFloat2 } from "@dxos/util";
|
|
152
355
|
var gridCols = [
|
|
153
356
|
"grid-cols-1",
|
|
@@ -155,21 +358,21 @@ var gridCols = [
|
|
|
155
358
|
"grid-cols-3",
|
|
156
359
|
"grid-cols-4"
|
|
157
360
|
];
|
|
158
|
-
var TupleInput = ({ binding,
|
|
159
|
-
const { status, error } = getStatus
|
|
160
|
-
const values =
|
|
161
|
-
return /* @__PURE__ */
|
|
361
|
+
var TupleInput = ({ binding, type, label, disabled, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
|
|
362
|
+
const { status, error } = getStatus();
|
|
363
|
+
const values = getValue3() ?? {};
|
|
364
|
+
return /* @__PURE__ */ React5.createElement(Input4.Root, {
|
|
162
365
|
validationValence: status
|
|
163
|
-
}, /* @__PURE__ */
|
|
366
|
+
}, /* @__PURE__ */ React5.createElement(InputHeader, {
|
|
164
367
|
error
|
|
165
|
-
}, /* @__PURE__ */
|
|
166
|
-
className:
|
|
167
|
-
}, binding.map((prop) => /* @__PURE__ */
|
|
368
|
+
}, /* @__PURE__ */ React5.createElement(Input4.Label, null, label)), /* @__PURE__ */ React5.createElement("div", {
|
|
369
|
+
className: mx3("grid gap-2", gridCols[binding.length - 1])
|
|
370
|
+
}, binding.map((prop) => /* @__PURE__ */ React5.createElement(Input4.TextInput, {
|
|
168
371
|
key: prop,
|
|
169
372
|
type: "number",
|
|
170
373
|
disabled,
|
|
171
374
|
value: values[prop],
|
|
172
|
-
onChange: (event) => onValueChange(
|
|
375
|
+
onChange: (event) => onValueChange(type, {
|
|
173
376
|
...values,
|
|
174
377
|
[prop]: safeParseFloat2(event.target.value, 0)
|
|
175
378
|
}),
|
|
@@ -178,118 +381,105 @@ var TupleInput = ({ binding, property, type, label, disabled, getStatus, getValu
|
|
|
178
381
|
};
|
|
179
382
|
|
|
180
383
|
// packages/ui/react-ui-form/src/components/Form/Defaults.tsx
|
|
181
|
-
import
|
|
182
|
-
import { Input as
|
|
183
|
-
var TextInput = ({
|
|
184
|
-
const { status, error } = getStatus
|
|
185
|
-
return /* @__PURE__ */
|
|
384
|
+
import React6 from "react";
|
|
385
|
+
import { Input as Input5, Select } from "@dxos/react-ui";
|
|
386
|
+
var TextInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
|
|
387
|
+
const { status, error } = getStatus();
|
|
388
|
+
return /* @__PURE__ */ React6.createElement(Input5.Root, {
|
|
186
389
|
validationValence: status
|
|
187
|
-
}, !inputOnly && /* @__PURE__ */
|
|
390
|
+
}, !inputOnly && /* @__PURE__ */ React6.createElement(InputHeader, {
|
|
188
391
|
error
|
|
189
|
-
}, /* @__PURE__ */
|
|
392
|
+
}, /* @__PURE__ */ React6.createElement(Input5.Label, null, label)), /* @__PURE__ */ React6.createElement(Input5.TextInput, {
|
|
190
393
|
disabled,
|
|
191
394
|
placeholder,
|
|
192
|
-
value:
|
|
193
|
-
onChange: (event) => onValueChange(
|
|
395
|
+
value: getValue3() ?? "",
|
|
396
|
+
onChange: (event) => onValueChange(type, event.target.value),
|
|
194
397
|
onBlur
|
|
195
|
-
}), inputOnly && /* @__PURE__ */
|
|
398
|
+
}), inputOnly && /* @__PURE__ */ React6.createElement(Input5.Validation, null, error));
|
|
196
399
|
};
|
|
197
|
-
var NumberInput = ({
|
|
198
|
-
const { status, error } = getStatus
|
|
199
|
-
return /* @__PURE__ */
|
|
400
|
+
var NumberInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
|
|
401
|
+
const { status, error } = getStatus();
|
|
402
|
+
return /* @__PURE__ */ React6.createElement(Input5.Root, {
|
|
200
403
|
validationValence: status
|
|
201
|
-
}, !inputOnly && /* @__PURE__ */
|
|
404
|
+
}, !inputOnly && /* @__PURE__ */ React6.createElement(InputHeader, {
|
|
202
405
|
error
|
|
203
|
-
}, /* @__PURE__ */
|
|
406
|
+
}, /* @__PURE__ */ React6.createElement(Input5.Label, null, label)), /* @__PURE__ */ React6.createElement(Input5.TextInput, {
|
|
204
407
|
type: "number",
|
|
205
408
|
disabled,
|
|
206
409
|
placeholder,
|
|
207
|
-
value:
|
|
208
|
-
onChange: (event) => onValueChange(
|
|
410
|
+
value: getValue3() ?? 0,
|
|
411
|
+
onChange: (event) => onValueChange(type, event.target.value),
|
|
209
412
|
onBlur
|
|
210
|
-
}), inputOnly && /* @__PURE__ */
|
|
413
|
+
}), inputOnly && /* @__PURE__ */ React6.createElement(Input5.DescriptionAndValidation, null, error));
|
|
211
414
|
};
|
|
212
|
-
var BooleanInput = ({
|
|
213
|
-
const { status, error } = getStatus
|
|
214
|
-
return /* @__PURE__ */
|
|
415
|
+
var BooleanInput = ({ type, label, inputOnly, getStatus, getValue: getValue3, onValueChange }) => {
|
|
416
|
+
const { status, error } = getStatus();
|
|
417
|
+
return /* @__PURE__ */ React6.createElement(Input5.Root, {
|
|
215
418
|
validationValence: status
|
|
216
|
-
}, !inputOnly && /* @__PURE__ */
|
|
419
|
+
}, !inputOnly && /* @__PURE__ */ React6.createElement(InputHeader, {
|
|
217
420
|
error
|
|
218
|
-
}, /* @__PURE__ */
|
|
219
|
-
checked:
|
|
220
|
-
onCheckedChange: (value) => onValueChange(
|
|
221
|
-
}), inputOnly && /* @__PURE__ */
|
|
421
|
+
}, /* @__PURE__ */ React6.createElement(Input5.Label, null, label)), /* @__PURE__ */ React6.createElement(Input5.Switch, {
|
|
422
|
+
checked: getValue3(),
|
|
423
|
+
onCheckedChange: (value) => onValueChange(type, value)
|
|
424
|
+
}), inputOnly && /* @__PURE__ */ React6.createElement(Input5.DescriptionAndValidation, null, error));
|
|
222
425
|
};
|
|
223
|
-
var SelectInput = ({
|
|
224
|
-
const { status, error } = getStatus
|
|
225
|
-
return /* @__PURE__ */
|
|
426
|
+
var SelectInput = ({ type, label, inputOnly, disabled, placeholder, options, getStatus, getValue: getValue3, onValueChange }) => {
|
|
427
|
+
const { status, error } = getStatus();
|
|
428
|
+
return /* @__PURE__ */ React6.createElement(Input5.Root, {
|
|
226
429
|
validationValence: status
|
|
227
|
-
}, !inputOnly && /* @__PURE__ */
|
|
430
|
+
}, !inputOnly && /* @__PURE__ */ React6.createElement(InputHeader, {
|
|
228
431
|
error
|
|
229
|
-
}, /* @__PURE__ */
|
|
230
|
-
value:
|
|
231
|
-
onValueChange: (value) => onValueChange(
|
|
232
|
-
}, /* @__PURE__ */
|
|
432
|
+
}, /* @__PURE__ */ React6.createElement(Input5.Label, null, label)), /* @__PURE__ */ React6.createElement(Select.Root, {
|
|
433
|
+
value: getValue3(),
|
|
434
|
+
onValueChange: (value) => onValueChange(type, value)
|
|
435
|
+
}, /* @__PURE__ */ React6.createElement(Select.TriggerButton, {
|
|
233
436
|
classNames: "is-full",
|
|
234
437
|
disabled,
|
|
235
438
|
placeholder
|
|
236
|
-
}), /* @__PURE__ */
|
|
439
|
+
}), /* @__PURE__ */ React6.createElement(Select.Portal, null, /* @__PURE__ */ React6.createElement(Select.Content, null, /* @__PURE__ */ React6.createElement(Select.Viewport, null, options?.map(({ value, label: label2 }) => (
|
|
237
440
|
// NOTE: Numeric values are converted to and from strings.
|
|
238
|
-
/* @__PURE__ */
|
|
441
|
+
/* @__PURE__ */ React6.createElement(Select.Option, {
|
|
239
442
|
key: String(value),
|
|
240
443
|
value: String(value)
|
|
241
444
|
}, label2 ?? String(value))
|
|
242
|
-
)))))), inputOnly && /* @__PURE__ */
|
|
445
|
+
)))))), inputOnly && /* @__PURE__ */ React6.createElement(Input5.DescriptionAndValidation, null, error));
|
|
243
446
|
};
|
|
244
447
|
|
|
245
448
|
// packages/ui/react-ui-form/src/components/Form/Form.tsx
|
|
246
|
-
import {
|
|
247
|
-
import {
|
|
248
|
-
import React6, { useEffect as useEffect2, useMemo as useMemo2 } from "react";
|
|
249
|
-
import { AST, S } from "@dxos/echo-schema";
|
|
250
|
-
import { findNode, getDiscriminatedType, isDiscriminatedUnion, SimpleType } from "@dxos/effect";
|
|
251
|
-
import { log as log2 } from "@dxos/log";
|
|
252
|
-
import { IconButton, useTranslation as useTranslation2 } from "@dxos/react-ui";
|
|
253
|
-
import { mx as mx2 } from "@dxos/react-ui-theme";
|
|
254
|
-
import { getSchemaProperties } from "@dxos/schema";
|
|
255
|
-
import { isNotFalsy } from "@dxos/util";
|
|
449
|
+
import React11, { useMemo as useMemo4 } from "react";
|
|
450
|
+
import { mx as mx7 } from "@dxos/react-ui-theme";
|
|
256
451
|
|
|
257
|
-
// packages/ui/react-ui-form/src/components/Form/
|
|
258
|
-
import
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
case "number":
|
|
268
|
-
return NumberInput;
|
|
269
|
-
case "boolean":
|
|
270
|
-
return BooleanInput;
|
|
271
|
-
}
|
|
272
|
-
};
|
|
452
|
+
// packages/ui/react-ui-form/src/components/Form/FormActions.tsx
|
|
453
|
+
import React8 from "react";
|
|
454
|
+
import { IconButton as IconButton2, useTranslation as useTranslation3 } from "@dxos/react-ui";
|
|
455
|
+
import { mx as mx4 } from "@dxos/react-ui-theme";
|
|
456
|
+
|
|
457
|
+
// packages/ui/react-ui-form/src/components/Form/FormContext.tsx
|
|
458
|
+
import React7, { createContext, useContext } from "react";
|
|
459
|
+
import { raise } from "@dxos/debug";
|
|
460
|
+
import { getValue as getValue2 } from "@dxos/echo-schema";
|
|
461
|
+
import { createJsonPath as createJsonPath2 } from "@dxos/effect";
|
|
273
462
|
|
|
274
463
|
// packages/ui/react-ui-form/src/hooks/useForm.ts
|
|
275
|
-
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
464
|
+
import { useCallback as useCallback2, useEffect as useEffect2, useMemo, useState as useState2 } from "react";
|
|
276
465
|
import { getValue, setValue } from "@dxos/echo-schema";
|
|
466
|
+
import { createJsonPath, fromEffectValidationPath } from "@dxos/effect";
|
|
277
467
|
import { invariant } from "@dxos/invariant";
|
|
278
468
|
import { log } from "@dxos/log";
|
|
279
469
|
import { validateSchema } from "@dxos/schema";
|
|
280
470
|
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/hooks/useForm.ts";
|
|
281
471
|
var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, onSave }) => {
|
|
282
|
-
const [values, setValues] =
|
|
283
|
-
|
|
472
|
+
const [values, setValues] = useState2(initialValues);
|
|
473
|
+
useEffect2(() => {
|
|
284
474
|
setValues(initialValues);
|
|
285
475
|
}, [
|
|
286
476
|
initialValues
|
|
287
477
|
]);
|
|
288
|
-
const [touched, setTouched] =
|
|
289
|
-
const [changed, setChanged] =
|
|
290
|
-
const [errors, setErrors] =
|
|
291
|
-
const [saving, setSaving] =
|
|
292
|
-
const validate =
|
|
478
|
+
const [touched, setTouched] = useState2(createKeySet(initialValues, false));
|
|
479
|
+
const [changed, setChanged] = useState2(createKeySet(initialValues, false));
|
|
480
|
+
const [errors, setErrors] = useState2({});
|
|
481
|
+
const [saving, setSaving] = useState2(false);
|
|
482
|
+
const validate = useCallback2((values2) => {
|
|
293
483
|
let errors2 = validateSchema(schema, values2) ?? [];
|
|
294
484
|
if (errors2.length === 0 && onValidate) {
|
|
295
485
|
const validatedValues = values2;
|
|
@@ -302,11 +492,11 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
|
|
|
302
492
|
schema,
|
|
303
493
|
onValidate
|
|
304
494
|
]);
|
|
305
|
-
const [schemaDirty, setSchemaDirty] =
|
|
306
|
-
|
|
495
|
+
const [schemaDirty, setSchemaDirty] = useState2(false);
|
|
496
|
+
useEffect2(() => setSchemaDirty(true), [
|
|
307
497
|
schema
|
|
308
498
|
]);
|
|
309
|
-
|
|
499
|
+
useEffect2(() => {
|
|
310
500
|
if (schemaDirty) {
|
|
311
501
|
validate(values);
|
|
312
502
|
setSchemaDirty(false);
|
|
@@ -315,13 +505,13 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
|
|
|
315
505
|
values,
|
|
316
506
|
schemaDirty
|
|
317
507
|
]);
|
|
318
|
-
const canSave = useMemo(() => !saving &&
|
|
319
|
-
|
|
508
|
+
const canSave = useMemo(() => !saving && // Check if any error paths that are touched have errors
|
|
509
|
+
!Object.entries(touched).some(([path, isTouched]) => isTouched && Object.keys(errors).some((errorPath) => errorPath === path || errorPath.startsWith(`${path}.`) || errorPath.startsWith(`${path}[`))), [
|
|
320
510
|
touched,
|
|
321
511
|
errors,
|
|
322
512
|
saving
|
|
323
513
|
]);
|
|
324
|
-
const handleSave =
|
|
514
|
+
const handleSave = useCallback2(async () => {
|
|
325
515
|
if (validate(values)) {
|
|
326
516
|
setSaving(true);
|
|
327
517
|
try {
|
|
@@ -338,17 +528,21 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
|
|
|
338
528
|
onSave,
|
|
339
529
|
changed
|
|
340
530
|
]);
|
|
341
|
-
const getStatus =
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
531
|
+
const getStatus = useCallback2((path) => {
|
|
532
|
+
const jsonPath = Array.isArray(path) ? createJsonPath(path) : path;
|
|
533
|
+
const matchingError = Object.entries(errors).find(([errorPath]) => errorPath === jsonPath || errorPath.startsWith(`${jsonPath}.`) || errorPath.startsWith(`${jsonPath}[`));
|
|
534
|
+
return {
|
|
535
|
+
status: matchingError ? "error" : void 0,
|
|
536
|
+
error: matchingError ? matchingError[1] : void 0
|
|
537
|
+
};
|
|
538
|
+
}, [
|
|
346
539
|
errors
|
|
347
540
|
]);
|
|
348
|
-
const getFormValue = (
|
|
349
|
-
return getValue(values,
|
|
541
|
+
const getFormValue = (path) => {
|
|
542
|
+
return getValue(values, createJsonPath(path));
|
|
350
543
|
};
|
|
351
|
-
const onValueChange = (
|
|
544
|
+
const onValueChange = (path, type, value) => {
|
|
545
|
+
const jsonPath = createJsonPath(path);
|
|
352
546
|
let parsedValue = value;
|
|
353
547
|
try {
|
|
354
548
|
if (type === "number") {
|
|
@@ -357,19 +551,19 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
|
|
|
357
551
|
} catch (err) {
|
|
358
552
|
log.catch(err, void 0, {
|
|
359
553
|
F: __dxlog_file,
|
|
360
|
-
L:
|
|
554
|
+
L: 192,
|
|
361
555
|
S: void 0,
|
|
362
556
|
C: (f, a) => f(...a)
|
|
363
557
|
});
|
|
364
558
|
parsedValue = void 0;
|
|
365
559
|
}
|
|
366
560
|
const newValues = {
|
|
367
|
-
...setValue(values,
|
|
561
|
+
...setValue(values, jsonPath, parsedValue)
|
|
368
562
|
};
|
|
369
563
|
setValues(newValues);
|
|
370
564
|
setChanged((prev) => ({
|
|
371
565
|
...prev,
|
|
372
|
-
[
|
|
566
|
+
[jsonPath]: true
|
|
373
567
|
}));
|
|
374
568
|
onValuesChanged?.(newValues);
|
|
375
569
|
const isValid = validate(newValues);
|
|
@@ -379,15 +573,12 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
|
|
|
379
573
|
});
|
|
380
574
|
}
|
|
381
575
|
};
|
|
382
|
-
const
|
|
383
|
-
const
|
|
576
|
+
const onTouched = useCallback2((path) => {
|
|
577
|
+
const jsonPath = createJsonPath(path);
|
|
384
578
|
setTouched((touched2) => ({
|
|
385
579
|
...touched2,
|
|
386
|
-
[
|
|
580
|
+
[jsonPath]: true
|
|
387
581
|
}));
|
|
388
|
-
if (event.relatedTarget?.getAttribute("type") === "submit") {
|
|
389
|
-
setTouched(createKeySet(values, true));
|
|
390
|
-
}
|
|
391
582
|
validate(values);
|
|
392
583
|
}, [
|
|
393
584
|
validate,
|
|
@@ -405,13 +596,13 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
|
|
|
405
596
|
getStatus,
|
|
406
597
|
getValue: getFormValue,
|
|
407
598
|
onValueChange,
|
|
408
|
-
|
|
599
|
+
onTouched
|
|
409
600
|
};
|
|
410
601
|
};
|
|
411
602
|
var createKeySet = (obj, value) => {
|
|
412
603
|
invariant(obj, void 0, {
|
|
413
604
|
F: __dxlog_file,
|
|
414
|
-
L:
|
|
605
|
+
L: 234,
|
|
415
606
|
S: void 0,
|
|
416
607
|
A: [
|
|
417
608
|
"obj",
|
|
@@ -425,337 +616,381 @@ var createKeySet = (obj, value) => {
|
|
|
425
616
|
};
|
|
426
617
|
var flatMap = (errors) => {
|
|
427
618
|
return errors.reduce((result, { path, message }) => {
|
|
428
|
-
|
|
429
|
-
|
|
619
|
+
const jsonPath = fromEffectValidationPath(path);
|
|
620
|
+
if (!(jsonPath in result)) {
|
|
621
|
+
result[jsonPath] = message;
|
|
430
622
|
}
|
|
431
623
|
return result;
|
|
432
624
|
}, {});
|
|
433
625
|
};
|
|
434
626
|
|
|
435
|
-
// packages/ui/react-ui-form/src/components/Form/
|
|
436
|
-
var
|
|
627
|
+
// packages/ui/react-ui-form/src/components/Form/FormContext.tsx
|
|
628
|
+
var FormContext = /* @__PURE__ */ createContext(void 0);
|
|
629
|
+
var useFormContext = () => {
|
|
630
|
+
return useContext(FormContext) ?? raise(new Error("Missing FormContext"));
|
|
631
|
+
};
|
|
632
|
+
var useFormValues = (path = []) => {
|
|
633
|
+
const { values: formValues } = useFormContext();
|
|
634
|
+
const jsonPath = createJsonPath2(path);
|
|
635
|
+
return getValue2(formValues, jsonPath);
|
|
636
|
+
};
|
|
637
|
+
var useInputProps = (path = []) => {
|
|
638
|
+
const { getStatus, getValue: getFormValue, onValueChange, onTouched } = useFormContext();
|
|
639
|
+
return {
|
|
640
|
+
getStatus: () => getStatus(path),
|
|
641
|
+
getValue: () => getFormValue(path),
|
|
642
|
+
onValueChange: (type, value) => onValueChange(path, type, value),
|
|
643
|
+
onBlur: () => onTouched(path)
|
|
644
|
+
};
|
|
645
|
+
};
|
|
646
|
+
var FormProvider = ({ children, ...formOptions }) => {
|
|
647
|
+
const formHandler = useForm(formOptions);
|
|
648
|
+
return /* @__PURE__ */ React7.createElement(FormContext.Provider, {
|
|
649
|
+
value: formHandler
|
|
650
|
+
}, children);
|
|
651
|
+
};
|
|
652
|
+
|
|
653
|
+
// packages/ui/react-ui-form/src/components/Form/FormActions.tsx
|
|
654
|
+
var FormActions = ({ onCancel, readonly }) => {
|
|
655
|
+
const { t } = useTranslation3(translationKey);
|
|
656
|
+
const { canSave, handleSave } = useFormContext();
|
|
657
|
+
return /* @__PURE__ */ React8.createElement("div", {
|
|
658
|
+
role: "none",
|
|
659
|
+
className: "flex justify-center"
|
|
660
|
+
}, /* @__PURE__ */ React8.createElement("div", {
|
|
661
|
+
role: "none",
|
|
662
|
+
className: mx4(onCancel && !readonly && "grid grid-cols-2 gap-2")
|
|
663
|
+
}, onCancel && !readonly && /* @__PURE__ */ React8.createElement(IconButton2, {
|
|
664
|
+
"data-testid": "cancel-button",
|
|
665
|
+
icon: "ph--x--regular",
|
|
666
|
+
label: t("button cancel"),
|
|
667
|
+
onClick: onCancel
|
|
668
|
+
}), handleSave && /* @__PURE__ */ React8.createElement(IconButton2, {
|
|
669
|
+
type: "submit",
|
|
670
|
+
"data-testid": "save-button",
|
|
671
|
+
disabled: !canSave,
|
|
672
|
+
icon: "ph--check--regular",
|
|
673
|
+
label: t("button save"),
|
|
674
|
+
onClick: handleSave
|
|
675
|
+
})));
|
|
676
|
+
};
|
|
677
|
+
|
|
678
|
+
// packages/ui/react-ui-form/src/components/Form/FormContent.tsx
|
|
679
|
+
import { pipe as pipe2 } from "effect";
|
|
680
|
+
import { capitalize as capitalize2 } from "effect/String";
|
|
681
|
+
import React10, { useMemo as useMemo3 } from "react";
|
|
682
|
+
import { AST as AST2, S } from "@dxos/echo-schema";
|
|
683
|
+
import { createJsonPath as createJsonPath3, findNode as findNode2, getDiscriminatedType as getDiscriminatedType2, isDiscriminatedUnion as isDiscriminatedUnion2 } from "@dxos/effect";
|
|
684
|
+
import { mx as mx6 } from "@dxos/react-ui-theme";
|
|
685
|
+
import { getSchemaProperties as getSchemaProperties2 } from "@dxos/schema";
|
|
686
|
+
import { isNotFalsy } from "@dxos/util";
|
|
687
|
+
|
|
688
|
+
// packages/ui/react-ui-form/src/components/Form/ArrayField.tsx
|
|
689
|
+
import { pipe } from "effect";
|
|
690
|
+
import { capitalize } from "effect/String";
|
|
691
|
+
import React9, { useCallback as useCallback3, useMemo as useMemo2 } from "react";
|
|
692
|
+
import { AST } from "@dxos/echo-schema";
|
|
693
|
+
import { findNode, getDiscriminatedType, isDiscriminatedUnion, SimpleType } from "@dxos/effect";
|
|
694
|
+
import { invariant as invariant2 } from "@dxos/invariant";
|
|
695
|
+
import { IconButton as IconButton3, useTranslation as useTranslation4 } from "@dxos/react-ui";
|
|
696
|
+
import { mx as mx5 } from "@dxos/react-ui-theme";
|
|
697
|
+
import { getSchemaProperties } from "@dxos/schema";
|
|
698
|
+
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/Form/ArrayField.tsx";
|
|
437
699
|
var padding = "px-2";
|
|
438
|
-
var
|
|
439
|
-
const
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
700
|
+
var ArrayField = ({ property, readonly, path, inputProps, Custom, lookupComponent }) => {
|
|
701
|
+
const { t } = useTranslation4(translationKey);
|
|
702
|
+
const { ast, name, type, title } = property;
|
|
703
|
+
const values = useFormValues(path ?? []);
|
|
704
|
+
invariant2(Array.isArray(values), `Values at path ${path?.join(".")} must be an array.`, {
|
|
705
|
+
F: __dxlog_file2,
|
|
706
|
+
L: 37,
|
|
707
|
+
S: void 0,
|
|
708
|
+
A: [
|
|
709
|
+
"Array.isArray(values)",
|
|
710
|
+
"`Values at path ${path?.join('.')} must be an array.`"
|
|
711
|
+
]
|
|
450
712
|
});
|
|
451
|
-
const
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
713
|
+
const label = title ?? pipe(name, capitalize);
|
|
714
|
+
const tupleType = findNode(ast, AST.isTupleType);
|
|
715
|
+
const elementType = tupleType?.rest[0]?.type;
|
|
716
|
+
const getDefaultObjectValue = (typeNode) => {
|
|
717
|
+
const baseNode = findNode(typeNode, isDiscriminatedUnion);
|
|
718
|
+
const typeLiteral = baseNode ? getDiscriminatedType(baseNode, {}) : findNode(typeNode, AST.isTypeLiteral);
|
|
719
|
+
if (!typeLiteral) {
|
|
720
|
+
return {};
|
|
721
|
+
}
|
|
722
|
+
return Object.fromEntries(getSchemaProperties(typeLiteral, {}).map((prop) => [
|
|
723
|
+
prop.name,
|
|
724
|
+
prop.defaultValue
|
|
725
|
+
]));
|
|
726
|
+
};
|
|
727
|
+
const newValue = useMemo2(() => {
|
|
728
|
+
if (type === "object" && elementType) {
|
|
729
|
+
return getDefaultObjectValue(elementType);
|
|
730
|
+
} else {
|
|
731
|
+
return SimpleType.getDefaultValue(type);
|
|
732
|
+
}
|
|
459
733
|
}, [
|
|
460
|
-
|
|
461
|
-
|
|
734
|
+
type,
|
|
735
|
+
elementType
|
|
736
|
+
]);
|
|
737
|
+
const handleAdd = useCallback3(() => {
|
|
738
|
+
inputProps.onValueChange(type, [
|
|
739
|
+
...values,
|
|
740
|
+
newValue
|
|
741
|
+
]);
|
|
742
|
+
}, [
|
|
743
|
+
type,
|
|
744
|
+
elementType,
|
|
745
|
+
inputProps,
|
|
746
|
+
newValue,
|
|
462
747
|
values
|
|
463
748
|
]);
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
errors
|
|
468
|
-
}, {
|
|
469
|
-
F: __dxlog_file2,
|
|
470
|
-
L: 106,
|
|
471
|
-
S: void 0,
|
|
472
|
-
C: (f, a) => f(...a)
|
|
473
|
-
});
|
|
474
|
-
}
|
|
749
|
+
const handleRemove = useCallback3((index) => {
|
|
750
|
+
const newValues = values.filter((_, i) => i !== index);
|
|
751
|
+
inputProps.onValueChange(type, newValues);
|
|
475
752
|
}, [
|
|
476
|
-
|
|
753
|
+
type,
|
|
754
|
+
inputProps,
|
|
755
|
+
values
|
|
477
756
|
]);
|
|
478
|
-
|
|
479
|
-
role: "form",
|
|
480
|
-
className: mx2("flex flex-col w-full gap-2 py-2", classNames),
|
|
481
|
-
"data-testid": testId
|
|
482
|
-
}, properties.map((property) => {
|
|
483
|
-
const { ast, name, type, format, title, description, examples, options, array } = property;
|
|
484
|
-
const key = [
|
|
485
|
-
...path,
|
|
486
|
-
name
|
|
487
|
-
];
|
|
488
|
-
const label = title ?? pipe(name, capitalize);
|
|
489
|
-
const placeholder = examples?.length ? `Example: "${examples[0]}"` : description;
|
|
490
|
-
const FoundComponent = lookupComponent?.({
|
|
491
|
-
prop: name,
|
|
492
|
-
schema: S.make(ast),
|
|
493
|
-
inputProps: {
|
|
494
|
-
property: name,
|
|
495
|
-
type,
|
|
496
|
-
format,
|
|
497
|
-
label,
|
|
498
|
-
disabled: readonly,
|
|
499
|
-
placeholder,
|
|
500
|
-
...inputProps
|
|
501
|
-
}
|
|
502
|
-
});
|
|
503
|
-
if (FoundComponent) {
|
|
504
|
-
return /* @__PURE__ */ React6.createElement("div", {
|
|
505
|
-
key: name,
|
|
506
|
-
role: "none",
|
|
507
|
-
className: padding
|
|
508
|
-
}, FoundComponent);
|
|
509
|
-
}
|
|
510
|
-
let InputComponent = Custom?.[key.join(".")];
|
|
511
|
-
if (!InputComponent) {
|
|
512
|
-
if (options) {
|
|
513
|
-
return /* @__PURE__ */ React6.createElement("div", {
|
|
514
|
-
key: name,
|
|
515
|
-
role: "none",
|
|
516
|
-
className: padding
|
|
517
|
-
}, /* @__PURE__ */ React6.createElement(SelectInput, {
|
|
518
|
-
type,
|
|
519
|
-
format,
|
|
520
|
-
property: name,
|
|
521
|
-
disabled: readonly,
|
|
522
|
-
label,
|
|
523
|
-
options: options.map((option) => ({
|
|
524
|
-
value: option,
|
|
525
|
-
label: String(option)
|
|
526
|
-
})),
|
|
527
|
-
placeholder,
|
|
528
|
-
...inputProps
|
|
529
|
-
}));
|
|
530
|
-
}
|
|
531
|
-
InputComponent = getInputComponent(type, format);
|
|
532
|
-
if (array) {
|
|
533
|
-
return /* @__PURE__ */ React6.createElement(ArrayField, {
|
|
534
|
-
key: name,
|
|
535
|
-
name,
|
|
536
|
-
type,
|
|
537
|
-
array: true,
|
|
538
|
-
label,
|
|
539
|
-
ast,
|
|
540
|
-
values,
|
|
541
|
-
format,
|
|
542
|
-
readonly,
|
|
543
|
-
placeholder,
|
|
544
|
-
inputProps,
|
|
545
|
-
Custom
|
|
546
|
-
});
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
if (!InputComponent) {
|
|
550
|
-
if (type === "object") {
|
|
551
|
-
const baseNode = findNode(ast, isDiscriminatedUnion);
|
|
552
|
-
const typeLiteral = baseNode ? getDiscriminatedType(baseNode, values[name]) : findNode(ast, AST.isTypeLiteral);
|
|
553
|
-
if (typeLiteral) {
|
|
554
|
-
const schema2 = S.make(typeLiteral);
|
|
555
|
-
return /* @__PURE__ */ React6.createElement("div", {
|
|
556
|
-
key: name,
|
|
557
|
-
role: "none"
|
|
558
|
-
}, /* @__PURE__ */ React6.createElement("div", {
|
|
559
|
-
className: padding
|
|
560
|
-
}, label), /* @__PURE__ */ React6.createElement(Form, {
|
|
561
|
-
schema: schema2,
|
|
562
|
-
path: key,
|
|
563
|
-
values: values[name] ?? {},
|
|
564
|
-
onValuesChanged: (childValues) => {
|
|
565
|
-
inputProps.onValueChange(name, "object", childValues);
|
|
566
|
-
},
|
|
567
|
-
Custom
|
|
568
|
-
}));
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
log2("no renderer for property", {
|
|
572
|
-
name,
|
|
573
|
-
type
|
|
574
|
-
}, {
|
|
575
|
-
F: __dxlog_file2,
|
|
576
|
-
L: 213,
|
|
577
|
-
S: void 0,
|
|
578
|
-
C: (f, a) => f(...a)
|
|
579
|
-
});
|
|
580
|
-
return null;
|
|
581
|
-
}
|
|
582
|
-
return /* @__PURE__ */ React6.createElement("div", {
|
|
583
|
-
key: name,
|
|
584
|
-
role: "none",
|
|
585
|
-
className: padding
|
|
586
|
-
}, /* @__PURE__ */ React6.createElement(InputComponent, {
|
|
587
|
-
type,
|
|
588
|
-
format,
|
|
589
|
-
property: name,
|
|
590
|
-
disabled: readonly,
|
|
591
|
-
label,
|
|
592
|
-
placeholder,
|
|
593
|
-
...inputProps
|
|
594
|
-
}));
|
|
595
|
-
}).filter(isNotFalsy), (onCancel || onSave) && !autoSave && /* @__PURE__ */ React6.createElement(FormActions, {
|
|
596
|
-
onCancel,
|
|
597
|
-
onSubmit: handleSave,
|
|
598
|
-
canSubmit: canSave,
|
|
599
|
-
readonly
|
|
600
|
-
}));
|
|
601
|
-
};
|
|
602
|
-
var ArrayField = ({ name, type, label, ast, values, format, readonly, placeholder, inputProps, Custom }) => {
|
|
603
|
-
const { t } = useTranslation2(translationKey);
|
|
604
|
-
const arrayValues = values[name] ?? [];
|
|
605
|
-
const key = [
|
|
606
|
-
name
|
|
607
|
-
];
|
|
608
|
-
const tupleType = findNode(ast, AST.isTupleType);
|
|
609
|
-
const elementType = tupleType?.rest[0]?.type;
|
|
610
|
-
if (type === "object" && elementType) {
|
|
611
|
-
const baseNode = findNode(elementType, isDiscriminatedUnion);
|
|
612
|
-
const typeLiteral = baseNode ? getDiscriminatedType(baseNode, values[name]) : findNode(elementType, AST.isTypeLiteral);
|
|
613
|
-
if (typeLiteral) {
|
|
614
|
-
const schema = S.make(typeLiteral);
|
|
615
|
-
return /* @__PURE__ */ React6.createElement("div", {
|
|
616
|
-
key: name,
|
|
617
|
-
role: "none",
|
|
618
|
-
className: mx2(padding)
|
|
619
|
-
}, /* @__PURE__ */ React6.createElement(InputHeader, null, label), /* @__PURE__ */ React6.createElement("div", {
|
|
620
|
-
role: "none",
|
|
621
|
-
className: "flex flex-col gap-1"
|
|
622
|
-
}, arrayValues.map((value, index) => {
|
|
623
|
-
return /* @__PURE__ */ React6.createElement("div", {
|
|
624
|
-
key: index,
|
|
625
|
-
role: "none",
|
|
626
|
-
className: "flex items-center gap-1"
|
|
627
|
-
}, /* @__PURE__ */ React6.createElement("div", {
|
|
628
|
-
role: "none",
|
|
629
|
-
className: "flex-1"
|
|
630
|
-
}, /* @__PURE__ */ React6.createElement(Form, {
|
|
631
|
-
schema,
|
|
632
|
-
path: [
|
|
633
|
-
...key,
|
|
634
|
-
`[${index}]`
|
|
635
|
-
],
|
|
636
|
-
values: value,
|
|
637
|
-
onValuesChanged: (childValues) => {
|
|
638
|
-
const newValues = [
|
|
639
|
-
...arrayValues
|
|
640
|
-
];
|
|
641
|
-
newValues[index] = childValues;
|
|
642
|
-
inputProps.onValueChange(name, "object", newValues);
|
|
643
|
-
},
|
|
644
|
-
Custom
|
|
645
|
-
})), /* @__PURE__ */ React6.createElement(IconButton, {
|
|
646
|
-
icon: "ph--trash--regular",
|
|
647
|
-
iconOnly: true,
|
|
648
|
-
label: t("button remove"),
|
|
649
|
-
onClick: () => {
|
|
650
|
-
const newValues = arrayValues.filter((_, i) => i !== index);
|
|
651
|
-
inputProps.onValueChange(name, type, newValues);
|
|
652
|
-
}
|
|
653
|
-
}));
|
|
654
|
-
})), /* @__PURE__ */ React6.createElement("div", {
|
|
655
|
-
role: "none",
|
|
656
|
-
className: "flex justify-between items-center plb-1"
|
|
657
|
-
}, /* @__PURE__ */ React6.createElement(IconButton, {
|
|
658
|
-
icon: "ph--plus--regular",
|
|
659
|
-
iconOnly: true,
|
|
660
|
-
label: t("button add"),
|
|
661
|
-
onClick: () => {
|
|
662
|
-
const newValues = [
|
|
663
|
-
...arrayValues,
|
|
664
|
-
{}
|
|
665
|
-
];
|
|
666
|
-
inputProps.onValueChange(name, type, newValues);
|
|
667
|
-
}
|
|
668
|
-
})));
|
|
669
|
-
}
|
|
670
|
-
return /* @__PURE__ */ React6.createElement("div", {
|
|
671
|
-
key: name,
|
|
672
|
-
role: "none"
|
|
673
|
-
}, "Nested form not supported in arrays, yet.");
|
|
674
|
-
}
|
|
675
|
-
const InputComponent = getInputComponent(type, format);
|
|
676
|
-
if (!InputComponent) {
|
|
757
|
+
if (!elementType) {
|
|
677
758
|
return null;
|
|
678
759
|
}
|
|
679
|
-
return /* @__PURE__ */
|
|
760
|
+
return /* @__PURE__ */ React9.createElement("div", {
|
|
680
761
|
role: "none",
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
}, /* @__PURE__ */ React6.createElement(InputHeader, null, label), /* @__PURE__ */ React6.createElement("div", {
|
|
762
|
+
className: mx5(padding)
|
|
763
|
+
}, /* @__PURE__ */ React9.createElement(InputHeader, null, label), /* @__PURE__ */ React9.createElement("div", {
|
|
684
764
|
role: "none",
|
|
685
765
|
className: "flex flex-col gap-1"
|
|
686
|
-
},
|
|
766
|
+
}, values.map((_value, index) => /* @__PURE__ */ React9.createElement("div", {
|
|
687
767
|
key: index,
|
|
688
768
|
role: "none",
|
|
689
|
-
className: "flex items-
|
|
690
|
-
}, /* @__PURE__ */
|
|
769
|
+
className: "flex items-center gap-1"
|
|
770
|
+
}, /* @__PURE__ */ React9.createElement("div", {
|
|
691
771
|
role: "none",
|
|
692
772
|
className: "flex-1"
|
|
693
|
-
}, /* @__PURE__ */
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
773
|
+
}, /* @__PURE__ */ React9.createElement(FormField, {
|
|
774
|
+
property: {
|
|
775
|
+
...property,
|
|
776
|
+
array: false,
|
|
777
|
+
ast: elementType
|
|
778
|
+
},
|
|
779
|
+
path: [
|
|
780
|
+
...path ?? [],
|
|
781
|
+
index
|
|
782
|
+
],
|
|
783
|
+
readonly,
|
|
784
|
+
inline: true,
|
|
785
|
+
Custom,
|
|
786
|
+
lookupComponent
|
|
787
|
+
})), /* @__PURE__ */ React9.createElement(IconButton3, {
|
|
703
788
|
icon: "ph--trash--regular",
|
|
704
789
|
iconOnly: true,
|
|
705
790
|
label: t("button remove"),
|
|
706
|
-
onClick: () =>
|
|
707
|
-
|
|
708
|
-
inputProps.onValueChange(name, type, newValues);
|
|
709
|
-
}
|
|
710
|
-
})))), /* @__PURE__ */ React6.createElement("div", {
|
|
791
|
+
onClick: () => handleRemove(index)
|
|
792
|
+
})))), /* @__PURE__ */ React9.createElement("div", {
|
|
711
793
|
role: "none",
|
|
712
794
|
className: "flex justify-between items-center plb-1"
|
|
713
|
-
}, /* @__PURE__ */
|
|
795
|
+
}, /* @__PURE__ */ React9.createElement(IconButton3, {
|
|
714
796
|
icon: "ph--plus--regular",
|
|
715
797
|
iconOnly: true,
|
|
716
798
|
label: t("button add"),
|
|
717
|
-
onClick:
|
|
718
|
-
const newValues = [
|
|
719
|
-
...arrayValues,
|
|
720
|
-
SimpleType.getDefaultValue(type)
|
|
721
|
-
];
|
|
722
|
-
inputProps.onValueChange(name, type, newValues);
|
|
723
|
-
}
|
|
799
|
+
onClick: handleAdd
|
|
724
800
|
})));
|
|
725
801
|
};
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
802
|
+
|
|
803
|
+
// packages/ui/react-ui-form/src/components/Form/factory.tsx
|
|
804
|
+
import { FormatEnum } from "@dxos/echo-schema";
|
|
805
|
+
var getInputComponent = (type, format) => {
|
|
806
|
+
switch (format) {
|
|
807
|
+
case FormatEnum.LatLng:
|
|
808
|
+
return GeoPointInput;
|
|
809
|
+
}
|
|
810
|
+
switch (type) {
|
|
811
|
+
case "string":
|
|
812
|
+
return TextInput;
|
|
813
|
+
case "number":
|
|
814
|
+
return NumberInput;
|
|
815
|
+
case "boolean":
|
|
816
|
+
return BooleanInput;
|
|
817
|
+
}
|
|
818
|
+
};
|
|
819
|
+
|
|
820
|
+
// packages/ui/react-ui-form/src/components/Form/FormContent.tsx
|
|
821
|
+
var FormField = ({ property, path, readonly, inline, lookupComponent, Custom }) => {
|
|
822
|
+
const inputProps = useInputProps(path);
|
|
823
|
+
const { ast, name, type, format, title, description, options, examples, array } = property;
|
|
824
|
+
const label = useMemo3(() => title ?? pipe2(name, capitalize2), [
|
|
825
|
+
title,
|
|
826
|
+
name
|
|
827
|
+
]);
|
|
828
|
+
const placeholder = useMemo3(() => examples?.length ? `Example: "${examples[0]}"` : description, [
|
|
829
|
+
examples,
|
|
830
|
+
description
|
|
831
|
+
]);
|
|
832
|
+
const FoundComponent = lookupComponent?.({
|
|
833
|
+
prop: name,
|
|
834
|
+
schema: S.make(ast),
|
|
835
|
+
inputProps: {
|
|
836
|
+
type,
|
|
837
|
+
format,
|
|
838
|
+
label,
|
|
839
|
+
disabled: readonly,
|
|
840
|
+
placeholder,
|
|
841
|
+
...inputProps
|
|
842
|
+
}
|
|
843
|
+
});
|
|
844
|
+
if (FoundComponent) {
|
|
845
|
+
return /* @__PURE__ */ React10.createElement("div", {
|
|
846
|
+
role: "none"
|
|
847
|
+
}, FoundComponent);
|
|
848
|
+
}
|
|
849
|
+
const jsonPath = createJsonPath3(path ?? []);
|
|
850
|
+
const CustomComponent = Custom?.[jsonPath];
|
|
851
|
+
if (CustomComponent) {
|
|
852
|
+
return (
|
|
853
|
+
// TODO(ZaymonFC): We should try to remove this div wrapper.
|
|
854
|
+
/* @__PURE__ */ React10.createElement("div", {
|
|
855
|
+
role: "none"
|
|
856
|
+
}, /* @__PURE__ */ React10.createElement(CustomComponent, {
|
|
857
|
+
type,
|
|
858
|
+
format,
|
|
859
|
+
label,
|
|
860
|
+
inputOnly: inline,
|
|
861
|
+
placeholder,
|
|
862
|
+
disabled: readonly,
|
|
863
|
+
...inputProps
|
|
864
|
+
}))
|
|
865
|
+
);
|
|
866
|
+
}
|
|
867
|
+
if (array) {
|
|
868
|
+
return /* @__PURE__ */ React10.createElement(ArrayField, {
|
|
869
|
+
property,
|
|
870
|
+
path,
|
|
871
|
+
inputProps,
|
|
872
|
+
readonly,
|
|
873
|
+
Custom
|
|
874
|
+
});
|
|
875
|
+
}
|
|
876
|
+
const InputComponent = getInputComponent(type, format);
|
|
877
|
+
if (InputComponent) {
|
|
878
|
+
return /* @__PURE__ */ React10.createElement("div", {
|
|
879
|
+
role: "none"
|
|
880
|
+
}, /* @__PURE__ */ React10.createElement(InputComponent, {
|
|
881
|
+
type,
|
|
882
|
+
format,
|
|
883
|
+
label,
|
|
884
|
+
inputOnly: inline,
|
|
885
|
+
placeholder,
|
|
886
|
+
disabled: readonly,
|
|
887
|
+
...inputProps
|
|
888
|
+
}));
|
|
889
|
+
}
|
|
890
|
+
if (options) {
|
|
891
|
+
return /* @__PURE__ */ React10.createElement("div", {
|
|
892
|
+
role: "none"
|
|
893
|
+
}, /* @__PURE__ */ React10.createElement(SelectInput, {
|
|
894
|
+
type,
|
|
895
|
+
format,
|
|
896
|
+
disabled: readonly,
|
|
897
|
+
inputOnly: inline,
|
|
898
|
+
label,
|
|
899
|
+
options: options.map((option) => ({
|
|
900
|
+
value: option,
|
|
901
|
+
label: String(option)
|
|
902
|
+
})),
|
|
903
|
+
placeholder,
|
|
904
|
+
...inputProps
|
|
905
|
+
}));
|
|
906
|
+
}
|
|
907
|
+
if (type === "object") {
|
|
908
|
+
const baseNode = findNode2(ast, isDiscriminatedUnion2);
|
|
909
|
+
const typeLiteral = baseNode ? getDiscriminatedType2(baseNode, inputProps.getValue()) : findNode2(ast, AST2.isTypeLiteral);
|
|
910
|
+
if (typeLiteral) {
|
|
911
|
+
return /* @__PURE__ */ React10.createElement("div", {
|
|
912
|
+
role: "none"
|
|
913
|
+
}, !inline && /* @__PURE__ */ React10.createElement("div", null, label), /* @__PURE__ */ React10.createElement(FormFields, {
|
|
914
|
+
schema: S.make(typeLiteral),
|
|
915
|
+
path,
|
|
916
|
+
readonly,
|
|
917
|
+
Custom
|
|
918
|
+
}));
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
return null;
|
|
922
|
+
};
|
|
923
|
+
var FormFields = ({ schema, path, filter, sort, readonly, lookupComponent, Custom }) => {
|
|
924
|
+
const values = useFormValues(path);
|
|
925
|
+
const properties = useMemo3(() => {
|
|
926
|
+
const props = getSchemaProperties2(schema.ast, values);
|
|
927
|
+
const filtered = filter ? filter(props) : props;
|
|
928
|
+
return sort ? filtered.sort((a, b) => sort.indexOf(a.name) - sort.indexOf(b.name)) : filtered;
|
|
929
|
+
}, [
|
|
930
|
+
schema,
|
|
931
|
+
values,
|
|
932
|
+
filter,
|
|
933
|
+
sort
|
|
934
|
+
]);
|
|
935
|
+
return /* @__PURE__ */ React10.createElement("div", {
|
|
936
|
+
role: "form",
|
|
937
|
+
className: mx6("flex flex-col w-full gap-2 py-2")
|
|
938
|
+
}, properties.map((property) => {
|
|
939
|
+
return /* @__PURE__ */ React10.createElement(FormField, {
|
|
940
|
+
key: property.name,
|
|
941
|
+
property,
|
|
942
|
+
path: [
|
|
943
|
+
...path ?? [],
|
|
944
|
+
property.name
|
|
945
|
+
],
|
|
946
|
+
readonly,
|
|
947
|
+
lookupComponent,
|
|
948
|
+
Custom
|
|
949
|
+
});
|
|
950
|
+
}).filter(isNotFalsy));
|
|
951
|
+
};
|
|
952
|
+
|
|
953
|
+
// packages/ui/react-ui-form/src/components/Form/Form.tsx
|
|
954
|
+
var Form = ({ classNames, schema, values: initialValues, path = [], readonly, filter, sort, autoSave, testId, onValuesChanged, onValidate, onSave, onCancel, lookupComponent, Custom }) => {
|
|
955
|
+
const onValid = useMemo4(() => autoSave ? onSave : void 0, [
|
|
956
|
+
autoSave,
|
|
957
|
+
onSave
|
|
958
|
+
]);
|
|
959
|
+
return /* @__PURE__ */ React11.createElement(FormProvider, {
|
|
960
|
+
schema,
|
|
961
|
+
initialValues,
|
|
962
|
+
onValuesChanged,
|
|
963
|
+
onValidate,
|
|
964
|
+
onValid,
|
|
965
|
+
onSave
|
|
966
|
+
}, /* @__PURE__ */ React11.createElement("div", {
|
|
732
967
|
role: "none",
|
|
733
|
-
className:
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
968
|
+
className: mx7("p-2", classNames),
|
|
969
|
+
"data-testid": testId
|
|
970
|
+
}, /* @__PURE__ */ React11.createElement(FormFields, {
|
|
971
|
+
schema,
|
|
972
|
+
path,
|
|
973
|
+
readonly,
|
|
974
|
+
filter,
|
|
975
|
+
sort,
|
|
976
|
+
lookupComponent,
|
|
977
|
+
Custom
|
|
978
|
+
}), (onCancel || onSave) && !autoSave && /* @__PURE__ */ React11.createElement(FormActions, {
|
|
979
|
+
onCancel,
|
|
980
|
+
readonly
|
|
746
981
|
})));
|
|
747
982
|
};
|
|
748
983
|
|
|
749
984
|
// packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx
|
|
750
985
|
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx";
|
|
751
986
|
var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
752
|
-
const { t } =
|
|
753
|
-
const [props, setProps] =
|
|
987
|
+
const { t } = useTranslation5(translationKey);
|
|
988
|
+
const [props, setProps] = useState3(projection.getFieldProjection(field.id).props);
|
|
754
989
|
useEffect3(() => setProps(projection.getFieldProjection(field.id).props), [
|
|
755
990
|
field,
|
|
756
991
|
projection
|
|
757
992
|
]);
|
|
758
|
-
const [schemas, setSchemas] =
|
|
993
|
+
const [schemas, setSchemas] = useState3([]);
|
|
759
994
|
useEffect3(() => {
|
|
760
995
|
if (!registry) {
|
|
761
996
|
return;
|
|
@@ -774,17 +1009,17 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
774
1009
|
}, [
|
|
775
1010
|
registry
|
|
776
1011
|
]);
|
|
777
|
-
const [referenceSchema, setReferenceSchema] =
|
|
1012
|
+
const [referenceSchema, setReferenceSchema] = useState3();
|
|
778
1013
|
useEffect3(() => {
|
|
779
1014
|
setReferenceSchema(schemas.find((schema) => schema.typename === props?.referenceSchema));
|
|
780
1015
|
}, [
|
|
781
1016
|
schemas,
|
|
782
1017
|
props?.referenceSchema
|
|
783
1018
|
]);
|
|
784
|
-
const [{ fieldSchema }, setFieldSchema] =
|
|
1019
|
+
const [{ fieldSchema }, setFieldSchema] = useState3({
|
|
785
1020
|
fieldSchema: getFormatSchema(props?.format)
|
|
786
1021
|
});
|
|
787
|
-
const handleValuesChanged =
|
|
1022
|
+
const handleValuesChanged = useCallback4((_props) => {
|
|
788
1023
|
setFieldSchema((prev) => {
|
|
789
1024
|
const fieldSchema2 = getFormatSchema(_props.format);
|
|
790
1025
|
if (prev.fieldSchema === fieldSchema2) {
|
|
@@ -812,14 +1047,14 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
812
1047
|
type
|
|
813
1048
|
};
|
|
814
1049
|
}
|
|
815
|
-
return
|
|
1050
|
+
return _props;
|
|
816
1051
|
});
|
|
817
1052
|
}, [
|
|
818
1053
|
schemas,
|
|
819
1054
|
props.format,
|
|
820
1055
|
props.referenceSchema
|
|
821
1056
|
]);
|
|
822
|
-
const handleValidate =
|
|
1057
|
+
const handleValidate = useCallback4(({ property }) => {
|
|
823
1058
|
if (property && view.fields.find((f) => f.path === property && f.path !== field.path)) {
|
|
824
1059
|
return [
|
|
825
1060
|
{
|
|
@@ -832,7 +1067,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
832
1067
|
view.fields,
|
|
833
1068
|
field
|
|
834
1069
|
]);
|
|
835
|
-
const handleSave =
|
|
1070
|
+
const handleSave = useCallback4((props2) => {
|
|
836
1071
|
projection.setFieldProjection({
|
|
837
1072
|
field,
|
|
838
1073
|
props: props2
|
|
@@ -843,50 +1078,51 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
843
1078
|
field,
|
|
844
1079
|
onSave
|
|
845
1080
|
]);
|
|
846
|
-
const handleCancel =
|
|
1081
|
+
const handleCancel = useCallback4(() => {
|
|
847
1082
|
requestAnimationFrame(() => onCancel?.());
|
|
848
1083
|
onSave();
|
|
849
1084
|
}, [
|
|
850
1085
|
onSave
|
|
851
1086
|
]);
|
|
852
|
-
const Custom =
|
|
853
|
-
["format"]: (props2) => /* @__PURE__ */
|
|
1087
|
+
const Custom = useMemo5(() => ({
|
|
1088
|
+
["format"]: (props2) => /* @__PURE__ */ React12.createElement(SelectInput, {
|
|
854
1089
|
...props2,
|
|
855
1090
|
options: FormatEnums.filter((value) => value !== FormatEnum2.None).map((value) => ({
|
|
856
1091
|
value,
|
|
857
1092
|
label: t(`format ${value}`)
|
|
858
1093
|
}))
|
|
859
1094
|
}),
|
|
860
|
-
["referenceSchema"]: (props2) => /* @__PURE__ */
|
|
1095
|
+
["referenceSchema"]: (props2) => /* @__PURE__ */ React12.createElement(SelectInput, {
|
|
861
1096
|
...props2,
|
|
862
1097
|
options: schemas.map((schema) => ({
|
|
863
1098
|
value: schema.typename
|
|
864
1099
|
}))
|
|
865
1100
|
}),
|
|
866
|
-
["referencePath"]: (props2) => /* @__PURE__ */
|
|
1101
|
+
["referencePath"]: (props2) => /* @__PURE__ */ React12.createElement(SelectInput, {
|
|
867
1102
|
...props2,
|
|
868
|
-
options: referenceSchema ?
|
|
1103
|
+
options: referenceSchema ? getSchemaProperties3(referenceSchema.ast).sort(sortProperties).map((p) => ({
|
|
869
1104
|
value: p.name
|
|
870
1105
|
})) : []
|
|
871
|
-
})
|
|
1106
|
+
}),
|
|
1107
|
+
["options"]: (props2) => /* @__PURE__ */ React12.createElement(SelectOptionInput, props2)
|
|
872
1108
|
}), [
|
|
873
1109
|
t,
|
|
874
1110
|
schemas,
|
|
875
1111
|
referenceSchema
|
|
876
1112
|
]);
|
|
877
|
-
const propIsNotType =
|
|
1113
|
+
const propIsNotType = useCallback4((props2) => props2.filter((p) => p.name !== "type"), []);
|
|
878
1114
|
if (!fieldSchema) {
|
|
879
|
-
|
|
1115
|
+
log2.warn("invalid format", {
|
|
880
1116
|
props
|
|
881
1117
|
}, {
|
|
882
1118
|
F: __dxlog_file3,
|
|
883
|
-
L:
|
|
1119
|
+
L: 174,
|
|
884
1120
|
S: void 0,
|
|
885
1121
|
C: (f, a) => f(...a)
|
|
886
1122
|
});
|
|
887
1123
|
return null;
|
|
888
1124
|
}
|
|
889
|
-
return /* @__PURE__ */
|
|
1125
|
+
return /* @__PURE__ */ React12.createElement(Form, {
|
|
890
1126
|
key: field.id,
|
|
891
1127
|
autoFocus: true,
|
|
892
1128
|
values: props,
|
|
@@ -905,30 +1141,29 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
905
1141
|
};
|
|
906
1142
|
|
|
907
1143
|
// packages/ui/react-ui-form/src/components/ViewEditor/ViewEditor.tsx
|
|
908
|
-
import
|
|
909
|
-
import { AST as
|
|
910
|
-
import { IconButton as
|
|
911
|
-
import { List } from "@dxos/react-ui-list";
|
|
912
|
-
import { ghostHover, inputTextLabel, mx as
|
|
1144
|
+
import React13, { useCallback as useCallback5, useMemo as useMemo6, useState as useState4 } from "react";
|
|
1145
|
+
import { AST as AST3, Format, S as S2 } from "@dxos/echo-schema";
|
|
1146
|
+
import { IconButton as IconButton4, useTranslation as useTranslation6 } from "@dxos/react-ui";
|
|
1147
|
+
import { List as List2 } from "@dxos/react-ui-list";
|
|
1148
|
+
import { ghostHover, inputTextLabel, mx as mx8 } from "@dxos/react-ui-theme";
|
|
913
1149
|
import { FieldSchema, ViewProjection, VIEW_FIELD_LIMIT } from "@dxos/schema";
|
|
914
|
-
import { arrayMove } from "@dxos/util";
|
|
915
1150
|
var grid = "grid grid-cols-[32px_1fr_32px] min-bs-[2.5rem]";
|
|
916
1151
|
var ViewMetaSchema = S2.Struct({
|
|
917
1152
|
name: S2.String.annotations({
|
|
918
|
-
[
|
|
1153
|
+
[AST3.TitleAnnotationId]: "View"
|
|
919
1154
|
}),
|
|
920
1155
|
typename: Format.DXN.annotations({
|
|
921
|
-
[
|
|
1156
|
+
[AST3.TitleAnnotationId]: "Typename"
|
|
922
1157
|
})
|
|
923
1158
|
}).pipe(S2.mutable);
|
|
924
1159
|
var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading = false, onTypenameChanged, onDelete }) => {
|
|
925
|
-
const { t } =
|
|
926
|
-
const projection =
|
|
1160
|
+
const { t } = useTranslation6(translationKey);
|
|
1161
|
+
const projection = useMemo6(() => new ViewProjection(schema, view), [
|
|
927
1162
|
schema,
|
|
928
1163
|
view
|
|
929
1164
|
]);
|
|
930
|
-
const [field, setField] =
|
|
931
|
-
const viewValues =
|
|
1165
|
+
const [field, setField] = useState4();
|
|
1166
|
+
const viewValues = useMemo6(() => {
|
|
932
1167
|
return {
|
|
933
1168
|
name: view.name,
|
|
934
1169
|
// TODO(burdon): Need to warn user of possible consequences of editing.
|
|
@@ -938,7 +1173,7 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
|
|
|
938
1173
|
}, [
|
|
939
1174
|
view
|
|
940
1175
|
]);
|
|
941
|
-
const handleViewUpdate =
|
|
1176
|
+
const handleViewUpdate = useCallback5(({ name, typename }) => {
|
|
942
1177
|
requestAnimationFrame(() => {
|
|
943
1178
|
if (view.name !== name) {
|
|
944
1179
|
view.name = name;
|
|
@@ -952,67 +1187,72 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
|
|
|
952
1187
|
schema,
|
|
953
1188
|
onTypenameChanged
|
|
954
1189
|
]);
|
|
955
|
-
const handleSelect =
|
|
1190
|
+
const handleSelect = useCallback5((field2) => {
|
|
956
1191
|
setField((f) => f === field2 ? void 0 : field2);
|
|
957
1192
|
}, []);
|
|
958
|
-
const handleAdd =
|
|
1193
|
+
const handleAdd = useCallback5(() => {
|
|
959
1194
|
const field2 = projection.createFieldProjection();
|
|
960
1195
|
setField(field2);
|
|
961
1196
|
}, [
|
|
962
1197
|
view
|
|
963
1198
|
]);
|
|
964
|
-
const handleMove =
|
|
965
|
-
|
|
1199
|
+
const handleMove = useCallback5((fromIndex, toIndex) => {
|
|
1200
|
+
const fields = [
|
|
1201
|
+
...view.fields
|
|
1202
|
+
];
|
|
1203
|
+
const [moved] = fields.splice(fromIndex, 1);
|
|
1204
|
+
fields.splice(toIndex, 0, moved);
|
|
1205
|
+
view.fields = fields;
|
|
966
1206
|
}, [
|
|
967
1207
|
view.fields
|
|
968
1208
|
]);
|
|
969
|
-
const handleClose =
|
|
970
|
-
return /* @__PURE__ */
|
|
1209
|
+
const handleClose = useCallback5(() => setField(void 0), []);
|
|
1210
|
+
return /* @__PURE__ */ React13.createElement("div", {
|
|
971
1211
|
role: "none",
|
|
972
|
-
className:
|
|
973
|
-
}, /* @__PURE__ */
|
|
1212
|
+
className: mx8("flex flex-col w-full divide-y divide-separator", classNames)
|
|
1213
|
+
}, /* @__PURE__ */ React13.createElement(Form, {
|
|
974
1214
|
autoFocus: true,
|
|
975
1215
|
autoSave: true,
|
|
976
1216
|
schema: ViewMetaSchema,
|
|
977
1217
|
values: viewValues,
|
|
978
1218
|
onSave: handleViewUpdate
|
|
979
|
-
}), /* @__PURE__ */
|
|
1219
|
+
}), /* @__PURE__ */ React13.createElement("div", null, /* @__PURE__ */ React13.createElement("div", {
|
|
980
1220
|
role: "none",
|
|
981
1221
|
className: "p-2"
|
|
982
|
-
}, /* @__PURE__ */
|
|
983
|
-
className:
|
|
984
|
-
}, t("fields label"))), /* @__PURE__ */
|
|
1222
|
+
}, /* @__PURE__ */ React13.createElement("label", {
|
|
1223
|
+
className: mx8(inputTextLabel)
|
|
1224
|
+
}, t("fields label"))), /* @__PURE__ */ React13.createElement(List2.Root, {
|
|
985
1225
|
items: view.fields,
|
|
986
1226
|
isItem: S2.is(FieldSchema),
|
|
987
1227
|
getId: (field2) => field2.id,
|
|
988
1228
|
onMove: handleMove
|
|
989
|
-
}, ({ items: fields }) => /* @__PURE__ */
|
|
1229
|
+
}, ({ items: fields }) => /* @__PURE__ */ React13.createElement(React13.Fragment, null, showHeading && /* @__PURE__ */ React13.createElement("div", {
|
|
990
1230
|
role: "heading",
|
|
991
1231
|
className: grid
|
|
992
|
-
}, /* @__PURE__ */
|
|
1232
|
+
}, /* @__PURE__ */ React13.createElement("div", null), /* @__PURE__ */ React13.createElement("div", {
|
|
993
1233
|
className: "flex items-center text-sm"
|
|
994
|
-
}, t("field path label"))), /* @__PURE__ */
|
|
1234
|
+
}, t("field path label"))), /* @__PURE__ */ React13.createElement("div", {
|
|
995
1235
|
role: "list",
|
|
996
1236
|
className: "flex flex-col w-full"
|
|
997
|
-
}, fields?.map((field2) => /* @__PURE__ */
|
|
1237
|
+
}, fields?.map((field2) => /* @__PURE__ */ React13.createElement(List2.Item, {
|
|
998
1238
|
key: field2.id,
|
|
999
1239
|
item: field2,
|
|
1000
|
-
classNames:
|
|
1001
|
-
}, /* @__PURE__ */
|
|
1240
|
+
classNames: mx8(grid, ghostHover, "cursor-pointer")
|
|
1241
|
+
}, /* @__PURE__ */ React13.createElement(List2.ItemDragHandle, null), /* @__PURE__ */ React13.createElement(List2.ItemTitle, {
|
|
1002
1242
|
onClick: () => handleSelect(field2)
|
|
1003
|
-
}, field2.path), /* @__PURE__ */
|
|
1243
|
+
}, field2.path), /* @__PURE__ */ React13.createElement(List2.ItemDeleteButton, {
|
|
1004
1244
|
disabled: view.fields.length <= 1,
|
|
1005
1245
|
onClick: () => onDelete(field2.id)
|
|
1006
|
-
}))))))), field && /* @__PURE__ */
|
|
1246
|
+
}))))))), field && /* @__PURE__ */ React13.createElement(FieldEditor, {
|
|
1007
1247
|
key: field.id,
|
|
1008
1248
|
view,
|
|
1009
1249
|
projection,
|
|
1010
1250
|
field,
|
|
1011
1251
|
registry,
|
|
1012
1252
|
onSave: handleClose
|
|
1013
|
-
}), !readonly && !field && /* @__PURE__ */
|
|
1253
|
+
}), !readonly && !field && /* @__PURE__ */ React13.createElement("div", {
|
|
1014
1254
|
className: "flex p-2 justify-center"
|
|
1015
|
-
}, /* @__PURE__ */
|
|
1255
|
+
}, /* @__PURE__ */ React13.createElement(IconButton4, {
|
|
1016
1256
|
icon: "ph--plus--regular",
|
|
1017
1257
|
label: t("button add property"),
|
|
1018
1258
|
onClick: handleAdd,
|
|
@@ -1242,14 +1482,15 @@ var formatForEditing = ({ type, format, value, locale = void 0 }) => {
|
|
|
1242
1482
|
};
|
|
1243
1483
|
export {
|
|
1244
1484
|
BooleanInput,
|
|
1485
|
+
DeprecatedFormContainer,
|
|
1245
1486
|
DeprecatedFormInput,
|
|
1246
1487
|
FieldEditor,
|
|
1247
1488
|
Form,
|
|
1248
|
-
FormActions,
|
|
1249
1489
|
GeoPointInput,
|
|
1250
1490
|
InputHeader,
|
|
1251
1491
|
NumberInput,
|
|
1252
1492
|
SelectInput,
|
|
1493
|
+
SelectOptionInput,
|
|
1253
1494
|
TextInput,
|
|
1254
1495
|
TupleInput,
|
|
1255
1496
|
ViewEditor,
|