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