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