@dxos/react-ui-form 0.8.4-main.422d1c7879 → 0.8.4-main.4f23b4e393
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 +148 -273
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/translations.mjs +82 -0
- package/dist/lib/browser/translations.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +148 -273
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/translations.mjs +84 -0
- package/dist/lib/node-esm/translations.mjs.map +7 -0
- package/dist/types/src/components/FieldEditor/FieldEditor.d.ts.map +1 -1
- package/dist/types/src/components/FieldEditor/FieldEditor.stories.d.ts +63 -63
- package/dist/types/src/components/FieldEditor/FieldEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/Form/Form.d.ts +19 -3
- package/dist/types/src/components/Form/Form.d.ts.map +1 -1
- package/dist/types/src/components/Form/Form.stories.d.ts +72 -72
- package/dist/types/src/components/Form/Form.stories.d.ts.map +1 -1
- package/dist/types/src/components/Form/FormField.d.ts +4 -4
- package/dist/types/src/components/Form/FormField.d.ts.map +1 -1
- package/dist/types/src/components/Form/FormFieldComponent.d.ts +5 -6
- package/dist/types/src/components/Form/FormFieldComponent.d.ts.map +1 -1
- package/dist/types/src/components/Form/FormFieldComponent.stories.d.ts.map +1 -1
- package/dist/types/src/components/Form/FormFieldSet.d.ts +4 -7
- package/dist/types/src/components/Form/FormFieldSet.d.ts.map +1 -1
- package/dist/types/src/components/Form/fields/ArrayField.d.ts +4 -4
- package/dist/types/src/components/Form/fields/ArrayField.d.ts.map +1 -1
- package/dist/types/src/components/Form/fields/BooleanField.d.ts.map +1 -1
- package/dist/types/src/components/Form/fields/GeoPointField.d.ts.map +1 -1
- package/dist/types/src/components/Form/fields/MarkdownField.d.ts.map +1 -1
- package/dist/types/src/components/Form/fields/MarkdownField.stories.d.ts +64 -63
- package/dist/types/src/components/Form/fields/MarkdownField.stories.d.ts.map +1 -1
- package/dist/types/src/components/Form/fields/NumberField.d.ts.map +1 -1
- package/dist/types/src/components/Form/fields/RefField.d.ts.map +1 -1
- package/dist/types/src/components/Form/fields/SelectField.d.ts.map +1 -1
- package/dist/types/src/components/Form/fields/SelectOptionField.d.ts.map +1 -1
- package/dist/types/src/components/Form/fields/SelectOptionField.stories.d.ts +63 -63
- package/dist/types/src/components/Form/fields/SelectOptionField.stories.d.ts.map +1 -1
- package/dist/types/src/components/Form/fields/TextAreaField.d.ts.map +1 -1
- package/dist/types/src/components/Form/fields/TextField.d.ts.map +1 -1
- package/dist/types/src/components/Form/fields/TupleField.d.ts.map +1 -1
- package/dist/types/src/components/ObjectForm/ObjectForm.d.ts.map +1 -1
- package/dist/types/src/components/ObjectPicker/ObjectPicker.d.ts +1 -1
- package/dist/types/src/components/ObjectPicker/ObjectPicker.d.ts.map +1 -1
- package/dist/types/src/components/ObjectPicker/ObjectPicker.stories.d.ts +63 -63
- package/dist/types/src/components/ObjectPicker/ObjectPicker.stories.d.ts.map +1 -1
- package/dist/types/src/components/ObjectProperties/ObjectProperties.d.ts +1 -1
- package/dist/types/src/components/ObjectProperties/ObjectProperties.d.ts.map +1 -1
- package/dist/types/src/components/ObjectProperties/ObjectProperties.stories.d.ts +63 -63
- package/dist/types/src/components/ObjectProperties/ObjectProperties.stories.d.ts.map +1 -1
- package/dist/types/src/components/Settings/Settings.d.ts +10 -2
- package/dist/types/src/components/Settings/Settings.d.ts.map +1 -1
- package/dist/types/src/components/Settings/Settings.stories.d.ts +63 -63
- package/dist/types/src/components/Settings/Settings.stories.d.ts.map +1 -1
- package/dist/types/src/components/Settings/SettingsFieldSet.d.ts +15 -10
- package/dist/types/src/components/Settings/SettingsFieldSet.d.ts.map +1 -1
- package/dist/types/src/components/Settings/SettingsItem.d.ts +8 -9
- package/dist/types/src/components/Settings/SettingsItem.d.ts.map +1 -1
- package/dist/types/src/components/Settings/SettingsSelectField.d.ts +18 -0
- package/dist/types/src/components/Settings/SettingsSelectField.d.ts.map +1 -0
- package/dist/types/src/components/Settings/index.d.ts +1 -0
- package/dist/types/src/components/Settings/index.d.ts.map +1 -1
- package/dist/types/src/components/ViewEditor/ViewEditor.d.ts +3 -4
- package/dist/types/src/components/ViewEditor/ViewEditor.d.ts.map +1 -1
- package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts +63 -63
- 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/useFormHandler.d.ts.map +1 -1
- package/dist/types/src/hooks/useKeyHandler.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +0 -2
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +63 -63
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/util/field-type.d.ts +1 -1
- package/dist/types/src/util/field-type.d.ts.map +1 -1
- package/dist/types/src/util/field.d.ts.map +1 -1
- package/dist/types/src/util/formatting.d.ts.map +1 -1
- package/dist/types/src/util/properties.d.ts.map +1 -1
- package/dist/types/src/util/refs.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +39 -30
- package/src/components/FieldEditor/FieldEditor.stories.tsx +2 -1
- package/src/components/FieldEditor/FieldEditor.tsx +3 -2
- package/src/components/Form/Form.stories.tsx +2 -1
- package/src/components/Form/Form.tsx +3 -3
- package/src/components/Form/FormField.tsx +2 -1
- package/src/components/Form/FormFieldComponent.tsx +3 -3
- package/src/components/Form/fields/ArrayField.tsx +6 -9
- package/src/components/Form/fields/GeoPointField.tsx +3 -2
- package/src/components/Form/fields/MarkdownField.stories.tsx +56 -1
- package/src/components/Form/fields/MarkdownField.tsx +2 -1
- package/src/components/Form/fields/RefField.tsx +4 -3
- package/src/components/Form/fields/SelectOptionField.stories.tsx +2 -1
- package/src/components/Form/fields/SelectOptionField.tsx +6 -5
- package/src/components/ObjectForm/ObjectForm.tsx +6 -5
- package/src/components/ObjectPicker/ObjectPicker.stories.tsx +8 -5
- package/src/components/ObjectPicker/ObjectPicker.tsx +18 -9
- package/src/components/ObjectProperties/ObjectProperties.stories.tsx +2 -1
- package/src/components/ObjectProperties/ObjectProperties.tsx +5 -4
- package/src/components/Settings/AUDIT.md +52 -0
- package/src/components/Settings/Settings.stories.tsx +2 -1
- package/src/components/Settings/Settings.tsx +3 -4
- package/src/components/Settings/SettingsFieldSet.tsx +55 -9
- package/src/components/Settings/SettingsItem.tsx +4 -8
- package/src/components/Settings/SettingsSelectField.tsx +59 -0
- package/src/components/Settings/index.ts +1 -0
- package/src/components/ViewEditor/ViewEditor.stories.tsx +7 -7
- package/src/components/ViewEditor/ViewEditor.tsx +17 -24
- package/src/components/testing.tsx +1 -1
- package/src/index.ts +0 -4
- package/src/util/field-type.ts +4 -1
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.4f23b4e393",
|
|
4
4
|
"description": "Data components.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -11,12 +11,21 @@
|
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"author": "DXOS.org",
|
|
13
13
|
"type": "module",
|
|
14
|
+
"imports": {
|
|
15
|
+
"#translations": "./src/translations.ts"
|
|
16
|
+
},
|
|
14
17
|
"exports": {
|
|
15
18
|
".": {
|
|
16
19
|
"source": "./src/index.ts",
|
|
17
20
|
"types": "./dist/types/src/index.d.ts",
|
|
18
21
|
"browser": "./dist/lib/browser/index.mjs",
|
|
19
22
|
"node": "./dist/lib/node-esm/index.mjs"
|
|
23
|
+
},
|
|
24
|
+
"./translations": {
|
|
25
|
+
"source": "./src/translations.ts",
|
|
26
|
+
"types": "./dist/types/src/translations.d.ts",
|
|
27
|
+
"browser": "./dist/lib/browser/translations.mjs",
|
|
28
|
+
"node": "./dist/lib/node-esm/translations.mjs"
|
|
20
29
|
}
|
|
21
30
|
},
|
|
22
31
|
"types": "dist/types/src/index.d.ts",
|
|
@@ -31,26 +40,26 @@
|
|
|
31
40
|
"@radix-ui/react-use-controllable-state": "1.1.0",
|
|
32
41
|
"date-fns": "^3.6.0",
|
|
33
42
|
"tabster": "^8.5.5",
|
|
34
|
-
"@dxos/
|
|
35
|
-
"@dxos/
|
|
36
|
-
"@dxos/echo-
|
|
37
|
-
"@dxos/
|
|
38
|
-
"@dxos/
|
|
39
|
-
"@dxos/
|
|
40
|
-
"@dxos/
|
|
41
|
-
"@dxos/
|
|
42
|
-
"@dxos/
|
|
43
|
-
"@dxos/
|
|
44
|
-
"@dxos/react-ui-components": "0.8.4-main.
|
|
45
|
-
"@dxos/react-
|
|
46
|
-
"@dxos/react-ui-
|
|
47
|
-
"@dxos/react-ui-
|
|
48
|
-
"@dxos/react-ui-search": "0.8.4-main.
|
|
49
|
-
"@dxos/schema": "0.8.4-main.
|
|
50
|
-
"@dxos/
|
|
51
|
-
"@dxos/
|
|
52
|
-
"@dxos/
|
|
53
|
-
"@dxos/
|
|
43
|
+
"@dxos/echo": "0.8.4-main.4f23b4e393",
|
|
44
|
+
"@dxos/async": "0.8.4-main.4f23b4e393",
|
|
45
|
+
"@dxos/echo-react": "0.8.4-main.4f23b4e393",
|
|
46
|
+
"@dxos/effect": "0.8.4-main.4f23b4e393",
|
|
47
|
+
"@dxos/echo-atom": "0.8.4-main.4f23b4e393",
|
|
48
|
+
"@dxos/echo-db": "0.8.4-main.4f23b4e393",
|
|
49
|
+
"@dxos/invariant": "0.8.4-main.4f23b4e393",
|
|
50
|
+
"@dxos/keys": "0.8.4-main.4f23b4e393",
|
|
51
|
+
"@dxos/react-client": "0.8.4-main.4f23b4e393",
|
|
52
|
+
"@dxos/lit-ui": "0.8.4-main.4f23b4e393",
|
|
53
|
+
"@dxos/react-ui-components": "0.8.4-main.4f23b4e393",
|
|
54
|
+
"@dxos/react-ui-editor": "0.8.4-main.4f23b4e393",
|
|
55
|
+
"@dxos/react-ui-list": "0.8.4-main.4f23b4e393",
|
|
56
|
+
"@dxos/react-ui-pickers": "0.8.4-main.4f23b4e393",
|
|
57
|
+
"@dxos/react-ui-search": "0.8.4-main.4f23b4e393",
|
|
58
|
+
"@dxos/schema": "0.8.4-main.4f23b4e393",
|
|
59
|
+
"@dxos/types": "0.8.4-main.4f23b4e393",
|
|
60
|
+
"@dxos/ui-editor": "0.8.4-main.4f23b4e393",
|
|
61
|
+
"@dxos/log": "0.8.4-main.4f23b4e393",
|
|
62
|
+
"@dxos/util": "0.8.4-main.4f23b4e393"
|
|
54
63
|
},
|
|
55
64
|
"devDependencies": {
|
|
56
65
|
"@types/react": "~19.2.7",
|
|
@@ -59,20 +68,20 @@
|
|
|
59
68
|
"fast-check": "^3.19.0",
|
|
60
69
|
"react": "~19.2.3",
|
|
61
70
|
"react-dom": "~19.2.3",
|
|
62
|
-
"vite": "^
|
|
63
|
-
"@dxos/random": "0.8.4-main.
|
|
64
|
-
"@dxos/react-client": "0.8.4-main.
|
|
65
|
-
"@dxos/react-ui": "0.8.4-main.
|
|
66
|
-
"@dxos/react-ui-syntax-highlighter": "0.8.4-main.
|
|
67
|
-
"@dxos/ui-theme": "0.8.4-main.
|
|
68
|
-
"@dxos/storybook-utils": "0.8.4-main.
|
|
71
|
+
"vite": "^8.0.10",
|
|
72
|
+
"@dxos/random": "0.8.4-main.4f23b4e393",
|
|
73
|
+
"@dxos/react-client": "0.8.4-main.4f23b4e393",
|
|
74
|
+
"@dxos/react-ui": "0.8.4-main.4f23b4e393",
|
|
75
|
+
"@dxos/react-ui-syntax-highlighter": "0.8.4-main.4f23b4e393",
|
|
76
|
+
"@dxos/ui-theme": "0.8.4-main.4f23b4e393",
|
|
77
|
+
"@dxos/storybook-utils": "0.8.4-main.4f23b4e393"
|
|
69
78
|
},
|
|
70
79
|
"peerDependencies": {
|
|
71
80
|
"effect": "3.20.0",
|
|
72
81
|
"react": "~19.2.3",
|
|
73
82
|
"react-dom": "~19.2.3",
|
|
74
|
-
"@dxos/
|
|
75
|
-
"@dxos/ui
|
|
83
|
+
"@dxos/ui-theme": "0.8.4-main.4f23b4e393",
|
|
84
|
+
"@dxos/react-ui": "0.8.4-main.4f23b4e393"
|
|
76
85
|
},
|
|
77
86
|
"publishConfig": {
|
|
78
87
|
"access": "public"
|
|
@@ -12,7 +12,8 @@ import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
|
12
12
|
import { ProjectionModel, ViewModel, createEchoChangeCallback } from '@dxos/schema';
|
|
13
13
|
import { Example } from '@dxos/schema/testing';
|
|
14
14
|
|
|
15
|
-
import { translations } from '
|
|
15
|
+
import { translations } from '#translations';
|
|
16
|
+
|
|
16
17
|
import { FIELD_EDITOR_DEBUG_SYMBOL, TestLayout } from '../testing';
|
|
17
18
|
import { FieldEditor, type FieldEditorProps } from './FieldEditor';
|
|
18
19
|
|
|
@@ -16,7 +16,8 @@ import {
|
|
|
16
16
|
getFormatSchema,
|
|
17
17
|
} from '@dxos/schema';
|
|
18
18
|
|
|
19
|
-
import { translationKey } from '
|
|
19
|
+
import { translationKey } from '#translations';
|
|
20
|
+
|
|
20
21
|
import { getFormProperties } from '../../util';
|
|
21
22
|
import { Form, type FormFieldMap, type FormRootProps, SelectField, SelectOptionField } from '../Form';
|
|
22
23
|
|
|
@@ -151,7 +152,7 @@ export const FieldEditor = ({ readonly, projection, field, registry, view, onSav
|
|
|
151
152
|
const handleSave = useCallback<NonNullable<FormRootProps<PropertyType>['onSave']>>(
|
|
152
153
|
(props) => {
|
|
153
154
|
if (view) {
|
|
154
|
-
Obj.
|
|
155
|
+
Obj.update(view, () => {
|
|
155
156
|
projection.setFieldProjection({ field, props });
|
|
156
157
|
});
|
|
157
158
|
} else {
|
|
@@ -14,7 +14,8 @@ import { withClientProvider } from '@dxos/react-client/testing';
|
|
|
14
14
|
import { Tooltip } from '@dxos/react-ui';
|
|
15
15
|
import { Loading, withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
16
16
|
|
|
17
|
-
import { translations } from '
|
|
17
|
+
import { translations } from '#translations';
|
|
18
|
+
|
|
18
19
|
import { TestLayout } from '../testing';
|
|
19
20
|
import { type ExcludeId, Form, type FormRootProps, omitId } from './Form';
|
|
20
21
|
|
|
@@ -21,6 +21,8 @@ import {
|
|
|
21
21
|
} from '@dxos/react-ui';
|
|
22
22
|
import { composable, composableProps, mx, withColumn } from '@dxos/ui-theme';
|
|
23
23
|
|
|
24
|
+
import { translationKey } from '#translations';
|
|
25
|
+
|
|
24
26
|
import {
|
|
25
27
|
type FormHandler,
|
|
26
28
|
type FormHandlerProps,
|
|
@@ -28,7 +30,6 @@ import {
|
|
|
28
30
|
useFormHandler,
|
|
29
31
|
useKeyHandler,
|
|
30
32
|
} from '../../hooks';
|
|
31
|
-
import { translationKey } from '../../translations';
|
|
32
33
|
import { FormFieldLabel, type FormFieldLabelProps, type FormFieldStateProps } from './FormFieldComponent';
|
|
33
34
|
import {
|
|
34
35
|
FormFieldSet as NaturalFormFieldSet,
|
|
@@ -265,7 +266,6 @@ const FormActions = ({ classNames }: FormActionsProps) => {
|
|
|
265
266
|
|
|
266
267
|
return (
|
|
267
268
|
<div
|
|
268
|
-
role='none'
|
|
269
269
|
className={mx(withColumn.center(), 'grid grid-flow-col gap-form-gap auto-cols-fr py-form-padding', classNames)}
|
|
270
270
|
>
|
|
271
271
|
{onCancel && (
|
|
@@ -341,7 +341,7 @@ const FormSubmit = ({ classNames, label, icon, disabled }: FormSubmitProps) => {
|
|
|
341
341
|
}
|
|
342
342
|
|
|
343
343
|
return (
|
|
344
|
-
<div
|
|
344
|
+
<div className={mx('flex w-full pt-form-padding', classNames)}>
|
|
345
345
|
<IconButton
|
|
346
346
|
classNames='w-full'
|
|
347
347
|
type='submit'
|
|
@@ -23,7 +23,8 @@ import {
|
|
|
23
23
|
import { useTranslation } from '@dxos/react-ui';
|
|
24
24
|
import { type ProjectionModel } from '@dxos/schema';
|
|
25
25
|
|
|
26
|
-
import { translationKey } from '
|
|
26
|
+
import { translationKey } from '#translations';
|
|
27
|
+
|
|
27
28
|
import { getRefProps } from '../../util';
|
|
28
29
|
import {
|
|
29
30
|
ArrayField,
|
|
@@ -80,7 +80,7 @@ export type FormFieldLabelProps = {
|
|
|
80
80
|
export const FormFieldLabel = ({ label, error, readonly, asChild }: FormFieldLabelProps) => {
|
|
81
81
|
const Label = readonly || asChild ? 'span' : Input.Label;
|
|
82
82
|
return (
|
|
83
|
-
<div
|
|
83
|
+
<div className='flex items-center justify-between'>
|
|
84
84
|
<Label className={inputTextLabel}>{label}</Label>
|
|
85
85
|
{error && (
|
|
86
86
|
<Tooltip.Trigger asChild content={error} side='bottom'>
|
|
@@ -116,7 +116,7 @@ export const FormFieldWrapper = <T,>(props: FormFieldWrapperProps<T>) => {
|
|
|
116
116
|
const str = String(value ?? '');
|
|
117
117
|
|
|
118
118
|
return (
|
|
119
|
-
<div
|
|
119
|
+
<div className='contents'>
|
|
120
120
|
<Input.Root validationValence={status}>
|
|
121
121
|
{layout !== 'inline' && <FormFieldLabel error={error} readonly={readonly} label={label} />}
|
|
122
122
|
{layout === 'static' ? <p>{str}</p> : children ? children({ value }) : null}
|
|
@@ -159,7 +159,7 @@ export class FormFieldErrorBoundary extends Component<FormFieldErrorBoundaryProp
|
|
|
159
159
|
if (this.state.error) {
|
|
160
160
|
return (
|
|
161
161
|
<div className='flex gap-2 border border-rose-fill font-mono text-sm'>
|
|
162
|
-
<span className='bg-rose-fill text-
|
|
162
|
+
<span className='bg-rose-fill text-base-foreground px-1 font-thin'>ERROR</span>
|
|
163
163
|
{String(this.props.path?.join('.'))}
|
|
164
164
|
</div>
|
|
165
165
|
);
|
|
@@ -9,7 +9,8 @@ import React, { useCallback } from 'react';
|
|
|
9
9
|
import { findNode, getArrayElementType, getDiscriminatedType, isDiscriminatedUnion, isNestedType } from '@dxos/effect';
|
|
10
10
|
import { IconButton, useTranslation } from '@dxos/react-ui';
|
|
11
11
|
|
|
12
|
-
import { translationKey } from '
|
|
12
|
+
import { translationKey } from '#translations';
|
|
13
|
+
|
|
13
14
|
import { getFormProperties } from '../../../util';
|
|
14
15
|
import { useFormValues } from '../Form';
|
|
15
16
|
import { FormField, type FormFieldProps } from '../FormField';
|
|
@@ -77,14 +78,10 @@ export const ArrayField = ({
|
|
|
77
78
|
<FormFieldLabel readonly={readonly} label={label} asChild />
|
|
78
79
|
)}
|
|
79
80
|
|
|
80
|
-
<div
|
|
81
|
+
<div className='flex flex-col gap-form-gap'>
|
|
81
82
|
{values?.map((_, index) => {
|
|
82
83
|
return (
|
|
83
|
-
<div
|
|
84
|
-
role='none'
|
|
85
|
-
key={index}
|
|
86
|
-
className='grid grid-cols-[1fr_min-content] gap-form-gap last:mb-form-gap items-center'
|
|
87
|
-
>
|
|
84
|
+
<div key={index} className='grid grid-cols-[1fr_min-content] gap-form-gap last:mb-form-gap items-center'>
|
|
88
85
|
<FormField
|
|
89
86
|
autoFocus={index === values.length - 1}
|
|
90
87
|
type={elementType}
|
|
@@ -95,9 +92,9 @@ export const ArrayField = ({
|
|
|
95
92
|
/>
|
|
96
93
|
|
|
97
94
|
{!readonly && layout !== 'static' && (
|
|
98
|
-
<div
|
|
95
|
+
<div className='flex flex-col h-full justify-end'>
|
|
99
96
|
{/* NOTE: Aligns with center of last field if multi-field object. */}
|
|
100
|
-
<div
|
|
97
|
+
<div className='flex items-center h-[2rem]'>
|
|
101
98
|
<IconButton
|
|
102
99
|
icon='ph--x--regular'
|
|
103
100
|
iconOnly
|
|
@@ -8,7 +8,8 @@ import { GeoLocation, type GeoPoint } from '@dxos/echo/internal';
|
|
|
8
8
|
import { Input, useTranslation } from '@dxos/react-ui';
|
|
9
9
|
import { safeParseFloat } from '@dxos/util';
|
|
10
10
|
|
|
11
|
-
import { translationKey } from '
|
|
11
|
+
import { translationKey } from '#translations';
|
|
12
|
+
|
|
12
13
|
import { type FormFieldComponentProps, FormFieldLabel } from '../FormFieldComponent';
|
|
13
14
|
|
|
14
15
|
export const GeoPointField = ({
|
|
@@ -62,7 +63,7 @@ export const GeoPointField = ({
|
|
|
62
63
|
{layout === 'static' ? (
|
|
63
64
|
<LatLng {...value} />
|
|
64
65
|
) : (
|
|
65
|
-
<div
|
|
66
|
+
<div className='grid grid-cols-2 gap-form-gap'>
|
|
66
67
|
<div>
|
|
67
68
|
<Input.Root>
|
|
68
69
|
{layout !== 'inline' && <Input.Label>{t('latitude.label')}</Input.Label>}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
6
6
|
import * as Schema from 'effect/Schema';
|
|
7
7
|
import React, { useMemo } from 'react';
|
|
8
|
+
import { expect, userEvent } from 'storybook/test';
|
|
8
9
|
|
|
9
10
|
import { Filter, Format, Obj, Ref } from '@dxos/echo';
|
|
10
11
|
import { useQuery } from '@dxos/react-client/echo';
|
|
@@ -13,7 +14,8 @@ import { Panel } from '@dxos/react-ui';
|
|
|
13
14
|
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
14
15
|
import { Text } from '@dxos/schema';
|
|
15
16
|
|
|
16
|
-
import { translations } from '
|
|
17
|
+
import { translations } from '#translations';
|
|
18
|
+
|
|
17
19
|
import { TestLayout } from '../../testing';
|
|
18
20
|
import { Form } from '../Form';
|
|
19
21
|
|
|
@@ -125,6 +127,59 @@ export const StringBacked: Story = {
|
|
|
125
127
|
render: () => <StringStory />,
|
|
126
128
|
};
|
|
127
129
|
|
|
130
|
+
// Regression test: keystrokes into a string-backed markdown field must not
|
|
131
|
+
// blur the editor. Previously the EditorView was destroyed and recreated on
|
|
132
|
+
// every change because `onChange` was a useTextEditor dep and form callbacks
|
|
133
|
+
// are unstable across renders.
|
|
134
|
+
export const StringBackedKeepsFocus: Story = {
|
|
135
|
+
render: () => (
|
|
136
|
+
<TestLayout>
|
|
137
|
+
<Form.Root schema={StringSchema} defaultValues={{ notes: '' }}>
|
|
138
|
+
<Form.Viewport>
|
|
139
|
+
<Form.Content>
|
|
140
|
+
<Form.FieldSet />
|
|
141
|
+
</Form.Content>
|
|
142
|
+
</Form.Viewport>
|
|
143
|
+
</Form.Root>
|
|
144
|
+
</TestLayout>
|
|
145
|
+
),
|
|
146
|
+
play: async ({ canvasElement }) => {
|
|
147
|
+
const waitFor = async <T,>(predicate: () => T | null | undefined, message: string): Promise<T> => {
|
|
148
|
+
for (let attempt = 0; attempt < 50; attempt++) {
|
|
149
|
+
const value = predicate();
|
|
150
|
+
if (value) {
|
|
151
|
+
return value;
|
|
152
|
+
}
|
|
153
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
154
|
+
}
|
|
155
|
+
throw new Error(message);
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const editorRoot = await waitFor(
|
|
159
|
+
() => canvasElement.querySelector<HTMLElement>('.cm-editor'),
|
|
160
|
+
'CodeMirror editor root (.cm-editor) not found',
|
|
161
|
+
);
|
|
162
|
+
const editorContent = editorRoot.querySelector<HTMLElement>('.cm-content')!;
|
|
163
|
+
await expect(editorContent).toBeVisible();
|
|
164
|
+
|
|
165
|
+
// Focus editor and wait for focus to settle inside the editor root.
|
|
166
|
+
editorContent.focus();
|
|
167
|
+
await waitFor(() => (editorRoot.contains(document.activeElement) ? true : null), 'Editor did not receive focus');
|
|
168
|
+
|
|
169
|
+
// Type several characters; focus must be preserved inside the editor root
|
|
170
|
+
// after every keystroke. Regression: previously the EditorView was
|
|
171
|
+
// destroyed and recreated on every change, which detached the focused
|
|
172
|
+
// contentDOM and blurred the input.
|
|
173
|
+
const phrase = 'hello world';
|
|
174
|
+
for (const ch of phrase) {
|
|
175
|
+
await userEvent.keyboard(ch);
|
|
176
|
+
await expect(editorRoot.contains(document.activeElement)).toBe(true);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
await expect(editorContent).toHaveTextContent(phrase);
|
|
180
|
+
},
|
|
181
|
+
};
|
|
182
|
+
|
|
128
183
|
export const RefPopulated: Story = {
|
|
129
184
|
render: () => <RefStory />,
|
|
130
185
|
decorators: [
|
|
@@ -13,7 +13,8 @@ import { Editor, useBasicMarkdownExtensions } from '@dxos/react-ui-editor';
|
|
|
13
13
|
import { Text } from '@dxos/schema';
|
|
14
14
|
import { createDataExtensions } from '@dxos/ui-editor';
|
|
15
15
|
|
|
16
|
-
import { translationKey } from '
|
|
16
|
+
import { translationKey } from '#translations';
|
|
17
|
+
|
|
17
18
|
import { type FormFieldComponentProps, FormFieldLabel } from '../FormFieldComponent';
|
|
18
19
|
|
|
19
20
|
const editorClassNames =
|
|
@@ -14,7 +14,8 @@ import { DxAnchor } from '@dxos/lit-ui/react';
|
|
|
14
14
|
import { Button, Icon, Input, useTranslation } from '@dxos/react-ui';
|
|
15
15
|
import { ParentLabelAnnotationId } from '@dxos/schema';
|
|
16
16
|
|
|
17
|
-
import { translationKey } from '
|
|
17
|
+
import { translationKey } from '#translations';
|
|
18
|
+
|
|
18
19
|
import { ObjectPicker, type ObjectPickerContentProps, type RefOption } from '../../ObjectPicker';
|
|
19
20
|
import { omitHiddenFormFields, omitId } from '../Form';
|
|
20
21
|
import { type FormFieldComponentProps, FormFieldLabel } from '../FormFieldComponent';
|
|
@@ -188,14 +189,14 @@ export const RefField = (props: RefFieldProps) => {
|
|
|
188
189
|
<ObjectPicker.Root open={open} onOpenChange={setOpen}>
|
|
189
190
|
<ObjectPicker.Trigger asChild classNames='p-0'>
|
|
190
191
|
{item ? (
|
|
191
|
-
<div
|
|
192
|
+
<div className='flex gap-form-gap w-full'>
|
|
192
193
|
<Input.Root key={item.id}>
|
|
193
194
|
<Input.TextInput value={item.label} readOnly classNames='w-full' />
|
|
194
195
|
</Input.Root>
|
|
195
196
|
</div>
|
|
196
197
|
) : (
|
|
197
198
|
<Button classNames='w-full text-start gap-form-gap'>
|
|
198
|
-
<div
|
|
199
|
+
<div className='grow overflow-hidden'>
|
|
199
200
|
<span className='truncate text-description'>{placeholder ?? t('ref-field.placeholder')}</span>
|
|
200
201
|
</div>
|
|
201
202
|
<Icon size={3} icon='ph--caret-down--bold' />
|
|
@@ -9,7 +9,8 @@ import React, { useState } from 'react';
|
|
|
9
9
|
import { SelectOption } from '@dxos/echo/internal';
|
|
10
10
|
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
11
11
|
|
|
12
|
-
import { translations } from '
|
|
12
|
+
import { translations } from '#translations';
|
|
13
|
+
|
|
13
14
|
import { TestLayout } from '../../testing';
|
|
14
15
|
import { Form } from '../Form';
|
|
15
16
|
import { SelectOptionField } from './SelectOptionField';
|
|
@@ -9,9 +9,10 @@ import { PublicKey } from '@dxos/keys';
|
|
|
9
9
|
import { type ChromaticPalette, IconButton, Input, Tag, useTranslation } from '@dxos/react-ui';
|
|
10
10
|
import { List } from '@dxos/react-ui-list';
|
|
11
11
|
import { HuePicker } from '@dxos/react-ui-pickers';
|
|
12
|
-
import { hues, osTranslations
|
|
12
|
+
import { hues, osTranslations } from '@dxos/ui-theme';
|
|
13
|
+
|
|
14
|
+
import { translationKey } from '#translations';
|
|
13
15
|
|
|
14
|
-
import { translationKey } from '../../../translations';
|
|
15
16
|
import { type FormFieldComponentProps, FormFieldLabel } from '../FormFieldComponent';
|
|
16
17
|
|
|
17
18
|
export const SelectOptionField = ({
|
|
@@ -119,7 +120,7 @@ export const SelectOptionField = ({
|
|
|
119
120
|
return (
|
|
120
121
|
<Input.Root validationValence={status}>
|
|
121
122
|
<FormFieldLabel error={error} readonly={readonly} label={label} />
|
|
122
|
-
<div
|
|
123
|
+
<div>
|
|
123
124
|
{options && (
|
|
124
125
|
<List.Root
|
|
125
126
|
items={options}
|
|
@@ -134,7 +135,7 @@ export const SelectOptionField = ({
|
|
|
134
135
|
<List.Item
|
|
135
136
|
role='button'
|
|
136
137
|
item={item}
|
|
137
|
-
classNames=
|
|
138
|
+
classNames='flex flex-col cursor-pointer rounded-xs dx-hover'
|
|
138
139
|
aria-expanded={selected === item.id}
|
|
139
140
|
>
|
|
140
141
|
<div className='flex items-center'>
|
|
@@ -146,7 +147,7 @@ export const SelectOptionField = ({
|
|
|
146
147
|
<IconButton
|
|
147
148
|
iconOnly
|
|
148
149
|
variant='ghost'
|
|
149
|
-
label={t(selected === item.id ? 'collapse
|
|
150
|
+
label={t(selected === item.id ? 'collapse.label' : 'expand.label', { ns: osTranslations })}
|
|
150
151
|
icon={selected === item.id ? 'ph--caret-down--regular' : 'ph--caret-right--regular'}
|
|
151
152
|
onClick={() => handleClick(item.id)}
|
|
152
153
|
/>
|
|
@@ -11,7 +11,8 @@ import { invariant } from '@dxos/invariant';
|
|
|
11
11
|
import { HuePicker } from '@dxos/react-ui-pickers';
|
|
12
12
|
import { isNonNullable } from '@dxos/util';
|
|
13
13
|
|
|
14
|
-
import { translationKey } from '
|
|
14
|
+
import { translationKey } from '#translations';
|
|
15
|
+
|
|
15
16
|
import { Form, type FormFieldMap, omitId } from '../Form';
|
|
16
17
|
|
|
17
18
|
export type ObjectFormProps = {
|
|
@@ -52,7 +53,7 @@ export const ObjectForm = ({ object, schema }: ObjectFormProps) => {
|
|
|
52
53
|
invariant(Type.isObjectSchema(schema));
|
|
53
54
|
const newObject = db.add(Obj.make(schema, values));
|
|
54
55
|
if (Obj.instanceOf(Tag.Tag, newObject)) {
|
|
55
|
-
Obj.
|
|
56
|
+
Obj.update(object, (object) => {
|
|
56
57
|
Obj.getMeta(object).tags = [...(Obj.getMeta(object).tags ?? []), Obj.getDXN(newObject).toString()];
|
|
57
58
|
});
|
|
58
59
|
}
|
|
@@ -67,10 +68,10 @@ export const ObjectForm = ({ object, schema }: ObjectFormProps) => {
|
|
|
67
68
|
|
|
68
69
|
const changedPaths = Object.keys(changed).filter((path) => changed[path as JsonPath]) as JsonPath[];
|
|
69
70
|
|
|
70
|
-
// Handle tags separately using Obj.
|
|
71
|
+
// Handle tags separately using Obj.update.
|
|
71
72
|
const hasTagsChange = changedPaths.some((path) => splitJsonPath(path)[0] === 'tags');
|
|
72
73
|
if (hasTagsChange) {
|
|
73
|
-
Obj.
|
|
74
|
+
Obj.update(object, (object) => {
|
|
74
75
|
Obj.getMeta(object).tags = tags?.map((tag: Ref.Ref<Tag.Tag>) => tag.dxn.toString()) ?? [];
|
|
75
76
|
});
|
|
76
77
|
}
|
|
@@ -78,7 +79,7 @@ export const ObjectForm = ({ object, schema }: ObjectFormProps) => {
|
|
|
78
79
|
// Handle other property changes.
|
|
79
80
|
const nonTagPaths = changedPaths.filter((path) => splitJsonPath(path)[0] !== 'tags');
|
|
80
81
|
if (nonTagPaths.length > 0) {
|
|
81
|
-
Obj.
|
|
82
|
+
Obj.update(object, () => {
|
|
82
83
|
for (const path of nonTagPaths) {
|
|
83
84
|
const parts = splitJsonPath(path);
|
|
84
85
|
const value = Obj.getValue(values, parts);
|
|
@@ -7,16 +7,17 @@ import * as Schema from 'effect/Schema';
|
|
|
7
7
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
8
8
|
import { expect, fn, userEvent, within } from 'storybook/test';
|
|
9
9
|
|
|
10
|
-
import { Obj } from '@dxos/echo';
|
|
10
|
+
import { Filter, Obj } from '@dxos/echo';
|
|
11
11
|
import { random } from '@dxos/random';
|
|
12
|
-
import {
|
|
12
|
+
import { useQuery } from '@dxos/react-client/echo';
|
|
13
13
|
import { useClientStory, withClientProvider } from '@dxos/react-client/testing';
|
|
14
14
|
import { Button } from '@dxos/react-ui';
|
|
15
15
|
import { withTheme } from '@dxos/react-ui/testing';
|
|
16
16
|
import { Person } from '@dxos/types';
|
|
17
17
|
import { osTranslations } from '@dxos/ui-theme';
|
|
18
18
|
|
|
19
|
-
import { translations } from '
|
|
19
|
+
import { translations } from '#translations';
|
|
20
|
+
|
|
20
21
|
import { ObjectPicker } from './ObjectPicker';
|
|
21
22
|
|
|
22
23
|
random.seed(1);
|
|
@@ -64,7 +65,9 @@ const DefaultStory = () => {
|
|
|
64
65
|
const handleCreateCallback = useCallback(
|
|
65
66
|
(values: any) => {
|
|
66
67
|
console.log('[on create]', values);
|
|
67
|
-
if (!space)
|
|
68
|
+
if (!space) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
68
71
|
const newPerson = space.db.add(Obj.make(Person.Person, values));
|
|
69
72
|
mockHandleCreate(values);
|
|
70
73
|
return newPerson;
|
|
@@ -73,7 +76,7 @@ const DefaultStory = () => {
|
|
|
73
76
|
);
|
|
74
77
|
|
|
75
78
|
return (
|
|
76
|
-
<div
|
|
79
|
+
<div className='w-96'>
|
|
77
80
|
<ObjectPicker.Root open={isOpen} onOpenChange={setIsOpen}>
|
|
78
81
|
<ObjectPicker.Trigger asChild>
|
|
79
82
|
<Button variant='primary' data-testid='trigger' classNames='w-full'>
|
|
@@ -6,9 +6,11 @@ import type * as Schema from 'effect/Schema';
|
|
|
6
6
|
import React, { type KeyboardEvent, forwardRef, useCallback, useState } from 'react';
|
|
7
7
|
|
|
8
8
|
import { type Palette, Popover, type ThemedClassName, useTranslation } from '@dxos/react-ui';
|
|
9
|
-
import { Combobox
|
|
9
|
+
import { Combobox } from '@dxos/react-ui-list';
|
|
10
|
+
import { useSearchListResults } from '@dxos/react-ui-search';
|
|
11
|
+
|
|
12
|
+
import { translationKey } from '#translations';
|
|
10
13
|
|
|
11
|
-
import { translationKey } from '../../translations';
|
|
12
14
|
import { Form } from '../Form';
|
|
13
15
|
import { type FormFieldMap } from '../Form/FormFieldComponent';
|
|
14
16
|
|
|
@@ -57,7 +59,7 @@ const ObjectPickerContent = forwardRef<HTMLDivElement, ObjectPickerContentProps>
|
|
|
57
59
|
const [showForm, setShowForm] = useState(false);
|
|
58
60
|
const [formInitialValue, setFormInitialValue] = useState<string>('');
|
|
59
61
|
|
|
60
|
-
const { results, handleSearch } = useSearchListResults({
|
|
62
|
+
const { results, query, handleSearch } = useSearchListResults({
|
|
61
63
|
items: options,
|
|
62
64
|
});
|
|
63
65
|
|
|
@@ -98,7 +100,7 @@ const ObjectPickerContent = forwardRef<HTMLDivElement, ObjectPickerContentProps>
|
|
|
98
100
|
|
|
99
101
|
if (showForm && createSchema) {
|
|
100
102
|
return (
|
|
101
|
-
<Combobox.Content {...props}
|
|
103
|
+
<Combobox.Content {...props} onKeyDownCapture={handleKeyDown} ref={forwardedRef}>
|
|
102
104
|
<Popover.Viewport>
|
|
103
105
|
<Form.Root
|
|
104
106
|
testId='create-referenced-object-form'
|
|
@@ -122,8 +124,13 @@ const ObjectPickerContent = forwardRef<HTMLDivElement, ObjectPickerContentProps>
|
|
|
122
124
|
}
|
|
123
125
|
|
|
124
126
|
return (
|
|
125
|
-
<Combobox.Content {...props}
|
|
126
|
-
<Combobox.Input
|
|
127
|
+
<Combobox.Content {...props} onKeyDownCapture={handleKeyDown} ref={forwardedRef}>
|
|
128
|
+
<Combobox.Input
|
|
129
|
+
placeholder={t('ref-field-combobox-input.placeholder')}
|
|
130
|
+
autoFocus
|
|
131
|
+
value={query}
|
|
132
|
+
onValueChange={handleSearch}
|
|
133
|
+
/>
|
|
127
134
|
<Combobox.List>
|
|
128
135
|
{results.map((option) => (
|
|
129
136
|
<Combobox.Item
|
|
@@ -137,10 +144,11 @@ const ObjectPickerContent = forwardRef<HTMLDivElement, ObjectPickerContentProps>
|
|
|
137
144
|
))}
|
|
138
145
|
{createSchema && onCreate && (
|
|
139
146
|
<CreateItem
|
|
147
|
+
query={query}
|
|
140
148
|
createOptionLabel={createOptionLabel}
|
|
141
149
|
createOptionIcon={createOptionIcon ?? 'ph--plus--regular'}
|
|
142
|
-
onCreateItemSelect={(
|
|
143
|
-
setFormInitialValue(
|
|
150
|
+
onCreateItemSelect={(currentQuery: string) => {
|
|
151
|
+
setFormInitialValue(currentQuery);
|
|
144
152
|
setShowForm(true);
|
|
145
153
|
}}
|
|
146
154
|
/>
|
|
@@ -153,16 +161,17 @@ const ObjectPickerContent = forwardRef<HTMLDivElement, ObjectPickerContentProps>
|
|
|
153
161
|
);
|
|
154
162
|
|
|
155
163
|
const CreateItem = ({
|
|
164
|
+
query,
|
|
156
165
|
createOptionLabel,
|
|
157
166
|
createOptionIcon,
|
|
158
167
|
onCreateItemSelect,
|
|
159
168
|
}: {
|
|
169
|
+
query: string;
|
|
160
170
|
createOptionLabel?: [string, { ns: string }];
|
|
161
171
|
createOptionIcon: string;
|
|
162
172
|
onCreateItemSelect: (query: string) => void;
|
|
163
173
|
}) => {
|
|
164
174
|
const { t } = useTranslation(translationKey);
|
|
165
|
-
const { query } = useSearchListInput();
|
|
166
175
|
|
|
167
176
|
const label = createOptionLabel
|
|
168
177
|
? t(createOptionLabel[0], { ns: createOptionLabel[1].ns, text: query })
|
|
@@ -16,7 +16,8 @@ import { Loading, withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
|
16
16
|
import { FactoryAnnotation, type FactoryFn } from '@dxos/schema';
|
|
17
17
|
import { Pipeline } from '@dxos/types';
|
|
18
18
|
|
|
19
|
-
import { translations } from '
|
|
19
|
+
import { translations } from '#translations';
|
|
20
|
+
|
|
20
21
|
import { OBJECT_PROPERTIES_DEBUG_SYMBOL } from '../testing';
|
|
21
22
|
import { ObjectProperties } from './ObjectProperties';
|
|
22
23
|
|