@dxos/react-ui-form 0.7.5-main.e9bb01b → 0.7.5-staging.2ff1350
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 +532 -360
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +567 -391
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +532 -360
- 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 +1 -2
- package/dist/types/src/components/FieldEditor/FieldEditor.d.ts.map +1 -1
- package/dist/types/src/components/Form/ArrayField.d.ts +1 -2
- package/dist/types/src/components/Form/ArrayField.d.ts.map +1 -1
- package/dist/types/src/components/Form/Defaults.d.ts +5 -5
- package/dist/types/src/components/Form/Defaults.d.ts.map +1 -1
- package/dist/types/src/components/Form/Form.d.ts +2 -2
- package/dist/types/src/components/Form/Form.d.ts.map +1 -1
- package/dist/types/src/components/Form/FormActions.d.ts +1 -2
- package/dist/types/src/components/Form/FormActions.d.ts.map +1 -1
- package/dist/types/src/components/Form/FormContent.d.ts +2 -3
- package/dist/types/src/components/Form/FormContent.d.ts.map +1 -1
- package/dist/types/src/components/Form/FormContext.d.ts +4 -1
- package/dist/types/src/components/Form/FormContext.d.ts.map +1 -1
- package/dist/types/src/components/Form/Input.d.ts +2 -2
- 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 +1 -2
- package/dist/types/src/components/Form/custom/SelectOptionsInput.d.ts.map +1 -1
- 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/factory.d.ts.map +1 -1
- package/dist/types/src/components/Form/index.d.ts +2 -0
- package/dist/types/src/components/Form/index.d.ts.map +1 -1
- package/dist/types/src/components/ViewEditor/Test.stories.d.ts +1 -2
- package/dist/types/src/components/ViewEditor/Test.stories.d.ts.map +1 -1
- package/dist/types/src/components/ViewEditor/ViewEditor.d.ts +1 -2
- package/dist/types/src/components/ViewEditor/ViewEditor.d.ts.map +1 -1
- package/dist/types/src/components/deprecated/Form.d.ts +1 -2
- package/dist/types/src/components/deprecated/Form.d.ts.map +1 -1
- package/dist/types/src/components/deprecated/Form.stories.d.ts +1 -2
- package/dist/types/src/components/deprecated/Form.stories.d.ts.map +1 -1
- package/dist/types/src/components/deprecated/FormInput.d.ts +2 -2
- package/dist/types/src/components/deprecated/FormInput.d.ts.map +1 -1
- package/dist/types/src/components/testing.d.ts +3 -3
- package/dist/types/src/components/testing.d.ts.map +1 -1
- package/dist/types/src/hooks/useForm.d.ts +3 -2
- package/dist/types/src/hooks/useForm.d.ts.map +1 -1
- package/dist/types/src/util/field.d.ts.map +1 -1
- package/dist/types/src/util/formatting.d.ts.map +1 -1
- package/package.json +28 -27
- package/src/components/Form/Defaults.tsx +61 -2
- package/src/components/Form/Form.tsx +17 -2
- package/src/components/Form/FormActions.tsx +1 -1
- package/src/components/Form/FormContent.tsx +10 -13
- package/src/components/Form/FormContext.tsx +48 -4
- package/src/components/Form/custom/GeoPointInput.tsx +42 -12
- package/src/components/Form/custom/SelectOptionsInput.tsx +7 -9
- package/src/components/Form/factory.tsx +4 -2
- package/src/components/Form/index.ts +3 -0
- package/src/components/ViewEditor/ViewEditor.tsx +2 -2
- package/src/components/deprecated/FormInput.tsx +1 -4
- package/src/hooks/useForm.ts +10 -3
- package/src/util/field.ts +19 -1
- package/src/util/formatting.ts +29 -1
|
@@ -92,93 +92,371 @@ var DeprecatedFormInput = ({ label, description, secondary, children }) => {
|
|
|
92
92
|
}, children))));
|
|
93
93
|
if (secondary) {
|
|
94
94
|
return /* @__PURE__ */ React.createElement("div", {
|
|
95
|
-
role: "none"
|
|
96
|
-
className: "flex flex-col w-full"
|
|
95
|
+
role: "none"
|
|
97
96
|
}, primary, secondary);
|
|
98
97
|
}
|
|
99
98
|
return primary;
|
|
100
99
|
};
|
|
101
100
|
|
|
102
101
|
// packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx
|
|
103
|
-
import React12, { useCallback as
|
|
102
|
+
import React12, { useCallback as useCallback6, useEffect as useEffect7, useMemo as useMemo6, useState as useState4 } from "react";
|
|
104
103
|
import { FormatEnum as FormatEnum2, FormatEnums, formatToType } from "@dxos/echo-schema";
|
|
105
104
|
import { log as log2 } from "@dxos/log";
|
|
106
105
|
import { useTranslation as useTranslation5 } from "@dxos/react-ui";
|
|
107
106
|
import { getFormatSchema, getSchemaProperties as getSchemaProperties3, sortProperties } from "@dxos/schema";
|
|
108
107
|
|
|
108
|
+
// packages/ui/react-ui-form/src/components/Form/FormContext.tsx
|
|
109
|
+
import React2, { createContext, useContext, useEffect as useEffect2 } from "react";
|
|
110
|
+
import { raise } from "@dxos/debug";
|
|
111
|
+
import { getValue as getValue2 } from "@dxos/echo-schema";
|
|
112
|
+
import { createJsonPath as createJsonPath2 } from "@dxos/effect";
|
|
113
|
+
|
|
114
|
+
// packages/ui/react-ui-form/src/hooks/useForm.ts
|
|
115
|
+
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
116
|
+
import { getValue, setValue } from "@dxos/echo-schema";
|
|
117
|
+
import { AST, createJsonPath, fromEffectValidationPath } from "@dxos/effect";
|
|
118
|
+
import { invariant } from "@dxos/invariant";
|
|
119
|
+
import { log } from "@dxos/log";
|
|
120
|
+
import { validateSchema } from "@dxos/schema";
|
|
121
|
+
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/hooks/useForm.ts";
|
|
122
|
+
var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, onSave }) => {
|
|
123
|
+
invariant(AST.isTypeLiteral(schema.ast), void 0, {
|
|
124
|
+
F: __dxlog_file,
|
|
125
|
+
L: 92,
|
|
126
|
+
S: void 0,
|
|
127
|
+
A: [
|
|
128
|
+
"AST.isTypeLiteral(schema.ast)",
|
|
129
|
+
""
|
|
130
|
+
]
|
|
131
|
+
});
|
|
132
|
+
const [values, setValues] = useState(initialValues);
|
|
133
|
+
useEffect(() => {
|
|
134
|
+
setValues(initialValues);
|
|
135
|
+
}, [
|
|
136
|
+
initialValues
|
|
137
|
+
]);
|
|
138
|
+
const [touched, setTouched] = useState(createKeySet(initialValues, false));
|
|
139
|
+
const [changed, setChanged] = useState(createKeySet(initialValues, false));
|
|
140
|
+
const [errors, setErrors] = useState({});
|
|
141
|
+
const [saving, setSaving] = useState(false);
|
|
142
|
+
const validate = useCallback((values2) => {
|
|
143
|
+
let errors2 = validateSchema(schema, values2) ?? [];
|
|
144
|
+
if (errors2.length === 0 && onValidate) {
|
|
145
|
+
const validatedValues = values2;
|
|
146
|
+
errors2 = onValidate(validatedValues) ?? [];
|
|
147
|
+
}
|
|
148
|
+
setErrors(flatMap(errors2));
|
|
149
|
+
const valid = errors2.length === 0;
|
|
150
|
+
return valid;
|
|
151
|
+
}, [
|
|
152
|
+
schema,
|
|
153
|
+
onValidate
|
|
154
|
+
]);
|
|
155
|
+
const [schemaDirty, setSchemaDirty] = useState(false);
|
|
156
|
+
useEffect(() => setSchemaDirty(true), [
|
|
157
|
+
schema
|
|
158
|
+
]);
|
|
159
|
+
useEffect(() => {
|
|
160
|
+
if (schemaDirty) {
|
|
161
|
+
validate(values);
|
|
162
|
+
setSchemaDirty(false);
|
|
163
|
+
}
|
|
164
|
+
}, [
|
|
165
|
+
values,
|
|
166
|
+
schemaDirty
|
|
167
|
+
]);
|
|
168
|
+
const formIsValid = useMemo(() => {
|
|
169
|
+
return Object.keys(errors).length === 0;
|
|
170
|
+
}, [
|
|
171
|
+
errors
|
|
172
|
+
]);
|
|
173
|
+
const canSave = useMemo(() => !saving && // Check if any error paths that are touched have errors
|
|
174
|
+
!Object.entries(touched).some(([path, isTouched]) => isTouched && Object.keys(errors).some((errorPath) => errorPath === path || errorPath.startsWith(`${path}.`) || errorPath.startsWith(`${path}[`))), [
|
|
175
|
+
touched,
|
|
176
|
+
errors,
|
|
177
|
+
saving
|
|
178
|
+
]);
|
|
179
|
+
const handleSave = useCallback(async () => {
|
|
180
|
+
if (validate(values)) {
|
|
181
|
+
setSaving(true);
|
|
182
|
+
try {
|
|
183
|
+
await onSave?.(values, {
|
|
184
|
+
changed
|
|
185
|
+
});
|
|
186
|
+
} finally {
|
|
187
|
+
setSaving(false);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}, [
|
|
191
|
+
values,
|
|
192
|
+
validate,
|
|
193
|
+
onSave,
|
|
194
|
+
changed
|
|
195
|
+
]);
|
|
196
|
+
const getStatus = useCallback((path) => {
|
|
197
|
+
const jsonPath = Array.isArray(path) ? createJsonPath(path) : path;
|
|
198
|
+
const matchingError = Object.entries(errors).find(([errorPath]) => errorPath === jsonPath || errorPath.startsWith(`${jsonPath}.`) || errorPath.startsWith(`${jsonPath}[`));
|
|
199
|
+
return {
|
|
200
|
+
status: matchingError ? "error" : void 0,
|
|
201
|
+
error: matchingError ? matchingError[1] : void 0
|
|
202
|
+
};
|
|
203
|
+
}, [
|
|
204
|
+
errors
|
|
205
|
+
]);
|
|
206
|
+
const getFormValue = (path) => {
|
|
207
|
+
return getValue(values, createJsonPath(path));
|
|
208
|
+
};
|
|
209
|
+
const onValueChange = (path, type, value) => {
|
|
210
|
+
const jsonPath = createJsonPath(path);
|
|
211
|
+
let parsedValue = value;
|
|
212
|
+
try {
|
|
213
|
+
if (type === "number") {
|
|
214
|
+
parsedValue = parseFloat(value) || 0;
|
|
215
|
+
}
|
|
216
|
+
} catch (err) {
|
|
217
|
+
log.catch(err, void 0, {
|
|
218
|
+
F: __dxlog_file,
|
|
219
|
+
L: 198,
|
|
220
|
+
S: void 0,
|
|
221
|
+
C: (f, a) => f(...a)
|
|
222
|
+
});
|
|
223
|
+
parsedValue = void 0;
|
|
224
|
+
}
|
|
225
|
+
const newValues = {
|
|
226
|
+
...setValue(values, jsonPath, parsedValue)
|
|
227
|
+
};
|
|
228
|
+
setValues(newValues);
|
|
229
|
+
setChanged((prev) => ({
|
|
230
|
+
...prev,
|
|
231
|
+
[jsonPath]: true
|
|
232
|
+
}));
|
|
233
|
+
onValuesChanged?.(newValues);
|
|
234
|
+
const isValid = validate(newValues);
|
|
235
|
+
if (isValid && onValid) {
|
|
236
|
+
onValid(newValues, {
|
|
237
|
+
changed
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
const onTouched = useCallback((path) => {
|
|
242
|
+
const jsonPath = createJsonPath(path);
|
|
243
|
+
setTouched((touched2) => ({
|
|
244
|
+
...touched2,
|
|
245
|
+
[jsonPath]: true
|
|
246
|
+
}));
|
|
247
|
+
validate(values);
|
|
248
|
+
}, [
|
|
249
|
+
validate,
|
|
250
|
+
values
|
|
251
|
+
]);
|
|
252
|
+
return {
|
|
253
|
+
// State.
|
|
254
|
+
values,
|
|
255
|
+
errors,
|
|
256
|
+
touched,
|
|
257
|
+
changed,
|
|
258
|
+
canSave,
|
|
259
|
+
handleSave,
|
|
260
|
+
formIsValid,
|
|
261
|
+
// Field utils.
|
|
262
|
+
getStatus,
|
|
263
|
+
getValue: getFormValue,
|
|
264
|
+
onValueChange,
|
|
265
|
+
onTouched
|
|
266
|
+
};
|
|
267
|
+
};
|
|
268
|
+
var createKeySet = (obj, value) => {
|
|
269
|
+
invariant(obj, void 0, {
|
|
270
|
+
F: __dxlog_file,
|
|
271
|
+
L: 241,
|
|
272
|
+
S: void 0,
|
|
273
|
+
A: [
|
|
274
|
+
"obj",
|
|
275
|
+
""
|
|
276
|
+
]
|
|
277
|
+
});
|
|
278
|
+
return Object.keys(obj).reduce((acc, key) => ({
|
|
279
|
+
...acc,
|
|
280
|
+
[key]: value
|
|
281
|
+
}), {});
|
|
282
|
+
};
|
|
283
|
+
var flatMap = (errors) => {
|
|
284
|
+
return errors.reduce((result, { path, message }) => {
|
|
285
|
+
const jsonPath = fromEffectValidationPath(path);
|
|
286
|
+
if (!(jsonPath in result)) {
|
|
287
|
+
result[jsonPath] = message;
|
|
288
|
+
}
|
|
289
|
+
return result;
|
|
290
|
+
}, {});
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
// packages/ui/react-ui-form/src/components/Form/FormContext.tsx
|
|
294
|
+
var FormContext = /* @__PURE__ */ createContext(void 0);
|
|
295
|
+
var useFormContext = () => {
|
|
296
|
+
return useContext(FormContext) ?? raise(new Error("Missing FormContext"));
|
|
297
|
+
};
|
|
298
|
+
var useFormValues = (path = []) => {
|
|
299
|
+
const { values: formValues } = useFormContext();
|
|
300
|
+
const jsonPath = createJsonPath2(path);
|
|
301
|
+
return getValue2(formValues, jsonPath);
|
|
302
|
+
};
|
|
303
|
+
var useInputProps = (path = []) => {
|
|
304
|
+
const { getStatus, getValue: getFormValue, onValueChange, onTouched } = useFormContext();
|
|
305
|
+
return {
|
|
306
|
+
getStatus: () => getStatus(path),
|
|
307
|
+
getValue: () => getFormValue(path),
|
|
308
|
+
onValueChange: (type, value) => onValueChange(path, type, value),
|
|
309
|
+
onBlur: () => onTouched(path)
|
|
310
|
+
};
|
|
311
|
+
};
|
|
312
|
+
var FormProvider = ({ children, formRef, autoSave, ...formOptions }) => {
|
|
313
|
+
const form = useForm(formOptions);
|
|
314
|
+
useEffect2(() => {
|
|
315
|
+
if (!formRef?.current) {
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
const handleKeyDown = (event) => {
|
|
319
|
+
const keyIsEnter = event.key === "Enter";
|
|
320
|
+
const modifierUsed = event.ctrlKey || event.altKey || event.metaKey || event.shiftKey;
|
|
321
|
+
const inputIsTextarea = event.target.tagName.toLowerCase() === "textarea";
|
|
322
|
+
const inputOptOut = event.target.hasAttribute("data-no-submit");
|
|
323
|
+
const shouldSubmitRegularInput = !inputIsTextarea && keyIsEnter && !modifierUsed;
|
|
324
|
+
const shouldSubmitTextarea = inputIsTextarea && keyIsEnter && event.metaKey;
|
|
325
|
+
if ((shouldSubmitRegularInput || shouldSubmitTextarea) && !inputOptOut) {
|
|
326
|
+
if (!autoSave && form.canSave) {
|
|
327
|
+
form.handleSave();
|
|
328
|
+
}
|
|
329
|
+
if (autoSave && form.formIsValid) {
|
|
330
|
+
event.target.blur();
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
const formElement = formRef.current;
|
|
335
|
+
formElement.addEventListener("keydown", handleKeyDown);
|
|
336
|
+
return () => formElement.removeEventListener("keydown", handleKeyDown);
|
|
337
|
+
}, [
|
|
338
|
+
formRef,
|
|
339
|
+
form.canSave,
|
|
340
|
+
form.formIsValid,
|
|
341
|
+
form.handleSave,
|
|
342
|
+
autoSave
|
|
343
|
+
]);
|
|
344
|
+
return /* @__PURE__ */ React2.createElement(FormContext.Provider, {
|
|
345
|
+
value: form
|
|
346
|
+
}, children);
|
|
347
|
+
};
|
|
348
|
+
|
|
109
349
|
// packages/ui/react-ui-form/src/components/Form/custom/GeoPointInput.tsx
|
|
110
|
-
import
|
|
350
|
+
import React4, { useCallback as useCallback2, useState as useState2, useEffect as useEffect3, useMemo as useMemo2 } from "react";
|
|
351
|
+
import { GeoLocation } from "@dxos/echo-schema";
|
|
111
352
|
import { Input as Input2, useTranslation } from "@dxos/react-ui";
|
|
112
353
|
import { safeParseFloat } from "@dxos/util";
|
|
113
354
|
|
|
114
355
|
// packages/ui/react-ui-form/src/components/Form/Input.tsx
|
|
115
|
-
import
|
|
356
|
+
import React3 from "react";
|
|
116
357
|
import { Icon, Tooltip } from "@dxos/react-ui";
|
|
117
358
|
import { errorText } from "@dxos/react-ui-theme";
|
|
118
359
|
var InputHeader = ({ children, error }) => {
|
|
119
|
-
return /* @__PURE__ */
|
|
360
|
+
return /* @__PURE__ */ React3.createElement("div", {
|
|
120
361
|
role: "none",
|
|
121
362
|
className: "flex justify-between items-center mb-1"
|
|
122
|
-
}, children, error && /* @__PURE__ */
|
|
363
|
+
}, children, error && /* @__PURE__ */ React3.createElement(Tooltip.Root, null, /* @__PURE__ */ React3.createElement(Tooltip.Trigger, {
|
|
123
364
|
asChild: true
|
|
124
|
-
}, /* @__PURE__ */
|
|
365
|
+
}, /* @__PURE__ */ React3.createElement(Icon, {
|
|
125
366
|
icon: "ph--warning--regular",
|
|
126
367
|
size: 4,
|
|
127
368
|
classNames: errorText
|
|
128
|
-
})), /* @__PURE__ */
|
|
369
|
+
})), /* @__PURE__ */ React3.createElement(Tooltip.Content, {
|
|
129
370
|
side: "bottom"
|
|
130
|
-
}, /* @__PURE__ */
|
|
371
|
+
}, /* @__PURE__ */ React3.createElement(Tooltip.Arrow, null), error)));
|
|
131
372
|
};
|
|
132
373
|
|
|
133
374
|
// packages/ui/react-ui-form/src/components/Form/custom/GeoPointInput.tsx
|
|
134
375
|
var GeoPointInput = ({ type, label, disabled, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
|
|
135
376
|
const { t } = useTranslation(translationKey);
|
|
136
377
|
const { status, error } = getStatus();
|
|
137
|
-
const
|
|
138
|
-
|
|
378
|
+
const geoPoint = useMemo2(() => getValue3() ?? [
|
|
379
|
+
0,
|
|
380
|
+
0
|
|
381
|
+
], [
|
|
382
|
+
getValue3
|
|
383
|
+
]);
|
|
384
|
+
const geoLocation = useMemo2(() => GeoLocation.fromGeoPoint(geoPoint), [
|
|
385
|
+
geoPoint
|
|
386
|
+
]);
|
|
387
|
+
const [longitudeText, setLongitudeText] = useState2(geoLocation.longitude?.toString());
|
|
388
|
+
const [latitudeText, setLatitudeText] = useState2(geoLocation.latitude?.toString());
|
|
389
|
+
useEffect3(() => {
|
|
390
|
+
const location = GeoLocation.fromGeoPoint(geoPoint);
|
|
391
|
+
setLongitudeText(location.longitude.toString());
|
|
392
|
+
setLatitudeText(location.latitude.toString());
|
|
393
|
+
}, [
|
|
394
|
+
geoPoint
|
|
395
|
+
]);
|
|
396
|
+
const handleCoordinateChange = useCallback2((coordinateType, setText) => (event) => {
|
|
397
|
+
const inputText = event.target.value;
|
|
398
|
+
setText(inputText);
|
|
399
|
+
if (inputText !== "" && inputText !== "-") {
|
|
400
|
+
const coord = safeParseFloat(inputText);
|
|
401
|
+
if (coord !== void 0 && !isNaN(coord)) {
|
|
402
|
+
const currentLocation = GeoLocation.fromGeoPoint(getValue3() ?? [
|
|
403
|
+
0,
|
|
404
|
+
0
|
|
405
|
+
]);
|
|
406
|
+
const newLocation = {
|
|
407
|
+
...currentLocation,
|
|
408
|
+
[coordinateType]: coord
|
|
409
|
+
};
|
|
410
|
+
const newValue = GeoLocation.toGeoPoint(newLocation);
|
|
411
|
+
onValueChange(type, newValue);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}, [
|
|
415
|
+
getValue3,
|
|
416
|
+
onValueChange,
|
|
417
|
+
type
|
|
418
|
+
]);
|
|
419
|
+
return /* @__PURE__ */ React4.createElement(Input2.Root, {
|
|
139
420
|
validationValence: status
|
|
140
|
-
}, /* @__PURE__ */
|
|
421
|
+
}, /* @__PURE__ */ React4.createElement(InputHeader, {
|
|
141
422
|
error
|
|
142
|
-
}, /* @__PURE__ */
|
|
423
|
+
}, /* @__PURE__ */ React4.createElement(Input2.Label, null, label)), /* @__PURE__ */ React4.createElement("div", {
|
|
424
|
+
role: "none",
|
|
143
425
|
className: "grid grid-cols-2 gap-2"
|
|
144
|
-
}, /* @__PURE__ */
|
|
145
|
-
type: "
|
|
426
|
+
}, /* @__PURE__ */ React4.createElement(Input2.TextInput, {
|
|
427
|
+
type: "text",
|
|
428
|
+
pattern: "^-?[0-9]*\\.?[0-9]*$",
|
|
146
429
|
disabled,
|
|
147
|
-
placeholder: t("placeholder
|
|
148
|
-
value:
|
|
149
|
-
onChange: (
|
|
150
|
-
lat,
|
|
151
|
-
safeParseFloat(event.target.value, 0)
|
|
152
|
-
]),
|
|
430
|
+
placeholder: t("placeholder latitude"),
|
|
431
|
+
value: latitudeText,
|
|
432
|
+
onChange: handleCoordinateChange("latitude", setLatitudeText),
|
|
153
433
|
onBlur
|
|
154
|
-
}), /* @__PURE__ */
|
|
155
|
-
type: "
|
|
434
|
+
}), /* @__PURE__ */ React4.createElement(Input2.TextInput, {
|
|
435
|
+
type: "text",
|
|
436
|
+
pattern: "^-?[0-9]*\\.?[0-9]*$",
|
|
156
437
|
disabled,
|
|
157
|
-
placeholder: t("placeholder
|
|
158
|
-
value:
|
|
159
|
-
onChange: (
|
|
160
|
-
safeParseFloat(event.target.value, 0),
|
|
161
|
-
lng
|
|
162
|
-
]),
|
|
438
|
+
placeholder: t("placeholder longitude"),
|
|
439
|
+
value: longitudeText,
|
|
440
|
+
onChange: handleCoordinateChange("longitude", setLongitudeText),
|
|
163
441
|
onBlur
|
|
164
442
|
})));
|
|
165
443
|
};
|
|
166
444
|
|
|
167
445
|
// packages/ui/react-ui-form/src/components/Form/custom/SelectOptionsInput.tsx
|
|
168
|
-
import
|
|
446
|
+
import React5, { useCallback as useCallback3, useEffect as useEffect4, useState as useState3, useRef } from "react";
|
|
169
447
|
import { PublicKey } from "@dxos/keys";
|
|
170
448
|
import { Icon as Icon2, IconButton, Input as Input3, Tag, Toolbar, useTranslation as useTranslation2 } from "@dxos/react-ui";
|
|
171
449
|
import { List } from "@dxos/react-ui-list";
|
|
172
|
-
import {
|
|
173
|
-
import {
|
|
450
|
+
import { HuePicker } from "@dxos/react-ui-pickers";
|
|
451
|
+
import { hues, mx as mx2 } from "@dxos/react-ui-theme";
|
|
174
452
|
var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3, onValueChange }) => {
|
|
175
|
-
const [selected, setSelectedId] =
|
|
176
|
-
const [isNewOption, setIsNewOption] =
|
|
453
|
+
const [selected, setSelectedId] = useState3(null);
|
|
454
|
+
const [isNewOption, setIsNewOption] = useState3(false);
|
|
177
455
|
const inputRef = useRef(null);
|
|
178
456
|
const { t } = useTranslation2(translationKey);
|
|
179
457
|
const { status, error } = getStatus();
|
|
180
458
|
const options = getValue3();
|
|
181
|
-
|
|
459
|
+
useEffect4(() => {
|
|
182
460
|
if (options === void 0) {
|
|
183
461
|
onValueChange(type, []);
|
|
184
462
|
}
|
|
@@ -189,16 +467,15 @@ var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3
|
|
|
189
467
|
]);
|
|
190
468
|
const randomHue = () => {
|
|
191
469
|
const usedHues = new Set(options?.map((option) => option.color) ?? []);
|
|
192
|
-
const
|
|
193
|
-
const unusedHues = hueKeys.filter((hue) => !usedHues.has(hue));
|
|
470
|
+
const unusedHues = hues.filter((hue) => !usedHues.has(hue));
|
|
194
471
|
if (unusedHues.length > 0) {
|
|
195
472
|
return unusedHues[Math.floor(Math.random() * unusedHues.length)];
|
|
196
473
|
}
|
|
197
474
|
const lastThree = new Set(options?.slice(-3).map((option) => option.color) ?? []);
|
|
198
|
-
const availableHues =
|
|
199
|
-
return availableHues[Math.floor(Math.random() * availableHues.length)] ??
|
|
475
|
+
const availableHues = hues.filter((hue) => !lastThree.has(hue));
|
|
476
|
+
return availableHues[Math.floor(Math.random() * availableHues.length)] ?? hues[Math.floor(Math.random() * hues.length)];
|
|
200
477
|
};
|
|
201
|
-
const handleAdd =
|
|
478
|
+
const handleAdd = useCallback3(() => {
|
|
202
479
|
const newId = PublicKey.random().truncate();
|
|
203
480
|
const newOption = {
|
|
204
481
|
id: newId,
|
|
@@ -216,7 +493,7 @@ var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3
|
|
|
216
493
|
type,
|
|
217
494
|
onValueChange
|
|
218
495
|
]);
|
|
219
|
-
const handleDelete =
|
|
496
|
+
const handleDelete = useCallback3((id) => {
|
|
220
497
|
const newOptions = options?.filter((option) => option.id !== id) ?? [];
|
|
221
498
|
onValueChange(type, newOptions);
|
|
222
499
|
setSelectedId(null);
|
|
@@ -225,7 +502,7 @@ var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3
|
|
|
225
502
|
type,
|
|
226
503
|
onValueChange
|
|
227
504
|
]);
|
|
228
|
-
const handleMove =
|
|
505
|
+
const handleMove = useCallback3((from, to) => {
|
|
229
506
|
if (!options) {
|
|
230
507
|
return;
|
|
231
508
|
}
|
|
@@ -240,10 +517,10 @@ var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3
|
|
|
240
517
|
type,
|
|
241
518
|
onValueChange
|
|
242
519
|
]);
|
|
243
|
-
const handleClick =
|
|
520
|
+
const handleClick = useCallback3((id) => {
|
|
244
521
|
setSelectedId((current) => current === id ? null : id);
|
|
245
522
|
}, []);
|
|
246
|
-
const handleTitleChange =
|
|
523
|
+
const handleTitleChange = useCallback3((id) => (e) => {
|
|
247
524
|
const newOptions = options?.map((o) => o.id === id ? {
|
|
248
525
|
...o,
|
|
249
526
|
title: e.target.value
|
|
@@ -254,12 +531,12 @@ var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3
|
|
|
254
531
|
type,
|
|
255
532
|
onValueChange
|
|
256
533
|
]);
|
|
257
|
-
const handleKeyDown =
|
|
534
|
+
const handleKeyDown = useCallback3((e) => {
|
|
258
535
|
if (e.key === "Enter") {
|
|
259
536
|
setSelectedId(null);
|
|
260
537
|
}
|
|
261
538
|
}, []);
|
|
262
|
-
const handleColorChange =
|
|
539
|
+
const handleColorChange = useCallback3((id) => (hue) => {
|
|
263
540
|
const newOptions = options?.map((o) => o.id === id ? {
|
|
264
541
|
...o,
|
|
265
542
|
color: hue
|
|
@@ -270,7 +547,7 @@ var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3
|
|
|
270
547
|
type,
|
|
271
548
|
onValueChange
|
|
272
549
|
]);
|
|
273
|
-
|
|
550
|
+
useEffect4(() => {
|
|
274
551
|
if (selected && isNewOption && inputRef.current) {
|
|
275
552
|
inputRef.current.focus();
|
|
276
553
|
setIsNewOption(false);
|
|
@@ -279,76 +556,77 @@ var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3
|
|
|
279
556
|
selected,
|
|
280
557
|
isNewOption
|
|
281
558
|
]);
|
|
282
|
-
return /* @__PURE__ */
|
|
559
|
+
return /* @__PURE__ */ React5.createElement(Input3.Root, {
|
|
283
560
|
validationValence: status
|
|
284
|
-
}, /* @__PURE__ */
|
|
561
|
+
}, /* @__PURE__ */ React5.createElement(InputHeader, {
|
|
285
562
|
error
|
|
286
|
-
}, /* @__PURE__ */
|
|
563
|
+
}, /* @__PURE__ */ React5.createElement(Input3.Label, null, label)), /* @__PURE__ */ React5.createElement("div", {
|
|
287
564
|
role: "none"
|
|
288
|
-
}, options && /* @__PURE__ */
|
|
565
|
+
}, options && /* @__PURE__ */ React5.createElement(List.Root, {
|
|
289
566
|
items: options,
|
|
290
567
|
isItem: (item) => true,
|
|
291
568
|
onMove: handleMove
|
|
292
|
-
}, ({ items }) => /* @__PURE__ */
|
|
569
|
+
}, ({ items }) => /* @__PURE__ */ React5.createElement("div", {
|
|
293
570
|
role: "list",
|
|
294
571
|
className: "w-full overflow-auto"
|
|
295
|
-
}, items?.map((item) => /* @__PURE__ */
|
|
572
|
+
}, items?.map((item) => /* @__PURE__ */ React5.createElement("div", {
|
|
296
573
|
key: item.id
|
|
297
|
-
}, /* @__PURE__ */
|
|
574
|
+
}, /* @__PURE__ */ React5.createElement(List.Item, {
|
|
298
575
|
role: "button",
|
|
299
576
|
item,
|
|
300
577
|
classNames: mx2("p-1 plb-2", "flex flex-col", "cursor-pointer", "hover:bg-hoverOverlay"),
|
|
301
578
|
"aria-expanded": selected === item.id
|
|
302
|
-
}, /* @__PURE__ */
|
|
579
|
+
}, /* @__PURE__ */ React5.createElement("div", {
|
|
303
580
|
className: "flex items-center"
|
|
304
|
-
}, /* @__PURE__ */
|
|
581
|
+
}, /* @__PURE__ */ React5.createElement(List.ItemDragHandle, null), /* @__PURE__ */ React5.createElement(List.ItemTitle, {
|
|
305
582
|
onClick: () => handleClick(item.id),
|
|
306
583
|
classNames: "flex-1"
|
|
307
|
-
}, /* @__PURE__ */
|
|
584
|
+
}, /* @__PURE__ */ React5.createElement(Tag, {
|
|
308
585
|
palette: item.color
|
|
309
|
-
}, item.title || "\u200B")), /* @__PURE__ */
|
|
586
|
+
}, item.title || "\u200B")), /* @__PURE__ */ React5.createElement(Icon2, {
|
|
310
587
|
icon: selected === item.id ? "ph--caret-down--regular" : "ph--caret-right--regular",
|
|
311
588
|
onClick: () => handleClick(item.id)
|
|
312
|
-
})), selected === item.id && /* @__PURE__ */
|
|
589
|
+
})), selected === item.id && /* @__PURE__ */ React5.createElement("div", {
|
|
313
590
|
className: "mis-4 mbs-2 flex flex-col gap-1"
|
|
314
|
-
}, /* @__PURE__ */
|
|
591
|
+
}, /* @__PURE__ */ React5.createElement(Input3.Label, {
|
|
315
592
|
classNames: "text-xs"
|
|
316
|
-
}, t("select option label")), /* @__PURE__ */
|
|
593
|
+
}, t("select option label")), /* @__PURE__ */ React5.createElement("div", {
|
|
317
594
|
className: "flex flex-row items-center gap-1"
|
|
318
|
-
}, /* @__PURE__ */
|
|
595
|
+
}, /* @__PURE__ */ React5.createElement(Input3.TextInput, {
|
|
319
596
|
placeholder: t("select option label placeholder"),
|
|
320
597
|
ref: selected === item.id ? inputRef : void 0,
|
|
321
598
|
value: item.title,
|
|
322
599
|
onChange: handleTitleChange(item.id),
|
|
323
600
|
onKeyDown: handleKeyDown,
|
|
324
|
-
classNames: "flex-1"
|
|
325
|
-
|
|
601
|
+
classNames: "flex-1",
|
|
602
|
+
"data-no-submit": true
|
|
603
|
+
}), /* @__PURE__ */ React5.createElement(Toolbar.Root, {
|
|
326
604
|
classNames: "p-0 m-0 !is-auto"
|
|
327
|
-
}, /* @__PURE__ */
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
})), /* @__PURE__ */
|
|
605
|
+
}, /* @__PURE__ */ React5.createElement(HuePicker, {
|
|
606
|
+
value: item.color,
|
|
607
|
+
onChange: handleColorChange(item.id)
|
|
608
|
+
})), /* @__PURE__ */ React5.createElement(IconButton, {
|
|
331
609
|
icon: "ph--trash--fill",
|
|
332
610
|
iconOnly: true,
|
|
333
611
|
label: t("select option delete"),
|
|
334
612
|
onClick: () => handleDelete(item.id)
|
|
335
|
-
})))))), /* @__PURE__ */
|
|
613
|
+
})))))), /* @__PURE__ */ React5.createElement("div", {
|
|
336
614
|
role: "listitem"
|
|
337
|
-
}, /* @__PURE__ */
|
|
615
|
+
}, /* @__PURE__ */ React5.createElement("div", {
|
|
338
616
|
role: "button",
|
|
339
617
|
className: mx2("p-1 plb-2", "flex flex-col", "cursor-pointer", "hover:bg-hoverOverlay"),
|
|
340
618
|
onClick: handleAdd
|
|
341
|
-
}, /* @__PURE__ */
|
|
619
|
+
}, /* @__PURE__ */ React5.createElement("div", {
|
|
342
620
|
className: "flex items-center gap-1"
|
|
343
|
-
}, /* @__PURE__ */
|
|
621
|
+
}, /* @__PURE__ */ React5.createElement(Icon2, {
|
|
344
622
|
icon: "ph--plus--regular"
|
|
345
|
-
}), /* @__PURE__ */
|
|
623
|
+
}), /* @__PURE__ */ React5.createElement("span", {
|
|
346
624
|
className: "text-sm"
|
|
347
625
|
}, t("select option add")))))))));
|
|
348
626
|
};
|
|
349
627
|
|
|
350
628
|
// packages/ui/react-ui-form/src/components/Form/custom/TupleInput.tsx
|
|
351
|
-
import
|
|
629
|
+
import React6 from "react";
|
|
352
630
|
import { Input as Input4 } from "@dxos/react-ui";
|
|
353
631
|
import { mx as mx3 } from "@dxos/react-ui-theme";
|
|
354
632
|
import { safeParseFloat as safeParseFloat2 } from "@dxos/util";
|
|
@@ -361,13 +639,13 @@ var gridCols = [
|
|
|
361
639
|
var TupleInput = ({ binding, type, label, disabled, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
|
|
362
640
|
const { status, error } = getStatus();
|
|
363
641
|
const values = getValue3() ?? {};
|
|
364
|
-
return /* @__PURE__ */
|
|
642
|
+
return /* @__PURE__ */ React6.createElement(Input4.Root, {
|
|
365
643
|
validationValence: status
|
|
366
|
-
}, /* @__PURE__ */
|
|
644
|
+
}, /* @__PURE__ */ React6.createElement(InputHeader, {
|
|
367
645
|
error
|
|
368
|
-
}, /* @__PURE__ */
|
|
646
|
+
}, /* @__PURE__ */ React6.createElement(Input4.Label, null, label)), /* @__PURE__ */ React6.createElement("div", {
|
|
369
647
|
className: mx3("grid gap-2", gridCols[binding.length - 1])
|
|
370
|
-
}, binding.map((prop) => /* @__PURE__ */
|
|
648
|
+
}, binding.map((prop) => /* @__PURE__ */ React6.createElement(Input4.TextInput, {
|
|
371
649
|
key: prop,
|
|
372
650
|
type: "number",
|
|
373
651
|
disabled,
|
|
@@ -381,282 +659,124 @@ var TupleInput = ({ binding, type, label, disabled, getStatus, getValue: getValu
|
|
|
381
659
|
};
|
|
382
660
|
|
|
383
661
|
// packages/ui/react-ui-form/src/components/Form/Defaults.tsx
|
|
384
|
-
import
|
|
662
|
+
import React7, { useCallback as useCallback4, useEffect as useEffect5, useRef as useRef2 } from "react";
|
|
385
663
|
import { Input as Input5, Select } from "@dxos/react-ui";
|
|
386
664
|
var TextInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
|
|
387
665
|
const { status, error } = getStatus();
|
|
388
|
-
return /* @__PURE__ */
|
|
666
|
+
return /* @__PURE__ */ React7.createElement(Input5.Root, {
|
|
389
667
|
validationValence: status
|
|
390
|
-
}, !inputOnly && /* @__PURE__ */
|
|
668
|
+
}, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
|
|
391
669
|
error
|
|
392
|
-
}, /* @__PURE__ */
|
|
670
|
+
}, /* @__PURE__ */ React7.createElement(Input5.Label, null, label)), /* @__PURE__ */ React7.createElement(Input5.TextInput, {
|
|
393
671
|
disabled,
|
|
394
672
|
placeholder,
|
|
395
673
|
value: getValue3() ?? "",
|
|
396
674
|
onChange: (event) => onValueChange(type, event.target.value),
|
|
397
675
|
onBlur
|
|
398
|
-
}), inputOnly && /* @__PURE__ */
|
|
676
|
+
}), inputOnly && /* @__PURE__ */ React7.createElement(Input5.Validation, null, error));
|
|
399
677
|
};
|
|
400
678
|
var NumberInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
|
|
401
679
|
const { status, error } = getStatus();
|
|
402
|
-
return /* @__PURE__ */
|
|
680
|
+
return /* @__PURE__ */ React7.createElement(Input5.Root, {
|
|
403
681
|
validationValence: status
|
|
404
|
-
}, !inputOnly && /* @__PURE__ */
|
|
682
|
+
}, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
|
|
405
683
|
error
|
|
406
|
-
}, /* @__PURE__ */
|
|
684
|
+
}, /* @__PURE__ */ React7.createElement(Input5.Label, null, label)), /* @__PURE__ */ React7.createElement(Input5.TextInput, {
|
|
407
685
|
type: "number",
|
|
408
686
|
disabled,
|
|
409
687
|
placeholder,
|
|
410
688
|
value: getValue3() ?? 0,
|
|
411
689
|
onChange: (event) => onValueChange(type, event.target.value),
|
|
412
690
|
onBlur
|
|
413
|
-
}), inputOnly && /* @__PURE__ */
|
|
691
|
+
}), inputOnly && /* @__PURE__ */ React7.createElement(Input5.DescriptionAndValidation, null, error));
|
|
414
692
|
};
|
|
415
693
|
var BooleanInput = ({ type, label, inputOnly, getStatus, getValue: getValue3, onValueChange }) => {
|
|
416
694
|
const { status, error } = getStatus();
|
|
417
|
-
|
|
695
|
+
const checked = Boolean(getValue3());
|
|
696
|
+
return /* @__PURE__ */ React7.createElement(Input5.Root, {
|
|
418
697
|
validationValence: status
|
|
419
|
-
}, !inputOnly && /* @__PURE__ */
|
|
698
|
+
}, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
|
|
420
699
|
error
|
|
421
|
-
}, /* @__PURE__ */
|
|
422
|
-
checked
|
|
700
|
+
}, /* @__PURE__ */ React7.createElement(Input5.Label, null, label)), /* @__PURE__ */ React7.createElement(Input5.Switch, {
|
|
701
|
+
checked,
|
|
423
702
|
onCheckedChange: (value) => onValueChange(type, value)
|
|
424
|
-
}), inputOnly && /* @__PURE__ */
|
|
703
|
+
}), inputOnly && /* @__PURE__ */ React7.createElement(Input5.DescriptionAndValidation, null, error));
|
|
425
704
|
};
|
|
426
705
|
var SelectInput = ({ type, label, inputOnly, disabled, placeholder, options, getStatus, getValue: getValue3, onValueChange }) => {
|
|
427
706
|
const { status, error } = getStatus();
|
|
428
|
-
return /* @__PURE__ */
|
|
707
|
+
return /* @__PURE__ */ React7.createElement(Input5.Root, {
|
|
429
708
|
validationValence: status
|
|
430
|
-
}, !inputOnly && /* @__PURE__ */
|
|
709
|
+
}, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
|
|
431
710
|
error
|
|
432
|
-
}, /* @__PURE__ */
|
|
711
|
+
}, /* @__PURE__ */ React7.createElement(Input5.Label, null, label)), /* @__PURE__ */ React7.createElement(Select.Root, {
|
|
433
712
|
value: getValue3(),
|
|
434
713
|
onValueChange: (value) => onValueChange(type, value)
|
|
435
|
-
}, /* @__PURE__ */
|
|
714
|
+
}, /* @__PURE__ */ React7.createElement(Select.TriggerButton, {
|
|
436
715
|
classNames: "is-full",
|
|
437
716
|
disabled,
|
|
438
717
|
placeholder
|
|
439
|
-
}), /* @__PURE__ */
|
|
718
|
+
}), /* @__PURE__ */ React7.createElement(Select.Portal, null, /* @__PURE__ */ React7.createElement(Select.Content, null, /* @__PURE__ */ React7.createElement(Select.Viewport, null, options?.map(({ value, label: label2 }) => (
|
|
440
719
|
// NOTE: Numeric values are converted to and from strings.
|
|
441
|
-
/* @__PURE__ */
|
|
720
|
+
/* @__PURE__ */ React7.createElement(Select.Option, {
|
|
442
721
|
key: String(value),
|
|
443
722
|
value: String(value)
|
|
444
723
|
}, label2 ?? String(value))
|
|
445
|
-
)))))), inputOnly && /* @__PURE__ */
|
|
724
|
+
)))))), inputOnly && /* @__PURE__ */ React7.createElement(Input5.DescriptionAndValidation, null, error));
|
|
446
725
|
};
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
import { mx as mx4 } from "@dxos/react-ui-theme";
|
|
456
|
-
|
|
457
|
-
// packages/ui/react-ui-form/src/components/Form/FormContext.tsx
|
|
458
|
-
import React7, { createContext, useContext } from "react";
|
|
459
|
-
import { raise } from "@dxos/debug";
|
|
460
|
-
import { getValue as getValue2 } from "@dxos/echo-schema";
|
|
461
|
-
import { createJsonPath as createJsonPath2 } from "@dxos/effect";
|
|
462
|
-
|
|
463
|
-
// packages/ui/react-ui-form/src/hooks/useForm.ts
|
|
464
|
-
import { useCallback as useCallback2, useEffect as useEffect2, useMemo, useState as useState2 } from "react";
|
|
465
|
-
import { getValue, setValue } from "@dxos/echo-schema";
|
|
466
|
-
import { createJsonPath, fromEffectValidationPath } from "@dxos/effect";
|
|
467
|
-
import { invariant } from "@dxos/invariant";
|
|
468
|
-
import { log } from "@dxos/log";
|
|
469
|
-
import { validateSchema } from "@dxos/schema";
|
|
470
|
-
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/hooks/useForm.ts";
|
|
471
|
-
var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, onSave }) => {
|
|
472
|
-
const [values, setValues] = useState2(initialValues);
|
|
473
|
-
useEffect2(() => {
|
|
474
|
-
setValues(initialValues);
|
|
475
|
-
}, [
|
|
476
|
-
initialValues
|
|
477
|
-
]);
|
|
478
|
-
const [touched, setTouched] = useState2(createKeySet(initialValues, false));
|
|
479
|
-
const [changed, setChanged] = useState2(createKeySet(initialValues, false));
|
|
480
|
-
const [errors, setErrors] = useState2({});
|
|
481
|
-
const [saving, setSaving] = useState2(false);
|
|
482
|
-
const validate = useCallback2((values2) => {
|
|
483
|
-
let errors2 = validateSchema(schema, values2) ?? [];
|
|
484
|
-
if (errors2.length === 0 && onValidate) {
|
|
485
|
-
const validatedValues = values2;
|
|
486
|
-
errors2 = onValidate(validatedValues) ?? [];
|
|
487
|
-
}
|
|
488
|
-
setErrors(flatMap(errors2));
|
|
489
|
-
const valid = errors2.length === 0;
|
|
490
|
-
return valid;
|
|
491
|
-
}, [
|
|
492
|
-
schema,
|
|
493
|
-
onValidate
|
|
494
|
-
]);
|
|
495
|
-
const [schemaDirty, setSchemaDirty] = useState2(false);
|
|
496
|
-
useEffect2(() => setSchemaDirty(true), [
|
|
497
|
-
schema
|
|
498
|
-
]);
|
|
499
|
-
useEffect2(() => {
|
|
500
|
-
if (schemaDirty) {
|
|
501
|
-
validate(values);
|
|
502
|
-
setSchemaDirty(false);
|
|
503
|
-
}
|
|
504
|
-
}, [
|
|
505
|
-
values,
|
|
506
|
-
schemaDirty
|
|
507
|
-
]);
|
|
508
|
-
const canSave = useMemo(() => !saving && // Check if any error paths that are touched have errors
|
|
509
|
-
!Object.entries(touched).some(([path, isTouched]) => isTouched && Object.keys(errors).some((errorPath) => errorPath === path || errorPath.startsWith(`${path}.`) || errorPath.startsWith(`${path}[`))), [
|
|
510
|
-
touched,
|
|
511
|
-
errors,
|
|
512
|
-
saving
|
|
513
|
-
]);
|
|
514
|
-
const handleSave = useCallback2(async () => {
|
|
515
|
-
if (validate(values)) {
|
|
516
|
-
setSaving(true);
|
|
517
|
-
try {
|
|
518
|
-
await onSave?.(values, {
|
|
519
|
-
changed
|
|
520
|
-
});
|
|
521
|
-
} finally {
|
|
522
|
-
setSaving(false);
|
|
523
|
-
}
|
|
726
|
+
var MarkdownInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
|
|
727
|
+
const { status, error } = getStatus();
|
|
728
|
+
const textareaRef = useRef2(null);
|
|
729
|
+
const adjustHeight = useCallback4(() => {
|
|
730
|
+
const textarea = textareaRef.current;
|
|
731
|
+
if (textarea) {
|
|
732
|
+
textarea.style.blockSize = "auto";
|
|
733
|
+
textarea.style.blockSize = `${textarea.scrollHeight + 2}px`;
|
|
524
734
|
}
|
|
735
|
+
}, []);
|
|
736
|
+
useEffect5(() => {
|
|
737
|
+
adjustHeight();
|
|
525
738
|
}, [
|
|
526
|
-
|
|
527
|
-
validate,
|
|
528
|
-
onSave,
|
|
529
|
-
changed
|
|
739
|
+
adjustHeight
|
|
530
740
|
]);
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
const matchingError = Object.entries(errors).find(([errorPath]) => errorPath === jsonPath || errorPath.startsWith(`${jsonPath}.`) || errorPath.startsWith(`${jsonPath}[`));
|
|
534
|
-
return {
|
|
535
|
-
status: matchingError ? "error" : void 0,
|
|
536
|
-
error: matchingError ? matchingError[1] : void 0
|
|
537
|
-
};
|
|
741
|
+
useEffect5(() => {
|
|
742
|
+
adjustHeight();
|
|
538
743
|
}, [
|
|
539
|
-
|
|
744
|
+
getValue3(),
|
|
745
|
+
adjustHeight
|
|
540
746
|
]);
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
parsedValue = void 0;
|
|
559
|
-
}
|
|
560
|
-
const newValues = {
|
|
561
|
-
...setValue(values, jsonPath, parsedValue)
|
|
562
|
-
};
|
|
563
|
-
setValues(newValues);
|
|
564
|
-
setChanged((prev) => ({
|
|
565
|
-
...prev,
|
|
566
|
-
[jsonPath]: true
|
|
567
|
-
}));
|
|
568
|
-
onValuesChanged?.(newValues);
|
|
569
|
-
const isValid = validate(newValues);
|
|
570
|
-
if (isValid && onValid) {
|
|
571
|
-
onValid(newValues, {
|
|
572
|
-
changed
|
|
573
|
-
});
|
|
574
|
-
}
|
|
575
|
-
};
|
|
576
|
-
const onTouched = useCallback2((path) => {
|
|
577
|
-
const jsonPath = createJsonPath(path);
|
|
578
|
-
setTouched((touched2) => ({
|
|
579
|
-
...touched2,
|
|
580
|
-
[jsonPath]: true
|
|
581
|
-
}));
|
|
582
|
-
validate(values);
|
|
583
|
-
}, [
|
|
584
|
-
validate,
|
|
585
|
-
values
|
|
586
|
-
]);
|
|
587
|
-
return {
|
|
588
|
-
// State.
|
|
589
|
-
values,
|
|
590
|
-
errors,
|
|
591
|
-
touched,
|
|
592
|
-
changed,
|
|
593
|
-
canSave,
|
|
594
|
-
handleSave,
|
|
595
|
-
// Field utils.
|
|
596
|
-
getStatus,
|
|
597
|
-
getValue: getFormValue,
|
|
598
|
-
onValueChange,
|
|
599
|
-
onTouched
|
|
600
|
-
};
|
|
601
|
-
};
|
|
602
|
-
var createKeySet = (obj, value) => {
|
|
603
|
-
invariant(obj, void 0, {
|
|
604
|
-
F: __dxlog_file,
|
|
605
|
-
L: 234,
|
|
606
|
-
S: void 0,
|
|
607
|
-
A: [
|
|
608
|
-
"obj",
|
|
609
|
-
""
|
|
610
|
-
]
|
|
611
|
-
});
|
|
612
|
-
return Object.keys(obj).reduce((acc, key) => ({
|
|
613
|
-
...acc,
|
|
614
|
-
[key]: value
|
|
615
|
-
}), {});
|
|
616
|
-
};
|
|
617
|
-
var flatMap = (errors) => {
|
|
618
|
-
return errors.reduce((result, { path, message }) => {
|
|
619
|
-
const jsonPath = fromEffectValidationPath(path);
|
|
620
|
-
if (!(jsonPath in result)) {
|
|
621
|
-
result[jsonPath] = message;
|
|
622
|
-
}
|
|
623
|
-
return result;
|
|
624
|
-
}, {});
|
|
747
|
+
return /* @__PURE__ */ React7.createElement(Input5.Root, {
|
|
748
|
+
validationValence: status
|
|
749
|
+
}, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
|
|
750
|
+
error
|
|
751
|
+
}, /* @__PURE__ */ React7.createElement(Input5.Label, null, label)), /* @__PURE__ */ React7.createElement(Input5.TextArea, {
|
|
752
|
+
ref: textareaRef,
|
|
753
|
+
disabled,
|
|
754
|
+
placeholder,
|
|
755
|
+
value: getValue3() ?? "",
|
|
756
|
+
classNames: "min-bs-auto max-h-40 overflow-auto",
|
|
757
|
+
onChange: (event) => onValueChange(type, event.target.value),
|
|
758
|
+
onBlur,
|
|
759
|
+
style: {
|
|
760
|
+
resize: "none"
|
|
761
|
+
},
|
|
762
|
+
spellCheck: false
|
|
763
|
+
}), inputOnly && /* @__PURE__ */ React7.createElement(Input5.Validation, null, error));
|
|
625
764
|
};
|
|
626
765
|
|
|
627
|
-
// packages/ui/react-ui-form/src/components/Form/
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
return useContext(FormContext) ?? raise(new Error("Missing FormContext"));
|
|
631
|
-
};
|
|
632
|
-
var useFormValues = (path = []) => {
|
|
633
|
-
const { values: formValues } = useFormContext();
|
|
634
|
-
const jsonPath = createJsonPath2(path);
|
|
635
|
-
return getValue2(formValues, jsonPath);
|
|
636
|
-
};
|
|
637
|
-
var useInputProps = (path = []) => {
|
|
638
|
-
const { getStatus, getValue: getFormValue, onValueChange, onTouched } = useFormContext();
|
|
639
|
-
return {
|
|
640
|
-
getStatus: () => getStatus(path),
|
|
641
|
-
getValue: () => getFormValue(path),
|
|
642
|
-
onValueChange: (type, value) => onValueChange(path, type, value),
|
|
643
|
-
onBlur: () => onTouched(path)
|
|
644
|
-
};
|
|
645
|
-
};
|
|
646
|
-
var FormProvider = ({ children, ...formOptions }) => {
|
|
647
|
-
const formHandler = useForm(formOptions);
|
|
648
|
-
return /* @__PURE__ */ React7.createElement(FormContext.Provider, {
|
|
649
|
-
value: formHandler
|
|
650
|
-
}, children);
|
|
651
|
-
};
|
|
766
|
+
// packages/ui/react-ui-form/src/components/Form/Form.tsx
|
|
767
|
+
import React11, { useEffect as useEffect6, useMemo as useMemo5, useRef as useRef3 } from "react";
|
|
768
|
+
import { mx as mx7 } from "@dxos/react-ui-theme";
|
|
652
769
|
|
|
653
770
|
// packages/ui/react-ui-form/src/components/Form/FormActions.tsx
|
|
771
|
+
import React8 from "react";
|
|
772
|
+
import { IconButton as IconButton2, useTranslation as useTranslation3 } from "@dxos/react-ui";
|
|
773
|
+
import { mx as mx4 } from "@dxos/react-ui-theme";
|
|
654
774
|
var FormActions = ({ onCancel, readonly }) => {
|
|
655
775
|
const { t } = useTranslation3(translationKey);
|
|
656
776
|
const { canSave, handleSave } = useFormContext();
|
|
657
777
|
return /* @__PURE__ */ React8.createElement("div", {
|
|
658
778
|
role: "none",
|
|
659
|
-
className: "flex justify-center"
|
|
779
|
+
className: "mt-2 flex justify-center"
|
|
660
780
|
}, /* @__PURE__ */ React8.createElement("div", {
|
|
661
781
|
role: "none",
|
|
662
782
|
className: mx4(onCancel && !readonly && "grid grid-cols-2 gap-2")
|
|
@@ -678,8 +798,8 @@ var FormActions = ({ onCancel, readonly }) => {
|
|
|
678
798
|
// packages/ui/react-ui-form/src/components/Form/FormContent.tsx
|
|
679
799
|
import { pipe as pipe2 } from "effect";
|
|
680
800
|
import { capitalize as capitalize2 } from "effect/String";
|
|
681
|
-
import React10, { useMemo as
|
|
682
|
-
import { AST as
|
|
801
|
+
import React10, { useMemo as useMemo4 } from "react";
|
|
802
|
+
import { AST as AST3, S } from "@dxos/echo-schema";
|
|
683
803
|
import { createJsonPath as createJsonPath3, findNode as findNode2, getDiscriminatedType as getDiscriminatedType2, isDiscriminatedUnion as isDiscriminatedUnion2 } from "@dxos/effect";
|
|
684
804
|
import { mx as mx6 } from "@dxos/react-ui-theme";
|
|
685
805
|
import { getSchemaProperties as getSchemaProperties2 } from "@dxos/schema";
|
|
@@ -688,8 +808,8 @@ import { isNotFalsy } from "@dxos/util";
|
|
|
688
808
|
// packages/ui/react-ui-form/src/components/Form/ArrayField.tsx
|
|
689
809
|
import { pipe } from "effect";
|
|
690
810
|
import { capitalize } from "effect/String";
|
|
691
|
-
import React9, { useCallback as
|
|
692
|
-
import { AST } from "@dxos/echo-schema";
|
|
811
|
+
import React9, { useCallback as useCallback5, useMemo as useMemo3 } from "react";
|
|
812
|
+
import { AST as AST2 } from "@dxos/echo-schema";
|
|
693
813
|
import { findNode, getDiscriminatedType, isDiscriminatedUnion, SimpleType } from "@dxos/effect";
|
|
694
814
|
import { invariant as invariant2 } from "@dxos/invariant";
|
|
695
815
|
import { IconButton as IconButton3, useTranslation as useTranslation4 } from "@dxos/react-ui";
|
|
@@ -711,11 +831,11 @@ var ArrayField = ({ property, readonly, path, inputProps, Custom, lookupComponen
|
|
|
711
831
|
]
|
|
712
832
|
});
|
|
713
833
|
const label = title ?? pipe(name, capitalize);
|
|
714
|
-
const tupleType = findNode(ast,
|
|
834
|
+
const tupleType = findNode(ast, AST2.isTupleType);
|
|
715
835
|
const elementType = tupleType?.rest[0]?.type;
|
|
716
836
|
const getDefaultObjectValue = (typeNode) => {
|
|
717
837
|
const baseNode = findNode(typeNode, isDiscriminatedUnion);
|
|
718
|
-
const typeLiteral = baseNode ? getDiscriminatedType(baseNode, {}) : findNode(typeNode,
|
|
838
|
+
const typeLiteral = baseNode ? getDiscriminatedType(baseNode, {}) : findNode(typeNode, AST2.isTypeLiteral);
|
|
719
839
|
if (!typeLiteral) {
|
|
720
840
|
return {};
|
|
721
841
|
}
|
|
@@ -724,7 +844,7 @@ var ArrayField = ({ property, readonly, path, inputProps, Custom, lookupComponen
|
|
|
724
844
|
prop.defaultValue
|
|
725
845
|
]));
|
|
726
846
|
};
|
|
727
|
-
const newValue =
|
|
847
|
+
const newValue = useMemo3(() => {
|
|
728
848
|
if (type === "object" && elementType) {
|
|
729
849
|
return getDefaultObjectValue(elementType);
|
|
730
850
|
} else {
|
|
@@ -734,7 +854,7 @@ var ArrayField = ({ property, readonly, path, inputProps, Custom, lookupComponen
|
|
|
734
854
|
type,
|
|
735
855
|
elementType
|
|
736
856
|
]);
|
|
737
|
-
const handleAdd =
|
|
857
|
+
const handleAdd = useCallback5(() => {
|
|
738
858
|
inputProps.onValueChange(type, [
|
|
739
859
|
...values,
|
|
740
860
|
newValue
|
|
@@ -746,7 +866,7 @@ var ArrayField = ({ property, readonly, path, inputProps, Custom, lookupComponen
|
|
|
746
866
|
newValue,
|
|
747
867
|
values
|
|
748
868
|
]);
|
|
749
|
-
const handleRemove =
|
|
869
|
+
const handleRemove = useCallback5((index) => {
|
|
750
870
|
const newValues = values.filter((_, i) => i !== index);
|
|
751
871
|
inputProps.onValueChange(type, newValues);
|
|
752
872
|
}, [
|
|
@@ -804,8 +924,10 @@ var ArrayField = ({ property, readonly, path, inputProps, Custom, lookupComponen
|
|
|
804
924
|
import { FormatEnum } from "@dxos/echo-schema";
|
|
805
925
|
var getInputComponent = (type, format) => {
|
|
806
926
|
switch (format) {
|
|
807
|
-
case FormatEnum.
|
|
927
|
+
case FormatEnum.LatLong:
|
|
808
928
|
return GeoPointInput;
|
|
929
|
+
case FormatEnum.Markdown:
|
|
930
|
+
return MarkdownInput;
|
|
809
931
|
}
|
|
810
932
|
switch (type) {
|
|
811
933
|
case "string":
|
|
@@ -821,11 +943,11 @@ var getInputComponent = (type, format) => {
|
|
|
821
943
|
var FormField = ({ property, path, readonly, inline, lookupComponent, Custom }) => {
|
|
822
944
|
const inputProps = useInputProps(path);
|
|
823
945
|
const { ast, name, type, format, title, description, options, examples, array } = property;
|
|
824
|
-
const label =
|
|
946
|
+
const label = useMemo4(() => title ?? pipe2(name, capitalize2), [
|
|
825
947
|
title,
|
|
826
948
|
name
|
|
827
949
|
]);
|
|
828
|
-
const placeholder =
|
|
950
|
+
const placeholder = useMemo4(() => examples?.length ? `Example: "${examples[0]}"` : description, [
|
|
829
951
|
examples,
|
|
830
952
|
description
|
|
831
953
|
]);
|
|
@@ -849,20 +971,15 @@ var FormField = ({ property, path, readonly, inline, lookupComponent, Custom })
|
|
|
849
971
|
const jsonPath = createJsonPath3(path ?? []);
|
|
850
972
|
const CustomComponent = Custom?.[jsonPath];
|
|
851
973
|
if (CustomComponent) {
|
|
852
|
-
return (
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
placeholder,
|
|
862
|
-
disabled: readonly,
|
|
863
|
-
...inputProps
|
|
864
|
-
}))
|
|
865
|
-
);
|
|
974
|
+
return /* @__PURE__ */ React10.createElement(CustomComponent, {
|
|
975
|
+
type,
|
|
976
|
+
format,
|
|
977
|
+
label,
|
|
978
|
+
inputOnly: inline,
|
|
979
|
+
placeholder,
|
|
980
|
+
disabled: readonly,
|
|
981
|
+
...inputProps
|
|
982
|
+
});
|
|
866
983
|
}
|
|
867
984
|
if (array) {
|
|
868
985
|
return /* @__PURE__ */ React10.createElement(ArrayField, {
|
|
@@ -906,7 +1023,7 @@ var FormField = ({ property, path, readonly, inline, lookupComponent, Custom })
|
|
|
906
1023
|
}
|
|
907
1024
|
if (type === "object") {
|
|
908
1025
|
const baseNode = findNode2(ast, isDiscriminatedUnion2);
|
|
909
|
-
const typeLiteral = baseNode ? getDiscriminatedType2(baseNode, inputProps.getValue()) : findNode2(ast,
|
|
1026
|
+
const typeLiteral = baseNode ? getDiscriminatedType2(baseNode, inputProps.getValue()) : findNode2(ast, AST3.isTypeLiteral);
|
|
910
1027
|
if (typeLiteral) {
|
|
911
1028
|
return /* @__PURE__ */ React10.createElement("div", {
|
|
912
1029
|
role: "none"
|
|
@@ -922,7 +1039,7 @@ var FormField = ({ property, path, readonly, inline, lookupComponent, Custom })
|
|
|
922
1039
|
};
|
|
923
1040
|
var FormFields = ({ schema, path, filter, sort, readonly, lookupComponent, Custom }) => {
|
|
924
1041
|
const values = useFormValues(path);
|
|
925
|
-
const properties =
|
|
1042
|
+
const properties = useMemo4(() => {
|
|
926
1043
|
const props = getSchemaProperties2(schema.ast, values);
|
|
927
1044
|
const filtered = filter ? filter(props) : props;
|
|
928
1045
|
return sort ? filtered.sort((a, b) => sort.indexOf(a.name) - sort.indexOf(b.name)) : filtered;
|
|
@@ -934,7 +1051,7 @@ var FormFields = ({ schema, path, filter, sort, readonly, lookupComponent, Custo
|
|
|
934
1051
|
]);
|
|
935
1052
|
return /* @__PURE__ */ React10.createElement("div", {
|
|
936
1053
|
role: "form",
|
|
937
|
-
className: mx6("flex flex-col w-full gap-2
|
|
1054
|
+
className: mx6("flex flex-col w-full gap-2")
|
|
938
1055
|
}, properties.map((property) => {
|
|
939
1056
|
return /* @__PURE__ */ React10.createElement(FormField, {
|
|
940
1057
|
key: property.name,
|
|
@@ -951,19 +1068,33 @@ var FormFields = ({ schema, path, filter, sort, readonly, lookupComponent, Custo
|
|
|
951
1068
|
};
|
|
952
1069
|
|
|
953
1070
|
// packages/ui/react-ui-form/src/components/Form/Form.tsx
|
|
954
|
-
var Form = ({ classNames, schema, values: initialValues, path = [], readonly, filter, sort, autoSave, testId, onValuesChanged, onValidate, onSave, onCancel, lookupComponent, Custom }) => {
|
|
955
|
-
const
|
|
1071
|
+
var Form = ({ classNames, schema, values: initialValues, path = [], autoFocus, readonly, filter, sort, autoSave, testId, onValuesChanged, onValidate, onSave, onCancel, lookupComponent, Custom }) => {
|
|
1072
|
+
const formRef = useRef3(null);
|
|
1073
|
+
const onValid = useMemo5(() => autoSave ? onSave : void 0, [
|
|
956
1074
|
autoSave,
|
|
957
1075
|
onSave
|
|
958
1076
|
]);
|
|
1077
|
+
useEffect6(() => {
|
|
1078
|
+
if (autoFocus && formRef.current) {
|
|
1079
|
+
const input = formRef.current.querySelector("input");
|
|
1080
|
+
if (input) {
|
|
1081
|
+
input.focus();
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
}, [
|
|
1085
|
+
autoFocus
|
|
1086
|
+
]);
|
|
959
1087
|
return /* @__PURE__ */ React11.createElement(FormProvider, {
|
|
1088
|
+
formRef,
|
|
960
1089
|
schema,
|
|
1090
|
+
autoSave,
|
|
961
1091
|
initialValues,
|
|
962
1092
|
onValuesChanged,
|
|
963
1093
|
onValidate,
|
|
964
1094
|
onValid,
|
|
965
1095
|
onSave
|
|
966
1096
|
}, /* @__PURE__ */ React11.createElement("div", {
|
|
1097
|
+
ref: formRef,
|
|
967
1098
|
role: "none",
|
|
968
1099
|
className: mx7("p-2", classNames),
|
|
969
1100
|
"data-testid": testId
|
|
@@ -985,13 +1116,13 @@ var Form = ({ classNames, schema, values: initialValues, path = [], readonly, fi
|
|
|
985
1116
|
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx";
|
|
986
1117
|
var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
987
1118
|
const { t } = useTranslation5(translationKey);
|
|
988
|
-
const [props, setProps] =
|
|
989
|
-
|
|
1119
|
+
const [props, setProps] = useState4(projection.getFieldProjection(field.id).props);
|
|
1120
|
+
useEffect7(() => setProps(projection.getFieldProjection(field.id).props), [
|
|
990
1121
|
field,
|
|
991
1122
|
projection
|
|
992
1123
|
]);
|
|
993
|
-
const [schemas, setSchemas] =
|
|
994
|
-
|
|
1124
|
+
const [schemas, setSchemas] = useState4([]);
|
|
1125
|
+
useEffect7(() => {
|
|
995
1126
|
if (!registry) {
|
|
996
1127
|
return;
|
|
997
1128
|
}
|
|
@@ -1009,17 +1140,17 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
1009
1140
|
}, [
|
|
1010
1141
|
registry
|
|
1011
1142
|
]);
|
|
1012
|
-
const [referenceSchema, setReferenceSchema] =
|
|
1013
|
-
|
|
1143
|
+
const [referenceSchema, setReferenceSchema] = useState4();
|
|
1144
|
+
useEffect7(() => {
|
|
1014
1145
|
setReferenceSchema(schemas.find((schema) => schema.typename === props?.referenceSchema));
|
|
1015
1146
|
}, [
|
|
1016
1147
|
schemas,
|
|
1017
1148
|
props?.referenceSchema
|
|
1018
1149
|
]);
|
|
1019
|
-
const [{ fieldSchema }, setFieldSchema] =
|
|
1150
|
+
const [{ fieldSchema }, setFieldSchema] = useState4({
|
|
1020
1151
|
fieldSchema: getFormatSchema(props?.format)
|
|
1021
1152
|
});
|
|
1022
|
-
const handleValuesChanged =
|
|
1153
|
+
const handleValuesChanged = useCallback6((_props) => {
|
|
1023
1154
|
setFieldSchema((prev) => {
|
|
1024
1155
|
const fieldSchema2 = getFormatSchema(_props.format);
|
|
1025
1156
|
if (prev.fieldSchema === fieldSchema2) {
|
|
@@ -1054,7 +1185,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
1054
1185
|
props.format,
|
|
1055
1186
|
props.referenceSchema
|
|
1056
1187
|
]);
|
|
1057
|
-
const handleValidate =
|
|
1188
|
+
const handleValidate = useCallback6(({ property }) => {
|
|
1058
1189
|
if (property && view.fields.find((f) => f.path === property && f.path !== field.path)) {
|
|
1059
1190
|
return [
|
|
1060
1191
|
{
|
|
@@ -1067,7 +1198,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
1067
1198
|
view.fields,
|
|
1068
1199
|
field
|
|
1069
1200
|
]);
|
|
1070
|
-
const handleSave =
|
|
1201
|
+
const handleSave = useCallback6((props2) => {
|
|
1071
1202
|
projection.setFieldProjection({
|
|
1072
1203
|
field,
|
|
1073
1204
|
props: props2
|
|
@@ -1078,13 +1209,13 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
1078
1209
|
field,
|
|
1079
1210
|
onSave
|
|
1080
1211
|
]);
|
|
1081
|
-
const handleCancel =
|
|
1212
|
+
const handleCancel = useCallback6(() => {
|
|
1082
1213
|
requestAnimationFrame(() => onCancel?.());
|
|
1083
1214
|
onSave();
|
|
1084
1215
|
}, [
|
|
1085
1216
|
onSave
|
|
1086
1217
|
]);
|
|
1087
|
-
const Custom =
|
|
1218
|
+
const Custom = useMemo6(() => ({
|
|
1088
1219
|
["format"]: (props2) => /* @__PURE__ */ React12.createElement(SelectInput, {
|
|
1089
1220
|
...props2,
|
|
1090
1221
|
options: FormatEnums.filter((value) => value !== FormatEnum2.None).map((value) => ({
|
|
@@ -1110,7 +1241,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
1110
1241
|
schemas,
|
|
1111
1242
|
referenceSchema
|
|
1112
1243
|
]);
|
|
1113
|
-
const propIsNotType =
|
|
1244
|
+
const propIsNotType = useCallback6((props2) => props2.filter((p) => p.name !== "type"), []);
|
|
1114
1245
|
if (!fieldSchema) {
|
|
1115
1246
|
log2.warn("invalid format", {
|
|
1116
1247
|
props
|
|
@@ -1141,8 +1272,8 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
1141
1272
|
};
|
|
1142
1273
|
|
|
1143
1274
|
// packages/ui/react-ui-form/src/components/ViewEditor/ViewEditor.tsx
|
|
1144
|
-
import React13, { useCallback as
|
|
1145
|
-
import { AST as
|
|
1275
|
+
import React13, { useCallback as useCallback7, useMemo as useMemo7, useState as useState5 } from "react";
|
|
1276
|
+
import { AST as AST4, Format, S as S2 } from "@dxos/echo-schema";
|
|
1146
1277
|
import { IconButton as IconButton4, useTranslation as useTranslation6 } from "@dxos/react-ui";
|
|
1147
1278
|
import { List as List2 } from "@dxos/react-ui-list";
|
|
1148
1279
|
import { ghostHover, inputTextLabel, mx as mx8 } from "@dxos/react-ui-theme";
|
|
@@ -1150,20 +1281,20 @@ import { FieldSchema, ViewProjection, VIEW_FIELD_LIMIT } from "@dxos/schema";
|
|
|
1150
1281
|
var grid = "grid grid-cols-[32px_1fr_32px] min-bs-[2.5rem]";
|
|
1151
1282
|
var ViewMetaSchema = S2.Struct({
|
|
1152
1283
|
name: S2.String.annotations({
|
|
1153
|
-
[
|
|
1284
|
+
[AST4.TitleAnnotationId]: "View"
|
|
1154
1285
|
}),
|
|
1155
|
-
typename: Format.
|
|
1156
|
-
[
|
|
1286
|
+
typename: Format.URL.annotations({
|
|
1287
|
+
[AST4.TitleAnnotationId]: "Typename"
|
|
1157
1288
|
})
|
|
1158
1289
|
}).pipe(S2.mutable);
|
|
1159
1290
|
var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading = false, onTypenameChanged, onDelete }) => {
|
|
1160
1291
|
const { t } = useTranslation6(translationKey);
|
|
1161
|
-
const projection =
|
|
1292
|
+
const projection = useMemo7(() => new ViewProjection(schema, view), [
|
|
1162
1293
|
schema,
|
|
1163
1294
|
view
|
|
1164
1295
|
]);
|
|
1165
|
-
const [field, setField] =
|
|
1166
|
-
const viewValues =
|
|
1296
|
+
const [field, setField] = useState5();
|
|
1297
|
+
const viewValues = useMemo7(() => {
|
|
1167
1298
|
return {
|
|
1168
1299
|
name: view.name,
|
|
1169
1300
|
// TODO(burdon): Need to warn user of possible consequences of editing.
|
|
@@ -1173,7 +1304,7 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
|
|
|
1173
1304
|
}, [
|
|
1174
1305
|
view
|
|
1175
1306
|
]);
|
|
1176
|
-
const handleViewUpdate =
|
|
1307
|
+
const handleViewUpdate = useCallback7(({ name, typename }) => {
|
|
1177
1308
|
requestAnimationFrame(() => {
|
|
1178
1309
|
if (view.name !== name) {
|
|
1179
1310
|
view.name = name;
|
|
@@ -1187,16 +1318,16 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
|
|
|
1187
1318
|
schema,
|
|
1188
1319
|
onTypenameChanged
|
|
1189
1320
|
]);
|
|
1190
|
-
const handleSelect =
|
|
1321
|
+
const handleSelect = useCallback7((field2) => {
|
|
1191
1322
|
setField((f) => f === field2 ? void 0 : field2);
|
|
1192
1323
|
}, []);
|
|
1193
|
-
const handleAdd =
|
|
1324
|
+
const handleAdd = useCallback7(() => {
|
|
1194
1325
|
const field2 = projection.createFieldProjection();
|
|
1195
1326
|
setField(field2);
|
|
1196
1327
|
}, [
|
|
1197
1328
|
view
|
|
1198
1329
|
]);
|
|
1199
|
-
const handleMove =
|
|
1330
|
+
const handleMove = useCallback7((fromIndex, toIndex) => {
|
|
1200
1331
|
const fields = [
|
|
1201
1332
|
...view.fields
|
|
1202
1333
|
];
|
|
@@ -1206,12 +1337,11 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
|
|
|
1206
1337
|
}, [
|
|
1207
1338
|
view.fields
|
|
1208
1339
|
]);
|
|
1209
|
-
const handleClose =
|
|
1340
|
+
const handleClose = useCallback7(() => setField(void 0), []);
|
|
1210
1341
|
return /* @__PURE__ */ React13.createElement("div", {
|
|
1211
1342
|
role: "none",
|
|
1212
1343
|
className: mx8("flex flex-col w-full divide-y divide-separator", classNames)
|
|
1213
1344
|
}, /* @__PURE__ */ React13.createElement(Form, {
|
|
1214
|
-
autoFocus: true,
|
|
1215
1345
|
autoSave: true,
|
|
1216
1346
|
schema: ViewMetaSchema,
|
|
1217
1347
|
values: viewValues,
|
|
@@ -1262,7 +1392,7 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
|
|
|
1262
1392
|
};
|
|
1263
1393
|
|
|
1264
1394
|
// packages/ui/react-ui-form/src/util/field.ts
|
|
1265
|
-
import { FormatEnum as FormatEnum3, TypeEnum } from "@dxos/echo-schema";
|
|
1395
|
+
import { FormatEnum as FormatEnum3, GeoLocation as GeoLocation2, TypeEnum } from "@dxos/echo-schema";
|
|
1266
1396
|
var parseValue = ({ type, format, value }) => {
|
|
1267
1397
|
if (value === void 0 || value === null || value === "") {
|
|
1268
1398
|
return void 0;
|
|
@@ -1316,6 +1446,26 @@ var parseValue = ({ type, format, value }) => {
|
|
|
1316
1446
|
const date = new Date(value);
|
|
1317
1447
|
return isNaN(date.getTime()) ? null : date;
|
|
1318
1448
|
}
|
|
1449
|
+
case FormatEnum3.LatLong: {
|
|
1450
|
+
if (typeof value === "string") {
|
|
1451
|
+
const cleaned = value.replace(/[^0-9.,-]+/g, "");
|
|
1452
|
+
const parts = cleaned.split(",");
|
|
1453
|
+
if (parts.length === 2) {
|
|
1454
|
+
const lat = parseFloat(parts[0]);
|
|
1455
|
+
const long = parseFloat(parts[1]);
|
|
1456
|
+
if (!isNaN(lat) && !isNaN(long)) {
|
|
1457
|
+
return GeoLocation2.toGeoPoint({
|
|
1458
|
+
latitude: lat,
|
|
1459
|
+
longitude: long
|
|
1460
|
+
});
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
return [
|
|
1465
|
+
0,
|
|
1466
|
+
0
|
|
1467
|
+
];
|
|
1468
|
+
}
|
|
1319
1469
|
default: {
|
|
1320
1470
|
return value;
|
|
1321
1471
|
}
|
|
@@ -1374,7 +1524,7 @@ var pathNotUniqueError = (path) => ({
|
|
|
1374
1524
|
});
|
|
1375
1525
|
|
|
1376
1526
|
// packages/ui/react-ui-form/src/util/formatting.ts
|
|
1377
|
-
import { FormatEnum as FormatEnum4, TypeEnum as TypeEnum2 } from "@dxos/echo-schema";
|
|
1527
|
+
import { FormatEnum as FormatEnum4, GeoLocation as GeoLocation3, TypeEnum as TypeEnum2 } from "@dxos/echo-schema";
|
|
1378
1528
|
var formatForDisplay = ({ type, format, value, locale = void 0 }) => {
|
|
1379
1529
|
const formatScalar = (type2) => {
|
|
1380
1530
|
switch (type2) {
|
|
@@ -1427,6 +1577,16 @@ var formatForDisplay = ({ type, format, value, locale = void 0 }) => {
|
|
|
1427
1577
|
return date.toLocaleTimeString(locale);
|
|
1428
1578
|
}
|
|
1429
1579
|
}
|
|
1580
|
+
case FormatEnum4.LatLong: {
|
|
1581
|
+
if (value === null || value === void 0) {
|
|
1582
|
+
return "";
|
|
1583
|
+
}
|
|
1584
|
+
if (Array.isArray(value) && value.length >= 2 && value.every(Number.isFinite)) {
|
|
1585
|
+
const { latitude, longitude } = GeoLocation3.fromGeoPoint(value);
|
|
1586
|
+
return `${latitude},${longitude}`;
|
|
1587
|
+
}
|
|
1588
|
+
return String(value);
|
|
1589
|
+
}
|
|
1430
1590
|
default: {
|
|
1431
1591
|
if (value === null || value === "undefined") {
|
|
1432
1592
|
return "";
|
|
@@ -1475,6 +1635,16 @@ var formatForEditing = ({ type, format, value, locale = void 0 }) => {
|
|
|
1475
1635
|
const date = new Date(value);
|
|
1476
1636
|
return date.toISOString().split("T")[1].split(".")[0];
|
|
1477
1637
|
}
|
|
1638
|
+
case FormatEnum4.LatLong: {
|
|
1639
|
+
if (value === null || value === void 0) {
|
|
1640
|
+
return "";
|
|
1641
|
+
}
|
|
1642
|
+
if (Array.isArray(value) && value.length >= 2 && value.every(Number.isFinite)) {
|
|
1643
|
+
const { latitude, longitude } = GeoLocation3.fromGeoPoint(value);
|
|
1644
|
+
return `${latitude},${longitude}`;
|
|
1645
|
+
}
|
|
1646
|
+
return String(value);
|
|
1647
|
+
}
|
|
1478
1648
|
default: {
|
|
1479
1649
|
return String(value);
|
|
1480
1650
|
}
|
|
@@ -1488,6 +1658,7 @@ export {
|
|
|
1488
1658
|
Form,
|
|
1489
1659
|
GeoPointInput,
|
|
1490
1660
|
InputHeader,
|
|
1661
|
+
MarkdownInput,
|
|
1491
1662
|
NumberInput,
|
|
1492
1663
|
SelectInput,
|
|
1493
1664
|
SelectOptionInput,
|
|
@@ -1501,6 +1672,7 @@ export {
|
|
|
1501
1672
|
parseValue,
|
|
1502
1673
|
pathNotUniqueError,
|
|
1503
1674
|
translations_default as translations,
|
|
1504
|
-
useForm
|
|
1675
|
+
useForm,
|
|
1676
|
+
useFormValues
|
|
1505
1677
|
};
|
|
1506
1678
|
//# sourceMappingURL=index.mjs.map
|