@dxos/react-ui-form 0.7.5-labs.071a3e2 → 0.7.5-labs.401163d
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 +402 -326
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +385 -305
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +402 -326
- 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 +61 -4
- package/src/components/Form/Form.tsx +8 -5
- 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/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,291 +621,124 @@ 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());
|
|
658
|
+
return /* @__PURE__ */ React7.createElement(Input5.Root, {
|
|
417
659
|
validationValence: status
|
|
418
|
-
}, !inputOnly && /* @__PURE__ */
|
|
660
|
+
}, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
|
|
419
661
|
error
|
|
420
|
-
}, /* @__PURE__ */
|
|
421
|
-
checked
|
|
662
|
+
}, /* @__PURE__ */ React7.createElement(Input5.Label, null, label)), /* @__PURE__ */ React7.createElement(Input5.Switch, {
|
|
663
|
+
checked,
|
|
422
664
|
onCheckedChange: (value) => onValueChange(type, value)
|
|
423
|
-
}), inputOnly && /* @__PURE__ */
|
|
665
|
+
}), inputOnly && /* @__PURE__ */ React7.createElement(Input5.DescriptionAndValidation, null, error));
|
|
424
666
|
};
|
|
425
667
|
var SelectInput = ({ type, label, inputOnly, disabled, placeholder, options, getStatus, getValue: getValue3, onValueChange }) => {
|
|
426
668
|
const { status, error } = getStatus();
|
|
427
|
-
return /* @__PURE__ */
|
|
669
|
+
return /* @__PURE__ */ React7.createElement(Input5.Root, {
|
|
428
670
|
validationValence: status
|
|
429
|
-
}, !inputOnly && /* @__PURE__ */
|
|
671
|
+
}, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
|
|
430
672
|
error
|
|
431
|
-
}, /* @__PURE__ */
|
|
673
|
+
}, /* @__PURE__ */ React7.createElement(Input5.Label, null, label)), /* @__PURE__ */ React7.createElement(Select.Root, {
|
|
432
674
|
value: getValue3(),
|
|
433
675
|
onValueChange: (value) => onValueChange(type, value)
|
|
434
|
-
}, /* @__PURE__ */
|
|
676
|
+
}, /* @__PURE__ */ React7.createElement(Select.TriggerButton, {
|
|
435
677
|
classNames: "is-full",
|
|
436
678
|
disabled,
|
|
437
679
|
placeholder
|
|
438
|
-
}), /* @__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 }) => (
|
|
439
681
|
// NOTE: Numeric values are converted to and from strings.
|
|
440
|
-
/* @__PURE__ */
|
|
682
|
+
/* @__PURE__ */ React7.createElement(Select.Option, {
|
|
441
683
|
key: String(value),
|
|
442
684
|
value: String(value)
|
|
443
685
|
}, label2 ?? String(value))
|
|
444
|
-
)))))), inputOnly && /* @__PURE__ */
|
|
686
|
+
)))))), inputOnly && /* @__PURE__ */ React7.createElement(Input5.DescriptionAndValidation, null, error));
|
|
445
687
|
};
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
import { mx as mx4 } from "@dxos/react-ui-theme";
|
|
455
|
-
|
|
456
|
-
// packages/ui/react-ui-form/src/components/Form/FormContext.tsx
|
|
457
|
-
import React7, { createContext, useContext } from "react";
|
|
458
|
-
import { raise } from "@dxos/debug";
|
|
459
|
-
import { getValue as getValue2 } from "@dxos/echo-schema";
|
|
460
|
-
import { createJsonPath as createJsonPath2 } from "@dxos/effect";
|
|
461
|
-
|
|
462
|
-
// packages/ui/react-ui-form/src/hooks/useForm.ts
|
|
463
|
-
import { useCallback as useCallback2, useEffect as useEffect2, useMemo, useState as useState2 } from "react";
|
|
464
|
-
import { getValue, setValue } from "@dxos/echo-schema";
|
|
465
|
-
import { AST, createJsonPath, fromEffectValidationPath } from "@dxos/effect";
|
|
466
|
-
import { invariant } from "@dxos/invariant";
|
|
467
|
-
import { log } from "@dxos/log";
|
|
468
|
-
import { validateSchema } from "@dxos/schema";
|
|
469
|
-
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/hooks/useForm.ts";
|
|
470
|
-
var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, onSave }) => {
|
|
471
|
-
invariant(AST.isTypeLiteral(schema.ast), void 0, {
|
|
472
|
-
F: __dxlog_file,
|
|
473
|
-
L: 91,
|
|
474
|
-
S: void 0,
|
|
475
|
-
A: [
|
|
476
|
-
"AST.isTypeLiteral(schema.ast)",
|
|
477
|
-
""
|
|
478
|
-
]
|
|
479
|
-
});
|
|
480
|
-
const [values, setValues] = useState2(initialValues);
|
|
481
|
-
useEffect2(() => {
|
|
482
|
-
setValues(initialValues);
|
|
483
|
-
}, [
|
|
484
|
-
initialValues
|
|
485
|
-
]);
|
|
486
|
-
const [touched, setTouched] = useState2(createKeySet(initialValues, false));
|
|
487
|
-
const [changed, setChanged] = useState2(createKeySet(initialValues, false));
|
|
488
|
-
const [errors, setErrors] = useState2({});
|
|
489
|
-
const [saving, setSaving] = useState2(false);
|
|
490
|
-
const validate = useCallback2((values2) => {
|
|
491
|
-
let errors2 = validateSchema(schema, values2) ?? [];
|
|
492
|
-
if (errors2.length === 0 && onValidate) {
|
|
493
|
-
const validatedValues = values2;
|
|
494
|
-
errors2 = onValidate(validatedValues) ?? [];
|
|
495
|
-
}
|
|
496
|
-
setErrors(flatMap(errors2));
|
|
497
|
-
const valid = errors2.length === 0;
|
|
498
|
-
return valid;
|
|
499
|
-
}, [
|
|
500
|
-
schema,
|
|
501
|
-
onValidate
|
|
502
|
-
]);
|
|
503
|
-
const [schemaDirty, setSchemaDirty] = useState2(false);
|
|
504
|
-
useEffect2(() => setSchemaDirty(true), [
|
|
505
|
-
schema
|
|
506
|
-
]);
|
|
507
|
-
useEffect2(() => {
|
|
508
|
-
if (schemaDirty) {
|
|
509
|
-
validate(values);
|
|
510
|
-
setSchemaDirty(false);
|
|
511
|
-
}
|
|
512
|
-
}, [
|
|
513
|
-
values,
|
|
514
|
-
schemaDirty
|
|
515
|
-
]);
|
|
516
|
-
const canSave = useMemo(() => !saving && // Check if any error paths that are touched have errors
|
|
517
|
-
!Object.entries(touched).some(([path, isTouched]) => isTouched && Object.keys(errors).some((errorPath) => errorPath === path || errorPath.startsWith(`${path}.`) || errorPath.startsWith(`${path}[`))), [
|
|
518
|
-
touched,
|
|
519
|
-
errors,
|
|
520
|
-
saving
|
|
521
|
-
]);
|
|
522
|
-
const handleSave = useCallback2(async () => {
|
|
523
|
-
if (validate(values)) {
|
|
524
|
-
setSaving(true);
|
|
525
|
-
try {
|
|
526
|
-
await onSave?.(values, {
|
|
527
|
-
changed
|
|
528
|
-
});
|
|
529
|
-
} finally {
|
|
530
|
-
setSaving(false);
|
|
531
|
-
}
|
|
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`;
|
|
532
696
|
}
|
|
697
|
+
}, []);
|
|
698
|
+
useEffect4(() => {
|
|
699
|
+
adjustHeight();
|
|
533
700
|
}, [
|
|
534
|
-
|
|
535
|
-
validate,
|
|
536
|
-
onSave,
|
|
537
|
-
changed
|
|
538
|
-
]);
|
|
539
|
-
const getStatus = useCallback2((path) => {
|
|
540
|
-
const jsonPath = Array.isArray(path) ? createJsonPath(path) : path;
|
|
541
|
-
const matchingError = Object.entries(errors).find(([errorPath]) => errorPath === jsonPath || errorPath.startsWith(`${jsonPath}.`) || errorPath.startsWith(`${jsonPath}[`));
|
|
542
|
-
return {
|
|
543
|
-
status: matchingError ? "error" : void 0,
|
|
544
|
-
error: matchingError ? matchingError[1] : void 0
|
|
545
|
-
};
|
|
546
|
-
}, [
|
|
547
|
-
errors
|
|
701
|
+
adjustHeight
|
|
548
702
|
]);
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
};
|
|
552
|
-
const onValueChange = (path, type, value) => {
|
|
553
|
-
const jsonPath = createJsonPath(path);
|
|
554
|
-
let parsedValue = value;
|
|
555
|
-
try {
|
|
556
|
-
if (type === "number") {
|
|
557
|
-
parsedValue = parseFloat(value) || 0;
|
|
558
|
-
}
|
|
559
|
-
} catch (err) {
|
|
560
|
-
log.catch(err, void 0, {
|
|
561
|
-
F: __dxlog_file,
|
|
562
|
-
L: 193,
|
|
563
|
-
S: void 0,
|
|
564
|
-
C: (f, a) => f(...a)
|
|
565
|
-
});
|
|
566
|
-
parsedValue = void 0;
|
|
567
|
-
}
|
|
568
|
-
const newValues = {
|
|
569
|
-
...setValue(values, jsonPath, parsedValue)
|
|
570
|
-
};
|
|
571
|
-
setValues(newValues);
|
|
572
|
-
setChanged((prev) => ({
|
|
573
|
-
...prev,
|
|
574
|
-
[jsonPath]: true
|
|
575
|
-
}));
|
|
576
|
-
onValuesChanged?.(newValues);
|
|
577
|
-
const isValid = validate(newValues);
|
|
578
|
-
if (isValid && onValid) {
|
|
579
|
-
onValid(newValues, {
|
|
580
|
-
changed
|
|
581
|
-
});
|
|
582
|
-
}
|
|
583
|
-
};
|
|
584
|
-
const onTouched = useCallback2((path) => {
|
|
585
|
-
const jsonPath = createJsonPath(path);
|
|
586
|
-
setTouched((touched2) => ({
|
|
587
|
-
...touched2,
|
|
588
|
-
[jsonPath]: true
|
|
589
|
-
}));
|
|
590
|
-
validate(values);
|
|
703
|
+
useEffect4(() => {
|
|
704
|
+
adjustHeight();
|
|
591
705
|
}, [
|
|
592
|
-
|
|
593
|
-
|
|
706
|
+
getValue3(),
|
|
707
|
+
adjustHeight
|
|
594
708
|
]);
|
|
595
|
-
return {
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
F: __dxlog_file,
|
|
613
|
-
L: 235,
|
|
614
|
-
S: void 0,
|
|
615
|
-
A: [
|
|
616
|
-
"obj",
|
|
617
|
-
""
|
|
618
|
-
]
|
|
619
|
-
});
|
|
620
|
-
return Object.keys(obj).reduce((acc, key) => ({
|
|
621
|
-
...acc,
|
|
622
|
-
[key]: value
|
|
623
|
-
}), {});
|
|
624
|
-
};
|
|
625
|
-
var flatMap = (errors) => {
|
|
626
|
-
return errors.reduce((result, { path, message }) => {
|
|
627
|
-
const jsonPath = fromEffectValidationPath(path);
|
|
628
|
-
if (!(jsonPath in result)) {
|
|
629
|
-
result[jsonPath] = message;
|
|
630
|
-
}
|
|
631
|
-
return result;
|
|
632
|
-
}, {});
|
|
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));
|
|
633
726
|
};
|
|
634
727
|
|
|
635
|
-
// packages/ui/react-ui-form/src/components/Form/
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
return useContext(FormContext) ?? raise(new Error("Missing FormContext"));
|
|
639
|
-
};
|
|
640
|
-
var useFormValues = (path = []) => {
|
|
641
|
-
const { values: formValues } = useFormContext();
|
|
642
|
-
const jsonPath = createJsonPath2(path);
|
|
643
|
-
return getValue2(formValues, jsonPath);
|
|
644
|
-
};
|
|
645
|
-
var useInputProps = (path = []) => {
|
|
646
|
-
const { getStatus, getValue: getFormValue, onValueChange, onTouched } = useFormContext();
|
|
647
|
-
return {
|
|
648
|
-
getStatus: () => getStatus(path),
|
|
649
|
-
getValue: () => getFormValue(path),
|
|
650
|
-
onValueChange: (type, value) => onValueChange(path, type, value),
|
|
651
|
-
onBlur: () => onTouched(path)
|
|
652
|
-
};
|
|
653
|
-
};
|
|
654
|
-
var FormProvider = ({ children, ...formOptions }) => {
|
|
655
|
-
const formHandler = useForm(formOptions);
|
|
656
|
-
return /* @__PURE__ */ React7.createElement(FormContext.Provider, {
|
|
657
|
-
value: formHandler
|
|
658
|
-
}, children);
|
|
659
|
-
};
|
|
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";
|
|
660
731
|
|
|
661
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";
|
|
662
736
|
var FormActions = ({ onCancel, readonly }) => {
|
|
663
737
|
const { t } = useTranslation3(translationKey);
|
|
664
738
|
const { canSave, handleSave } = useFormContext();
|
|
665
739
|
return /* @__PURE__ */ React8.createElement("div", {
|
|
666
740
|
role: "none",
|
|
667
|
-
className: "flex justify-center"
|
|
741
|
+
className: "mt-2 flex justify-center"
|
|
668
742
|
}, /* @__PURE__ */ React8.createElement("div", {
|
|
669
743
|
role: "none",
|
|
670
744
|
className: mx4(onCancel && !readonly && "grid grid-cols-2 gap-2")
|
|
@@ -696,7 +770,7 @@ import { isNotFalsy } from "@dxos/util";
|
|
|
696
770
|
// packages/ui/react-ui-form/src/components/Form/ArrayField.tsx
|
|
697
771
|
import { pipe } from "effect";
|
|
698
772
|
import { capitalize } from "effect/String";
|
|
699
|
-
import React9, { useCallback as
|
|
773
|
+
import React9, { useCallback as useCallback4, useMemo as useMemo2 } from "react";
|
|
700
774
|
import { AST as AST2 } from "@dxos/echo-schema";
|
|
701
775
|
import { findNode, getDiscriminatedType, isDiscriminatedUnion, SimpleType } from "@dxos/effect";
|
|
702
776
|
import { invariant as invariant2 } from "@dxos/invariant";
|
|
@@ -742,7 +816,7 @@ var ArrayField = ({ property, readonly, path, inputProps, Custom, lookupComponen
|
|
|
742
816
|
type,
|
|
743
817
|
elementType
|
|
744
818
|
]);
|
|
745
|
-
const handleAdd =
|
|
819
|
+
const handleAdd = useCallback4(() => {
|
|
746
820
|
inputProps.onValueChange(type, [
|
|
747
821
|
...values,
|
|
748
822
|
newValue
|
|
@@ -754,7 +828,7 @@ var ArrayField = ({ property, readonly, path, inputProps, Custom, lookupComponen
|
|
|
754
828
|
newValue,
|
|
755
829
|
values
|
|
756
830
|
]);
|
|
757
|
-
const handleRemove =
|
|
831
|
+
const handleRemove = useCallback4((index) => {
|
|
758
832
|
const newValues = values.filter((_, i) => i !== index);
|
|
759
833
|
inputProps.onValueChange(type, newValues);
|
|
760
834
|
}, [
|
|
@@ -814,6 +888,8 @@ var getInputComponent = (type, format) => {
|
|
|
814
888
|
switch (format) {
|
|
815
889
|
case FormatEnum.LatLng:
|
|
816
890
|
return GeoPointInput;
|
|
891
|
+
case FormatEnum.Markdown:
|
|
892
|
+
return MarkdownInput;
|
|
817
893
|
}
|
|
818
894
|
switch (type) {
|
|
819
895
|
case "string":
|
|
@@ -857,20 +933,15 @@ var FormField = ({ property, path, readonly, inline, lookupComponent, Custom })
|
|
|
857
933
|
const jsonPath = createJsonPath3(path ?? []);
|
|
858
934
|
const CustomComponent = Custom?.[jsonPath];
|
|
859
935
|
if (CustomComponent) {
|
|
860
|
-
return (
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
placeholder,
|
|
870
|
-
disabled: readonly,
|
|
871
|
-
...inputProps
|
|
872
|
-
}))
|
|
873
|
-
);
|
|
936
|
+
return /* @__PURE__ */ React10.createElement(CustomComponent, {
|
|
937
|
+
type,
|
|
938
|
+
format,
|
|
939
|
+
label,
|
|
940
|
+
inputOnly: inline,
|
|
941
|
+
placeholder,
|
|
942
|
+
disabled: readonly,
|
|
943
|
+
...inputProps
|
|
944
|
+
});
|
|
874
945
|
}
|
|
875
946
|
if (array) {
|
|
876
947
|
return /* @__PURE__ */ React10.createElement(ArrayField, {
|
|
@@ -942,7 +1013,7 @@ var FormFields = ({ schema, path, filter, sort, readonly, lookupComponent, Custo
|
|
|
942
1013
|
]);
|
|
943
1014
|
return /* @__PURE__ */ React10.createElement("div", {
|
|
944
1015
|
role: "form",
|
|
945
|
-
className: mx6("flex flex-col w-full gap-2
|
|
1016
|
+
className: mx6("flex flex-col w-full gap-2")
|
|
946
1017
|
}, properties.map((property) => {
|
|
947
1018
|
return /* @__PURE__ */ React10.createElement(FormField, {
|
|
948
1019
|
key: property.name,
|
|
@@ -960,13 +1031,14 @@ var FormFields = ({ schema, path, filter, sort, readonly, lookupComponent, Custo
|
|
|
960
1031
|
|
|
961
1032
|
// packages/ui/react-ui-form/src/components/Form/Form.tsx
|
|
962
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);
|
|
963
1035
|
const onValid = useMemo4(() => autoSave ? onSave : void 0, [
|
|
964
1036
|
autoSave,
|
|
965
1037
|
onSave
|
|
966
1038
|
]);
|
|
967
|
-
|
|
968
|
-
if (autoFocus) {
|
|
969
|
-
const input =
|
|
1039
|
+
useEffect5(() => {
|
|
1040
|
+
if (autoFocus && formRef.current) {
|
|
1041
|
+
const input = formRef.current.querySelector("input");
|
|
970
1042
|
if (input) {
|
|
971
1043
|
input.focus();
|
|
972
1044
|
}
|
|
@@ -975,13 +1047,16 @@ var Form = ({ classNames, schema, values: initialValues, path = [], autoFocus, r
|
|
|
975
1047
|
autoFocus
|
|
976
1048
|
]);
|
|
977
1049
|
return /* @__PURE__ */ React11.createElement(FormProvider, {
|
|
1050
|
+
formRef,
|
|
978
1051
|
schema,
|
|
1052
|
+
autoSave,
|
|
979
1053
|
initialValues,
|
|
980
1054
|
onValuesChanged,
|
|
981
1055
|
onValidate,
|
|
982
1056
|
onValid,
|
|
983
1057
|
onSave
|
|
984
1058
|
}, /* @__PURE__ */ React11.createElement("div", {
|
|
1059
|
+
ref: formRef,
|
|
985
1060
|
role: "none",
|
|
986
1061
|
className: mx7("p-2", classNames),
|
|
987
1062
|
"data-testid": testId
|
|
@@ -1004,12 +1079,12 @@ var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/c
|
|
|
1004
1079
|
var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
1005
1080
|
const { t } = useTranslation5(translationKey);
|
|
1006
1081
|
const [props, setProps] = useState3(projection.getFieldProjection(field.id).props);
|
|
1007
|
-
|
|
1082
|
+
useEffect6(() => setProps(projection.getFieldProjection(field.id).props), [
|
|
1008
1083
|
field,
|
|
1009
1084
|
projection
|
|
1010
1085
|
]);
|
|
1011
1086
|
const [schemas, setSchemas] = useState3([]);
|
|
1012
|
-
|
|
1087
|
+
useEffect6(() => {
|
|
1013
1088
|
if (!registry) {
|
|
1014
1089
|
return;
|
|
1015
1090
|
}
|
|
@@ -1028,7 +1103,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
1028
1103
|
registry
|
|
1029
1104
|
]);
|
|
1030
1105
|
const [referenceSchema, setReferenceSchema] = useState3();
|
|
1031
|
-
|
|
1106
|
+
useEffect6(() => {
|
|
1032
1107
|
setReferenceSchema(schemas.find((schema) => schema.typename === props?.referenceSchema));
|
|
1033
1108
|
}, [
|
|
1034
1109
|
schemas,
|
|
@@ -1037,7 +1112,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
1037
1112
|
const [{ fieldSchema }, setFieldSchema] = useState3({
|
|
1038
1113
|
fieldSchema: getFormatSchema(props?.format)
|
|
1039
1114
|
});
|
|
1040
|
-
const handleValuesChanged =
|
|
1115
|
+
const handleValuesChanged = useCallback5((_props) => {
|
|
1041
1116
|
setFieldSchema((prev) => {
|
|
1042
1117
|
const fieldSchema2 = getFormatSchema(_props.format);
|
|
1043
1118
|
if (prev.fieldSchema === fieldSchema2) {
|
|
@@ -1072,7 +1147,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
1072
1147
|
props.format,
|
|
1073
1148
|
props.referenceSchema
|
|
1074
1149
|
]);
|
|
1075
|
-
const handleValidate =
|
|
1150
|
+
const handleValidate = useCallback5(({ property }) => {
|
|
1076
1151
|
if (property && view.fields.find((f) => f.path === property && f.path !== field.path)) {
|
|
1077
1152
|
return [
|
|
1078
1153
|
{
|
|
@@ -1085,7 +1160,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
1085
1160
|
view.fields,
|
|
1086
1161
|
field
|
|
1087
1162
|
]);
|
|
1088
|
-
const handleSave =
|
|
1163
|
+
const handleSave = useCallback5((props2) => {
|
|
1089
1164
|
projection.setFieldProjection({
|
|
1090
1165
|
field,
|
|
1091
1166
|
props: props2
|
|
@@ -1096,7 +1171,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
1096
1171
|
field,
|
|
1097
1172
|
onSave
|
|
1098
1173
|
]);
|
|
1099
|
-
const handleCancel =
|
|
1174
|
+
const handleCancel = useCallback5(() => {
|
|
1100
1175
|
requestAnimationFrame(() => onCancel?.());
|
|
1101
1176
|
onSave();
|
|
1102
1177
|
}, [
|
|
@@ -1128,7 +1203,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
1128
1203
|
schemas,
|
|
1129
1204
|
referenceSchema
|
|
1130
1205
|
]);
|
|
1131
|
-
const propIsNotType =
|
|
1206
|
+
const propIsNotType = useCallback5((props2) => props2.filter((p) => p.name !== "type"), []);
|
|
1132
1207
|
if (!fieldSchema) {
|
|
1133
1208
|
log2.warn("invalid format", {
|
|
1134
1209
|
props
|
|
@@ -1159,7 +1234,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
1159
1234
|
};
|
|
1160
1235
|
|
|
1161
1236
|
// packages/ui/react-ui-form/src/components/ViewEditor/ViewEditor.tsx
|
|
1162
|
-
import React13, { useCallback as
|
|
1237
|
+
import React13, { useCallback as useCallback6, useMemo as useMemo6, useState as useState4 } from "react";
|
|
1163
1238
|
import { AST as AST4, Format, S as S2 } from "@dxos/echo-schema";
|
|
1164
1239
|
import { IconButton as IconButton4, useTranslation as useTranslation6 } from "@dxos/react-ui";
|
|
1165
1240
|
import { List as List2 } from "@dxos/react-ui-list";
|
|
@@ -1170,7 +1245,7 @@ var ViewMetaSchema = S2.Struct({
|
|
|
1170
1245
|
name: S2.String.annotations({
|
|
1171
1246
|
[AST4.TitleAnnotationId]: "View"
|
|
1172
1247
|
}),
|
|
1173
|
-
typename: Format.
|
|
1248
|
+
typename: Format.URL.annotations({
|
|
1174
1249
|
[AST4.TitleAnnotationId]: "Typename"
|
|
1175
1250
|
})
|
|
1176
1251
|
}).pipe(S2.mutable);
|
|
@@ -1191,7 +1266,7 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
|
|
|
1191
1266
|
}, [
|
|
1192
1267
|
view
|
|
1193
1268
|
]);
|
|
1194
|
-
const handleViewUpdate =
|
|
1269
|
+
const handleViewUpdate = useCallback6(({ name, typename }) => {
|
|
1195
1270
|
requestAnimationFrame(() => {
|
|
1196
1271
|
if (view.name !== name) {
|
|
1197
1272
|
view.name = name;
|
|
@@ -1205,16 +1280,16 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
|
|
|
1205
1280
|
schema,
|
|
1206
1281
|
onTypenameChanged
|
|
1207
1282
|
]);
|
|
1208
|
-
const handleSelect =
|
|
1283
|
+
const handleSelect = useCallback6((field2) => {
|
|
1209
1284
|
setField((f) => f === field2 ? void 0 : field2);
|
|
1210
1285
|
}, []);
|
|
1211
|
-
const handleAdd =
|
|
1286
|
+
const handleAdd = useCallback6(() => {
|
|
1212
1287
|
const field2 = projection.createFieldProjection();
|
|
1213
1288
|
setField(field2);
|
|
1214
1289
|
}, [
|
|
1215
1290
|
view
|
|
1216
1291
|
]);
|
|
1217
|
-
const handleMove =
|
|
1292
|
+
const handleMove = useCallback6((fromIndex, toIndex) => {
|
|
1218
1293
|
const fields = [
|
|
1219
1294
|
...view.fields
|
|
1220
1295
|
];
|
|
@@ -1224,12 +1299,11 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
|
|
|
1224
1299
|
}, [
|
|
1225
1300
|
view.fields
|
|
1226
1301
|
]);
|
|
1227
|
-
const handleClose =
|
|
1302
|
+
const handleClose = useCallback6(() => setField(void 0), []);
|
|
1228
1303
|
return /* @__PURE__ */ React13.createElement("div", {
|
|
1229
1304
|
role: "none",
|
|
1230
1305
|
className: mx8("flex flex-col w-full divide-y divide-separator", classNames)
|
|
1231
1306
|
}, /* @__PURE__ */ React13.createElement(Form, {
|
|
1232
|
-
autoFocus: true,
|
|
1233
1307
|
autoSave: true,
|
|
1234
1308
|
schema: ViewMetaSchema,
|
|
1235
1309
|
values: viewValues,
|
|
@@ -1506,6 +1580,7 @@ export {
|
|
|
1506
1580
|
Form,
|
|
1507
1581
|
GeoPointInput,
|
|
1508
1582
|
InputHeader,
|
|
1583
|
+
MarkdownInput,
|
|
1509
1584
|
NumberInput,
|
|
1510
1585
|
SelectInput,
|
|
1511
1586
|
SelectOptionInput,
|
|
@@ -1519,6 +1594,7 @@ export {
|
|
|
1519
1594
|
parseValue,
|
|
1520
1595
|
pathNotUniqueError,
|
|
1521
1596
|
translations_default as translations,
|
|
1522
|
-
useForm
|
|
1597
|
+
useForm,
|
|
1598
|
+
useFormValues
|
|
1523
1599
|
};
|
|
1524
1600
|
//# sourceMappingURL=index.mjs.map
|