@dxos/react-ui-form 0.8.4-main.937b3ca → 0.8.4-main.9735255
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 +45 -25
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +45 -25
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/components/Form/Form.d.ts.map +1 -1
- package/dist/types/src/components/ViewEditor/ViewEditor.d.ts.map +1 -1
- package/dist/types/src/hooks/useFormHandler.d.ts.map +1 -1
- package/dist/types/src/util/echo.d.ts +6 -0
- package/dist/types/src/util/echo.d.ts.map +1 -0
- package/dist/types/src/util/index.d.ts +1 -0
- package/dist/types/src/util/index.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +31 -31
- package/src/components/Form/Form.tsx +3 -2
- package/src/components/ViewEditor/ViewEditor.tsx +21 -18
- package/src/hooks/useFormHandler.ts +7 -1
- package/src/util/echo.ts +25 -0
- package/src/util/index.ts +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/react-ui-form",
|
|
3
|
-
"version": "0.8.4-main.
|
|
3
|
+
"version": "0.8.4-main.9735255",
|
|
4
4
|
"description": "Data components.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -37,28 +37,28 @@
|
|
|
37
37
|
"date-fns": "^3.3.1",
|
|
38
38
|
"jsonpath": "^1.1.1",
|
|
39
39
|
"tabster": "^8.5.5",
|
|
40
|
-
"@dxos/async": "0.8.4-main.
|
|
41
|
-
"@dxos/debug": "0.8.4-main.
|
|
42
|
-
"@dxos/echo
|
|
43
|
-
"@dxos/
|
|
44
|
-
"@dxos/echo": "0.8.4-main.
|
|
45
|
-
"@dxos/
|
|
46
|
-
"@dxos/
|
|
47
|
-
"@dxos/
|
|
48
|
-
"@dxos/
|
|
49
|
-
"@dxos/
|
|
50
|
-
"@dxos/react-
|
|
51
|
-
"@dxos/react-ui-
|
|
52
|
-
"@dxos/react-ui-
|
|
53
|
-
"@dxos/react-ui-
|
|
54
|
-
"@dxos/react-ui-pickers": "0.8.4-main.
|
|
55
|
-
"@dxos/react-ui-
|
|
56
|
-
"@dxos/react-ui-
|
|
57
|
-
"@dxos/
|
|
58
|
-
"@dxos/
|
|
59
|
-
"@dxos/types": "0.8.4-main.
|
|
60
|
-
"@dxos/
|
|
61
|
-
"@dxos/util": "0.8.4-main.
|
|
40
|
+
"@dxos/async": "0.8.4-main.9735255",
|
|
41
|
+
"@dxos/debug": "0.8.4-main.9735255",
|
|
42
|
+
"@dxos/echo": "0.8.4-main.9735255",
|
|
43
|
+
"@dxos/echo-query": "0.8.4-main.9735255",
|
|
44
|
+
"@dxos/echo-react": "0.8.4-main.9735255",
|
|
45
|
+
"@dxos/invariant": "0.8.4-main.9735255",
|
|
46
|
+
"@dxos/keys": "0.8.4-main.9735255",
|
|
47
|
+
"@dxos/lit-ui": "0.8.4-main.9735255",
|
|
48
|
+
"@dxos/react-client": "0.8.4-main.9735255",
|
|
49
|
+
"@dxos/log": "0.8.4-main.9735255",
|
|
50
|
+
"@dxos/react-ui-components": "0.8.4-main.9735255",
|
|
51
|
+
"@dxos/react-ui-editor": "0.8.4-main.9735255",
|
|
52
|
+
"@dxos/react-ui-mosaic": "0.8.4-main.9735255",
|
|
53
|
+
"@dxos/react-ui-list": "0.8.4-main.9735255",
|
|
54
|
+
"@dxos/react-ui-pickers": "0.8.4-main.9735255",
|
|
55
|
+
"@dxos/react-ui-searchlist": "0.8.4-main.9735255",
|
|
56
|
+
"@dxos/react-ui-stack": "0.8.4-main.9735255",
|
|
57
|
+
"@dxos/schema": "0.8.4-main.9735255",
|
|
58
|
+
"@dxos/types": "0.8.4-main.9735255",
|
|
59
|
+
"@dxos/ui-types": "0.8.4-main.9735255",
|
|
60
|
+
"@dxos/effect": "0.8.4-main.9735255",
|
|
61
|
+
"@dxos/util": "0.8.4-main.9735255"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
64
|
"@types/jsonpath": "^0.2.4",
|
|
@@ -69,19 +69,19 @@
|
|
|
69
69
|
"react": "~19.2.3",
|
|
70
70
|
"react-dom": "~19.2.3",
|
|
71
71
|
"vite": "7.1.9",
|
|
72
|
-
"@dxos/random": "0.8.4-main.
|
|
73
|
-
"@dxos/react-
|
|
74
|
-
"@dxos/react-ui
|
|
75
|
-
"@dxos/
|
|
76
|
-
"@dxos/ui-theme": "0.8.4-main.
|
|
77
|
-
"@dxos/
|
|
72
|
+
"@dxos/random": "0.8.4-main.9735255",
|
|
73
|
+
"@dxos/react-client": "0.8.4-main.9735255",
|
|
74
|
+
"@dxos/react-ui": "0.8.4-main.9735255",
|
|
75
|
+
"@dxos/react-ui-syntax-highlighter": "0.8.4-main.9735255",
|
|
76
|
+
"@dxos/ui-theme": "0.8.4-main.9735255",
|
|
77
|
+
"@dxos/storybook-utils": "0.8.4-main.9735255"
|
|
78
78
|
},
|
|
79
79
|
"peerDependencies": {
|
|
80
80
|
"effect": "3.19.11",
|
|
81
81
|
"react": "~19.2.3",
|
|
82
82
|
"react-dom": "~19.2.3",
|
|
83
|
-
"@dxos/ui
|
|
84
|
-
"@dxos/
|
|
83
|
+
"@dxos/react-ui": "0.8.4-main.9735255",
|
|
84
|
+
"@dxos/ui-theme": "0.8.4-main.9735255"
|
|
85
85
|
},
|
|
86
86
|
"publishConfig": {
|
|
87
87
|
"access": "public"
|
|
@@ -8,7 +8,7 @@ import type * as SchemaAST from 'effect/SchemaAST';
|
|
|
8
8
|
import React, { type PropsWithChildren, useEffect, useMemo, useRef } from 'react';
|
|
9
9
|
|
|
10
10
|
import { type AnyProperties } from '@dxos/echo/internal';
|
|
11
|
-
import { createJsonPath, getValue as getValue
|
|
11
|
+
import { createJsonPath, getValue as getValue$ } from '@dxos/effect';
|
|
12
12
|
import { IconButton, type IconButtonProps, ScrollArea, type ThemedClassName, useTranslation } from '@dxos/react-ui';
|
|
13
13
|
import { mx } from '@dxos/ui-theme';
|
|
14
14
|
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
useKeyHandler,
|
|
21
21
|
} from '../../hooks';
|
|
22
22
|
import { translationKey } from '../../translations';
|
|
23
|
+
import { setValueEchoAware } from '../../util';
|
|
23
24
|
|
|
24
25
|
import { FormFieldLabel, type FormFieldLabelProps, type FormFieldStateProps } from './FormFieldComponent';
|
|
25
26
|
import {
|
|
@@ -93,7 +94,7 @@ const useFormValues: {
|
|
|
93
94
|
|
|
94
95
|
useEffect(() => {
|
|
95
96
|
if (!value && defaultValue) {
|
|
96
|
-
|
|
97
|
+
setValueEchoAware(values, jsonPath, defaultValue());
|
|
97
98
|
}
|
|
98
99
|
}, [value, defaultValue]);
|
|
99
100
|
|
|
@@ -12,6 +12,7 @@ import React, { forwardRef, useCallback, useContext, useImperativeHandle, useMem
|
|
|
12
12
|
import { Filter, Format, Obj, Query, QueryAST, type SchemaRegistry } from '@dxos/echo';
|
|
13
13
|
import { EchoSchema, type JsonProp, isMutable, toJsonSchema } from '@dxos/echo/internal';
|
|
14
14
|
import { invariant } from '@dxos/invariant';
|
|
15
|
+
import { useObject } from '@dxos/react-client/echo';
|
|
15
16
|
import { Callout, IconButton, Input, type ThemedClassName, useTranslation } from '@dxos/react-ui';
|
|
16
17
|
import { QueryForm, type QueryFormProps } from '@dxos/react-ui-components';
|
|
17
18
|
import { List } from '@dxos/react-ui-list';
|
|
@@ -21,7 +22,6 @@ import {
|
|
|
21
22
|
ProjectionModel,
|
|
22
23
|
VIEW_FIELD_LIMIT,
|
|
23
24
|
type View,
|
|
24
|
-
createDirectChangeCallback,
|
|
25
25
|
createEchoChangeCallback,
|
|
26
26
|
getTypenameFromQuery,
|
|
27
27
|
} from '@dxos/schema';
|
|
@@ -81,11 +81,9 @@ export const ViewEditor = forwardRef<ProjectionModel, ViewEditorProps>(
|
|
|
81
81
|
// Use reactive and mutable version of json schema when schema is mutable.
|
|
82
82
|
const jsonSchema = schema instanceof EchoSchema ? schema.jsonSchema : toJsonSchema(schema);
|
|
83
83
|
|
|
84
|
-
//
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
? createEchoChangeCallback(view, schema)
|
|
88
|
-
: createDirectChangeCallback(view.projection, jsonSchema);
|
|
84
|
+
// Always use createEchoChangeCallback since the view is ECHO-backed.
|
|
85
|
+
// Pass schema only when mutable to allow schema mutations.
|
|
86
|
+
const change = createEchoChangeCallback(view, schema instanceof EchoSchema ? schema : undefined);
|
|
89
87
|
|
|
90
88
|
const model = new ProjectionModel({
|
|
91
89
|
registry: atomRegistry,
|
|
@@ -220,15 +218,16 @@ const FieldList = ({ schema, view, registry, readonly, showHeading = false, onDe
|
|
|
220
218
|
const schemaReadonly = !isMutable(schema);
|
|
221
219
|
const { t } = useTranslation(translationKey);
|
|
222
220
|
|
|
221
|
+
// Subscribe to view changes for reactivity.
|
|
222
|
+
const [viewSnapshot] = useObject(view);
|
|
223
|
+
|
|
223
224
|
const projectionModel = useMemo(() => {
|
|
224
225
|
// Use reactive and mutable version of json schema when schema is mutable.
|
|
225
226
|
const jsonSchema = schema instanceof EchoSchema ? schema.jsonSchema : toJsonSchema(schema);
|
|
226
227
|
|
|
227
|
-
//
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
? createEchoChangeCallback(view, schema)
|
|
231
|
-
: createDirectChangeCallback(view.projection, jsonSchema);
|
|
228
|
+
// Always use createEchoChangeCallback since the view is ECHO-backed.
|
|
229
|
+
// Pass schema only when mutable to allow schema mutations.
|
|
230
|
+
const change = createEchoChangeCallback(view, schema instanceof EchoSchema ? schema : undefined);
|
|
232
231
|
|
|
233
232
|
const model = new ProjectionModel({
|
|
234
233
|
registry: atomRegistry,
|
|
@@ -264,15 +263,15 @@ const FieldList = ({ schema, view, registry, readonly, showHeading = false, onDe
|
|
|
264
263
|
const handleMove = useCallback(
|
|
265
264
|
(fromIndex: number, toIndex: number) => {
|
|
266
265
|
invariant(!readonly);
|
|
267
|
-
// NOTE(ZaymonFC): Using arrayMove here causes a race condition with the kanban model.
|
|
268
|
-
const fields = [...view.projection.fields];
|
|
269
|
-
const [moved] = fields.splice(fromIndex, 1);
|
|
270
|
-
fields.splice(toIndex, 0, moved);
|
|
271
266
|
Obj.change(view, (v) => {
|
|
267
|
+
// NOTE(ZaymonFC): Using arrayMove here causes a race condition with the kanban model.
|
|
268
|
+
const fields = [...v.projection.fields];
|
|
269
|
+
const [moved] = fields.splice(fromIndex, 1);
|
|
270
|
+
fields.splice(toIndex, 0, moved);
|
|
272
271
|
v.projection.fields = fields;
|
|
273
272
|
});
|
|
274
273
|
},
|
|
275
|
-
[view
|
|
274
|
+
[view, readonly],
|
|
276
275
|
);
|
|
277
276
|
|
|
278
277
|
const handleClose = useCallback(() => setExpandedField(undefined), []);
|
|
@@ -293,9 +292,13 @@ const FieldList = ({ schema, view, registry, readonly, showHeading = false, onDe
|
|
|
293
292
|
[projectionModel],
|
|
294
293
|
);
|
|
295
294
|
|
|
295
|
+
if (!viewSnapshot) {
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
|
|
296
299
|
return (
|
|
297
300
|
<List.Root<FieldType>
|
|
298
|
-
items={
|
|
301
|
+
items={viewSnapshot.projection.fields as FieldType[]}
|
|
299
302
|
isItem={Schema.is(FieldSchema)}
|
|
300
303
|
getId={(field) => field.id}
|
|
301
304
|
onMove={readonly ? undefined : handleMove}
|
|
@@ -332,7 +335,7 @@ const FieldList = ({ schema, view, registry, readonly, showHeading = false, onDe
|
|
|
332
335
|
<List.ItemDeleteButton
|
|
333
336
|
label={t('delete field label')}
|
|
334
337
|
autoHide={false}
|
|
335
|
-
disabled={readonly || schemaReadonly ||
|
|
338
|
+
disabled={readonly || schemaReadonly || viewSnapshot.projection.fields.length <= 1}
|
|
336
339
|
onClick={() => handleDelete(field.id)}
|
|
337
340
|
data-testid='field.delete'
|
|
338
341
|
/>
|
|
@@ -7,6 +7,7 @@ import type * as Schema from 'effect/Schema';
|
|
|
7
7
|
import type * as SchemaAST from 'effect/SchemaAST';
|
|
8
8
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
9
9
|
|
|
10
|
+
import { Obj } from '@dxos/echo';
|
|
10
11
|
import { type AnyProperties } from '@dxos/echo/internal';
|
|
11
12
|
import {
|
|
12
13
|
type JsonPath,
|
|
@@ -20,6 +21,8 @@ import { useDefaultValue } from '@dxos/react-ui';
|
|
|
20
21
|
import { type ValidationError, validateSchema } from '@dxos/schema';
|
|
21
22
|
import { type MaybePromise } from '@dxos/util';
|
|
22
23
|
|
|
24
|
+
import { setValueEchoAware } from '../util';
|
|
25
|
+
|
|
23
26
|
export type FormFieldStatus = {
|
|
24
27
|
status?: 'error';
|
|
25
28
|
error?: string;
|
|
@@ -267,7 +270,10 @@ export const useFormHandler = <T extends AnyProperties>({
|
|
|
267
270
|
}
|
|
268
271
|
|
|
269
272
|
// Update.
|
|
270
|
-
|
|
273
|
+
// For ECHO objects, mutate in place via Obj.change(); for plain objects, spread to create new reference.
|
|
274
|
+
const newValues = Obj.isObject(values)
|
|
275
|
+
? (setValueEchoAware(values, jsonPath, parsedValue), values)
|
|
276
|
+
: { ...setValue$(values, jsonPath, parsedValue) };
|
|
271
277
|
setValues(newValues);
|
|
272
278
|
|
|
273
279
|
// TODO(burdon): Check value has changed from original.
|
package/src/util/echo.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Obj } from '@dxos/echo';
|
|
6
|
+
import { type JsonPath, setValue as setValuePlain, splitJsonPath } from '@dxos/effect';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Sets a value on an object, using Obj.change() if it's an ECHO object.
|
|
10
|
+
*/
|
|
11
|
+
// TODO(wittjosiah): Consider refactoring Form to not know about ECHO at all.
|
|
12
|
+
// Instead of directly mutating the values object, Form could work with a plain
|
|
13
|
+
// object copy and communicate all mutations through callbacks (e.g., onValuesChanged).
|
|
14
|
+
// The caller would then be responsible for applying changes to ECHO objects via
|
|
15
|
+
// Obj.change(). This would keep Form agnostic to the underlying data layer and
|
|
16
|
+
// avoid coupling react-ui-form to @dxos/echo.
|
|
17
|
+
export const setValueEchoAware = <T extends object>(obj: T, path: JsonPath, value: any): T => {
|
|
18
|
+
if (Obj.isObject(obj)) {
|
|
19
|
+
Obj.change(obj, (mutableObj) => {
|
|
20
|
+
Obj.setValue(mutableObj, splitJsonPath(path), value);
|
|
21
|
+
});
|
|
22
|
+
return obj;
|
|
23
|
+
}
|
|
24
|
+
return setValuePlain(obj, path, value);
|
|
25
|
+
};
|