@dxos/react-ui-form 0.7.5-labs.a279d8c → 0.7.5-main.2567c87
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 +408 -425
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +467 -469
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +408 -425
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/components/Form/Defaults.d.ts +6 -5
- package/dist/types/src/components/Form/Defaults.d.ts.map +1 -1
- package/dist/types/src/components/Form/Form.d.ts +20 -10
- package/dist/types/src/components/Form/Form.d.ts.map +1 -1
- package/dist/types/src/components/Form/Form.stories.d.ts +1 -2
- package/dist/types/src/components/Form/Form.stories.d.ts.map +1 -1
- package/dist/types/src/components/Form/Input.d.ts +6 -5
- package/dist/types/src/components/Form/Input.d.ts.map +1 -1
- package/dist/types/src/components/Form/custom/GeoPointInput.d.ts +2 -1
- package/dist/types/src/components/Form/custom/GeoPointInput.d.ts.map +1 -1
- package/dist/types/src/components/Form/custom/TupleInput.d.ts +2 -1
- package/dist/types/src/components/Form/custom/TupleInput.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/hooks/useForm.d.ts +11 -10
- package/dist/types/src/hooks/useForm.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +26 -26
- package/src/components/FieldEditor/FieldEditor.tsx +4 -4
- package/src/components/Form/Defaults.tsx +33 -20
- package/src/components/Form/Form.stories.tsx +5 -15
- package/src/components/Form/Form.tsx +359 -37
- package/src/components/Form/Input.tsx +6 -5
- package/src/components/Form/custom/GeoPointInput.tsx +15 -6
- package/src/components/Form/custom/TupleInput.tsx +9 -5
- package/src/components/Form/factory.tsx +5 -2
- package/src/hooks/useForm.ts +48 -57
- package/dist/types/src/components/Form/ArrayField.d.ts +0 -16
- package/dist/types/src/components/Form/ArrayField.d.ts.map +0 -1
- package/dist/types/src/components/Form/FormActions.d.ts +0 -7
- package/dist/types/src/components/Form/FormActions.d.ts.map +0 -1
- package/dist/types/src/components/Form/FormContent.d.ts +0 -26
- package/dist/types/src/components/Form/FormContent.d.ts.map +0 -1
- package/dist/types/src/components/Form/FormContext.d.ts +0 -20
- package/dist/types/src/components/Form/FormContext.d.ts.map +0 -1
- package/src/components/Form/ArrayField.tsx +0 -111
- package/src/components/Form/FormActions.tsx +0 -41
- package/src/components/Form/FormContent.tsx +0 -155
- package/src/components/Form/FormContext.tsx +0 -48
|
@@ -80,11 +80,11 @@ var DeprecatedFormInput = ({ label, description, secondary, children }) => {
|
|
|
80
80
|
};
|
|
81
81
|
|
|
82
82
|
// packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx
|
|
83
|
-
import
|
|
83
|
+
import React7, { useCallback as useCallback2, useEffect as useEffect3, useMemo as useMemo3, useState as useState2 } from "react";
|
|
84
84
|
import { FormatEnum as FormatEnum2, FormatEnums, formatToType } from "@dxos/echo-schema";
|
|
85
|
-
import { log as
|
|
86
|
-
import { useTranslation as
|
|
87
|
-
import { getFormatSchema, getSchemaProperties as
|
|
85
|
+
import { log as log3 } from "@dxos/log";
|
|
86
|
+
import { useTranslation as useTranslation3 } from "@dxos/react-ui";
|
|
87
|
+
import { getFormatSchema, getSchemaProperties as getSchemaProperties2, sortProperties } from "@dxos/schema";
|
|
88
88
|
|
|
89
89
|
// packages/ui/react-ui-form/src/components/Form/custom/GeoPointInput.tsx
|
|
90
90
|
import React3 from "react";
|
|
@@ -111,10 +111,10 @@ var InputHeader = ({ children, error }) => {
|
|
|
111
111
|
};
|
|
112
112
|
|
|
113
113
|
// packages/ui/react-ui-form/src/components/Form/custom/GeoPointInput.tsx
|
|
114
|
-
var GeoPointInput = ({ type, label, disabled, getStatus, getValue:
|
|
114
|
+
var GeoPointInput = ({ property, type, label, disabled, getStatus, getValue: getValue2, onValueChange, onBlur }) => {
|
|
115
115
|
const { t } = useTranslation(translationKey);
|
|
116
|
-
const { status, error } = getStatus();
|
|
117
|
-
const [lng = 0, lat = 0] =
|
|
116
|
+
const { status, error } = getStatus?.(property);
|
|
117
|
+
const [lng = 0, lat = 0] = getValue2(property) ?? [];
|
|
118
118
|
return /* @__PURE__ */ React3.createElement(Input2.Root, {
|
|
119
119
|
validationValence: status
|
|
120
120
|
}, /* @__PURE__ */ React3.createElement(InputHeader, {
|
|
@@ -126,7 +126,7 @@ var GeoPointInput = ({ type, label, disabled, getStatus, getValue: getValue3, on
|
|
|
126
126
|
disabled,
|
|
127
127
|
placeholder: t("placeholder longitude"),
|
|
128
128
|
value: lng,
|
|
129
|
-
onChange: (event) => onValueChange(type, [
|
|
129
|
+
onChange: (event) => onValueChange(property, type, [
|
|
130
130
|
lat,
|
|
131
131
|
safeParseFloat(event.target.value, 0)
|
|
132
132
|
]),
|
|
@@ -136,7 +136,7 @@ var GeoPointInput = ({ type, label, disabled, getStatus, getValue: getValue3, on
|
|
|
136
136
|
disabled,
|
|
137
137
|
placeholder: t("placeholder latitude"),
|
|
138
138
|
value: lat,
|
|
139
|
-
onChange: (event) => onValueChange(type, [
|
|
139
|
+
onChange: (event) => onValueChange(property, type, [
|
|
140
140
|
safeParseFloat(event.target.value, 0),
|
|
141
141
|
lng
|
|
142
142
|
]),
|
|
@@ -155,9 +155,9 @@ var gridCols = [
|
|
|
155
155
|
"grid-cols-3",
|
|
156
156
|
"grid-cols-4"
|
|
157
157
|
];
|
|
158
|
-
var TupleInput = ({ binding, type, label, disabled, getStatus, getValue:
|
|
159
|
-
const { status, error } = getStatus();
|
|
160
|
-
const values =
|
|
158
|
+
var TupleInput = ({ binding, property, type, label, disabled, getStatus, getValue: getValue2, onValueChange, onBlur }) => {
|
|
159
|
+
const { status, error } = getStatus?.(property);
|
|
160
|
+
const values = getValue2(property) ?? {};
|
|
161
161
|
return /* @__PURE__ */ React4.createElement(Input3.Root, {
|
|
162
162
|
validationValence: status
|
|
163
163
|
}, /* @__PURE__ */ React4.createElement(InputHeader, {
|
|
@@ -169,7 +169,7 @@ var TupleInput = ({ binding, type, label, disabled, getStatus, getValue: getValu
|
|
|
169
169
|
type: "number",
|
|
170
170
|
disabled,
|
|
171
171
|
value: values[prop],
|
|
172
|
-
onChange: (event) => onValueChange(type, {
|
|
172
|
+
onChange: (event) => onValueChange(property, type, {
|
|
173
173
|
...values,
|
|
174
174
|
[prop]: safeParseFloat2(event.target.value, 0)
|
|
175
175
|
}),
|
|
@@ -180,8 +180,8 @@ var TupleInput = ({ binding, type, label, disabled, getStatus, getValue: getValu
|
|
|
180
180
|
// packages/ui/react-ui-form/src/components/Form/Defaults.tsx
|
|
181
181
|
import React5 from "react";
|
|
182
182
|
import { Input as Input4, Select } from "@dxos/react-ui";
|
|
183
|
-
var TextInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, getValue:
|
|
184
|
-
const { status, error } = getStatus();
|
|
183
|
+
var TextInput = ({ property, type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue2, onValueChange, onBlur }) => {
|
|
184
|
+
const { status, error } = getStatus?.(property);
|
|
185
185
|
return /* @__PURE__ */ React5.createElement(Input4.Root, {
|
|
186
186
|
validationValence: status
|
|
187
187
|
}, !inputOnly && /* @__PURE__ */ React5.createElement(InputHeader, {
|
|
@@ -189,13 +189,13 @@ var TextInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, get
|
|
|
189
189
|
}, /* @__PURE__ */ React5.createElement(Input4.Label, null, label)), /* @__PURE__ */ React5.createElement(Input4.TextInput, {
|
|
190
190
|
disabled,
|
|
191
191
|
placeholder,
|
|
192
|
-
value:
|
|
193
|
-
onChange: (event) => onValueChange(type, event.target.value),
|
|
192
|
+
value: getValue2(property) ?? "",
|
|
193
|
+
onChange: (event) => onValueChange(property, type, event.target.value),
|
|
194
194
|
onBlur
|
|
195
195
|
}), inputOnly && /* @__PURE__ */ React5.createElement(Input4.Validation, null, error));
|
|
196
196
|
};
|
|
197
|
-
var NumberInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, getValue:
|
|
198
|
-
const { status, error } = getStatus();
|
|
197
|
+
var NumberInput = ({ property, type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue2, onValueChange, onBlur }) => {
|
|
198
|
+
const { status, error } = getStatus?.(property);
|
|
199
199
|
return /* @__PURE__ */ React5.createElement(Input4.Root, {
|
|
200
200
|
validationValence: status
|
|
201
201
|
}, !inputOnly && /* @__PURE__ */ React5.createElement(InputHeader, {
|
|
@@ -204,31 +204,31 @@ var NumberInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, g
|
|
|
204
204
|
type: "number",
|
|
205
205
|
disabled,
|
|
206
206
|
placeholder,
|
|
207
|
-
value:
|
|
208
|
-
onChange: (event) => onValueChange(type, event.target.value),
|
|
207
|
+
value: getValue2(property) ?? 0,
|
|
208
|
+
onChange: (event) => onValueChange(property, type, event.target.value),
|
|
209
209
|
onBlur
|
|
210
210
|
}), inputOnly && /* @__PURE__ */ React5.createElement(Input4.DescriptionAndValidation, null, error));
|
|
211
211
|
};
|
|
212
|
-
var BooleanInput = ({ type, label, inputOnly, getStatus, getValue:
|
|
213
|
-
const { status, error } = getStatus();
|
|
212
|
+
var BooleanInput = ({ property, type, label, inputOnly, getStatus, getValue: getValue2, onValueChange }) => {
|
|
213
|
+
const { status, error } = getStatus?.(property);
|
|
214
214
|
return /* @__PURE__ */ React5.createElement(Input4.Root, {
|
|
215
215
|
validationValence: status
|
|
216
216
|
}, !inputOnly && /* @__PURE__ */ React5.createElement(InputHeader, {
|
|
217
217
|
error
|
|
218
218
|
}, /* @__PURE__ */ React5.createElement(Input4.Label, null, label)), /* @__PURE__ */ React5.createElement(Input4.Switch, {
|
|
219
|
-
checked:
|
|
220
|
-
onCheckedChange: (value) => onValueChange(type, value)
|
|
219
|
+
checked: getValue2(property),
|
|
220
|
+
onCheckedChange: (value) => onValueChange(property, type, value)
|
|
221
221
|
}), inputOnly && /* @__PURE__ */ React5.createElement(Input4.DescriptionAndValidation, null, error));
|
|
222
222
|
};
|
|
223
|
-
var SelectInput = ({ type, label, inputOnly, disabled, placeholder, options, getStatus, getValue:
|
|
224
|
-
const { status, error } = getStatus();
|
|
223
|
+
var SelectInput = ({ property, type, label, inputOnly, disabled, placeholder, options, getStatus, getValue: getValue2, onValueChange }) => {
|
|
224
|
+
const { status, error } = getStatus?.(property);
|
|
225
225
|
return /* @__PURE__ */ React5.createElement(Input4.Root, {
|
|
226
226
|
validationValence: status
|
|
227
227
|
}, !inputOnly && /* @__PURE__ */ React5.createElement(InputHeader, {
|
|
228
228
|
error
|
|
229
229
|
}, /* @__PURE__ */ React5.createElement(Input4.Label, null, label)), /* @__PURE__ */ React5.createElement(Select.Root, {
|
|
230
|
-
value:
|
|
231
|
-
onValueChange: (value) => onValueChange(type, value)
|
|
230
|
+
value: getValue2(property),
|
|
231
|
+
onValueChange: (value) => onValueChange(property, type, value)
|
|
232
232
|
}, /* @__PURE__ */ React5.createElement(Select.TriggerButton, {
|
|
233
233
|
classNames: "is-full",
|
|
234
234
|
disabled,
|
|
@@ -243,38 +243,42 @@ var SelectInput = ({ type, label, inputOnly, disabled, placeholder, options, get
|
|
|
243
243
|
};
|
|
244
244
|
|
|
245
245
|
// packages/ui/react-ui-form/src/components/Form/Form.tsx
|
|
246
|
-
import
|
|
247
|
-
import {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
import
|
|
246
|
+
import { pipe } from "effect";
|
|
247
|
+
import { capitalize } from "effect/String";
|
|
248
|
+
import React6, { useEffect as useEffect2, useMemo as useMemo2 } from "react";
|
|
249
|
+
import { AST, S } from "@dxos/echo-schema";
|
|
250
|
+
import { findNode, getDiscriminatedType, isDiscriminatedUnion, SimpleType } from "@dxos/effect";
|
|
251
|
+
import { log as log2 } from "@dxos/log";
|
|
251
252
|
import { IconButton, useTranslation as useTranslation2 } from "@dxos/react-ui";
|
|
252
253
|
import { mx as mx2 } from "@dxos/react-ui-theme";
|
|
254
|
+
import { getSchemaProperties } from "@dxos/schema";
|
|
255
|
+
import { isNotFalsy } from "@dxos/util";
|
|
253
256
|
|
|
254
|
-
// packages/ui/react-ui-form/src/components/Form/
|
|
255
|
-
import
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
257
|
+
// packages/ui/react-ui-form/src/components/Form/factory.tsx
|
|
258
|
+
import { FormatEnum } from "@dxos/echo-schema";
|
|
259
|
+
var getInputComponent = (type, format) => {
|
|
260
|
+
switch (format) {
|
|
261
|
+
case FormatEnum.LatLng:
|
|
262
|
+
return GeoPointInput;
|
|
263
|
+
}
|
|
264
|
+
switch (type) {
|
|
265
|
+
case "string":
|
|
266
|
+
return TextInput;
|
|
267
|
+
case "number":
|
|
268
|
+
return NumberInput;
|
|
269
|
+
case "boolean":
|
|
270
|
+
return BooleanInput;
|
|
271
|
+
}
|
|
272
|
+
};
|
|
259
273
|
|
|
260
274
|
// packages/ui/react-ui-form/src/hooks/useForm.ts
|
|
261
275
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
262
276
|
import { getValue, setValue } from "@dxos/echo-schema";
|
|
263
|
-
import { AST, createJsonPath, fromEffectValidationPath } from "@dxos/effect";
|
|
264
277
|
import { invariant } from "@dxos/invariant";
|
|
265
278
|
import { log } from "@dxos/log";
|
|
266
279
|
import { validateSchema } from "@dxos/schema";
|
|
267
280
|
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/hooks/useForm.ts";
|
|
268
281
|
var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, onSave }) => {
|
|
269
|
-
invariant(AST.isTypeLiteral(schema.ast), void 0, {
|
|
270
|
-
F: __dxlog_file,
|
|
271
|
-
L: 91,
|
|
272
|
-
S: void 0,
|
|
273
|
-
A: [
|
|
274
|
-
"AST.isTypeLiteral(schema.ast)",
|
|
275
|
-
""
|
|
276
|
-
]
|
|
277
|
-
});
|
|
278
282
|
const [values, setValues] = useState(initialValues);
|
|
279
283
|
useEffect(() => {
|
|
280
284
|
setValues(initialValues);
|
|
@@ -311,8 +315,8 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
|
|
|
311
315
|
values,
|
|
312
316
|
schemaDirty
|
|
313
317
|
]);
|
|
314
|
-
const canSave = useMemo(() => !saving &&
|
|
315
|
-
|
|
318
|
+
const canSave = useMemo(() => !saving && Object.keys(values).every((property) => touched[property] === false || !errors[property]), [
|
|
319
|
+
values,
|
|
316
320
|
touched,
|
|
317
321
|
errors,
|
|
318
322
|
saving
|
|
@@ -334,21 +338,17 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
|
|
|
334
338
|
onSave,
|
|
335
339
|
changed
|
|
336
340
|
]);
|
|
337
|
-
const getStatus = useCallback((
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
error: matchingError ? matchingError[1] : void 0
|
|
343
|
-
};
|
|
344
|
-
}, [
|
|
341
|
+
const getStatus = useCallback((property) => ({
|
|
342
|
+
status: errors[property] ? "error" : void 0,
|
|
343
|
+
error: errors[property] ? errors[property] : void 0
|
|
344
|
+
}), [
|
|
345
|
+
touched,
|
|
345
346
|
errors
|
|
346
347
|
]);
|
|
347
|
-
const getFormValue = (
|
|
348
|
-
return getValue(values,
|
|
348
|
+
const getFormValue = (property) => {
|
|
349
|
+
return getValue(values, property);
|
|
349
350
|
};
|
|
350
|
-
const onValueChange = (
|
|
351
|
-
const jsonPath = createJsonPath(path);
|
|
351
|
+
const onValueChange = (property, type, value) => {
|
|
352
352
|
let parsedValue = value;
|
|
353
353
|
try {
|
|
354
354
|
if (type === "number") {
|
|
@@ -357,19 +357,19 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
|
|
|
357
357
|
} catch (err) {
|
|
358
358
|
log.catch(err, void 0, {
|
|
359
359
|
F: __dxlog_file,
|
|
360
|
-
L:
|
|
360
|
+
L: 178,
|
|
361
361
|
S: void 0,
|
|
362
362
|
C: (f, a) => f(...a)
|
|
363
363
|
});
|
|
364
364
|
parsedValue = void 0;
|
|
365
365
|
}
|
|
366
366
|
const newValues = {
|
|
367
|
-
...setValue(values,
|
|
367
|
+
...setValue(values, property, parsedValue)
|
|
368
368
|
};
|
|
369
369
|
setValues(newValues);
|
|
370
370
|
setChanged((prev) => ({
|
|
371
371
|
...prev,
|
|
372
|
-
[
|
|
372
|
+
[property]: true
|
|
373
373
|
}));
|
|
374
374
|
onValuesChanged?.(newValues);
|
|
375
375
|
const isValid = validate(newValues);
|
|
@@ -379,12 +379,15 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
|
|
|
379
379
|
});
|
|
380
380
|
}
|
|
381
381
|
};
|
|
382
|
-
const
|
|
383
|
-
const
|
|
382
|
+
const onBlur = useCallback((event) => {
|
|
383
|
+
const { name } = event.target;
|
|
384
384
|
setTouched((touched2) => ({
|
|
385
385
|
...touched2,
|
|
386
|
-
[
|
|
386
|
+
[name]: true
|
|
387
387
|
}));
|
|
388
|
+
if (event.relatedTarget?.getAttribute("type") === "submit") {
|
|
389
|
+
setTouched(createKeySet(values, true));
|
|
390
|
+
}
|
|
388
391
|
validate(values);
|
|
389
392
|
}, [
|
|
390
393
|
validate,
|
|
@@ -402,13 +405,13 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
|
|
|
402
405
|
getStatus,
|
|
403
406
|
getValue: getFormValue,
|
|
404
407
|
onValueChange,
|
|
405
|
-
|
|
408
|
+
onBlur
|
|
406
409
|
};
|
|
407
410
|
};
|
|
408
411
|
var createKeySet = (obj, value) => {
|
|
409
412
|
invariant(obj, void 0, {
|
|
410
413
|
F: __dxlog_file,
|
|
411
|
-
L:
|
|
414
|
+
L: 229,
|
|
412
415
|
S: void 0,
|
|
413
416
|
A: [
|
|
414
417
|
"obj",
|
|
@@ -422,359 +425,338 @@ var createKeySet = (obj, value) => {
|
|
|
422
425
|
};
|
|
423
426
|
var flatMap = (errors) => {
|
|
424
427
|
return errors.reduce((result, { path, message }) => {
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
result[jsonPath] = message;
|
|
428
|
+
if (!(path in result)) {
|
|
429
|
+
result[path] = message;
|
|
428
430
|
}
|
|
429
431
|
return result;
|
|
430
432
|
}, {});
|
|
431
433
|
};
|
|
432
434
|
|
|
433
|
-
// packages/ui/react-ui-form/src/components/Form/
|
|
434
|
-
var
|
|
435
|
-
var useFormContext = () => {
|
|
436
|
-
return useContext(FormContext) ?? raise(new Error("Missing FormContext"));
|
|
437
|
-
};
|
|
438
|
-
var useFormValues = (path = []) => {
|
|
439
|
-
const { values: formValues } = useFormContext();
|
|
440
|
-
const jsonPath = createJsonPath2(path);
|
|
441
|
-
return getValue2(formValues, jsonPath);
|
|
442
|
-
};
|
|
443
|
-
var useInputProps = (path = []) => {
|
|
444
|
-
const { getStatus, getValue: getFormValue, onValueChange, onTouched } = useFormContext();
|
|
445
|
-
return {
|
|
446
|
-
getStatus: () => getStatus(path),
|
|
447
|
-
getValue: () => getFormValue(path),
|
|
448
|
-
onValueChange: (type, value) => onValueChange(path, type, value),
|
|
449
|
-
onBlur: () => onTouched(path)
|
|
450
|
-
};
|
|
451
|
-
};
|
|
452
|
-
var FormProvider = ({ children, ...formOptions }) => {
|
|
453
|
-
const formHandler = useForm(formOptions);
|
|
454
|
-
return /* @__PURE__ */ React6.createElement(FormContext.Provider, {
|
|
455
|
-
value: formHandler
|
|
456
|
-
}, children);
|
|
457
|
-
};
|
|
458
|
-
|
|
459
|
-
// packages/ui/react-ui-form/src/components/Form/FormActions.tsx
|
|
460
|
-
var FormActions = ({ onCancel, readonly }) => {
|
|
461
|
-
const { t } = useTranslation2(translationKey);
|
|
462
|
-
const { canSave, handleSave } = useFormContext();
|
|
463
|
-
return /* @__PURE__ */ React7.createElement("div", {
|
|
464
|
-
role: "none",
|
|
465
|
-
className: "flex justify-center"
|
|
466
|
-
}, /* @__PURE__ */ React7.createElement("div", {
|
|
467
|
-
role: "none",
|
|
468
|
-
className: mx2(onCancel && !readonly && "grid grid-cols-2 gap-2")
|
|
469
|
-
}, onCancel && !readonly && /* @__PURE__ */ React7.createElement(IconButton, {
|
|
470
|
-
"data-testid": "cancel-button",
|
|
471
|
-
icon: "ph--x--regular",
|
|
472
|
-
label: t("button cancel"),
|
|
473
|
-
onClick: onCancel
|
|
474
|
-
}), handleSave && /* @__PURE__ */ React7.createElement(IconButton, {
|
|
475
|
-
type: "submit",
|
|
476
|
-
"data-testid": "save-button",
|
|
477
|
-
disabled: !canSave,
|
|
478
|
-
icon: "ph--check--regular",
|
|
479
|
-
label: t("button save"),
|
|
480
|
-
onClick: handleSave
|
|
481
|
-
})));
|
|
482
|
-
};
|
|
483
|
-
|
|
484
|
-
// packages/ui/react-ui-form/src/components/Form/FormContent.tsx
|
|
485
|
-
import { pipe as pipe2 } from "effect";
|
|
486
|
-
import { capitalize as capitalize2 } from "effect/String";
|
|
487
|
-
import React9, { useMemo as useMemo3 } from "react";
|
|
488
|
-
import { AST as AST3, S } from "@dxos/echo-schema";
|
|
489
|
-
import { createJsonPath as createJsonPath3, findNode as findNode2, getDiscriminatedType as getDiscriminatedType2, isDiscriminatedUnion as isDiscriminatedUnion2 } from "@dxos/effect";
|
|
490
|
-
import { mx as mx4 } from "@dxos/react-ui-theme";
|
|
491
|
-
import { getSchemaProperties as getSchemaProperties2 } from "@dxos/schema";
|
|
492
|
-
import { isNotFalsy } from "@dxos/util";
|
|
493
|
-
|
|
494
|
-
// packages/ui/react-ui-form/src/components/Form/ArrayField.tsx
|
|
495
|
-
import { pipe } from "effect";
|
|
496
|
-
import { capitalize } from "effect/String";
|
|
497
|
-
import React8, { useCallback as useCallback2, useMemo as useMemo2 } from "react";
|
|
498
|
-
import { AST as AST2 } from "@dxos/echo-schema";
|
|
499
|
-
import { findNode, getDiscriminatedType, isDiscriminatedUnion, SimpleType } from "@dxos/effect";
|
|
500
|
-
import { invariant as invariant2 } from "@dxos/invariant";
|
|
501
|
-
import { IconButton as IconButton2, useTranslation as useTranslation3 } from "@dxos/react-ui";
|
|
502
|
-
import { mx as mx3 } from "@dxos/react-ui-theme";
|
|
503
|
-
import { getSchemaProperties } from "@dxos/schema";
|
|
504
|
-
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/Form/ArrayField.tsx";
|
|
435
|
+
// packages/ui/react-ui-form/src/components/Form/Form.tsx
|
|
436
|
+
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/Form/Form.tsx";
|
|
505
437
|
var padding = "px-2";
|
|
506
|
-
var
|
|
507
|
-
const
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
invariant2(Array.isArray(values), void 0, {
|
|
511
|
-
F: __dxlog_file2,
|
|
512
|
-
L: 37,
|
|
513
|
-
S: void 0,
|
|
514
|
-
A: [
|
|
515
|
-
"Array.isArray(values)",
|
|
516
|
-
""
|
|
517
|
-
]
|
|
518
|
-
});
|
|
519
|
-
const label = title ?? pipe(name, capitalize);
|
|
520
|
-
const tupleType = findNode(ast, AST2.isTupleType);
|
|
521
|
-
const elementType = tupleType?.rest[0]?.type;
|
|
522
|
-
const getDefaultObjectValue = (typeNode) => {
|
|
523
|
-
const baseNode = findNode(typeNode, isDiscriminatedUnion);
|
|
524
|
-
const typeLiteral = baseNode ? getDiscriminatedType(baseNode, {}) : findNode(typeNode, AST2.isTypeLiteral);
|
|
525
|
-
if (!typeLiteral) {
|
|
526
|
-
return {};
|
|
527
|
-
}
|
|
528
|
-
return Object.fromEntries(getSchemaProperties(typeLiteral, {}).map((prop) => [
|
|
529
|
-
prop.name,
|
|
530
|
-
prop.defaultValue
|
|
531
|
-
]));
|
|
532
|
-
};
|
|
533
|
-
const newValue = useMemo2(() => {
|
|
534
|
-
if (type === "object" && elementType) {
|
|
535
|
-
return getDefaultObjectValue(elementType);
|
|
536
|
-
} else {
|
|
537
|
-
return SimpleType.getDefaultValue(type);
|
|
538
|
-
}
|
|
539
|
-
}, [
|
|
540
|
-
type,
|
|
541
|
-
elementType
|
|
438
|
+
var Form = ({ classNames, schema, values: initialValues, path = [], readonly, filter, sort, autoSave, testId, onValuesChanged, onValidate, onSave, onCancel, lookupComponent, Custom }) => {
|
|
439
|
+
const onValid = useMemo2(() => autoSave ? onSave : void 0, [
|
|
440
|
+
autoSave,
|
|
441
|
+
onSave
|
|
542
442
|
]);
|
|
543
|
-
const
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
443
|
+
const { canSave, values, errors, handleSave, ...inputProps } = useForm({
|
|
444
|
+
schema,
|
|
445
|
+
initialValues,
|
|
446
|
+
onValuesChanged,
|
|
447
|
+
onValidate,
|
|
448
|
+
onValid,
|
|
449
|
+
onSave
|
|
450
|
+
});
|
|
451
|
+
const properties = useMemo2(() => {
|
|
452
|
+
const props = getSchemaProperties(schema.ast, values);
|
|
453
|
+
const filtered = filter ? filter(props) : props;
|
|
454
|
+
const findIndex = (props2, prop) => {
|
|
455
|
+
const idx = props2.findIndex((p) => p === prop);
|
|
456
|
+
return idx === -1 ? Infinity : idx;
|
|
457
|
+
};
|
|
458
|
+
return sort ? filtered.sort(({ name: a }, { name: b }) => findIndex(sort, a) - findIndex(sort, b)) : filtered;
|
|
548
459
|
}, [
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
inputProps,
|
|
552
|
-
newValue,
|
|
460
|
+
schema,
|
|
461
|
+
filter,
|
|
553
462
|
values
|
|
554
463
|
]);
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
464
|
+
useEffect2(() => {
|
|
465
|
+
if (errors && Object.keys(errors).length) {
|
|
466
|
+
log2.warn("validation", {
|
|
467
|
+
errors
|
|
468
|
+
}, {
|
|
469
|
+
F: __dxlog_file2,
|
|
470
|
+
L: 106,
|
|
471
|
+
S: void 0,
|
|
472
|
+
C: (f, a) => f(...a)
|
|
473
|
+
});
|
|
474
|
+
}
|
|
558
475
|
}, [
|
|
559
|
-
|
|
560
|
-
inputProps,
|
|
561
|
-
values
|
|
476
|
+
errors
|
|
562
477
|
]);
|
|
563
|
-
|
|
478
|
+
return /* @__PURE__ */ React6.createElement("div", {
|
|
479
|
+
role: "form",
|
|
480
|
+
className: mx2("flex flex-col w-full gap-2 py-2", classNames),
|
|
481
|
+
"data-testid": testId
|
|
482
|
+
}, properties.map((property) => {
|
|
483
|
+
const { ast, name, type, format, title, description, examples, options, array } = property;
|
|
484
|
+
const key = [
|
|
485
|
+
...path,
|
|
486
|
+
name
|
|
487
|
+
];
|
|
488
|
+
const label = title ?? pipe(name, capitalize);
|
|
489
|
+
const placeholder = examples?.length ? `Example: "${examples[0]}"` : description;
|
|
490
|
+
const FoundComponent = lookupComponent?.({
|
|
491
|
+
prop: name,
|
|
492
|
+
schema: S.make(ast),
|
|
493
|
+
inputProps: {
|
|
494
|
+
property: name,
|
|
495
|
+
type,
|
|
496
|
+
format,
|
|
497
|
+
label,
|
|
498
|
+
disabled: readonly,
|
|
499
|
+
placeholder,
|
|
500
|
+
...inputProps
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
if (FoundComponent) {
|
|
504
|
+
return /* @__PURE__ */ React6.createElement("div", {
|
|
505
|
+
key: name,
|
|
506
|
+
role: "none",
|
|
507
|
+
className: padding
|
|
508
|
+
}, FoundComponent);
|
|
509
|
+
}
|
|
510
|
+
let InputComponent = Custom?.[key.join(".")];
|
|
511
|
+
if (!InputComponent) {
|
|
512
|
+
if (options) {
|
|
513
|
+
return /* @__PURE__ */ React6.createElement("div", {
|
|
514
|
+
key: name,
|
|
515
|
+
role: "none",
|
|
516
|
+
className: padding
|
|
517
|
+
}, /* @__PURE__ */ React6.createElement(SelectInput, {
|
|
518
|
+
type,
|
|
519
|
+
format,
|
|
520
|
+
property: name,
|
|
521
|
+
disabled: readonly,
|
|
522
|
+
label,
|
|
523
|
+
options: options.map((option) => ({
|
|
524
|
+
value: option,
|
|
525
|
+
label: String(option)
|
|
526
|
+
})),
|
|
527
|
+
placeholder,
|
|
528
|
+
...inputProps
|
|
529
|
+
}));
|
|
530
|
+
}
|
|
531
|
+
InputComponent = getInputComponent(type, format);
|
|
532
|
+
if (array) {
|
|
533
|
+
return /* @__PURE__ */ React6.createElement(ArrayField, {
|
|
534
|
+
key: name,
|
|
535
|
+
name,
|
|
536
|
+
type,
|
|
537
|
+
array: true,
|
|
538
|
+
label,
|
|
539
|
+
ast,
|
|
540
|
+
values,
|
|
541
|
+
format,
|
|
542
|
+
readonly,
|
|
543
|
+
placeholder,
|
|
544
|
+
inputProps,
|
|
545
|
+
Custom
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
if (!InputComponent) {
|
|
550
|
+
if (type === "object") {
|
|
551
|
+
const baseNode = findNode(ast, isDiscriminatedUnion);
|
|
552
|
+
const typeLiteral = baseNode ? getDiscriminatedType(baseNode, values[name]) : findNode(ast, AST.isTypeLiteral);
|
|
553
|
+
if (typeLiteral) {
|
|
554
|
+
const schema2 = S.make(typeLiteral);
|
|
555
|
+
return /* @__PURE__ */ React6.createElement("div", {
|
|
556
|
+
key: name,
|
|
557
|
+
role: "none"
|
|
558
|
+
}, /* @__PURE__ */ React6.createElement("div", {
|
|
559
|
+
className: padding
|
|
560
|
+
}, label), /* @__PURE__ */ React6.createElement(Form, {
|
|
561
|
+
schema: schema2,
|
|
562
|
+
path: key,
|
|
563
|
+
values: values[name] ?? {},
|
|
564
|
+
onValuesChanged: (childValues) => {
|
|
565
|
+
inputProps.onValueChange(name, "object", childValues);
|
|
566
|
+
},
|
|
567
|
+
Custom
|
|
568
|
+
}));
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
log2("no renderer for property", {
|
|
572
|
+
name,
|
|
573
|
+
type
|
|
574
|
+
}, {
|
|
575
|
+
F: __dxlog_file2,
|
|
576
|
+
L: 213,
|
|
577
|
+
S: void 0,
|
|
578
|
+
C: (f, a) => f(...a)
|
|
579
|
+
});
|
|
580
|
+
return null;
|
|
581
|
+
}
|
|
582
|
+
return /* @__PURE__ */ React6.createElement("div", {
|
|
583
|
+
key: name,
|
|
584
|
+
role: "none",
|
|
585
|
+
className: padding
|
|
586
|
+
}, /* @__PURE__ */ React6.createElement(InputComponent, {
|
|
587
|
+
type,
|
|
588
|
+
format,
|
|
589
|
+
property: name,
|
|
590
|
+
disabled: readonly,
|
|
591
|
+
label,
|
|
592
|
+
placeholder,
|
|
593
|
+
...inputProps
|
|
594
|
+
}));
|
|
595
|
+
}).filter(isNotFalsy), (onCancel || onSave) && !autoSave && /* @__PURE__ */ React6.createElement(FormActions, {
|
|
596
|
+
onCancel,
|
|
597
|
+
onSubmit: handleSave,
|
|
598
|
+
canSubmit: canSave,
|
|
599
|
+
readonly
|
|
600
|
+
}));
|
|
601
|
+
};
|
|
602
|
+
var ArrayField = ({ name, type, label, ast, values, format, readonly, placeholder, inputProps, Custom }) => {
|
|
603
|
+
const { t } = useTranslation2(translationKey);
|
|
604
|
+
const arrayValues = values[name] ?? [];
|
|
605
|
+
const key = [
|
|
606
|
+
name
|
|
607
|
+
];
|
|
608
|
+
const tupleType = findNode(ast, AST.isTupleType);
|
|
609
|
+
const elementType = tupleType?.rest[0]?.type;
|
|
610
|
+
if (type === "object" && elementType) {
|
|
611
|
+
const baseNode = findNode(elementType, isDiscriminatedUnion);
|
|
612
|
+
const typeLiteral = baseNode ? getDiscriminatedType(baseNode, values[name]) : findNode(elementType, AST.isTypeLiteral);
|
|
613
|
+
if (typeLiteral) {
|
|
614
|
+
const schema = S.make(typeLiteral);
|
|
615
|
+
return /* @__PURE__ */ React6.createElement("div", {
|
|
616
|
+
key: name,
|
|
617
|
+
role: "none",
|
|
618
|
+
className: mx2(padding)
|
|
619
|
+
}, /* @__PURE__ */ React6.createElement(InputHeader, null, label), /* @__PURE__ */ React6.createElement("div", {
|
|
620
|
+
role: "none",
|
|
621
|
+
className: "flex flex-col gap-1"
|
|
622
|
+
}, arrayValues.map((value, index) => {
|
|
623
|
+
return /* @__PURE__ */ React6.createElement("div", {
|
|
624
|
+
key: index,
|
|
625
|
+
role: "none",
|
|
626
|
+
className: "flex items-center gap-1"
|
|
627
|
+
}, /* @__PURE__ */ React6.createElement("div", {
|
|
628
|
+
role: "none",
|
|
629
|
+
className: "flex-1"
|
|
630
|
+
}, /* @__PURE__ */ React6.createElement(Form, {
|
|
631
|
+
schema,
|
|
632
|
+
path: [
|
|
633
|
+
...key,
|
|
634
|
+
`[${index}]`
|
|
635
|
+
],
|
|
636
|
+
values: value,
|
|
637
|
+
onValuesChanged: (childValues) => {
|
|
638
|
+
const newValues = [
|
|
639
|
+
...arrayValues
|
|
640
|
+
];
|
|
641
|
+
newValues[index] = childValues;
|
|
642
|
+
inputProps.onValueChange(name, "object", newValues);
|
|
643
|
+
},
|
|
644
|
+
Custom
|
|
645
|
+
})), /* @__PURE__ */ React6.createElement(IconButton, {
|
|
646
|
+
icon: "ph--trash--regular",
|
|
647
|
+
iconOnly: true,
|
|
648
|
+
label: t("button remove"),
|
|
649
|
+
onClick: () => {
|
|
650
|
+
const newValues = arrayValues.filter((_, i) => i !== index);
|
|
651
|
+
inputProps.onValueChange(name, type, newValues);
|
|
652
|
+
}
|
|
653
|
+
}));
|
|
654
|
+
})), /* @__PURE__ */ React6.createElement("div", {
|
|
655
|
+
role: "none",
|
|
656
|
+
className: "flex justify-between items-center plb-1"
|
|
657
|
+
}, /* @__PURE__ */ React6.createElement(IconButton, {
|
|
658
|
+
icon: "ph--plus--regular",
|
|
659
|
+
iconOnly: true,
|
|
660
|
+
label: t("button add"),
|
|
661
|
+
onClick: () => {
|
|
662
|
+
const newValues = [
|
|
663
|
+
...arrayValues,
|
|
664
|
+
{}
|
|
665
|
+
];
|
|
666
|
+
inputProps.onValueChange(name, type, newValues);
|
|
667
|
+
}
|
|
668
|
+
})));
|
|
669
|
+
}
|
|
670
|
+
return /* @__PURE__ */ React6.createElement("div", {
|
|
671
|
+
key: name,
|
|
672
|
+
role: "none"
|
|
673
|
+
}, "Nested form not supported in arrays, yet.");
|
|
674
|
+
}
|
|
675
|
+
const InputComponent = getInputComponent(type, format);
|
|
676
|
+
if (!InputComponent) {
|
|
564
677
|
return null;
|
|
565
678
|
}
|
|
566
|
-
return /* @__PURE__ */
|
|
679
|
+
return /* @__PURE__ */ React6.createElement("div", {
|
|
567
680
|
role: "none",
|
|
568
|
-
|
|
569
|
-
|
|
681
|
+
key: "meta-input",
|
|
682
|
+
className: mx2(padding)
|
|
683
|
+
}, /* @__PURE__ */ React6.createElement(InputHeader, null, label), /* @__PURE__ */ React6.createElement("div", {
|
|
570
684
|
role: "none",
|
|
571
685
|
className: "flex flex-col gap-1"
|
|
572
|
-
},
|
|
686
|
+
}, arrayValues.map((_, index) => /* @__PURE__ */ React6.createElement("div", {
|
|
573
687
|
key: index,
|
|
574
688
|
role: "none",
|
|
575
|
-
className: "flex items-
|
|
576
|
-
}, /* @__PURE__ */
|
|
689
|
+
className: "flex items-start gap-1"
|
|
690
|
+
}, /* @__PURE__ */ React6.createElement("div", {
|
|
577
691
|
role: "none",
|
|
578
692
|
className: "flex-1"
|
|
579
|
-
}, /* @__PURE__ */
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
readonly,
|
|
590
|
-
inline: true,
|
|
591
|
-
Custom,
|
|
592
|
-
lookupComponent
|
|
593
|
-
})), /* @__PURE__ */ React8.createElement(IconButton2, {
|
|
693
|
+
}, /* @__PURE__ */ React6.createElement(InputComponent, {
|
|
694
|
+
type,
|
|
695
|
+
format,
|
|
696
|
+
label,
|
|
697
|
+
inputOnly: true,
|
|
698
|
+
property: `${name}[${index}]`,
|
|
699
|
+
disabled: readonly,
|
|
700
|
+
placeholder,
|
|
701
|
+
...inputProps
|
|
702
|
+
})), /* @__PURE__ */ React6.createElement(IconButton, {
|
|
594
703
|
icon: "ph--trash--regular",
|
|
595
704
|
iconOnly: true,
|
|
596
705
|
label: t("button remove"),
|
|
597
|
-
onClick: () =>
|
|
598
|
-
|
|
706
|
+
onClick: () => {
|
|
707
|
+
const newValues = arrayValues.filter((_2, i) => i !== index);
|
|
708
|
+
inputProps.onValueChange(name, type, newValues);
|
|
709
|
+
}
|
|
710
|
+
})))), /* @__PURE__ */ React6.createElement("div", {
|
|
599
711
|
role: "none",
|
|
600
712
|
className: "flex justify-between items-center plb-1"
|
|
601
|
-
}, /* @__PURE__ */
|
|
713
|
+
}, /* @__PURE__ */ React6.createElement(IconButton, {
|
|
602
714
|
icon: "ph--plus--regular",
|
|
603
715
|
iconOnly: true,
|
|
604
716
|
label: t("button add"),
|
|
605
|
-
onClick:
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
var getInputComponent = (type, format) => {
|
|
612
|
-
switch (format) {
|
|
613
|
-
case FormatEnum.LatLng:
|
|
614
|
-
return GeoPointInput;
|
|
615
|
-
}
|
|
616
|
-
switch (type) {
|
|
617
|
-
case "string":
|
|
618
|
-
return TextInput;
|
|
619
|
-
case "number":
|
|
620
|
-
return NumberInput;
|
|
621
|
-
case "boolean":
|
|
622
|
-
return BooleanInput;
|
|
623
|
-
}
|
|
624
|
-
};
|
|
625
|
-
|
|
626
|
-
// packages/ui/react-ui-form/src/components/Form/FormContent.tsx
|
|
627
|
-
var FormField = ({ property, path, readonly, inline, lookupComponent, Custom }) => {
|
|
628
|
-
const inputProps = useInputProps(path);
|
|
629
|
-
const { ast, name, type, format, title, description, options, examples, array } = property;
|
|
630
|
-
const label = useMemo3(() => title ?? pipe2(name, capitalize2), [
|
|
631
|
-
title,
|
|
632
|
-
name
|
|
633
|
-
]);
|
|
634
|
-
const placeholder = useMemo3(() => examples?.length ? `Example: "${examples[0]}"` : description, [
|
|
635
|
-
examples,
|
|
636
|
-
description
|
|
637
|
-
]);
|
|
638
|
-
if (array) {
|
|
639
|
-
return /* @__PURE__ */ React9.createElement(ArrayField, {
|
|
640
|
-
property,
|
|
641
|
-
path,
|
|
642
|
-
inputProps,
|
|
643
|
-
readonly,
|
|
644
|
-
Custom
|
|
645
|
-
});
|
|
646
|
-
}
|
|
647
|
-
const FoundComponent = lookupComponent?.({
|
|
648
|
-
prop: name,
|
|
649
|
-
schema: S.make(ast),
|
|
650
|
-
inputProps: {
|
|
651
|
-
type,
|
|
652
|
-
format,
|
|
653
|
-
label,
|
|
654
|
-
disabled: readonly,
|
|
655
|
-
placeholder,
|
|
656
|
-
...inputProps
|
|
657
|
-
}
|
|
658
|
-
});
|
|
659
|
-
if (FoundComponent) {
|
|
660
|
-
return /* @__PURE__ */ React9.createElement("div", null, FoundComponent);
|
|
661
|
-
}
|
|
662
|
-
const jsonPath = createJsonPath3(path ?? []);
|
|
663
|
-
const InputComponent = Custom?.[jsonPath] || getInputComponent(type, format);
|
|
664
|
-
if (InputComponent) {
|
|
665
|
-
return /* @__PURE__ */ React9.createElement("div", null, /* @__PURE__ */ React9.createElement(InputComponent, {
|
|
666
|
-
type,
|
|
667
|
-
format,
|
|
668
|
-
label,
|
|
669
|
-
inputOnly: inline,
|
|
670
|
-
placeholder,
|
|
671
|
-
disabled: readonly,
|
|
672
|
-
...inputProps
|
|
673
|
-
}));
|
|
674
|
-
}
|
|
675
|
-
if (options) {
|
|
676
|
-
return /* @__PURE__ */ React9.createElement("div", {
|
|
677
|
-
role: "none"
|
|
678
|
-
}, /* @__PURE__ */ React9.createElement(SelectInput, {
|
|
679
|
-
type,
|
|
680
|
-
format,
|
|
681
|
-
disabled: readonly,
|
|
682
|
-
inputOnly: inline,
|
|
683
|
-
label,
|
|
684
|
-
options: options.map((option) => ({
|
|
685
|
-
value: option,
|
|
686
|
-
label: String(option)
|
|
687
|
-
})),
|
|
688
|
-
placeholder,
|
|
689
|
-
...inputProps
|
|
690
|
-
}));
|
|
691
|
-
}
|
|
692
|
-
if (type === "object") {
|
|
693
|
-
const baseNode = findNode2(ast, isDiscriminatedUnion2);
|
|
694
|
-
const typeLiteral = baseNode ? getDiscriminatedType2(baseNode, inputProps.getValue()) : findNode2(ast, AST3.isTypeLiteral);
|
|
695
|
-
if (typeLiteral) {
|
|
696
|
-
return /* @__PURE__ */ React9.createElement("div", null, !inline && /* @__PURE__ */ React9.createElement("div", null, label), /* @__PURE__ */ React9.createElement(FormFields, {
|
|
697
|
-
schema: S.make(typeLiteral),
|
|
698
|
-
path,
|
|
699
|
-
readonly,
|
|
700
|
-
Custom
|
|
701
|
-
}));
|
|
717
|
+
onClick: () => {
|
|
718
|
+
const newValues = [
|
|
719
|
+
...arrayValues,
|
|
720
|
+
SimpleType.getDefaultValue(type)
|
|
721
|
+
];
|
|
722
|
+
inputProps.onValueChange(name, type, newValues);
|
|
702
723
|
}
|
|
703
|
-
}
|
|
704
|
-
return null;
|
|
705
|
-
};
|
|
706
|
-
var FormFields = ({ schema, path, filter, sort, readonly, lookupComponent, Custom }) => {
|
|
707
|
-
const values = useFormValues(path);
|
|
708
|
-
const properties = useMemo3(() => {
|
|
709
|
-
const props = getSchemaProperties2(schema.ast, values);
|
|
710
|
-
const filtered = filter ? filter(props) : props;
|
|
711
|
-
return sort ? filtered.sort((a, b) => sort.indexOf(a.name) - sort.indexOf(b.name)) : filtered;
|
|
712
|
-
}, [
|
|
713
|
-
schema,
|
|
714
|
-
values,
|
|
715
|
-
filter,
|
|
716
|
-
sort
|
|
717
|
-
]);
|
|
718
|
-
return /* @__PURE__ */ React9.createElement("div", {
|
|
719
|
-
role: "form",
|
|
720
|
-
className: mx4("flex flex-col w-full gap-2 py-2")
|
|
721
|
-
}, properties.map((property) => {
|
|
722
|
-
return /* @__PURE__ */ React9.createElement(FormField, {
|
|
723
|
-
key: property.name,
|
|
724
|
-
property,
|
|
725
|
-
path: [
|
|
726
|
-
...path ?? [],
|
|
727
|
-
property.name
|
|
728
|
-
],
|
|
729
|
-
readonly,
|
|
730
|
-
lookupComponent,
|
|
731
|
-
Custom
|
|
732
|
-
});
|
|
733
|
-
}).filter(isNotFalsy));
|
|
724
|
+
})));
|
|
734
725
|
};
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
const onValid = useMemo4(() => autoSave ? onSave : void 0, [
|
|
739
|
-
autoSave,
|
|
740
|
-
onSave
|
|
741
|
-
]);
|
|
742
|
-
return /* @__PURE__ */ React10.createElement(FormProvider, {
|
|
743
|
-
schema,
|
|
744
|
-
initialValues,
|
|
745
|
-
onValuesChanged,
|
|
746
|
-
onValidate,
|
|
747
|
-
onValid,
|
|
748
|
-
onSave
|
|
749
|
-
}, /* @__PURE__ */ React10.createElement("div", {
|
|
726
|
+
var FormActions = ({ onCancel, onSubmit, canSubmit, readonly }) => {
|
|
727
|
+
const { t } = useTranslation2(translationKey);
|
|
728
|
+
return /* @__PURE__ */ React6.createElement("div", {
|
|
750
729
|
role: "none",
|
|
751
|
-
className:
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
730
|
+
className: "flex justify-center"
|
|
731
|
+
}, /* @__PURE__ */ React6.createElement("div", {
|
|
732
|
+
role: "none",
|
|
733
|
+
className: mx2(onCancel && !readonly && "grid grid-cols-2 gap-2")
|
|
734
|
+
}, onCancel && !readonly && /* @__PURE__ */ React6.createElement(IconButton, {
|
|
735
|
+
"data-testid": "cancel-button",
|
|
736
|
+
icon: "ph--x--regular",
|
|
737
|
+
label: t("button cancel"),
|
|
738
|
+
onClick: onCancel
|
|
739
|
+
}), onSubmit && /* @__PURE__ */ React6.createElement(IconButton, {
|
|
740
|
+
type: "submit",
|
|
741
|
+
"data-testid": "save-button",
|
|
742
|
+
disabled: !canSubmit,
|
|
743
|
+
icon: "ph--check--regular",
|
|
744
|
+
label: t("button save"),
|
|
745
|
+
onClick: onSubmit
|
|
764
746
|
})));
|
|
765
747
|
};
|
|
766
748
|
|
|
767
749
|
// packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx
|
|
768
750
|
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx";
|
|
769
751
|
var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
770
|
-
const { t } =
|
|
752
|
+
const { t } = useTranslation3(translationKey);
|
|
771
753
|
const [props, setProps] = useState2(projection.getFieldProjection(field.id).props);
|
|
772
|
-
|
|
754
|
+
useEffect3(() => setProps(projection.getFieldProjection(field.id).props), [
|
|
773
755
|
field,
|
|
774
756
|
projection
|
|
775
757
|
]);
|
|
776
758
|
const [schemas, setSchemas] = useState2([]);
|
|
777
|
-
|
|
759
|
+
useEffect3(() => {
|
|
778
760
|
if (!registry) {
|
|
779
761
|
return;
|
|
780
762
|
}
|
|
@@ -793,7 +775,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
793
775
|
registry
|
|
794
776
|
]);
|
|
795
777
|
const [referenceSchema, setReferenceSchema] = useState2();
|
|
796
|
-
|
|
778
|
+
useEffect3(() => {
|
|
797
779
|
setReferenceSchema(schemas.find((schema) => schema.typename === props?.referenceSchema));
|
|
798
780
|
}, [
|
|
799
781
|
schemas,
|
|
@@ -802,7 +784,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
802
784
|
const [{ fieldSchema }, setFieldSchema] = useState2({
|
|
803
785
|
fieldSchema: getFormatSchema(props?.format)
|
|
804
786
|
});
|
|
805
|
-
const handleValuesChanged =
|
|
787
|
+
const handleValuesChanged = useCallback2((_props) => {
|
|
806
788
|
setFieldSchema((prev) => {
|
|
807
789
|
const fieldSchema2 = getFormatSchema(_props.format);
|
|
808
790
|
if (prev.fieldSchema === fieldSchema2) {
|
|
@@ -837,7 +819,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
837
819
|
props.format,
|
|
838
820
|
props.referenceSchema
|
|
839
821
|
]);
|
|
840
|
-
const handleValidate =
|
|
822
|
+
const handleValidate = useCallback2(({ property }) => {
|
|
841
823
|
if (property && view.fields.find((f) => f.path === property && f.path !== field.path)) {
|
|
842
824
|
return [
|
|
843
825
|
{
|
|
@@ -850,7 +832,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
850
832
|
view.fields,
|
|
851
833
|
field
|
|
852
834
|
]);
|
|
853
|
-
const handleSave =
|
|
835
|
+
const handleSave = useCallback2((props2) => {
|
|
854
836
|
projection.setFieldProjection({
|
|
855
837
|
field,
|
|
856
838
|
props: props2
|
|
@@ -861,29 +843,29 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
861
843
|
field,
|
|
862
844
|
onSave
|
|
863
845
|
]);
|
|
864
|
-
const handleCancel =
|
|
846
|
+
const handleCancel = useCallback2(() => {
|
|
865
847
|
requestAnimationFrame(() => onCancel?.());
|
|
866
848
|
onSave();
|
|
867
849
|
}, [
|
|
868
850
|
onSave
|
|
869
851
|
]);
|
|
870
|
-
const Custom =
|
|
871
|
-
["format"]: (props2) => /* @__PURE__ */
|
|
852
|
+
const Custom = useMemo3(() => ({
|
|
853
|
+
["format"]: (props2) => /* @__PURE__ */ React7.createElement(SelectInput, {
|
|
872
854
|
...props2,
|
|
873
855
|
options: FormatEnums.filter((value) => value !== FormatEnum2.None).map((value) => ({
|
|
874
856
|
value,
|
|
875
857
|
label: t(`format ${value}`)
|
|
876
858
|
}))
|
|
877
859
|
}),
|
|
878
|
-
["referenceSchema"]: (props2) => /* @__PURE__ */
|
|
860
|
+
["referenceSchema"]: (props2) => /* @__PURE__ */ React7.createElement(SelectInput, {
|
|
879
861
|
...props2,
|
|
880
862
|
options: schemas.map((schema) => ({
|
|
881
863
|
value: schema.typename
|
|
882
864
|
}))
|
|
883
865
|
}),
|
|
884
|
-
["referencePath"]: (props2) => /* @__PURE__ */
|
|
866
|
+
["referencePath"]: (props2) => /* @__PURE__ */ React7.createElement(SelectInput, {
|
|
885
867
|
...props2,
|
|
886
|
-
options: referenceSchema ?
|
|
868
|
+
options: referenceSchema ? getSchemaProperties2(referenceSchema.ast).sort(sortProperties).map((p) => ({
|
|
887
869
|
value: p.name
|
|
888
870
|
})) : []
|
|
889
871
|
})
|
|
@@ -892,9 +874,9 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
892
874
|
schemas,
|
|
893
875
|
referenceSchema
|
|
894
876
|
]);
|
|
895
|
-
const propIsNotType =
|
|
877
|
+
const propIsNotType = useCallback2((props2) => props2.filter((p) => p.name !== "type"), []);
|
|
896
878
|
if (!fieldSchema) {
|
|
897
|
-
|
|
879
|
+
log3.warn("invalid format", {
|
|
898
880
|
props
|
|
899
881
|
}, {
|
|
900
882
|
F: __dxlog_file3,
|
|
@@ -904,7 +886,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
904
886
|
});
|
|
905
887
|
return null;
|
|
906
888
|
}
|
|
907
|
-
return /* @__PURE__ */
|
|
889
|
+
return /* @__PURE__ */ React7.createElement(Form, {
|
|
908
890
|
key: field.id,
|
|
909
891
|
autoFocus: true,
|
|
910
892
|
values: props,
|
|
@@ -923,30 +905,30 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
923
905
|
};
|
|
924
906
|
|
|
925
907
|
// packages/ui/react-ui-form/src/components/ViewEditor/ViewEditor.tsx
|
|
926
|
-
import
|
|
927
|
-
import { AST as
|
|
928
|
-
import { IconButton as
|
|
908
|
+
import React8, { useCallback as useCallback3, useMemo as useMemo4, useState as useState3 } from "react";
|
|
909
|
+
import { AST as AST2, Format, S as S2 } from "@dxos/echo-schema";
|
|
910
|
+
import { IconButton as IconButton2, useTranslation as useTranslation4 } from "@dxos/react-ui";
|
|
929
911
|
import { List } from "@dxos/react-ui-list";
|
|
930
|
-
import { ghostHover, inputTextLabel, mx as
|
|
912
|
+
import { ghostHover, inputTextLabel, mx as mx3 } from "@dxos/react-ui-theme";
|
|
931
913
|
import { FieldSchema, ViewProjection, VIEW_FIELD_LIMIT } from "@dxos/schema";
|
|
932
914
|
import { arrayMove } from "@dxos/util";
|
|
933
915
|
var grid = "grid grid-cols-[32px_1fr_32px] min-bs-[2.5rem]";
|
|
934
916
|
var ViewMetaSchema = S2.Struct({
|
|
935
917
|
name: S2.String.annotations({
|
|
936
|
-
[
|
|
918
|
+
[AST2.TitleAnnotationId]: "View"
|
|
937
919
|
}),
|
|
938
920
|
typename: Format.DXN.annotations({
|
|
939
|
-
[
|
|
921
|
+
[AST2.TitleAnnotationId]: "Typename"
|
|
940
922
|
})
|
|
941
923
|
}).pipe(S2.mutable);
|
|
942
924
|
var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading = false, onTypenameChanged, onDelete }) => {
|
|
943
|
-
const { t } =
|
|
944
|
-
const projection =
|
|
925
|
+
const { t } = useTranslation4(translationKey);
|
|
926
|
+
const projection = useMemo4(() => new ViewProjection(schema, view), [
|
|
945
927
|
schema,
|
|
946
928
|
view
|
|
947
929
|
]);
|
|
948
930
|
const [field, setField] = useState3();
|
|
949
|
-
const viewValues =
|
|
931
|
+
const viewValues = useMemo4(() => {
|
|
950
932
|
return {
|
|
951
933
|
name: view.name,
|
|
952
934
|
// TODO(burdon): Need to warn user of possible consequences of editing.
|
|
@@ -956,7 +938,7 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
|
|
|
956
938
|
}, [
|
|
957
939
|
view
|
|
958
940
|
]);
|
|
959
|
-
const handleViewUpdate =
|
|
941
|
+
const handleViewUpdate = useCallback3(({ name, typename }) => {
|
|
960
942
|
requestAnimationFrame(() => {
|
|
961
943
|
if (view.name !== name) {
|
|
962
944
|
view.name = name;
|
|
@@ -970,67 +952,67 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
|
|
|
970
952
|
schema,
|
|
971
953
|
onTypenameChanged
|
|
972
954
|
]);
|
|
973
|
-
const handleSelect =
|
|
955
|
+
const handleSelect = useCallback3((field2) => {
|
|
974
956
|
setField((f) => f === field2 ? void 0 : field2);
|
|
975
957
|
}, []);
|
|
976
|
-
const handleAdd =
|
|
958
|
+
const handleAdd = useCallback3(() => {
|
|
977
959
|
const field2 = projection.createFieldProjection();
|
|
978
960
|
setField(field2);
|
|
979
961
|
}, [
|
|
980
962
|
view
|
|
981
963
|
]);
|
|
982
|
-
const handleMove =
|
|
964
|
+
const handleMove = useCallback3((fromIndex, toIndex) => {
|
|
983
965
|
arrayMove(view.fields, fromIndex, toIndex);
|
|
984
966
|
}, [
|
|
985
967
|
view.fields
|
|
986
968
|
]);
|
|
987
|
-
const handleClose =
|
|
988
|
-
return /* @__PURE__ */
|
|
969
|
+
const handleClose = useCallback3(() => setField(void 0), []);
|
|
970
|
+
return /* @__PURE__ */ React8.createElement("div", {
|
|
989
971
|
role: "none",
|
|
990
|
-
className:
|
|
991
|
-
}, /* @__PURE__ */
|
|
972
|
+
className: mx3("flex flex-col w-full divide-y divide-separator", classNames)
|
|
973
|
+
}, /* @__PURE__ */ React8.createElement(Form, {
|
|
992
974
|
autoFocus: true,
|
|
993
975
|
autoSave: true,
|
|
994
976
|
schema: ViewMetaSchema,
|
|
995
977
|
values: viewValues,
|
|
996
978
|
onSave: handleViewUpdate
|
|
997
|
-
}), /* @__PURE__ */
|
|
979
|
+
}), /* @__PURE__ */ React8.createElement("div", null, /* @__PURE__ */ React8.createElement("div", {
|
|
998
980
|
role: "none",
|
|
999
981
|
className: "p-2"
|
|
1000
|
-
}, /* @__PURE__ */
|
|
1001
|
-
className:
|
|
1002
|
-
}, t("fields label"))), /* @__PURE__ */
|
|
982
|
+
}, /* @__PURE__ */ React8.createElement("label", {
|
|
983
|
+
className: mx3(inputTextLabel)
|
|
984
|
+
}, t("fields label"))), /* @__PURE__ */ React8.createElement(List.Root, {
|
|
1003
985
|
items: view.fields,
|
|
1004
986
|
isItem: S2.is(FieldSchema),
|
|
1005
987
|
getId: (field2) => field2.id,
|
|
1006
988
|
onMove: handleMove
|
|
1007
|
-
}, ({ items: fields }) => /* @__PURE__ */
|
|
989
|
+
}, ({ items: fields }) => /* @__PURE__ */ React8.createElement(React8.Fragment, null, showHeading && /* @__PURE__ */ React8.createElement("div", {
|
|
1008
990
|
role: "heading",
|
|
1009
991
|
className: grid
|
|
1010
|
-
}, /* @__PURE__ */
|
|
992
|
+
}, /* @__PURE__ */ React8.createElement("div", null), /* @__PURE__ */ React8.createElement("div", {
|
|
1011
993
|
className: "flex items-center text-sm"
|
|
1012
|
-
}, t("field path label"))), /* @__PURE__ */
|
|
994
|
+
}, t("field path label"))), /* @__PURE__ */ React8.createElement("div", {
|
|
1013
995
|
role: "list",
|
|
1014
996
|
className: "flex flex-col w-full"
|
|
1015
|
-
}, fields?.map((field2) => /* @__PURE__ */
|
|
997
|
+
}, fields?.map((field2) => /* @__PURE__ */ React8.createElement(List.Item, {
|
|
1016
998
|
key: field2.id,
|
|
1017
999
|
item: field2,
|
|
1018
|
-
classNames:
|
|
1019
|
-
}, /* @__PURE__ */
|
|
1000
|
+
classNames: mx3(grid, ghostHover, "cursor-pointer")
|
|
1001
|
+
}, /* @__PURE__ */ React8.createElement(List.ItemDragHandle, null), /* @__PURE__ */ React8.createElement(List.ItemTitle, {
|
|
1020
1002
|
onClick: () => handleSelect(field2)
|
|
1021
|
-
}, field2.path), /* @__PURE__ */
|
|
1003
|
+
}, field2.path), /* @__PURE__ */ React8.createElement(List.ItemDeleteButton, {
|
|
1022
1004
|
disabled: view.fields.length <= 1,
|
|
1023
1005
|
onClick: () => onDelete(field2.id)
|
|
1024
|
-
}))))))), field && /* @__PURE__ */
|
|
1006
|
+
}))))))), field && /* @__PURE__ */ React8.createElement(FieldEditor, {
|
|
1025
1007
|
key: field.id,
|
|
1026
1008
|
view,
|
|
1027
1009
|
projection,
|
|
1028
1010
|
field,
|
|
1029
1011
|
registry,
|
|
1030
1012
|
onSave: handleClose
|
|
1031
|
-
}), !readonly && !field && /* @__PURE__ */
|
|
1013
|
+
}), !readonly && !field && /* @__PURE__ */ React8.createElement("div", {
|
|
1032
1014
|
className: "flex p-2 justify-center"
|
|
1033
|
-
}, /* @__PURE__ */
|
|
1015
|
+
}, /* @__PURE__ */ React8.createElement(IconButton2, {
|
|
1034
1016
|
icon: "ph--plus--regular",
|
|
1035
1017
|
label: t("button add property"),
|
|
1036
1018
|
onClick: handleAdd,
|
|
@@ -1263,6 +1245,7 @@ export {
|
|
|
1263
1245
|
DeprecatedFormInput,
|
|
1264
1246
|
FieldEditor,
|
|
1265
1247
|
Form,
|
|
1248
|
+
FormActions,
|
|
1266
1249
|
GeoPointInput,
|
|
1267
1250
|
InputHeader,
|
|
1268
1251
|
NumberInput,
|