@dxos/react-ui-form 0.7.5-labs.8a82073 → 0.7.5-labs.c0e040f
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 +398 -323
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +381 -302
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +398 -323
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/components/Form/Defaults.d.ts +1 -0
- package/dist/types/src/components/Form/Defaults.d.ts.map +1 -1
- package/dist/types/src/components/Form/Form.d.ts.map +1 -1
- 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/custom/SelectOptionsInput.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/hooks/useForm.d.ts +1 -0
- package/dist/types/src/hooks/useForm.d.ts.map +1 -1
- package/package.json +24 -24
- package/src/components/Form/Defaults.tsx +59 -3
- package/src/components/Form/Form.tsx +8 -5
- package/src/components/Form/FormContent.tsx +9 -12
- package/src/components/Form/FormContext.tsx +48 -4
- package/src/components/Form/custom/SelectOptionsInput.tsx +5 -7
- package/src/components/Form/factory.tsx +3 -1
- package/src/components/Form/index.ts +3 -0
- package/src/components/ViewEditor/ViewEditor.tsx +2 -2
- package/src/hooks/useForm.ts +6 -0
|
@@ -99,34 +99,275 @@ var DeprecatedFormInput = ({ label, description, secondary, children }) => {
|
|
|
99
99
|
};
|
|
100
100
|
|
|
101
101
|
// packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx
|
|
102
|
-
import React12, { useCallback as
|
|
102
|
+
import React12, { useCallback as useCallback5, useEffect as useEffect6, useMemo as useMemo5, useState as useState3 } from "react";
|
|
103
103
|
import { FormatEnum as FormatEnum2, FormatEnums, formatToType } from "@dxos/echo-schema";
|
|
104
104
|
import { log as log2 } from "@dxos/log";
|
|
105
105
|
import { useTranslation as useTranslation5 } from "@dxos/react-ui";
|
|
106
106
|
import { getFormatSchema, getSchemaProperties as getSchemaProperties3, sortProperties } from "@dxos/schema";
|
|
107
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
|
+
|
|
108
349
|
// packages/ui/react-ui-form/src/components/Form/custom/GeoPointInput.tsx
|
|
109
|
-
import
|
|
350
|
+
import React4 from "react";
|
|
110
351
|
import { Input as Input2, useTranslation } from "@dxos/react-ui";
|
|
111
352
|
import { safeParseFloat } from "@dxos/util";
|
|
112
353
|
|
|
113
354
|
// packages/ui/react-ui-form/src/components/Form/Input.tsx
|
|
114
|
-
import
|
|
355
|
+
import React3 from "react";
|
|
115
356
|
import { Icon, Tooltip } from "@dxos/react-ui";
|
|
116
357
|
import { errorText } from "@dxos/react-ui-theme";
|
|
117
358
|
var InputHeader = ({ children, error }) => {
|
|
118
|
-
return /* @__PURE__ */
|
|
359
|
+
return /* @__PURE__ */ React3.createElement("div", {
|
|
119
360
|
role: "none",
|
|
120
361
|
className: "flex justify-between items-center mb-1"
|
|
121
|
-
}, children, error && /* @__PURE__ */
|
|
362
|
+
}, children, error && /* @__PURE__ */ React3.createElement(Tooltip.Root, null, /* @__PURE__ */ React3.createElement(Tooltip.Trigger, {
|
|
122
363
|
asChild: true
|
|
123
|
-
}, /* @__PURE__ */
|
|
364
|
+
}, /* @__PURE__ */ React3.createElement(Icon, {
|
|
124
365
|
icon: "ph--warning--regular",
|
|
125
366
|
size: 4,
|
|
126
367
|
classNames: errorText
|
|
127
|
-
})), /* @__PURE__ */
|
|
368
|
+
})), /* @__PURE__ */ React3.createElement(Tooltip.Content, {
|
|
128
369
|
side: "bottom"
|
|
129
|
-
}, /* @__PURE__ */
|
|
370
|
+
}, /* @__PURE__ */ React3.createElement(Tooltip.Arrow, null), error)));
|
|
130
371
|
};
|
|
131
372
|
|
|
132
373
|
// packages/ui/react-ui-form/src/components/Form/custom/GeoPointInput.tsx
|
|
@@ -134,13 +375,13 @@ var GeoPointInput = ({ type, label, disabled, getStatus, getValue: getValue3, on
|
|
|
134
375
|
const { t } = useTranslation(translationKey);
|
|
135
376
|
const { status, error } = getStatus();
|
|
136
377
|
const [lng = 0, lat = 0] = getValue3() ?? [];
|
|
137
|
-
return /* @__PURE__ */
|
|
378
|
+
return /* @__PURE__ */ React4.createElement(Input2.Root, {
|
|
138
379
|
validationValence: status
|
|
139
|
-
}, /* @__PURE__ */
|
|
380
|
+
}, /* @__PURE__ */ React4.createElement(InputHeader, {
|
|
140
381
|
error
|
|
141
|
-
}, /* @__PURE__ */
|
|
382
|
+
}, /* @__PURE__ */ React4.createElement(Input2.Label, null, label)), /* @__PURE__ */ React4.createElement("div", {
|
|
142
383
|
className: "grid grid-cols-2 gap-2"
|
|
143
|
-
}, /* @__PURE__ */
|
|
384
|
+
}, /* @__PURE__ */ React4.createElement(Input2.TextInput, {
|
|
144
385
|
type: "number",
|
|
145
386
|
disabled,
|
|
146
387
|
placeholder: t("placeholder longitude"),
|
|
@@ -150,7 +391,7 @@ var GeoPointInput = ({ type, label, disabled, getStatus, getValue: getValue3, on
|
|
|
150
391
|
safeParseFloat(event.target.value, 0)
|
|
151
392
|
]),
|
|
152
393
|
onBlur
|
|
153
|
-
}), /* @__PURE__ */
|
|
394
|
+
}), /* @__PURE__ */ React4.createElement(Input2.TextInput, {
|
|
154
395
|
type: "number",
|
|
155
396
|
disabled,
|
|
156
397
|
placeholder: t("placeholder latitude"),
|
|
@@ -164,20 +405,20 @@ var GeoPointInput = ({ type, label, disabled, getStatus, getValue: getValue3, on
|
|
|
164
405
|
};
|
|
165
406
|
|
|
166
407
|
// packages/ui/react-ui-form/src/components/Form/custom/SelectOptionsInput.tsx
|
|
167
|
-
import
|
|
408
|
+
import React5, { useCallback as useCallback2, useEffect as useEffect3, useState as useState2, useRef } from "react";
|
|
168
409
|
import { PublicKey } from "@dxos/keys";
|
|
169
410
|
import { Icon as Icon2, IconButton, Input as Input3, Tag, Toolbar, useTranslation as useTranslation2 } from "@dxos/react-ui";
|
|
170
411
|
import { List } from "@dxos/react-ui-list";
|
|
171
412
|
import { HuePickerToolbarButton } from "@dxos/react-ui-pickers";
|
|
172
|
-
import {
|
|
413
|
+
import { hues, mx as mx2 } from "@dxos/react-ui-theme";
|
|
173
414
|
var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3, onValueChange }) => {
|
|
174
|
-
const [selected, setSelectedId] =
|
|
175
|
-
const [isNewOption, setIsNewOption] =
|
|
415
|
+
const [selected, setSelectedId] = useState2(null);
|
|
416
|
+
const [isNewOption, setIsNewOption] = useState2(false);
|
|
176
417
|
const inputRef = useRef(null);
|
|
177
418
|
const { t } = useTranslation2(translationKey);
|
|
178
419
|
const { status, error } = getStatus();
|
|
179
420
|
const options = getValue3();
|
|
180
|
-
|
|
421
|
+
useEffect3(() => {
|
|
181
422
|
if (options === void 0) {
|
|
182
423
|
onValueChange(type, []);
|
|
183
424
|
}
|
|
@@ -188,16 +429,15 @@ var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3
|
|
|
188
429
|
]);
|
|
189
430
|
const randomHue = () => {
|
|
190
431
|
const usedHues = new Set(options?.map((option) => option.color) ?? []);
|
|
191
|
-
const
|
|
192
|
-
const unusedHues = hueKeys.filter((hue) => !usedHues.has(hue));
|
|
432
|
+
const unusedHues = hues.filter((hue) => !usedHues.has(hue));
|
|
193
433
|
if (unusedHues.length > 0) {
|
|
194
434
|
return unusedHues[Math.floor(Math.random() * unusedHues.length)];
|
|
195
435
|
}
|
|
196
436
|
const lastThree = new Set(options?.slice(-3).map((option) => option.color) ?? []);
|
|
197
|
-
const availableHues =
|
|
198
|
-
return availableHues[Math.floor(Math.random() * availableHues.length)] ??
|
|
437
|
+
const availableHues = hues.filter((hue) => !lastThree.has(hue));
|
|
438
|
+
return availableHues[Math.floor(Math.random() * availableHues.length)] ?? hues[Math.floor(Math.random() * hues.length)];
|
|
199
439
|
};
|
|
200
|
-
const handleAdd =
|
|
440
|
+
const handleAdd = useCallback2(() => {
|
|
201
441
|
const newId = PublicKey.random().truncate();
|
|
202
442
|
const newOption = {
|
|
203
443
|
id: newId,
|
|
@@ -215,7 +455,7 @@ var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3
|
|
|
215
455
|
type,
|
|
216
456
|
onValueChange
|
|
217
457
|
]);
|
|
218
|
-
const handleDelete =
|
|
458
|
+
const handleDelete = useCallback2((id) => {
|
|
219
459
|
const newOptions = options?.filter((option) => option.id !== id) ?? [];
|
|
220
460
|
onValueChange(type, newOptions);
|
|
221
461
|
setSelectedId(null);
|
|
@@ -224,7 +464,7 @@ var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3
|
|
|
224
464
|
type,
|
|
225
465
|
onValueChange
|
|
226
466
|
]);
|
|
227
|
-
const handleMove =
|
|
467
|
+
const handleMove = useCallback2((from, to) => {
|
|
228
468
|
if (!options) {
|
|
229
469
|
return;
|
|
230
470
|
}
|
|
@@ -239,10 +479,10 @@ var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3
|
|
|
239
479
|
type,
|
|
240
480
|
onValueChange
|
|
241
481
|
]);
|
|
242
|
-
const handleClick =
|
|
482
|
+
const handleClick = useCallback2((id) => {
|
|
243
483
|
setSelectedId((current) => current === id ? null : id);
|
|
244
484
|
}, []);
|
|
245
|
-
const handleTitleChange =
|
|
485
|
+
const handleTitleChange = useCallback2((id) => (e) => {
|
|
246
486
|
const newOptions = options?.map((o) => o.id === id ? {
|
|
247
487
|
...o,
|
|
248
488
|
title: e.target.value
|
|
@@ -253,12 +493,12 @@ var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3
|
|
|
253
493
|
type,
|
|
254
494
|
onValueChange
|
|
255
495
|
]);
|
|
256
|
-
const handleKeyDown =
|
|
496
|
+
const handleKeyDown = useCallback2((e) => {
|
|
257
497
|
if (e.key === "Enter") {
|
|
258
498
|
setSelectedId(null);
|
|
259
499
|
}
|
|
260
500
|
}, []);
|
|
261
|
-
const handleColorChange =
|
|
501
|
+
const handleColorChange = useCallback2((id) => (hue) => {
|
|
262
502
|
const newOptions = options?.map((o) => o.id === id ? {
|
|
263
503
|
...o,
|
|
264
504
|
color: hue
|
|
@@ -269,7 +509,7 @@ var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3
|
|
|
269
509
|
type,
|
|
270
510
|
onValueChange
|
|
271
511
|
]);
|
|
272
|
-
|
|
512
|
+
useEffect3(() => {
|
|
273
513
|
if (selected && isNewOption && inputRef.current) {
|
|
274
514
|
inputRef.current.focus();
|
|
275
515
|
setIsNewOption(false);
|
|
@@ -278,76 +518,77 @@ var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3
|
|
|
278
518
|
selected,
|
|
279
519
|
isNewOption
|
|
280
520
|
]);
|
|
281
|
-
return /* @__PURE__ */
|
|
521
|
+
return /* @__PURE__ */ React5.createElement(Input3.Root, {
|
|
282
522
|
validationValence: status
|
|
283
|
-
}, /* @__PURE__ */
|
|
523
|
+
}, /* @__PURE__ */ React5.createElement(InputHeader, {
|
|
284
524
|
error
|
|
285
|
-
}, /* @__PURE__ */
|
|
525
|
+
}, /* @__PURE__ */ React5.createElement(Input3.Label, null, label)), /* @__PURE__ */ React5.createElement("div", {
|
|
286
526
|
role: "none"
|
|
287
|
-
}, options && /* @__PURE__ */
|
|
527
|
+
}, options && /* @__PURE__ */ React5.createElement(List.Root, {
|
|
288
528
|
items: options,
|
|
289
529
|
isItem: (item) => true,
|
|
290
530
|
onMove: handleMove
|
|
291
|
-
}, ({ items }) => /* @__PURE__ */
|
|
531
|
+
}, ({ items }) => /* @__PURE__ */ React5.createElement("div", {
|
|
292
532
|
role: "list",
|
|
293
533
|
className: "w-full overflow-auto"
|
|
294
|
-
}, items?.map((item) => /* @__PURE__ */
|
|
534
|
+
}, items?.map((item) => /* @__PURE__ */ React5.createElement("div", {
|
|
295
535
|
key: item.id
|
|
296
|
-
}, /* @__PURE__ */
|
|
536
|
+
}, /* @__PURE__ */ React5.createElement(List.Item, {
|
|
297
537
|
role: "button",
|
|
298
538
|
item,
|
|
299
539
|
classNames: mx2("p-1 plb-2", "flex flex-col", "cursor-pointer", "hover:bg-hoverOverlay"),
|
|
300
540
|
"aria-expanded": selected === item.id
|
|
301
|
-
}, /* @__PURE__ */
|
|
541
|
+
}, /* @__PURE__ */ React5.createElement("div", {
|
|
302
542
|
className: "flex items-center"
|
|
303
|
-
}, /* @__PURE__ */
|
|
543
|
+
}, /* @__PURE__ */ React5.createElement(List.ItemDragHandle, null), /* @__PURE__ */ React5.createElement(List.ItemTitle, {
|
|
304
544
|
onClick: () => handleClick(item.id),
|
|
305
545
|
classNames: "flex-1"
|
|
306
|
-
}, /* @__PURE__ */
|
|
546
|
+
}, /* @__PURE__ */ React5.createElement(Tag, {
|
|
307
547
|
palette: item.color
|
|
308
|
-
}, item.title || "\u200B")), /* @__PURE__ */
|
|
548
|
+
}, item.title || "\u200B")), /* @__PURE__ */ React5.createElement(Icon2, {
|
|
309
549
|
icon: selected === item.id ? "ph--caret-down--regular" : "ph--caret-right--regular",
|
|
310
550
|
onClick: () => handleClick(item.id)
|
|
311
|
-
})), selected === item.id && /* @__PURE__ */
|
|
551
|
+
})), selected === item.id && /* @__PURE__ */ React5.createElement("div", {
|
|
312
552
|
className: "mis-4 mbs-2 flex flex-col gap-1"
|
|
313
|
-
}, /* @__PURE__ */
|
|
553
|
+
}, /* @__PURE__ */ React5.createElement(Input3.Label, {
|
|
314
554
|
classNames: "text-xs"
|
|
315
|
-
}, t("select option label")), /* @__PURE__ */
|
|
555
|
+
}, t("select option label")), /* @__PURE__ */ React5.createElement("div", {
|
|
316
556
|
className: "flex flex-row items-center gap-1"
|
|
317
|
-
}, /* @__PURE__ */
|
|
557
|
+
}, /* @__PURE__ */ React5.createElement(Input3.TextInput, {
|
|
318
558
|
placeholder: t("select option label placeholder"),
|
|
319
559
|
ref: selected === item.id ? inputRef : void 0,
|
|
320
560
|
value: item.title,
|
|
321
561
|
onChange: handleTitleChange(item.id),
|
|
322
562
|
onKeyDown: handleKeyDown,
|
|
323
|
-
classNames: "flex-1"
|
|
324
|
-
|
|
563
|
+
classNames: "flex-1",
|
|
564
|
+
"data-no-submit": true
|
|
565
|
+
}), /* @__PURE__ */ React5.createElement(Toolbar.Root, {
|
|
325
566
|
classNames: "p-0 m-0 !is-auto"
|
|
326
|
-
}, /* @__PURE__ */
|
|
567
|
+
}, /* @__PURE__ */ React5.createElement(HuePickerToolbarButton, {
|
|
327
568
|
hue: item.color,
|
|
328
569
|
onChangeHue: handleColorChange(item.id)
|
|
329
|
-
})), /* @__PURE__ */
|
|
570
|
+
})), /* @__PURE__ */ React5.createElement(IconButton, {
|
|
330
571
|
icon: "ph--trash--fill",
|
|
331
572
|
iconOnly: true,
|
|
332
573
|
label: t("select option delete"),
|
|
333
574
|
onClick: () => handleDelete(item.id)
|
|
334
|
-
})))))), /* @__PURE__ */
|
|
575
|
+
})))))), /* @__PURE__ */ React5.createElement("div", {
|
|
335
576
|
role: "listitem"
|
|
336
|
-
}, /* @__PURE__ */
|
|
577
|
+
}, /* @__PURE__ */ React5.createElement("div", {
|
|
337
578
|
role: "button",
|
|
338
579
|
className: mx2("p-1 plb-2", "flex flex-col", "cursor-pointer", "hover:bg-hoverOverlay"),
|
|
339
580
|
onClick: handleAdd
|
|
340
|
-
}, /* @__PURE__ */
|
|
581
|
+
}, /* @__PURE__ */ React5.createElement("div", {
|
|
341
582
|
className: "flex items-center gap-1"
|
|
342
|
-
}, /* @__PURE__ */
|
|
583
|
+
}, /* @__PURE__ */ React5.createElement(Icon2, {
|
|
343
584
|
icon: "ph--plus--regular"
|
|
344
|
-
}), /* @__PURE__ */
|
|
585
|
+
}), /* @__PURE__ */ React5.createElement("span", {
|
|
345
586
|
className: "text-sm"
|
|
346
587
|
}, t("select option add")))))))));
|
|
347
588
|
};
|
|
348
589
|
|
|
349
590
|
// packages/ui/react-ui-form/src/components/Form/custom/TupleInput.tsx
|
|
350
|
-
import
|
|
591
|
+
import React6 from "react";
|
|
351
592
|
import { Input as Input4 } from "@dxos/react-ui";
|
|
352
593
|
import { mx as mx3 } from "@dxos/react-ui-theme";
|
|
353
594
|
import { safeParseFloat as safeParseFloat2 } from "@dxos/util";
|
|
@@ -360,13 +601,13 @@ var gridCols = [
|
|
|
360
601
|
var TupleInput = ({ binding, type, label, disabled, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
|
|
361
602
|
const { status, error } = getStatus();
|
|
362
603
|
const values = getValue3() ?? {};
|
|
363
|
-
return /* @__PURE__ */
|
|
604
|
+
return /* @__PURE__ */ React6.createElement(Input4.Root, {
|
|
364
605
|
validationValence: status
|
|
365
|
-
}, /* @__PURE__ */
|
|
606
|
+
}, /* @__PURE__ */ React6.createElement(InputHeader, {
|
|
366
607
|
error
|
|
367
|
-
}, /* @__PURE__ */
|
|
608
|
+
}, /* @__PURE__ */ React6.createElement(Input4.Label, null, label)), /* @__PURE__ */ React6.createElement("div", {
|
|
368
609
|
className: mx3("grid gap-2", gridCols[binding.length - 1])
|
|
369
|
-
}, binding.map((prop) => /* @__PURE__ */
|
|
610
|
+
}, binding.map((prop) => /* @__PURE__ */ React6.createElement(Input4.TextInput, {
|
|
370
611
|
key: prop,
|
|
371
612
|
type: "number",
|
|
372
613
|
disabled,
|
|
@@ -380,286 +621,118 @@ var TupleInput = ({ binding, type, label, disabled, getStatus, getValue: getValu
|
|
|
380
621
|
};
|
|
381
622
|
|
|
382
623
|
// packages/ui/react-ui-form/src/components/Form/Defaults.tsx
|
|
383
|
-
import
|
|
624
|
+
import React7, { useCallback as useCallback3, useEffect as useEffect4, useRef as useRef2 } from "react";
|
|
384
625
|
import { Input as Input5, Select } from "@dxos/react-ui";
|
|
385
626
|
var TextInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
|
|
386
627
|
const { status, error } = getStatus();
|
|
387
|
-
return /* @__PURE__ */
|
|
628
|
+
return /* @__PURE__ */ React7.createElement(Input5.Root, {
|
|
388
629
|
validationValence: status
|
|
389
|
-
}, !inputOnly && /* @__PURE__ */
|
|
630
|
+
}, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
|
|
390
631
|
error
|
|
391
|
-
}, /* @__PURE__ */
|
|
632
|
+
}, /* @__PURE__ */ React7.createElement(Input5.Label, null, label)), /* @__PURE__ */ React7.createElement(Input5.TextInput, {
|
|
392
633
|
disabled,
|
|
393
634
|
placeholder,
|
|
394
635
|
value: getValue3() ?? "",
|
|
395
636
|
onChange: (event) => onValueChange(type, event.target.value),
|
|
396
637
|
onBlur
|
|
397
|
-
}), inputOnly && /* @__PURE__ */
|
|
638
|
+
}), inputOnly && /* @__PURE__ */ React7.createElement(Input5.Validation, null, error));
|
|
398
639
|
};
|
|
399
640
|
var NumberInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
|
|
400
641
|
const { status, error } = getStatus();
|
|
401
|
-
return /* @__PURE__ */
|
|
642
|
+
return /* @__PURE__ */ React7.createElement(Input5.Root, {
|
|
402
643
|
validationValence: status
|
|
403
|
-
}, !inputOnly && /* @__PURE__ */
|
|
644
|
+
}, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
|
|
404
645
|
error
|
|
405
|
-
}, /* @__PURE__ */
|
|
646
|
+
}, /* @__PURE__ */ React7.createElement(Input5.Label, null, label)), /* @__PURE__ */ React7.createElement(Input5.TextInput, {
|
|
406
647
|
type: "number",
|
|
407
648
|
disabled,
|
|
408
649
|
placeholder,
|
|
409
650
|
value: getValue3() ?? 0,
|
|
410
651
|
onChange: (event) => onValueChange(type, event.target.value),
|
|
411
652
|
onBlur
|
|
412
|
-
}), inputOnly && /* @__PURE__ */
|
|
653
|
+
}), inputOnly && /* @__PURE__ */ React7.createElement(Input5.DescriptionAndValidation, null, error));
|
|
413
654
|
};
|
|
414
655
|
var BooleanInput = ({ type, label, inputOnly, getStatus, getValue: getValue3, onValueChange }) => {
|
|
415
656
|
const { status, error } = getStatus();
|
|
416
657
|
const checked = Boolean(getValue3());
|
|
417
|
-
return /* @__PURE__ */
|
|
658
|
+
return /* @__PURE__ */ React7.createElement(Input5.Root, {
|
|
418
659
|
validationValence: status
|
|
419
|
-
}, !inputOnly && /* @__PURE__ */
|
|
660
|
+
}, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
|
|
420
661
|
error
|
|
421
|
-
}, /* @__PURE__ */
|
|
662
|
+
}, /* @__PURE__ */ React7.createElement(Input5.Label, null, label)), /* @__PURE__ */ React7.createElement(Input5.Switch, {
|
|
422
663
|
checked,
|
|
423
664
|
onCheckedChange: (value) => onValueChange(type, value)
|
|
424
|
-
}), inputOnly && /* @__PURE__ */
|
|
665
|
+
}), inputOnly && /* @__PURE__ */ React7.createElement(Input5.DescriptionAndValidation, null, error));
|
|
425
666
|
};
|
|
426
667
|
var SelectInput = ({ type, label, inputOnly, disabled, placeholder, options, getStatus, getValue: getValue3, onValueChange }) => {
|
|
427
668
|
const { status, error } = getStatus();
|
|
428
|
-
return /* @__PURE__ */
|
|
669
|
+
return /* @__PURE__ */ React7.createElement(Input5.Root, {
|
|
429
670
|
validationValence: status
|
|
430
|
-
}, !inputOnly && /* @__PURE__ */
|
|
671
|
+
}, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
|
|
431
672
|
error
|
|
432
|
-
}, /* @__PURE__ */
|
|
673
|
+
}, /* @__PURE__ */ React7.createElement(Input5.Label, null, label)), /* @__PURE__ */ React7.createElement(Select.Root, {
|
|
433
674
|
value: getValue3(),
|
|
434
675
|
onValueChange: (value) => onValueChange(type, value)
|
|
435
|
-
}, /* @__PURE__ */
|
|
676
|
+
}, /* @__PURE__ */ React7.createElement(Select.TriggerButton, {
|
|
436
677
|
classNames: "is-full",
|
|
437
678
|
disabled,
|
|
438
679
|
placeholder
|
|
439
|
-
}), /* @__PURE__ */
|
|
680
|
+
}), /* @__PURE__ */ React7.createElement(Select.Portal, null, /* @__PURE__ */ React7.createElement(Select.Content, null, /* @__PURE__ */ React7.createElement(Select.Viewport, null, options?.map(({ value, label: label2 }) => (
|
|
440
681
|
// NOTE: Numeric values are converted to and from strings.
|
|
441
|
-
/* @__PURE__ */
|
|
682
|
+
/* @__PURE__ */ React7.createElement(Select.Option, {
|
|
442
683
|
key: String(value),
|
|
443
684
|
value: String(value)
|
|
444
685
|
}, label2 ?? String(value))
|
|
445
|
-
)))))), inputOnly && /* @__PURE__ */
|
|
686
|
+
)))))), inputOnly && /* @__PURE__ */ React7.createElement(Input5.DescriptionAndValidation, null, error));
|
|
446
687
|
};
|
|
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 { AST, 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
|
-
invariant(AST.isTypeLiteral(schema.ast), void 0, {
|
|
473
|
-
F: __dxlog_file,
|
|
474
|
-
L: 91,
|
|
475
|
-
S: void 0,
|
|
476
|
-
A: [
|
|
477
|
-
"AST.isTypeLiteral(schema.ast)",
|
|
478
|
-
""
|
|
479
|
-
]
|
|
480
|
-
});
|
|
481
|
-
const [values, setValues] = useState2(initialValues);
|
|
482
|
-
useEffect2(() => {
|
|
483
|
-
setValues(initialValues);
|
|
484
|
-
}, [
|
|
485
|
-
initialValues
|
|
486
|
-
]);
|
|
487
|
-
const [touched, setTouched] = useState2(createKeySet(initialValues, false));
|
|
488
|
-
const [changed, setChanged] = useState2(createKeySet(initialValues, false));
|
|
489
|
-
const [errors, setErrors] = useState2({});
|
|
490
|
-
const [saving, setSaving] = useState2(false);
|
|
491
|
-
const validate = useCallback2((values2) => {
|
|
492
|
-
let errors2 = validateSchema(schema, values2) ?? [];
|
|
493
|
-
if (errors2.length === 0 && onValidate) {
|
|
494
|
-
const validatedValues = values2;
|
|
495
|
-
errors2 = onValidate(validatedValues) ?? [];
|
|
496
|
-
}
|
|
497
|
-
setErrors(flatMap(errors2));
|
|
498
|
-
const valid = errors2.length === 0;
|
|
499
|
-
return valid;
|
|
500
|
-
}, [
|
|
501
|
-
schema,
|
|
502
|
-
onValidate
|
|
503
|
-
]);
|
|
504
|
-
const [schemaDirty, setSchemaDirty] = useState2(false);
|
|
505
|
-
useEffect2(() => setSchemaDirty(true), [
|
|
506
|
-
schema
|
|
507
|
-
]);
|
|
508
|
-
useEffect2(() => {
|
|
509
|
-
if (schemaDirty) {
|
|
510
|
-
validate(values);
|
|
511
|
-
setSchemaDirty(false);
|
|
512
|
-
}
|
|
513
|
-
}, [
|
|
514
|
-
values,
|
|
515
|
-
schemaDirty
|
|
516
|
-
]);
|
|
517
|
-
const canSave = useMemo(() => !saving && // Check if any error paths that are touched have errors
|
|
518
|
-
!Object.entries(touched).some(([path, isTouched]) => isTouched && Object.keys(errors).some((errorPath) => errorPath === path || errorPath.startsWith(`${path}.`) || errorPath.startsWith(`${path}[`))), [
|
|
519
|
-
touched,
|
|
520
|
-
errors,
|
|
521
|
-
saving
|
|
522
|
-
]);
|
|
523
|
-
const handleSave = useCallback2(async () => {
|
|
524
|
-
if (validate(values)) {
|
|
525
|
-
setSaving(true);
|
|
526
|
-
try {
|
|
527
|
-
await onSave?.(values, {
|
|
528
|
-
changed
|
|
529
|
-
});
|
|
530
|
-
} finally {
|
|
531
|
-
setSaving(false);
|
|
532
|
-
}
|
|
688
|
+
var MarkdownInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
|
|
689
|
+
const { status, error } = getStatus();
|
|
690
|
+
const textareaRef = useRef2(null);
|
|
691
|
+
const adjustHeight = useCallback3(() => {
|
|
692
|
+
const textarea = textareaRef.current;
|
|
693
|
+
if (textarea) {
|
|
694
|
+
textarea.style.blockSize = "auto";
|
|
695
|
+
textarea.style.blockSize = `${textarea.scrollHeight + 2}px`;
|
|
533
696
|
}
|
|
697
|
+
}, []);
|
|
698
|
+
useEffect4(() => {
|
|
699
|
+
adjustHeight();
|
|
534
700
|
}, [
|
|
535
|
-
|
|
536
|
-
validate,
|
|
537
|
-
onSave,
|
|
538
|
-
changed
|
|
539
|
-
]);
|
|
540
|
-
const getStatus = useCallback2((path) => {
|
|
541
|
-
const jsonPath = Array.isArray(path) ? createJsonPath(path) : path;
|
|
542
|
-
const matchingError = Object.entries(errors).find(([errorPath]) => errorPath === jsonPath || errorPath.startsWith(`${jsonPath}.`) || errorPath.startsWith(`${jsonPath}[`));
|
|
543
|
-
return {
|
|
544
|
-
status: matchingError ? "error" : void 0,
|
|
545
|
-
error: matchingError ? matchingError[1] : void 0
|
|
546
|
-
};
|
|
547
|
-
}, [
|
|
548
|
-
errors
|
|
701
|
+
adjustHeight
|
|
549
702
|
]);
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
};
|
|
553
|
-
const onValueChange = (path, type, value) => {
|
|
554
|
-
const jsonPath = createJsonPath(path);
|
|
555
|
-
let parsedValue = value;
|
|
556
|
-
try {
|
|
557
|
-
if (type === "number") {
|
|
558
|
-
parsedValue = parseFloat(value) || 0;
|
|
559
|
-
}
|
|
560
|
-
} catch (err) {
|
|
561
|
-
log.catch(err, void 0, {
|
|
562
|
-
F: __dxlog_file,
|
|
563
|
-
L: 193,
|
|
564
|
-
S: void 0,
|
|
565
|
-
C: (f, a) => f(...a)
|
|
566
|
-
});
|
|
567
|
-
parsedValue = void 0;
|
|
568
|
-
}
|
|
569
|
-
const newValues = {
|
|
570
|
-
...setValue(values, jsonPath, parsedValue)
|
|
571
|
-
};
|
|
572
|
-
setValues(newValues);
|
|
573
|
-
setChanged((prev) => ({
|
|
574
|
-
...prev,
|
|
575
|
-
[jsonPath]: true
|
|
576
|
-
}));
|
|
577
|
-
onValuesChanged?.(newValues);
|
|
578
|
-
const isValid = validate(newValues);
|
|
579
|
-
if (isValid && onValid) {
|
|
580
|
-
onValid(newValues, {
|
|
581
|
-
changed
|
|
582
|
-
});
|
|
583
|
-
}
|
|
584
|
-
};
|
|
585
|
-
const onTouched = useCallback2((path) => {
|
|
586
|
-
const jsonPath = createJsonPath(path);
|
|
587
|
-
setTouched((touched2) => ({
|
|
588
|
-
...touched2,
|
|
589
|
-
[jsonPath]: true
|
|
590
|
-
}));
|
|
591
|
-
validate(values);
|
|
703
|
+
useEffect4(() => {
|
|
704
|
+
adjustHeight();
|
|
592
705
|
}, [
|
|
593
|
-
|
|
594
|
-
|
|
706
|
+
getValue3(),
|
|
707
|
+
adjustHeight
|
|
595
708
|
]);
|
|
596
|
-
return {
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
F: __dxlog_file,
|
|
614
|
-
L: 235,
|
|
615
|
-
S: void 0,
|
|
616
|
-
A: [
|
|
617
|
-
"obj",
|
|
618
|
-
""
|
|
619
|
-
]
|
|
620
|
-
});
|
|
621
|
-
return Object.keys(obj).reduce((acc, key) => ({
|
|
622
|
-
...acc,
|
|
623
|
-
[key]: value
|
|
624
|
-
}), {});
|
|
625
|
-
};
|
|
626
|
-
var flatMap = (errors) => {
|
|
627
|
-
return errors.reduce((result, { path, message }) => {
|
|
628
|
-
const jsonPath = fromEffectValidationPath(path);
|
|
629
|
-
if (!(jsonPath in result)) {
|
|
630
|
-
result[jsonPath] = message;
|
|
631
|
-
}
|
|
632
|
-
return result;
|
|
633
|
-
}, {});
|
|
709
|
+
return /* @__PURE__ */ React7.createElement(Input5.Root, {
|
|
710
|
+
validationValence: status
|
|
711
|
+
}, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
|
|
712
|
+
error
|
|
713
|
+
}, /* @__PURE__ */ React7.createElement(Input5.Label, null, label)), /* @__PURE__ */ React7.createElement(Input5.TextArea, {
|
|
714
|
+
ref: textareaRef,
|
|
715
|
+
disabled,
|
|
716
|
+
placeholder,
|
|
717
|
+
value: getValue3() ?? "",
|
|
718
|
+
classNames: "min-bs-auto overflow-hidden",
|
|
719
|
+
onChange: (event) => onValueChange(type, event.target.value),
|
|
720
|
+
onBlur,
|
|
721
|
+
style: {
|
|
722
|
+
resize: "none"
|
|
723
|
+
},
|
|
724
|
+
spellCheck: false
|
|
725
|
+
}), inputOnly && /* @__PURE__ */ React7.createElement(Input5.Validation, null, error));
|
|
634
726
|
};
|
|
635
727
|
|
|
636
|
-
// packages/ui/react-ui-form/src/components/Form/
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
return useContext(FormContext) ?? raise(new Error("Missing FormContext"));
|
|
640
|
-
};
|
|
641
|
-
var useFormValues = (path = []) => {
|
|
642
|
-
const { values: formValues } = useFormContext();
|
|
643
|
-
const jsonPath = createJsonPath2(path);
|
|
644
|
-
return getValue2(formValues, jsonPath);
|
|
645
|
-
};
|
|
646
|
-
var useInputProps = (path = []) => {
|
|
647
|
-
const { getStatus, getValue: getFormValue, onValueChange, onTouched } = useFormContext();
|
|
648
|
-
return {
|
|
649
|
-
getStatus: () => getStatus(path),
|
|
650
|
-
getValue: () => getFormValue(path),
|
|
651
|
-
onValueChange: (type, value) => onValueChange(path, type, value),
|
|
652
|
-
onBlur: () => onTouched(path)
|
|
653
|
-
};
|
|
654
|
-
};
|
|
655
|
-
var FormProvider = ({ children, ...formOptions }) => {
|
|
656
|
-
const formHandler = useForm(formOptions);
|
|
657
|
-
return /* @__PURE__ */ React7.createElement(FormContext.Provider, {
|
|
658
|
-
value: formHandler
|
|
659
|
-
}, children);
|
|
660
|
-
};
|
|
728
|
+
// packages/ui/react-ui-form/src/components/Form/Form.tsx
|
|
729
|
+
import React11, { useEffect as useEffect5, useMemo as useMemo4, useRef as useRef3 } from "react";
|
|
730
|
+
import { mx as mx7 } from "@dxos/react-ui-theme";
|
|
661
731
|
|
|
662
732
|
// packages/ui/react-ui-form/src/components/Form/FormActions.tsx
|
|
733
|
+
import React8 from "react";
|
|
734
|
+
import { IconButton as IconButton2, useTranslation as useTranslation3 } from "@dxos/react-ui";
|
|
735
|
+
import { mx as mx4 } from "@dxos/react-ui-theme";
|
|
663
736
|
var FormActions = ({ onCancel, readonly }) => {
|
|
664
737
|
const { t } = useTranslation3(translationKey);
|
|
665
738
|
const { canSave, handleSave } = useFormContext();
|
|
@@ -697,7 +770,7 @@ import { isNotFalsy } from "@dxos/util";
|
|
|
697
770
|
// packages/ui/react-ui-form/src/components/Form/ArrayField.tsx
|
|
698
771
|
import { pipe } from "effect";
|
|
699
772
|
import { capitalize } from "effect/String";
|
|
700
|
-
import React9, { useCallback as
|
|
773
|
+
import React9, { useCallback as useCallback4, useMemo as useMemo2 } from "react";
|
|
701
774
|
import { AST as AST2 } from "@dxos/echo-schema";
|
|
702
775
|
import { findNode, getDiscriminatedType, isDiscriminatedUnion, SimpleType } from "@dxos/effect";
|
|
703
776
|
import { invariant as invariant2 } from "@dxos/invariant";
|
|
@@ -743,7 +816,7 @@ var ArrayField = ({ property, readonly, path, inputProps, Custom, lookupComponen
|
|
|
743
816
|
type,
|
|
744
817
|
elementType
|
|
745
818
|
]);
|
|
746
|
-
const handleAdd =
|
|
819
|
+
const handleAdd = useCallback4(() => {
|
|
747
820
|
inputProps.onValueChange(type, [
|
|
748
821
|
...values,
|
|
749
822
|
newValue
|
|
@@ -755,7 +828,7 @@ var ArrayField = ({ property, readonly, path, inputProps, Custom, lookupComponen
|
|
|
755
828
|
newValue,
|
|
756
829
|
values
|
|
757
830
|
]);
|
|
758
|
-
const handleRemove =
|
|
831
|
+
const handleRemove = useCallback4((index) => {
|
|
759
832
|
const newValues = values.filter((_, i) => i !== index);
|
|
760
833
|
inputProps.onValueChange(type, newValues);
|
|
761
834
|
}, [
|
|
@@ -815,6 +888,8 @@ var getInputComponent = (type, format) => {
|
|
|
815
888
|
switch (format) {
|
|
816
889
|
case FormatEnum.LatLng:
|
|
817
890
|
return GeoPointInput;
|
|
891
|
+
case FormatEnum.Markdown:
|
|
892
|
+
return MarkdownInput;
|
|
818
893
|
}
|
|
819
894
|
switch (type) {
|
|
820
895
|
case "string":
|
|
@@ -858,20 +933,15 @@ var FormField = ({ property, path, readonly, inline, lookupComponent, Custom })
|
|
|
858
933
|
const jsonPath = createJsonPath3(path ?? []);
|
|
859
934
|
const CustomComponent = Custom?.[jsonPath];
|
|
860
935
|
if (CustomComponent) {
|
|
861
|
-
return (
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
placeholder,
|
|
871
|
-
disabled: readonly,
|
|
872
|
-
...inputProps
|
|
873
|
-
}))
|
|
874
|
-
);
|
|
936
|
+
return /* @__PURE__ */ React10.createElement(CustomComponent, {
|
|
937
|
+
type,
|
|
938
|
+
format,
|
|
939
|
+
label,
|
|
940
|
+
inputOnly: inline,
|
|
941
|
+
placeholder,
|
|
942
|
+
disabled: readonly,
|
|
943
|
+
...inputProps
|
|
944
|
+
});
|
|
875
945
|
}
|
|
876
946
|
if (array) {
|
|
877
947
|
return /* @__PURE__ */ React10.createElement(ArrayField, {
|
|
@@ -961,13 +1031,14 @@ var FormFields = ({ schema, path, filter, sort, readonly, lookupComponent, Custo
|
|
|
961
1031
|
|
|
962
1032
|
// packages/ui/react-ui-form/src/components/Form/Form.tsx
|
|
963
1033
|
var Form = ({ classNames, schema, values: initialValues, path = [], autoFocus, readonly, filter, sort, autoSave, testId, onValuesChanged, onValidate, onSave, onCancel, lookupComponent, Custom }) => {
|
|
1034
|
+
const formRef = useRef3(null);
|
|
964
1035
|
const onValid = useMemo4(() => autoSave ? onSave : void 0, [
|
|
965
1036
|
autoSave,
|
|
966
1037
|
onSave
|
|
967
1038
|
]);
|
|
968
|
-
|
|
969
|
-
if (autoFocus) {
|
|
970
|
-
const input =
|
|
1039
|
+
useEffect5(() => {
|
|
1040
|
+
if (autoFocus && formRef.current) {
|
|
1041
|
+
const input = formRef.current.querySelector("input");
|
|
971
1042
|
if (input) {
|
|
972
1043
|
input.focus();
|
|
973
1044
|
}
|
|
@@ -976,13 +1047,16 @@ var Form = ({ classNames, schema, values: initialValues, path = [], autoFocus, r
|
|
|
976
1047
|
autoFocus
|
|
977
1048
|
]);
|
|
978
1049
|
return /* @__PURE__ */ React11.createElement(FormProvider, {
|
|
1050
|
+
formRef,
|
|
979
1051
|
schema,
|
|
1052
|
+
autoSave,
|
|
980
1053
|
initialValues,
|
|
981
1054
|
onValuesChanged,
|
|
982
1055
|
onValidate,
|
|
983
1056
|
onValid,
|
|
984
1057
|
onSave
|
|
985
1058
|
}, /* @__PURE__ */ React11.createElement("div", {
|
|
1059
|
+
ref: formRef,
|
|
986
1060
|
role: "none",
|
|
987
1061
|
className: mx7("p-2", classNames),
|
|
988
1062
|
"data-testid": testId
|
|
@@ -1005,12 +1079,12 @@ var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/c
|
|
|
1005
1079
|
var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
1006
1080
|
const { t } = useTranslation5(translationKey);
|
|
1007
1081
|
const [props, setProps] = useState3(projection.getFieldProjection(field.id).props);
|
|
1008
|
-
|
|
1082
|
+
useEffect6(() => setProps(projection.getFieldProjection(field.id).props), [
|
|
1009
1083
|
field,
|
|
1010
1084
|
projection
|
|
1011
1085
|
]);
|
|
1012
1086
|
const [schemas, setSchemas] = useState3([]);
|
|
1013
|
-
|
|
1087
|
+
useEffect6(() => {
|
|
1014
1088
|
if (!registry) {
|
|
1015
1089
|
return;
|
|
1016
1090
|
}
|
|
@@ -1029,7 +1103,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
1029
1103
|
registry
|
|
1030
1104
|
]);
|
|
1031
1105
|
const [referenceSchema, setReferenceSchema] = useState3();
|
|
1032
|
-
|
|
1106
|
+
useEffect6(() => {
|
|
1033
1107
|
setReferenceSchema(schemas.find((schema) => schema.typename === props?.referenceSchema));
|
|
1034
1108
|
}, [
|
|
1035
1109
|
schemas,
|
|
@@ -1038,7 +1112,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
1038
1112
|
const [{ fieldSchema }, setFieldSchema] = useState3({
|
|
1039
1113
|
fieldSchema: getFormatSchema(props?.format)
|
|
1040
1114
|
});
|
|
1041
|
-
const handleValuesChanged =
|
|
1115
|
+
const handleValuesChanged = useCallback5((_props) => {
|
|
1042
1116
|
setFieldSchema((prev) => {
|
|
1043
1117
|
const fieldSchema2 = getFormatSchema(_props.format);
|
|
1044
1118
|
if (prev.fieldSchema === fieldSchema2) {
|
|
@@ -1073,7 +1147,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
1073
1147
|
props.format,
|
|
1074
1148
|
props.referenceSchema
|
|
1075
1149
|
]);
|
|
1076
|
-
const handleValidate =
|
|
1150
|
+
const handleValidate = useCallback5(({ property }) => {
|
|
1077
1151
|
if (property && view.fields.find((f) => f.path === property && f.path !== field.path)) {
|
|
1078
1152
|
return [
|
|
1079
1153
|
{
|
|
@@ -1086,7 +1160,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
1086
1160
|
view.fields,
|
|
1087
1161
|
field
|
|
1088
1162
|
]);
|
|
1089
|
-
const handleSave =
|
|
1163
|
+
const handleSave = useCallback5((props2) => {
|
|
1090
1164
|
projection.setFieldProjection({
|
|
1091
1165
|
field,
|
|
1092
1166
|
props: props2
|
|
@@ -1097,7 +1171,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
1097
1171
|
field,
|
|
1098
1172
|
onSave
|
|
1099
1173
|
]);
|
|
1100
|
-
const handleCancel =
|
|
1174
|
+
const handleCancel = useCallback5(() => {
|
|
1101
1175
|
requestAnimationFrame(() => onCancel?.());
|
|
1102
1176
|
onSave();
|
|
1103
1177
|
}, [
|
|
@@ -1129,7 +1203,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
1129
1203
|
schemas,
|
|
1130
1204
|
referenceSchema
|
|
1131
1205
|
]);
|
|
1132
|
-
const propIsNotType =
|
|
1206
|
+
const propIsNotType = useCallback5((props2) => props2.filter((p) => p.name !== "type"), []);
|
|
1133
1207
|
if (!fieldSchema) {
|
|
1134
1208
|
log2.warn("invalid format", {
|
|
1135
1209
|
props
|
|
@@ -1160,7 +1234,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
1160
1234
|
};
|
|
1161
1235
|
|
|
1162
1236
|
// packages/ui/react-ui-form/src/components/ViewEditor/ViewEditor.tsx
|
|
1163
|
-
import React13, { useCallback as
|
|
1237
|
+
import React13, { useCallback as useCallback6, useMemo as useMemo6, useState as useState4 } from "react";
|
|
1164
1238
|
import { AST as AST4, Format, S as S2 } from "@dxos/echo-schema";
|
|
1165
1239
|
import { IconButton as IconButton4, useTranslation as useTranslation6 } from "@dxos/react-ui";
|
|
1166
1240
|
import { List as List2 } from "@dxos/react-ui-list";
|
|
@@ -1171,7 +1245,7 @@ var ViewMetaSchema = S2.Struct({
|
|
|
1171
1245
|
name: S2.String.annotations({
|
|
1172
1246
|
[AST4.TitleAnnotationId]: "View"
|
|
1173
1247
|
}),
|
|
1174
|
-
typename: Format.
|
|
1248
|
+
typename: Format.URL.annotations({
|
|
1175
1249
|
[AST4.TitleAnnotationId]: "Typename"
|
|
1176
1250
|
})
|
|
1177
1251
|
}).pipe(S2.mutable);
|
|
@@ -1192,7 +1266,7 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
|
|
|
1192
1266
|
}, [
|
|
1193
1267
|
view
|
|
1194
1268
|
]);
|
|
1195
|
-
const handleViewUpdate =
|
|
1269
|
+
const handleViewUpdate = useCallback6(({ name, typename }) => {
|
|
1196
1270
|
requestAnimationFrame(() => {
|
|
1197
1271
|
if (view.name !== name) {
|
|
1198
1272
|
view.name = name;
|
|
@@ -1206,16 +1280,16 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
|
|
|
1206
1280
|
schema,
|
|
1207
1281
|
onTypenameChanged
|
|
1208
1282
|
]);
|
|
1209
|
-
const handleSelect =
|
|
1283
|
+
const handleSelect = useCallback6((field2) => {
|
|
1210
1284
|
setField((f) => f === field2 ? void 0 : field2);
|
|
1211
1285
|
}, []);
|
|
1212
|
-
const handleAdd =
|
|
1286
|
+
const handleAdd = useCallback6(() => {
|
|
1213
1287
|
const field2 = projection.createFieldProjection();
|
|
1214
1288
|
setField(field2);
|
|
1215
1289
|
}, [
|
|
1216
1290
|
view
|
|
1217
1291
|
]);
|
|
1218
|
-
const handleMove =
|
|
1292
|
+
const handleMove = useCallback6((fromIndex, toIndex) => {
|
|
1219
1293
|
const fields = [
|
|
1220
1294
|
...view.fields
|
|
1221
1295
|
];
|
|
@@ -1225,12 +1299,11 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
|
|
|
1225
1299
|
}, [
|
|
1226
1300
|
view.fields
|
|
1227
1301
|
]);
|
|
1228
|
-
const handleClose =
|
|
1302
|
+
const handleClose = useCallback6(() => setField(void 0), []);
|
|
1229
1303
|
return /* @__PURE__ */ React13.createElement("div", {
|
|
1230
1304
|
role: "none",
|
|
1231
1305
|
className: mx8("flex flex-col w-full divide-y divide-separator", classNames)
|
|
1232
1306
|
}, /* @__PURE__ */ React13.createElement(Form, {
|
|
1233
|
-
autoFocus: true,
|
|
1234
1307
|
autoSave: true,
|
|
1235
1308
|
schema: ViewMetaSchema,
|
|
1236
1309
|
values: viewValues,
|
|
@@ -1507,6 +1580,7 @@ export {
|
|
|
1507
1580
|
Form,
|
|
1508
1581
|
GeoPointInput,
|
|
1509
1582
|
InputHeader,
|
|
1583
|
+
MarkdownInput,
|
|
1510
1584
|
NumberInput,
|
|
1511
1585
|
SelectInput,
|
|
1512
1586
|
SelectOptionInput,
|
|
@@ -1520,6 +1594,7 @@ export {
|
|
|
1520
1594
|
parseValue,
|
|
1521
1595
|
pathNotUniqueError,
|
|
1522
1596
|
translations_default as translations,
|
|
1523
|
-
useForm
|
|
1597
|
+
useForm,
|
|
1598
|
+
useFormValues
|
|
1524
1599
|
};
|
|
1525
1600
|
//# sourceMappingURL=index.mjs.map
|