@dxos/react-ui-form 0.7.1-staging.8709ba7 → 0.7.2-staging.6d26b2a
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 +107 -81
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +100 -74
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +107 -81
- 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/Custom.d.ts +2 -1
- package/dist/types/src/components/Form/Custom.d.ts.map +1 -1
- package/dist/types/src/components/Form/Defaults.d.ts +11 -4
- package/dist/types/src/components/Form/Defaults.d.ts.map +1 -1
- package/dist/types/src/components/Form/Form.d.ts +5 -4
- package/dist/types/src/components/Form/Form.d.ts.map +1 -1
- package/dist/types/src/components/Form/Form.stories.d.ts +1 -4
- package/dist/types/src/components/Form/Form.stories.d.ts.map +1 -1
- package/dist/types/src/components/Form/Input.d.ts +3 -8
- package/dist/types/src/components/Form/Input.d.ts.map +1 -1
- package/dist/types/src/components/Form/factory.d.ts +2 -2
- package/dist/types/src/components/Form/factory.d.ts.map +1 -1
- package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts.map +1 -1
- package/dist/types/src/hooks/useForm.d.ts +5 -4
- package/dist/types/src/hooks/useForm.d.ts.map +1 -1
- package/package.json +22 -24
- package/src/components/Form/Custom.tsx +9 -9
- package/src/components/Form/Defaults.tsx +10 -5
- package/src/components/Form/Form.stories.tsx +2 -2
- package/src/components/Form/Form.tsx +43 -19
- package/src/components/Form/Input.tsx +3 -7
- package/src/components/Form/factory.tsx +4 -4
- package/src/components/ViewEditor/ViewEditor.stories.tsx +1 -2
- package/src/hooks/useForm.ts +7 -6
|
@@ -1,27 +1,22 @@
|
|
|
1
1
|
import React, { type FC, type PropsWithChildren } from 'react';
|
|
2
|
-
import { type FormatEnum } from '@dxos/echo-schema';
|
|
2
|
+
import { type BaseObject, type FormatEnum, type PropertyKey } from '@dxos/echo-schema';
|
|
3
3
|
import { type SimpleType } from '@dxos/effect';
|
|
4
|
-
import { type PropertyKey } from '@dxos/schema';
|
|
5
4
|
import { type FormHandler } from '../../hooks';
|
|
6
5
|
/**
|
|
7
6
|
* Props passed to input components.
|
|
8
7
|
*/
|
|
9
|
-
export type InputProps<T extends
|
|
8
|
+
export type InputProps<T extends BaseObject> = {
|
|
10
9
|
property: PropertyKey<T>;
|
|
11
10
|
type: SimpleType;
|
|
12
11
|
format?: FormatEnum;
|
|
13
12
|
label: string;
|
|
14
13
|
disabled?: boolean;
|
|
15
14
|
placeholder?: string;
|
|
16
|
-
options?: Array<{
|
|
17
|
-
value: string | number;
|
|
18
|
-
label?: string;
|
|
19
|
-
}>;
|
|
20
15
|
} & Pick<FormHandler<T>, 'getStatus' | 'getValue' | 'onValueChange' | 'onBlur'>;
|
|
21
16
|
/**
|
|
22
17
|
* Form input component.
|
|
23
18
|
*/
|
|
24
|
-
export type InputComponent<T extends
|
|
19
|
+
export type InputComponent<T extends BaseObject> = FC<InputProps<T>>;
|
|
25
20
|
export type InputHeaderProps = PropsWithChildren<{
|
|
26
21
|
error?: string;
|
|
27
22
|
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Input.d.ts","sourceRoot":"","sources":["../../../../../src/components/Form/Input.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,KAAK,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAE/D,OAAO,EAAE,KAAK,UAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"Input.d.ts","sourceRoot":"","sources":["../../../../../src/components/Form/Input.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,KAAK,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAE/D,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACvF,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAI/C,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C;;GAEG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,UAAU,IAAI;IAC7C,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;IACzB,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,GAAG,UAAU,GAAG,eAAe,GAAG,QAAQ,CAAC,CAAC;AAEhF;;GAEG;AACH,MAAM,MAAM,cAAc,CAAC,CAAC,SAAS,UAAU,IAAI,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AAErE,MAAM,MAAM,gBAAgB,GAAG,iBAAiB,CAAC;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC,CAAC;AAEH,eAAO,MAAM,WAAW,wBAAyB,gBAAgB,sBAiBhE,CAAC"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { FormatEnum } from '@dxos/echo-schema';
|
|
1
|
+
import { type BaseObject, FormatEnum } from '@dxos/echo-schema';
|
|
2
2
|
import { type SimpleType } from '@dxos/effect';
|
|
3
3
|
import { type InputComponent } from './Input';
|
|
4
4
|
/**
|
|
5
5
|
* Get property input component.
|
|
6
6
|
*/
|
|
7
|
-
export declare const getInputComponent: <T extends
|
|
7
|
+
export declare const getInputComponent: <T extends BaseObject>(type: SimpleType, format?: FormatEnum) => InputComponent<T> | undefined;
|
|
8
8
|
//# sourceMappingURL=factory.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../../../src/components/Form/factory.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../../../src/components/Form/factory.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,UAAU,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAI/C,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C;;GAEG;AACH,eAAO,MAAM,iBAAiB,GAAI,CAAC,SAAS,UAAU,QAC9C,UAAU,WACP,UAAU,KAClB,cAAc,CAAC,CAAC,CAAC,GAAG,SActB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ViewEditor.stories.d.ts","sourceRoot":"","sources":["../../../../../src/components/ViewEditor/ViewEditor.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,aAAa,CAAC;AAErB,OAAO,EAAE,KAAK,IAAI,EAAE,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"ViewEditor.stories.d.ts","sourceRoot":"","sources":["../../../../../src/components/ViewEditor/ViewEditor.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,aAAa,CAAC;AAErB,OAAO,EAAE,KAAK,IAAI,EAAE,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAS5D,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AA0C1C,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,UAAU,CAQjC,CAAC;AAEF,eAAe,IAAI,CAAC;AAEpB,KAAK,KAAK,GAAG,QAAQ,CAAC;AAEtB,eAAO,MAAM,OAAO,EAAE,KAAU,CAAC"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { type FocusEvent } from 'react';
|
|
2
|
+
import { type BaseObject, type PropertyKey } from '@dxos/echo-schema';
|
|
2
3
|
import { type SimpleType, type S } from '@dxos/effect';
|
|
3
|
-
import { type
|
|
4
|
+
import { type ValidationError } from '@dxos/schema';
|
|
4
5
|
/**
|
|
5
6
|
* Return type from `useForm` hook.
|
|
6
7
|
*/
|
|
7
|
-
export type FormHandler<T extends
|
|
8
|
+
export type FormHandler<T extends BaseObject> = {
|
|
8
9
|
values: T;
|
|
9
10
|
errors: Record<PropertyKey<T>, string>;
|
|
10
11
|
touched: Record<PropertyKey<T>, boolean>;
|
|
@@ -22,7 +23,7 @@ export type FormHandler<T extends object = {}> = {
|
|
|
22
23
|
/**
|
|
23
24
|
* Hook options.
|
|
24
25
|
*/
|
|
25
|
-
export interface FormOptions<T extends
|
|
26
|
+
export interface FormOptions<T extends BaseObject> {
|
|
26
27
|
schema: S.Schema<T>;
|
|
27
28
|
initialValues: T;
|
|
28
29
|
/**
|
|
@@ -54,5 +55,5 @@ export interface FormOptions<T extends object> {
|
|
|
54
55
|
* Creates a hook for managing form state, including values, validation, and submission.
|
|
55
56
|
* Deeply integrated with `@dxos/schema` for schema-based validation.
|
|
56
57
|
*/
|
|
57
|
-
export declare const useForm: <T extends
|
|
58
|
+
export declare const useForm: <T extends BaseObject>({ schema, initialValues, onValuesChanged, onValidate, onValid, onSubmit, }: FormOptions<T>) => FormHandler<T>;
|
|
58
59
|
//# sourceMappingURL=useForm.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useForm.d.ts","sourceRoot":"","sources":["../../../../src/hooks/useForm.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,UAAU,EAA6C,MAAM,OAAO,CAAC;AAEnF,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,
|
|
1
|
+
{"version":3,"file":"useForm.d.ts","sourceRoot":"","sources":["../../../../src/hooks/useForm.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,UAAU,EAA6C,MAAM,OAAO,CAAC;AAEnF,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACtE,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,CAAC,EAAE,MAAM,cAAc,CAAC;AAGvD,OAAO,EAAkB,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpE;;GAEG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,UAAU,IAAI;IAK9C,MAAM,EAAE,CAAC,CAAC;IACV,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IACvC,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IACzC,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IACzC,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,MAAM,IAAI,CAAC;IAMzB,SAAS,EAAE,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,KAAK;QAAE,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9E,QAAQ,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAC7C,aAAa,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IACjF,MAAM,EAAE,CAAC,KAAK,EAAE,UAAU,CAAC,gBAAgB,GAAG,mBAAmB,CAAC,KAAK,IAAI,CAAC;CAC7E,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC,SAAS,UAAU;IAC/C,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAGpB,aAAa,EAAE,CAAC,CAAC;IAEjB;;;;OAIG;IACH,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,IAAI,CAAC;IAEtC;;;;OAIG;IAEH,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,eAAe,EAAE,GAAG,SAAS,CAAC;IAE1D;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE;QAAE,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;KAAE,KAAK,IAAI,CAAC;IAE5E;;OAEG;IACH,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE;QAAE,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;KAAE,KAAK,IAAI,CAAC;CAC9E;AAED;;;GAGG;AACH,eAAO,MAAM,OAAO,GAAI,CAAC,SAAS,UAAU,8EAOzC,WAAW,CAAC,CAAC,CAAC,KAAG,WAAW,CAAC,CAAC,CAiIhC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/react-ui-form",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.2-staging.6d26b2a",
|
|
4
4
|
"description": "Data components.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -23,27 +23,25 @@
|
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@atlaskit/pragmatic-drag-and-drop": "^1.4.0",
|
|
26
|
-
"@atlaskit/pragmatic-drag-and-drop-flourish": "^1.1.2",
|
|
27
26
|
"@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.0.3",
|
|
28
|
-
"@atlaskit/pragmatic-drag-and-drop-react-drop-indicator": "^1.1.3",
|
|
29
27
|
"@effect/schema": "^0.75.5",
|
|
30
28
|
"@radix-ui/react-context": "^1.0.0",
|
|
31
29
|
"date-fns": "^3.3.1",
|
|
32
30
|
"effect": "^3.9.2",
|
|
33
31
|
"jsonpath": "^1.1.1",
|
|
34
|
-
"@dxos/async": "0.7.
|
|
35
|
-
"@dxos/debug": "0.7.
|
|
36
|
-
"@dxos/echo-db": "0.7.
|
|
37
|
-
"@dxos/
|
|
38
|
-
"@dxos/
|
|
39
|
-
"@dxos/echo-schema": "0.7.
|
|
40
|
-
"@dxos/keys": "0.7.
|
|
41
|
-
"@dxos/
|
|
42
|
-
"@dxos/
|
|
43
|
-
"@dxos/react-ui-
|
|
44
|
-
"@dxos/
|
|
45
|
-
"@dxos/
|
|
46
|
-
"@dxos/util": "0.7.
|
|
32
|
+
"@dxos/async": "0.7.2-staging.6d26b2a",
|
|
33
|
+
"@dxos/debug": "0.7.2-staging.6d26b2a",
|
|
34
|
+
"@dxos/echo-db": "0.7.2-staging.6d26b2a",
|
|
35
|
+
"@dxos/effect": "0.7.2-staging.6d26b2a",
|
|
36
|
+
"@dxos/invariant": "0.7.2-staging.6d26b2a",
|
|
37
|
+
"@dxos/echo-schema": "0.7.2-staging.6d26b2a",
|
|
38
|
+
"@dxos/keys": "0.7.2-staging.6d26b2a",
|
|
39
|
+
"@dxos/log": "0.7.2-staging.6d26b2a",
|
|
40
|
+
"@dxos/react-ui-list": "0.7.2-staging.6d26b2a",
|
|
41
|
+
"@dxos/react-ui-types": "0.7.2-staging.6d26b2a",
|
|
42
|
+
"@dxos/react-client": "0.7.2-staging.6d26b2a",
|
|
43
|
+
"@dxos/schema": "0.7.2-staging.6d26b2a",
|
|
44
|
+
"@dxos/util": "0.7.2-staging.6d26b2a"
|
|
47
45
|
},
|
|
48
46
|
"devDependencies": {
|
|
49
47
|
"@phosphor-icons/react": "^2.1.5",
|
|
@@ -54,12 +52,12 @@
|
|
|
54
52
|
"react": "~18.2.0",
|
|
55
53
|
"react-dom": "~18.2.0",
|
|
56
54
|
"vite": "5.4.7",
|
|
57
|
-
"@dxos/echo-signals": "0.7.
|
|
58
|
-
"@dxos/random": "0.7.
|
|
59
|
-
"@dxos/react-ui
|
|
60
|
-
"@dxos/react-ui": "0.7.
|
|
61
|
-
"@dxos/react-ui-theme": "0.7.
|
|
62
|
-
"@dxos/storybook-utils": "0.7.
|
|
55
|
+
"@dxos/echo-signals": "0.7.2-staging.6d26b2a",
|
|
56
|
+
"@dxos/random": "0.7.2-staging.6d26b2a",
|
|
57
|
+
"@dxos/react-ui": "0.7.2-staging.6d26b2a",
|
|
58
|
+
"@dxos/react-ui-syntax-highlighter": "0.7.2-staging.6d26b2a",
|
|
59
|
+
"@dxos/react-ui-theme": "0.7.2-staging.6d26b2a",
|
|
60
|
+
"@dxos/storybook-utils": "0.7.2-staging.6d26b2a"
|
|
63
61
|
},
|
|
64
62
|
"peerDependencies": {
|
|
65
63
|
"@effect/schema": "^0.75.5",
|
|
@@ -67,8 +65,8 @@
|
|
|
67
65
|
"effect": "^3.9.2",
|
|
68
66
|
"react": "~18.2.0",
|
|
69
67
|
"react-dom": "~18.2.0",
|
|
70
|
-
"@dxos/react-ui": "0.7.
|
|
71
|
-
"@dxos/react-ui-theme": "0.7.
|
|
68
|
+
"@dxos/react-ui": "0.7.2-staging.6d26b2a",
|
|
69
|
+
"@dxos/react-ui-theme": "0.7.2-staging.6d26b2a"
|
|
72
70
|
},
|
|
73
71
|
"publishConfig": {
|
|
74
72
|
"access": "public"
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import React from 'react';
|
|
6
6
|
|
|
7
|
-
import { type
|
|
7
|
+
import { type BaseObject, type GeoPoint } from '@dxos/echo-schema';
|
|
8
8
|
import { Input, useTranslation } from '@dxos/react-ui';
|
|
9
9
|
|
|
10
10
|
import { InputHeader, type InputProps } from './Input';
|
|
@@ -14,7 +14,7 @@ import { translationKey } from '../../translations';
|
|
|
14
14
|
// Custom format components.
|
|
15
15
|
//
|
|
16
16
|
|
|
17
|
-
export const
|
|
17
|
+
export const GeiPointInput = <T extends BaseObject>({
|
|
18
18
|
property,
|
|
19
19
|
type,
|
|
20
20
|
label,
|
|
@@ -26,7 +26,7 @@ export const LatLngInput = <T extends object>({
|
|
|
26
26
|
}: InputProps<T>) => {
|
|
27
27
|
const { t } = useTranslation(translationKey);
|
|
28
28
|
const { status, error } = getStatus?.(property);
|
|
29
|
-
const
|
|
29
|
+
const [lng = 0, lat = 0] = getValue<GeoPoint>(property) ?? [];
|
|
30
30
|
|
|
31
31
|
return (
|
|
32
32
|
<Input.Root validationValence={status}>
|
|
@@ -37,17 +37,17 @@ export const LatLngInput = <T extends object>({
|
|
|
37
37
|
<Input.TextInput
|
|
38
38
|
type='number'
|
|
39
39
|
disabled={disabled}
|
|
40
|
-
placeholder={t('placeholder
|
|
41
|
-
value={
|
|
42
|
-
onChange={(event) => onValueChange(property, type,
|
|
40
|
+
placeholder={t('placeholder longitude')}
|
|
41
|
+
value={lng}
|
|
42
|
+
onChange={(event) => onValueChange(property, type, [lat, safeParseFloat(event.target.value, 0)])}
|
|
43
43
|
onBlur={onBlur}
|
|
44
44
|
/>
|
|
45
45
|
<Input.TextInput
|
|
46
46
|
type='number'
|
|
47
47
|
disabled={disabled}
|
|
48
|
-
placeholder={t('placeholder
|
|
49
|
-
value={
|
|
50
|
-
onChange={(event) => onValueChange(property, type,
|
|
48
|
+
placeholder={t('placeholder latitude')}
|
|
49
|
+
value={lat}
|
|
50
|
+
onChange={(event) => onValueChange(property, type, [safeParseFloat(event.target.value, 0), lng])}
|
|
51
51
|
onBlur={onBlur}
|
|
52
52
|
/>
|
|
53
53
|
</div>
|
|
@@ -4,11 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
import React from 'react';
|
|
6
6
|
|
|
7
|
+
import { type BaseObject } from '@dxos/echo-schema';
|
|
7
8
|
import { Input, Select } from '@dxos/react-ui';
|
|
8
9
|
|
|
9
10
|
import { type InputProps, InputHeader } from './Input';
|
|
10
11
|
|
|
11
|
-
export const TextInput = <T extends
|
|
12
|
+
export const TextInput = <T extends BaseObject>({
|
|
12
13
|
property,
|
|
13
14
|
type,
|
|
14
15
|
label,
|
|
@@ -37,7 +38,7 @@ export const TextInput = <T extends object>({
|
|
|
37
38
|
);
|
|
38
39
|
};
|
|
39
40
|
|
|
40
|
-
export const NumberInput = <T extends
|
|
41
|
+
export const NumberInput = <T extends BaseObject>({
|
|
41
42
|
property,
|
|
42
43
|
type,
|
|
43
44
|
label,
|
|
@@ -68,7 +69,7 @@ export const NumberInput = <T extends object>({
|
|
|
68
69
|
);
|
|
69
70
|
};
|
|
70
71
|
|
|
71
|
-
export const BooleanInput = <T extends
|
|
72
|
+
export const BooleanInput = <T extends BaseObject>({
|
|
72
73
|
property,
|
|
73
74
|
type,
|
|
74
75
|
label,
|
|
@@ -91,7 +92,11 @@ export const BooleanInput = <T extends object>({
|
|
|
91
92
|
);
|
|
92
93
|
};
|
|
93
94
|
|
|
94
|
-
export
|
|
95
|
+
export type SelectInputOptions<T extends BaseObject> = InputProps<T> & {
|
|
96
|
+
options?: Array<{ value: string | number; label?: string }>;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
export const SelectInput = <T extends BaseObject>({
|
|
95
100
|
property,
|
|
96
101
|
type,
|
|
97
102
|
label,
|
|
@@ -101,7 +106,7 @@ export const SelectInput = <T extends object>({
|
|
|
101
106
|
getStatus,
|
|
102
107
|
getValue,
|
|
103
108
|
onValueChange,
|
|
104
|
-
}:
|
|
109
|
+
}: SelectInputOptions<T>) => {
|
|
105
110
|
const { status, error } = getStatus?.(property);
|
|
106
111
|
|
|
107
112
|
return (
|
|
@@ -26,7 +26,7 @@ const TestSchema = S.Struct({
|
|
|
26
26
|
street: S.optional(S.String.annotations({ [AST.TitleAnnotationId]: 'Street' })),
|
|
27
27
|
city: S.optional(S.String.annotations({ [AST.TitleAnnotationId]: 'City' })),
|
|
28
28
|
zip: S.optional(S.String.pipe(S.pattern(/^\d{5}(-\d{4})?$/)).annotations({ [AST.TitleAnnotationId]: 'ZIP' })),
|
|
29
|
-
location: S.optional(Format.
|
|
29
|
+
location: S.optional(Format.GeoPoint.annotations({ [AST.TitleAnnotationId]: 'Location' })),
|
|
30
30
|
}).annotations({ [AST.TitleAnnotationId]: 'Address' }),
|
|
31
31
|
),
|
|
32
32
|
}).pipe(S.mutable);
|
|
@@ -51,7 +51,7 @@ const DefaultStory = ({ values: initialValues }: StoryProps) => {
|
|
|
51
51
|
};
|
|
52
52
|
|
|
53
53
|
const meta: Meta<StoryProps> = {
|
|
54
|
-
title: 'ui/react-ui-
|
|
54
|
+
title: 'ui/react-ui-form/Form',
|
|
55
55
|
component: Form,
|
|
56
56
|
render: DefaultStory,
|
|
57
57
|
decorators: [withLayout({ fullscreen: true, tooltips: true }), withTheme],
|
|
@@ -2,16 +2,19 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { pipe } from 'effect';
|
|
6
|
+
import { capitalize } from 'effect/String';
|
|
5
7
|
import React, { useEffect, useMemo } from 'react';
|
|
6
8
|
|
|
7
|
-
import { AST, S } from '@dxos/echo-schema';
|
|
9
|
+
import { AST, type BaseObject, S, type PropertyKey } from '@dxos/echo-schema';
|
|
8
10
|
import { findNode, getDiscriminatedType, isDiscriminatedUnion } from '@dxos/effect';
|
|
9
11
|
import { log } from '@dxos/log';
|
|
10
12
|
import { IconButton, type ThemedClassName, useTranslation } from '@dxos/react-ui';
|
|
11
13
|
import { mx } from '@dxos/react-ui-theme';
|
|
12
|
-
import { getSchemaProperties, type
|
|
14
|
+
import { getSchemaProperties, type SchemaProperty } from '@dxos/schema';
|
|
13
15
|
import { isNotFalsy } from '@dxos/util';
|
|
14
16
|
|
|
17
|
+
import { SelectInput } from './Defaults';
|
|
15
18
|
import { type InputComponent } from './Input';
|
|
16
19
|
import { getInputComponent } from './factory';
|
|
17
20
|
import { type FormOptions, useForm } from '../../hooks';
|
|
@@ -21,9 +24,9 @@ import { translationKey } from '../../translations';
|
|
|
21
24
|
|
|
22
25
|
const padding = 'px-2';
|
|
23
26
|
|
|
24
|
-
export type PropsFilter<T extends
|
|
27
|
+
export type PropsFilter<T extends BaseObject> = (props: SchemaProperty<T>[]) => SchemaProperty<T>[];
|
|
25
28
|
|
|
26
|
-
export type FormProps<T extends
|
|
29
|
+
export type FormProps<T extends BaseObject> = ThemedClassName<
|
|
27
30
|
{
|
|
28
31
|
values: T;
|
|
29
32
|
/** Path to the current object from the root. Used with nested forms. */
|
|
@@ -48,7 +51,7 @@ export type FormProps<T extends object> = ThemedClassName<
|
|
|
48
51
|
/**
|
|
49
52
|
* General purpose form component that displays field controls based on the given schema.
|
|
50
53
|
*/
|
|
51
|
-
export const Form = <T extends
|
|
54
|
+
export const Form = <T extends BaseObject>({
|
|
52
55
|
classNames,
|
|
53
56
|
schema,
|
|
54
57
|
values: initialValues,
|
|
@@ -76,7 +79,7 @@ export const Form = <T extends object = {}>({
|
|
|
76
79
|
|
|
77
80
|
// Filter and sort props.
|
|
78
81
|
// TODO(burdon): Move into useForm?
|
|
79
|
-
const
|
|
82
|
+
const properties = useMemo(() => {
|
|
80
83
|
const props = getSchemaProperties<T>(schema.ast, values);
|
|
81
84
|
const filtered = filter ? filter(props) : props;
|
|
82
85
|
const findIndex = (props: PropertyKey<T>[], prop: PropertyKey<T>) => {
|
|
@@ -96,25 +99,50 @@ export const Form = <T extends object = {}>({
|
|
|
96
99
|
|
|
97
100
|
return (
|
|
98
101
|
<div role='form' className={mx('flex flex-col w-full gap-2 py-2', classNames)}>
|
|
99
|
-
{
|
|
100
|
-
.map((
|
|
101
|
-
|
|
102
|
-
// TODO(burdon): Use Select control if options are present in annotation?
|
|
102
|
+
{properties
|
|
103
|
+
.map((property) => {
|
|
104
|
+
const { ast, name, type, format, title, description, examples, options } = property;
|
|
103
105
|
const key = [...path, name];
|
|
104
|
-
const
|
|
106
|
+
const label = pipe(title ?? name, capitalize);
|
|
107
|
+
const placeholder = examples?.length ? `Example: "${examples[0]}"` : description;
|
|
108
|
+
|
|
109
|
+
// Get generic input.
|
|
110
|
+
let InputComponent = Custom?.[key.join('.')];
|
|
111
|
+
if (!InputComponent) {
|
|
112
|
+
// Select.
|
|
113
|
+
if (options) {
|
|
114
|
+
return (
|
|
115
|
+
<div key={name} role='none' className={padding}>
|
|
116
|
+
<SelectInput
|
|
117
|
+
type={type}
|
|
118
|
+
format={format}
|
|
119
|
+
property={name}
|
|
120
|
+
disabled={readonly}
|
|
121
|
+
label={label}
|
|
122
|
+
options={options.map((option) => ({ value: option, label: String(option) }))}
|
|
123
|
+
placeholder={placeholder}
|
|
124
|
+
{...inputProps}
|
|
125
|
+
/>
|
|
126
|
+
</div>
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
InputComponent = getInputComponent<T>(type, format);
|
|
131
|
+
}
|
|
132
|
+
|
|
105
133
|
if (!InputComponent) {
|
|
106
134
|
// Recursively render form.
|
|
107
135
|
if (type === 'object') {
|
|
108
|
-
const baseNode = findNode(
|
|
136
|
+
const baseNode = findNode(ast, isDiscriminatedUnion);
|
|
109
137
|
const typeLiteral = baseNode
|
|
110
138
|
? getDiscriminatedType(baseNode, values[name] as any)
|
|
111
|
-
: findNode(
|
|
139
|
+
: findNode(ast, AST.isTypeLiteral);
|
|
112
140
|
|
|
113
141
|
if (typeLiteral) {
|
|
114
142
|
const schema = S.make(typeLiteral);
|
|
115
143
|
return (
|
|
116
144
|
<div key={name} role='none'>
|
|
117
|
-
<div className={padding}>{
|
|
145
|
+
<div className={padding}>{label}</div>
|
|
118
146
|
<Form<any>
|
|
119
147
|
schema={schema}
|
|
120
148
|
path={key}
|
|
@@ -133,8 +161,6 @@ export const Form = <T extends object = {}>({
|
|
|
133
161
|
return null;
|
|
134
162
|
}
|
|
135
163
|
|
|
136
|
-
const placeholder = examples?.length ? `Example: ${examples[0]}` : description;
|
|
137
|
-
|
|
138
164
|
return (
|
|
139
165
|
<div key={name} role='none' className={padding}>
|
|
140
166
|
<InputComponent
|
|
@@ -142,7 +168,7 @@ export const Form = <T extends object = {}>({
|
|
|
142
168
|
format={format}
|
|
143
169
|
property={name}
|
|
144
170
|
disabled={readonly}
|
|
145
|
-
label={
|
|
171
|
+
label={label}
|
|
146
172
|
placeholder={placeholder}
|
|
147
173
|
{...inputProps}
|
|
148
174
|
/>
|
|
@@ -151,8 +177,6 @@ export const Form = <T extends object = {}>({
|
|
|
151
177
|
})
|
|
152
178
|
.filter(isNotFalsy)}
|
|
153
179
|
|
|
154
|
-
{/* {errors && <div className='overflow-hidden text-sm'>{JSON.stringify(errors)}</div>} */}
|
|
155
|
-
|
|
156
180
|
{(onCancel || onSubmit) && !autoSave && (
|
|
157
181
|
<div role='none' className='flex justify-center'>
|
|
158
182
|
<div role='none' className={mx(onCancel && !readonly && 'grid grid-cols-2 gap-2')}>
|
|
@@ -4,33 +4,29 @@
|
|
|
4
4
|
|
|
5
5
|
import React, { type FC, type PropsWithChildren } from 'react';
|
|
6
6
|
|
|
7
|
-
import { type FormatEnum } from '@dxos/echo-schema';
|
|
7
|
+
import { type BaseObject, type FormatEnum, type PropertyKey } from '@dxos/echo-schema';
|
|
8
8
|
import { type SimpleType } from '@dxos/effect';
|
|
9
9
|
import { Icon, Tooltip } from '@dxos/react-ui';
|
|
10
10
|
import { errorText } from '@dxos/react-ui-theme';
|
|
11
|
-
import { type PropertyKey } from '@dxos/schema';
|
|
12
11
|
|
|
13
12
|
import { type FormHandler } from '../../hooks';
|
|
14
13
|
|
|
15
14
|
/**
|
|
16
15
|
* Props passed to input components.
|
|
17
16
|
*/
|
|
18
|
-
export type InputProps<T extends
|
|
17
|
+
export type InputProps<T extends BaseObject> = {
|
|
19
18
|
property: PropertyKey<T>;
|
|
20
19
|
type: SimpleType;
|
|
21
20
|
format?: FormatEnum;
|
|
22
21
|
label: string;
|
|
23
22
|
disabled?: boolean;
|
|
24
23
|
placeholder?: string;
|
|
25
|
-
// TODO(burdon): Provide from annotations? E.g., enum.
|
|
26
|
-
options?: Array<{ value: string | number; label?: string }>;
|
|
27
24
|
} & Pick<FormHandler<T>, 'getStatus' | 'getValue' | 'onValueChange' | 'onBlur'>;
|
|
28
25
|
|
|
29
26
|
/**
|
|
30
27
|
* Form input component.
|
|
31
28
|
*/
|
|
32
|
-
|
|
33
|
-
export type InputComponent<T extends object = {}> = FC<InputProps<T>>;
|
|
29
|
+
export type InputComponent<T extends BaseObject> = FC<InputProps<T>>;
|
|
34
30
|
|
|
35
31
|
export type InputHeaderProps = PropsWithChildren<{
|
|
36
32
|
error?: string;
|
|
@@ -2,23 +2,23 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { FormatEnum } from '@dxos/echo-schema';
|
|
5
|
+
import { type BaseObject, FormatEnum } from '@dxos/echo-schema';
|
|
6
6
|
import { type SimpleType } from '@dxos/effect';
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import { GeiPointInput } from './Custom';
|
|
9
9
|
import { BooleanInput, NumberInput, TextInput } from './Defaults';
|
|
10
10
|
import { type InputComponent } from './Input';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Get property input component.
|
|
14
14
|
*/
|
|
15
|
-
export const getInputComponent = <T extends
|
|
15
|
+
export const getInputComponent = <T extends BaseObject>(
|
|
16
16
|
type: SimpleType,
|
|
17
17
|
format?: FormatEnum,
|
|
18
18
|
): InputComponent<T> | undefined => {
|
|
19
19
|
switch (format) {
|
|
20
20
|
case FormatEnum.LatLng:
|
|
21
|
-
return
|
|
21
|
+
return GeiPointInput;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
switch (type) {
|
|
@@ -10,8 +10,7 @@ import React, { useCallback, useEffect, useState } from 'react';
|
|
|
10
10
|
import { Format, type MutableSchema, S, toJsonSchema, TypedObject } from '@dxos/echo-schema';
|
|
11
11
|
import { useSpace } from '@dxos/react-client/echo';
|
|
12
12
|
import { withClientProvider } from '@dxos/react-client/testing';
|
|
13
|
-
import { ViewProjection, createView } from '@dxos/schema';
|
|
14
|
-
import { type ViewType } from '@dxos/schema';
|
|
13
|
+
import { type ViewType, ViewProjection, createView } from '@dxos/schema';
|
|
15
14
|
import { withTheme, withLayout } from '@dxos/storybook-utils';
|
|
16
15
|
|
|
17
16
|
import { ViewEditor } from './ViewEditor';
|
package/src/hooks/useForm.ts
CHANGED
|
@@ -4,15 +4,16 @@
|
|
|
4
4
|
|
|
5
5
|
import { type FocusEvent, useCallback, useEffect, useMemo, useState } from 'react';
|
|
6
6
|
|
|
7
|
+
import { type BaseObject, type PropertyKey } from '@dxos/echo-schema';
|
|
7
8
|
import { type SimpleType, type S } from '@dxos/effect';
|
|
8
9
|
import { invariant } from '@dxos/invariant';
|
|
9
10
|
import { log } from '@dxos/log';
|
|
10
|
-
import { validateSchema, type
|
|
11
|
+
import { validateSchema, type ValidationError } from '@dxos/schema';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Return type from `useForm` hook.
|
|
14
15
|
*/
|
|
15
|
-
export type FormHandler<T extends
|
|
16
|
+
export type FormHandler<T extends BaseObject> = {
|
|
16
17
|
//
|
|
17
18
|
// Form state management.
|
|
18
19
|
//
|
|
@@ -37,7 +38,7 @@ export type FormHandler<T extends object = {}> = {
|
|
|
37
38
|
/**
|
|
38
39
|
* Hook options.
|
|
39
40
|
*/
|
|
40
|
-
export interface FormOptions<T extends
|
|
41
|
+
export interface FormOptions<T extends BaseObject> {
|
|
41
42
|
schema: S.Schema<T>;
|
|
42
43
|
|
|
43
44
|
// TODO(burdon): Are these reactive?
|
|
@@ -73,7 +74,7 @@ export interface FormOptions<T extends object> {
|
|
|
73
74
|
* Creates a hook for managing form state, including values, validation, and submission.
|
|
74
75
|
* Deeply integrated with `@dxos/schema` for schema-based validation.
|
|
75
76
|
*/
|
|
76
|
-
export const useForm = <T extends
|
|
77
|
+
export const useForm = <T extends BaseObject>({
|
|
77
78
|
schema,
|
|
78
79
|
initialValues,
|
|
79
80
|
onValuesChanged,
|
|
@@ -211,12 +212,12 @@ export const useForm = <T extends object>({
|
|
|
211
212
|
} satisfies FormHandler<T>;
|
|
212
213
|
};
|
|
213
214
|
|
|
214
|
-
const createKeySet = <T extends
|
|
215
|
+
const createKeySet = <T extends BaseObject, V>(obj: T, value: V): Record<PropertyKey<T>, V> => {
|
|
215
216
|
invariant(obj);
|
|
216
217
|
return Object.keys(obj).reduce((acc, key) => ({ ...acc, [key]: value }), {} as Record<PropertyKey<T>, V>);
|
|
217
218
|
};
|
|
218
219
|
|
|
219
|
-
const flatMap = <T extends
|
|
220
|
+
const flatMap = <T extends BaseObject>(errors: ValidationError[]) => {
|
|
220
221
|
return errors.reduce(
|
|
221
222
|
(result, { path, message }) => {
|
|
222
223
|
if (!(path in result)) {
|