@dxos/react-ui-form 0.8.2-main.2f9c567 → 0.8.2-main.5885341
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 +49 -83
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +177 -210
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +49 -83
- 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/ArrayField.d.ts.map +1 -1
- package/dist/types/src/components/Form/Defaults.d.ts.map +1 -1
- package/dist/types/src/components/Form/Form.d.ts +2 -3
- package/dist/types/src/components/Form/Form.d.ts.map +1 -1
- package/dist/types/src/components/Form/Form.stories.d.ts +32 -33
- package/dist/types/src/components/Form/Form.stories.d.ts.map +1 -1
- package/dist/types/src/components/Form/FormContent.d.ts +2 -2
- package/dist/types/src/components/Form/FormContent.d.ts.map +1 -1
- package/dist/types/src/components/Form/RefField.d.ts +2 -3
- package/dist/types/src/components/Form/RefField.d.ts.map +1 -1
- package/dist/types/src/components/Form/custom/SelectOptionsInput.stories.d.ts.map +1 -1
- package/dist/types/src/components/Form/index.d.ts +0 -1
- package/dist/types/src/components/Form/index.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.map +1 -1
- package/dist/types/src/components/deprecated/Form.d.ts +2 -2
- package/dist/types/src/components/deprecated/Form.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +0 -1
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useForm.d.ts +2 -2
- package/dist/types/src/hooks/useForm.d.ts.map +1 -1
- package/package.json +24 -24
- package/src/components/Form/ArrayField.tsx +6 -5
- package/src/components/Form/Defaults.tsx +1 -4
- package/src/components/Form/Form.stories.tsx +41 -46
- package/src/components/Form/Form.tsx +2 -3
- package/src/components/Form/FormContent.tsx +6 -5
- package/src/components/Form/RefField.tsx +2 -2
- package/src/components/Form/custom/SelectOptionsInput.stories.tsx +4 -5
- package/src/components/Form/index.ts +1 -1
- package/src/components/ViewEditor/ViewEditor.stories.tsx +2 -3
- package/src/components/ViewEditor/ViewEditor.tsx +8 -9
- package/src/components/deprecated/Form.tsx +6 -6
- package/src/hooks/index.ts +0 -1
- package/src/hooks/useForm.ts +3 -3
- package/dist/types/src/hooks/useRefQueryLookupHandler.d.ts +0 -8
- package/dist/types/src/hooks/useRefQueryLookupHandler.d.ts.map +0 -1
- package/src/hooks/useRefQueryLookupHandler.ts +0 -43
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { pipe } from 'effect';
|
|
6
6
|
import { capitalize } from 'effect/String';
|
|
7
7
|
import React, { useCallback, useMemo } from 'react';
|
|
8
8
|
|
|
9
|
+
import { AST } from '@dxos/echo-schema';
|
|
9
10
|
import { findNode, getDiscriminatedType, isDiscriminatedUnion, SimpleType } from '@dxos/effect';
|
|
10
11
|
import { invariant } from '@dxos/invariant';
|
|
11
12
|
import { IconButton, useTranslation } from '@dxos/react-ui';
|
|
@@ -38,12 +39,12 @@ export const ArrayField = ({ property, readonly, path, inputProps, Custom, looku
|
|
|
38
39
|
invariant(Array.isArray(values), `Values at path ${path?.join('.')} must be an array.`);
|
|
39
40
|
const label = title ?? pipe(name, capitalize);
|
|
40
41
|
|
|
41
|
-
const tupleType = findNode(ast,
|
|
42
|
-
const elementType = (tupleType as
|
|
42
|
+
const tupleType = findNode(ast, AST.isTupleType);
|
|
43
|
+
const elementType = (tupleType as AST.TupleType | undefined)?.rest[0]?.type;
|
|
43
44
|
|
|
44
|
-
const getDefaultObjectValue = (typeNode:
|
|
45
|
+
const getDefaultObjectValue = (typeNode: AST.AST): any => {
|
|
45
46
|
const baseNode = findNode(typeNode, isDiscriminatedUnion);
|
|
46
|
-
const typeLiteral = baseNode ? getDiscriminatedType(baseNode, {}) : findNode(typeNode,
|
|
47
|
+
const typeLiteral = baseNode ? getDiscriminatedType(baseNode, {}) : findNode(typeNode, AST.isTypeLiteral);
|
|
47
48
|
if (!typeLiteral) {
|
|
48
49
|
return {};
|
|
49
50
|
}
|
|
@@ -107,9 +107,6 @@ export const SelectInput = ({
|
|
|
107
107
|
}: SelectInputOptions) => {
|
|
108
108
|
const { status, error } = getStatus();
|
|
109
109
|
|
|
110
|
-
const value = getValue() as string | undefined;
|
|
111
|
-
const handleValueChange = useCallback((value: string | number) => onValueChange(type, value), [type, onValueChange]);
|
|
112
|
-
|
|
113
110
|
return (
|
|
114
111
|
<Input.Root validationValence={status}>
|
|
115
112
|
{!inputOnly && (
|
|
@@ -117,7 +114,7 @@ export const SelectInput = ({
|
|
|
117
114
|
<Input.Label>{label}</Input.Label>
|
|
118
115
|
</InputHeader>
|
|
119
116
|
)}
|
|
120
|
-
<Select.Root value={
|
|
117
|
+
<Select.Root value={getValue()} onValueChange={(value) => onValueChange(type, value)}>
|
|
121
118
|
{/* TODO(burdon): Placeholder not working? */}
|
|
122
119
|
<Select.TriggerButton classNames='is-full' disabled={disabled} placeholder={placeholder} />
|
|
123
120
|
<Select.Portal>
|
|
@@ -5,11 +5,10 @@
|
|
|
5
5
|
import '@dxos-theme';
|
|
6
6
|
|
|
7
7
|
import { type Meta, type StoryObj } from '@storybook/react';
|
|
8
|
-
import { Schema, SchemaAST } from 'effect';
|
|
9
8
|
import React, { useCallback, useState } from 'react';
|
|
10
9
|
|
|
11
10
|
import { ContactType } from '@dxos/client/testing';
|
|
12
|
-
import { type BaseObject, Expando, Format, getDXN, Ref, type TypeAnnotation } from '@dxos/echo-schema';
|
|
11
|
+
import { AST, type BaseObject, Expando, Format, getDXN, Ref, S, type TypeAnnotation } from '@dxos/echo-schema';
|
|
13
12
|
import { live } from '@dxos/live-object';
|
|
14
13
|
import { Testing } from '@dxos/schema/testing';
|
|
15
14
|
import { withLayout, withTheme } from '@dxos/storybook-utils';
|
|
@@ -19,27 +18,25 @@ import { Form, type FormProps } from './Form';
|
|
|
19
18
|
import translations from '../../translations';
|
|
20
19
|
import { TestLayout, TestPanel } from '../testing';
|
|
21
20
|
|
|
22
|
-
const AddressSchema =
|
|
23
|
-
street:
|
|
24
|
-
city:
|
|
25
|
-
zip:
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
location: Schema.optional(Format.GeoPoint.annotations({ [SchemaAST.TitleAnnotationId]: 'Location' })),
|
|
29
|
-
}).annotations({ [SchemaAST.TitleAnnotationId]: 'Address' });
|
|
21
|
+
const AddressSchema = S.Struct({
|
|
22
|
+
street: S.optional(S.String.annotations({ [AST.TitleAnnotationId]: 'Street' })),
|
|
23
|
+
city: S.optional(S.String.annotations({ [AST.TitleAnnotationId]: 'City' })),
|
|
24
|
+
zip: S.optional(S.String.pipe(S.pattern(/^\d{5}(-\d{4})?$/)).annotations({ [AST.TitleAnnotationId]: 'ZIP' })),
|
|
25
|
+
location: S.optional(Format.GeoPoint.annotations({ [AST.TitleAnnotationId]: 'Location' })),
|
|
26
|
+
}).annotations({ [AST.TitleAnnotationId]: 'Address' });
|
|
30
27
|
|
|
31
28
|
// TODO(burdon): Translations?
|
|
32
|
-
const TestSchema =
|
|
33
|
-
name:
|
|
34
|
-
active:
|
|
35
|
-
rank:
|
|
36
|
-
website:
|
|
37
|
-
address:
|
|
38
|
-
}).pipe(
|
|
29
|
+
const TestSchema = S.Struct({
|
|
30
|
+
name: S.optional(S.String.annotations({ [AST.TitleAnnotationId]: 'Name' })),
|
|
31
|
+
active: S.optional(S.Boolean.annotations({ [AST.TitleAnnotationId]: 'Active' })),
|
|
32
|
+
rank: S.optional(S.Number.annotations({ [AST.TitleAnnotationId]: 'Rank' })),
|
|
33
|
+
website: S.optional(Format.URL.annotations({ [AST.TitleAnnotationId]: 'Website' })),
|
|
34
|
+
address: S.optional(AddressSchema),
|
|
35
|
+
}).pipe(S.mutable);
|
|
39
36
|
|
|
40
|
-
type TestType =
|
|
37
|
+
type TestType = S.Schema.Type<typeof TestSchema>;
|
|
41
38
|
|
|
42
|
-
type StoryProps<T extends BaseObject> = { schema:
|
|
39
|
+
type StoryProps<T extends BaseObject> = { schema: S.Schema<T> } & FormProps<T>;
|
|
43
40
|
|
|
44
41
|
const DefaultStory = <T extends BaseObject>({ schema, values: initialValues, ...props }: StoryProps<T>) => {
|
|
45
42
|
const [values, setValues] = useState(initialValues);
|
|
@@ -120,24 +117,22 @@ export const OrganizationAutoSave: Story<Testing.Organization> = {
|
|
|
120
117
|
// TODO(burdon): Move into separate storybook and use test types.
|
|
121
118
|
//
|
|
122
119
|
|
|
123
|
-
const ShapeSchema =
|
|
124
|
-
shape:
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
type:
|
|
128
|
-
radius:
|
|
120
|
+
const ShapeSchema = S.Struct({
|
|
121
|
+
shape: S.optional(
|
|
122
|
+
S.Union(
|
|
123
|
+
S.Struct({
|
|
124
|
+
type: S.Literal('circle').annotations({ [AST.TitleAnnotationId]: 'Type' }),
|
|
125
|
+
radius: S.optional(S.Number.annotations({ [AST.TitleAnnotationId]: 'Radius' })),
|
|
129
126
|
}),
|
|
130
|
-
|
|
131
|
-
type:
|
|
132
|
-
size:
|
|
133
|
-
Schema.Number.pipe(Schema.nonNegative()).annotations({ [SchemaAST.TitleAnnotationId]: 'Size' }),
|
|
134
|
-
),
|
|
127
|
+
S.Struct({
|
|
128
|
+
type: S.Literal('square').annotations({ [AST.TitleAnnotationId]: 'Type' }),
|
|
129
|
+
size: S.optional(S.Number.pipe(S.nonNegative()).annotations({ [AST.TitleAnnotationId]: 'Size' })),
|
|
135
130
|
}),
|
|
136
|
-
).annotations({ [
|
|
131
|
+
).annotations({ [AST.TitleAnnotationId]: 'Shape' }),
|
|
137
132
|
),
|
|
138
|
-
}).pipe(
|
|
133
|
+
}).pipe(S.mutable);
|
|
139
134
|
|
|
140
|
-
type ShapeType =
|
|
135
|
+
type ShapeType = S.Schema.Type<typeof ShapeSchema>;
|
|
141
136
|
|
|
142
137
|
type DiscriminatedUnionStoryProps = FormProps<ShapeType>;
|
|
143
138
|
|
|
@@ -183,12 +178,12 @@ export const DiscriminatedShape: StoryObj<DiscriminatedUnionStoryProps> = {
|
|
|
183
178
|
},
|
|
184
179
|
};
|
|
185
180
|
|
|
186
|
-
const ArraysSchema =
|
|
187
|
-
names:
|
|
188
|
-
addresses:
|
|
189
|
-
}).pipe(
|
|
181
|
+
const ArraysSchema = S.Struct({
|
|
182
|
+
names: S.Array(S.String.pipe(S.nonEmptyString())),
|
|
183
|
+
addresses: S.Array(AddressSchema),
|
|
184
|
+
}).pipe(S.mutable);
|
|
190
185
|
|
|
191
|
-
type ArraysType =
|
|
186
|
+
type ArraysType = S.Schema.Type<typeof ArraysSchema>;
|
|
192
187
|
|
|
193
188
|
const ArraysStory = ({ values: initialValues }: FormProps<ArraysType>) => {
|
|
194
189
|
const [values, setValues] = useState(initialValues);
|
|
@@ -215,13 +210,13 @@ export const Arrays: StoryObj<FormProps<ArraysType>> = {
|
|
|
215
210
|
},
|
|
216
211
|
};
|
|
217
212
|
|
|
218
|
-
const ColorSchema =
|
|
219
|
-
color:
|
|
220
|
-
[
|
|
213
|
+
const ColorSchema = S.Struct({
|
|
214
|
+
color: S.Union(S.Literal('red'), S.Literal('green'), S.Literal('blue')).annotations({
|
|
215
|
+
[AST.TitleAnnotationId]: 'Color',
|
|
221
216
|
}),
|
|
222
|
-
}).pipe(
|
|
217
|
+
}).pipe(S.mutable);
|
|
223
218
|
|
|
224
|
-
type ColorType =
|
|
219
|
+
type ColorType = S.Schema.Type<typeof ColorSchema>;
|
|
225
220
|
|
|
226
221
|
const EnumStory = ({ values: initialValues }: FormProps<ColorType>) => {
|
|
227
222
|
const [values, setValues] = useState(initialValues);
|
|
@@ -247,10 +242,10 @@ export const Enum: StoryObj<FormProps<ColorType>> = {
|
|
|
247
242
|
},
|
|
248
243
|
};
|
|
249
244
|
|
|
250
|
-
const RefSchema =
|
|
245
|
+
const RefSchema = S.Struct({
|
|
251
246
|
contact: Ref(ContactType).annotations({ title: 'Contact Reference' }),
|
|
252
|
-
optionalContact:
|
|
253
|
-
unknownExpando:
|
|
247
|
+
optionalContact: S.optional(Ref(ContactType).annotations({ title: 'Optional Contact Reference' })),
|
|
248
|
+
unknownExpando: S.optional(Ref(Expando).annotations({ title: 'Optional Ref to an Expando (DXN Input)' })),
|
|
254
249
|
});
|
|
255
250
|
|
|
256
251
|
const RefStory = ({ values: initialValues }: FormProps<any>) => {
|
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { type Schema } from 'effect';
|
|
6
5
|
import React, { type ReactElement, useEffect, useMemo, useRef } from 'react';
|
|
7
6
|
|
|
8
|
-
import { type BaseObject, type PropertyKey } from '@dxos/echo-schema';
|
|
7
|
+
import { type BaseObject, type S, type PropertyKey } from '@dxos/echo-schema';
|
|
9
8
|
import { type ThemedClassName } from '@dxos/react-ui';
|
|
10
9
|
import { mx } from '@dxos/react-ui-theme';
|
|
11
10
|
import { type SchemaProperty } from '@dxos/schema';
|
|
@@ -21,7 +20,7 @@ export type PropsFilter<T extends BaseObject> = (props: SchemaProperty<T>[]) =>
|
|
|
21
20
|
|
|
22
21
|
export type ComponentLookup = (args: {
|
|
23
22
|
prop: string;
|
|
24
|
-
schema:
|
|
23
|
+
schema: S.Schema<any>;
|
|
25
24
|
inputProps: InputProps;
|
|
26
25
|
}) => ReactElement | undefined;
|
|
27
26
|
|
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { pipe } from 'effect';
|
|
6
6
|
import { capitalize } from 'effect/String';
|
|
7
7
|
import React, { useMemo } from 'react';
|
|
8
8
|
|
|
9
|
+
import { AST, S } from '@dxos/echo-schema';
|
|
9
10
|
import { createJsonPath, findNode, getDiscriminatedType, isDiscriminatedUnion } from '@dxos/effect';
|
|
10
11
|
import { mx } from '@dxos/react-ui-theme';
|
|
11
12
|
import { getSchemaProperties, type SchemaProperty } from '@dxos/schema';
|
|
@@ -50,7 +51,7 @@ export const FormField = ({
|
|
|
50
51
|
|
|
51
52
|
const FoundComponent = lookupComponent?.({
|
|
52
53
|
prop: name,
|
|
53
|
-
schema:
|
|
54
|
+
schema: S.make(ast),
|
|
54
55
|
inputProps: {
|
|
55
56
|
type,
|
|
56
57
|
format,
|
|
@@ -139,14 +140,14 @@ export const FormField = ({
|
|
|
139
140
|
const baseNode = findNode(ast, isDiscriminatedUnion);
|
|
140
141
|
const typeLiteral = baseNode
|
|
141
142
|
? getDiscriminatedType(baseNode, inputProps.getValue() as any)
|
|
142
|
-
: findNode(ast,
|
|
143
|
+
: findNode(ast, AST.isTypeLiteral);
|
|
143
144
|
|
|
144
145
|
if (typeLiteral) {
|
|
145
146
|
return (
|
|
146
147
|
<div role='none'>
|
|
147
148
|
{!inline && <h3 className='text-lg mbs-2 mbe-1'>{label}</h3>}
|
|
148
149
|
<FormFields
|
|
149
|
-
schema={
|
|
150
|
+
schema={S.make(typeLiteral)}
|
|
150
151
|
path={path}
|
|
151
152
|
readonly={readonly}
|
|
152
153
|
onQueryRefOptions={onQueryRefOptions}
|
|
@@ -162,7 +163,7 @@ export const FormField = ({
|
|
|
162
163
|
};
|
|
163
164
|
|
|
164
165
|
export type FormContentProps = {
|
|
165
|
-
schema:
|
|
166
|
+
schema: S.Schema.All;
|
|
166
167
|
path?: (string | number)[];
|
|
167
168
|
filter?: (props: SchemaProperty<any>[]) => SchemaProperty<any>[];
|
|
168
169
|
sort?: string[];
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { type SchemaAST } from 'effect';
|
|
6
5
|
import React, { useEffect, useState } from 'react';
|
|
7
6
|
|
|
8
7
|
import {
|
|
8
|
+
type AST,
|
|
9
9
|
Expando,
|
|
10
10
|
getTypeAnnotation,
|
|
11
11
|
Ref,
|
|
@@ -25,7 +25,7 @@ import { type FormInputStateProps } from './FormContext';
|
|
|
25
25
|
export type QueryRefOptions = (type: TypeAnnotation) => MaybePromise<{ dxn: DXN; label?: string }[]>;
|
|
26
26
|
|
|
27
27
|
type RefFieldProps = {
|
|
28
|
-
ast:
|
|
28
|
+
ast: AST.AST;
|
|
29
29
|
type: SimpleType;
|
|
30
30
|
label: string;
|
|
31
31
|
readonly?: boolean;
|
|
@@ -5,10 +5,9 @@
|
|
|
5
5
|
import '@dxos-theme';
|
|
6
6
|
|
|
7
7
|
import { type Meta, type StoryObj } from '@storybook/react';
|
|
8
|
-
import { Schema } from 'effect';
|
|
9
8
|
import React, { useState } from 'react';
|
|
10
9
|
|
|
11
|
-
import { SelectOptionSchema, type SelectOption } from '@dxos/echo-schema';
|
|
10
|
+
import { S, SelectOptionSchema, type SelectOption } from '@dxos/echo-schema';
|
|
12
11
|
import { withLayout, withTheme } from '@dxos/storybook-utils';
|
|
13
12
|
|
|
14
13
|
import { SelectOptionInput } from './SelectOptionsInput';
|
|
@@ -16,9 +15,9 @@ import translations from '../../../translations';
|
|
|
16
15
|
import { TestLayout, TestPanel } from '../../testing';
|
|
17
16
|
import { Form } from '../Form';
|
|
18
17
|
|
|
19
|
-
const schema =
|
|
20
|
-
options:
|
|
21
|
-
}).pipe(
|
|
18
|
+
const schema = S.Struct({
|
|
19
|
+
options: S.Array(SelectOptionSchema).pipe(S.mutable),
|
|
20
|
+
}).pipe(S.mutable);
|
|
22
21
|
|
|
23
22
|
const DefaultStory = () => {
|
|
24
23
|
const [values, setValues] = useState<{ options: SelectOption[] }>({
|
|
@@ -5,10 +5,9 @@
|
|
|
5
5
|
import '@dxos-theme';
|
|
6
6
|
|
|
7
7
|
import { type Meta, type StoryObj } from '@storybook/react';
|
|
8
|
-
import { Schema } from 'effect';
|
|
9
8
|
import React, { useCallback, useMemo, useState } from 'react';
|
|
10
9
|
|
|
11
|
-
import { Format, type EchoSchema, toJsonSchema, TypedObject } from '@dxos/echo-schema';
|
|
10
|
+
import { Format, type EchoSchema, S, toJsonSchema, TypedObject } from '@dxos/echo-schema';
|
|
12
11
|
import { Filter, useQuery, useSpace } from '@dxos/react-client/echo';
|
|
13
12
|
import { withClientProvider } from '@dxos/react-client/testing';
|
|
14
13
|
import { useAsyncEffect } from '@dxos/react-ui';
|
|
@@ -27,7 +26,7 @@ const DefaultStory = () => {
|
|
|
27
26
|
useAsyncEffect(async () => {
|
|
28
27
|
if (space) {
|
|
29
28
|
class TestSchema extends TypedObject({ typename: 'example.com/type/Test', version: '0.1.0' })({
|
|
30
|
-
name:
|
|
29
|
+
name: S.String,
|
|
31
30
|
email: Format.Email,
|
|
32
31
|
salary: Format.Currency(),
|
|
33
32
|
}) {}
|
|
@@ -2,11 +2,10 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { Schema, SchemaAST } from 'effect';
|
|
6
5
|
import React, { useCallback, useMemo, useState } from 'react';
|
|
7
6
|
|
|
8
7
|
import { type SchemaRegistry } from '@dxos/echo-db';
|
|
9
|
-
import { Format, type BaseSchema, type JsonProp } from '@dxos/echo-schema';
|
|
8
|
+
import { AST, Format, type BaseSchema, S, type JsonProp } from '@dxos/echo-schema';
|
|
10
9
|
import { invariant } from '@dxos/invariant';
|
|
11
10
|
import { IconButton, type ThemedClassName, useTranslation } from '@dxos/react-ui';
|
|
12
11
|
import { List } from '@dxos/react-ui-list';
|
|
@@ -19,16 +18,16 @@ import { Form } from '../Form';
|
|
|
19
18
|
|
|
20
19
|
const grid = 'grid grid-cols-[32px_1fr_32px] min-bs-[2.5rem]';
|
|
21
20
|
|
|
22
|
-
const ViewMetaSchema =
|
|
23
|
-
name:
|
|
24
|
-
[
|
|
21
|
+
const ViewMetaSchema = S.Struct({
|
|
22
|
+
name: S.String.annotations({
|
|
23
|
+
[AST.TitleAnnotationId]: 'View',
|
|
25
24
|
}),
|
|
26
25
|
typename: Format.URL.annotations({
|
|
27
|
-
[
|
|
26
|
+
[AST.TitleAnnotationId]: 'Typename',
|
|
28
27
|
}),
|
|
29
|
-
}).pipe(
|
|
28
|
+
}).pipe(S.mutable);
|
|
30
29
|
|
|
31
|
-
type ViewMetaType =
|
|
30
|
+
type ViewMetaType = S.Schema.Type<typeof ViewMetaSchema>;
|
|
32
31
|
|
|
33
32
|
export type ViewEditorProps = ThemedClassName<{
|
|
34
33
|
schema: BaseSchema;
|
|
@@ -157,7 +156,7 @@ export const ViewEditor = ({
|
|
|
157
156
|
|
|
158
157
|
<List.Root<FieldType>
|
|
159
158
|
items={view.fields}
|
|
160
|
-
isItem={
|
|
159
|
+
isItem={S.is(FieldSchema)}
|
|
161
160
|
getId={(field) => field.id}
|
|
162
161
|
onMove={schema.readonly ? undefined : handleMove}
|
|
163
162
|
>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { SchemaAST, type Schema, Option, pipe } from 'effect';
|
|
5
|
+
import { SchemaAST as AST, type Schema as S, Option, pipe } from 'effect';
|
|
6
6
|
import React, { useState } from 'react';
|
|
7
7
|
|
|
8
8
|
import { findProperty } from '@dxos/effect';
|
|
@@ -13,7 +13,7 @@ import { type ViewType, getFieldValue, setFieldValue } from '@dxos/schema';
|
|
|
13
13
|
export type DeprecatedFormProps<T extends {} = {}> = ThemedClassName<{
|
|
14
14
|
view: ViewType;
|
|
15
15
|
object: T;
|
|
16
|
-
schema?:
|
|
16
|
+
schema?: S.Schema<T>;
|
|
17
17
|
readonly?: boolean;
|
|
18
18
|
}>;
|
|
19
19
|
|
|
@@ -31,16 +31,16 @@ export const DeprecatedForm = <T extends {} = {}>({
|
|
|
31
31
|
<div role='none' className={mx('flex flex-col w-full gap-2 p-2', classNames)}>
|
|
32
32
|
{view.fields.map((field) => {
|
|
33
33
|
const prop = schema && findProperty(schema, field.path);
|
|
34
|
-
const title = (prop && pipe(
|
|
35
|
-
const description = (prop && pipe(
|
|
34
|
+
const title = (prop && pipe(AST.getTitleAnnotation(prop), Option.getOrUndefined)) ?? '';
|
|
35
|
+
const description = (prop && pipe(AST.getDescriptionAnnotation(prop), Option.getOrUndefined)) ?? title;
|
|
36
36
|
// const format =
|
|
37
|
-
// (prop && (getPatternAnnotation(prop) ?? (
|
|
37
|
+
// (prop && (getPatternAnnotation(prop) ?? (AST.isNumberKeyword(prop) && RealNumberFormat))) || undefined;
|
|
38
38
|
|
|
39
39
|
//
|
|
40
40
|
// Boolean
|
|
41
41
|
//
|
|
42
42
|
|
|
43
|
-
if (prop &&
|
|
43
|
+
if (prop && AST.isBooleanKeyword(prop)) {
|
|
44
44
|
const value = object && getFieldValue(object, field);
|
|
45
45
|
const onChange = (checked: boolean) => {
|
|
46
46
|
setFieldValue(object, field, checked);
|
package/src/hooks/index.ts
CHANGED
package/src/hooks/useForm.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { SchemaAST, type Schema } from 'effect';
|
|
5
|
+
import { SchemaAST as AST, type Schema as S } from 'effect';
|
|
6
6
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
7
7
|
|
|
8
8
|
import { type BaseObject, getValue, setValue } from '@dxos/echo-schema';
|
|
@@ -45,7 +45,7 @@ export interface FormOptions<T extends BaseObject> {
|
|
|
45
45
|
/**
|
|
46
46
|
* Effect schema (Type literal).
|
|
47
47
|
*/
|
|
48
|
-
schema:
|
|
48
|
+
schema: S.Schema<T>;
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
51
|
* Initial values (which may not pass validation).
|
|
@@ -90,7 +90,7 @@ export const useForm = <T extends BaseObject>({
|
|
|
90
90
|
onValid,
|
|
91
91
|
onSave,
|
|
92
92
|
}: FormOptions<T>): FormHandler<T> => {
|
|
93
|
-
invariant(
|
|
93
|
+
invariant(AST.isTypeLiteral(schema.ast));
|
|
94
94
|
|
|
95
95
|
const [values, setValues] = useState<Partial<T>>(initialValues);
|
|
96
96
|
useEffect(() => {
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { type Space } from '@dxos/react-client/echo';
|
|
2
|
-
import { type QueryRefOptions } from '../components';
|
|
3
|
-
type UseRefQueryLookupProps = {
|
|
4
|
-
space?: Space;
|
|
5
|
-
};
|
|
6
|
-
export declare const useRefQueryLookupHandler: ({ space }: UseRefQueryLookupProps) => QueryRefOptions;
|
|
7
|
-
export {};
|
|
8
|
-
//# sourceMappingURL=useRefQueryLookupHandler.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useRefQueryLookupHandler.d.ts","sourceRoot":"","sources":["../../../../src/hooks/useRefQueryLookupHandler.ts"],"names":[],"mappings":"AAOA,OAAO,EAAU,KAAK,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAG7D,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD,KAAK,sBAAsB,GAAG;IAC5B,KAAK,CAAC,EAAE,KAAK,CAAC;CACf,CAAC;AAEF,eAAO,MAAM,wBAAwB,cAAe,sBAAsB,KAAG,eA0B5E,CAAC"}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2025 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { useCallback } from 'react';
|
|
6
|
-
|
|
7
|
-
import { getDXN, type TypeAnnotation } from '@dxos/echo-schema';
|
|
8
|
-
import { Filter, type Space } from '@dxos/react-client/echo';
|
|
9
|
-
import { isNonNullable } from '@dxos/util';
|
|
10
|
-
|
|
11
|
-
import { type QueryRefOptions } from '../components';
|
|
12
|
-
|
|
13
|
-
type UseRefQueryLookupProps = {
|
|
14
|
-
space?: Space;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export const useRefQueryLookupHandler = ({ space }: UseRefQueryLookupProps): QueryRefOptions => {
|
|
18
|
-
const handleRefQueryLookup = useCallback(
|
|
19
|
-
async (typeInfo: TypeAnnotation) => {
|
|
20
|
-
if (!space) {
|
|
21
|
-
return [];
|
|
22
|
-
}
|
|
23
|
-
const query = space.db.query(Filter.typename(typeInfo.typename));
|
|
24
|
-
const { objects } = await query.run();
|
|
25
|
-
|
|
26
|
-
return objects
|
|
27
|
-
.map((object) => {
|
|
28
|
-
const dxn = getDXN(object);
|
|
29
|
-
if (!dxn) {
|
|
30
|
-
return undefined;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// TODO(Zaymon): Better fallback object names?
|
|
34
|
-
const item = { dxn, label: object?.name ?? object?.id ?? '' };
|
|
35
|
-
return item;
|
|
36
|
-
})
|
|
37
|
-
.filter(isNonNullable);
|
|
38
|
-
},
|
|
39
|
-
[space],
|
|
40
|
-
);
|
|
41
|
-
|
|
42
|
-
return handleRefQueryLookup;
|
|
43
|
-
};
|