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