@dxos/react-ui-form 0.8.4-main.5ea62a8 → 0.8.4-main.66e292d

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 (91) hide show
  1. package/dist/lib/browser/index.mjs +534 -348
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node-esm/index.mjs +534 -348
  5. package/dist/lib/node-esm/index.mjs.map +4 -4
  6. package/dist/lib/node-esm/meta.json +1 -1
  7. package/dist/types/src/components/ControlSection/ControlSection.stories.d.ts +8 -7
  8. package/dist/types/src/components/ControlSection/ControlSection.stories.d.ts.map +1 -1
  9. package/dist/types/src/components/FieldEditor/FieldEditor.d.ts.map +1 -1
  10. package/dist/types/src/components/FieldEditor/FieldEditor.stories.d.ts +8 -7
  11. package/dist/types/src/components/FieldEditor/FieldEditor.stories.d.ts.map +1 -1
  12. package/dist/types/src/components/Form/ArrayField.d.ts.map +1 -1
  13. package/dist/types/src/components/Form/Form.d.ts +6 -5
  14. package/dist/types/src/components/Form/Form.d.ts.map +1 -1
  15. package/dist/types/src/components/Form/Form.stories.d.ts +52 -37
  16. package/dist/types/src/components/Form/Form.stories.d.ts.map +1 -1
  17. package/dist/types/src/components/Form/FormActions.d.ts.map +1 -1
  18. package/dist/types/src/components/Form/FormContent.d.ts +5 -5
  19. package/dist/types/src/components/Form/FormContent.d.ts.map +1 -1
  20. package/dist/types/src/components/Form/FormContext.d.ts +4 -4
  21. package/dist/types/src/components/Form/FormContext.d.ts.map +1 -1
  22. package/dist/types/src/components/Form/Input.d.ts +2 -2
  23. package/dist/types/src/components/Form/Input.d.ts.map +1 -1
  24. package/dist/types/src/components/Form/RefField.d.ts +10 -6
  25. package/dist/types/src/components/Form/RefField.d.ts.map +1 -1
  26. package/dist/types/src/components/Form/custom/SelectOptionsInput.stories.d.ts +8 -7
  27. package/dist/types/src/components/Form/custom/SelectOptionsInput.stories.d.ts.map +1 -1
  28. package/dist/types/src/components/Form/factory.d.ts +2 -2
  29. package/dist/types/src/components/Form/factory.d.ts.map +1 -1
  30. package/dist/types/src/components/ObjectPicker/ObjectPicker.d.ts +41 -0
  31. package/dist/types/src/components/ObjectPicker/ObjectPicker.d.ts.map +1 -0
  32. package/dist/types/src/components/ObjectPicker/ObjectPicker.stories.d.ts +82 -0
  33. package/dist/types/src/components/ObjectPicker/ObjectPicker.stories.d.ts.map +1 -0
  34. package/dist/types/src/components/ObjectPicker/index.d.ts +2 -0
  35. package/dist/types/src/components/ObjectPicker/index.d.ts.map +1 -0
  36. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts +20 -6
  37. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts.map +1 -1
  38. package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts +13 -11
  39. package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts.map +1 -1
  40. package/dist/types/src/components/index.d.ts +1 -0
  41. package/dist/types/src/components/index.d.ts.map +1 -1
  42. package/dist/types/src/hooks/useForm.d.ts +5 -5
  43. package/dist/types/src/hooks/useForm.d.ts.map +1 -1
  44. package/dist/types/src/hooks/useQueryRefOptions.d.ts +9 -3
  45. package/dist/types/src/hooks/useQueryRefOptions.d.ts.map +1 -1
  46. package/dist/types/src/hooks/useRefQueryLookupHandler.d.ts.map +1 -1
  47. package/dist/types/src/translations.d.ts +7 -6
  48. package/dist/types/src/translations.d.ts.map +1 -1
  49. package/dist/types/src/util/field.d.ts +3 -3
  50. package/dist/types/src/util/field.d.ts.map +1 -1
  51. package/dist/types/src/util/formatting.d.ts +2 -2
  52. package/dist/types/src/util/formatting.d.ts.map +1 -1
  53. package/dist/types/src/util/refs.d.ts +1 -1
  54. package/dist/types/src/util/refs.d.ts.map +1 -1
  55. package/dist/types/src/util/schema.d.ts +1 -1
  56. package/dist/types/src/util/schema.d.ts.map +1 -1
  57. package/dist/types/tsconfig.tsbuildinfo +1 -1
  58. package/package.json +40 -37
  59. package/src/components/ControlSection/ControlSection.stories.tsx +4 -5
  60. package/src/components/ControlSection/ControlSection.tsx +1 -1
  61. package/src/components/FieldEditor/FieldEditor.stories.tsx +8 -7
  62. package/src/components/FieldEditor/FieldEditor.tsx +7 -4
  63. package/src/components/Form/ArrayField.tsx +7 -4
  64. package/src/components/Form/Defaults.tsx +1 -1
  65. package/src/components/Form/Form.stories.tsx +52 -52
  66. package/src/components/Form/Form.tsx +19 -9
  67. package/src/components/Form/FormActions.tsx +7 -2
  68. package/src/components/Form/FormContent.tsx +83 -23
  69. package/src/components/Form/FormContext.tsx +6 -6
  70. package/src/components/Form/Input.tsx +2 -2
  71. package/src/components/Form/RefField.tsx +50 -66
  72. package/src/components/Form/custom/GeoPointInput.tsx +1 -1
  73. package/src/components/Form/custom/SelectOptionsInput.stories.tsx +5 -6
  74. package/src/components/Form/custom/SelectOptionsInput.tsx +2 -2
  75. package/src/components/Form/factory.tsx +7 -4
  76. package/src/components/ObjectPicker/ObjectPicker.stories.tsx +207 -0
  77. package/src/components/ObjectPicker/ObjectPicker.tsx +161 -0
  78. package/src/components/ObjectPicker/index.ts +5 -0
  79. package/src/components/ViewEditor/ViewEditor.stories.tsx +112 -49
  80. package/src/components/ViewEditor/ViewEditor.test.tsx +6 -5
  81. package/src/components/ViewEditor/ViewEditor.tsx +277 -208
  82. package/src/components/index.ts +1 -0
  83. package/src/components/testing.tsx +2 -2
  84. package/src/hooks/useForm.ts +11 -8
  85. package/src/hooks/useQueryRefOptions.ts +15 -6
  86. package/src/hooks/useRefQueryLookupHandler.ts +5 -5
  87. package/src/translations.ts +7 -6
  88. package/src/util/field.ts +25 -25
  89. package/src/util/formatting.ts +22 -22
  90. package/src/util/refs.ts +7 -7
  91. package/src/util/schema.ts +2 -4
