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