@dxos/react-ui-form 0.8.4-main.4a85c3132b → 0.8.4-main.51f1e5ca51

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 (141) hide show
  1. package/dist/lib/browser/index.mjs +1005 -585
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/browser/translations.mjs +82 -0
  5. package/dist/lib/browser/translations.mjs.map +7 -0
  6. package/dist/lib/node-esm/index.mjs +1005 -585
  7. package/dist/lib/node-esm/index.mjs.map +4 -4
  8. package/dist/lib/node-esm/meta.json +1 -1
  9. package/dist/lib/node-esm/translations.mjs +84 -0
  10. package/dist/lib/node-esm/translations.mjs.map +7 -0
  11. package/dist/types/src/components/FieldEditor/FieldEditor.d.ts.map +1 -1
  12. package/dist/types/src/components/FieldEditor/FieldEditor.stories.d.ts +63 -61
  13. package/dist/types/src/components/FieldEditor/FieldEditor.stories.d.ts.map +1 -1
  14. package/dist/types/src/components/Form/Form.d.ts +40 -12
  15. package/dist/types/src/components/Form/Form.d.ts.map +1 -1
  16. package/dist/types/src/components/Form/Form.stories.d.ts +76 -74
  17. package/dist/types/src/components/Form/Form.stories.d.ts.map +1 -1
  18. package/dist/types/src/components/Form/FormField.d.ts +11 -5
  19. package/dist/types/src/components/Form/FormField.d.ts.map +1 -1
  20. package/dist/types/src/components/Form/FormFieldComponent.d.ts +8 -7
  21. package/dist/types/src/components/Form/FormFieldComponent.d.ts.map +1 -1
  22. package/dist/types/src/components/Form/FormFieldComponent.stories.d.ts.map +1 -1
  23. package/dist/types/src/components/Form/FormFieldSet.d.ts +5 -9
  24. package/dist/types/src/components/Form/FormFieldSet.d.ts.map +1 -1
  25. package/dist/types/src/components/Form/fields/ArrayField.d.ts +4 -4
  26. package/dist/types/src/components/Form/fields/ArrayField.d.ts.map +1 -1
  27. package/dist/types/src/components/Form/fields/BooleanField.d.ts.map +1 -1
  28. package/dist/types/src/components/Form/fields/GeoPointField.d.ts.map +1 -1
  29. package/dist/types/src/components/Form/fields/MarkdownField.d.ts +8 -1
  30. package/dist/types/src/components/Form/fields/MarkdownField.d.ts.map +1 -1
  31. package/dist/types/src/components/Form/fields/MarkdownField.stories.d.ts +83 -0
  32. package/dist/types/src/components/Form/fields/MarkdownField.stories.d.ts.map +1 -0
  33. package/dist/types/src/components/Form/fields/NumberField.d.ts.map +1 -1
  34. package/dist/types/src/components/Form/fields/RefField.d.ts +15 -7
  35. package/dist/types/src/components/Form/fields/RefField.d.ts.map +1 -1
  36. package/dist/types/src/components/Form/fields/SelectField.d.ts.map +1 -1
  37. package/dist/types/src/components/Form/fields/SelectOptionField.d.ts.map +1 -1
  38. package/dist/types/src/components/Form/fields/SelectOptionField.stories.d.ts +63 -61
  39. package/dist/types/src/components/Form/fields/SelectOptionField.stories.d.ts.map +1 -1
  40. package/dist/types/src/components/Form/fields/TextAreaField.d.ts.map +1 -1
  41. package/dist/types/src/components/Form/fields/TextField.d.ts +1 -1
  42. package/dist/types/src/components/Form/fields/TextField.d.ts.map +1 -1
  43. package/dist/types/src/components/Form/fields/TupleField.d.ts.map +1 -1
  44. package/dist/types/src/components/ObjectForm/ObjectForm.d.ts +9 -0
  45. package/dist/types/src/components/ObjectForm/ObjectForm.d.ts.map +1 -0
  46. package/dist/types/src/components/ObjectForm/index.d.ts +2 -0
  47. package/dist/types/src/components/ObjectForm/index.d.ts.map +1 -0
  48. package/dist/types/src/components/ObjectPicker/ObjectPicker.d.ts +26 -4
  49. package/dist/types/src/components/ObjectPicker/ObjectPicker.d.ts.map +1 -1
  50. package/dist/types/src/components/ObjectPicker/ObjectPicker.stories.d.ts +63 -61
  51. package/dist/types/src/components/ObjectPicker/ObjectPicker.stories.d.ts.map +1 -1
  52. package/dist/types/src/components/ObjectProperties/ObjectProperties.d.ts +9 -0
  53. package/dist/types/src/components/ObjectProperties/ObjectProperties.d.ts.map +1 -0
  54. package/dist/types/src/components/ObjectProperties/ObjectProperties.stories.d.ts +127 -0
  55. package/dist/types/src/components/ObjectProperties/ObjectProperties.stories.d.ts.map +1 -0
  56. package/dist/types/src/components/ObjectProperties/ObjectProperties.test.d.ts +2 -0
  57. package/dist/types/src/components/ObjectProperties/ObjectProperties.test.d.ts.map +1 -0
  58. package/dist/types/src/components/ObjectProperties/index.d.ts +2 -0
  59. package/dist/types/src/components/ObjectProperties/index.d.ts.map +1 -0
  60. package/dist/types/src/components/Settings/Settings.d.ts +28 -33
  61. package/dist/types/src/components/Settings/Settings.d.ts.map +1 -1
  62. package/dist/types/src/components/Settings/Settings.stories.d.ts +64 -61
  63. package/dist/types/src/components/Settings/Settings.stories.d.ts.map +1 -1
  64. package/dist/types/src/components/Settings/SettingsFieldSet.d.ts +43 -0
  65. package/dist/types/src/components/Settings/SettingsFieldSet.d.ts.map +1 -0
  66. package/dist/types/src/components/Settings/SettingsItem.d.ts +16 -0
  67. package/dist/types/src/components/Settings/SettingsItem.d.ts.map +1 -0
  68. package/dist/types/src/components/Settings/SettingsSelectField.d.ts +18 -0
  69. package/dist/types/src/components/Settings/SettingsSelectField.d.ts.map +1 -0
  70. package/dist/types/src/components/Settings/index.d.ts +2 -0
  71. package/dist/types/src/components/Settings/index.d.ts.map +1 -1
  72. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts +2 -2
  73. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts.map +1 -1
  74. package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts +65 -63
  75. package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts.map +1 -1
  76. package/dist/types/src/components/index.d.ts +2 -0
  77. package/dist/types/src/components/index.d.ts.map +1 -1
  78. package/dist/types/src/components/testing.d.ts +4 -4
  79. package/dist/types/src/components/testing.d.ts.map +1 -1
  80. package/dist/types/src/hooks/useFormHandler.d.ts.map +1 -1
  81. package/dist/types/src/hooks/useKeyHandler.d.ts +2 -1
  82. package/dist/types/src/hooks/useKeyHandler.d.ts.map +1 -1
  83. package/dist/types/src/index.d.ts +0 -2
  84. package/dist/types/src/index.d.ts.map +1 -1
  85. package/dist/types/src/translations.d.ts +63 -61
  86. package/dist/types/src/translations.d.ts.map +1 -1
  87. package/dist/types/src/util/field-type.d.ts +19 -0
  88. package/dist/types/src/util/field-type.d.ts.map +1 -0
  89. package/dist/types/src/util/field.d.ts.map +1 -1
  90. package/dist/types/src/util/formatting.d.ts.map +1 -1
  91. package/dist/types/src/util/index.d.ts +1 -0
  92. package/dist/types/src/util/index.d.ts.map +1 -1
  93. package/dist/types/src/util/properties.d.ts.map +1 -1
  94. package/dist/types/src/util/refs.d.ts +1 -0
  95. package/dist/types/src/util/refs.d.ts.map +1 -1
  96. package/dist/types/tsconfig.tsbuildinfo +1 -1
  97. package/package.json +42 -40
  98. package/src/components/FieldEditor/FieldEditor.stories.tsx +2 -2
  99. package/src/components/FieldEditor/FieldEditor.test.tsx +0 -1
  100. package/src/components/FieldEditor/FieldEditor.tsx +4 -3
  101. package/src/components/Form/AUDIT.md +17 -0
  102. package/src/components/Form/Form.stories.tsx +25 -38
  103. package/src/components/Form/Form.tsx +77 -47
  104. package/src/components/Form/FormField.tsx +27 -15
  105. package/src/components/Form/FormFieldComponent.tsx +3 -1
  106. package/src/components/Form/FormFieldSet.tsx +98 -77
  107. package/src/components/Form/fields/ArrayField.tsx +16 -6
  108. package/src/components/Form/fields/GeoPointField.tsx +8 -7
  109. package/src/components/Form/fields/MarkdownField.stories.tsx +152 -0
  110. package/src/components/Form/fields/MarkdownField.tsx +135 -45
  111. package/src/components/Form/fields/RefField.tsx +78 -38
  112. package/src/components/Form/fields/SelectOptionField.stories.tsx +8 -6
  113. package/src/components/Form/fields/SelectOptionField.tsx +8 -8
  114. package/src/components/Form/fields/TextField.tsx +2 -2
  115. package/src/components/Form/fields/TupleField.tsx +1 -1
  116. package/src/components/ObjectForm/ObjectForm.tsx +114 -0
  117. package/src/components/ObjectForm/index.ts +5 -0
  118. package/src/components/ObjectPicker/ObjectPicker.stories.tsx +9 -7
  119. package/src/components/ObjectPicker/ObjectPicker.tsx +83 -64
  120. package/src/components/ObjectProperties/ObjectProperties.stories.tsx +362 -0
  121. package/src/components/ObjectProperties/ObjectProperties.test.tsx +101 -0
  122. package/src/components/ObjectProperties/ObjectProperties.tsx +141 -0
  123. package/src/components/ObjectProperties/index.ts +5 -0
  124. package/src/components/Settings/AUDIT.md +52 -0
  125. package/src/components/Settings/Settings.stories.tsx +69 -21
  126. package/src/components/Settings/Settings.tsx +35 -183
  127. package/src/components/Settings/SettingsFieldSet.tsx +257 -0
  128. package/src/components/Settings/SettingsItem.tsx +62 -0
  129. package/src/components/Settings/SettingsSelectField.tsx +59 -0
  130. package/src/components/Settings/index.ts +2 -0
  131. package/src/components/ViewEditor/ViewEditor.stories.tsx +12 -12
  132. package/src/components/ViewEditor/ViewEditor.test.tsx +0 -1
  133. package/src/components/ViewEditor/ViewEditor.tsx +27 -15
  134. package/src/components/index.ts +2 -0
  135. package/src/components/testing.tsx +19 -11
  136. package/src/hooks/useKeyHandler.tsx +7 -7
  137. package/src/index.ts +0 -4
  138. package/src/translations.ts +66 -63
  139. package/src/util/field-type.ts +60 -0
  140. package/src/util/index.ts +1 -0
  141. package/src/util/refs.ts +7 -3
@@ -1,87 +1,11 @@
1
- // src/translations.ts
2
- var translationKey = "@dxos/react-ui-form";
3
- var translations = [
4
- {
5
- "en-US": {
6
- [translationKey]: {
7
- "fields label": "Fields",
8
- "hidden fields label": "Hidden Fields",
9
- "empty readonly ref field label": "(none)",
10
- // TODO(burdon): Standardize field/property.
11
- "add property button label": "Add property",
12
- "field property label": "Property",
13
- "field property placeholder": "Property name",
14
- "field format label": "Type",
15
- "field path label": "Field path",
16
- "add field": "Add field",
17
- "delete field": "Delete field",
18
- "field limit reached": "Maximum number of fields reached",
19
- "boolean input true value": "Yes",
20
- "boolean input false value": "No",
21
- "show field label": "Show field",
22
- "hide field label": "Hide field",
23
- "delete field label": "Delete field",
24
- "ref field combobox input placeholder": "Search\u2026",
25
- "ref field placeholder_one": "Select\u2026",
26
- "ref field placeholder_other": "Select items\u2026",
27
- "example placeholder": "Example",
28
- "latitude placeholder": "Latitude (e.g., 40.7128)",
29
- "longitude placeholder": "Longitude (e.g., -74.0060)",
30
- "cancel button label": "Cancel",
31
- "save button label": "Save",
32
- // FormatEnum
33
- "format boolean": "Boolean",
34
- "format currency": "Currency",
35
- "format date": "Date",
36
- "format date-time": "DateTime",
37
- "format did": "DID",
38
- "format duration": "Duration",
39
- "format dxn": "DXN",
40
- "format email": "Email",
41
- "format formula": "Formula",
42
- "format hostname": "Hostname",
43
- "format integer": "Integer",
44
- "format json": "JSON",
45
- "format lnglat": "Geopoint",
46
- "format markdown": "Markdown",
47
- "format percent": "Percent",
48
- "format ref": "Reference",
49
- "format regex": "RegExp",
50
- "format string": "String",
51
- "format single-select": "Select",
52
- "format multi-select": "Multi-select",
53
- "format text": "Long text",
54
- "format time": "Time",
55
- "format timestamp": "Timestamp",
56
- "format user": "User",
57
- "format number": "Number",
58
- "format uri": "URI",
59
- "format url": "URL",
60
- "format uuid": "UUID",
61
- // GeoPointField.
62
- "latitude label": "Latitude",
63
- "longitude label": "Longitude",
64
- // SelectOptionsField.
65
- "select option label": "Label",
66
- "select option label placeholder": "Option label",
67
- "select option color": "Color",
68
- "select option delete": "Delete",
69
- "select option add": "Add option",
70
- // System schema message.
71
- "system schema title": "System type",
72
- "system schema description": "System type: cannot add or remove fields."
73
- }
74
- }
75
- }
76
- ];
77
-
78
1
  // src/components/FieldEditor/FieldEditor.tsx
79
- import React17, { useCallback as useCallback14, useEffect as useEffect7, useMemo as useMemo7, useState as useState5 } from "react";
80
- import { Obj as Obj2 } from "@dxos/echo";
2
+ import React17, { useCallback as useCallback14, useEffect as useEffect5, useMemo as useMemo8, useState as useState6 } from "react";
3
+ import { Obj as Obj3 } from "@dxos/echo";
81
4
  import { Format as Format4, FormatEnums, formatToType } from "@dxos/echo/internal";
82
5
  import { log as log2 } from "@dxos/log";
83
- import { useAsyncEffect, useTranslation as useTranslation8 } from "@dxos/react-ui";
6
+ import { useAsyncEffect, useTranslation as useTranslation9 } from "@dxos/react-ui";
84
7
  import { formatToAdditionalPropertyAttributes, getFormatSchema } from "@dxos/schema";
8
+ import { translationKey as translationKey9 } from "#translations";
85
9
 
86
10
  // src/util/field.ts
87
11
  import { Format, GeoLocation, TypeEnum } from "@dxos/echo/internal";
@@ -204,6 +128,46 @@ var pathNotUniqueError = (path) => ({
204
128
  message: `'${path}' is already present`
205
129
  });
206
130
 
131
+ // src/util/field-type.ts
132
+ import * as SchemaAST from "effect/SchemaAST";
133
+ import { getAnnotation, isLiteralUnion } from "@dxos/effect";
134
+ var detectFieldType = (ast) => {
135
+ if (isLiteralUnion(ast)) {
136
+ return "select";
137
+ }
138
+ if (SchemaAST.isTypeLiteral(ast)) {
139
+ return "struct";
140
+ }
141
+ switch (ast._tag) {
142
+ case "BooleanKeyword":
143
+ return "boolean";
144
+ case "StringKeyword":
145
+ return "string";
146
+ case "NumberKeyword":
147
+ return "number";
148
+ }
149
+ return void 0;
150
+ };
151
+ var getSelectOptionsFromAst = (ast) => {
152
+ if (!isLiteralUnion(ast)) {
153
+ return void 0;
154
+ }
155
+ return ast.types.flatMap((literalNode) => {
156
+ const value3 = literalNode.literal;
157
+ if (typeof value3 !== "string" && typeof value3 !== "number") {
158
+ return [];
159
+ }
160
+ const title = getAnnotation(SchemaAST.TitleAnnotationId, false)(literalNode);
161
+ const label = title ?? (typeof value3 === "string" ? value3.charAt(0).toUpperCase() + value3.slice(1) : String(value3));
162
+ return [
163
+ {
164
+ value: value3,
165
+ label
166
+ }
167
+ ];
168
+ });
169
+ };
170
+
207
171
  // src/util/formatting.ts
208
172
  import { format as formatDate } from "date-fns/format";
209
173
  import { Format as Format2, GeoLocation as GeoLocation2, TypeEnum as TypeEnum2 } from "@dxos/echo/internal";