@@ -2,26 +2,35 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { useEffect, useState } from 'react';
5
+ import { useCallback, useEffect, useState } from 'react';
6
6
 
7
- import { type TypeAnnotation } from '@dxos/echo-schema';
7
+ import { type TypeAnnotation } from '@dxos/echo/internal';
8
8
  import { type DXN } from '@dxos/keys';
9
9
  import { log } from '@dxos/log';
10
- import { type TagPickerItemData } from '@dxos/react-ui-tag-picker';
10
+ import { type Palette } from '@dxos/react-ui-types';
11
11
  import { type MaybePromise } from '@dxos/util';
12
12
 
13
13
  export type RefOption = { dxn: DXN; label?: string };
14
14
  export type QueryRefOptions = (type: TypeAnnotation) => MaybePromise<RefOption[]>;
15
15
 
16
+ export type QueryTag = {
17
+ id: string;
18
+ label: string;
19
+ hue?: Palette;
20
+ };
21
+
16
22
  type UseQueryRefOptionsProps = { refTypeInfo: TypeAnnotation | undefined; onQueryRefOptions?: QueryRefOptions };
17
23
 
18
24
  /**
19
25
  * Hook to query reference options based on type information.
20
26
  * Used internally within forms to fetch and format reference options for reference fields.
21
27
  */
