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