@dxos/react-ui-form 0.8.2-main.fbd8ed0 → 0.8.2-staging.4d6ad0f
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 +1440 -1244
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +1426 -1230
- package/dist/lib/node/index.cjs.map +3 -3
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +1440 -1244
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/components/ControlSection/ControlSection.d.ts +1 -1
- package/dist/types/src/components/ControlSection/ControlSection.d.ts.map +1 -1
- package/dist/types/src/components/FieldEditor/FieldEditor.d.ts.map +1 -1
- package/dist/types/src/components/FieldEditor/FieldEditor.test.d.ts +2 -0
- package/dist/types/src/components/FieldEditor/FieldEditor.test.d.ts.map +1 -0
- package/dist/types/src/components/Form/ArrayField.d.ts.map +1 -1
- package/dist/types/src/components/Form/Defaults.d.ts +4 -4
- package/dist/types/src/components/Form/Defaults.d.ts.map +1 -1
- package/dist/types/src/components/Form/Form.d.ts.map +1 -1
- package/dist/types/src/components/Form/Form.stories.d.ts +1 -2
- package/dist/types/src/components/Form/Form.stories.d.ts.map +1 -1
- package/dist/types/src/components/Form/FormActions.d.ts +1 -1
- package/dist/types/src/components/Form/FormActions.d.ts.map +1 -1
- package/dist/types/src/components/Form/FormContent.d.ts.map +1 -1
- package/dist/types/src/components/Form/FormContext.d.ts.map +1 -1
- package/dist/types/src/components/Form/RefField.d.ts.map +1 -1
- package/dist/types/src/components/ViewEditor/ViewEditor.d.ts.map +1 -1
- package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts +5 -3
- package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/testing.d.ts.map +1 -1
- package/dist/types/src/hooks/useRefQueryLookupHandler.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +5 -0
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/vitest-setup.d.ts +2 -0
- package/dist/types/src/vitest-setup.d.ts.map +1 -0
- package/package.json +27 -25
- package/src/components/ControlSection/ControlSection.tsx +2 -2
- package/src/components/FieldEditor/FieldEditor.test.tsx +49 -0
- package/src/components/FieldEditor/FieldEditor.tsx +3 -2
- package/src/components/Form/ArrayField.tsx +51 -34
- package/src/components/Form/Defaults.tsx +74 -48
- package/src/components/Form/Form.stories.tsx +77 -101
- package/src/components/Form/Form.tsx +1 -2
- package/src/components/Form/FormActions.tsx +15 -18
- package/src/components/Form/FormContent.tsx +24 -29
- package/src/components/Form/FormContext.tsx +11 -7
- package/src/components/Form/Input.tsx +1 -1
- package/src/components/Form/RefField.tsx +30 -10
- package/src/components/ViewEditor/ViewEditor.stories.tsx +14 -5
- package/src/components/ViewEditor/ViewEditor.tsx +51 -24
- package/src/components/testing.tsx +5 -9
- package/src/hooks/useRefQueryLookupHandler.ts +1 -3
- package/src/translations.ts +9 -2
- package/src/vitest-setup.ts +11 -0
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { Schema
|
|
5
|
+
import { Schema } from 'effect';
|
|
6
6
|
import React, { useCallback, useMemo, useState } from 'react';
|
|
7
7
|
|
|
8
8
|
import { type SchemaRegistry } from '@dxos/echo-db';
|
|
9
|
-
import { Format, type JsonProp, isMutable, toJsonSchema } from '@dxos/echo-schema';
|
|
9
|
+
import { EchoSchema, Format, type JsonProp, isMutable, toJsonSchema } from '@dxos/echo-schema';
|
|
10
10
|
import { invariant } from '@dxos/invariant';
|
|
11
|
-
import { IconButton, type ThemedClassName, useTranslation } from '@dxos/react-ui';
|
|
11
|
+
import { Icon, IconButton, Message, type ThemedClassName, useTranslation } from '@dxos/react-ui';
|
|
12
12
|
import { List } from '@dxos/react-ui-list';
|
|
13
13
|
import { ghostHover, inputTextLabel, mx } from '@dxos/react-ui-theme';
|
|
14
14
|
import { FieldSchema, type FieldType, type ViewType, ViewProjection, VIEW_FIELD_LIMIT } from '@dxos/schema';
|
|
@@ -21,10 +21,10 @@ const grid = 'grid grid-cols-[32px_1fr_32px] min-bs-[2.5rem]';
|
|
|
21
21
|
|
|
22
22
|
const ViewMetaSchema = Schema.Struct({
|
|
23
23
|
name: Schema.String.annotations({
|
|
24
|
-
|
|
24
|
+
title: 'View',
|
|
25
25
|
}),
|
|
26
26
|
typename: Format.URL.annotations({
|
|
27
|
-
|
|
27
|
+
title: 'Typename',
|
|
28
28
|
}),
|
|
29
29
|
}).pipe(Schema.mutable);
|
|
30
30
|
|
|
@@ -54,7 +54,11 @@ export const ViewEditor = ({
|
|
|
54
54
|
onDelete,
|
|
55
55
|
}: ViewEditorProps) => {
|
|
56
56
|
const { t } = useTranslation(translationKey);
|
|
57
|
-
const projection = useMemo(() =>
|
|
57
|
+
const projection = useMemo(() => {
|
|
58
|
+
// Use reactive and mutable version of json schema when schema is mutable.
|
|
59
|
+
const jsonSchema = schema instanceof EchoSchema ? schema.jsonSchema : toJsonSchema(schema);
|
|
60
|
+
return new ViewProjection(jsonSchema, view);
|
|
61
|
+
}, [schema, view]);
|
|
58
62
|
const [field, setField] = useState<FieldType>();
|
|
59
63
|
const immutable = readonly || !isMutable(schema);
|
|
60
64
|
|
|
@@ -68,9 +72,15 @@ export const ViewEditor = ({
|
|
|
68
72
|
};
|
|
69
73
|
}, [view]);
|
|
70
74
|
|
|
71
|
-
const handleSelect = useCallback(
|
|
72
|
-
|
|
73
|
-
|
|
75
|
+
const handleSelect = useCallback(
|
|
76
|
+
(field: FieldType) => {
|
|
77
|
+
if (immutable) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
setField((f) => (f === field ? undefined : field));
|
|
81
|
+
},
|
|
82
|
+
[immutable],
|
|
83
|
+
);
|
|
74
84
|
|
|
75
85
|
// TODO(burdon): Check if mutable; variant of useCallback that return undefined if readonly?
|
|
76
86
|
|
|
@@ -88,12 +98,12 @@ export const ViewEditor = ({
|
|
|
88
98
|
view.name = name;
|
|
89
99
|
}
|
|
90
100
|
|
|
91
|
-
if (view.query.typename !== typename) {
|
|
101
|
+
if (view.query.typename !== typename && !immutable) {
|
|
92
102
|
onTypenameChanged?.(typename);
|
|
93
103
|
}
|
|
94
104
|
});
|
|
95
105
|
},
|
|
96
|
-
[schema, view, onTypenameChanged],
|
|
106
|
+
[schema, view, onTypenameChanged, immutable],
|
|
97
107
|
);
|
|
98
108
|
|
|
99
109
|
const handleDelete = useCallback(
|
|
@@ -141,16 +151,28 @@ export const ViewEditor = ({
|
|
|
141
151
|
);
|
|
142
152
|
|
|
143
153
|
return (
|
|
144
|
-
<div role='none' className={mx('
|
|
145
|
-
<
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
+
<div role='none' className={mx('overflow-y-auto', classNames)}>
|
|
155
|
+
<div role='none' className='p-2'>
|
|
156
|
+
<div role='none' className='mbe-2'>
|
|
157
|
+
{immutable && (
|
|
158
|
+
<Message.Root valence='neutral' className='rounded'>
|
|
159
|
+
<Message.Title>
|
|
160
|
+
<Icon icon='ph--info--regular' size={5} classNames='inline' /> {t('system schema title')}
|
|
161
|
+
</Message.Title>
|
|
162
|
+
<Message.Body>{t('system schema description')}</Message.Body>
|
|
163
|
+
</Message.Root>
|
|
164
|
+
)}
|
|
165
|
+
</div>
|
|
166
|
+
<Form<ViewMetaType>
|
|
167
|
+
autoSave
|
|
168
|
+
schema={ViewMetaSchema}
|
|
169
|
+
values={viewValues}
|
|
170
|
+
onSave={handleUpdate}
|
|
171
|
+
classNames='min-bs-0 overflow-y-auto'
|
|
172
|
+
/>
|
|
173
|
+
</div>
|
|
174
|
+
|
|
175
|
+
<div role='none' className='min-bs-0 overflow-y-auto'>
|
|
154
176
|
{/* TODO(burdon): Clean up common form ux. */}
|
|
155
177
|
<div role='none' className='p-2'>
|
|
156
178
|
<label className={mx(inputTextLabel)}>{t('fields label')}</label>
|
|
@@ -173,7 +195,11 @@ export const ViewEditor = ({
|
|
|
173
195
|
|
|
174
196
|
<div role='list' className='flex flex-col w-full'>
|
|
175
197
|
{fields?.map((field) => (
|
|
176
|
-
<List.Item<FieldType>
|
|
198
|
+
<List.Item<FieldType>
|
|
199
|
+
key={field.id}
|
|
200
|
+
item={field}
|
|
201
|
+
classNames={mx(grid, ghostHover, !immutable && 'cursor-pointer')}
|
|
202
|
+
>
|
|
177
203
|
<List.ItemDragHandle />
|
|
178
204
|
<List.ItemTitle onClick={() => handleSelect(field)}>{field.path}</List.ItemTitle>
|
|
179
205
|
<div className='flex items-center gap-2 -ml-4'>
|
|
@@ -214,7 +240,7 @@ export const ViewEditor = ({
|
|
|
214
240
|
<List.Item<string>
|
|
215
241
|
key={property}
|
|
216
242
|
item={property}
|
|
217
|
-
classNames={mx(grid, ghostHover, 'cursor-pointer')}
|
|
243
|
+
classNames={mx(grid, ghostHover, !immutable && 'cursor-pointer')}
|
|
218
244
|
>
|
|
219
245
|
<div />
|
|
220
246
|
<List.ItemTitle>{property}</List.ItemTitle>
|
|
@@ -240,13 +266,14 @@ export const ViewEditor = ({
|
|
|
240
266
|
)}
|
|
241
267
|
|
|
242
268
|
{!readonly && !field && (
|
|
243
|
-
<div className='
|
|
269
|
+
<div role='none' className='p-2'>
|
|
244
270
|
<IconButton
|
|
245
271
|
icon='ph--plus--regular'
|
|
246
272
|
label={t('button add property')}
|
|
247
273
|
onClick={immutable ? undefined : handleAdd}
|
|
248
274
|
// TODO(burdon): Show field limit in ux (not tooltip).
|
|
249
275
|
disabled={view.fields.length >= VIEW_FIELD_LIMIT}
|
|
276
|
+
classNames='flex is-full'
|
|
250
277
|
/>
|
|
251
278
|
</div>
|
|
252
279
|
)}
|
|
@@ -5,20 +5,16 @@
|
|
|
5
5
|
import React, { type PropsWithChildren } from 'react';
|
|
6
6
|
|
|
7
7
|
import { type ThemedClassName } from '@dxos/react-ui';
|
|
8
|
-
import {
|
|
8
|
+
import { JsonFilter } from '@dxos/react-ui-syntax-highlighter';
|
|
9
9
|
import { mx } from '@dxos/react-ui-theme';
|
|
10
10
|
|
|
11
11
|
export const TestPanel = ({ classNames, children }: ThemedClassName<PropsWithChildren>) => (
|
|
12
|
-
<div className='
|
|
13
|
-
<div className={mx('flex flex-col border border-separator rounded w-[300px]', classNames)}>{children}</div>
|
|
14
|
-
</div>
|
|
12
|
+
<div className={mx('w-full max-w-[30rem] border border-separator p-2 rounded', classNames)}>{children}</div>
|
|
15
13
|
);
|
|
16
14
|
|
|
17
15
|
export const TestLayout = ({ classNames, json, children }: ThemedClassName<PropsWithChildren<{ json?: any }>>) => (
|
|
18
|
-
<div className='w-full h-full grid grid-cols-
|
|
19
|
-
<div className={mx('
|
|
20
|
-
<
|
|
21
|
-
{JSON.stringify(json, null, 2)}
|
|
22
|
-
</SyntaxHighlighter>
|
|
16
|
+
<div className='w-full h-full grid grid-cols-[1fr_1fr]'>
|
|
17
|
+
<div className={mx('m-2 justify-center overflow-y-auto', classNames)}>{children}</div>
|
|
18
|
+
<JsonFilter data={json} classNames='w-full text-xs' testId='debug' />
|
|
23
19
|
</div>
|
|
24
20
|
);
|
|
@@ -13,7 +13,7 @@ import { type QueryRefOptions } from './useQueryRefOptions';
|
|
|
13
13
|
type UseRefQueryLookupProps = { space?: Space };
|
|
14
14
|
|
|
15
15
|
export const useRefQueryLookupHandler = ({ space }: UseRefQueryLookupProps): QueryRefOptions => {
|
|
16
|
-
|
|
16
|
+
return useCallback(
|
|
17
17
|
async (typeInfo: TypeAnnotation) => {
|
|
18
18
|
if (!space) {
|
|
19
19
|
return [];
|
|
@@ -36,6 +36,4 @@ export const useRefQueryLookupHandler = ({ space }: UseRefQueryLookupProps): Que
|
|
|
36
36
|
},
|
|
37
37
|
[space],
|
|
38
38
|
);
|
|
39
|
-
|
|
40
|
-
return handleRefQueryLookup;
|
|
41
39
|
};
|
package/src/translations.ts
CHANGED
|
@@ -10,6 +10,7 @@ export default [
|
|
|
10
10
|
[translationKey]: {
|
|
11
11
|
'fields label': 'Fields',
|
|
12
12
|
'hidden fields label': 'Hidden Fields',
|
|
13
|
+
'empty readonly ref field label': '(none)',
|
|
13
14
|
|
|
14
15
|
// TODO(burdon): Standardize field/property.
|
|
15
16
|
'button add property': 'Add property',
|
|
@@ -20,6 +21,8 @@ export default [
|
|
|
20
21
|
'add field': 'Add field',
|
|
21
22
|
'delete field': 'Delete field',
|
|
22
23
|
'field limit reached': 'Maximum number of fields reached',
|
|
24
|
+
'boolean input true value': 'Yes',
|
|
25
|
+
'boolean input false value': 'No',
|
|
23
26
|
|
|
24
27
|
// TODO(burdon): Factor out?
|
|
25
28
|
'button cancel': 'Cancel',
|
|
@@ -52,16 +55,20 @@ export default [
|
|
|
52
55
|
'format uri': 'URI',
|
|
53
56
|
'format uuid': 'UUID',
|
|
54
57
|
|
|
55
|
-
// Placeholders
|
|
58
|
+
// Placeholders.
|
|
56
59
|
'placeholder latitude': 'Latitude',
|
|
57
60
|
'placeholder longitude': 'Longitude',
|
|
58
61
|
|
|
59
|
-
// SelectOptionsInput
|
|
62
|
+
// SelectOptionsInput.
|
|
60
63
|
'select option label': 'Label',
|
|
61
64
|
'select option label placeholder': 'Option label',
|
|
62
65
|
'select option color': 'Color',
|
|
63
66
|
'select option delete': 'Delete',
|
|
64
67
|
'select option add': 'Add option',
|
|
68
|
+
|
|
69
|
+
// System schema message.
|
|
70
|
+
'system schema title': 'System Schema',
|
|
71
|
+
'system schema description': 'This schema is managed by the system and cannot be modified.',
|
|
65
72
|
},
|
|
66
73
|
},
|
|
67
74
|
},
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
// https://github.com/testing-library/jest-dom#with-vitest
|
|
6
|
+
import '@testing-library/jest-dom/vitest';
|
|
7
|
+
|
|
8
|
+
// https://github.com/jsdom/jsdom/issues/3368#issuecomment-1396749033
|
|
9
|
+
import ResizeObserver from 'resize-observer-polyfill';
|
|
10
|
+
|
|
11
|
+
global.ResizeObserver = ResizeObserver;
|