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