@@ -352,43 +316,52 @@ var getFormProperties = (ast) => {
352
316
 
353
317
  // src/util/refs.ts
354
318
  import { Ref } from "@dxos/echo";
355
- import { getArrayElementType, isArrayType } from "@dxos/effect";
319
+ import { ReferenceAnnotationId } from "@dxos/echo/internal";
320
+ import { findAnnotation, getArrayElementType, isArrayType } from "@dxos/effect";
356
321
  var getRefProps = (ast) => {
357
322
  if (isArrayType(ast)) {
358
323
  const elementType = getArrayElementType(ast);
359
324
  if (elementType) {
360
325
  if (Ref.isRefType(elementType)) {
326
+ const typename = findAnnotation(elementType, ReferenceAnnotationId)?.typename;
361
327
  return {
362
328
  ast: elementType,
363
- isArray: true
329
+ isArray: true,
330
+ typename
364
331
  };
365
332
  }
366
333
  }
367
334
  }
368
335
  if (Ref.isRefType(ast)) {
336
+ const typename = findAnnotation(ast, ReferenceAnnotationId)?.typename;
369
337
  return {
370
338
  ast,
371
- isArray: false
339
+ isArray: false,
340
+ typename
372
341
  };
373
342
  }
374
343
  return void 0;
375
344
  };
376
345
 
377
346
  // src/components/Form/fields/ArrayField.tsx
378
- import * as Option3 from "effect/Option";
379
- import * as SchemaAST3 from "effect/SchemaAST";
347
+ import * as Option4 from "effect/Option";
348
+ import * as SchemaAST4 from "effect/SchemaAST";
380
349
  import React5, { useCallback as useCallback3 } from "react";
381
350
  import { findNode as findNode2, getArrayElementType as getArrayElementType2, getDiscriminatedType as getDiscriminatedType2, isDiscriminatedUnion as isDiscriminatedUnion2, isNestedType as isNestedType2 } from "@dxos/effect";
382
351
  import { IconButton as IconButton2, useTranslation as useTranslation3 } from "@dxos/react-ui";
352
+ import { translationKey as translationKey3 } from "#translations";
383
353
 
384
354
  // src/components/Form/Form.tsx
385
355
  import { createContext } from "@radix-ui/react-context";
356
+ import * as Option3 from "effect/Option";
386
357
  import * as Schema2 from "effect/Schema";
387
- import * as SchemaAST2 from "effect/SchemaAST";
388
- import React4, { useEffect as useEffect3, useMemo as useMemo4, useRef } from "react";
358
+ import * as SchemaAST3 from "effect/SchemaAST";
359
+ import React4, { useEffect as useEffect2, useMemo as useMemo4, useRef } from "react";
360
+ import { Annotation as EchoAnnotation } from "@dxos/echo";
389
361
  import { createJsonPath as createJsonPath3, getValue as getValue$2 } from "@dxos/effect";
390
- import { IconButton, ScrollArea, useTranslation as useTranslation2 } from "@dxos/react-ui";
391
- import { mx as mx2 } from "@dxos/ui-theme";
362
+ import { IconButton, ScrollArea, useMergeRefs, useTranslation as useTranslation2 } from "@dxos/react-ui";
363
+ import { composable, composableProps, mx, withColumn } from "@dxos/ui-theme";
364
+ import { translationKey as translationKey2 } from "#translations";
392
365
 
393
366
  // src/hooks/useFormHandler.ts
394
367
  import { useControllableState } from "@radix-ui/react-use-controllable-state";
@@ -426,12 +399,7 @@ var useFormHandler = ({ schema, autoSave, values: valuesProp, defaultValues: def
426
399
  log("validate", {
427
400
  values: values2,
428
401
  errors: errors2
429
- }, {
430
- F: __dxlog_file,
431
- L: 155,
432
- S: void 0,
433
- C: (f, a) => f(...a)
434
- });
402
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 42, S: void 0 });
435
403
  if (errors2.length === 0 && onValidate) {
436
404
  const validatedValues = values2;
437
405
  errors2 = onValidate(validatedValues) ?? [];
@@ -519,12 +487,7 @@ var useFormHandler = ({ schema, autoSave, values: valuesProp, defaultValues: def
519
487
  log("onValueChange", {
520
488
  path,
521
489
  value: value3
522
- }, {
523
- F: __dxlog_file,
524
- L: 254,
525
- S: void 0,
526
- C: (f, a) => f(...a)
527
- });
490
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 138, S: void 0 });
528
491
  const jsonPath = createJsonPath(path);
529
492
  const pathArray = path;
530
493
  let parsedValue = value3;
@@ -533,12 +496,7 @@ var useFormHandler = ({ schema, autoSave, values: valuesProp, defaultValues: def
533
496
  parsedValue = parseFloat(value3) || 0;
534
497
  }
535
498
  } catch (err) {
536
- log.catch(err, void 0, {
537
- F: __dxlog_file,
538
- L: 264,
539
- S: void 0,
540
- C: (f, a) => f(...a)
541
- });
499
+ log.catch(err, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 150, S: void 0 });
542
500
  parsedValue = void 0;
543
501
  }
544
502
  const newValues = mergeAtPath(values, pathArray, parsedValue);
@@ -647,9 +605,9 @@ var flatMap = (errors) => {
647
605
  };
648
606
 
649
607
  // src/hooks/useKeyHandler.tsx
650
- import { useCallback as useCallback2, useEffect as useEffect2 } from "react";
608
+ import { useCallback as useCallback2, useLayoutEffect } from "react";
651
609
  import { addEventListener } from "@dxos/async";
652
- var useKeyHandler = (formElement, form) => {
610
+ var useKeyHandler = (elRef, form) => {
653
611
  const handleKeyDown = useCallback2((event) => {
654
612
  switch (event.key) {
655
613
  case "Enter": {
@@ -665,13 +623,14 @@ var useKeyHandler = (formElement, form) => {
665
623
  form.onSave,
666
624
  form.autoSave
667
625
  ]);
668
- useEffect2(() => {
669
- if (!formElement) {
626
+ useLayoutEffect(() => {
627
+ const el = elRef.current;
628
+ if (!el) {
670
629
  return;
671
630
  }
672
- return addEventListener(formElement, "keydown", handleKeyDown);
631
+ return addEventListener(el, "keydown", handleKeyDown);
673
632
  }, [
674
- formElement,
633
+ elRef,
675
634
  handleKeyDown
676
635
  ]);
677
636
  };
@@ -751,20 +710,19 @@ var FormFieldErrorBoundary = class extends Component {
751
710
  };
752
711
 
753
712
  // src/components/Form/FormFieldSet.tsx
754
- import React3, { forwardRef, useMemo as useMemo3 } from "react";
755
- import { mx } from "@dxos/ui-theme";
756
- import { isTruthy } from "@dxos/util";
713
+ import React3, { useMemo as useMemo3 } from "react";
757
714
 
758
715
  // src/components/Form/FormField.tsx
759
716
  import * as Match from "effect/Match";
760
717
  import * as Option2 from "effect/Option";
761
718
  import * as Schema from "effect/Schema";
762
- import * as SchemaAST from "effect/SchemaAST";
719
+ import * as SchemaAST2 from "effect/SchemaAST";
763
720
  import * as String2 from "effect/String";
764
721
  import React2, { useMemo as useMemo2 } from "react";
765
722
  import { Format as Format3 } from "@dxos/echo";
766
- import { createJsonPath as createJsonPath2, findNode, getAnnotation, getDiscriminatedType, isArrayType as isArrayType2, isDiscriminatedUnion, isLiteralUnion, isNestedType } from "@dxos/effect";
723
+ import { createJsonPath as createJsonPath2, findNode, getAnnotation as getAnnotation2, getDiscriminatedType, isArrayType as isArrayType2, isDiscriminatedUnion, isLiteralUnion as isLiteralUnion2, isNestedType } from "@dxos/effect";
767
724
  import { useTranslation } from "@dxos/react-ui";
725
+ import { translationKey } from "#translations";
768
726
  var FormField = (props) => {
769
727
  const {
770
728
  type,
@@ -776,23 +734,25 @@ var FormField = (props) => {
776
734
  readonly,
777
735
  layout,
778
736
  // RefFieldProps
737
+ createTypename,
779
738
  createOptionLabel,
780
739
  createOptionIcon,
781
740
  createInitialValuePath,
741
+ createFieldMap: createFieldMap3,
782
742
  db,
783
- schemaHook,
784
- getOptions: getRefOptions,
743
+ useSchema: schemaHook,
744
+ getOptions,
785
745
  onCreate
786
746
  } = props;
787
747
  const { t } = useTranslation(translationKey);
788
- const title = getAnnotation(SchemaAST.TitleAnnotationId)(type);
789
- const description = getAnnotation(SchemaAST.DescriptionAnnotationId)(type);
790
- const examples = getAnnotation(SchemaAST.ExamplesAnnotationId)(type);
748
+ const title = getAnnotation2(SchemaAST2.TitleAnnotationId)(type);
749
+ const description = getAnnotation2(SchemaAST2.DescriptionAnnotationId)(type);
750
+ const examples = getAnnotation2(SchemaAST2.ExamplesAnnotationId)(type);
791
751
  const label = useMemo2(() => title ?? String2.capitalize(name), [
792
752
  title,
793
753
  name
794
754
  ]);
795
- const placeholder = useMemo2(() => examples?.length ? `${t("example placeholder")}: ${examples[0]}` : description ?? label, [
755
+ const placeholder = useMemo2(() => examples?.length ? `${t("example.placeholder")}: ${examples[0]}` : description ?? label, [
796
756
  examples,
797
757
  description,
798
758
  label
@@ -805,6 +765,7 @@ var FormField = (props) => {
805
765
  label,
806
766
  placeholder,
807
767
  layout,
768
+ db,
808
769
  ...fieldState
809
770
  };
810
771
  const jsonPath = createJsonPath2(path ?? []);
@@ -831,7 +792,7 @@ var FormField = (props) => {
831
792
  if (Field) {
832
793
  return /* @__PURE__ */ React2.createElement(Field, fieldProps);
833
794
  }
834
- const options = getOptions(type);
795
+ const options = getSelectOptions(type);
835
796
  if (options) {
836
797
  const fieldProjections = projection?.getFieldProjections();
837
798
  const fieldProjection = fieldProjections?.find((fp) => fp.field.path === name);
@@ -849,21 +810,23 @@ var FormField = (props) => {
849
810
  }
850
811
  const refProps = getRefProps(type);
851
812
  if (refProps) {
813
+ const isCreateTarget = !createTypename || refProps.typename === createTypename;
852
814
  return /* @__PURE__ */ React2.createElement(RefField, {
853
815
  ...fieldProps,
854
816
  ...refProps,
855
- createOptionLabel,
856
- createOptionIcon,
857
- createInitialValuePath,
817
+ createOptionLabel: isCreateTarget ? createOptionLabel : void 0,
818
+ createOptionIcon: isCreateTarget ? createOptionIcon : void 0,
819
+ createInitialValuePath: isCreateTarget ? createInitialValuePath : void 0,
820
+ createFieldMap: isCreateTarget ? createFieldMap3 : void 0,
858
821
  db,
859
- schemaHook,
860
- getOptions: getRefOptions,
822
+ useSchema: schemaHook,
823
+ getOptions,
861
824
  onCreate
862
825
  });
863
826
  }
864
827
  if (isNestedType(type)) {
865
828
  const baseNode = findNode(type, isDiscriminatedUnion);
866
- const typeLiteral = baseNode ? getDiscriminatedType(baseNode, fieldState.getValue()) : findNode(type, SchemaAST.isTypeLiteral);
829
+ const typeLiteral = baseNode ? getDiscriminatedType(baseNode, fieldState.getValue()) : findNode(type, SchemaAST2.isTypeLiteral);
867
830
  if (typeLiteral) {
868
831
  const schema = Schema.make(typeLiteral);
869
832
  return /* @__PURE__ */ React2.createElement(FormFieldSet, {
@@ -879,8 +842,8 @@ var FormField = (props) => {
879
842
  createOptionIcon,
880
843
  createInitialValuePath,
881
844
  db,
882
- schemaHook,
883
- getOptions: getRefOptions,
845
+ useSchema: schemaHook,
846
+ getOptions,
884
847
  onCreate
885
848
  });
886
849
  }
@@ -904,8 +867,8 @@ var getFormField = ({ type, format }) => {
904
867
  return BooleanField;
905
868
  }
906
869
  };
907
- var getOptions = (ast) => {
908
- if (isLiteralUnion(ast)) {
870
+ var getSelectOptions = (ast) => {
871
+ if (isLiteralUnion2(ast)) {
909
872
  return ast.types.map((type) => type.literal).filter((v) => v !== null);
910
873
  }
911
874
  return Format3.OptionsAnnotation.getFromAst(ast).pipe((annotation) => Option2.getOrUndefined(annotation));
@@ -913,47 +876,19 @@ var getOptions = (ast) => {
913
876
 
914
877
  // src/components/Form/FormFieldSet.tsx
915
878
  var FORM_FIELDSET_NAME = "Form.FieldSet";
916
- var FormFieldSet = /* @__PURE__ */ forwardRef(({ label, schema, readonly, path, exclude, sort, projection, layout, ...props }, forwardRef4) => {
879
+ var FormFieldSet = ({ label, schema, readonly, path, sort, exclude, projection, layout, ...props }) => {
917
880
  const values = useFormValues(FORM_FIELDSET_NAME, path);
918
- const properties = useMemo3(() => {
919
- if (!schema) {
920
- return [];
921
- }
922
- const props2 = getFormProperties(schema.ast);
923
- if (projection) {
924
- const fieldProjections = projection.getFieldProjections();
925
- const hiddenProperties = new Set(projection.getHiddenProperties());
926
- const visibleProps = props2.filter((prop) => !hiddenProperties.has(prop.name.toString()));
927
- const orderedProps = [];
928
- for (const fieldProjection of fieldProjections) {
929
- const fieldPath = String(fieldProjection.field.path);
930
- const prop = visibleProps.find((p) => p.name === fieldPath);
931
- if (prop) {
932
- orderedProps.push(prop);
933
- }
934
- }
935
- const projectionPaths = new Set(fieldProjections.map((projection2) => String(projection2.field.path)));
936
- const remainingProps = visibleProps.filter((prop) => !projectionPaths.has(prop.name.toString()));
937
- orderedProps.push(...remainingProps);
938
- return orderedProps;
939
- }
940
- const filtered = exclude ? exclude(props2) : props2;
941
- return sort ? filtered.sort(({ name: a }, { name: b }) => sort.indexOf(a.toString()) - sort.indexOf(b.toString())) : filtered;
942
- }, [
881
+ const properties = useFormFieldSetProperties({
943
882
  schema,
944
883
  values,
945
884
  exclude,
946
885
  sort,
947
- projection?.fields
948
- ]);
886
+ projection
887
+ });
949
888
  if ((readonly || layout === "static") && values == null) {
950
889
  return null;
951
890
  }
952
- return /* @__PURE__ */ React3.createElement("div", {
953
- role: "form",
954
- className: mx("w-full", layout === "inline" && "flex flex-col gap-2"),
955
- ref: forwardRef4
956
- }, layout !== "inline" && label && /* @__PURE__ */ React3.createElement(FormFieldLabel, {
891
+ return /* @__PURE__ */ React3.createElement(React3.Fragment, null, layout !== "inline" && label && /* @__PURE__ */ React3.createElement(FormFieldLabel, {
957
892
  label,
958
893
  asChild: true
959
894
  }), properties.map((property) => {
@@ -976,12 +911,52 @@ var FormFieldSet = /* @__PURE__ */ forwardRef(({ label, schema, readonly, path,
976
911
  projection,
977
912
  ...props
978
913
  }));
979
- }).filter(isTruthy));
980
- });
914
+ }));
915
+ };
981
916
  FormFieldSet.displayName = FORM_FIELDSET_NAME;
917
+ var useFormFieldSetProperties = ({ schema, exclude, projection, values, sort }) => {
918
+ return useMemo3(() => {
919
+ if (!schema) {
920
+ return [];
921
+ }
922
+ const schemaProps = getFormProperties(schema.ast);
923
+ const filteredProps = exclude ? exclude(schemaProps) : schemaProps;
924
+ if (projection) {
925
+ const fieldProjections = projection.getFieldProjections();
926
+ const hiddenProperties = new Set(projection.getHiddenProperties());
927
+ const visibleProps = filteredProps.filter((prop) => !hiddenProperties.has(prop.name.toString()));
928
+ const orderedProps = [];
929
+ for (const fieldProjection of fieldProjections) {
930
+ const fieldPath = String(fieldProjection.field.path);
931
+ const prop = visibleProps.find((prop2) => prop2.name === fieldPath);
932
+ if (prop) {
933
+ orderedProps.push(prop);
934
+ }
935
+ }
936
+ const projectionPaths = new Set(fieldProjections.map((projection2) => String(projection2.field.path)));
937
+ const remainingProps = visibleProps.filter((prop) => !projectionPaths.has(prop.name.toString()));
938
+ orderedProps.push(...remainingProps);
939
+ return orderedProps;
940
+ }
941
+ return sort ? [
942
+ ...filteredProps
943
+ ].sort(({ name: a }, { name: b }) => sort.indexOf(a.toString()) - sort.indexOf(b.toString())) : filteredProps;
944
+ }, [
945
+ schema,
946
+ values,
947
+ exclude,
948
+ sort,
949
+ projection
950
+ ]);
951
+ };
982
952
 
983
953
  // src/components/Form/Form.tsx
984
954
  var omitId = (schema) => schema.pipe(Schema2.omit("id"));
955
+ var omitHiddenFormFields = (schema) => {
956
+ const properties = SchemaAST3.getPropertySignatures(schema.ast);
957
+ const hidden = properties.filter((prop) => Option3.getOrElse(EchoAnnotation.FormInputAnnotation.getFromAst(prop.type), () => true) === false).map((prop) => prop.name);
958
+ return hidden.length === 0 ? schema : schema.pipe(Schema2.omit(...hidden));
959
+ };
985
960
  var [FormContextProvider, useFormContext] = createContext("Form");
986
961
  var useFormValues = (componentName, path, defaultValue) => {
987
962
  const stablePath = useMemo4(() => path ?? [], [
@@ -991,10 +966,10 @@ var useFormValues = (componentName, path, defaultValue) => {
991
966
  const { form: { values, onValueChange } } = useFormContext(componentName);
992
967
  const value3 = getValue$2(values, jsonPath);
993
968
  const lastAppliedPathRef = useRef(null);
994
- useEffect3(() => {
969
+ useEffect2(() => {
995
970
  if (value3 == null && defaultValue && lastAppliedPathRef.current !== jsonPath) {
996
971
  lastAppliedPathRef.current = jsonPath;
997
- onValueChange(stablePath, SchemaAST2.stringKeyword, defaultValue());
972
+ onValueChange(stablePath, SchemaAST3.stringKeyword, defaultValue());
998
973
  }
999
974
  }, [
1000
975
  value3,
@@ -1038,29 +1013,35 @@ var FormRoot = ({ children, schema, values, onSave, onCancel, ...props }) => {
1038
1013
  };
1039
1014
  FormRoot.displayName = "Form.Root";
1040
1015
  var FORM_VIEWPORT_NAME = "Form.Viewport";
1041
- var FormViewport = ({ children, classNames, margin = true, padding = true, thin = true, ...props }) => {
1016
+ var FormViewport = composable(({ children, ...props }, forwardedRef) => {
1042
1017
  return /* @__PURE__ */ React4.createElement(ScrollArea.Root, {
1018
+ ...composableProps(props),
1043
1019
  orientation: "vertical",
1044
- classNames,
1045
- margin,
1046
- padding,
1047
- thin,
1048
- ...props
1020
+ centered: true,
1021
+ padding: true,
1022
+ thin: true,
1023
+ ref: forwardedRef
1049
1024
  }, /* @__PURE__ */ React4.createElement(ScrollArea.Viewport, null, children));
1050
- };
1025
+ });
1051
1026
  FormViewport.displayName = FORM_VIEWPORT_NAME;
1052
1027
  var FORM_CONTENT_NAME = "Form.Content";
1053
- var FormContent = ({ classNames, children }) => {
1028
+ var FormContent = composable(({ children, ...props }, forwardedRef) => {
1054
1029
  const { form, testId } = useFormContext(FORM_CONTENT_NAME);
1055
- const ref = useRef(null);
1056
- useKeyHandler(ref.current, form);
1030
+ const localRef = useRef(null);
1031
+ const mergedRef = useMergeRefs([
1032
+ forwardedRef,
1033
+ localRef
1034
+ ]);
1035
+ useKeyHandler(localRef, form);
1057
1036
  return /* @__PURE__ */ React4.createElement("div", {
1058
- ref,
1059
- role: "form",
1060
- className: mx2("w-full flex flex-col gap-form-padding", classNames),
1061
- "data-testid": testId
1037
+ ...composableProps(props, {
1038
+ role: "form",
1039
+ classNames: mx(withColumn.center(), "flex flex-col w-full pb-form-gap")
1040
+ }),
1041
+ "data-testid": testId,
1042
+ ref: mergedRef
1062
1043
  }, children);
1063
- };
1044
+ });
1064
1045
  FormContent.displayName = FORM_CONTENT_NAME;
1065
1046
  var FORM_FIELDSET_NAME2 = "Form.FieldSet";
1066
1047
  var FormFieldSet2 = (props) => {
@@ -1074,18 +1055,18 @@ var FormFieldSet2 = (props) => {
1074
1055
  FormFieldSet2.displayName = FORM_FIELDSET_NAME2;
1075
1056
  var FORM_ACTIONS_NAME = "Form.Actions";
1076
1057
  var FormActions = ({ classNames }) => {
1077
- const { t } = useTranslation2(translationKey);
1058
+ const { t } = useTranslation2(translationKey2);
1078
1059
  const { form: { canSave, onSave, onCancel }, readonly, layout } = useFormContext(FORM_ACTIONS_NAME);
1079
1060
  if (readonly || layout === "static") {
1080
1061
  return null;
1081
1062
  }
1082
1063
  return /* @__PURE__ */ React4.createElement("div", {
1083
1064
  role: "none",
1084
- className: mx2("grid grid-flow-col gap-2 auto-cols-fr py-form-padding", classNames)
1065
+ className: mx(withColumn.center(), "grid grid-flow-col gap-form-gap auto-cols-fr py-form-padding", classNames)
1085
1066
  }, onCancel && /* @__PURE__ */ React4.createElement(IconButton, {
1086
1067
  icon: "ph--x--regular",
1087
1068
  iconEnd: true,
1088
- label: t("cancel button label"),
1069
+ label: t("cancel-button.label"),
1089
1070
  onClick: onCancel,
1090
1071
  "data-testid": "cancel-button"
1091
1072
  }), onSave && /* @__PURE__ */ React4.createElement(IconButton, {
@@ -1094,29 +1075,43 @@ var FormActions = ({ classNames }) => {
1094
1075
  disabled: !canSave,
1095
1076
  icon: "ph--check--regular",
1096
1077
  iconEnd: true,
1097
- label: t("save button label"),
1078
+ label: t("save-button.label"),
1098
1079
  onClick: onSave,
1099
1080
  "data-testid": "save-button"
1100
1081
  }));
1101
1082
  };
1102
1083
  FormActions.displayName = FORM_ACTIONS_NAME;
1084
+ var FORM_SECTION_NAME = "Form.Section";
1085
+ var FormSection = composable(({ children, label, description, ...props }, forwardedRef) => {
1086
+ return /* @__PURE__ */ React4.createElement("div", {
1087
+ ...composableProps(props, {
1088
+ classNames: "flex flex-col pt-form-section-gap first:pt-0"
1089
+ }),
1090
+ ref: forwardedRef
1091
+ }, /* @__PURE__ */ React4.createElement("h2", {
1092
+ className: "text-lg"
1093
+ }, label), description && /* @__PURE__ */ React4.createElement("p", {
1094
+ className: "text-description"
1095
+ }, description), children);
1096
+ });
1097
+ FormSection.displayName = FORM_SECTION_NAME;
1103
1098
  var FORM_SUBMIT_NAME = "Form.Submit";
1104
1099
  var FormSubmit = ({ classNames, label, icon, disabled }) => {
1105
- const { t } = useTranslation2(translationKey);
1100
+ const { t } = useTranslation2(translationKey2);
1106
1101
  const { form: { canSave, onSave }, readonly, layout } = useFormContext(FORM_SUBMIT_NAME);
1107
1102
  if (readonly || layout === "static") {
1108
1103
  return null;
1109
1104
  }
1110
1105
  return /* @__PURE__ */ React4.createElement("div", {
1111
1106
  role: "none",
1112
- className: mx2("flex w-full pt-form-padding", classNames)
1107
+ className: mx("flex w-full pt-form-padding", classNames)
1113
1108
  }, /* @__PURE__ */ React4.createElement(IconButton, {
1114
1109
  classNames: "w-full",
1115
1110
  type: "submit",
1116
1111
  variant: "primary",
1117
1112
  disabled: disabled ?? !canSave,
1118
1113
  icon: icon ?? "ph--check--regular",
1119
- label: label ?? t("save button label"),
1114
+ label: label ?? t("save-button.label"),
1120
1115
  onClick: onSave,
1121
1116
  "data-testid": "save-button"
1122
1117
  }));
@@ -1126,6 +1121,7 @@ var Form = {
1126
1121
  Root: FormRoot,
1127
1122
  Viewport: FormViewport,
1128
1123
  Content: FormContent,
1124
+ Section: FormSection,
1129
1125
  FieldSet: FormFieldSet2,
1130
1126
  Label: FormFieldLabel,
1131
1127
  Actions: FormActions,
@@ -1134,18 +1130,18 @@ var Form = {
1134
1130
 
1135
1131
  // src/components/Form/fields/ArrayField.tsx
1136
1132
  var ArrayField = ({ type, path, label, readonly, layout, fieldProps: inputProps, ...props }) => {
1137
- const { t } = useTranslation3(translationKey);
1133
+ const { t } = useTranslation3(translationKey3);
1138
1134
  const elementType = getArrayElementType2(type);
1139
1135
  const { onValueChange } = inputProps;
1140
1136
  const values = useFormValues(ArrayField.displayName, path, () => []);
1141
1137
  const getDefaultObjectValue = (typeNode) => {
1142
1138
  const baseNode = findNode2(typeNode, isDiscriminatedUnion2);
1143
- const typeLiteral = baseNode ? getDiscriminatedType2(baseNode, {}) : findNode2(typeNode, SchemaAST3.isTypeLiteral);
1139
+ const typeLiteral = baseNode ? getDiscriminatedType2(baseNode, {}) : findNode2(typeNode, SchemaAST4.isTypeLiteral);
1144
1140
  if (!typeLiteral) {
1145
1141
  return {};
1146
1142
  }
1147
1143
  return Object.fromEntries(getFormProperties(typeLiteral).map((prop) => {
1148
- const defaultValue = SchemaAST3.getDefaultAnnotation(prop.type).pipe((annotation) => Option3.getOrUndefined(annotation));
1144
+ const defaultValue = SchemaAST4.getDefaultAnnotation(prop.type).pipe((annotation) => Option4.getOrUndefined(annotation));
1149
1145
  return [
1150
1146
  prop.name,
1151
1147
  defaultValue
@@ -1180,12 +1176,12 @@ var ArrayField = ({ type, path, label, readonly, layout, fieldProps: inputProps,
1180
1176
  asChild: true
1181
1177
  }), /* @__PURE__ */ React5.createElement("div", {
1182
1178
  role: "none",
1183
- className: "flex flex-col gap-2"
1179
+ className: "flex flex-col gap-form-gap"
1184
1180
  }, values?.map((_, index) => {
1185
1181
  return /* @__PURE__ */ React5.createElement("div", {
1186
1182
  role: "none",
1187
1183
  key: index,
1188
- className: "grid grid-cols-[1fr_min-content] gap-2 last:mb-3"
1184
+ className: "grid grid-cols-[1fr_min-content] gap-form-gap last:mb-form-gap items-center"
1189
1185
  }, /* @__PURE__ */ React5.createElement(FormField, {
1190
1186
  autoFocus: index === values.length - 1,
1191
1187
  type: elementType,
@@ -1205,14 +1201,14 @@ var ArrayField = ({ type, path, label, readonly, layout, fieldProps: inputProps,
1205
1201
  }, /* @__PURE__ */ React5.createElement(IconButton2, {
1206
1202
  icon: "ph--x--regular",
1207
1203
  iconOnly: true,
1208
- label: t("button remove"),
1204
+ label: t("remove.button"),
1209
1205
  onClick: () => handleDelete(index),
1210
1206
  classNames: "self-center"
1211
1207
  }))));
1212
1208
  })), !readonly && layout !== "static" && /* @__PURE__ */ React5.createElement(IconButton2, {
1213
1209
  classNames: "flex w-full",
1214
1210
  icon: "ph--plus--regular",
1215
- label: t("add field"),
1211
+ label: t("add-item.button"),
1216
1212
  onClick: handleAdd
1217
1213
  }));
1218
1214
  };
@@ -1260,12 +1256,13 @@ var BooleanField = ({ type, readonly, onValueChange, ...props }) => {
1260
1256
  };
1261
1257
 
1262
1258
  // src/components/Form/fields/GeoPointField.tsx
1263
- import React7, { useCallback as useCallback5, useEffect as useEffect4, useMemo as useMemo5, useState as useState2 } from "react";
1259
+ import React7, { useCallback as useCallback5, useEffect as useEffect3, useMemo as useMemo5, useState as useState2 } from "react";
1264
1260
  import { GeoLocation as GeoLocation3 } from "@dxos/echo/internal";
1265
1261
  import { Input as Input3, useTranslation as useTranslation4 } from "@dxos/react-ui";
1266
1262
  import { safeParseFloat } from "@dxos/util";
1263
+ import { translationKey as translationKey4 } from "#translations";
1267
1264
  var GeoPointField = ({ type, label, readonly, layout, getStatus, getValue, onValueChange, onBlur }) => {
1268
- const { t } = useTranslation4(translationKey);
1265
+ const { t } = useTranslation4(translationKey4);
1269
1266
  const { status, error } = getStatus();
1270
1267
  const geoPoint = useMemo5(() => getValue() ?? [
1271
1268
  0,
@@ -1278,7 +1275,7 @@ var GeoPointField = ({ type, label, readonly, layout, getStatus, getValue, onVal
1278
1275
  ]);
1279
1276
  const [longitudeText, setLongitudeText] = useState2(value3.longitude?.toString());
1280
1277
  const [latitudeText, setLatitudeText] = useState2(value3.latitude?.toString());
1281
- useEffect4(() => {
1278
+ useEffect3(() => {
1282
1279
  const location = GeoLocation3.fromGeoPoint(geoPoint);
1283
1280
  setLongitudeText(location.longitude?.toString());
1284
1281
  setLatitudeText(location.latitude?.toString());
@@ -1320,24 +1317,24 @@ var GeoPointField = ({ type, label, readonly, layout, getStatus, getValue, onVal
1320
1317
  asChild: true
1321
1318
  }), layout === "static" ? /* @__PURE__ */ React7.createElement(LatLng, value3) : /* @__PURE__ */ React7.createElement("div", {
1322
1319
  role: "none",
1323
- className: "grid grid-cols-2 gap-2"
1324
- }, /* @__PURE__ */ React7.createElement("div", null, /* @__PURE__ */ React7.createElement(Input3.Root, null, layout !== "inline" && /* @__PURE__ */ React7.createElement(Input3.Label, null, t("latitude label")), /* @__PURE__ */ React7.createElement(Input3.TextInput, {
1320
+ className: "grid grid-cols-2 gap-form-gap"
1321
+ }, /* @__PURE__ */ React7.createElement("div", null, /* @__PURE__ */ React7.createElement(Input3.Root, null, layout !== "inline" && /* @__PURE__ */ React7.createElement(Input3.Label, null, t("latitude.label")), /* @__PURE__ */ React7.createElement(Input3.TextInput, {
1325
1322
  type: "number",
1326
1323
  step: "0.00001",
1327
1324
  min: "-90",
1328
1325
  max: "90",
1329
1326
  disabled: !!readonly,
1330
- placeholder: t("latitude placeholder"),
1327
+ placeholder: t("latitude.placeholder"),
1331
1328
  value: latitudeText ?? "",
1332
1329
  onChange: handleChange("latitude", setLatitudeText),
1333
1330
  onBlur
1334
- }))), /* @__PURE__ */ React7.createElement("div", null, /* @__PURE__ */ React7.createElement(Input3.Root, null, layout !== "inline" && /* @__PURE__ */ React7.createElement(Input3.Label, null, t("longitude label")), /* @__PURE__ */ React7.createElement(Input3.TextInput, {
1331
+ }))), /* @__PURE__ */ React7.createElement("div", null, /* @__PURE__ */ React7.createElement(Input3.Root, null, layout !== "inline" && /* @__PURE__ */ React7.createElement(Input3.Label, null, t("longitude.label")), /* @__PURE__ */ React7.createElement(Input3.TextInput, {
1335
1332
  type: "number",
1336
1333
  step: "0.00001",
1337
1334
  min: "-180",
1338
1335
  max: "180",
1339
1336
  disabled: !!readonly,
1340
- placeholder: t("longitude placeholder"),
1337
+ placeholder: t("longitude.placeholder"),
1341
1338
  value: longitudeText ?? "",
1342
1339
  onChange: handleChange("longitude", setLongitudeText),
1343
1340
  onBlur
@@ -1347,7 +1344,7 @@ var LatLng = ({ latitude = 0, longitude = 0 }) => {
1347
1344
  const latHem = latitude >= 0 ? "N" : "S";
1348
1345
  const lngHem = longitude >= 0 ? "E" : "W";
1349
1346
  return /* @__PURE__ */ React7.createElement("span", {
1350
- className: "inline-flex items-center gap-1"
1347
+ className: "inline-flex items-center gap-form-gap"
1351
1348
  }, /* @__PURE__ */ React7.createElement("span", null, /* @__PURE__ */ React7.createElement("span", null, Math.abs(latitude).toFixed(5)), /* @__PURE__ */ React7.createElement("span", {
1352
1349
  className: "text-subdued"
1353
1350
  }, "\xB0", latHem)), /* @__PURE__ */ React7.createElement("span", null, /* @__PURE__ */ React7.createElement("span", null, Math.abs(longitude).toFixed(5)), /* @__PURE__ */ React7.createElement("span", {
@@ -1356,56 +1353,141 @@ var LatLng = ({ latitude = 0, longitude = 0 }) => {
1356
1353
  };
1357
1354
 
1358
1355
  // src/components/Form/fields/MarkdownField.tsx
1359
- import React8, { useCallback as useCallback6, useEffect as useEffect5, useRef as useRef2 } from "react";
1360
- import { Input as Input4 } from "@dxos/react-ui";
1361
- var MarkdownField = ({ type, readonly, label, placeholder, layout, getStatus, getValue, onValueChange, onBlur }) => {
1356
+ import { useAtomValue } from "@effect-atom/atom-react";
1357
+ import React8, { useCallback as useCallback6, useMemo as useMemo6 } from "react";
1358
+ import { Obj, Ref as Ref2 } from "@dxos/echo";
1359
+ import { AtomRef } from "@dxos/echo-atom";
1360
+ import { createDocAccessor } from "@dxos/echo-db";
1361
+ import { Button, Icon as Icon2, Input as Input4, useTranslation as useTranslation5 } from "@dxos/react-ui";
1362
+ import { Editor, useBasicMarkdownExtensions } from "@dxos/react-ui-editor";
1363
+ import { Text } from "@dxos/schema";
1364
+ import { createDataExtensions } from "@dxos/ui-editor";
1365
+ import { translationKey as translationKey5 } from "#translations";
1366
+ var editorClassNames = "transition-colors bg-input-surface focus-within:bg-focus-surface border border-separator rounded-xs p-1 px-2";
1367
+ var MarkdownField = ({ type, readonly, label, placeholder, layout, db, getStatus, getValue, onValueChange }) => {
1362
1368
  const { status, error } = getStatus();
1363
- const textareaRef = useRef2(null);
1364
- const adjustHeight = useCallback6(() => {
1365
- const textarea = textareaRef.current;
1366
- if (textarea) {
1367
- textarea.style.blockSize = "auto";
1368
- textarea.style.blockSize = `${textarea.scrollHeight + 2}px`;
1369
- }
1370
- }, []);
1371
- useEffect5(() => {
1372
- adjustHeight();
1373
- }, [
1374
- adjustHeight
1375
- ]);
1376
- useEffect5(() => {
1377
- adjustHeight();
1378
- }, [
1379
- getValue(),
1380
- adjustHeight
1381
- ]);
1382
- const handleChange = useCallback6((event) => onValueChange(type, event.target.value), [
1383
- type,
1384
- onValueChange
1385
- ]);
1369
+ const isRef = Ref2.isRefType(type);
1386
1370
  const value3 = getValue();
1387
- if ((readonly || layout === "static") && !value3) {
1371
+ if ((readonly || layout === "static") && value3 == null) {
1388
1372
  return null;
1389
1373
  }
1374
+ const renderEditor = () => {
1375
+ if (isRef) {
1376
+ const reference = value3;
1377
+ if (reference) {
1378
+ return /* @__PURE__ */ React8.createElement(RefMarkdownEditor, {
1379
+ reference,
1380
+ placeholder
1381
+ });
1382
+ }
1383
+ if (readonly) {
1384
+ return null;
1385
+ }
1386
+ return /* @__PURE__ */ React8.createElement(CreateTextButton, {
1387
+ db,
1388
+ disabled: !db,
1389
+ onCreate: (ref) => onValueChange(type, ref)
1390
+ });
1391
+ }
1392
+ return /* @__PURE__ */ React8.createElement(StringMarkdownEditor, {
1393
+ value: value3 ?? "",
1394
+ placeholder,
1395
+ readonly: !!readonly,
1396
+ onChange: (next) => onValueChange(type, next)
1397
+ });
1398
+ };
1399
+ const renderStatic = () => {
1400
+ if (isRef) {
1401
+ const reference = value3;
1402
+ return reference ? /* @__PURE__ */ React8.createElement(RefStaticText, {
1403
+ reference
1404
+ }) : null;
1405
+ }
1406
+ return /* @__PURE__ */ React8.createElement("p", {
1407
+ className: "whitespace-pre-wrap"
1408
+ }, value3 ?? "");
1409
+ };
1390
1410
  return /* @__PURE__ */ React8.createElement(Input4.Root, {
1391
1411
  validationValence: status
1392
1412
  }, layout !== "inline" && /* @__PURE__ */ React8.createElement(FormFieldLabel, {
1393
1413
  error,
1394
1414
  readonly,
1395
1415
  label
1396
- }), layout === "static" ? /* @__PURE__ */ React8.createElement("p", null, value3) : /* @__PURE__ */ React8.createElement(Input4.TextArea, {
1397
- ref: textareaRef,
1398
- disabled: !!readonly,
1416
+ }), layout === "static" ? renderStatic() : renderEditor(), layout === "full" && /* @__PURE__ */ React8.createElement(Input4.Validation, null, error));
1417
+ };
1418
+ var RefStaticText = ({ reference }) => {
1419
+ const text = useAtomValue(useMemo6(() => AtomRef.make(reference), [
1420
+ reference
1421
+ ]));
1422
+ if (!text?.content) {
1423
+ return null;
1424
+ }
1425
+ return /* @__PURE__ */ React8.createElement("p", {
1426
+ className: "whitespace-pre-wrap"
1427
+ }, text.content);
1428
+ };
1429
+ var RefMarkdownEditor = ({ reference, placeholder }) => {
1430
+ const text = useAtomValue(useMemo6(() => AtomRef.make(reference), [
1431
+ reference
1432
+ ]));
1433
+ const dataExtensions = useMemo6(() => text ? [
1434
+ createDataExtensions({
1435
+ id: reference.dxn.toString(),
1436
+ text: createDocAccessor(text, [
1437
+ "content"
1438
+ ])
1439
+ })
1440
+ ] : [], [
1441
+ text,
1442
+ reference
1443
+ ]);
1444
+ const extensions = useBasicMarkdownExtensions({
1399
1445
  placeholder,
1400
- value: value3 ?? "",
1401
- classNames: "min-h-auto max-h-40 overflow-auto",
1402
- onChange: handleChange,
1403
- onBlur,
1404
- style: {
1405
- resize: "none"
1406
- },
1407
- spellCheck: false
1408
- }), layout === "full" && /* @__PURE__ */ React8.createElement(Input4.Validation, null, error));
1446
+ extensions: dataExtensions
1447
+ });
1448
+ if (!text) {
1449
+ return null;
1450
+ }
1451
+ return /* @__PURE__ */ React8.createElement(Editor.Root, null, /* @__PURE__ */ React8.createElement(Editor.View, {
1452
+ classNames: editorClassNames,
1453
+ extensions
1454
+ }));
1455
+ };
1456
+ var StringMarkdownEditor = ({ value: value3, placeholder, readonly, onChange }) => {
1457
+ const extensions = useBasicMarkdownExtensions({
1458
+ placeholder
1459
+ });
1460
+ const handleChange = useCallback6((next) => onChange(next), [
1461
+ onChange
1462
+ ]);
1463
+ return /* @__PURE__ */ React8.createElement(Editor.Root, null, /* @__PURE__ */ React8.createElement(Editor.View, {
1464
+ classNames: editorClassNames,
1465
+ extensions,
1466
+ value: value3,
1467
+ onChange: readonly ? void 0 : handleChange
1468
+ }));
1469
+ };
1470
+ var CreateTextButton = ({ db, disabled, onCreate }) => {
1471
+ const { t } = useTranslation5(translationKey5);
1472
+ const handleClick = useCallback6(() => {
1473
+ if (!db) {
1474
+ return;
1475
+ }
1476
+ const text = db.add(Obj.make(Text.Text, {
1477
+ content: ""
1478
+ }));
1479
+ onCreate(Ref2.make(text));
1480
+ }, [
1481
+ db,
1482
+ onCreate
1483
+ ]);
1484
+ return /* @__PURE__ */ React8.createElement(Button, {
1485
+ onClick: handleClick,
1486
+ disabled
1487
+ }, /* @__PURE__ */ React8.createElement(Icon2, {
1488
+ icon: "ph--plus--regular",
1489
+ size: 4
1490
+ }), /* @__PURE__ */ React8.createElement("span", null, t("create-text.label")));
1409
1491
  };
1410
1492
 
1411
1493
  // src/components/Form/fields/NumberField.tsx
@@ -1431,47 +1513,32 @@ var NumberField = ({ type, readonly, placeholder, onValueChange, onBlur, ...prop
1431
1513
  };
1432
1514
 
1433
1515
  // src/components/Form/fields/RefField.tsx
1516
+ import React11, { useCallback as useCallback9, useMemo as useMemo7, useState as useState4 } from "react";
1434
1517
  import "@dxos/lit-ui/dx-tag-picker.pcss";
1435
- import React11, { useCallback as useCallback9, useMemo as useMemo6 } from "react";
1436
- import { Entity, Filter, Obj, Ref as Ref2, Type } from "@dxos/echo";
1437
- import { ReferenceAnnotationId } from "@dxos/echo/internal";
1438
- import { useQuery, useSchema as useSchema$ } from "@dxos/echo-react";
1439
- import { findAnnotation } from "@dxos/effect";
1518
+ import { Entity, Filter, Obj as Obj2, Ref as Ref3, Type } from "@dxos/echo";
1519
+ import { useQuery, useSchema as defaultUseSchema } from "@dxos/echo-react";
1520
+ import { ReferenceAnnotationId as ReferenceAnnotationId2 } from "@dxos/echo/internal";
1521
+ import { findAnnotation as findAnnotation2 } from "@dxos/effect";
1440
1522
  import { DXN } from "@dxos/keys";
1441
1523
  import { DxAnchor } from "@dxos/lit-ui/react";
1442
- import { Button, Icon as Icon2, Input as Input6, useTranslation as useTranslation6 } from "@dxos/react-ui";
1443
- import { mx as mx3 } from "@dxos/ui-theme";
1524
+ import { Button as Button2, Icon as Icon3, Input as Input6, useTranslation as useTranslation7 } from "@dxos/react-ui";
1525
+ import { ParentLabelAnnotationId } from "@dxos/schema";
1526
+ import { translationKey as translationKey7 } from "#translations";
1444
1527
 
1445
1528
  // src/components/ObjectPicker/ObjectPicker.tsx
1446
- import React10, { forwardRef as forwardRef2, useCallback as useCallback8, useState as useState3 } from "react";
1447
- import { Popover, useTranslation as useTranslation5 } from "@dxos/react-ui";
1448
- import { Combobox, useSearchListInput, useSearchListResults } from "@dxos/react-ui-searchlist";
1449
- var CreateItem = ({ createOptionLabel, createOptionIcon, onCreateItemSelect }) => {
1450
- const { t } = useTranslation5(translationKey);
1451
- const { query } = useSearchListInput();
1452
- return /* @__PURE__ */ React10.createElement(Combobox.Item, {
1453
- value: "__create__",
1454
- label: t(createOptionLabel[0], {
1455
- ns: createOptionLabel[1].ns,
1456
- text: query
1457
- }),
1458
- icon: createOptionIcon,
1459
- classNames: "flex items-center gap-2",
1460
- closeOnSelect: false,
1461
- onSelect: () => {
1462
- onCreateItemSelect(query);
1463
- }
1464
- });
1465
- };
1466
- var ObjectPickerContent = /* @__PURE__ */ forwardRef2(({ options, selectedIds, createSchema, createOptionLabel, createOptionIcon, createInitialValuePath, onSelect, onCreate, ...props }, ref) => {
1467
- const { t } = useTranslation5(translationKey);
1529
+ import React10, { forwardRef, useCallback as useCallback8, useState as useState3 } from "react";
1530
+ import { Popover, useTranslation as useTranslation6 } from "@dxos/react-ui";
1531
+ import { Combobox, useSearchListInput, useSearchListResults } from "@dxos/react-ui-search";
1532
+ import { translationKey as translationKey6 } from "#translations";
1533
+ var ObjectPickerContent = /* @__PURE__ */ forwardRef(({ options, selectedIds, createSchema, createOptionLabel, createOptionIcon, createInitialValuePath, createFieldMap: createFieldMap3, onSelect, onCreate, ...props }, forwardedRef) => {
1534
+ const { t } = useTranslation6(translationKey6);
1468
1535
  const [showForm, setShowForm] = useState3(false);
1469
1536
  const [formInitialValue, setFormInitialValue] = useState3("");
1470
1537
  const { results, handleSearch } = useSearchListResults({
1471
1538
  items: options
1472
1539
  });
1473
- const handleFormSave = useCallback8((values) => {
1474
- onCreate?.(values);
1540
+ const handleFormSave = useCallback8(async (values) => {
1541
+ await onCreate?.(values);
1475
1542
  setShowForm(false);
1476
1543
  setFormInitialValue("");
1477
1544
  }, [
@@ -1493,21 +1560,30 @@ var ObjectPickerContent = /* @__PURE__ */ forwardRef2(({ options, selectedIds, c
1493
1560
  }, [
1494
1561
  createSchema
1495
1562
  ]);
1563
+ if (showForm && createSchema) {
1564
+ return /* @__PURE__ */ React10.createElement(Combobox.Content, {
1565
+ ...props,
1566
+ onSearch: handleSearch,
1567
+ onKeyDownCapture: handleKeyDown,
1568
+ ref: forwardedRef
1569
+ }, /* @__PURE__ */ React10.createElement(Popover.Viewport, null, /* @__PURE__ */ React10.createElement(Form.Root, {
1570
+ testId: "create-referenced-object-form",
1571
+ schema: createSchema,
1572
+ defaultValues: createInitialValuePath ? {
1573
+ [createInitialValuePath]: formInitialValue
1574
+ } : {},
1575
+ fieldMap: createFieldMap3,
1576
+ onSave: handleFormSave,
1577
+ onCancel: handleFormCancel
1578
+ }, /* @__PURE__ */ React10.createElement(Form.Viewport, null, /* @__PURE__ */ React10.createElement(Form.Content, null, /* @__PURE__ */ React10.createElement(Form.FieldSet, null), /* @__PURE__ */ React10.createElement(Form.Actions, null))))), /* @__PURE__ */ React10.createElement(Combobox.Arrow, null));
1579
+ }
1496
1580
  return /* @__PURE__ */ React10.createElement(Combobox.Content, {
1497
1581
  ...props,
1498
- ref,
1499
1582
  onSearch: handleSearch,
1500
- onKeyDownCapture: handleKeyDown
1501
- }, showForm && createSchema ? /* @__PURE__ */ React10.createElement(Popover.Viewport, null, /* @__PURE__ */ React10.createElement(Form.Root, {
1502
- testId: "create-referenced-object-form",
1503
- schema: createSchema,
1504
- values: createInitialValuePath ? {
1505
- [createInitialValuePath]: formInitialValue
1506
- } : {},
1507
- onSave: handleFormSave,
1508
- onCancel: handleFormCancel
1509
- }, /* @__PURE__ */ React10.createElement(Form.Viewport, null, /* @__PURE__ */ React10.createElement(Form.Content, null, /* @__PURE__ */ React10.createElement(Form.FieldSet, null), /* @__PURE__ */ React10.createElement(Form.Actions, null))))) : /* @__PURE__ */ React10.createElement(React10.Fragment, null, /* @__PURE__ */ React10.createElement(Combobox.Input, {
1510
- placeholder: t("ref field combobox input placeholder"),
1583
+ onKeyDownCapture: handleKeyDown,
1584
+ ref: forwardedRef
1585
+ }, /* @__PURE__ */ React10.createElement(Combobox.Input, {
1586
+ placeholder: t("ref-field-combobox-input.placeholder"),
1511
1587
  autoFocus: true
1512
1588
  }), /* @__PURE__ */ React10.createElement(Combobox.List, null, results.map((option) => /* @__PURE__ */ React10.createElement(Combobox.Item, {
1513
1589
  key: option.id,
@@ -1516,16 +1592,34 @@ var ObjectPickerContent = /* @__PURE__ */ forwardRef2(({ options, selectedIds, c
1516
1592
  checked: selectedIds?.includes(option.id),
1517
1593
  onSelect: () => onSelect(option.id),
1518
1594
  classNames: "flex items-center gap-2"
1519
- })), createOptionLabel && createOptionIcon && createSchema && onCreate && /* @__PURE__ */ React10.createElement(CreateItem, {
1595
+ })), createSchema && onCreate && /* @__PURE__ */ React10.createElement(CreateItem, {
1520
1596
  createOptionLabel,
1521
- createOptionIcon,
1597
+ createOptionIcon: createOptionIcon ?? "ph--plus--regular",
1522
1598
  onCreateItemSelect: (query) => {
1523
1599
  setFormInitialValue(query);
1524
1600
  setShowForm(true);
1525
1601
  }
1526
- }))), /* @__PURE__ */ React10.createElement(Combobox.Arrow, null));
1602
+ })), /* @__PURE__ */ React10.createElement(Combobox.Arrow, null));
1527
1603
  });
1528
- ObjectPickerContent.displayName = "ObjectPickerContent";
1604
+ var CreateItem = ({ createOptionLabel, createOptionIcon, onCreateItemSelect }) => {
1605
+ const { t } = useTranslation6(translationKey6);
1606
+ const { query } = useSearchListInput();
1607
+ const label = createOptionLabel ? t(createOptionLabel[0], {
1608
+ ns: createOptionLabel[1].ns,
1609
+ text: query
1610
+ }) : t("create-option.label");
1611
+ return /* @__PURE__ */ React10.createElement(Combobox.Item, {
1612
+ value: "__create__",
1613
+ label,
1614
+ icon: createOptionIcon,
1615
+ classNames: "flex items-center gap-2",
1616
+ closeOnSelect: false,
1617
+ onSelect: () => {
1618
+ onCreateItemSelect(query);
1619
+ }
1620
+ });
1621
+ };
1622
+ ObjectPickerContent.displayName = "ObjectPicker.Content";
1529
1623
  var ObjectPicker = {
1530
1624
  Root: Combobox.Root,
1531
1625
  Portal: Combobox.Portal,
@@ -1538,34 +1632,43 @@ var ObjectPicker = {
1538
1632
  var isRefSnapshot = (val) => {
1539
1633
  return typeof val === "object" && typeof val?.["/"] === "string";
1540
1634
  };
1541
- var defaultGetOptions = (results) => results.map((result) => {
1635
+ var defaultGetOptions = (results, { parentLabel } = {}) => results.map((result) => {
1542
1636
  const id = Entity.getDXN(result).toString();
1543
- const label = Entity.getLabel(result);
1637
+ const parent = parentLabel ? Obj2.getParent(result) : void 0;
1638
+ const label = parent ? Entity.getLabel(parent) : Entity.getLabel(result);
1544
1639
  return {
1545
1640
  id,
1546
1641
  label: label ?? id
1547
1642
  };
1548
1643
  });
1549
- var defaultResultsHook = (db, typename) => useQuery(db, typename ? typename === Type.getTypename(Obj.Unknown) ? Filter.everything() : Filter.typename(typename) : Filter.nothing());
1644
+ var defaultUseResults = (db, typename) => useQuery(db, typename ? typename === Type.getTypename(Obj2.Unknown) ? Filter.everything() : Filter.typename(typename) : Filter.nothing());
1550
1645
  var RefField = (props) => {
1551
- const { type, readonly, label, placeholder, layout, getStatus, getValue, createOptionLabel, createOptionIcon, createInitialValuePath, db, resultsHook: useResults = defaultResultsHook, schemaHook: useSchema = useSchema$, getOptions: getOptions2 = defaultGetOptions, onCreate, onValueChange } = props;
1552
- const { t } = useTranslation6(translationKey);
1646
+ const { type, readonly, label, placeholder, layout, getStatus, getValue, createOptionLabel, createOptionIcon, createInitialValuePath, createFieldMap: createFieldMap3, db, useSchema = defaultUseSchema, useResults = defaultUseResults, getOptions = defaultGetOptions, onCreate, onValueChange } = props;
1647
+ const { t } = useTranslation7(translationKey7);
1553
1648
  const { status, error } = getStatus();
1554
- const typename = useMemo6(() => type ? findAnnotation(type, ReferenceAnnotationId)?.typename : void 0, [
1649
+ const typename = useMemo7(() => type ? findAnnotation2(type, ReferenceAnnotationId2)?.typename : void 0, [
1555
1650
  type
1556
1651
  ]);
1557
1652
  const results = useResults(db, typename);
1558
- const options = useMemo6(() => getOptions2(results), [
1653
+ const options = useMemo7(() => {
1654
+ const parentLabel = type ? findAnnotation2(type, ParentLabelAnnotationId) === true : false;
1655
+ return getOptions(results, {
1656
+ parentLabel
1657
+ });
1658
+ }, [
1559
1659
  results,
1560
- getOptions2
1660
+ getOptions,
1661
+ type
1561
1662
  ]);
1562
1663
  const handleGetValue = useCallback9(() => {
1563
1664
  const formValue = getValue();
1665
+ const dxnToObjectId = (dxn) => dxn.split(":").pop() ?? dxn;
1564
1666
  const unknownToRefOption = (value3) => {
1565
- const isRef = Ref2.isRef(value3);
1667
+ const isRef = Ref3.isRef(value3);
1566
1668
  if (isRef || isRefSnapshot(value3)) {
1567
1669
  const dxnString = isRef ? value3.dxn.toString() : value3["/"];
1568
- const matchingOption = options.find((option) => option.id === dxnString);
1670
+ const objectId = dxnToObjectId(dxnString);
1671
+ const matchingOption = options.find((option) => dxnToObjectId(option.id) === objectId);
1569
1672
  if (matchingOption) {
1570
1673
  return matchingOption;
1571
1674
  }
@@ -1577,29 +1680,37 @@ var RefField = (props) => {
1577
1680
  options,
1578
1681
  getValue
1579
1682
  ]);
1580
- const handleUpdate = useCallback9((id) => {
1581
- const item2 = options.find((option) => option.id === id);
1582
- const ref = item2 ? Ref2.fromDXN(DXN.parse(item2.id)) : void 0;
1583
- onValueChange(type, ref);
1584
- }, [
1585
- options,
1586
- type,
1587
- onValueChange
1588
- ]);
1589
1683
  const item = handleGetValue();
1590
- const selectedIds = useMemo6(() => item ? [
1684
+ const selectedIds = useMemo7(() => item ? [
1591
1685
  item.id
1592
1686
  ] : [], [
1593
1687
  item
1594
1688
  ]);
1595
1689
  const createSchema = useSchema(db, typename);
1596
- const handleCreate = useCallback9((values) => {
1597
- if (createSchema && onCreate) {
1598
- onCreate(createSchema, values);
1690
+ const [open, setOpen] = useState4(false);
1691
+ const handleCreate = useCallback9(async (values) => {
1692
+ if (!createSchema || !onCreate) {
1693
+ return;
1694
+ }
1695
+ const newObject = await onCreate(createSchema, values);
1696
+ if (newObject) {
1697
+ onValueChange(type, Ref3.make(newObject));
1599
1698
  }
1699
+ setOpen(false);
1600
1700
  }, [
1601
1701
  createSchema,
1602
- onCreate
1702
+ onCreate,
1703
+ type,
1704
+ onValueChange
1705
+ ]);
1706
+ const handleUpdate = useCallback9((id) => {
1707
+ const item2 = options.find((option) => option.id === id);
1708
+ const ref = item2 ? Ref3.fromDXN(DXN.parse(item2.id)) : void 0;
1709
+ onValueChange(type, ref);
1710
+ }, [
1711
+ options,
1712
+ type,
1713
+ onValueChange
1603
1714
  ]);
1604
1715
  const handleSelect = useCallback9((id) => {
1605
1716
  if (item?.id === id) {
@@ -1621,40 +1732,48 @@ var RefField = (props) => {
1621
1732
  readonly,
1622
1733
  label
1623
1734
  }), /* @__PURE__ */ React11.createElement("div", null, readonly ? !item ? /* @__PURE__ */ React11.createElement("p", {
1624
- className: mx3("text-description", "mb-2")
1625
- }, t("empty readonly ref field label")) : /* @__PURE__ */ React11.createElement(DxAnchor, {
1735
+ className: "text-description mb-2"
1736
+ }, t("empty-readonly-ref-field.label")) : /* @__PURE__ */ React11.createElement(DxAnchor, {
1626
1737
  key: item.id,
1627
1738
  dxn: item.id,
1628
1739
  rootclassname: "me-1"
1629
- }, item.label) : /* @__PURE__ */ React11.createElement(ObjectPicker.Root, null, /* @__PURE__ */ React11.createElement(ObjectPicker.Trigger, {
1740
+ }, item.label) : /* @__PURE__ */ React11.createElement(ObjectPicker.Root, {
1741
+ open,
1742
+ onOpenChange: setOpen
1743
+ }, /* @__PURE__ */ React11.createElement(ObjectPicker.Trigger, {
1630
1744
  asChild: true,
1631
1745
  classNames: "p-0"
1632
1746
  }, item ? /* @__PURE__ */ React11.createElement("div", {
1633
- className: "flex gap-2 w-full"
1747
+ role: "none",
1748
+ className: "flex gap-form-gap w-full"
1634
1749
  }, /* @__PURE__ */ React11.createElement(Input6.Root, {
1635
1750
  key: item.id
1636
1751
  }, /* @__PURE__ */ React11.createElement(Input6.TextInput, {
1637
1752
  value: item.label,
1638
1753
  readOnly: true,
1639
1754
  classNames: "w-full"
1640
- }))) : /* @__PURE__ */ React11.createElement(Button, {
1641
- classNames: "w-full text-start gap-2"
1755
+ }))) : /* @__PURE__ */ React11.createElement(Button2, {
1756
+ classNames: "w-full text-start gap-form-gap"
1642
1757
  }, /* @__PURE__ */ React11.createElement("div", {
1643
1758
  role: "none",
1644
1759
  className: "grow overflow-hidden"
1645
1760
  }, /* @__PURE__ */ React11.createElement("span", {
1646
- className: "flex truncate text-description"
1647
- }, placeholder ?? t("ref field placeholder"))), /* @__PURE__ */ React11.createElement(Icon2, {
1761
+ className: "truncate text-description"
1762
+ }, placeholder ?? t("ref-field.placeholder"))), /* @__PURE__ */ React11.createElement(Icon3, {
1648
1763
  size: 3,
1649
1764
  icon: "ph--caret-down--bold"
1650
1765
  }))), /* @__PURE__ */ React11.createElement(ObjectPicker.Portal, null, /* @__PURE__ */ React11.createElement(ObjectPicker.Content, {
1651
1766
  classNames: "dx-card-popover-width",
1652
1767
  options,
1653
1768
  selectedIds,
1654
- createSchema: createSchema && omitId(createSchema),
1769
+ // Strip hidden (`FormInputAnnotation.set(false)`) fields so the
1770
+ // form's validator doesn't reject required-but-hidden fields
1771
+ // such as backing-object refs supplied by a `FactoryAnnotation`.
1772
+ createSchema: createSchema && omitHiddenFormFields(omitId(createSchema)),
1655
1773
  createOptionLabel,
1656
1774
  createOptionIcon,
1657
1775
  createInitialValuePath,
1776
+ createFieldMap: createFieldMap3,
1658
1777
  onCreate: handleCreate,
1659
1778
  onSelect: handleSelect
1660
1779
  })))), layout === "full" && /* @__PURE__ */ React11.createElement(Input6.DescriptionAndValidation, null, error));
@@ -1696,20 +1815,21 @@ var SelectField = ({ type, readonly, label, layout, placeholder, options, getSta
1696
1815
  };
1697
1816
 
1698
1817
  // src/components/Form/fields/SelectOptionField.tsx
1699
- import React13, { useCallback as useCallback11, useEffect as useEffect6, useRef as useRef3, useState as useState4 } from "react";
1818
+ import React13, { useCallback as useCallback11, useEffect as useEffect4, useRef as useRef2, useState as useState5 } from "react";
1700
1819
  import { PublicKey } from "@dxos/keys";
1701
- import { IconButton as IconButton3, Input as Input8, Tag, useTranslation as useTranslation7 } from "@dxos/react-ui";
1820
+ import { IconButton as IconButton3, Input as Input8, Tag, useTranslation as useTranslation8 } from "@dxos/react-ui";
1702
1821
  import { List } from "@dxos/react-ui-list";
1703
1822
  import { HuePicker } from "@dxos/react-ui-pickers";
1704
1823
  import { hues, osTranslations, subtleHover } from "@dxos/ui-theme";
1824
+ import { translationKey as translationKey8 } from "#translations";
1705
1825
  var SelectOptionField = ({ type, readonly, label, getStatus, getValue, onValueChange }) => {
1706
- const { t } = useTranslation7(translationKey);
1826
+ const { t } = useTranslation8(translationKey8);
1707
1827
  const { status, error } = getStatus();
1708
- const [selected, setSelectedId] = useState4(null);
1709
- const [isNewOption, setIsNewOption] = useState4(false);
1710
- const inputRef = useRef3(null);
1828
+ const [selected, setSelectedId] = useState5(null);
1829
+ const [isNewOption, setIsNewOption] = useState5(false);
1830
+ const inputRef = useRef2(null);
1711
1831
  const options = getValue();
1712
- useEffect6(() => {
1832
+ useEffect4(() => {
1713
1833
  if (options === void 0) {
1714
1834
  onValueChange(type, []);
1715
1835
  }
@@ -1800,7 +1920,7 @@ var SelectOptionField = ({ type, readonly, label, getStatus, getValue, onValueCh
1800
1920
  type,
1801
1921
  onValueChange
1802
1922
  ]);
1803
- useEffect6(() => {
1923
+ useEffect4(() => {
1804
1924
  if (selected && isNewOption && inputRef.current) {
1805
1925
  inputRef.current.focus();
1806
1926
  setIsNewOption(false);
@@ -1853,14 +1973,14 @@ var SelectOptionField = ({ type, readonly, label, getStatus, getValue, onValueCh
1853
1973
  icon: selected === item.id ? "ph--caret-down--regular" : "ph--caret-right--regular",
1854
1974
  onClick: () => handleClick(item.id)
1855
1975
  })), selected === item.id && /* @__PURE__ */ React13.createElement("div", {
1856
- className: "flex flex-col p-form-padding gap-1 dx-density-fine"
1976
+ className: "flex flex-col p-form-padding gap-form-gap dx-density-fine"
1857
1977
  }, /* @__PURE__ */ React13.createElement(Input8.Label, {
1858
1978
  classNames: "text-xs"
1859
- }, t("select option label")), /* @__PURE__ */ React13.createElement("div", {
1860
- className: "grid grid-cols-[1fr_min-content_min-content] gap-1"
1979
+ }, t("select-option.label")), /* @__PURE__ */ React13.createElement("div", {
1980
+ className: "grid grid-cols-[1fr_min-content_min-content] gap-form-gap"
1861
1981
  }, /* @__PURE__ */ React13.createElement(Input8.TextInput, {
1862
1982
  disabled: !!readonly,
1863
- placeholder: t("select option label placeholder"),
1983
+ placeholder: t("select-option-label.placeholder"),
1864
1984
  ref: selected === item.id ? inputRef : void 0,
1865
1985
  value: item.title,
1866
1986
  onChange: handleTitleChange(item.id),
@@ -1874,12 +1994,12 @@ var SelectOptionField = ({ type, readonly, label, getStatus, getValue, onValueCh
1874
1994
  disabled: !!readonly,
1875
1995
  icon: "ph--trash--fill",
1876
1996
  iconOnly: true,
1877
- label: t("select option delete"),
1997
+ label: t("select-option-delete.button"),
1878
1998
  onClick: () => handleDelete(item.id)
1879
1999
  })))))), /* @__PURE__ */ React13.createElement(IconButton3, {
1880
2000
  variant: "ghost",
1881
2001
  icon: "ph--plus--regular",
1882
- label: t("select option add"),
2002
+ label: t("select-option-add.button"),
1883
2003
  onClick: handleAdd,
1884
2004
  disabled: !!readonly,
1885
2005
  classNames: "w-full"
@@ -1889,7 +2009,7 @@ var SelectOptionField = ({ type, readonly, label, getStatus, getValue, onValueCh
1889
2009
  // src/components/Form/fields/TextField.tsx
1890
2010
  import React14, { useCallback as useCallback12 } from "react";
1891
2011
  import { Input as Input9 } from "@dxos/react-ui";
1892
- var TextField = ({ type, readonly, placeholder, onValueChange, onBlur, ...props }) => {
2012
+ var TextField = ({ type, readonly, placeholder, onBlur, onValueChange, ...props }) => {
1893
2013
  const handleChange = useCallback12((event) => onValueChange(type, event.target.value), [
1894
2014
  type,
1895
2015
  onValueChange
@@ -1902,8 +2022,8 @@ var TextField = ({ type, readonly, placeholder, onValueChange, onBlur, ...props
1902
2022
  disabled: !!readonly,
1903
2023
  placeholder,
1904
2024
  value: value3,
1905
- onChange: handleChange,
1906
- onBlur
2025
+ onBlur,
2026
+ onChange: handleChange
1907
2027
  }));
1908
2028
  };
1909
2029
 
@@ -1931,7 +2051,7 @@ var TextAreaField = ({ type, readonly, placeholder, onValueChange, onBlur, ...pr
1931
2051
  // src/components/Form/fields/TupleField.tsx
1932
2052
  import React16 from "react";
1933
2053
  import { Input as Input11 } from "@dxos/react-ui";
1934
- import { mx as mx4 } from "@dxos/ui-theme";
2054
+ import { mx as mx2 } from "@dxos/ui-theme";
1935
2055
  import { safeParseFloat as safeParseFloat3 } from "@dxos/util";
1936
2056
  var gridCols = [
1937
2057
  "grid-cols-1",
@@ -1949,7 +2069,7 @@ var TupleField = ({ binding, type, readonly, label, getStatus, getValue, onValue
1949
2069
  readonly,
1950
2070
  label
1951
2071
  }), /* @__PURE__ */ React16.createElement("div", {
1952
- className: mx4("grid gap-2", gridCols[binding.length - 1])
2072
+ className: mx2("grid gap-form-gap", gridCols[binding.length - 1])
1953
2073
  }, binding.map((prop) => /* @__PURE__ */ React16.createElement(Input11.TextInput, {
1954
2074
  key: prop,
1955
2075
  type: "number",
@@ -1968,13 +2088,13 @@ var TupleField = ({ binding, type, readonly, label, getStatus, getValue, onValue
1968
2088
  // src/components/FieldEditor/FieldEditor.tsx
1969
2089
  var __dxlog_file2 = "/__w/dxos/dxos/packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx";
1970
2090
  var FieldEditor = ({ readonly, projection, field, registry, view, onSave, onCancel }) => {
1971
- const { t } = useTranslation8(translationKey);
1972
- const [props, setProps] = useState5(projection.getFieldProjection(field.id).props);
1973
- useEffect7(() => setProps(projection.getFieldProjection(field.id).props), [
2091
+ const { t } = useTranslation9(translationKey9);
2092
+ const [props, setProps] = useState6(projection.getFieldProjection(field.id).props);
2093
+ useEffect5(() => setProps(projection.getFieldProjection(field.id).props), [
1974
2094
  field,
1975
2095
  projection
1976
2096
  ]);
1977
- const [schemas, setSchemas] = useState5([]);
2097
+ const [schemas, setSchemas] = useState6([]);
1978
2098
  useAsyncEffect(async () => {
1979
2099
  if (!registry) {
1980
2100
  return;
@@ -1988,22 +2108,22 @@ var FieldEditor = ({ readonly, projection, field, registry, view, onSave, onCanc
1988
2108
  }, [
1989
2109
  registry
1990
2110
  ]);
1991
- const [referenceSchema, setReferenceSchema] = useState5();
1992
- useEffect7(() => {
2111
+ const [referenceSchema, setReferenceSchema] = useState6();
2112
+ useEffect5(() => {
1993
2113
  setReferenceSchema(schemas.find((schema) => schema.typename === props?.referenceSchema));
1994
2114
  }, [
1995
2115
  schemas,
1996
2116
  props?.referenceSchema
1997
2117
  ]);
1998
- const [{ fieldSchema }, setFieldSchema] = useState5({
2118
+ const [{ fieldSchema }, setFieldSchema] = useState6({
1999
2119
  fieldSchema: getFormatSchema(props?.format)
2000
2120
  });
2001
- const fieldMap = useMemo7(() => ({
2121
+ const fieldMap = useMemo8(() => ({
2002
2122
  ["format"]: (props2) => /* @__PURE__ */ React17.createElement(SelectField, {
2003
2123
  ...props2,
2004
2124
  options: FormatEnums.filter((value3) => value3 !== Format4.TypeFormat.None).map((value3) => ({
2005
2125
  value: value3,
2006
- label: t(`format ${value3}`)
2126
+ label: t(`format.${value3}.label`)
2007
2127
  }))
2008
2128
  }),
2009
2129
  ["referenceSchema"]: (props2) => /* @__PURE__ */ React17.createElement(SelectField, {
@@ -2077,7 +2197,7 @@ var FieldEditor = ({ readonly, projection, field, registry, view, onSave, onCanc
2077
2197
  ]);
2078
2198
  const handleSave = useCallback14((props2) => {
2079
2199
  if (view) {
2080
- Obj2.change(view, () => {
2200
+ Obj3.update(view, () => {
2081
2201
  projection.setFieldProjection({
2082
2202
  field,
2083
2203
  props: props2
@@ -2105,12 +2225,7 @@ var FieldEditor = ({ readonly, projection, field, registry, view, onSave, onCanc
2105
2225
  if (!fieldSchema) {
2106
2226
  log2.warn("invalid format", {
2107
2227
  props
2108
- }, {
2109
- F: __dxlog_file2,
2110
- L: 172,
2111
- S: void 0,
2112
- C: (f, a) => f(...a)
2113
- });
2228
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 156, S: void 0 });
2114
2229
  return null;
2115
2230
  }
2116
2231
  return /* @__PURE__ */ React17.createElement(Form.Root, {
@@ -2132,160 +2247,491 @@ var FieldEditor = ({ readonly, projection, field, registry, view, onSave, onCanc
2132
2247
  }, /* @__PURE__ */ React17.createElement(Form.Content, null, /* @__PURE__ */ React17.createElement(Form.FieldSet, null), /* @__PURE__ */ React17.createElement(Form.Actions, null)));
2133
2248
  };
2134
2249
 
2135
- // src/components/Settings/Settings.tsx
2136
- import React18 from "react";
2137
- import { Button as Button2, Input as Input12, ScrollArea as ScrollArea2, toLocalizedString, useTranslation as useTranslation9 } from "@dxos/react-ui";
2138
- import { mx as mx5 } from "@dxos/ui-theme";
2139
- var SETTINGS_ROOT_NAME = "Settings.Root";
2140
- var SETTINGS_SECTION_NAME = "Settings.Section";
2141
- var SETTINGS_SECTION_HEADING_NAME = "Settings.SectionHeading";
2142
- var SETTINGS_GROUP_NAME = "Settings.Group";
2143
- var SETTINGS_GROUP_BUTTON_NAME = "Settings.GroupButton";
2144
- var SETTINGS_CONTAINER_NAME = "Settings.Container";
2145
- var SETTINGS_FRAME_NAME = "Settings.Frame";
2146
- var SETTINGS_FRAME_ITEM_NAME = "Settings.FrameItem";
2147
- var SETTINGS_ITEM_NAME = "Settings.Item";
2148
- var SETTINGS_ITEM_INPUT_NAME = "Settings.ItemInput";
2149
- var styles = {
2150
- title: "pb-trim-md text-base-surface-text text-lg",
2151
- description: "text-base text-description",
2152
- grid: "grid grid-cols-1 md:grid-cols-[1fr_1fr] gap-x-trim-lg"
2153
- };
2154
- var SettingsRoot = ({ children }) => {
2155
- return /* @__PURE__ */ React18.createElement(ScrollArea2.Root, {
2156
- orientation: "vertical",
2157
- className: "dx-article"
2158
- }, /* @__PURE__ */ React18.createElement(ScrollArea2.Viewport, {
2159
- classNames: "p-trim-md"
2160
- }, children));
2161
- };
2162
- SettingsRoot.displayName = SETTINGS_ROOT_NAME;
2163
- var SettingsSection = ({ title, description, children }) => {
2164
- return /* @__PURE__ */ React18.createElement(React18.Fragment, null, /* @__PURE__ */ React18.createElement(SettingsSectionHeading, {
2165
- title,
2166
- description
2167
- }), /* @__PURE__ */ React18.createElement("div", {
2168
- className: "w-full pt-trim-md space-y-trim-md"
2169
- }, children));
2170
- };
2171
- SettingsSection.displayName = SETTINGS_SECTION_NAME;
2172
- var SettingsSectionHeading = ({ title, description }) => {
2173
- const { t } = useTranslation9(translationKey);
2174
- return /* @__PURE__ */ React18.createElement(React18.Fragment, null, /* @__PURE__ */ React18.createElement("h2", {
2175
- className: "px-trim-md mt-trim-md mb-trim-md text-xl"
2176
- }, toLocalizedString(title, t)), description && /* @__PURE__ */ React18.createElement("p", {
2177
- className: "px-trim-md my-trim-md text-description"
2178
- }, toLocalizedString(description, t)));
2250
+ // src/components/ObjectForm/ObjectForm.tsx
2251
+ import * as Schema3 from "effect/Schema";
2252
+ import React18, { useCallback as useCallback15, useMemo as useMemo9 } from "react";
2253
+ import { DXN as DXN2, Obj as Obj4, Ref as Ref4, Tag as Tag2, Type as Type2 } from "@dxos/echo";
2254
+ import { splitJsonPath } from "@dxos/echo/internal";
2255
+ import { invariant } from "@dxos/invariant";
2256
+ import { HuePicker as HuePicker2 } from "@dxos/react-ui-pickers";
2257
+ import { isNonNullable } from "@dxos/util";
2258
+ import { translationKey as translationKey10 } from "#translations";
2259
+ var __dxlog_file3 = "/__w/dxos/dxos/packages/ui/react-ui-form/src/components/ObjectForm/ObjectForm.tsx";
2260
+ var createFieldMap = {
2261
+ hue: ({ type, label, layout, getValue, onValueChange }) => {
2262
+ const handleChange = useCallback15((nextHue) => onValueChange(type, nextHue), [
2263
+ onValueChange,
2264
+ type
2265
+ ]);
2266
+ const handleReset = useCallback15(() => onValueChange(type, void 0), [
2267
+ onValueChange,
2268
+ type
2269
+ ]);
2270
+ return /* @__PURE__ */ React18.createElement(React18.Fragment, null, layout !== "inline" && /* @__PURE__ */ React18.createElement(Form.Label, {
2271
+ label
2272
+ }), /* @__PURE__ */ React18.createElement(HuePicker2, {
2273
+ value: getValue(),
2274
+ onChange: handleChange,
2275
+ onReset: handleReset
2276
+ }));
2277
+ }
2179
2278
  };
2180
- SettingsSectionHeading.displayName = SETTINGS_SECTION_HEADING_NAME;
2181
- var SettingsGroupButton = ({ classNames, ...props }) => {
2182
- return /* @__PURE__ */ React18.createElement(Button2, {
2183
- ...props,
2184
- classNames: [
2185
- "md:col-span-2",
2186
- classNames
2187
- ]
2188
- });
2279
+ var ObjectForm = ({ object, schema }) => {
2280
+ const db = Obj4.getDatabase(object);
2281
+ const meta = Obj4.getMeta(object);
2282
+ const tags = (meta.tags ?? []).map((tag) => db?.makeRef(DXN2.parse(tag))).filter(isNonNullable);
2283
+ const values = useMemo9(() => ({
2284
+ tags,
2285
+ ...object
2286
+ }), [
2287
+ object,
2288
+ tags
2289
+ ]);
2290
+ const formSchema = useMemo9(() => omitId(Schema3.Struct({
2291
+ tags: Schema3.Array(Ref4.Ref(Tag2.Tag)).pipe(Schema3.optional)
2292
+ }).pipe(Schema3.extend(schema))), [
2293
+ schema
2294
+ ]);
2295
+ const handleCreate = useCallback15((schema2, values2) => {
2296
+ invariant(db, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 49, S: void 0, A: ["db", ""] });
2297
+ invariant(Type2.isObjectSchema(schema2), void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 50, S: void 0, A: ["Type.isObjectSchema(schema)", ""] });
2298
+ const newObject = db.add(Obj4.make(schema2, values2));
2299
+ if (Obj4.instanceOf(Tag2.Tag, newObject)) {
2300
+ Obj4.update(object, (object2) => {
2301
+ Obj4.getMeta(object2).tags = [
2302
+ ...Obj4.getMeta(object2).tags ?? [],
2303
+ Obj4.getDXN(newObject).toString()
2304
+ ];
2305
+ });
2306
+ }
2307
+ }, []);
2308
+ const handleChange = useCallback15(({ tags: tags2, ...values2 }, { isValid, changed }) => {
2309
+ if (!isValid) {
2310
+ return;
2311
+ }
2312
+ const changedPaths = Object.keys(changed).filter((path) => changed[path]);
2313
+ const hasTagsChange = changedPaths.some((path) => splitJsonPath(path)[0] === "tags");
2314
+ if (hasTagsChange) {
2315
+ Obj4.update(object, (object2) => {
2316
+ Obj4.getMeta(object2).tags = tags2?.map((tag) => tag.dxn.toString()) ?? [];
2317
+ });
2318
+ }
2319
+ const nonTagPaths = changedPaths.filter((path) => splitJsonPath(path)[0] !== "tags");
2320
+ if (nonTagPaths.length > 0) {
2321
+ Obj4.update(object, () => {
2322
+ for (const path of nonTagPaths) {
2323
+ const parts = splitJsonPath(path);
2324
+ const value3 = Obj4.getValue(values2, parts);
2325
+ Obj4.setValue(object, parts, value3);
2326
+ }
2327
+ });
2328
+ }
2329
+ }, [
2330
+ object
2331
+ ]);
2332
+ return /* @__PURE__ */ React18.createElement(Form.Root, {
2333
+ schema: formSchema,
2334
+ defaultValues: values,
2335
+ createTypename: Type2.getTypename(Tag2.Tag),
2336
+ createOptionIcon: "ph--plus--regular",
2337
+ createOptionLabel: [
2338
+ "add-tag.label",
2339
+ {
2340
+ ns: translationKey10
2341
+ }
2342
+ ],
2343
+ createInitialValuePath: "label",
2344
+ createFieldMap,
2345
+ db,
2346
+ onValuesChanged: handleChange,
2347
+ onCreate: handleCreate
2348
+ }, /* @__PURE__ */ React18.createElement(Form.Viewport, null, /* @__PURE__ */ React18.createElement(Form.Content, null, /* @__PURE__ */ React18.createElement(Form.FieldSet, null))));
2189
2349
  };
2190
- SettingsGroupButton.displayName = SETTINGS_GROUP_BUTTON_NAME;
2191
- var SettingsGroup = ({ children, classNames }) => /* @__PURE__ */ React18.createElement("div", {
2192
- role: "none",
2193
- className: mx5("group space-y-trim-md", classNames)
2194
- }, children);
2195
- SettingsGroup.displayName = SETTINGS_GROUP_NAME;
2196
- var SettingsFrame = ({ children }) => /* @__PURE__ */ React18.createElement("div", {
2197
- role: "none",
2198
- className: "p-trim-md border border-separator rounded-md"
2199
- }, children);
2200
- SettingsFrame.displayName = SETTINGS_FRAME_NAME;
2201
- var SettingsFrameItem = ({ title, description, children }) => {
2202
- const { t } = useTranslation9(translationKey);
2203
- return /* @__PURE__ */ React18.createElement("div", {
2204
- role: "group",
2205
- className: "min-w-0"
2206
- }, /* @__PURE__ */ React18.createElement("h3", {
2207
- className: "text-lg mb-2"
2208
- }, toLocalizedString(title, t)), description && /* @__PURE__ */ React18.createElement("p", {
2209
- className: "my-trim-sm md:mb-0 text-description"
2210
- }, toLocalizedString(description, t)), children);
2350
+
2351
+ // src/components/ObjectProperties/ObjectProperties.tsx
2352
+ import * as Function from "effect/Function";
2353
+ import * as Option5 from "effect/Option";
2354
+ import * as Schema4 from "effect/Schema";
2355
+ import React19, { useCallback as useCallback16, useMemo as useMemo10 } from "react";
2356
+ import { DXN as DXN3, Obj as Obj5, Ref as Ref5, Tag as Tag3, Type as Type3 } from "@dxos/echo";
2357
+ import { splitJsonPath as splitJsonPath2 } from "@dxos/echo/internal";
2358
+ import { invariant as invariant2 } from "@dxos/invariant";
2359
+ import { HuePicker as HuePicker3 } from "@dxos/react-ui-pickers";
2360
+ import { FactoryAnnotation } from "@dxos/schema";
2361
+ import { composable as composable2, composableProps as composableProps2 } from "@dxos/ui-theme";
2362
+ import { isNonNullable as isNonNullable2 } from "@dxos/util";
2363
+ import { translationKey as translationKey11 } from "#translations";
2364
+ var __dxlog_file4 = "/__w/dxos/dxos/packages/ui/react-ui-form/src/components/ObjectProperties/ObjectProperties.tsx";
2365
+ var ObjectProperties = composable2(({ children, object, ...props }, forwardedRef) => {
2366
+ const db = Obj5.getDatabase(object);
2367
+ const meta = Obj5.getMeta(object);
2368
+ const tags = (meta.tags ?? []).map((tag) => db?.makeRef(DXN3.parse(tag))).filter(isNonNullable2);
2369
+ const values = useMemo10(() => ({
2370
+ tags,
2371
+ ...object
2372
+ }), [
2373
+ object,
2374
+ tags
2375
+ ]);
2376
+ const formSchema = useMemo10(() => {
2377
+ return Function.pipe(Obj5.getSchema(object), Option5.fromNullable, Option5.map((schema) => omitId(BaseSchema.pipe(Schema4.extend(schema)))), Option5.getOrUndefined);
2378
+ }, [
2379
+ object
2380
+ ]);
2381
+ const handleCreate = useCallback16((schema, values2) => {
2382
+ invariant2(db, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 45, S: void 0, A: ["db", ""] });
2383
+ invariant2(Type3.isObjectSchema(schema), void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 46, S: void 0, A: ["Type.isObjectSchema(schema)", ""] });
2384
+ const factory = Option5.getOrUndefined(FactoryAnnotation.get(schema));
2385
+ const newObject = factory ? factory(values2) : Obj5.make(schema, values2);
2386
+ return db.add(newObject);
2387
+ }, [
2388
+ db
2389
+ ]);
2390
+ const handleChange = useCallback16(({ tags: tags2, ...values2 }, { isValid, changed }) => {
2391
+ if (!isValid) {
2392
+ return;
2393
+ }
2394
+ const changedPaths = Object.keys(changed).filter((path) => changed[path]);
2395
+ const hasTagsChange = changedPaths.some((path) => splitJsonPath2(path)[0] === "tags");
2396
+ if (hasTagsChange) {
2397
+ Obj5.update(object, (object2) => {
2398
+ Obj5.getMeta(object2).tags = tags2?.map((tag) => tag.dxn.toString()) ?? [];
2399
+ });
2400
+ }
2401
+ const nonTagPaths = changedPaths.filter((path) => splitJsonPath2(path)[0] !== "tags");
2402
+ if (nonTagPaths.length > 0) {
2403
+ Obj5.update(object, () => {
2404
+ for (const path of nonTagPaths) {
2405
+ const parts = splitJsonPath2(path);
2406
+ const value3 = Obj5.getValue(values2, parts);
2407
+ Obj5.setValue(object, parts, value3);
2408
+ }
2409
+ });
2410
+ }
2411
+ }, [
2412
+ object
2413
+ ]);
2414
+ if (!formSchema) {
2415
+ return null;
2416
+ }
2417
+ return /* @__PURE__ */ React19.createElement(Form.Root, {
2418
+ schema: formSchema,
2419
+ defaultValues: values,
2420
+ createTypename: Type3.getTypename(Tag3.Tag),
2421
+ createOptionIcon: "ph--plus--regular",
2422
+ createOptionLabel: [
2423
+ "add-tag.label",
2424
+ {
2425
+ ns: translationKey11
2426
+ }
2427
+ ],
2428
+ createInitialValuePath: "label",
2429
+ createFieldMap: createFieldMap2,
2430
+ db,
2431
+ onValuesChanged: handleChange,
2432
+ onCreate: handleCreate
2433
+ }, /* @__PURE__ */ React19.createElement(Form.Viewport, {
2434
+ ...composableProps2(props),
2435
+ ref: forwardedRef
2436
+ }, /* @__PURE__ */ React19.createElement(Form.Content, null, /* @__PURE__ */ React19.createElement(Form.FieldSet, null), children)));
2437
+ });
2438
+ var createFieldMap2 = {
2439
+ hue: ({ type, label, layout, getValue, onValueChange }) => {
2440
+ const handleChange = useCallback16((nextHue) => onValueChange(type, nextHue), [
2441
+ onValueChange,
2442
+ type
2443
+ ]);
2444
+ const handleReset = useCallback16(() => onValueChange(type, void 0), [
2445
+ onValueChange,
2446
+ type
2447
+ ]);
2448
+ return /* @__PURE__ */ React19.createElement(React19.Fragment, null, layout !== "inline" && /* @__PURE__ */ React19.createElement(Form.Label, {
2449
+ label
2450
+ }), /* @__PURE__ */ React19.createElement(HuePicker3, {
2451
+ value: getValue(),
2452
+ onChange: handleChange,
2453
+ onReset: handleReset
2454
+ }));
2455
+ }
2211
2456
  };
2212
- SettingsFrameItem.displayName = SETTINGS_FRAME_ITEM_NAME;
2213
- var SettingsContainer = ({ classNames, children }) => {
2214
- return /* @__PURE__ */ React18.createElement("div", {
2457
+ var BaseSchema = Schema4.Struct({
2458
+ tags: Schema4.Array(Ref5.Ref(Tag3.Tag)).pipe(Schema4.optional)
2459
+ });
2460
+
2461
+ // src/components/Settings/Settings.tsx
2462
+ import React22 from "react";
2463
+ import { ScrollArea as ScrollArea2, toLocalizedString as toLocalizedString2, useTranslation as useTranslation11 } from "@dxos/react-ui";
2464
+ import { composable as composable3, composableProps as composableProps3, mx as mx4 } from "@dxos/ui-theme";
2465
+ import { translationKey as translationKey13 } from "#translations";
2466
+
2467
+ // src/components/Settings/SettingsFieldSet.tsx
2468
+ import * as SchemaAST5 from "effect/SchemaAST";
2469
+ import * as String3 from "effect/String";
2470
+ import React21, { useCallback as useCallback17, useMemo as useMemo11 } from "react";
2471
+ import { getAnnotation as getAnnotation3 } from "@dxos/effect";
2472
+ import { Input as Input13, Select as Select2 } from "@dxos/react-ui";
2473
+
2474
+ // src/components/Settings/SettingsItem.tsx
2475
+ import React20 from "react";
2476
+ import { Input as Input12, toLocalizedString, useTranslation as useTranslation10 } from "@dxos/react-ui";
2477
+ import { mx as mx3 } from "@dxos/ui-theme";
2478
+ import { translationKey as translationKey12 } from "#translations";
2479
+ var SETTINGS_PANEL_NAME = "Settings.Panel";
2480
+ var SETTINGS_ITEM_NAME = "Settings.Item";
2481
+ var SettingsPanel = ({ classNames, children }) => {
2482
+ return /* @__PURE__ */ React20.createElement("div", {
2215
2483
  role: "none",
2216
- className: mx5([
2217
- "dx-article",
2218
- "*:first:mt-0! *:last:mb-0! px-trim-md py-trim-md",
2219
- "border border-separator rounded-md",
2220
- classNames
2221
- ])
2484
+ className: mx3("flex flex-col gap-3 p-trim-md border border-separator rounded-sm", classNames)
2222
2485
  }, children);
2223
2486
  };
2224
- SettingsContainer.displayName = SETTINGS_CONTAINER_NAME;
2487
+ SettingsPanel.displayName = SETTINGS_PANEL_NAME;
2225
2488
  var SettingsItem = ({ title, description = "", children }) => {
2226
- const { t } = useTranslation9(translationKey);
2227
- return /* @__PURE__ */ React18.createElement(SettingsContainer, {
2228
- classNames: styles.grid
2229
- }, /* @__PURE__ */ React18.createElement("h3", {
2230
- className: mx5(styles.title, "md:col-span-2")
2231
- }, toLocalizedString(title, t)), /* @__PURE__ */ React18.createElement("p", {
2232
- className: styles.description
2233
- }, toLocalizedString(description, t)), /* @__PURE__ */ React18.createElement("div", {
2489
+ const { t } = useTranslation10(translationKey12);
2490
+ return /* @__PURE__ */ React20.createElement(Input12.Root, null, /* @__PURE__ */ React20.createElement(SettingsPanel, {
2491
+ classNames: "grid grid-cols-1 md:grid-cols-[1fr_1fr] gap-x-trim-lg gap-y-0"
2492
+ }, /* @__PURE__ */ React20.createElement(Input12.Label, {
2493
+ classNames: "pb-trim-md text-base-surface-text text-lg md:col-span-2"
2494
+ }, toLocalizedString(title, t)), /* @__PURE__ */ React20.createElement(Input12.DescriptionAndValidation, null, /* @__PURE__ */ React20.createElement(Input12.Description, {
2495
+ classNames: "text-base text-description"
2496
+ }, toLocalizedString(description, t))), /* @__PURE__ */ React20.createElement("div", {
2234
2497
  role: "none",
2235
- className: "overflow-hidden text-end py-1"
2236
- }, children));
2498
+ className: "text-end py-1"
2499
+ }, children)));
2237
2500
  };
2238
2501
  SettingsItem.displayName = SETTINGS_ITEM_NAME;
2239
- var SettingsItemInput = ({ title, description = "", children }) => {
2240
- const { t } = useTranslation9(translationKey);
2241
- return /* @__PURE__ */ React18.createElement(Input12.Root, null, /* @__PURE__ */ React18.createElement(SettingsContainer, {
2242
- classNames: styles.grid
2243
- }, /* @__PURE__ */ React18.createElement(Input12.Label, {
2244
- classNames: mx5(styles.title, "md:col-span-2")
2245
- }, toLocalizedString(title, t)), /* @__PURE__ */ React18.createElement(Input12.DescriptionAndValidation, null, /* @__PURE__ */ React18.createElement(Input12.Description, {
2246
- classNames: styles.description
2247
- }, toLocalizedString(description, t))), /* @__PURE__ */ React18.createElement("div", {
2502
+
2503
+ // src/components/Settings/SettingsFieldSet.tsx
2504
+ var SettingsFieldSet = ({ schema, values, onValuesChanged, readonly, fieldMap, visible, sort, pathPrefix = "" }) => {
2505
+ const properties = useMemo11(() => {
2506
+ const props = getFormProperties(schema.ast);
2507
+ if (!sort) {
2508
+ return props;
2509
+ }
2510
+ const rank = (name) => {
2511
+ const idx = sort.indexOf(name);
2512
+ return idx === -1 ? Number.POSITIVE_INFINITY : idx;
2513
+ };
2514
+ return [
2515
+ ...props
2516
+ ].sort(({ name: a }, { name: b }) => rank(a.toString()) - rank(b.toString()));
2517
+ }, [
2518
+ schema,
2519
+ sort
2520
+ ]);
2521
+ const handleChange = useCallback17((name, value3) => {
2522
+ onValuesChanged?.({
2523
+ ...values,
2524
+ [name]: value3
2525
+ });
2526
+ }, [
2527
+ values,
2528
+ onValuesChanged
2529
+ ]);
2530
+ return /* @__PURE__ */ React21.createElement(React21.Fragment, null, properties.map((property) => {
2531
+ const name = property.name.toString();
2532
+ const path = pathPrefix ? `${pathPrefix}.${name}` : name;
2533
+ if (visible && !visible(path, values)) {
2534
+ return null;
2535
+ }
2536
+ const entry = fieldMap?.[name];
2537
+ return /* @__PURE__ */ React21.createElement(SettingsFieldItem, {
2538
+ key: name,
2539
+ path,
2540
+ property,
2541
+ value: values[name],
2542
+ onChange: (value3) => handleChange(name, value3),
2543
+ readonly,
2544
+ customField: typeof entry === "function" ? entry : void 0,
2545
+ nestedFieldMap: typeof entry === "object" ? entry : void 0,
2546
+ visible,
2547
+ sort
2548
+ });
2549
+ }));
2550
+ };
2551
+ SettingsFieldSet.displayName = "Settings.FieldSet";
2552
+ var SettingsFieldItem = ({ property, path, value: value3, onChange, readonly, customField, nestedFieldMap, visible, sort }) => {
2553
+ const { type } = property;
2554
+ const name = property.name.toString();
2555
+ const title = getAnnotation3(SchemaAST5.TitleAnnotationId)(type) ?? String3.capitalize(name);
2556
+ const description = getAnnotation3(SchemaAST5.DescriptionAnnotationId)(type);
2557
+ if (customField) {
2558
+ const CustomField = customField;
2559
+ return /* @__PURE__ */ React21.createElement(SettingsItem, {
2560
+ title,
2561
+ description
2562
+ }, /* @__PURE__ */ React21.createElement(CustomField, {
2563
+ value: value3,
2564
+ onChange,
2565
+ readonly
2566
+ }));
2567
+ }
2568
+ const fieldType = detectFieldType(type);
2569
+ switch (fieldType) {
2570
+ case "struct":
2571
+ return /* @__PURE__ */ React21.createElement(SettingsFieldSet, {
2572
+ schema: {
2573
+ ast: type
2574
+ },
2575
+ values: value3 ?? {},
2576
+ onValuesChanged: onChange,
2577
+ readonly,
2578
+ fieldMap: nestedFieldMap,
2579
+ visible,
2580
+ sort,
2581
+ pathPrefix: path
2582
+ });
2583
+ case "boolean":
2584
+ return /* @__PURE__ */ React21.createElement(SettingsItem, {
2585
+ title,
2586
+ description
2587
+ }, /* @__PURE__ */ React21.createElement(Input13.Switch, {
2588
+ disabled: readonly,
2589
+ checked: !!value3,
2590
+ onCheckedChange: (checked) => onChange(!!checked)
2591
+ }));
2592
+ case "select": {
2593
+ const options = getSelectOptionsFromAst(type) ?? [];
2594
+ return /* @__PURE__ */ React21.createElement(SettingsItem, {
2595
+ title,
2596
+ description
2597
+ }, /* @__PURE__ */ React21.createElement(Select2.Root, {
2598
+ disabled: readonly,
2599
+ value: value3 == null ? "" : globalThis.String(value3),
2600
+ onValueChange: (selected) => {
2601
+ const matched = options.find((option) => globalThis.String(option.value) === selected);
2602
+ onChange(matched?.value ?? selected);
2603
+ }
2604
+ }, /* @__PURE__ */ React21.createElement(Select2.TriggerButton, {
2605
+ disabled: readonly
2606
+ }), /* @__PURE__ */ React21.createElement(Select2.Portal, null, /* @__PURE__ */ React21.createElement(Select2.Content, null, /* @__PURE__ */ React21.createElement(Select2.Viewport, null, options.map((option) => /* @__PURE__ */ React21.createElement(Select2.Option, {
2607
+ key: globalThis.String(option.value),
2608
+ value: globalThis.String(option.value)
2609
+ }, option.label ?? globalThis.String(option.value)))), /* @__PURE__ */ React21.createElement(Select2.Arrow, null)))));
2610
+ }
2611
+ case "string":
2612
+ return /* @__PURE__ */ React21.createElement(SettingsItem, {
2613
+ title,
2614
+ description
2615
+ }, /* @__PURE__ */ React21.createElement(Input13.TextInput, {
2616
+ disabled: readonly,
2617
+ value: value3 ?? "",
2618
+ onChange: (event) => onChange(event.target.value)
2619
+ }));
2620
+ case "number":
2621
+ return /* @__PURE__ */ React21.createElement(SettingsItem, {
2622
+ title,
2623
+ description
2624
+ }, /* @__PURE__ */ React21.createElement(Input13.TextInput, {
2625
+ disabled: readonly,
2626
+ type: "number",
2627
+ value: value3 ?? "",
2628
+ onChange: (event) => {
2629
+ if (event.target.value === "") {
2630
+ onChange(void 0);
2631
+ return;
2632
+ }
2633
+ const parsed = Number(event.target.value);
2634
+ onChange(Number.isNaN(parsed) ? void 0 : parsed);
2635
+ }
2636
+ }));
2637
+ default:
2638
+ return null;
2639
+ }
2640
+ };
2641
+
2642
+ // src/components/Settings/Settings.tsx
2643
+ var SETTINGS_ROOT_NAME = "Settings.Root";
2644
+ var SETTINGS_VIEWPORT_NAME = "Settings.Viewport";
2645
+ var SETTINGS_SECTION_NAME = "Settings.Section";
2646
+ var SettingsRoot = ({ children, classNames }) => {
2647
+ return /* @__PURE__ */ React22.createElement("div", {
2648
+ className: mx4("flex flex-col gap-2", classNames)
2649
+ }, children);
2650
+ };
2651
+ SettingsRoot.displayName = SETTINGS_ROOT_NAME;
2652
+ var SettingsViewport = composable3(({ children, ...props }, forwardedRef) => {
2653
+ return /* @__PURE__ */ React22.createElement(ScrollArea2.Root, {
2654
+ ...composableProps3(props),
2655
+ orientation: "vertical",
2656
+ centered: true,
2657
+ thin: true,
2658
+ ref: forwardedRef
2659
+ }, /* @__PURE__ */ React22.createElement(ScrollArea2.Viewport, {
2660
+ classNames: "px-4 pointer-coarse:px-2"
2661
+ }, /* @__PURE__ */ React22.createElement("div", {
2248
2662
  role: "none",
2249
- className: "text-end py-1"
2663
+ className: "dx-document flex flex-col gap-2 py-4"
2250
2664
  }, children)));
2665
+ });
2666
+ SettingsViewport.displayName = SETTINGS_VIEWPORT_NAME;
2667
+ var SettingsSection = ({ title, description, children }) => {
2668
+ const { t } = useTranslation11(translationKey13);
2669
+ return /* @__PURE__ */ React22.createElement(React22.Fragment, null, /* @__PURE__ */ React22.createElement("h2", {
2670
+ className: "px-trim-md mt-trim-md text-xl"
2671
+ }, toLocalizedString2(title, t)), description && /* @__PURE__ */ React22.createElement("p", {
2672
+ className: "px-trim-md text-description"
2673
+ }, toLocalizedString2(description, t)), /* @__PURE__ */ React22.createElement("div", {
2674
+ className: "w-full pt-trim-md space-y-trim-md"
2675
+ }, children));
2251
2676
  };
2252
- SettingsItemInput.displayName = SETTINGS_ITEM_INPUT_NAME;
2677
+ SettingsSection.displayName = SETTINGS_SECTION_NAME;
2253
2678
  var Settings = {
2254
2679
  Root: SettingsRoot,
2680
+ Viewport: SettingsViewport,
2255
2681
  Section: SettingsSection,
2256
- SectionHeading: SettingsSectionHeading,
2257
- Group: SettingsGroup,
2258
- GroupButton: SettingsGroupButton,
2259
- Container: SettingsContainer,
2260
- Frame: SettingsFrame,
2261
- FrameItem: SettingsFrameItem,
2682
+ Panel: SettingsPanel,
2262
2683
  Item: SettingsItem,
2263
- ItemInput: SettingsItemInput
2684
+ FieldSet: SettingsFieldSet
2685
+ };
2686
+
2687
+ // src/components/Settings/SettingsSelectField.tsx
2688
+ import React23 from "react";
2689
+ import { Select as Select3 } from "@dxos/react-ui";
2690
+ var createSelectField = ({ options, defaultLabel = "Default" }) => {
2691
+ const normalized = options.map((option) => typeof option === "string" ? {
2692
+ value: option,
2693
+ label: option
2694
+ } : option);
2695
+ const hasDefault = defaultLabel !== null;
2696
+ const sentinel = hasDefault ? `__default__${Math.random().toString(36).slice(2)}` : "";
2697
+ return ({ value: value3, onChange, readonly }) => /* @__PURE__ */ React23.createElement(Select3.Root, {
2698
+ disabled: readonly,
2699
+ value: value3 ?? sentinel,
2700
+ onValueChange: (next) => onChange(hasDefault && next === sentinel ? void 0 : next)
2701
+ }, /* @__PURE__ */ React23.createElement(Select3.TriggerButton, {
2702
+ disabled: readonly
2703
+ }), /* @__PURE__ */ React23.createElement(Select3.Portal, null, /* @__PURE__ */ React23.createElement(Select3.Content, null, /* @__PURE__ */ React23.createElement(Select3.Viewport, null, hasDefault && /* @__PURE__ */ React23.createElement(Select3.Option, {
2704
+ value: sentinel
2705
+ }, defaultLabel), normalized.map((option) => /* @__PURE__ */ React23.createElement(Select3.Option, {
2706
+ key: option.value,
2707
+ value: option.value
2708
+ }, option.label ?? option.value))), /* @__PURE__ */ React23.createElement(Select3.Arrow, null))));
2264
2709
  };
2265
2710
 
2266
2711
  // src/components/ViewEditor/ViewEditor.tsx
2267
2712
  import { RegistryContext } from "@effect-atom/atom-react";
2268
- import * as Array2 from "effect/Array";
2713
+ import * as Array4 from "effect/Array";
2269
2714
  import * as Match2 from "effect/Match";
2270
- import * as Option4 from "effect/Option";
2271
- import * as Schema3 from "effect/Schema";
2272
- import React19, { forwardRef as forwardRef3, useCallback as useCallback15, useContext, useImperativeHandle, useMemo as useMemo8, useState as useState6 } from "react";
2273
- import { Entity as Entity2, Feed, Filter as Filter2, Format as Format5, Obj as Obj3, Query, QueryAST, Ref as Ref3 } from "@dxos/echo";
2715
+ import * as Option6 from "effect/Option";
2716
+ import * as Schema5 from "effect/Schema";
2717
+ import React24, { forwardRef as forwardRef2, useCallback as useCallback18, useContext, useImperativeHandle, useMemo as useMemo12, useState as useState7 } from "react";
2718
+ import { Entity as Entity2, Feed, Filter as Filter2, Format as Format5, Obj as Obj6, Query, QueryAST, Ref as Ref6 } from "@dxos/echo";
2274
2719
  import { View } from "@dxos/echo";
2275
2720
  import { EchoSchema, isMutable, toJsonSchema } from "@dxos/echo/internal";
2276
- import { invariant } from "@dxos/invariant";
2721
+ import { invariant as invariant3 } from "@dxos/invariant";
2277
2722
  import { useObject, useQuery as useQuery2 } from "@dxos/react-client/echo";
2278
- import { IconButton as IconButton4, Input as Input13, Message, useTranslation as useTranslation10 } from "@dxos/react-ui";
2723
+ import { IconButton as IconButton4, Input as Input14, Message, useTranslation as useTranslation12 } from "@dxos/react-ui";
2279
2724
  import { QueryForm } from "@dxos/react-ui-components";
2280
2725
  import { List as List2 } from "@dxos/react-ui-list";
2281
- import { ProjectionModel, VIEW_FIELD_LIMIT, createEchoChangeCallback, getTypenameFromQuery } from "@dxos/schema";
2282
- import { mx as mx6, osTranslations as osTranslations2, subtleHover as subtleHover2 } from "@dxos/ui-theme";
2283
- var __dxlog_file3 = "/__w/dxos/dxos/packages/ui/react-ui-form/src/components/ViewEditor/ViewEditor.tsx";
2284
- var ViewEditor = /* @__PURE__ */ forwardRef3(({ classNames, schema, view, mode = "schema", registry, db, readonly, showHeading = false, types, tags, onQueryChanged, onDelete }, forwardedRef) => {
2726
+ import { ParentLabelAnnotation, ProjectionModel, VIEW_FIELD_LIMIT, createEchoChangeCallback, getTypenameFromQuery } from "@dxos/schema";
2727
+ import { mx as mx5, osTranslations as osTranslations2, subtleHover as subtleHover2 } from "@dxos/ui-theme";
2728
+ import { translationKey as translationKey14 } from "#translations";
2729
+ var __dxlog_file5 = "/__w/dxos/dxos/packages/ui/react-ui-form/src/components/ViewEditor/ViewEditor.tsx";
2730
+ var ViewEditor = /* @__PURE__ */ forwardRef2(({ classNames, schema, view, mode = "schema", registry, db, readonly, showHeading = false, types, tags, onQueryChanged, onDelete }, forwardedRef) => {
2285
2731
  const atomRegistry = useContext(RegistryContext);
2286
2732
  const schemaReadonly = !isMutable(schema);
2287
- const { t } = useTranslation10(translationKey);
2288
- const projectionModel = useMemo8(() => {
2733
+ const { t } = useTranslation12(translationKey14);
2734
+ const projectionModel = useMemo12(() => {
2289
2735
  const jsonSchema = schema instanceof EchoSchema ? schema.jsonSchema : toJsonSchema(schema);
2290
2736
  const change = createEchoChangeCallback(view, schema instanceof EchoSchema ? schema : void 0);
2291
2737
  const model = new ProjectionModel({
@@ -2309,21 +2755,21 @@ var ViewEditor = /* @__PURE__ */ forwardRef3(({ classNames, schema, view, mode =
2309
2755
  if (from._tag !== "scope") {
2310
2756
  return void 0;
2311
2757
  }
2312
- return Option4.fromNullable(from.scope.queues).pipe(Option4.flatMap((queues) => Array2.head(queues)), Option4.map(String), Option4.getOrUndefined);
2758
+ return Option6.fromNullable(from.scope.queues).pipe(Option6.flatMap((queues) => Array4.head(queues)), Option6.map(String), Option6.getOrUndefined);
2313
2759
  }), Match2.orElse(() => void 0));
2314
2760
  const feeds = useQuery2(db, Filter2.type(Feed.Feed));
2315
- const targetRef = useMemo8(() => {
2761
+ const targetRef = useMemo12(() => {
2316
2762
  if (!queueTarget) {
2317
2763
  return void 0;
2318
2764
  }
2319
2765
  const feed = feeds.find((feed2) => Feed.getQueueDxn(feed2)?.toString() === queueTarget);
2320
- return feed ? Ref3.fromDXN(Entity2.getDXN(feed)) : void 0;
2766
+ return feed ? Ref6.fromDXN(Entity2.getDXN(feed)) : void 0;
2321
2767
  }, [
2322
2768
  queueTarget,
2323
2769
  feeds
2324
2770
  ]);
2325
- const viewSchema = useMemo8(() => {
2326
- const base = Schema3.Struct({
2771
+ const viewSchema = useMemo12(() => {
2772
+ const base = Schema5.Struct({
2327
2773
  query: mode === "schema" ? Format5.URL.annotations({
2328
2774
  title: "Record type"
2329
2775
  }) : QueryAST.Query.annotations({
@@ -2331,18 +2777,19 @@ var ViewEditor = /* @__PURE__ */ forwardRef3(({ classNames, schema, view, mode =
2331
2777
  })
2332
2778
  });
2333
2779
  if (mode === "tag") {
2334
- return Schema3.Struct({
2780
+ return Schema5.Struct({
2335
2781
  ...base.fields,
2336
- target: Schema3.optional(Ref3.Ref(Feed.Feed).annotations({
2782
+ // TODO(wittjosiah): Replace Type.Feed with Dataset.Dataset when Ref.Ref supports unions.
2783
+ target: Ref6.Ref(Feed.Feed).pipe(Schema5.annotations({
2337
2784
  title: "Target Feed"
2338
- }))
2339
- }).pipe(Schema3.mutable);
2785
+ }), ParentLabelAnnotation.set(true), Schema5.optional)
2786
+ }).pipe(Schema5.mutable);
2340
2787
  }
2341
- return base.pipe(Schema3.mutable);
2788
+ return base.pipe(Schema5.mutable);
2342
2789
  }, [
2343
2790
  mode
2344
2791
  ]);
2345
- const viewValues = useMemo8(() => ({
2792
+ const viewValues = useMemo12(() => ({
2346
2793
  query: mode === "schema" ? getTypenameFromQuery(view.query.ast) : view.query.ast,
2347
2794
  target: targetRef
2348
2795
  }), [
@@ -2350,7 +2797,7 @@ var ViewEditor = /* @__PURE__ */ forwardRef3(({ classNames, schema, view, mode =
2350
2797
  view.query.ast,
2351
2798
  targetRef
2352
2799
  ]);
2353
- const fieldMap = useMemo8(() => mode === "tag" ? customFields({
2800
+ const fieldMap = useMemo12(() => mode === "tag" ? customFields({
2354
2801
  types,
2355
2802
  tags
2356
2803
  }) : void 0, [
@@ -2358,12 +2805,12 @@ var ViewEditor = /* @__PURE__ */ forwardRef3(({ classNames, schema, view, mode =
2358
2805
  types,
2359
2806
  tags
2360
2807
  ]);
2361
- const handleUpdate = useCallback15((values) => {
2808
+ const handleUpdate = useCallback18((values) => {
2362
2809
  const targetValue = values.target;
2363
2810
  let queueDxn;
2364
- if (Ref3.isRef(targetValue)) {
2811
+ if (Ref6.isRef(targetValue)) {
2365
2812
  const feedDxn = targetValue.dxn.toString();
2366
- const feed = feeds.find((feed2) => Obj3.getDXN(feed2).toString() === feedDxn);
2813
+ const feed = feeds.find((feed2) => Obj6.getDXN(feed2).toString() === feedDxn);
2367
2814
  if (feed) {
2368
2815
  queueDxn = Feed.getQueueDxn(feed)?.toString();
2369
2816
  }
@@ -2375,37 +2822,29 @@ var ViewEditor = /* @__PURE__ */ forwardRef3(({ classNames, schema, view, mode =
2375
2822
  mode,
2376
2823
  feeds
2377
2824
  ]);
2378
- const handleDelete = useCallback15((fieldId) => {
2379
- invariant(!readonly, void 0, {
2380
- F: __dxlog_file3,
2381
- L: 174,
2382
- S: void 0,
2383
- A: [
2384
- "!readonly",
2385
- ""
2386
- ]
2387
- });
2825
+ const handleDelete = useCallback18((fieldId) => {
2826
+ invariant3(!readonly, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file5, L: 127, S: void 0, A: ["!readonly", ""] });
2388
2827
  onDelete?.(fieldId);
2389
2828
  }, [
2390
2829
  onDelete,
2391
2830
  readonly
2392
2831
  ]);
2393
- return /* @__PURE__ */ React19.createElement("div", {
2832
+ return /* @__PURE__ */ React24.createElement("div", {
2394
2833
  role: "none",
2395
- className: mx6(classNames)
2396
- }, schemaReadonly && !readonly && /* @__PURE__ */ React19.createElement(Message.Root, {
2834
+ className: mx5(classNames)
2835
+ }, schemaReadonly && !readonly && /* @__PURE__ */ React24.createElement(Message.Root, {
2397
2836
  valence: "info",
2398
2837
  classNames: "my-form-padding"
2399
- }, /* @__PURE__ */ React19.createElement(Message.Title, null, t("system schema description"))), /* @__PURE__ */ React19.createElement(Form.Root, {
2838
+ }, /* @__PURE__ */ React24.createElement(Message.Title, null, t("system-schema.description"))), /* @__PURE__ */ React24.createElement(Form.Root, {
2400
2839
  schema: viewSchema,
2401
2840
  values: viewValues,
2402
2841
  fieldMap,
2403
2842
  db,
2404
2843
  onValuesChanged: handleUpdate
2405
- }, /* @__PURE__ */ React19.createElement(Form.FieldSet, null), /* @__PURE__ */ React19.createElement(FormFieldLabel, {
2406
- label: t("fields label"),
2844
+ }, /* @__PURE__ */ React24.createElement(Form.FieldSet, null), /* @__PURE__ */ React24.createElement(FormFieldLabel, {
2845
+ label: t("fields.label"),
2407
2846
  asChild: true
2408
- }), /* @__PURE__ */ React19.createElement(FieldList, {
2847
+ }), /* @__PURE__ */ React24.createElement(FieldList, {
2409
2848
  schema,
2410
2849
  view,
2411
2850
  registry,
@@ -2417,9 +2856,9 @@ var ViewEditor = /* @__PURE__ */ forwardRef3(({ classNames, schema, view, mode =
2417
2856
  var FieldList = ({ schema, view, registry, readonly, showHeading = false, onDelete }) => {
2418
2857
  const atomRegistry = useContext(RegistryContext);
2419
2858
  const schemaReadonly = !isMutable(schema);
2420
- const { t } = useTranslation10(translationKey);
2859
+ const { t } = useTranslation12(translationKey14);
2421
2860
  const [viewSnapshot] = useObject(view);
2422
- const projectionModel = useMemo8(() => {
2861
+ const projectionModel = useMemo12(() => {
2423
2862
  const jsonSchema = schema instanceof EchoSchema ? schema.jsonSchema : toJsonSchema(schema);
2424
2863
  const change = createEchoChangeCallback(view, schema instanceof EchoSchema ? schema : void 0);
2425
2864
  const model = new ProjectionModel({
@@ -2434,38 +2873,22 @@ var FieldList = ({ schema, view, registry, readonly, showHeading = false, onDele
2434
2873
  schema,
2435
2874
  view
2436
2875
  ]);
2437
- const [expandedField, setExpandedField] = useState6();
2438
- const handleAdd = useCallback15(() => {
2439
- invariant(!readonly, void 0, {
2440
- F: __dxlog_file3,
2441
- L: 239,
2442
- S: void 0,
2443
- A: [
2444
- "!readonly",
2445
- ""
2446
- ]
2447
- });
2876
+ const [expandedField, setExpandedField] = useState7();
2877
+ const handleAdd = useCallback18(() => {
2878
+ invariant3(!readonly, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file5, L: 183, S: void 0, A: ["!readonly", ""] });
2448
2879
  const field = projectionModel.createFieldProjection();
2449
2880
  setExpandedField(field.id);
2450
2881
  }, [
2451
2882
  projectionModel,
2452
2883
  readonly
2453
2884
  ]);
2454
- const handleToggleField = useCallback15((field) => {
2885
+ const handleToggleField = useCallback18((field) => {
2455
2886
  setExpandedField((prevExpandedFieldId) => prevExpandedFieldId === field.id ? void 0 : field.id);
2456
2887
  }, [
2457
2888
  readonly
2458
2889
  ]);
2459
- const handleDelete = useCallback15((fieldId) => {
2460
- invariant(!readonly, void 0, {
2461
- F: __dxlog_file3,
2462
- L: 253,
2463
- S: void 0,
2464
- A: [
2465
- "!readonly",
2466
- ""
2467
- ]
2468
- });
2890
+ const handleDelete = useCallback18((fieldId) => {
2891
+ invariant3(!readonly, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file5, L: 196, S: void 0, A: ["!readonly", ""] });
2469
2892
  if (fieldId === expandedField) {
2470
2893
  setExpandedField(void 0);
2471
2894
  }
@@ -2475,36 +2898,28 @@ var FieldList = ({ schema, view, registry, readonly, showHeading = false, onDele
2475
2898
  onDelete,
2476
2899
  readonly
2477
2900
  ]);
2478
- const handleMove = useCallback15((fromIndex, toIndex) => {
2479
- invariant(!readonly, void 0, {
2480
- F: __dxlog_file3,
2481
- L: 265,
2482
- S: void 0,
2483
- A: [
2484
- "!readonly",
2485
- ""
2486
- ]
2487
- });
2488
- Obj3.change(view, (v) => {
2901
+ const handleMove = useCallback18((fromIndex, toIndex) => {
2902
+ invariant3(!readonly, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file5, L: 207, S: void 0, A: ["!readonly", ""] });
2903
+ Obj6.update(view, (view2) => {
2489
2904
  const fields = [
2490
- ...v.projection.fields
2905
+ ...view2.projection.fields
2491
2906
  ];
2492
2907
  const [moved] = fields.splice(fromIndex, 1);
2493
2908
  fields.splice(toIndex, 0, moved);
2494
- v.projection.fields = fields;
2909
+ view2.projection.fields = fields;
2495
2910
  });
2496
2911
  }, [
2497
2912
  view,
2498
2913
  readonly
2499
2914
  ]);
2500
- const handleClose = useCallback15(() => setExpandedField(void 0), []);
2501
- const handleHide = useCallback15((fieldId) => {
2915
+ const handleClose = useCallback18(() => setExpandedField(void 0), []);
2916
+ const handleHide = useCallback18((fieldId) => {
2502
2917
  setExpandedField(void 0);
2503
2918
  projectionModel.hideFieldProjection(fieldId);
2504
2919
  }, [
2505
2920
  projectionModel
2506
2921
  ]);
2507
- const handleShow = useCallback15((property) => {
2922
+ const handleShow = useCallback18((property) => {
2508
2923
  setExpandedField(void 0);
2509
2924
  projectionModel.showFieldProjection(property);
2510
2925
  }, [
@@ -2513,70 +2928,70 @@ var FieldList = ({ schema, view, registry, readonly, showHeading = false, onDele
2513
2928
  if (!viewSnapshot) {
2514
2929
  return null;
2515
2930
  }
2516
- return /* @__PURE__ */ React19.createElement(List2.Root, {
2931
+ return /* @__PURE__ */ React24.createElement(List2.Root, {
2517
2932
  items: viewSnapshot.projection.fields,
2518
- isItem: Schema3.is(View.FieldSchema),
2933
+ isItem: Schema5.is(View.FieldSchema),
2519
2934
  getId: (field) => field.id,
2520
2935
  onMove: readonly ? void 0 : handleMove,
2521
2936
  readonly
2522
- }, ({ items: fields }) => /* @__PURE__ */ React19.createElement(React19.Fragment, null, showHeading && /* @__PURE__ */ React19.createElement("h3", {
2937
+ }, ({ items: fields }) => /* @__PURE__ */ React24.createElement(React24.Fragment, null, showHeading && /* @__PURE__ */ React24.createElement("h3", {
2523
2938
  className: "text-sm"
2524
- }, t("field path label")), /* @__PURE__ */ React19.createElement("div", {
2939
+ }, t("field-path.label")), /* @__PURE__ */ React24.createElement("div", {
2525
2940
  role: "list",
2526
2941
  className: "grid grid-cols-[min-content_1fr_min-content_min-content_min-content]"
2527
2942
  }, fields?.map((field) => {
2528
2943
  const hidden = field.visible === false;
2529
- return /* @__PURE__ */ React19.createElement(List2.Item, {
2944
+ return /* @__PURE__ */ React24.createElement(List2.Item, {
2530
2945
  key: field.id,
2531
2946
  item: field,
2532
2947
  classNames: "grid grid-cols-subgrid col-span-5",
2533
2948
  "aria-expanded": expandedField === field.id
2534
- }, /* @__PURE__ */ React19.createElement("div", {
2949
+ }, /* @__PURE__ */ React24.createElement("div", {
2535
2950
  role: "none",
2536
- className: mx6(subtleHover2, "grid grid-cols-subgrid col-span-5", "rounded-xs cursor-pointer min-h-10")
2537
- }, /* @__PURE__ */ React19.createElement(List2.ItemDragHandle, {
2951
+ className: mx5(subtleHover2, "grid grid-cols-subgrid col-span-5", "rounded-xs cursor-pointer min-h-10")
2952
+ }, /* @__PURE__ */ React24.createElement(List2.ItemDragHandle, {
2538
2953
  disabled: readonly || schemaReadonly
2539
- }), /* @__PURE__ */ React19.createElement(List2.ItemTitle, {
2954
+ }), /* @__PURE__ */ React24.createElement(List2.ItemTitle, {
2540
2955
  classNames: hidden && "text-subdued",
2541
2956
  onClick: () => handleToggleField(field)
2542
- }, field.path), /* @__PURE__ */ React19.createElement(List2.ItemButton, {
2957
+ }, field.path), /* @__PURE__ */ React24.createElement(List2.ItemIconButton, {
2543
2958
  label: t(hidden ? "show field label" : "hide field label"),
2544
2959
  "data-testid": hidden ? "show-field-button" : "hide-field-button",
2545
2960
  icon: hidden ? "ph--eye-closed--regular" : "ph--eye--regular",
2546
2961
  autoHide: false,
2547
2962
  disabled: readonly || !hidden && projectionModel.getFields().length <= 1,
2548
2963
  onClick: () => hidden ? handleShow(field.path) : handleHide(field.id)
2549
- }), !readonly && /* @__PURE__ */ React19.createElement(React19.Fragment, null, /* @__PURE__ */ React19.createElement(List2.ItemDeleteButton, {
2550
- label: t("delete field label"),
2964
+ }), !readonly && /* @__PURE__ */ React24.createElement(React24.Fragment, null, /* @__PURE__ */ React24.createElement(List2.ItemDeleteButton, {
2965
+ label: t("delete-field.label"),
2551
2966
  autoHide: false,
2552
2967
  disabled: readonly || schemaReadonly || viewSnapshot.projection.fields.length <= 1,
2553
2968
  onClick: () => handleDelete(field.id),
2554
2969
  "data-testid": "field.delete"
2555
- }), /* @__PURE__ */ React19.createElement(IconButton4, {
2970
+ }), /* @__PURE__ */ React24.createElement(List2.ItemIconButton, {
2556
2971
  iconOnly: true,
2557
2972
  variant: "ghost",
2558
- label: t("toggle expand label", {
2973
+ label: t("toggle-expand.label", {
2559
2974
  ns: osTranslations2
2560
2975
  }),
2561
2976
  icon: expandedField === field.id ? "ph--caret-down--regular" : "ph--caret-right--regular",
2562
2977
  onClick: () => handleToggleField(field),
2563
2978
  "data-testid": "field.toggle"
2564
- }))), expandedField === field.id && !readonly && /* @__PURE__ */ React19.createElement("div", {
2979
+ }))), expandedField === field.id && !readonly && /* @__PURE__ */ React24.createElement("div", {
2565
2980
  role: "none",
2566
- className: "col-span-5 mt-1 mb-1 border border-separator rounded-md"
2567
- }, /* @__PURE__ */ React19.createElement(FieldEditor, {
2981
+ className: "col-span-full mt-1 mb-1 border border-separator rounded-md"
2982
+ }, /* @__PURE__ */ React24.createElement(FieldEditor, {
2568
2983
  readonly: readonly || schemaReadonly,
2569
2984
  registry,
2570
2985
  projection: projectionModel,
2571
2986
  field,
2572
2987
  onSave: handleClose
2573
2988
  })));
2574
- })), !readonly && !expandedField && /* @__PURE__ */ React19.createElement("div", {
2989
+ })), !readonly && !expandedField && /* @__PURE__ */ React24.createElement("div", {
2575
2990
  role: "none",
2576
2991
  className: "my-form-padding"
2577
- }, /* @__PURE__ */ React19.createElement(IconButton4, {
2992
+ }, /* @__PURE__ */ React24.createElement(IconButton4, {
2578
2993
  icon: "ph--plus--regular",
2579
- label: t("add property button label"),
2994
+ label: t("add-property-button.label"),
2580
2995
  onClick: handleAdd,
2581
2996
  disabled: viewSnapshot.projection.fields.length >= VIEW_FIELD_LIMIT,
2582
2997
  classNames: "w-full"
@@ -2584,13 +2999,13 @@ var FieldList = ({ schema, view, registry, readonly, showHeading = false, onDele
2584
2999
  };
2585
3000
  var customFields = ({ types, tags }) => ({
2586
3001
  query: ({ type, readonly, label, getValue, onValueChange }) => {
2587
- const handleChange = useCallback15((query) => onValueChange(type, query.ast), [
3002
+ const handleChange = useCallback18((query) => onValueChange(type, query.ast), [
2588
3003
  onValueChange
2589
3004
  ]);
2590
- return /* @__PURE__ */ React19.createElement(Input13.Root, null, /* @__PURE__ */ React19.createElement(FormFieldLabel, {
3005
+ return /* @__PURE__ */ React24.createElement(Input14.Root, null, /* @__PURE__ */ React24.createElement(FormFieldLabel, {
2591
3006
  readonly,
2592
3007
  label
2593
- }), /* @__PURE__ */ React19.createElement(QueryForm, {
3008
+ }), /* @__PURE__ */ React24.createElement(QueryForm, {
2594
3009
  initialQuery: getValue(),
2595
3010
  types,
2596
3011
  tags,
@@ -2609,7 +3024,9 @@ export {
2609
3024
  GeoPointField,
2610
3025
  MarkdownField,
2611
3026
  NumberField,
3027
+ ObjectForm,
2612
3028
  ObjectPicker,
3029
+ ObjectProperties,
2613
3030
  RefField,
2614
3031
  SelectField,
2615
3032
  SelectOptionField,
@@ -2619,15 +3036,18 @@ export {
2619
3036
  TupleField,
2620
3037
  ViewEditor,
2621
3038
  cellClassesForFieldType,
3039
+ createSelectField,
3040
+ detectFieldType,
2622
3041
  formatForDisplay,
2623
3042
  formatForEditing,
2624
3043
  getDefaultValue,
2625
3044
  getFormProperties,
2626
3045
  getRefProps,
3046
+ getSelectOptionsFromAst,
3047
+ omitHiddenFormFields,
2627
3048
  omitId,
2628
3049
  parseValue,
2629
3050
  pathNotUniqueError,
2630
- translations,
2631
3051
  useFormContext,
2632
3052
  useFormFieldState,
2633
3053
  useFormHandler,