28
+ // TODO(wittjosiah): This should be a reactive query so that the options are always up to date.
22
29
  export const useQueryRefOptions = ({ refTypeInfo, onQueryRefOptions }: UseQueryRefOptionsProps) => {
23
- const [options, setOptions] = useState<TagPickerItemData[]>([]);
30
+ const [options, setOptions] = useState<QueryTag[]>([]);
24
31
  const [loading, setLoading] = useState(false);
32
+ const [state, setState] = useState({});
33
+ const update = useCallback(() => setState({}), []);
25
34
 
26
35
  useEffect(() => {
27
36
  if (!refTypeInfo || !onQueryRefOptions) {
@@ -47,7 +56,7 @@ export const useQueryRefOptions = ({ refTypeInfo, onQueryRefOptions }: UseQueryR
47
56
  };
48
57
 
49
58
  void fetchOptions();
50
- }, [refTypeInfo, onQueryRefOptions]);
59
+ }, [refTypeInfo, onQueryRefOptions, state]);
51
60
 
52
- return { options, loading };
61
+ return { options, update, loading };
53
62
  };
@@ -4,7 +4,8 @@
4
4
 
5
5
  import { useCallback } from 'react';
6
6
 
7
- import { type TypeAnnotation, getObjectDXN } from '@dxos/echo-schema';
7
+ import { Obj } from '@dxos/echo';
8
+ import { type TypeAnnotation } from '@dxos/echo/internal';
8
9
  import { Filter, type Space } from '@dxos/react-client/echo';
9
10
  import { isNonNullable } from '@dxos/util';
10
11
 
@@ -18,18 +19,17 @@ export const useRefQueryLookupHandler = ({ space }: UseRefQueryLookupProps): Que
18
19
  if (!space) {
19
20
  return [];
20
21
  }
22
+
21
23
  const query = space.db.query(Filter.typename(typeInfo.typename));
22
24
  const { objects } = await query.run();
23
-
24
25
  return objects
25
26
  .map((object) => {
26
- const dxn = getObjectDXN(object);
27
+ const dxn = Obj.getDXN(object);
27
28
  if (!dxn) {
28
29
  return undefined;
29
30
  }
30
31
 
31
- // TODO(Zaymon): Better fallback object names?
32
- const item = { dxn, label: object?.name ?? object?.id ?? '' };
32
+ const item = { dxn, label: Obj.getLabel(object) ?? object?.id ?? '' };
33
33
  return item;
34
34
  })
35
35
  .filter(isNonNullable);
