@dxos/react-ui-form 0.8.4-main.b97322e → 0.8.4-main.dedc0f3

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 (94) hide show
  1. package/dist/lib/browser/index.mjs +601 -528
  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 +601 -528
  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.d.ts +2 -2
  8. package/dist/types/src/components/ControlSection/ControlSection.d.ts.map +1 -1
  9. package/dist/types/src/components/ControlSection/ControlSection.stories.d.ts +79 -4
  10. package/dist/types/src/components/ControlSection/ControlSection.stories.d.ts.map +1 -1
  11. package/dist/types/src/components/FieldEditor/FieldEditor.d.ts +2 -2
  12. package/dist/types/src/components/FieldEditor/FieldEditor.d.ts.map +1 -1
  13. package/dist/types/src/components/FieldEditor/FieldEditor.stories.d.ts +74 -4
  14. package/dist/types/src/components/FieldEditor/FieldEditor.stories.d.ts.map +1 -1
  15. package/dist/types/src/components/Form/ArrayField.d.ts +2 -2
  16. package/dist/types/src/components/Form/ArrayField.d.ts.map +1 -1
  17. package/dist/types/src/components/Form/Defaults.d.ts +5 -5
  18. package/dist/types/src/components/Form/Defaults.d.ts.map +1 -1
  19. package/dist/types/src/components/Form/Form.d.ts +5 -4
  20. package/dist/types/src/components/Form/Form.d.ts.map +1 -1
  21. package/dist/types/src/components/Form/Form.stories.d.ts +126 -30
  22. package/dist/types/src/components/Form/Form.stories.d.ts.map +1 -1
  23. package/dist/types/src/components/Form/FormActions.d.ts.map +1 -1
  24. package/dist/types/src/components/Form/FormContent.d.ts +16 -10
  25. package/dist/types/src/components/Form/FormContent.d.ts.map +1 -1
  26. package/dist/types/src/components/Form/FormContext.d.ts +1 -1
  27. package/dist/types/src/components/Form/FormContext.d.ts.map +1 -1
  28. package/dist/types/src/components/Form/Input.d.ts +4 -1
  29. package/dist/types/src/components/Form/Input.d.ts.map +1 -1
  30. package/dist/types/src/components/Form/RefField.d.ts +10 -4
  31. package/dist/types/src/components/Form/RefField.d.ts.map +1 -1
  32. package/dist/types/src/components/Form/custom/GeoPointInput.d.ts +1 -1
  33. package/dist/types/src/components/Form/custom/GeoPointInput.d.ts.map +1 -1
  34. package/dist/types/src/components/Form/custom/SelectOptionsInput.d.ts +1 -1
  35. package/dist/types/src/components/Form/custom/SelectOptionsInput.d.ts.map +1 -1
  36. package/dist/types/src/components/Form/custom/SelectOptionsInput.stories.d.ts +74 -3
  37. package/dist/types/src/components/Form/custom/SelectOptionsInput.stories.d.ts.map +1 -1
  38. package/dist/types/src/components/Form/custom/TupleInput.d.ts +1 -1
  39. package/dist/types/src/components/Form/factory.d.ts.map +1 -1
  40. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts +3 -2
  41. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts.map +1 -1
  42. package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts +76 -5
  43. package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts.map +1 -1
  44. package/dist/types/src/components/index.d.ts +0 -1
  45. package/dist/types/src/components/index.d.ts.map +1 -1
  46. package/dist/types/src/components/testing.d.ts +6 -3
  47. package/dist/types/src/components/testing.d.ts.map +1 -1
  48. package/dist/types/src/hooks/useForm.d.ts +1 -1
  49. package/dist/types/src/hooks/useForm.d.ts.map +1 -1
  50. package/dist/types/src/translations.d.ts +9 -4
  51. package/dist/types/src/translations.d.ts.map +1 -1
  52. package/dist/types/src/util/field.d.ts.map +1 -1
  53. package/dist/types/tsconfig.tsbuildinfo +1 -1
  54. package/package.json +35 -30
  55. package/src/components/ControlSection/ControlSection.stories.tsx +8 -10
  56. package/src/components/ControlSection/ControlSection.tsx +26 -12
  57. package/src/components/FieldEditor/FieldEditor.stories.tsx +8 -9
  58. package/src/components/FieldEditor/FieldEditor.test.tsx +3 -2
  59. package/src/components/FieldEditor/FieldEditor.tsx +22 -17
  60. package/src/components/Form/ArrayField.tsx +8 -8
  61. package/src/components/Form/Defaults.tsx +22 -20
  62. package/src/components/Form/Form.stories.tsx +129 -93
  63. package/src/components/Form/Form.tsx +16 -12
  64. package/src/components/Form/FormActions.tsx +2 -1
  65. package/src/components/Form/FormContent.tsx +96 -34
  66. package/src/components/Form/FormContext.tsx +5 -5
  67. package/src/components/Form/Input.tsx +4 -1
  68. package/src/components/Form/RefField.tsx +126 -40
  69. package/src/components/Form/custom/GeoPointInput.tsx +29 -21
  70. package/src/components/Form/custom/SelectOptionsInput.stories.tsx +7 -6
  71. package/src/components/Form/custom/SelectOptionsInput.tsx +29 -30
  72. package/src/components/Form/custom/TupleInput.tsx +2 -2
  73. package/src/components/Form/factory.tsx +1 -1
  74. package/src/components/ViewEditor/ViewEditor.stories.tsx +50 -23
  75. package/src/components/ViewEditor/ViewEditor.test.tsx +7 -10
  76. package/src/components/ViewEditor/ViewEditor.tsx +151 -132
  77. package/src/components/index.ts +0 -2
  78. package/src/components/testing.tsx +15 -9
  79. package/src/hooks/useForm.ts +5 -3
  80. package/src/hooks/useRefQueryLookupHandler.ts +1 -1
  81. package/src/translations.ts +11 -5
  82. package/src/util/field.ts +8 -18
  83. package/dist/types/src/components/deprecated/Form.d.ts +0 -15
  84. package/dist/types/src/components/deprecated/Form.d.ts.map +0 -1
  85. package/dist/types/src/components/deprecated/Form.stories.d.ts +0 -13
  86. package/dist/types/src/components/deprecated/Form.stories.d.ts.map +0 -1
  87. package/dist/types/src/components/deprecated/FormInput.d.ts +0 -16
  88. package/dist/types/src/components/deprecated/FormInput.d.ts.map +0 -1
  89. package/dist/types/src/components/deprecated/index.d.ts +0 -2
  90. package/dist/types/src/components/deprecated/index.d.ts.map +0 -1
  91. package/src/components/deprecated/Form.stories.tsx +0 -62
  92. package/src/components/deprecated/Form.tsx +0 -119
  93. package/src/components/deprecated/FormInput.tsx +0 -71
  94. package/src/components/deprecated/index.ts +0 -5
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/react-ui-form",
3
- "version": "0.8.4-main.b97322e",
3
+ "version": "0.8.4-main.dedc0f3",
4
4
  "description": "Data components.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -9,6 +9,7 @@
