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