@dxos/react-ui-form 0.7.5-labs.8a82073 → 0.7.5-labs.c0e040f

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/dist/lib/browser/index.mjs +398 -323
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node/index.cjs +381 -302
  5. package/dist/lib/node/index.cjs.map +4 -4
  6. package/dist/lib/node/meta.json +1 -1
  7. package/dist/lib/node-esm/index.mjs +398 -323
  8. package/dist/lib/node-esm/index.mjs.map +4 -4
  9. package/dist/lib/node-esm/meta.json +1 -1
  10. package/dist/types/src/components/Form/Defaults.d.ts +1 -0
  11. package/dist/types/src/components/Form/Defaults.d.ts.map +1 -1
  12. package/dist/types/src/components/Form/Form.d.ts.map +1 -1
  13. package/dist/types/src/components/Form/FormContent.d.ts.map +1 -1
  14. package/dist/types/src/components/Form/FormContext.d.ts +4 -1
  15. package/dist/types/src/components/Form/FormContext.d.ts.map +1 -1
  16. package/dist/types/src/components/Form/custom/SelectOptionsInput.d.ts.map +1 -1
  17. package/dist/types/src/components/Form/factory.d.ts.map +1 -1
  18. package/dist/types/src/components/Form/index.d.ts +2 -0
  19. package/dist/types/src/components/Form/index.d.ts.map +1 -1
  20. package/dist/types/src/hooks/useForm.d.ts +1 -0
  21. package/dist/types/src/hooks/useForm.d.ts.map +1 -1
  22. package/package.json +24 -24
  23. package/src/components/Form/Defaults.tsx +59 -3
  24. package/src/components/Form/Form.tsx +8 -5
  25. package/src/components/Form/FormContent.tsx +9 -12
  26. package/src/components/Form/FormContext.tsx +48 -4
  27. package/src/components/Form/custom/SelectOptionsInput.tsx +5 -7
  28. package/src/components/Form/factory.tsx +3 -1
  29. package/src/components/Form/index.ts +3 -0
  30. package/src/components/ViewEditor/ViewEditor.tsx +2 -2
  31. 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 useCallback4, useEffect as useEffect4, useMemo as useMemo5, useState as useState3 } from "react";
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 React3 from "react";
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 React2 from "react";
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__ */ React2.createElement("div", {
359
+ return /* @__PURE__ */ React3.createElement("div", {
119
360
  role: "none",
120
361
  className: "flex justify-between items-center mb-1"
121
- }, children, error && /* @__PURE__ */ React2.createElement(Tooltip.Root, null, /* @__PURE__ */ React2.createElement(Tooltip.Trigger, {
362
+ }, children, error && /* @__PURE__ */ React3.createElement(Tooltip.Root, null, /* @__PURE__ */ React3.createElement(Tooltip.Trigger, {
122
363
  asChild: true
123
- }, /* @__PURE__ */ React2.createElement(Icon, {
364
+ }, /* @__PURE__ */ React3.createElement(Icon, {
124
365
  icon: "ph--warning--regular",
125
366
  size: 4,
126
367
  classNames: errorText
127
- })), /* @__PURE__ */ React2.createElement(Tooltip.Content, {
368
+ })), /* @__PURE__ */ React3.createElement(Tooltip.Content, {
128
369
  side: "bottom"
129
- }, /* @__PURE__ */ React2.createElement(Tooltip.Arrow, null), error)));
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__ */ React3.createElement(Input2.Root, {
378
+ return /* @__PURE__ */ React4.createElement(Input2.Root, {
138
379
  validationValence: status
139
- }, /* @__PURE__ */ React3.createElement(InputHeader, {
380
+ }, /* @__PURE__ */ React4.createElement(InputHeader, {
140
381
  error
141
- }, /* @__PURE__ */ React3.createElement(Input2.Label, null, label)), /* @__PURE__ */ React3.createElement("div", {
382
+ }, /* @__PURE__ */ React4.createElement(Input2.Label, null, label)), /* @__PURE__ */ React4.createElement("div", {
142
383
  className: "grid grid-cols-2 gap-2"
143
- }, /* @__PURE__ */ React3.createElement(Input2.TextInput, {
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__ */ React3.createElement(Input2.TextInput, {
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 React4, { useCallback, useEffect, useState, useRef } from "react";
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 { hueTokenThemes, mx as mx2 } from "@dxos/react-ui-theme";
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] = useState(null);
175
- const [isNewOption, setIsNewOption] = useState(false);
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
- useEffect(() => {
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 hueKeys = Object.keys(hueTokenThemes);
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 = hueKeys.filter((hue) => !lastThree.has(hue));
198
- return availableHues[Math.floor(Math.random() * availableHues.length)] ?? hueKeys[Math.floor(Math.random() * hueKeys.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 = useCallback(() => {
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 = useCallback((id) => {
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 = useCallback((from, to) => {
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 = useCallback((id) => {
482
+ const handleClick = useCallback2((id) => {
243
483
  setSelectedId((current) => current === id ? null : id);
244
484
  }, []);
245
- const handleTitleChange = useCallback((id) => (e) => {
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 = useCallback((e) => {
496
+ const handleKeyDown = useCallback2((e) => {
257
497
  if (e.key === "Enter") {
258
498
  setSelectedId(null);
259
499
  }
260
500
  }, []);
261
- const handleColorChange = useCallback((id) => (hue) => {
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
- useEffect(() => {
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__ */ React4.createElement(Input3.Root, {
521
+ return /* @__PURE__ */ React5.createElement(Input3.Root, {
282
522
  validationValence: status
283
- }, /* @__PURE__ */ React4.createElement(InputHeader, {
523
+ }, /* @__PURE__ */ React5.createElement(InputHeader, {
284
524
  error
285
- }, /* @__PURE__ */ React4.createElement(Input3.Label, null, label)), /* @__PURE__ */ React4.createElement("div", {
525
+ }, /* @__PURE__ */ React5.createElement(Input3.Label, null, label)), /* @__PURE__ */ React5.createElement("div", {
286
526
  role: "none"
287
- }, options && /* @__PURE__ */ React4.createElement(List.Root, {
527
+ }, options && /* @__PURE__ */ React5.createElement(List.Root, {
288
528
  items: options,
289
529
  isItem: (item) => true,
290
530
  onMove: handleMove
291
- }, ({ items }) => /* @__PURE__ */ React4.createElement("div", {
531
+ }, ({ items }) => /* @__PURE__ */ React5.createElement("div", {
292
532
  role: "list",
293
533
  className: "w-full overflow-auto"
294
- }, items?.map((item) => /* @__PURE__ */ React4.createElement("div", {
534
+ }, items?.map((item) => /* @__PURE__ */ React5.createElement("div", {
295
535
  key: item.id
296
- }, /* @__PURE__ */ React4.createElement(List.Item, {
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__ */ React4.createElement("div", {
541
+ }, /* @__PURE__ */ React5.createElement("div", {
302
542
  className: "flex items-center"
303
- }, /* @__PURE__ */ React4.createElement(List.ItemDragHandle, null), /* @__PURE__ */ React4.createElement(List.ItemTitle, {
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__ */ React4.createElement(Tag, {
546
+ }, /* @__PURE__ */ React5.createElement(Tag, {
307
547
  palette: item.color
308
- }, item.title || "\u200B")), /* @__PURE__ */ React4.createElement(Icon2, {
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__ */ React4.createElement("div", {
551
+ })), selected === item.id && /* @__PURE__ */ React5.createElement("div", {
312
552
  className: "mis-4 mbs-2 flex flex-col gap-1"
313
- }, /* @__PURE__ */ React4.createElement(Input3.Label, {
553
+ }, /* @__PURE__ */ React5.createElement(Input3.Label, {
314
554
  classNames: "text-xs"
315
- }, t("select option label")), /* @__PURE__ */ React4.createElement("div", {
555
+ }, t("select option label")), /* @__PURE__ */ React5.createElement("div", {
316
556
  className: "flex flex-row items-center gap-1"
317
- }, /* @__PURE__ */ React4.createElement(Input3.TextInput, {
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
- }), /* @__PURE__ */ React4.createElement(Toolbar.Root, {
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__ */ React4.createElement(HuePickerToolbarButton, {
567
+ }, /* @__PURE__ */ React5.createElement(HuePickerToolbarButton, {
327
568
  hue: item.color,
328
569
  onChangeHue: handleColorChange(item.id)
329
- })), /* @__PURE__ */ React4.createElement(IconButton, {
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__ */ React4.createElement("div", {
575
+ })))))), /* @__PURE__ */ React5.createElement("div", {
335
576
  role: "listitem"
336
- }, /* @__PURE__ */ React4.createElement("div", {
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__ */ React4.createElement("div", {
581
+ }, /* @__PURE__ */ React5.createElement("div", {
341
582
  className: "flex items-center gap-1"
342
- }, /* @__PURE__ */ React4.createElement(Icon2, {
583
+ }, /* @__PURE__ */ React5.createElement(Icon2, {
343
584
  icon: "ph--plus--regular"
344
- }), /* @__PURE__ */ React4.createElement("span", {
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 React5 from "react";
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__ */ React5.createElement(Input4.Root, {
604
+ return /* @__PURE__ */ React6.createElement(Input4.Root, {
364
605
  validationValence: status
365
- }, /* @__PURE__ */ React5.createElement(InputHeader, {
606
+ }, /* @__PURE__ */ React6.createElement(InputHeader, {
366
607
  error
367
- }, /* @__PURE__ */ React5.createElement(Input4.Label, null, label)), /* @__PURE__ */ React5.createElement("div", {
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__ */ React5.createElement(Input4.TextInput, {
610
+ }, binding.map((prop) => /* @__PURE__ */ React6.createElement(Input4.TextInput, {
370
611
  key: prop,
371
612
  type: "number",
372
613
  disabled,
@@ -380,286 +621,118 @@ var TupleInput = ({ binding, type, label, disabled, getStatus, getValue: getValu
380
621
  };
381
622
 
382
623
  // packages/ui/react-ui-form/src/components/Form/Defaults.tsx
383
- import React6 from "react";
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__ */ React6.createElement(Input5.Root, {
628
+ return /* @__PURE__ */ React7.createElement(Input5.Root, {
388
629
  validationValence: status
389
- }, !inputOnly && /* @__PURE__ */ React6.createElement(InputHeader, {
630
+ }, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
390
631
  error
391
- }, /* @__PURE__ */ React6.createElement(Input5.Label, null, label)), /* @__PURE__ */ React6.createElement(Input5.TextInput, {
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__ */ React6.createElement(Input5.Validation, null, error));
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__ */ React6.createElement(Input5.Root, {
642
+ return /* @__PURE__ */ React7.createElement(Input5.Root, {
402
643
  validationValence: status
403
- }, !inputOnly && /* @__PURE__ */ React6.createElement(InputHeader, {
644
+ }, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
404
645
  error
405
- }, /* @__PURE__ */ React6.createElement(Input5.Label, null, label)), /* @__PURE__ */ React6.createElement(Input5.TextInput, {
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__ */ React6.createElement(Input5.DescriptionAndValidation, null, error));
653
+ }), inputOnly && /* @__PURE__ */ React7.createElement(Input5.DescriptionAndValidation, null, error));
413
654
  };
414
655
  var BooleanInput = ({ type, label, inputOnly, getStatus, getValue: getValue3, onValueChange }) => {
415
656
  const { status, error } = getStatus();
416
657
  const checked = Boolean(getValue3());
417
- return /* @__PURE__ */ React6.createElement(Input5.Root, {
658
+ return /* @__PURE__ */ React7.createElement(Input5.Root, {
418
659
  validationValence: status
419
- }, !inputOnly && /* @__PURE__ */ React6.createElement(InputHeader, {
660
+ }, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
420
661
  error
421
- }, /* @__PURE__ */ React6.createElement(Input5.Label, null, label)), /* @__PURE__ */ React6.createElement(Input5.Switch, {
662
+ }, /* @__PURE__ */ React7.createElement(Input5.Label, null, label)), /* @__PURE__ */ React7.createElement(Input5.Switch, {
422
663
  checked,
423
664
  onCheckedChange: (value) => onValueChange(type, value)
424
- }), inputOnly && /* @__PURE__ */ React6.createElement(Input5.DescriptionAndValidation, null, error));
665
+ }), inputOnly && /* @__PURE__ */ React7.createElement(Input5.DescriptionAndValidation, null, error));
425
666
  };
426
667
  var SelectInput = ({ type, label, inputOnly, disabled, placeholder, options, getStatus, getValue: getValue3, onValueChange }) => {
427
668
  const { status, error } = getStatus();
428
- return /* @__PURE__ */ React6.createElement(Input5.Root, {
669
+ return /* @__PURE__ */ React7.createElement(Input5.Root, {
429
670
  validationValence: status
430
- }, !inputOnly && /* @__PURE__ */ React6.createElement(InputHeader, {
671
+ }, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
431
672
  error
432
- }, /* @__PURE__ */ React6.createElement(Input5.Label, null, label)), /* @__PURE__ */ React6.createElement(Select.Root, {
673
+ }, /* @__PURE__ */ React7.createElement(Input5.Label, null, label)), /* @__PURE__ */ React7.createElement(Select.Root, {
433
674
  value: getValue3(),
434
675
  onValueChange: (value) => onValueChange(type, value)
435
- }, /* @__PURE__ */ React6.createElement(Select.TriggerButton, {
676
+ }, /* @__PURE__ */ React7.createElement(Select.TriggerButton, {
436
677
  classNames: "is-full",
437
678
  disabled,
438
679
  placeholder
439
- }), /* @__PURE__ */ React6.createElement(Select.Portal, null, /* @__PURE__ */ React6.createElement(Select.Content, null, /* @__PURE__ */ React6.createElement(Select.Viewport, null, options?.map(({ value, label: label2 }) => (
680
+ }), /* @__PURE__ */ React7.createElement(Select.Portal, null, /* @__PURE__ */ React7.createElement(Select.Content, null, /* @__PURE__ */ React7.createElement(Select.Viewport, null, options?.map(({ value, label: label2 }) => (
440
681
  // NOTE: Numeric values are converted to and from strings.
441
- /* @__PURE__ */ React6.createElement(Select.Option, {
682
+ /* @__PURE__ */ React7.createElement(Select.Option, {
442
683
  key: String(value),
443
684
  value: String(value)
444
685
  }, label2 ?? String(value))
445
- )))))), inputOnly && /* @__PURE__ */ React6.createElement(Input5.DescriptionAndValidation, null, error));
686
+ )))))), inputOnly && /* @__PURE__ */ React7.createElement(Input5.DescriptionAndValidation, null, error));
446
687
  };
447
-
448
- // packages/ui/react-ui-form/src/components/Form/Form.tsx
449
- import React11, { useEffect as useEffect3, useMemo as useMemo4 } from "react";
450
- import { mx as mx7 } from "@dxos/react-ui-theme";
451
-
452
- // packages/ui/react-ui-form/src/components/Form/FormActions.tsx
453
- import React8 from "react";
454
- import { IconButton as IconButton2, useTranslation as useTranslation3 } from "@dxos/react-ui";
455
- import { mx as mx4 } from "@dxos/react-ui-theme";
456
-
457
- // packages/ui/react-ui-form/src/components/Form/FormContext.tsx
458
- import React7, { createContext, useContext } from "react";
459
- import { raise } from "@dxos/debug";
460
- import { getValue as getValue2 } from "@dxos/echo-schema";
461
- import { createJsonPath as createJsonPath2 } from "@dxos/effect";
462
-
463
- // packages/ui/react-ui-form/src/hooks/useForm.ts
464
- import { useCallback as useCallback2, useEffect as useEffect2, useMemo, useState as useState2 } from "react";
465
- import { getValue, setValue } from "@dxos/echo-schema";
466
- import { AST, createJsonPath, fromEffectValidationPath } from "@dxos/effect";
467
- import { invariant } from "@dxos/invariant";
468
- import { log } from "@dxos/log";
469
- import { validateSchema } from "@dxos/schema";
470
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/hooks/useForm.ts";
471
- var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, onSave }) => {
472
- invariant(AST.isTypeLiteral(schema.ast), void 0, {
473
- F: __dxlog_file,
474
- L: 91,
475
- S: void 0,
476
- A: [
477
- "AST.isTypeLiteral(schema.ast)",
478
- ""
479
- ]
480
- });
481
- const [values, setValues] = useState2(initialValues);
482
- useEffect2(() => {
483
- setValues(initialValues);
484
- }, [
485
- initialValues
486
- ]);
487
- const [touched, setTouched] = useState2(createKeySet(initialValues, false));
488
- const [changed, setChanged] = useState2(createKeySet(initialValues, false));
489
- const [errors, setErrors] = useState2({});
490
- const [saving, setSaving] = useState2(false);
491
- const validate = useCallback2((values2) => {
492
- let errors2 = validateSchema(schema, values2) ?? [];
493
- if (errors2.length === 0 && onValidate) {
494
- const validatedValues = values2;
495
- errors2 = onValidate(validatedValues) ?? [];
496
- }
497
- setErrors(flatMap(errors2));
498
- const valid = errors2.length === 0;
499
- return valid;
500
- }, [
501
- schema,
502
- onValidate
503
- ]);
504
- const [schemaDirty, setSchemaDirty] = useState2(false);
505
- useEffect2(() => setSchemaDirty(true), [
506
- schema
507
- ]);
508
- useEffect2(() => {
509
- if (schemaDirty) {
510
- validate(values);
511
- setSchemaDirty(false);
512
- }
513
- }, [
514
- values,
515
- schemaDirty
516
- ]);
517
- const canSave = useMemo(() => !saving && // Check if any error paths that are touched have errors
518
- !Object.entries(touched).some(([path, isTouched]) => isTouched && Object.keys(errors).some((errorPath) => errorPath === path || errorPath.startsWith(`${path}.`) || errorPath.startsWith(`${path}[`))), [
519
- touched,
520
- errors,
521
- saving
522
- ]);
523
- const handleSave = useCallback2(async () => {
524
- if (validate(values)) {
525
- setSaving(true);
526
- try {
527
- await onSave?.(values, {
528
- changed
529
- });
530
- } finally {
531
- setSaving(false);
532
- }
688
+ var MarkdownInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
689
+ const { status, error } = getStatus();
690
+ const textareaRef = useRef2(null);
691
+ const adjustHeight = useCallback3(() => {
692
+ const textarea = textareaRef.current;
693
+ if (textarea) {
694
+ textarea.style.blockSize = "auto";
695
+ textarea.style.blockSize = `${textarea.scrollHeight + 2}px`;
533
696
  }
697
+ }, []);
698
+ useEffect4(() => {
699
+ adjustHeight();
534
700
  }, [
535
- values,
536
- validate,
537
- onSave,
538
- changed
539
- ]);
540
- const getStatus = useCallback2((path) => {
541
- const jsonPath = Array.isArray(path) ? createJsonPath(path) : path;
542
- const matchingError = Object.entries(errors).find(([errorPath]) => errorPath === jsonPath || errorPath.startsWith(`${jsonPath}.`) || errorPath.startsWith(`${jsonPath}[`));
543
- return {
544
- status: matchingError ? "error" : void 0,
545
- error: matchingError ? matchingError[1] : void 0
546
- };
547
- }, [
548
- errors
701
+ adjustHeight
549
702
  ]);
550
- const getFormValue = (path) => {
551
- return getValue(values, createJsonPath(path));
552
- };
553
- const onValueChange = (path, type, value) => {
554
- const jsonPath = createJsonPath(path);
555
- let parsedValue = value;
556
- try {
557
- if (type === "number") {
558
- parsedValue = parseFloat(value) || 0;
559
- }
560
- } catch (err) {
561
- log.catch(err, void 0, {
562
- F: __dxlog_file,
563
- L: 193,
564
- S: void 0,
565
- C: (f, a) => f(...a)
566
- });
567
- parsedValue = void 0;
568
- }
569
- const newValues = {
570
- ...setValue(values, jsonPath, parsedValue)
571
- };
572
- setValues(newValues);
573
- setChanged((prev) => ({
574
- ...prev,
575
- [jsonPath]: true
576
- }));
577
- onValuesChanged?.(newValues);
578
- const isValid = validate(newValues);
579
- if (isValid && onValid) {
580
- onValid(newValues, {
581
- changed
582
- });
583
- }
584
- };
585
- const onTouched = useCallback2((path) => {
586
- const jsonPath = createJsonPath(path);
587
- setTouched((touched2) => ({
588
- ...touched2,
589
- [jsonPath]: true
590
- }));
591
- validate(values);
703
+ useEffect4(() => {
704
+ adjustHeight();
592
705
  }, [
593
- validate,
594
- values
706
+ getValue3(),
707
+ adjustHeight
595
708
  ]);
596
- return {
597
- // State.
598
- values,
599
- errors,
600
- touched,
601
- changed,
602
- canSave,
603
- handleSave,
604
- // Field utils.
605
- getStatus,
606
- getValue: getFormValue,
607
- onValueChange,
608
- onTouched
609
- };
610
- };
611
- var createKeySet = (obj, value) => {
612
- invariant(obj, void 0, {
613
- F: __dxlog_file,
614
- L: 235,
615
- S: void 0,
616
- A: [
617
- "obj",
618
- ""
619
- ]
620
- });
621
- return Object.keys(obj).reduce((acc, key) => ({
622
- ...acc,
623
- [key]: value
624
- }), {});
625
- };
626
- var flatMap = (errors) => {
627
- return errors.reduce((result, { path, message }) => {
628
- const jsonPath = fromEffectValidationPath(path);
629
- if (!(jsonPath in result)) {
630
- result[jsonPath] = message;
631
- }
632
- return result;
633
- }, {});
709
+ return /* @__PURE__ */ React7.createElement(Input5.Root, {
710
+ validationValence: status
711
+ }, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
712
+ error
713
+ }, /* @__PURE__ */ React7.createElement(Input5.Label, null, label)), /* @__PURE__ */ React7.createElement(Input5.TextArea, {
714
+ ref: textareaRef,
715
+ disabled,
716
+ placeholder,
717
+ value: getValue3() ?? "",
718
+ classNames: "min-bs-auto overflow-hidden",
719
+ onChange: (event) => onValueChange(type, event.target.value),
720
+ onBlur,
721
+ style: {
722
+ resize: "none"
723
+ },
724
+ spellCheck: false
725
+ }), inputOnly && /* @__PURE__ */ React7.createElement(Input5.Validation, null, error));
634
726
  };
635
727
 
636
- // packages/ui/react-ui-form/src/components/Form/FormContext.tsx
637
- var FormContext = /* @__PURE__ */ createContext(void 0);
638
- var useFormContext = () => {
639
- return useContext(FormContext) ?? raise(new Error("Missing FormContext"));
640
- };
641
- var useFormValues = (path = []) => {
642
- const { values: formValues } = useFormContext();
643
- const jsonPath = createJsonPath2(path);
644
- return getValue2(formValues, jsonPath);
645
- };
646
- var useInputProps = (path = []) => {
647
- const { getStatus, getValue: getFormValue, onValueChange, onTouched } = useFormContext();
648
- return {
649
- getStatus: () => getStatus(path),
650
- getValue: () => getFormValue(path),
651
- onValueChange: (type, value) => onValueChange(path, type, value),
652
- onBlur: () => onTouched(path)
653
- };
654
- };
655
- var FormProvider = ({ children, ...formOptions }) => {
656
- const formHandler = useForm(formOptions);
657
- return /* @__PURE__ */ React7.createElement(FormContext.Provider, {
658
- value: formHandler
659
- }, children);
660
- };
728
+ // packages/ui/react-ui-form/src/components/Form/Form.tsx
729
+ import React11, { useEffect as useEffect5, useMemo as useMemo4, useRef as useRef3 } from "react";
730
+ import { mx as mx7 } from "@dxos/react-ui-theme";
661
731
 
662
732
  // packages/ui/react-ui-form/src/components/Form/FormActions.tsx
733
+ import React8 from "react";
734
+ import { IconButton as IconButton2, useTranslation as useTranslation3 } from "@dxos/react-ui";
735
+ import { mx as mx4 } from "@dxos/react-ui-theme";
663
736
  var FormActions = ({ onCancel, readonly }) => {
664
737
  const { t } = useTranslation3(translationKey);
665
738
  const { canSave, handleSave } = useFormContext();
@@ -697,7 +770,7 @@ import { isNotFalsy } from "@dxos/util";
697
770
  // packages/ui/react-ui-form/src/components/Form/ArrayField.tsx
698
771
  import { pipe } from "effect";
699
772
  import { capitalize } from "effect/String";
700
- import React9, { useCallback as useCallback3, useMemo as useMemo2 } from "react";
773
+ import React9, { useCallback as useCallback4, useMemo as useMemo2 } from "react";
701
774
  import { AST as AST2 } from "@dxos/echo-schema";
702
775
  import { findNode, getDiscriminatedType, isDiscriminatedUnion, SimpleType } from "@dxos/effect";
703
776
  import { invariant as invariant2 } from "@dxos/invariant";
@@ -743,7 +816,7 @@ var ArrayField = ({ property, readonly, path, inputProps, Custom, lookupComponen
743
816
  type,
744
817
  elementType
745
818
  ]);
746
- const handleAdd = useCallback3(() => {
819
+ const handleAdd = useCallback4(() => {
747
820
  inputProps.onValueChange(type, [
748
821
  ...values,
749
822
  newValue
@@ -755,7 +828,7 @@ var ArrayField = ({ property, readonly, path, inputProps, Custom, lookupComponen
755
828
  newValue,
756
829
  values
757
830
  ]);
758
- const handleRemove = useCallback3((index) => {
831
+ const handleRemove = useCallback4((index) => {
759
832
  const newValues = values.filter((_, i) => i !== index);
760
833
  inputProps.onValueChange(type, newValues);
761
834
  }, [
@@ -815,6 +888,8 @@ var getInputComponent = (type, format) => {
815
888
  switch (format) {
816
889
  case FormatEnum.LatLng:
817
890
  return GeoPointInput;
891
+ case FormatEnum.Markdown:
892
+ return MarkdownInput;
818
893
  }
819
894
  switch (type) {
820
895
  case "string":
@@ -858,20 +933,15 @@ var FormField = ({ property, path, readonly, inline, lookupComponent, Custom })
858
933
  const jsonPath = createJsonPath3(path ?? []);
859
934
  const CustomComponent = Custom?.[jsonPath];
860
935
  if (CustomComponent) {
861
- return (
862
- // TODO(ZaymonFC): We should try to remove this div wrapper.
863
- /* @__PURE__ */ React10.createElement("div", {
864
- role: "none"
865
- }, /* @__PURE__ */ React10.createElement(CustomComponent, {
866
- type,
867
- format,
868
- label,
869
- inputOnly: inline,
870
- placeholder,
871
- disabled: readonly,
872
- ...inputProps
873
- }))
874
- );
936
+ return /* @__PURE__ */ React10.createElement(CustomComponent, {
937
+ type,
938
+ format,
939
+ label,
940
+ inputOnly: inline,
941
+ placeholder,
942
+ disabled: readonly,
943
+ ...inputProps
944
+ });
875
945
  }
876
946
  if (array) {
877
947
  return /* @__PURE__ */ React10.createElement(ArrayField, {
@@ -961,13 +1031,14 @@ var FormFields = ({ schema, path, filter, sort, readonly, lookupComponent, Custo
961
1031
 
962
1032
  // packages/ui/react-ui-form/src/components/Form/Form.tsx
963
1033
  var Form = ({ classNames, schema, values: initialValues, path = [], autoFocus, readonly, filter, sort, autoSave, testId, onValuesChanged, onValidate, onSave, onCancel, lookupComponent, Custom }) => {
1034
+ const formRef = useRef3(null);
964
1035
  const onValid = useMemo4(() => autoSave ? onSave : void 0, [
965
1036
  autoSave,
966
1037
  onSave
967
1038
  ]);
968
- useEffect3(() => {
969
- if (autoFocus) {
970
- const input = document.querySelector("input");
1039
+ useEffect5(() => {
1040
+ if (autoFocus && formRef.current) {
1041
+ const input = formRef.current.querySelector("input");
971
1042
  if (input) {
972
1043
  input.focus();
973
1044
  }
@@ -976,13 +1047,16 @@ var Form = ({ classNames, schema, values: initialValues, path = [], autoFocus, r
976
1047
  autoFocus
977
1048
  ]);
978
1049
  return /* @__PURE__ */ React11.createElement(FormProvider, {
1050
+ formRef,
979
1051
  schema,
1052
+ autoSave,
980
1053
  initialValues,
981
1054
  onValuesChanged,
982
1055
  onValidate,
983
1056
  onValid,
984
1057
  onSave
985
1058
  }, /* @__PURE__ */ React11.createElement("div", {
1059
+ ref: formRef,
986
1060
  role: "none",
987
1061
  className: mx7("p-2", classNames),
988
1062
  "data-testid": testId
@@ -1005,12 +1079,12 @@ var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/c
1005
1079
  var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
1006
1080
  const { t } = useTranslation5(translationKey);
1007
1081
  const [props, setProps] = useState3(projection.getFieldProjection(field.id).props);
1008
- useEffect4(() => setProps(projection.getFieldProjection(field.id).props), [
1082
+ useEffect6(() => setProps(projection.getFieldProjection(field.id).props), [
1009
1083
  field,
1010
1084
  projection
1011
1085
  ]);
1012
1086
  const [schemas, setSchemas] = useState3([]);
1013
- useEffect4(() => {
1087
+ useEffect6(() => {
1014
1088
  if (!registry) {
1015
1089
  return;
1016
1090
  }
@@ -1029,7 +1103,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
1029
1103
  registry
1030
1104
  ]);
1031
1105
  const [referenceSchema, setReferenceSchema] = useState3();
1032
- useEffect4(() => {
1106
+ useEffect6(() => {
1033
1107
  setReferenceSchema(schemas.find((schema) => schema.typename === props?.referenceSchema));
1034
1108
  }, [
1035
1109
  schemas,
@@ -1038,7 +1112,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
1038
1112
  const [{ fieldSchema }, setFieldSchema] = useState3({
1039
1113
  fieldSchema: getFormatSchema(props?.format)
1040
1114
  });
1041
- const handleValuesChanged = useCallback4((_props) => {
1115
+ const handleValuesChanged = useCallback5((_props) => {
1042
1116
  setFieldSchema((prev) => {
1043
1117
  const fieldSchema2 = getFormatSchema(_props.format);
1044
1118
  if (prev.fieldSchema === fieldSchema2) {
@@ -1073,7 +1147,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
1073
1147
  props.format,
1074
1148
  props.referenceSchema
1075
1149
  ]);
1076
- const handleValidate = useCallback4(({ property }) => {
1150
+ const handleValidate = useCallback5(({ property }) => {
1077
1151
  if (property && view.fields.find((f) => f.path === property && f.path !== field.path)) {
1078
1152
  return [
1079
1153
  {
@@ -1086,7 +1160,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
1086
1160
  view.fields,
1087
1161
  field
1088
1162
  ]);
1089
- const handleSave = useCallback4((props2) => {
1163
+ const handleSave = useCallback5((props2) => {
1090
1164
  projection.setFieldProjection({
1091
1165
  field,
1092
1166
  props: props2
@@ -1097,7 +1171,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
1097
1171
  field,
1098
1172
  onSave
1099
1173
  ]);
1100
- const handleCancel = useCallback4(() => {
1174
+ const handleCancel = useCallback5(() => {
1101
1175
  requestAnimationFrame(() => onCancel?.());
1102
1176
  onSave();
1103
1177
  }, [
@@ -1129,7 +1203,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
1129
1203
  schemas,
1130
1204
  referenceSchema
1131
1205
  ]);
1132
- const propIsNotType = useCallback4((props2) => props2.filter((p) => p.name !== "type"), []);
1206
+ const propIsNotType = useCallback5((props2) => props2.filter((p) => p.name !== "type"), []);
1133
1207
  if (!fieldSchema) {
1134
1208
  log2.warn("invalid format", {
1135
1209
  props
@@ -1160,7 +1234,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
1160
1234
  };
1161
1235
 
1162
1236
  // packages/ui/react-ui-form/src/components/ViewEditor/ViewEditor.tsx
1163
- import React13, { useCallback as useCallback5, useMemo as useMemo6, useState as useState4 } from "react";
1237
+ import React13, { useCallback as useCallback6, useMemo as useMemo6, useState as useState4 } from "react";
1164
1238
  import { AST as AST4, Format, S as S2 } from "@dxos/echo-schema";
1165
1239
  import { IconButton as IconButton4, useTranslation as useTranslation6 } from "@dxos/react-ui";
1166
1240
  import { List as List2 } from "@dxos/react-ui-list";
@@ -1171,7 +1245,7 @@ var ViewMetaSchema = S2.Struct({
1171
1245
  name: S2.String.annotations({
1172
1246
  [AST4.TitleAnnotationId]: "View"
1173
1247
  }),
1174
- typename: Format.DXN.annotations({
1248
+ typename: Format.URL.annotations({
1175
1249
  [AST4.TitleAnnotationId]: "Typename"
1176
1250
  })
1177
1251
  }).pipe(S2.mutable);
@@ -1192,7 +1266,7 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
1192
1266
  }, [
1193
1267
  view
1194
1268
  ]);
1195
- const handleViewUpdate = useCallback5(({ name, typename }) => {
1269
+ const handleViewUpdate = useCallback6(({ name, typename }) => {
1196
1270
  requestAnimationFrame(() => {
1197
1271
  if (view.name !== name) {
1198
1272
  view.name = name;
@@ -1206,16 +1280,16 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
1206
1280
  schema,
1207
1281
  onTypenameChanged
1208
1282
  ]);
1209
- const handleSelect = useCallback5((field2) => {
1283
+ const handleSelect = useCallback6((field2) => {
1210
1284
  setField((f) => f === field2 ? void 0 : field2);
1211
1285
  }, []);
1212
- const handleAdd = useCallback5(() => {
1286
+ const handleAdd = useCallback6(() => {
1213
1287
  const field2 = projection.createFieldProjection();
1214
1288
  setField(field2);
1215
1289
  }, [
1216
1290
  view
1217
1291
  ]);
1218
- const handleMove = useCallback5((fromIndex, toIndex) => {
1292
+ const handleMove = useCallback6((fromIndex, toIndex) => {
1219
1293
  const fields = [
1220
1294
  ...view.fields
1221
1295
  ];
@@ -1225,12 +1299,11 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
1225
1299
  }, [
1226
1300
  view.fields
1227
1301
  ]);
1228
- const handleClose = useCallback5(() => setField(void 0), []);
1302
+ const handleClose = useCallback6(() => setField(void 0), []);
1229
1303
  return /* @__PURE__ */ React13.createElement("div", {
1230
1304
  role: "none",
1231
1305
  className: mx8("flex flex-col w-full divide-y divide-separator", classNames)
1232
1306
  }, /* @__PURE__ */ React13.createElement(Form, {
1233
- autoFocus: true,
1234
1307
  autoSave: true,
1235
1308
  schema: ViewMetaSchema,
1236
1309
  values: viewValues,
@@ -1507,6 +1580,7 @@ export {
1507
1580
  Form,
1508
1581
  GeoPointInput,
1509
1582
  InputHeader,
1583
+ MarkdownInput,
1510
1584
  NumberInput,
1511
1585
  SelectInput,
1512
1586
  SelectOptionInput,
@@ -1520,6 +1594,7 @@ export {
1520
1594
  parseValue,
1521
1595
  pathNotUniqueError,
1522
1596
  translations_default as translations,
1523
- useForm
1597
+ useForm,
1598
+ useFormValues
1524
1599
  };
1525
1600
  //# sourceMappingURL=index.mjs.map