@dxos/react-ui-form 0.8.4-main.b97322e → 0.8.4-main.c4373fc
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.
- package/dist/lib/browser/index.mjs +810 -594
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +810 -594
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/components/ControlSection/ControlSection.d.ts +2 -2
- package/dist/types/src/components/ControlSection/ControlSection.d.ts.map +1 -1
- package/dist/types/src/components/ControlSection/ControlSection.stories.d.ts +81 -5
- package/dist/types/src/components/ControlSection/ControlSection.stories.d.ts.map +1 -1
- package/dist/types/src/components/FieldEditor/FieldEditor.d.ts +2 -2
- package/dist/types/src/components/FieldEditor/FieldEditor.d.ts.map +1 -1
- package/dist/types/src/components/FieldEditor/FieldEditor.stories.d.ts +76 -5
- package/dist/types/src/components/FieldEditor/FieldEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/Form/ArrayField.d.ts +2 -2
- package/dist/types/src/components/Form/ArrayField.d.ts.map +1 -1
- package/dist/types/src/components/Form/Defaults.d.ts +5 -5
- package/dist/types/src/components/Form/Defaults.d.ts.map +1 -1
- package/dist/types/src/components/Form/Form.d.ts +7 -6
- package/dist/types/src/components/Form/Form.d.ts.map +1 -1
- package/dist/types/src/components/Form/Form.stories.d.ts +129 -32
- package/dist/types/src/components/Form/Form.stories.d.ts.map +1 -1
- package/dist/types/src/components/Form/FormActions.d.ts.map +1 -1
- package/dist/types/src/components/Form/FormContent.d.ts +17 -11
- package/dist/types/src/components/Form/FormContent.d.ts.map +1 -1
- package/dist/types/src/components/Form/FormContext.d.ts +3 -3
- package/dist/types/src/components/Form/FormContext.d.ts.map +1 -1
- package/dist/types/src/components/Form/Input.d.ts +5 -2
- package/dist/types/src/components/Form/Input.d.ts.map +1 -1
- package/dist/types/src/components/Form/RefField.d.ts +14 -5
- package/dist/types/src/components/Form/RefField.d.ts.map +1 -1
- package/dist/types/src/components/Form/custom/GeoPointInput.d.ts +1 -1
- package/dist/types/src/components/Form/custom/GeoPointInput.d.ts.map +1 -1
- package/dist/types/src/components/Form/custom/SelectOptionsInput.d.ts +1 -1
- package/dist/types/src/components/Form/custom/SelectOptionsInput.d.ts.map +1 -1
- package/dist/types/src/components/Form/custom/SelectOptionsInput.stories.d.ts +76 -4
- package/dist/types/src/components/Form/custom/SelectOptionsInput.stories.d.ts.map +1 -1
- package/dist/types/src/components/Form/custom/TupleInput.d.ts +1 -1
- package/dist/types/src/components/Form/factory.d.ts +1 -1
- package/dist/types/src/components/Form/factory.d.ts.map +1 -1
- package/dist/types/src/components/ObjectPicker/ObjectPicker.d.ts +41 -0
- package/dist/types/src/components/ObjectPicker/ObjectPicker.d.ts.map +1 -0
- package/dist/types/src/components/ObjectPicker/ObjectPicker.stories.d.ts +81 -0
- package/dist/types/src/components/ObjectPicker/ObjectPicker.stories.d.ts.map +1 -0
- package/dist/types/src/components/ObjectPicker/index.d.ts +2 -0
- package/dist/types/src/components/ObjectPicker/index.d.ts.map +1 -0
- package/dist/types/src/components/ViewEditor/ViewEditor.d.ts +16 -4
- package/dist/types/src/components/ViewEditor/ViewEditor.d.ts.map +1 -1
- package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts +79 -7
- package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +1 -1
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/components/testing.d.ts +6 -3
- package/dist/types/src/components/testing.d.ts.map +1 -1
- package/dist/types/src/hooks/useForm.d.ts +3 -3
- package/dist/types/src/hooks/useForm.d.ts.map +1 -1
- package/dist/types/src/hooks/useQueryRefOptions.d.ts +8 -3
- package/dist/types/src/hooks/useQueryRefOptions.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +11 -5
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/util/field.d.ts +1 -1
- package/dist/types/src/util/field.d.ts.map +1 -1
- package/dist/types/src/util/formatting.d.ts +1 -1
- package/dist/types/src/util/formatting.d.ts.map +1 -1
- package/dist/types/src/util/refs.d.ts +1 -1
- package/dist/types/src/util/refs.d.ts.map +1 -1
- package/dist/types/src/util/schema.d.ts +1 -1
- package/dist/types/src/util/schema.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +41 -36
- package/src/components/ControlSection/ControlSection.stories.tsx +11 -14
- package/src/components/ControlSection/ControlSection.tsx +26 -12
- package/src/components/FieldEditor/FieldEditor.stories.tsx +14 -14
- package/src/components/FieldEditor/FieldEditor.test.tsx +3 -2
- package/src/components/FieldEditor/FieldEditor.tsx +26 -18
- package/src/components/Form/ArrayField.tsx +12 -11
- package/src/components/Form/Defaults.tsx +22 -20
- package/src/components/Form/Form.stories.tsx +135 -99
- package/src/components/Form/Form.tsx +26 -15
- package/src/components/Form/FormActions.tsx +2 -1
- package/src/components/Form/FormContent.tsx +121 -39
- package/src/components/Form/FormContext.tsx +8 -8
- package/src/components/Form/Input.tsx +5 -2
- package/src/components/Form/RefField.tsx +97 -41
- package/src/components/Form/custom/GeoPointInput.tsx +29 -21
- package/src/components/Form/custom/SelectOptionsInput.stories.tsx +11 -11
- package/src/components/Form/custom/SelectOptionsInput.tsx +30 -31
- package/src/components/Form/custom/TupleInput.tsx +2 -2
- package/src/components/Form/factory.tsx +2 -2
- package/src/components/ObjectPicker/ObjectPicker.stories.tsx +207 -0
- package/src/components/ObjectPicker/ObjectPicker.tsx +161 -0
- package/src/components/ObjectPicker/index.ts +5 -0
- package/src/components/ViewEditor/ViewEditor.stories.tsx +102 -44
- package/src/components/ViewEditor/ViewEditor.test.tsx +9 -12
- package/src/components/ViewEditor/ViewEditor.tsx +328 -220
- package/src/components/index.ts +1 -2
- package/src/components/testing.tsx +15 -9
- package/src/hooks/useForm.ts +8 -4
- package/src/hooks/useQueryRefOptions.ts +9 -3
- package/src/hooks/useRefQueryLookupHandler.ts +1 -1
- package/src/translations.ts +13 -6
- package/src/util/field.ts +9 -19
- package/src/util/formatting.ts +1 -1
- package/src/util/refs.ts +2 -2
- package/src/util/schema.ts +2 -4
- package/dist/types/src/components/deprecated/Form.d.ts +0 -15
- package/dist/types/src/components/deprecated/Form.d.ts.map +0 -1
- package/dist/types/src/components/deprecated/Form.stories.d.ts +0 -13
- package/dist/types/src/components/deprecated/Form.stories.d.ts.map +0 -1
- package/dist/types/src/components/deprecated/FormInput.d.ts +0 -16
- package/dist/types/src/components/deprecated/FormInput.d.ts.map +0 -1
- package/dist/types/src/components/deprecated/index.d.ts +0 -2
- package/dist/types/src/components/deprecated/index.d.ts.map +0 -1
- package/src/components/deprecated/Form.stories.tsx +0 -62
- package/src/components/deprecated/Form.tsx +0 -119
- package/src/components/deprecated/FormInput.tsx +0 -71
- package/src/components/deprecated/index.ts +0 -5
|
@@ -2,24 +2,24 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import '@dxos-theme';
|
|
6
|
-
|
|
7
5
|
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
8
|
-
import
|
|
9
|
-
import React, { useCallback, useMemo,
|
|
6
|
+
import * as Schema from 'effect/Schema';
|
|
7
|
+
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
10
8
|
|
|
11
|
-
import { Obj, Type } from '@dxos/echo';
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
9
|
+
import { DXN, Filter, Obj, Query, Type } from '@dxos/echo';
|
|
10
|
+
import { type EchoSchema, Format, toJsonSchema } from '@dxos/echo/internal';
|
|
11
|
+
import { QueryBuilder } from '@dxos/echo-query';
|
|
12
|
+
import { useSpace } from '@dxos/react-client/echo';
|
|
14
13
|
import { withClientProvider } from '@dxos/react-client/testing';
|
|
15
14
|
import { useAsyncEffect } from '@dxos/react-ui';
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
15
|
+
import { withTheme } from '@dxos/react-ui/testing';
|
|
16
|
+
import { type DataType, type ProjectionModel, createView, getTypenameFromQuery } from '@dxos/schema';
|
|
18
17
|
|
|
19
|
-
import { ViewEditor, type ViewEditorProps } from './ViewEditor';
|
|
20
18
|
import { translations } from '../../translations';
|
|
21
19
|
import { TestLayout, TestPanel, VIEW_EDITOR_DEBUG_SYMBOL } from '../testing';
|
|
22
20
|
|
|
21
|
+
import { ViewEditor, type ViewEditorProps } from './ViewEditor';
|
|
22
|
+
|
|
23
23
|
// Type definition for debug objects exposed to tests.
|
|
24
24
|
export type ViewEditorDebugObjects = {
|
|
25
25
|
schema: EchoSchema;
|
|
@@ -27,68 +27,113 @@ export type ViewEditorDebugObjects = {
|
|
|
27
27
|
projection: ProjectionModel;
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
-
type StoryProps = Pick<ViewEditorProps, 'readonly'>;
|
|
30
|
+
type StoryProps = Pick<ViewEditorProps, 'readonly' | 'mode'>;
|
|
31
31
|
|
|
32
32
|
const DefaultStory = (props: StoryProps) => {
|
|
33
33
|
const space = useSpace();
|
|
34
34
|
const [schema, setSchema] = useState<EchoSchema>();
|
|
35
35
|
const [view, setView] = useState<DataType.View>();
|
|
36
|
-
const
|
|
36
|
+
const projectionRef = useRef<ProjectionModel>(null);
|
|
37
|
+
|
|
37
38
|
useAsyncEffect(async () => {
|
|
38
39
|
if (space) {
|
|
39
|
-
|
|
40
|
+
const TestSchema = Schema.Struct({
|
|
40
41
|
name: Schema.String,
|
|
41
42
|
email: Format.Email,
|
|
42
43
|
salary: Format.Currency(),
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
}).pipe(
|
|
45
|
+
Type.Obj({
|
|
46
|
+
typename: 'example.com/type/Test',
|
|
47
|
+
version: '0.1.0',
|
|
48
|
+
}),
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
const AlternateSchema = Schema.Struct({
|
|
52
|
+
title: Schema.String,
|
|
53
|
+
description: Schema.String,
|
|
54
|
+
completed: Schema.Boolean,
|
|
55
|
+
}).pipe(
|
|
56
|
+
Type.Obj({
|
|
57
|
+
typename: 'example.com/type/Alternate',
|
|
58
|
+
version: '0.1.0',
|
|
59
|
+
}),
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
const [testSchema] = await space.db.schemaRegistry.register([TestSchema, AlternateSchema]);
|
|
46
63
|
const view = createView({
|
|
47
64
|
name: 'Test',
|
|
48
|
-
|
|
65
|
+
query: Query.select(Filter.type(TestSchema)),
|
|
66
|
+
queryString: 'Query.select(Filter.type(TestSchema))',
|
|
49
67
|
jsonSchema: toJsonSchema(TestSchema),
|
|
50
68
|
presentation: Obj.make(Type.Expando, {}),
|
|
51
69
|
});
|
|
52
|
-
const projection = new ProjectionModel(schema.jsonSchema, view.projection);
|
|
53
70
|
|
|
54
|
-
setSchema(
|
|
71
|
+
setSchema(testSchema);
|
|
55
72
|
setView(view);
|
|
56
|
-
setProjection(projection);
|
|
57
73
|
}
|
|
58
74
|
}, [space]);
|
|
59
75
|
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
(newTypename: string) => {
|
|
64
|
-
if (!schema) {
|
|
76
|
+
const updateViewQuery = useCallback(
|
|
77
|
+
async (queryString: string, target?: string) => {
|
|
78
|
+
if (!schema || !view || !space) {
|
|
65
79
|
return;
|
|
66
80
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
view.query.
|
|
81
|
+
|
|
82
|
+
if (props.mode === 'query') {
|
|
83
|
+
view.query.string = queryString;
|
|
84
|
+
|
|
85
|
+
const builder = new QueryBuilder();
|
|
86
|
+
const filter = builder.build(queryString) ?? Filter.nothing();
|
|
87
|
+
const queue = target && DXN.tryParse(target) ? target : undefined;
|
|
88
|
+
const newQuery = queue ? Query.select(filter).options({ queues: [queue] }) : Query.select(filter);
|
|
89
|
+
view.query.ast = newQuery.ast;
|
|
90
|
+
|
|
91
|
+
const typename = getTypenameFromQuery(newQuery.ast);
|
|
92
|
+
const [newSchema] = await space.db.schemaRegistry.query({ typename }).run();
|
|
93
|
+
if (!newSchema) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const newView = createView({
|
|
98
|
+
query: newQuery,
|
|
99
|
+
jsonSchema: newSchema.jsonSchema,
|
|
100
|
+
presentation: Obj.make(Type.Expando, {}),
|
|
101
|
+
});
|
|
102
|
+
view.projection = Obj.getSnapshot(newView).projection;
|
|
103
|
+
setSchema(() => newSchema);
|
|
104
|
+
} else {
|
|
105
|
+
const typename = queryString;
|
|
106
|
+
const newQuery = Query.select(Filter.typename(typename));
|
|
107
|
+
view.query.ast = newQuery.ast;
|
|
108
|
+
schema.updateTypename(typename);
|
|
70
109
|
}
|
|
71
|
-
schema.updateTypename(newTypename);
|
|
72
110
|
},
|
|
73
|
-
[
|
|
111
|
+
[view, schema],
|
|
74
112
|
);
|
|
75
113
|
|
|
76
|
-
const handleDelete = useCallback(
|
|
114
|
+
const handleDelete = useCallback(
|
|
115
|
+
(property: string) => projectionRef.current?.deleteFieldProjection(property),
|
|
116
|
+
[projectionRef],
|
|
117
|
+
);
|
|
77
118
|
|
|
78
119
|
// Expose objects on window for test access.
|
|
79
120
|
useEffect(() => {
|
|
80
|
-
if (typeof window !== 'undefined' && schema && view &&
|
|
81
|
-
(window as any)[VIEW_EDITOR_DEBUG_SYMBOL] = {
|
|
121
|
+
if (typeof window !== 'undefined' && schema && view && projectionRef.current) {
|
|
122
|
+
(window as any)[VIEW_EDITOR_DEBUG_SYMBOL] = {
|
|
123
|
+
schema,
|
|
124
|
+
view,
|
|
125
|
+
projection: projectionRef.current,
|
|
126
|
+
} satisfies ViewEditorDebugObjects;
|
|
82
127
|
}
|
|
83
|
-
}, [schema, view
|
|
128
|
+
}, [schema, view]);
|
|
84
129
|
|
|
85
130
|
// NOTE(ZaymonFC): This looks awkward but it resolves an infinite parsing issue with sb.
|
|
86
131
|
const json = useMemo(
|
|
87
|
-
() => JSON.parse(JSON.stringify({ schema, view, projection })),
|
|
88
|
-
[JSON.stringify(schema), JSON.stringify(view)
|
|
132
|
+
() => JSON.parse(JSON.stringify({ schema, view, projection: projectionRef.current })),
|
|
133
|
+
[JSON.stringify(schema), JSON.stringify(view)],
|
|
89
134
|
);
|
|
90
135
|
|
|
91
|
-
if (!schema || !view
|
|
136
|
+
if (!schema || !view) {
|
|
92
137
|
return <div />;
|
|
93
138
|
}
|
|
94
139
|
|
|
@@ -96,11 +141,13 @@ const DefaultStory = (props: StoryProps) => {
|
|
|
96
141
|
<TestLayout json={json}>
|
|
97
142
|
<TestPanel>
|
|
98
143
|
<ViewEditor
|
|
144
|
+
ref={projectionRef}
|
|
99
145
|
schema={schema}
|
|
100
146
|
view={view}
|
|
101
147
|
registry={space?.db.schemaRegistry}
|
|
148
|
+
mode={props.mode}
|
|
102
149
|
readonly={props.readonly}
|
|
103
|
-
|
|
150
|
+
onQueryChanged={updateViewQuery}
|
|
104
151
|
onDelete={handleDelete}
|
|
105
152
|
/>
|
|
106
153
|
</TestPanel>
|
|
@@ -108,19 +155,30 @@ const DefaultStory = (props: StoryProps) => {
|
|
|
108
155
|
);
|
|
109
156
|
};
|
|
110
157
|
|
|
111
|
-
const meta
|
|
158
|
+
const meta = {
|
|
112
159
|
title: 'ui/react-ui-form/ViewEditor',
|
|
113
160
|
render: DefaultStory,
|
|
114
|
-
decorators: [withClientProvider({ createSpace: true }),
|
|
115
|
-
parameters: {
|
|
116
|
-
|
|
161
|
+
decorators: [withClientProvider({ createSpace: true }), withTheme],
|
|
162
|
+
parameters: {
|
|
163
|
+
layout: 'fullscreen',
|
|
164
|
+
translations,
|
|
165
|
+
},
|
|
166
|
+
} satisfies Meta<typeof DefaultStory>;
|
|
117
167
|
|
|
118
168
|
export default meta;
|
|
119
169
|
|
|
120
|
-
type Story = StoryObj<
|
|
170
|
+
type Story = StoryObj<typeof meta>;
|
|
121
171
|
|
|
122
172
|
export const Default: Story = {};
|
|
123
173
|
|
|
124
174
|
export const Readonly: Story = {
|
|
125
|
-
args: {
|
|
175
|
+
args: {
|
|
176
|
+
readonly: true,
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
export const QueryMode: Story = {
|
|
181
|
+
args: {
|
|
182
|
+
mode: 'query',
|
|
183
|
+
},
|
|
126
184
|
};
|
|
@@ -3,15 +3,16 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { composeStories } from '@storybook/react';
|
|
6
|
-
import {
|
|
6
|
+
import { cleanup, fireEvent, screen, waitFor } from '@testing-library/react';
|
|
7
7
|
import { afterEach, describe, expect, test } from 'vitest';
|
|
8
8
|
|
|
9
|
-
import { EchoSchema, isInstanceOf } from '@dxos/echo
|
|
9
|
+
import { EchoSchema, isInstanceOf } from '@dxos/echo/internal';
|
|
10
10
|
import { DataType, ProjectionModel } from '@dxos/schema';
|
|
11
11
|
|
|
12
|
+
import { VIEW_EDITOR_DEBUG_SYMBOL } from '../testing';
|
|
13
|
+
|
|
12
14
|
import * as stories from './ViewEditor.stories';
|
|
13
15
|
import { type ViewEditorDebugObjects } from './ViewEditor.stories';
|
|
14
|
-
import { VIEW_EDITOR_DEBUG_SYMBOL } from '../testing';
|
|
15
16
|
|
|
16
17
|
const { Default } = composeStories(stories);
|
|
17
18
|
|
|
@@ -41,7 +42,7 @@ describe('ViewEditor', () => {
|
|
|
41
42
|
test('renders view editor', async () => {
|
|
42
43
|
await Default.run();
|
|
43
44
|
await waitForViewEditor();
|
|
44
|
-
expect(screen.getByText('
|
|
45
|
+
expect(screen.getByText('Record type')).toBeInTheDocument();
|
|
45
46
|
});
|
|
46
47
|
|
|
47
48
|
test('change property name', async () => {
|
|
@@ -140,7 +141,7 @@ describe('ViewEditor', () => {
|
|
|
140
141
|
// Find the delete button for the 'name' property.
|
|
141
142
|
const nameProperty = screen.getByText('name');
|
|
142
143
|
const propertyRow = nameProperty.closest('[role="listitem"]');
|
|
143
|
-
const deleteButton = propertyRow?.querySelector('
|
|
144
|
+
const deleteButton = propertyRow?.querySelector('[data-testid="field.delete"]');
|
|
144
145
|
|
|
145
146
|
if (!deleteButton) {
|
|
146
147
|
throw new Error('Delete button not found');
|
|
@@ -188,19 +189,15 @@ describe('ViewEditor', () => {
|
|
|
188
189
|
// Access the live objects directly from window using symbol.
|
|
189
190
|
const debugObjects = getViewEditorDebugObjects();
|
|
190
191
|
|
|
191
|
-
// Check that hiddenFields is non-empty.
|
|
192
|
-
expect(debugObjects.view.projection.hiddenFields).toBeDefined();
|
|
193
|
-
expect(debugObjects.view.projection.hiddenFields!.length).toBeGreaterThan(0);
|
|
194
|
-
|
|
195
192
|
// Click the show button
|
|
196
193
|
fireEvent.click(screen.getByTestId('show-field-button'));
|
|
197
194
|
|
|
198
195
|
// Wait for the data to update and check that hiddenFields is empty.
|
|
199
196
|
await waitFor(() => {
|
|
200
|
-
expect(debugObjects.view.projection.
|
|
197
|
+
expect(debugObjects.view.projection.fields.filter(({ visible }) => visible === false)!.length).toBe(0);
|
|
201
198
|
});
|
|
202
199
|
|
|
203
200
|
// Also verify that the field is back in the visible fields list.
|
|
204
|
-
expect(debugObjects.view.projection.fields.length).toBeGreaterThan(0);
|
|
201
|
+
expect(debugObjects.view.projection.fields.filter(({ visible }) => visible !== false).length).toBeGreaterThan(0);
|
|
205
202
|
});
|
|
206
|
-
});
|
|
203
|
+
}, 30_000);
|