@@ -15,7 +15,7 @@ export const translations = [
15
15
  'empty readonly ref field label': '(none)',
16
16
 
17
17
  // TODO(burdon): Standardize field/property.
18
- 'button add property': 'Add property',
18
+ 'add property button label': 'Add property',
19
19
  'field property label': 'Property',
20
20
  'field property placeholder': 'Property name',
21
21
  'field format label': 'Type',
@@ -28,12 +28,13 @@ export const translations = [
28
28
  'show field label': 'Show field',
29
29
  'hide field label': 'Hide field',
30
30
  'delete field label': 'Delete field',
31
+ 'ref field combobox input placeholder': 'Search…',
31
32
  'ref field placeholder_one': 'Select…',
32
33
  'ref field placeholder_other': 'Select items…',
33
34
 
34
35
  // TODO(burdon): Factor out?
35
- 'button cancel': 'Cancel',
36
- 'button save': 'Save',
36
+ 'cancel button label': 'Cancel',
37
+ 'save button label': 'Save',
37
38
 
38
39
  // FormatEnum
39
40
  'format boolean': 'Boolean',
@@ -48,7 +49,7 @@ export const translations = [
48
49
  'format hostname': 'Hostname',
49
50
  'format integer': 'Integer',
50
51
  'format json': 'JSON',
51
- 'format latlng': 'Geopoint',
52
+ 'format lnglat': 'Geopoint',
52
53
  'format markdown': 'Markdown',
53
54
  'format percent': 'Percent',
54
55
  'format ref': 'Reference',
@@ -77,9 +78,9 @@ export const translations = [
77
78
  'select option add': 'Add option',
78
79
 
79
80
  // System schema message.
80
- 'system schema title': 'System record type',
81
+ 'system schema title': 'System type',
81
82
  'system schema description':
82
- 'This is a system record type and cannot be modified, though the view can still be configured.',
83
+ 'This is a system type and cannot be modified, though the view can still be configured.',
83
84
  },
84
85
  },
85
86
  },
package/src/util/field.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { FormatEnum, GeoLocation, TypeEnum } from '@dxos/echo-schema';
5
+ import { Format, GeoLocation, TypeEnum } from '@dxos/echo/internal';
6
6
  import { type ValidationError } from '@dxos/schema';
7
7
 
8
8
  /**
@@ -13,7 +13,7 @@ import { type ValidationError } from '@dxos/schema';
13
13
  */
14
14
  export type ParseProps = {
15
15
  type?: TypeEnum;
16
- format?: FormatEnum;
16
+ format?: Format.TypeFormat;
17
17
  value: any;
18
18
  };
19
19
 
@@ -57,31 +57,31 @@ export const parseValue = ({ type, format, value }: ParseProps) => {
57
57
  }
58
58
 
59
59
  switch (format) {
60
- case FormatEnum.Boolean:
60
+ case Format.TypeFormat.Boolean:
61
61
  return parseScalar(TypeEnum.Boolean);
62
62
 
63
- case FormatEnum.Number:
64
- case FormatEnum.Percent:
65
- case FormatEnum.Currency:
63
+ case Format.TypeFormat.Number:
64
+ case Format.TypeFormat.Percent:
65
+ case Format.TypeFormat.Currency:
66
66
  return parseScalar(TypeEnum.Number);
67
67
 
68
- case FormatEnum.String:
69
- case FormatEnum.Markdown: {
68
+ case Format.TypeFormat.String:
69
+ case Format.TypeFormat.Markdown: {
70
70
  return parseScalar(TypeEnum.String);
71
71
  }
72
72
 
73
- case FormatEnum.Ref:
74
- throw new Error(`unexpected format: ${FormatEnum.Ref}`);
73
+ case Format.TypeFormat.Ref:
74
+ throw new Error(`unexpected format: ${Format.TypeFormat.Ref}`);
75
75
 
76
- case FormatEnum.DateTime:
77
- case FormatEnum.Date:
78
- case FormatEnum.Time:
79
- case FormatEnum.Timestamp: {
76
+ case Format.TypeFormat.DateTime:
77
+ case Format.TypeFormat.Date:
78
+ case Format.TypeFormat.Time:
79
+ case Format.TypeFormat.Timestamp: {
80
80
  const date = new Date(value as string | number);
81
81
  return isNaN(date.getTime()) ? null : date;
82
82
  }
83
83
 
84
- case FormatEnum.GeoPoint: {
84
+ case Format.TypeFormat.GeoPoint: {
85
85
  // Parse string in format "lat,long" to GeoPoint [longitude, latitude].
86
86
  if (typeof value === 'string') {
87
87
  // Only keep digits, decimal points, minus signs, and commas.
@@ -108,23 +108,23 @@ export const parseValue = ({ type, format, value }: ParseProps) => {
108
108
  // TODO(burdon): Type and format.
109
109
  export type CellClassesForFieldTypeProps = {
110
110
  type?: TypeEnum;
111
- format?: FormatEnum;
111
+ format?: Format.TypeFormat;
112
112
  };
113
113
 
114
114
  export const cellClassesForFieldType = ({ type, format }: CellClassesForFieldTypeProps): string[] | undefined => {
115
115
  switch (format || type) {
116
- case FormatEnum.Markdown:
116
+ case Format.TypeFormat.Markdown:
117
117
  return undefined;
118
- case FormatEnum.Time:
119
- case FormatEnum.Timestamp:
120
- case FormatEnum.DateTime:
121
- case FormatEnum.Date:
122
- case FormatEnum.Duration:
118
+ case Format.TypeFormat.Time:
119
+ case Format.TypeFormat.Timestamp:
120
+ case Format.TypeFormat.DateTime:
121
+ case Format.TypeFormat.Date:
122
+ case Format.TypeFormat.Duration:
123
123
  return ['font-mono', 'text-right'];
124
- case FormatEnum.Currency:
124
+ case Format.TypeFormat.Currency:
125
125
  return ['text-right'];
126
- case FormatEnum.JSON:
127
- case FormatEnum.DID:
126
+ case Format.TypeFormat.JSON:
127
+ case Format.TypeFormat.DID:
128
128
  return ['font-mono'];
129
129
  case TypeEnum.Number:
130
130
  case TypeEnum.Boolean:
@@ -4,11 +4,11 @@
4
4
 
5
5
  import { format as formatDate } from 'date-fns/format';
6
6
 
7
- import { FormatEnum, GeoLocation, TypeEnum } from '@dxos/echo-schema';
7
+ import { Format, GeoLocation, TypeEnum } from '@dxos/echo/internal';
8
8
 
9
9
  type ValueFormatProps = {
10
10
  type: TypeEnum;
11
- format?: FormatEnum | undefined;
11
+ format?: Format.TypeFormat | undefined;
12
12
  value: any;
13
13
  locale?: string | undefined;
14
14
  };
@@ -41,20 +41,20 @@ export const formatForDisplay = ({ type, format, value, locale = undefined }: Va
41
41
  }
42
42
 
43
43
  switch (format) {
44
- case FormatEnum.Boolean: {
44
+ case Format.TypeFormat.Boolean: {
45
45
  return formatScalar(TypeEnum.Boolean);
46
46
  }
47
- case FormatEnum.Number: {
47
+ case Format.TypeFormat.Number: {
48
48
  return formatScalar(TypeEnum.Number);
49
49
  }
50
- case FormatEnum.String:
51
- case FormatEnum.Ref: {
50
+ case Format.TypeFormat.String:
51
+ case Format.TypeFormat.Ref: {
52
52
  return formatScalar(TypeEnum.String);
53
53
  }
54
- case FormatEnum.Percent: {
54
+ case Format.TypeFormat.Percent: {
55
55
  return `${(value as number) * 100}%`;
56
56
  }
57
- case FormatEnum.Currency: {
57
+ case Format.TypeFormat.Currency: {
58
58
  // TODO(burdon): Get from property annotation.
59
59
  return (value as number).toLocaleString(locale, {
60
60
  style: 'currency',
@@ -63,28 +63,28 @@ export const formatForDisplay = ({ type, format, value, locale = undefined }: Va
63
63
  maximumFractionDigits: 2,
64
64
  });
65
65
  }
66
- case FormatEnum.Date: {
66
+ case Format.TypeFormat.Date: {
67
67
  try {
68
68
  return formatDate(new Date(value as number), 'yyyy-MM-dd');
69
69
  } catch (error) {
70
70
  return 'Invalid Date';
71
71
  }
72
72
  }
73
- case FormatEnum.Time: {
73
+ case Format.TypeFormat.Time: {
74
74
  try {
75
75
  return formatDate(new Date(value as number), 'HH:mm:ss');
76
76
  } catch (error) {
77
77
  return 'Invalid Time';
78
78
  }
79
79
  }
80
- case FormatEnum.DateTime: {
80
+ case Format.TypeFormat.DateTime: {
81
81
  try {
82
82
  return formatDate(new Date(value as number), 'yyyy-MM-dd HH:mm:ss');
83
83
  } catch (error) {
84
84
  return 'Invalid DateTime';
85
85
  }
86
86
  }
87
- case FormatEnum.GeoPoint: {
87
+ case Format.TypeFormat.GeoPoint: {
88
88
  if (value === null || value === undefined) {
89
89
  return '';
90
90
  }
@@ -125,31 +125,31 @@ export const formatForEditing = ({ type, format, value, locale = undefined }: Va
125
125
  }
126
126
 
127
127
  switch (format) {
128
- case FormatEnum.Boolean:
129
- case FormatEnum.Number:
130
- case FormatEnum.String:
131
- case FormatEnum.Ref: {
128
+ case Format.TypeFormat.Boolean:
129
+ case Format.TypeFormat.Number:
130
+ case Format.TypeFormat.String:
131
+ case Format.TypeFormat.Ref: {
132
132
  return formatScalar(type);
133
133
  }
134
- case FormatEnum.Percent: {
134
+ case Format.TypeFormat.Percent: {
135
135
  return String(value * 100);
136
136
  }
137
- case FormatEnum.Currency: {
137
+ case Format.TypeFormat.Currency: {
138
138
  return String(value);
139
139
  }
140
- case FormatEnum.DateTime: {
140
+ case Format.TypeFormat.DateTime: {
141
141
  const date = new Date(value as number);
142
142
  return date.toISOString();
143
143
  }
144
- case FormatEnum.Date: {
144
+ case Format.TypeFormat.Date: {
145
145
  const date = new Date(value as number);
146
146
  return date.toISOString().split('T')[0];
147
147
  }
148
- case FormatEnum.Time: {
148
+ case Format.TypeFormat.Time: {
149
149
  const date = new Date(value as number);
150
150
  return date.toISOString().split('T')[1].split('.')[0];
151
151
  }
152
- case FormatEnum.GeoPoint: {
152
+ case Format.TypeFormat.GeoPoint: {
153
153
  // Handle null or undefined
154
154
  if (value === null || value === undefined) {
155
155
  return '';
package/src/util/refs.ts CHANGED
@@ -2,9 +2,9 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { type SchemaAST } from 'effect';
5
+ import type * as SchemaAST from 'effect/SchemaAST';
6
6
 
7
- import { FormatEnum, ReferenceAnnotationId } from '@dxos/echo-schema';
7
+ import { Format, ReferenceAnnotationId } from '@dxos/echo/internal';
8
8
  import { findAnnotation } from '@dxos/effect';
9
9
  import { type SchemaProperty } from '@dxos/schema';
10
10
 
@@ -18,11 +18,6 @@ type RefProps = {
18
18
  export const getRefProps = (property: SchemaProperty<any>): RefProps | undefined => {
19
19
  const { ast, format, array } = property;
20
20
 
21
- // Direct reference.
22
- if (format === FormatEnum.Ref) {
23
- return { ast, isArray: false };
24
- }
25
-
26
21
  // Array of references.
27
22
  if (array) {
28
23
  const elementType = findArrayElementType(ast);
@@ -34,5 +29,10 @@ export const getRefProps = (property: SchemaProperty<any>): RefProps | undefined
34
29
  }
35
30
  }
36
31
 
32
+ // Direct reference.
33
+ if (format === Format.TypeFormat.Ref) {
34
+ return { ast, isArray: false };
35
+ }
36
+
37
37
  return undefined;
38
38
  };
@@ -2,13 +2,11 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { SchemaAST } from 'effect';
5
+ import * as SchemaAST from 'effect/SchemaAST';
6
6
 
7
7
  import { findNode } from '@dxos/effect';
8
8
 
9
9
  export const findArrayElementType = (ast: SchemaAST.AST) => {
10
10
  const tupleType = findNode(ast, SchemaAST.isTupleType);
11
- const elementType = (tupleType as SchemaAST.TupleType | undefined)?.rest[0]?.type;
12
-
13
- return elementType;
11
+ return (tupleType as SchemaAST.TupleType | undefined)?.rest[0]?.type;
14
12
  };