9
9
  "type": "module",
10
10
  "exports": {
11
11
  ".": {
12
+ "source": "./src/index.ts",
12
13
  "types": "./dist/types/src/index.d.ts",
13
14
  "browser": "./dist/lib/browser/index.mjs",
14
15
  "node": "./dist/lib/node-esm/index.mjs"
@@ -25,52 +26,56 @@
25
26
  "dependencies": {
26
27
  "@atlaskit/pragmatic-drag-and-drop": "^1.4.0",
27
28
  "@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.0.3",
29
+ "@fluentui/react-tabster": "^9.24.2",
28
30
  "@preact-signals/safe-react": "^0.9.0",
29
31
  "@radix-ui/react-context": "1.1.1",
30
32
  "date-fns": "^3.3.1",
31
33
  "jsonpath": "^1.1.1",
32
- "@dxos/async": "0.8.4-main.b97322e",
33
- "@dxos/debug": "0.8.4-main.b97322e",
34
- "@dxos/echo-schema": "0.8.4-main.b97322e",
35
- "@dxos/echo": "0.8.4-main.b97322e",
36
- "@dxos/echo-db": "0.8.4-main.b97322e",
37
- "@dxos/effect": "0.8.4-main.b97322e",
38
- "@dxos/invariant": "0.8.4-main.b97322e",
39
- "@dxos/keys": "0.8.4-main.b97322e",
40
- "@dxos/lit-ui": "0.8.4-main.b97322e",
41
- "@dxos/log": "0.8.4-main.b97322e",
42
- "@dxos/react-client": "0.8.4-main.b97322e",
43
- "@dxos/live-object": "0.8.4-main.b97322e",
44
- "@dxos/react-ui-list": "0.8.4-main.b97322e",
45
- "@dxos/react-ui-stack": "0.8.4-main.b97322e",
46
- "@dxos/react-ui-pickers": "0.8.4-main.b97322e",
47
- "@dxos/react-ui-types": "0.8.4-main.b97322e",
48
- "@dxos/react-ui-tag-picker": "0.8.4-main.b97322e",
49
- "@dxos/schema": "0.8.4-main.b97322e",
50
- "@dxos/util": "0.8.4-main.b97322e"
34
+ "@dxos/async": "0.8.4-main.dedc0f3",
35
+ "@dxos/echo": "0.8.4-main.dedc0f3",
36
+ "@dxos/debug": "0.8.4-main.dedc0f3",
37
+ "@dxos/echo-db": "0.8.4-main.dedc0f3",
38
+ "@dxos/echo-schema": "0.8.4-main.dedc0f3",
39
+ "@dxos/effect": "0.8.4-main.dedc0f3",
40
+ "@dxos/keys": "0.8.4-main.dedc0f3",
41
+ "@dxos/lit-ui": "0.8.4-main.dedc0f3",
42
+ "@dxos/live-object": "0.8.4-main.dedc0f3",
43
+ "@dxos/log": "0.8.4-main.dedc0f3",
44
+ "@dxos/react-client": "0.8.4-main.dedc0f3",
45
+ "@dxos/invariant": "0.8.4-main.dedc0f3",
46
+ "@dxos/react-ui-editor": "0.8.4-main.dedc0f3",
47
+ "@dxos/react-ui-components": "0.8.4-main.dedc0f3",
48
+ "@dxos/react-ui-searchlist": "0.8.4-main.dedc0f3",
49
+ "@dxos/react-ui-stack": "0.8.4-main.dedc0f3",
50
+ "@dxos/react-ui-tag-picker": "0.8.4-main.dedc0f3",
51
+ "@dxos/react-ui-types": "0.8.4-main.dedc0f3",
52
+ "@dxos/schema": "0.8.4-main.dedc0f3",
53
+ "@dxos/react-ui-pickers": "0.8.4-main.dedc0f3",
54
+ "@dxos/react-ui-list": "0.8.4-main.dedc0f3",
55
+ "@dxos/util": "0.8.4-main.dedc0f3"
51
56
  },
52
57
  "devDependencies": {
53
58
  "@types/jsonpath": "^0.2.4",
54
59
  "@types/react": "~18.2.0",
55
60
  "@types/react-dom": "~18.2.0",
56
- "effect": "3.17.0",
61
+ "effect": "3.17.7",
57
62
  "fast-check": "^3.19.0",
58
63
  "react": "~18.2.0",
59
64
  "react-dom": "~18.2.0",
60
- "vite": "5.4.7",
61
- "@dxos/echo-signals": "0.8.4-main.b97322e",
62
- "@dxos/random": "0.8.4-main.b97322e",
63
- "@dxos/react-ui": "0.8.4-main.b97322e",
64
- "@dxos/react-ui-syntax-highlighter": "0.8.4-main.b97322e",
65
- "@dxos/storybook-utils": "0.8.4-main.b97322e",
66
- "@dxos/react-ui-theme": "0.8.4-main.b97322e"
65
+ "vite": "7.1.1",
66
+ "@dxos/echo-signals": "0.8.4-main.dedc0f3",
67
+ "@dxos/random": "0.8.4-main.dedc0f3",
68
+ "@dxos/react-ui": "0.8.4-main.dedc0f3",
69
+ "@dxos/react-ui-syntax-highlighter": "0.8.4-main.dedc0f3",
70
+ "@dxos/react-ui-theme": "0.8.4-main.dedc0f3",
71
+ "@dxos/storybook-utils": "0.8.4-main.dedc0f3"
67
72
  },
68
73
  "peerDependencies": {
69
74
  "effect": "^3.13.3",
70
75
  "react": "~18.2.0",
71
76
  "react-dom": "~18.2.0",
72
- "@dxos/react-ui": "0.8.4-main.b97322e",
73
- "@dxos/react-ui-theme": "0.8.4-main.b97322e"
77
+ "@dxos/react-ui": "0.8.4-main.dedc0f3",
78
+ "@dxos/react-ui-theme": "0.8.4-main.dedc0f3"
74
79
  },
75
80
  "publishConfig": {
76
81
  "access": "public"
@@ -7,31 +7,29 @@ import '@dxos-theme';
7
7
  import { type Meta, type StoryObj } from '@storybook/react-vite';
8
8
  import React from 'react';
9
9
 
10
- import { StackItem } from '@dxos/react-ui-stack';
11
10
  import { withLayout, withTheme } from '@dxos/storybook-utils';
12
11
 
13
- import { ControlPage, ControlSection, type ControlSectionProps } from './ControlSection';
14
12
  import { translations } from '../../translations';
15
13
 
16
- const meta: Meta<ControlSectionProps> = {
14
+ import { ControlPage, ControlSection } from './ControlSection';
15
+
16
+ const meta = {
17
17
  title: 'ui/react-ui-form/ControlSection',
18
18
  component: ControlSection,
19
19
  render: (args) => (
20
- <StackItem.Content classNames='w-[40rem]'>
21
- <ControlPage>
22
- <ControlSection {...args} />
23
- </ControlPage>
24
- </StackItem.Content>
20
+ <ControlPage classNames='w-[40rem]'>
21
+ <ControlSection {...args} />
22
+ </ControlPage>
25
23
  ),
26
24
  decorators: [withLayout({ fullscreen: true, classNames: 'justify-center' }), withTheme],
27
25
  parameters: {
28
26
  translations,
29
27
  },
30
- };
28
+ } satisfies Meta<typeof ControlSection>;
31
29
 
32
30
  export default meta;
33
31
 
34
- type Story = StoryObj<ControlSectionProps>;
32
+ type Story = StoryObj<typeof meta>;
35
33
 
36
34
  export const Default: Story = {
37
35
  args: {
@@ -13,6 +13,7 @@ import {
13
13
  toLocalizedString,
14
14
  useTranslation,
15
15
  } from '@dxos/react-ui';
16
+ import { StackItem } from '@dxos/react-ui-stack';
16
17
  import { mx } from '@dxos/react-ui-theme';
17
18
 
18
19
  import { translationKey } from '../../translations';
@@ -21,9 +22,11 @@ export type ControlPageProps = ThemedClassName<ComponentPropsWithoutRef<'div'>>;
21
22
 
22
23
  export const ControlPage = ({ children, classNames, ...props }: ControlPageProps) => {
23
24
  return (
24
- <div role='none' className={mx('pli-cardSpacingInline', classNames)} {...props}>
25
- {children}
26
- </div>
25
+ <StackItem.Content classNames='block overflow-y-auto [--control-spacing:var(--dx-trimMd)]'>
26
+ <div role='none' className={mx('pli-cardSpacingInline pbe-trimLg', classNames)} {...props}>
27
+ {children}
28
+ </div>
29
+ </StackItem.Content>
27
30
  );
28
31
  };
29
32
 
@@ -59,12 +62,16 @@ export const ControlGroupButton = ({ classNames, ...props }: ButtonProps) => {
59
62
  return <Button {...props} classNames={['md:col-span-2', classNames]} />;
60
63
  };
61
64
 
62
- export type ControlGroupProps = ThemedClassName<PropsWithChildren<{}>>;
65
+ export type ControlGroupProps = ThemedClassName<PropsWithChildren>;
63
66
 
64
67
  export const ControlGroup = ({ children, classNames }: ControlGroupProps) => (
65
68
  <div
66
69
  role='none'
67
- className={mx('group container-max-width grid grid-cols-1 md:grid-cols-[1fr_min-content] gap-trimMd', classNames)}
70
+ className={mx(
71
+ 'group container-max-width grid grid-cols-1 md:grid-cols-[1fr_min-content] gap-trimMd',
72
+ '[--control-spacing:0px] [&_input]:justify-self-end [&_button]:justify-self-end',
73
+ classNames,
74
+ )}
68
75
  >
69
76
  {children}
70
77
  </div>
@@ -73,23 +80,30 @@ export const ControlGroup = ({ children, classNames }: ControlGroupProps) => (
73
80
  export const ControlFrame = ({ children }: ControlGroupProps) => (
74
81
  <div
75
82
  role='none'
76
- className='p-trimMd container-max-width grid grid-cols-1 md:grid-cols-[1fr_1fr] gap-trimSm md:gap-trimMd border border-separator rounded-md'
83
+ className={mx(
84
+ 'container-max-width grid grid-cols-1 md:grid-cols-[1fr_1fr] gap-trimSm md:gap-trimMd p-trimMd',
85
+ 'border border-separator rounded-md',
86
+ )}
77
87
  >
78
88
  {children}
79
89
  </div>
80
90
  );
81
91
 
92
+ export const controlItemClasses = mx([
93
+ 'container-max-width grid md:col-span-2 grid-cols-subgrid gap-trimSm items-center',
94
+ // TODO(burdon): Use grid gap consistently or apply margins consistently?
95
+ 'mlb-[--control-spacing] *:first:!mbs-0 *:last:!mbe-0 pli-trimMd plb-trimMd',
96
+ 'border border-separator rounded-md',
97
+ ]);
98
+
99
+ const controlItemTitleClasses = 'mbe-0 text-lg text-baseText font-normal';
100
+ const controlItemDescriptionClasses = 'mlb-trimSm md:mbe-0 text-base text-description';
101
+
82
102
  export type ControlItemProps = PropsWithChildren<{
83
103
  title: Label;
84
104
  description?: Label;
85
105
  }>;
86
106
 
87
- export const controlItemClasses =
88
- 'pli-trimMd plb-trimMd container-max-width grid md:col-span-2 grid-cols-subgrid items-center gap-trimSm border border-separator rounded-md *:first:!mbs-0 *:last:!mbe-0';
89
-
90
- const controlItemTitleClasses = 'text-lg font-normal';
91
- const controlItemDescriptionClasses = 'text-base mlb-trimSm md:mbe-0 text-description';
92
-
93
107
  export const ControlItem = ({ title, description, children }: ControlItemProps) => {
94
108
  const { t } = useTranslation(translationKey);
95
109
 
@@ -5,7 +5,7 @@
5
5
  import '@dxos-theme';
6
6
 
7
7
  import { type Meta, type StoryObj } from '@storybook/react-vite';
8
- import React, { useMemo, useEffect } from 'react';
8
+ import React, { useEffect, useMemo } from 'react';
9
9
 
10
10
  import { createEchoSchema } from '@dxos/live-object/testing';
11
11
  import { log } from '@dxos/log';
@@ -13,9 +13,10 @@ import { ProjectionModel } from '@dxos/schema';
13
13
  import { TestSchema, testView } from '@dxos/schema/testing';
14
14
  import { withLayout, withTheme } from '@dxos/storybook-utils';
15
15
 
16
- import { FieldEditor, type FieldEditorProps } from './FieldEditor';
17
16
  import { translations } from '../../translations';
18
- import { TestLayout, TestPanel, FIELD_EDITOR_DEBUG_SYMBOL } from '../testing';
17
+ import { FIELD_EDITOR_DEBUG_SYMBOL, TestLayout, TestPanel } from '../testing';
18
+
19
+ import { FieldEditor, type FieldEditorProps } from './FieldEditor';
19
20
 
20
21
  // Type definition for debug objects exposed to tests.
21
22
  export type FieldEditorDebugObjects = {
@@ -23,8 +24,6 @@ export type FieldEditorDebugObjects = {
23
24
  projection: ProjectionModel;
24
25
  };
25
26
 
26
- type StoryProps = FieldEditorProps;
27
-
28
27
  const DefaultStory = (props: FieldEditorProps) => {
29
28
  const handleComplete: FieldEditorProps['onSave'] = () => {
30
29
  log.info('onClose', { props });
@@ -55,19 +54,19 @@ const DefaultStory = (props: FieldEditorProps) => {
55
54
  );
56
55
  };
57
56
 
58
- const meta: Meta<StoryProps> = {
57
+ const meta = {
59
58
  title: 'ui/react-ui-form/FieldEditor',
60
- component: FieldEditor,
59
+ component: FieldEditor as any,
61
60
  render: DefaultStory,
62
61
  decorators: [withLayout({ fullscreen: true }), withTheme],
63
62
  parameters: {
64
63
  translations,
65
64
  },
66
- };
65
+ } satisfies Meta<typeof DefaultStory>;
67
66
 
68
67
  export default meta;
69
68
 
70
- type Story = StoryObj<StoryProps>;
69
+ type Story = StoryObj<typeof meta>;
71
70
 
72
71
  export const Default: Story = {
73
72
  args: {
@@ -3,14 +3,15 @@
3
3
  //
4
4
 
5
5
  import { composeStories } from '@storybook/react';
6
- import { screen, cleanup, fireEvent, act } from '@testing-library/react';
6
+ import { act, cleanup, fireEvent, screen } from '@testing-library/react';
7
7
  import { afterEach, describe, expect, test } from 'vitest';
8
8
 
9
9
  import { ProjectionModel } from '@dxos/schema';
10
10
 
11
+ import { FIELD_EDITOR_DEBUG_SYMBOL } from '../testing';
12
+
11
13
  import * as stories from './FieldEditor.stories';
12
14
  import { type FieldEditorDebugObjects } from './FieldEditor.stories';
13
- import { FIELD_EDITOR_DEBUG_SYMBOL } from '../testing';
14
15
 
15
16
  const { Default } = composeStories(stories);
16
17
 
@@ -5,17 +5,17 @@
5
5
  import React, { useCallback, useEffect, useMemo, useState } from 'react';
6
6
 
7
7
  import { type SchemaRegistry } from '@dxos/echo-db';
8
- import { FormatEnum, FormatEnums, formatToType, type EchoSchema } from '@dxos/echo-schema';
8
+ import { type EchoSchema, FormatEnum, FormatEnums, formatToType } from '@dxos/echo-schema';
9
9
  import { log } from '@dxos/log';
10
- import { useTranslation } from '@dxos/react-ui';
10
+ import { useAsyncEffect, useTranslation } from '@dxos/react-ui';
11
11
  import {
12
- getFormatSchema,
13
- getSchemaProperties,
14
- sortProperties,
15
12
  type FieldType,
16
- type PropertyType,
17
13
  type ProjectionModel,
14
+ type PropertyType,
18
15
  type SchemaProperty,
16
+ getFormatSchema,
17
+ getSchemaProperties,
18
+ sortProperties,
19
19
  } from '@dxos/schema';
20
20
 
21
21
  import { translationKey } from '../../translations';
@@ -27,18 +27,26 @@ export type FieldEditorProps = {
27
27
  registry?: SchemaRegistry;
28
28
  onSave: () => void;
29
29
  onCancel?: () => void;
30
- } & Pick<FormProps<any>, 'outerSpacing'>;
30
+ } & Pick<FormProps<any>, 'outerSpacing' | 'readonly'>;
31
31
 
32
32
  /**
33
33
  * Displays a Form representing the metadata for a given `Field` and `View`.
34
34
  */
35
- export const FieldEditor = ({ projection, field, registry, onSave, onCancel, outerSpacing }: FieldEditorProps) => {
35
+ export const FieldEditor = ({
36
+ readonly,
37
+ projection,
38
+ field,
39
+ registry,
40
+ onSave,
41
+ onCancel,
42
+ outerSpacing,
43
+ }: FieldEditorProps) => {
36
44
  const { t } = useTranslation(translationKey);
37
45
  const [props, setProps] = useState<PropertyType>(projection.getFieldProjection(field.id).props);
38
46
  useEffect(() => setProps(projection.getFieldProjection(field.id).props), [field, projection]);
39
47
 
40
48
  const [schemas, setSchemas] = useState<EchoSchema[]>([]);
41
- useEffect(() => {
49
+ useAsyncEffect(async () => {
42
50
  if (!registry) {
43
51
  return;
44
52
  }
@@ -46,14 +54,10 @@ export const FieldEditor = ({ projection, field, registry, onSave, onCancel, out
46
54
  const subscription = registry.query().subscribe((query) => setSchemas(query.results), { fire: true });
47
55
 
48
56
  // TODO(dmaretskyi): This shouldn't be needed.
49
- const t = setTimeout(async () => {
50
- const schemas = await registry.query().run();
51
- setSchemas(schemas);
52
- });
53
- return () => {
54
- clearTimeout(t);
55
- subscription?.();
56
- };
57
+ const schemas = await registry.query().run();
58
+ setSchemas(schemas);
59
+
60
+ return () => subscription?.();
57
61
  }, [registry]);
58
62
 
59
63
  const [referenceSchema, setReferenceSchema] = useState<EchoSchema>();
@@ -178,6 +182,7 @@ export const FieldEditor = ({ projection, field, registry, onSave, onCancel, out
178
182
  <Form<PropertyType>
179
183
  key={field.id}
180
184
  autoFocus
185
+ readonly={readonly}
181
186
  values={props}
182
187
  schema={fieldSchema}
183
188
  filter={propIsNotType}
@@ -6,26 +6,26 @@ import { SchemaAST, pipe } from 'effect';
6
6
  import { capitalize } from 'effect/String';
7
7
  import React, { Fragment, useCallback } from 'react';
8
8
 
9
- import { findNode, getDiscriminatedType, isDiscriminatedUnion, SimpleType } from '@dxos/effect';
9
+ import { SimpleType, findNode, getDiscriminatedType, isDiscriminatedUnion } from '@dxos/effect';
10
10
  import { invariant } from '@dxos/invariant';
11
11
  import { IconButton, useTranslation } from '@dxos/react-ui';
12
- import { getSchemaProperties, type SchemaProperty } from '@dxos/schema';
12
+ import { type SchemaProperty, getSchemaProperties } from '@dxos/schema';
13
13
 
14
- import { type ComponentLookup } from './Form';
15
- import { FormField } from './FormContent';
16
- import { useFormValues, type FormInputStateProps } from './FormContext';
17
- import { InputHeader, type InputComponent } from './Input';
18
14
  import { translationKey } from '../../translations';
19
15
  import { findArrayElementType } from '../../util';
20
16
 
17
+ import { type ComponentLookup } from './Form';
18
+ import { FormField, type FormFieldProps } from './FormContent';
19
+ import { type FormInputStateProps, useFormValues } from './FormContext';
20
+ import { type InputComponent, InputHeader } from './Input';
21
+
21
22
  type ArrayFieldProps = {
22
23
  property: SchemaProperty<any>;
23
- readonly?: boolean;
24
24
  inputProps: FormInputStateProps;
25
25
  path?: (string | number)[];
26
26
  Custom?: Partial<Record<string, InputComponent>>;
27
27
  lookupComponent?: ComponentLookup;
28
- };
28
+ } & Pick<FormFieldProps, 'readonly'>;
29
29
 
30
30
  export const ArrayField = ({ property, readonly, path, inputProps, Custom, lookupComponent }: ArrayFieldProps) => {
31
31
  const { t } = useTranslation(translationKey);
@@ -6,14 +6,15 @@ import React, { useCallback, useEffect, useRef } from 'react';
6
6
 
7
7
  import { Input, Select, useTranslation } from '@dxos/react-ui';
8
8
 
9
- import { type InputProps, InputHeader } from './Input';
10
9
  import { translationKey } from '../../translations';
11
10
 
11
+ import { InputHeader, type InputProps } from './Input';
12
+
12
13
  export const TextInput = ({
13
14
  type,
14
15
  label,
15
16
  inputOnly,
16
- disabled,
17
+ readonly,
17
18
  placeholder,
18
19
  getStatus,
19
20
  getValue,
@@ -22,16 +23,16 @@ export const TextInput = ({
22
23
  }: InputProps) => {
23
24
  const { status, error } = getStatus();
24
25
 
25
- return disabled && !getValue() ? null : disabled && inputOnly ? (
26
+ return readonly && !getValue() ? null : readonly === 'static' && inputOnly ? (
26
27
  <p>{getValue() ?? ''}</p>
27
28
  ) : (
28
29
  <Input.Root validationValence={status}>
29
30
  {!inputOnly && <InputHeader error={error} label={label} />}
30
- {disabled ? (
31
+ {readonly === 'static' ? (
31
32
  <p>{getValue() ?? ''}</p>
32
33
  ) : (
33
34
  <Input.TextInput
34
- disabled={disabled}
35
+ disabled={!!readonly}
35
36
  placeholder={placeholder}
36
37
  value={getValue() ?? ''}
37
38
  onChange={(event) => onValueChange(type, event.target.value)}
@@ -47,7 +48,7 @@ export const NumberInput = ({
47
48
  type,
48
49
  label,
49
50
  inputOnly,
50
- disabled,
51
+ readonly,
51
52
  placeholder,
52
53
  getStatus,
53
54
  getValue,
@@ -56,19 +57,19 @@ export const NumberInput = ({
56
57
  }: InputProps) => {
57
58
  const { status, error } = getStatus();
58
59
 
59
- return disabled && !getValue() ? null : disabled && inputOnly ? (
60
+ return readonly && !getValue() ? null : readonly === 'static' && inputOnly ? (
60
61
  <p>{getValue() ?? ''}</p>
61
62
  ) : (
62
63
  <Input.Root validationValence={status}>
63
64
  {!inputOnly && <InputHeader error={error} label={label} />}
64
- {disabled ? (
65
+ {readonly === 'static' ? (
65
66
  <p>{getValue() ?? ''}</p>
66
67
  ) : (
67
68
  <Input.TextInput
68
69
  type='number'
69
- disabled={disabled}
70
+ disabled={!!readonly}
70
71
  placeholder={placeholder}
71
- value={getValue() ?? 0}
72
+ value={getValue()}
72
73
  onChange={(event) => onValueChange(type, event.target.value)}
73
74
  onBlur={onBlur}
74
75
  />
@@ -78,7 +79,7 @@ export const NumberInput = ({
78
79
  );
79
80
  };
80
81
 
81
- export const BooleanInput = ({ type, label, inputOnly, getStatus, getValue, onValueChange, disabled }: InputProps) => {
82
+ export const BooleanInput = ({ type, label, inputOnly, getStatus, getValue, onValueChange, readonly }: InputProps) => {
82
83
  const { status, error } = getStatus();
83
84
  const checked = Boolean(getValue());
84
85
  const { t } = useTranslation(translationKey);
@@ -86,10 +87,10 @@ export const BooleanInput = ({ type, label, inputOnly, getStatus, getValue, onVa
86
87
  return (
87
88
  <Input.Root validationValence={status}>
88
89
  {!inputOnly && <InputHeader error={error} label={label} />}
89
- {disabled ? (
90
+ {readonly === 'static' ? (
90
91
  <p>{t(checked ? 'boolean input true value' : 'boolean input false value')}</p>
91
92
  ) : (
92
- <Input.Switch checked={checked} onCheckedChange={(value) => onValueChange(type, value)} />
93
+ <Input.Switch disabled={!!readonly} checked={checked} onCheckedChange={(value) => onValueChange(type, value)} />
93
94
  )}
94
95
  {inputOnly && <Input.DescriptionAndValidation>{error}</Input.DescriptionAndValidation>}
95
96
  </Input.Root>
@@ -104,7 +105,7 @@ export const SelectInput = ({
104
105
  type,
105
106
  label,
106
107
  inputOnly,
107
- disabled,
108
+ readonly,
108
109
  placeholder,
109
110
  options,
110
111
  getStatus,
@@ -116,15 +117,15 @@ export const SelectInput = ({
116
117
  const value = getValue() as string | undefined;
117
118
  const handleValueChange = useCallback((value: string | number) => onValueChange(type, value), [type, onValueChange]);
118
119
 
119
- return disabled && !value ? null : (
120
+ return readonly && !value ? null : (
120
121
  <Input.Root validationValence={status}>
121
122
  {!inputOnly && <InputHeader error={error} label={label} />}
122
- {disabled ? (
123
+ {readonly === 'static' ? (
123
124
  <p>{options?.find(({ value: optionValue }) => optionValue === value)?.label ?? String(value)}</p>
124
125
  ) : (
125
126
  <Select.Root value={value} onValueChange={handleValueChange}>
126
127
  {/* TODO(burdon): Placeholder not working? */}
127
- <Select.TriggerButton classNames='is-full' disabled={disabled} placeholder={placeholder} />
128
+ <Select.TriggerButton classNames='is-full' disabled={!!readonly} placeholder={placeholder} />
128
129
  <Select.Portal>
129
130
  <Select.Content>
130
131
  <Select.Viewport>
@@ -135,6 +136,7 @@ export const SelectInput = ({
135
136
  </Select.Option>
136
137
  ))}
137
138
  </Select.Viewport>
139
+ <Select.Arrow />
138
140
  </Select.Content>
139
141
  </Select.Portal>
140
142
  </Select.Root>
@@ -148,7 +150,7 @@ export const MarkdownInput = ({
148
150
  type,
149
151
  label,
150
152
  inputOnly,
151
- disabled,
153
+ readonly,
152
154
  placeholder,
153
155
  getStatus,
154
156
  getValue,
@@ -182,12 +184,12 @@ export const MarkdownInput = ({
182
184
  return (
183
185
  <Input.Root validationValence={status}>
184
186
  {!inputOnly && <InputHeader error={error} label={label} />}
185
- {disabled ? (
187
+ {readonly === 'static' ? (
186
188
  <p>{getValue() ?? ''}</p>
187
189
  ) : (
188
190
  <Input.TextArea
189
191
  ref={textareaRef}
190
- disabled={disabled}
192
+ disabled={!!readonly}
191
193
  placeholder={placeholder}
192
194
  value={getValue() ?? ''}
193
195
  classNames={'min-bs-auto max-h-40 overflow-auto'}