@dxos/react-ui-form 0.7.5-main.9d26e3a → 0.7.5-main.e9bb01b
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/browser/index.mjs +743 -466
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +777 -515
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +743 -466
- 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 +13 -16
- 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 +2 -1
- package/dist/types/src/components/ViewEditor/ViewEditor.d.ts.map +1 -1
- package/dist/types/src/components/ViewEditor/ViewEditor.stories.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/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +25 -24
- package/src/components/FieldEditor/FieldEditor.stories.tsx +1 -1
- package/src/components/FieldEditor/FieldEditor.tsx +58 -40
- 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 +39 -330
- 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.stories.tsx +25 -4
- package/src/components/ViewEditor/ViewEditor.tsx +14 -6
- 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,317 +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: 99,
|
|
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
|
-
let InputComponent = Custom?.[key.join(".")];
|
|
491
|
-
if (!InputComponent) {
|
|
492
|
-
if (options) {
|
|
493
|
-
return /* @__PURE__ */ React6.createElement("div", {
|
|
494
|
-
key: name,
|
|
495
|
-
role: "none",
|
|
496
|
-
className: padding
|
|
497
|
-
}, /* @__PURE__ */ React6.createElement(SelectInput, {
|
|
498
|
-
type,
|
|
499
|
-
format,
|
|
500
|
-
property: name,
|
|
501
|
-
disabled: readonly,
|
|
502
|
-
label,
|
|
503
|
-
options: options.map((option) => ({
|
|
504
|
-
value: option,
|
|
505
|
-
label: String(option)
|
|
506
|
-
})),
|
|
507
|
-
placeholder,
|
|
508
|
-
...inputProps
|
|
509
|
-
}));
|
|
510
|
-
}
|
|
511
|
-
InputComponent = getInputComponent(type, format);
|
|
512
|
-
if (array) {
|
|
513
|
-
return /* @__PURE__ */ React6.createElement(ArrayField, {
|
|
514
|
-
key: name,
|
|
515
|
-
name,
|
|
516
|
-
type,
|
|
517
|
-
array: true,
|
|
518
|
-
label,
|
|
519
|
-
ast,
|
|
520
|
-
values,
|
|
521
|
-
format,
|
|
522
|
-
readonly,
|
|
523
|
-
placeholder,
|
|
524
|
-
inputProps,
|
|
525
|
-
Custom
|
|
526
|
-
});
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
if (!InputComponent) {
|
|
530
|
-
if (type === "object") {
|
|
531
|
-
const baseNode = findNode(ast, isDiscriminatedUnion);
|
|
532
|
-
const typeLiteral = baseNode ? getDiscriminatedType(baseNode, values[name]) : findNode(ast, AST.isTypeLiteral);
|
|
533
|
-
if (typeLiteral) {
|
|
534
|
-
const schema2 = S.make(typeLiteral);
|
|
535
|
-
return /* @__PURE__ */ React6.createElement("div", {
|
|
536
|
-
key: name,
|
|
537
|
-
role: "none"
|
|
538
|
-
}, /* @__PURE__ */ React6.createElement("div", {
|
|
539
|
-
className: padding
|
|
540
|
-
}, label), /* @__PURE__ */ React6.createElement(Form, {
|
|
541
|
-
schema: schema2,
|
|
542
|
-
path: key,
|
|
543
|
-
values: values[name] ?? {},
|
|
544
|
-
onValuesChanged: (childValues) => {
|
|
545
|
-
inputProps.onValueChange(name, "object", childValues);
|
|
546
|
-
},
|
|
547
|
-
Custom
|
|
548
|
-
}));
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
log2("no renderer for property", {
|
|
552
|
-
name,
|
|
553
|
-
type
|
|
554
|
-
}, {
|
|
555
|
-
F: __dxlog_file2,
|
|
556
|
-
L: 184,
|
|
557
|
-
S: void 0,
|
|
558
|
-
C: (f, a) => f(...a)
|
|
559
|
-
});
|
|
560
|
-
return null;
|
|
561
|
-
}
|
|
562
|
-
return /* @__PURE__ */ React6.createElement("div", {
|
|
563
|
-
key: name,
|
|
564
|
-
role: "none",
|
|
565
|
-
className: padding
|
|
566
|
-
}, /* @__PURE__ */ React6.createElement(InputComponent, {
|
|
567
|
-
type,
|
|
568
|
-
format,
|
|
569
|
-
property: name,
|
|
570
|
-
disabled: readonly,
|
|
571
|
-
label,
|
|
572
|
-
placeholder,
|
|
573
|
-
...inputProps
|
|
574
|
-
}));
|
|
575
|
-
}).filter(isNotFalsy), (onCancel || onSave) && !autoSave && /* @__PURE__ */ React6.createElement(FormActions, {
|
|
576
|
-
onCancel,
|
|
577
|
-
onSubmit: handleSave,
|
|
578
|
-
canSubmit: canSave,
|
|
579
|
-
readonly
|
|
580
|
-
}));
|
|
581
|
-
};
|
|
582
|
-
var ArrayField = ({ name, type, label, ast, values, format, readonly, placeholder, inputProps, Custom }) => {
|
|
583
|
-
const { t } = useTranslation2(translationKey);
|
|
584
|
-
const arrayValues = values[name] ?? [];
|
|
585
|
-
const key = [
|
|
586
|
-
name
|
|
587
|
-
];
|
|
588
|
-
const tupleType = findNode(ast, AST.isTupleType);
|
|
589
|
-
const elementType = tupleType?.rest[0]?.type;
|
|
590
|
-
if (type === "object" && elementType) {
|
|
591
|
-
const baseNode = findNode(elementType, isDiscriminatedUnion);
|
|
592
|
-
const typeLiteral = baseNode ? getDiscriminatedType(baseNode, values[name]) : findNode(elementType, AST.isTypeLiteral);
|
|
593
|
-
if (typeLiteral) {
|
|
594
|
-
const schema = S.make(typeLiteral);
|
|
595
|
-
return /* @__PURE__ */ React6.createElement("div", {
|
|
596
|
-
key: name,
|
|
597
|
-
role: "none",
|
|
598
|
-
className: mx2(padding)
|
|
599
|
-
}, /* @__PURE__ */ React6.createElement(InputHeader, null, label), /* @__PURE__ */ React6.createElement("div", {
|
|
600
|
-
role: "none",
|
|
601
|
-
className: "flex flex-col gap-1"
|
|
602
|
-
}, arrayValues.map((value, index) => {
|
|
603
|
-
return /* @__PURE__ */ React6.createElement("div", {
|
|
604
|
-
key: index,
|
|
605
|
-
role: "none",
|
|
606
|
-
className: "flex items-center gap-1"
|
|
607
|
-
}, /* @__PURE__ */ React6.createElement("div", {
|
|
608
|
-
role: "none",
|
|
609
|
-
className: "flex-1"
|
|
610
|
-
}, /* @__PURE__ */ React6.createElement(Form, {
|
|
611
|
-
schema,
|
|
612
|
-
path: [
|
|
613
|
-
...key,
|
|
614
|
-
`[${index}]`
|
|
615
|
-
],
|
|
616
|
-
values: value,
|
|
617
|
-
onValuesChanged: (childValues) => {
|
|
618
|
-
const newValues = [
|
|
619
|
-
...arrayValues
|
|
620
|
-
];
|
|
621
|
-
newValues[index] = childValues;
|
|
622
|
-
inputProps.onValueChange(name, "object", newValues);
|
|
623
|
-
},
|
|
624
|
-
Custom
|
|
625
|
-
})), /* @__PURE__ */ React6.createElement(IconButton, {
|
|
626
|
-
icon: "ph--trash--regular",
|
|
627
|
-
iconOnly: true,
|
|
628
|
-
label: t("button remove"),
|
|
629
|
-
onClick: () => {
|
|
630
|
-
const newValues = arrayValues.filter((_, i) => i !== index);
|
|
631
|
-
inputProps.onValueChange(name, type, newValues);
|
|
632
|
-
}
|
|
633
|
-
}));
|
|
634
|
-
})), /* @__PURE__ */ React6.createElement("div", {
|
|
635
|
-
role: "none",
|
|
636
|
-
className: "flex justify-between items-center plb-1"
|
|
637
|
-
}, /* @__PURE__ */ React6.createElement(IconButton, {
|
|
638
|
-
icon: "ph--plus--regular",
|
|
639
|
-
iconOnly: true,
|
|
640
|
-
label: t("button add"),
|
|
641
|
-
onClick: () => {
|
|
642
|
-
const newValues = [
|
|
643
|
-
...arrayValues,
|
|
644
|
-
{}
|
|
645
|
-
];
|
|
646
|
-
inputProps.onValueChange(name, type, newValues);
|
|
647
|
-
}
|
|
648
|
-
})));
|
|
649
|
-
}
|
|
650
|
-
return /* @__PURE__ */ React6.createElement("div", {
|
|
651
|
-
key: name,
|
|
652
|
-
role: "none"
|
|
653
|
-
}, "Nested form not supported in arrays, yet.");
|
|
654
|
-
}
|
|
655
|
-
const InputComponent = getInputComponent(type, format);
|
|
656
|
-
if (!InputComponent) {
|
|
757
|
+
if (!elementType) {
|
|
657
758
|
return null;
|
|
658
759
|
}
|
|
659
|
-
return /* @__PURE__ */
|
|
760
|
+
return /* @__PURE__ */ React9.createElement("div", {
|
|
660
761
|
role: "none",
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
}, /* @__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", {
|
|
664
764
|
role: "none",
|
|
665
765
|
className: "flex flex-col gap-1"
|
|
666
|
-
},
|
|
766
|
+
}, values.map((_value, index) => /* @__PURE__ */ React9.createElement("div", {
|
|
667
767
|
key: index,
|
|
668
768
|
role: "none",
|
|
669
|
-
className: "flex items-
|
|
670
|
-
}, /* @__PURE__ */
|
|
769
|
+
className: "flex items-center gap-1"
|
|
770
|
+
}, /* @__PURE__ */ React9.createElement("div", {
|
|
671
771
|
role: "none",
|
|
672
772
|
className: "flex-1"
|
|
673
|
-
}, /* @__PURE__ */
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
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, {
|
|
683
788
|
icon: "ph--trash--regular",
|
|
684
789
|
iconOnly: true,
|
|
685
790
|
label: t("button remove"),
|
|
686
|
-
onClick: () =>
|
|
687
|
-
|
|
688
|
-
inputProps.onValueChange(name, type, newValues);
|
|
689
|
-
}
|
|
690
|
-
})))), /* @__PURE__ */ React6.createElement("div", {
|
|
791
|
+
onClick: () => handleRemove(index)
|
|
792
|
+
})))), /* @__PURE__ */ React9.createElement("div", {
|
|
691
793
|
role: "none",
|
|
692
794
|
className: "flex justify-between items-center plb-1"
|
|
693
|
-
}, /* @__PURE__ */
|
|
795
|
+
}, /* @__PURE__ */ React9.createElement(IconButton3, {
|
|
694
796
|
icon: "ph--plus--regular",
|
|
695
797
|
iconOnly: true,
|
|
696
798
|
label: t("button add"),
|
|
697
|
-
onClick:
|
|
698
|
-
const newValues = [
|
|
699
|
-
...arrayValues,
|
|
700
|
-
SimpleType.getDefaultValue(type)
|
|
701
|
-
];
|
|
702
|
-
inputProps.onValueChange(name, type, newValues);
|
|
703
|
-
}
|
|
799
|
+
onClick: handleAdd
|
|
704
800
|
})));
|
|
705
801
|
};
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
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", {
|
|
712
967
|
role: "none",
|
|
713
|
-
className:
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
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
|
|
726
981
|
})));
|
|
727
982
|
};
|
|
728
983
|
|
|
729
984
|
// packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx
|
|
730
985
|
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx";
|
|
731
986
|
var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
732
|
-
const { t } =
|
|
733
|
-
const [props, setProps] =
|
|
987
|
+
const { t } = useTranslation5(translationKey);
|
|
988
|
+
const [props, setProps] = useState3(projection.getFieldProjection(field.id).props);
|
|
734
989
|
useEffect3(() => setProps(projection.getFieldProjection(field.id).props), [
|
|
735
990
|
field,
|
|
736
991
|
projection
|
|
737
992
|
]);
|
|
738
|
-
const [schemas, setSchemas] =
|
|
993
|
+
const [schemas, setSchemas] = useState3([]);
|
|
739
994
|
useEffect3(() => {
|
|
740
995
|
if (!registry) {
|
|
741
996
|
return;
|
|
@@ -754,17 +1009,17 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
754
1009
|
}, [
|
|
755
1010
|
registry
|
|
756
1011
|
]);
|
|
757
|
-
const [
|
|
1012
|
+
const [referenceSchema, setReferenceSchema] = useState3();
|
|
758
1013
|
useEffect3(() => {
|
|
759
|
-
|
|
1014
|
+
setReferenceSchema(schemas.find((schema) => schema.typename === props?.referenceSchema));
|
|
760
1015
|
}, [
|
|
761
1016
|
schemas,
|
|
762
1017
|
props?.referenceSchema
|
|
763
1018
|
]);
|
|
764
|
-
const [{ fieldSchema }, setFieldSchema] =
|
|
1019
|
+
const [{ fieldSchema }, setFieldSchema] = useState3({
|
|
765
1020
|
fieldSchema: getFormatSchema(props?.format)
|
|
766
1021
|
});
|
|
767
|
-
const handleValuesChanged =
|
|
1022
|
+
const handleValuesChanged = useCallback4((_props) => {
|
|
768
1023
|
setFieldSchema((prev) => {
|
|
769
1024
|
const fieldSchema2 = getFormatSchema(_props.format);
|
|
770
1025
|
if (prev.fieldSchema === fieldSchema2) {
|
|
@@ -774,9 +1029,15 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
774
1029
|
fieldSchema: fieldSchema2
|
|
775
1030
|
};
|
|
776
1031
|
});
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
1032
|
+
setReferenceSchema((prev) => {
|
|
1033
|
+
if (_props.referenceSchema !== prev?.typename) {
|
|
1034
|
+
const newSchema = schemas.find((schema) => schema.typename === _props.referenceSchema);
|
|
1035
|
+
if (newSchema) {
|
|
1036
|
+
return newSchema;
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
return prev;
|
|
1040
|
+
});
|
|
780
1041
|
setProps((props2) => {
|
|
781
1042
|
const type = formatToType[_props.format];
|
|
782
1043
|
if (props2.type !== type) {
|
|
@@ -786,14 +1047,14 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
786
1047
|
type
|
|
787
1048
|
};
|
|
788
1049
|
}
|
|
789
|
-
return
|
|
1050
|
+
return _props;
|
|
790
1051
|
});
|
|
791
1052
|
}, [
|
|
792
1053
|
schemas,
|
|
793
1054
|
props.format,
|
|
794
1055
|
props.referenceSchema
|
|
795
1056
|
]);
|
|
796
|
-
const handleValidate =
|
|
1057
|
+
const handleValidate = useCallback4(({ property }) => {
|
|
797
1058
|
if (property && view.fields.find((f) => f.path === property && f.path !== field.path)) {
|
|
798
1059
|
return [
|
|
799
1060
|
{
|
|
@@ -806,7 +1067,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
806
1067
|
view.fields,
|
|
807
1068
|
field
|
|
808
1069
|
]);
|
|
809
|
-
const handleSave =
|
|
1070
|
+
const handleSave = useCallback4((props2) => {
|
|
810
1071
|
projection.setFieldProjection({
|
|
811
1072
|
field,
|
|
812
1073
|
props: props2
|
|
@@ -817,29 +1078,56 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
817
1078
|
field,
|
|
818
1079
|
onSave
|
|
819
1080
|
]);
|
|
820
|
-
const handleCancel =
|
|
1081
|
+
const handleCancel = useCallback4(() => {
|
|
821
1082
|
requestAnimationFrame(() => onCancel?.());
|
|
822
1083
|
onSave();
|
|
823
1084
|
}, [
|
|
824
1085
|
onSave
|
|
825
1086
|
]);
|
|
1087
|
+
const Custom = useMemo5(() => ({
|
|
1088
|
+
["format"]: (props2) => /* @__PURE__ */ React12.createElement(SelectInput, {
|
|
1089
|
+
...props2,
|
|
1090
|
+
options: FormatEnums.filter((value) => value !== FormatEnum2.None).map((value) => ({
|
|
1091
|
+
value,
|
|
1092
|
+
label: t(`format ${value}`)
|
|
1093
|
+
}))
|
|
1094
|
+
}),
|
|
1095
|
+
["referenceSchema"]: (props2) => /* @__PURE__ */ React12.createElement(SelectInput, {
|
|
1096
|
+
...props2,
|
|
1097
|
+
options: schemas.map((schema) => ({
|
|
1098
|
+
value: schema.typename
|
|
1099
|
+
}))
|
|
1100
|
+
}),
|
|
1101
|
+
["referencePath"]: (props2) => /* @__PURE__ */ React12.createElement(SelectInput, {
|
|
1102
|
+
...props2,
|
|
1103
|
+
options: referenceSchema ? getSchemaProperties3(referenceSchema.ast).sort(sortProperties).map((p) => ({
|
|
1104
|
+
value: p.name
|
|
1105
|
+
})) : []
|
|
1106
|
+
}),
|
|
1107
|
+
["options"]: (props2) => /* @__PURE__ */ React12.createElement(SelectOptionInput, props2)
|
|
1108
|
+
}), [
|
|
1109
|
+
t,
|
|
1110
|
+
schemas,
|
|
1111
|
+
referenceSchema
|
|
1112
|
+
]);
|
|
1113
|
+
const propIsNotType = useCallback4((props2) => props2.filter((p) => p.name !== "type"), []);
|
|
826
1114
|
if (!fieldSchema) {
|
|
827
|
-
|
|
1115
|
+
log2.warn("invalid format", {
|
|
828
1116
|
props
|
|
829
1117
|
}, {
|
|
830
1118
|
F: __dxlog_file3,
|
|
831
|
-
L:
|
|
1119
|
+
L: 174,
|
|
832
1120
|
S: void 0,
|
|
833
1121
|
C: (f, a) => f(...a)
|
|
834
1122
|
});
|
|
835
1123
|
return null;
|
|
836
1124
|
}
|
|
837
|
-
return /* @__PURE__ */
|
|
1125
|
+
return /* @__PURE__ */ React12.createElement(Form, {
|
|
838
1126
|
key: field.id,
|
|
839
1127
|
autoFocus: true,
|
|
840
1128
|
values: props,
|
|
841
1129
|
schema: fieldSchema,
|
|
842
|
-
filter:
|
|
1130
|
+
filter: propIsNotType,
|
|
843
1131
|
sort: [
|
|
844
1132
|
"property",
|
|
845
1133
|
"format"
|
|
@@ -848,55 +1136,34 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
848
1136
|
onValidate: handleValidate,
|
|
849
1137
|
onSave: handleSave,
|
|
850
1138
|
onCancel: handleCancel,
|
|
851
|
-
Custom
|
|
852
|
-
["format"]: (props2) => /* @__PURE__ */ React7.createElement(SelectInput, {
|
|
853
|
-
...props2,
|
|
854
|
-
options: FormatEnums.filter((value) => value !== FormatEnum2.None).map((value) => ({
|
|
855
|
-
value,
|
|
856
|
-
label: t(`format ${value}`)
|
|
857
|
-
}))
|
|
858
|
-
}),
|
|
859
|
-
["referenceSchema"]: (props2) => /* @__PURE__ */ React7.createElement(SelectInput, {
|
|
860
|
-
...props2,
|
|
861
|
-
options: schemas.map((schema2) => ({
|
|
862
|
-
value: schema2.typename
|
|
863
|
-
}))
|
|
864
|
-
}),
|
|
865
|
-
["referencePath"]: (props2) => /* @__PURE__ */ React7.createElement(SelectInput, {
|
|
866
|
-
...props2,
|
|
867
|
-
options: schema ? getSchemaProperties2(schema.ast).sort(sortProperties).map((p) => ({
|
|
868
|
-
value: p.name
|
|
869
|
-
})) : []
|
|
870
|
-
})
|
|
871
|
-
}
|
|
1139
|
+
Custom
|
|
872
1140
|
});
|
|
873
1141
|
};
|
|
874
1142
|
|
|
875
1143
|
// packages/ui/react-ui-form/src/components/ViewEditor/ViewEditor.tsx
|
|
876
|
-
import
|
|
877
|
-
import { AST as
|
|
878
|
-
import { IconButton as
|
|
879
|
-
import { List } from "@dxos/react-ui-list";
|
|
880
|
-
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";
|
|
881
1149
|
import { FieldSchema, ViewProjection, VIEW_FIELD_LIMIT } from "@dxos/schema";
|
|
882
|
-
import { arrayMove } from "@dxos/util";
|
|
883
1150
|
var grid = "grid grid-cols-[32px_1fr_32px] min-bs-[2.5rem]";
|
|
884
1151
|
var ViewMetaSchema = S2.Struct({
|
|
885
1152
|
name: S2.String.annotations({
|
|
886
|
-
[
|
|
1153
|
+
[AST3.TitleAnnotationId]: "View"
|
|
887
1154
|
}),
|
|
888
1155
|
typename: Format.DXN.annotations({
|
|
889
|
-
[
|
|
1156
|
+
[AST3.TitleAnnotationId]: "Typename"
|
|
890
1157
|
})
|
|
891
1158
|
}).pipe(S2.mutable);
|
|
892
|
-
var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading = false, onDelete }) => {
|
|
893
|
-
const { t } =
|
|
894
|
-
const projection =
|
|
1159
|
+
var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading = false, onTypenameChanged, onDelete }) => {
|
|
1160
|
+
const { t } = useTranslation6(translationKey);
|
|
1161
|
+
const projection = useMemo6(() => new ViewProjection(schema, view), [
|
|
895
1162
|
schema,
|
|
896
1163
|
view
|
|
897
1164
|
]);
|
|
898
|
-
const [field, setField] =
|
|
899
|
-
const viewValues =
|
|
1165
|
+
const [field, setField] = useState4();
|
|
1166
|
+
const viewValues = useMemo6(() => {
|
|
900
1167
|
return {
|
|
901
1168
|
name: view.name,
|
|
902
1169
|
// TODO(burdon): Need to warn user of possible consequences of editing.
|
|
@@ -906,77 +1173,86 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
|
|
|
906
1173
|
}, [
|
|
907
1174
|
view
|
|
908
1175
|
]);
|
|
909
|
-
const handleViewUpdate =
|
|
1176
|
+
const handleViewUpdate = useCallback5(({ name, typename }) => {
|
|
910
1177
|
requestAnimationFrame(() => {
|
|
911
|
-
view.name
|
|
912
|
-
|
|
913
|
-
|
|
1178
|
+
if (view.name !== name) {
|
|
1179
|
+
view.name = name;
|
|
1180
|
+
}
|
|
1181
|
+
if (view.query.type !== typename) {
|
|
1182
|
+
onTypenameChanged(typename);
|
|
1183
|
+
}
|
|
914
1184
|
});
|
|
915
1185
|
}, [
|
|
916
1186
|
view,
|
|
917
|
-
schema
|
|
1187
|
+
schema,
|
|
1188
|
+
onTypenameChanged
|
|
918
1189
|
]);
|
|
919
|
-
const handleSelect =
|
|
1190
|
+
const handleSelect = useCallback5((field2) => {
|
|
920
1191
|
setField((f) => f === field2 ? void 0 : field2);
|
|
921
1192
|
}, []);
|
|
922
|
-
const handleAdd =
|
|
1193
|
+
const handleAdd = useCallback5(() => {
|
|
923
1194
|
const field2 = projection.createFieldProjection();
|
|
924
1195
|
setField(field2);
|
|
925
1196
|
}, [
|
|
926
1197
|
view
|
|
927
1198
|
]);
|
|
928
|
-
const handleMove =
|
|
929
|
-
|
|
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;
|
|
930
1206
|
}, [
|
|
931
1207
|
view.fields
|
|
932
1208
|
]);
|
|
933
|
-
const handleClose =
|
|
934
|
-
return /* @__PURE__ */
|
|
1209
|
+
const handleClose = useCallback5(() => setField(void 0), []);
|
|
1210
|
+
return /* @__PURE__ */ React13.createElement("div", {
|
|
935
1211
|
role: "none",
|
|
936
|
-
className:
|
|
937
|
-
}, /* @__PURE__ */
|
|
1212
|
+
className: mx8("flex flex-col w-full divide-y divide-separator", classNames)
|
|
1213
|
+
}, /* @__PURE__ */ React13.createElement(Form, {
|
|
938
1214
|
autoFocus: true,
|
|
939
1215
|
autoSave: true,
|
|
940
1216
|
schema: ViewMetaSchema,
|
|
941
1217
|
values: viewValues,
|
|
942
1218
|
onSave: handleViewUpdate
|
|
943
|
-
}), /* @__PURE__ */
|
|
1219
|
+
}), /* @__PURE__ */ React13.createElement("div", null, /* @__PURE__ */ React13.createElement("div", {
|
|
944
1220
|
role: "none",
|
|
945
1221
|
className: "p-2"
|
|
946
|
-
}, /* @__PURE__ */
|
|
947
|
-
className:
|
|
948
|
-
}, t("fields label"))), /* @__PURE__ */
|
|
1222
|
+
}, /* @__PURE__ */ React13.createElement("label", {
|
|
1223
|
+
className: mx8(inputTextLabel)
|
|
1224
|
+
}, t("fields label"))), /* @__PURE__ */ React13.createElement(List2.Root, {
|
|
949
1225
|
items: view.fields,
|
|
950
1226
|
isItem: S2.is(FieldSchema),
|
|
951
1227
|
getId: (field2) => field2.id,
|
|
952
1228
|
onMove: handleMove
|
|
953
|
-
}, ({ items: fields }) => /* @__PURE__ */
|
|
1229
|
+
}, ({ items: fields }) => /* @__PURE__ */ React13.createElement(React13.Fragment, null, showHeading && /* @__PURE__ */ React13.createElement("div", {
|
|
954
1230
|
role: "heading",
|
|
955
1231
|
className: grid
|
|
956
|
-
}, /* @__PURE__ */
|
|
1232
|
+
}, /* @__PURE__ */ React13.createElement("div", null), /* @__PURE__ */ React13.createElement("div", {
|
|
957
1233
|
className: "flex items-center text-sm"
|
|
958
|
-
}, t("field path label"))), /* @__PURE__ */
|
|
1234
|
+
}, t("field path label"))), /* @__PURE__ */ React13.createElement("div", {
|
|
959
1235
|
role: "list",
|
|
960
1236
|
className: "flex flex-col w-full"
|
|
961
|
-
}, fields?.map((field2) => /* @__PURE__ */
|
|
1237
|
+
}, fields?.map((field2) => /* @__PURE__ */ React13.createElement(List2.Item, {
|
|
962
1238
|
key: field2.id,
|
|
963
1239
|
item: field2,
|
|
964
|
-
classNames:
|
|
965
|
-
}, /* @__PURE__ */
|
|
1240
|
+
classNames: mx8(grid, ghostHover, "cursor-pointer")
|
|
1241
|
+
}, /* @__PURE__ */ React13.createElement(List2.ItemDragHandle, null), /* @__PURE__ */ React13.createElement(List2.ItemTitle, {
|
|
966
1242
|
onClick: () => handleSelect(field2)
|
|
967
|
-
}, field2.path), /* @__PURE__ */
|
|
1243
|
+
}, field2.path), /* @__PURE__ */ React13.createElement(List2.ItemDeleteButton, {
|
|
968
1244
|
disabled: view.fields.length <= 1,
|
|
969
1245
|
onClick: () => onDelete(field2.id)
|
|
970
|
-
}))))))), field && /* @__PURE__ */
|
|
1246
|
+
}))))))), field && /* @__PURE__ */ React13.createElement(FieldEditor, {
|
|
971
1247
|
key: field.id,
|
|
972
1248
|
view,
|
|
973
1249
|
projection,
|
|
974
1250
|
field,
|
|
975
1251
|
registry,
|
|
976
1252
|
onSave: handleClose
|
|
977
|
-
}), !readonly && !field && /* @__PURE__ */
|
|
1253
|
+
}), !readonly && !field && /* @__PURE__ */ React13.createElement("div", {
|
|
978
1254
|
className: "flex p-2 justify-center"
|
|
979
|
-
}, /* @__PURE__ */
|
|
1255
|
+
}, /* @__PURE__ */ React13.createElement(IconButton4, {
|
|
980
1256
|
icon: "ph--plus--regular",
|
|
981
1257
|
label: t("button add property"),
|
|
982
1258
|
onClick: handleAdd,
|
|
@@ -1206,14 +1482,15 @@ var formatForEditing = ({ type, format, value, locale = void 0 }) => {
|
|
|
1206
1482
|
};
|
|
1207
1483
|
export {
|
|
1208
1484
|
BooleanInput,
|
|
1485
|
+
DeprecatedFormContainer,
|
|
1209
1486
|
DeprecatedFormInput,
|
|
1210
1487
|
FieldEditor,
|
|
1211
1488
|
Form,
|
|
1212
|
-
FormActions,
|
|
1213
1489
|
GeoPointInput,
|
|
1214
1490
|
InputHeader,
|
|
1215
1491
|
NumberInput,
|
|
1216
1492
|
SelectInput,
|
|
1493
|
+
SelectOptionInput,
|
|
1217
1494
|
TextInput,
|
|
1218
1495
|
TupleInput,
|
|
1219
1496
|
ViewEditor,
|