@dxos/react-ui-table 0.8.4-main.3eb6e50203 → 0.8.4-main.4a85c3132b
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/{chunk-OZBLY7XM.mjs → chunk-DSR2MRZB.mjs} +10 -6
- package/dist/lib/browser/chunk-DSR2MRZB.mjs.map +7 -0
- package/dist/lib/browser/{chunk-GTGYBRJA.mjs → chunk-PTHMYAAM.mjs} +25 -22
- package/dist/lib/browser/chunk-PTHMYAAM.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +179 -175
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +2 -2
- package/dist/lib/browser/testing/index.mjs.map +1 -1
- package/dist/lib/browser/types/index.mjs +1 -1
- package/dist/lib/node-esm/{chunk-DPNSZHU5.mjs → chunk-GI72MQSG.mjs} +25 -22
- package/dist/lib/node-esm/chunk-GI72MQSG.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-WNZSKIRF.mjs → chunk-HTZJSULI.mjs} +10 -6
- package/dist/lib/node-esm/chunk-HTZJSULI.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +179 -175
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/testing/index.mjs +2 -2
- package/dist/lib/node-esm/testing/index.mjs.map +1 -1
- package/dist/lib/node-esm/types/index.mjs +1 -1
- package/dist/types/src/components/Table/ColumnSettings.d.ts.map +1 -1
- package/dist/types/src/components/Table/DynamicTable.d.ts +2 -2
- package/dist/types/src/components/Table/DynamicTable.d.ts.map +1 -1
- package/dist/types/src/components/Table/DynamicTable.stories.d.ts +1 -1
- package/dist/types/src/components/Table/Relations.stories.d.ts.map +1 -1
- package/dist/types/src/components/Table/Table.d.ts +7 -7
- package/dist/types/src/components/Table/Table.d.ts.map +1 -1
- package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
- package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts +3 -3
- package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts.map +1 -1
- package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +2 -2
- package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
- package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TableToolbar/TableToolbar.d.ts +1 -1
- package/dist/types/src/components/TableToolbar/TableToolbar.d.ts.map +1 -1
- package/dist/types/src/hooks/useAddRow.d.ts +1 -1
- package/dist/types/src/hooks/useAddRow.d.ts.map +1 -1
- package/dist/types/src/hooks/useProjectionModel.d.ts +1 -1
- package/dist/types/src/hooks/useProjectionModel.d.ts.map +1 -1
- package/dist/types/src/model/table-model.d.ts +2 -1
- package/dist/types/src/model/table-model.d.ts.map +1 -1
- package/dist/types/src/model/table-presentation.d.ts.map +1 -1
- package/dist/types/src/testing/useTestTableModel.d.ts +2 -2
- package/dist/types/src/testing/useTestTableModel.d.ts.map +1 -1
- package/dist/types/src/types/Table.d.ts +1 -1
- package/dist/types/src/types/Table.d.ts.map +1 -1
- package/dist/types/src/util/dynamic-table.d.ts +2 -2
- package/dist/types/src/util/dynamic-table.d.ts.map +1 -1
- package/dist/types/src/util/query-ast.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +36 -36
- package/src/components/Table/ColumnSettings.tsx +3 -4
- package/src/components/Table/DynamicTable.stories.tsx +2 -2
- package/src/components/Table/DynamicTable.tsx +7 -7
- package/src/components/Table/Relations.stories.tsx +12 -9
- package/src/components/Table/Table.stories.tsx +34 -25
- package/src/components/Table/Table.tsx +53 -57
- package/src/components/TableCellEditor/CellValidationMessage.tsx +4 -4
- package/src/components/TableCellEditor/FormCellEditor.tsx +11 -5
- package/src/components/TableCellEditor/TableCellEditor.stories.tsx +3 -2
- package/src/components/TableCellEditor/TableCellEditor.tsx +3 -3
- package/src/components/TableToolbar/TableToolbar.tsx +6 -6
- package/src/hooks/useAddRow.ts +1 -1
- package/src/hooks/useProjectionModel.ts +3 -3
- package/src/model/table-model.test.ts +4 -4
- package/src/model/table-model.ts +2 -1
- package/src/model/table-presentation.test.ts +4 -4
- package/src/model/table-presentation.ts +12 -11
- package/src/playwright/playwright.config.ts +1 -1
- package/src/testing/useTestTableModel.ts +2 -2
- package/src/types/Table.ts +9 -4
- package/src/util/dynamic-table.test.ts +2 -2
- package/src/util/dynamic-table.ts +7 -6
- package/src/util/query-ast.ts +3 -0
- package/src/util/table-buttons.ts +1 -1
- package/src/util/table-controls.ts +2 -2
- package/dist/lib/browser/chunk-GTGYBRJA.mjs.map +0 -7
- package/dist/lib/browser/chunk-OZBLY7XM.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-DPNSZHU5.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-WNZSKIRF.mjs.map +0 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/react-ui-table",
|
|
3
|
-
"version": "0.8.4-main.
|
|
3
|
+
"version": "0.8.4-main.4a85c3132b",
|
|
4
4
|
"description": "A table component.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -68,31 +68,31 @@
|
|
|
68
68
|
"@radix-ui/react-use-controllable-state": "1.1.0",
|
|
69
69
|
"date-fns": "^3.3.1",
|
|
70
70
|
"lodash.orderby": "^4.6.0",
|
|
71
|
-
"@dxos/async": "0.8.4-main.
|
|
72
|
-
"@dxos/context": "0.8.4-main.
|
|
73
|
-
"@dxos/
|
|
74
|
-
"@dxos/echo": "0.8.4-main.
|
|
75
|
-
"@dxos/
|
|
76
|
-
"@dxos/
|
|
77
|
-
"@dxos/
|
|
78
|
-
"@dxos/random": "0.8.4-main.
|
|
79
|
-
"@dxos/
|
|
80
|
-
"@dxos/react-client": "0.8.4-main.
|
|
81
|
-
"@dxos/
|
|
82
|
-
"@dxos/react-ui-attention": "0.8.4-main.
|
|
83
|
-
"@dxos/react-ui-
|
|
84
|
-
"@dxos/react-ui-
|
|
85
|
-
"@dxos/react-ui-form": "0.8.4-main.
|
|
86
|
-
"@dxos/react-ui-
|
|
87
|
-
"@dxos/react-ui-
|
|
88
|
-
"@dxos/react-ui-
|
|
89
|
-
"@dxos/
|
|
90
|
-
"@dxos/
|
|
91
|
-
"@dxos/
|
|
92
|
-
"@dxos/
|
|
93
|
-
"@dxos/ui-types": "0.8.4-main.
|
|
94
|
-
"@dxos/
|
|
95
|
-
"@dxos/
|
|
71
|
+
"@dxos/async": "0.8.4-main.4a85c3132b",
|
|
72
|
+
"@dxos/context": "0.8.4-main.4a85c3132b",
|
|
73
|
+
"@dxos/debug": "0.8.4-main.4a85c3132b",
|
|
74
|
+
"@dxos/echo": "0.8.4-main.4a85c3132b",
|
|
75
|
+
"@dxos/echo-atom": "0.8.4-main.4a85c3132b",
|
|
76
|
+
"@dxos/effect": "0.8.4-main.4a85c3132b",
|
|
77
|
+
"@dxos/invariant": "0.8.4-main.4a85c3132b",
|
|
78
|
+
"@dxos/random": "0.8.4-main.4a85c3132b",
|
|
79
|
+
"@dxos/log": "0.8.4-main.4a85c3132b",
|
|
80
|
+
"@dxos/react-client": "0.8.4-main.4a85c3132b",
|
|
81
|
+
"@dxos/keys": "0.8.4-main.4a85c3132b",
|
|
82
|
+
"@dxos/react-ui-attention": "0.8.4-main.4a85c3132b",
|
|
83
|
+
"@dxos/react-ui-components": "0.8.4-main.4a85c3132b",
|
|
84
|
+
"@dxos/react-ui-editor": "0.8.4-main.4a85c3132b",
|
|
85
|
+
"@dxos/react-ui-form": "0.8.4-main.4a85c3132b",
|
|
86
|
+
"@dxos/react-ui-menu": "0.8.4-main.4a85c3132b",
|
|
87
|
+
"@dxos/react-ui-searchlist": "0.8.4-main.4a85c3132b",
|
|
88
|
+
"@dxos/react-ui-grid": "0.8.4-main.4a85c3132b",
|
|
89
|
+
"@dxos/react-ui-stack": "0.8.4-main.4a85c3132b",
|
|
90
|
+
"@dxos/schema": "0.8.4-main.4a85c3132b",
|
|
91
|
+
"@dxos/types": "0.8.4-main.4a85c3132b",
|
|
92
|
+
"@dxos/react-ui-syntax-highlighter": "0.8.4-main.4a85c3132b",
|
|
93
|
+
"@dxos/ui-types": "0.8.4-main.4a85c3132b",
|
|
94
|
+
"@dxos/util": "0.8.4-main.4a85c3132b",
|
|
95
|
+
"@dxos/lit-grid": "0.8.4-main.4a85c3132b"
|
|
96
96
|
},
|
|
97
97
|
"devDependencies": {
|
|
98
98
|
"@effect/platform": "0.94.4",
|
|
@@ -103,14 +103,14 @@
|
|
|
103
103
|
"fast-check": "^3.19.0",
|
|
104
104
|
"react": "~19.2.3",
|
|
105
105
|
"react-dom": "~19.2.3",
|
|
106
|
-
"vite": "7.1.
|
|
107
|
-
"@dxos/
|
|
108
|
-
"@dxos/
|
|
109
|
-
"@dxos/react-client": "0.8.4-main.
|
|
110
|
-
"@dxos/react-ui": "0.8.4-main.
|
|
111
|
-
"@dxos/storybook-utils": "0.8.4-main.
|
|
112
|
-
"@dxos/test-utils": "0.8.4-main.
|
|
113
|
-
"@dxos/ui-theme": "0.8.4-main.
|
|
106
|
+
"vite": "^7.1.11",
|
|
107
|
+
"@dxos/lit-ui": "0.8.4-main.4a85c3132b",
|
|
108
|
+
"@dxos/random": "0.8.4-main.4a85c3132b",
|
|
109
|
+
"@dxos/react-client": "0.8.4-main.4a85c3132b",
|
|
110
|
+
"@dxos/react-ui": "0.8.4-main.4a85c3132b",
|
|
111
|
+
"@dxos/storybook-utils": "0.8.4-main.4a85c3132b",
|
|
112
|
+
"@dxos/test-utils": "0.8.4-main.4a85c3132b",
|
|
113
|
+
"@dxos/ui-theme": "0.8.4-main.4a85c3132b"
|
|
114
114
|
},
|
|
115
115
|
"peerDependencies": {
|
|
116
116
|
"@effect-atom/atom-react": "^0.5.0",
|
|
@@ -118,8 +118,8 @@
|
|
|
118
118
|
"effect": "3.19.16",
|
|
119
119
|
"react": "~19.2.3",
|
|
120
120
|
"react-dom": "~19.2.3",
|
|
121
|
-
"@dxos/react-ui": "0.8.4-main.
|
|
122
|
-
"@dxos/ui-theme": "0.8.4-main.
|
|
121
|
+
"@dxos/react-ui": "0.8.4-main.4a85c3132b",
|
|
122
|
+
"@dxos/ui-theme": "0.8.4-main.4a85c3132b"
|
|
123
123
|
},
|
|
124
124
|
"publishConfig": {
|
|
125
125
|
"access": "public"
|
|
@@ -5,10 +5,9 @@
|
|
|
5
5
|
import { useAtomValue } from '@effect-atom/atom-react';
|
|
6
6
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
7
7
|
|
|
8
|
-
import { type SchemaRegistry } from '@dxos/echo';
|
|
8
|
+
import { type SchemaRegistry, type View } from '@dxos/echo';
|
|
9
9
|
import { Popover } from '@dxos/react-ui';
|
|
10
10
|
import { FieldEditor } from '@dxos/react-ui-form';
|
|
11
|
-
import { type FieldType } from '@dxos/schema';
|
|
12
11
|
|
|
13
12
|
import { type ModalController, type TableModel } from '../../model';
|
|
14
13
|
|
|
@@ -20,7 +19,7 @@ type ColumnSettingsProps = {
|
|
|
20
19
|
};
|
|
21
20
|
|
|
22
21
|
export const ColumnSettings = ({ registry, model, modals, onNewColumn }: ColumnSettingsProps) => {
|
|
23
|
-
const [newField, setNewField] = useState<FieldType>();
|
|
22
|
+
const [newField, setNewField] = useState<View.FieldType>();
|
|
24
23
|
const state = useAtomValue(modals.state);
|
|
25
24
|
|
|
26
25
|
useEffect(() => {
|
|
@@ -64,7 +63,7 @@ export const ColumnSettings = ({ registry, model, modals, onNewColumn }: ColumnS
|
|
|
64
63
|
<Popover.Root modal={false} open={state?.type === 'columnSettings'}>
|
|
65
64
|
<Popover.VirtualTrigger virtualRef={modals.trigger} />
|
|
66
65
|
<Popover.Portal>
|
|
67
|
-
<Popover.Content classNames='md:
|
|
66
|
+
<Popover.Content classNames='md:w-64'>
|
|
68
67
|
<Popover.Viewport>
|
|
69
68
|
<FieldEditor
|
|
70
69
|
projection={model.projection}
|
|
@@ -11,7 +11,7 @@ import { Format } from '@dxos/echo/internal';
|
|
|
11
11
|
import { faker } from '@dxos/random';
|
|
12
12
|
import { Filter, useQuery, useSchema } from '@dxos/react-client/echo';
|
|
13
13
|
import { useClientStory, withClientProvider } from '@dxos/react-client/testing';
|
|
14
|
-
import { withTheme } from '@dxos/react-ui/testing';
|
|
14
|
+
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
15
15
|
import { type SchemaPropertyDefinition } from '@dxos/schema';
|
|
16
16
|
import { TestSchema } from '@dxos/schema/testing';
|
|
17
17
|
import { withRegistry } from '@dxos/storybook-utils';
|
|
@@ -59,7 +59,7 @@ const DynamicTableStory = () => {
|
|
|
59
59
|
const meta = {
|
|
60
60
|
title: 'ui/react-ui-table/DynamicTable',
|
|
61
61
|
component: DynamicTable,
|
|
62
|
-
decorators: [withTheme(), withRegistry],
|
|
62
|
+
decorators: [withTheme(), withLayout({ layout: 'fullscreen' }), withRegistry],
|
|
63
63
|
parameters: {
|
|
64
64
|
layout: 'fullscreen',
|
|
65
65
|
translations,
|
|
@@ -19,7 +19,7 @@ import { type TablePropertyDefinition, getBaseSchema, makeDynamicTable } from '.
|
|
|
19
19
|
|
|
20
20
|
import { Table, type TableController } from './Table';
|
|
21
21
|
|
|
22
|
-
export type DynamicTableProps<T extends Type.
|
|
22
|
+
export type DynamicTableProps<T extends Type.AnyEntity = Type.AnyEntity> = ThemedClassName<{
|
|
23
23
|
schema?: T;
|
|
24
24
|
name?: string; // TODO(burdon): Remove?
|
|
25
25
|
rows: any[];
|
|
@@ -36,13 +36,13 @@ export type DynamicTableProps<T extends Type.Entity.Any = Type.Entity.Any> = The
|
|
|
36
36
|
*/
|
|
37
37
|
// TODO(burdon): Instead of creating component variants, create helpers/hooks that normalize the props.
|
|
38
38
|
// TODO(burdon): Warning: Cannot update a component (`DynamicTable`) while rendering a different component (`DynamicTable`).
|
|
39
|
-
export const DynamicTable = <T extends Type.
|
|
39
|
+
export const DynamicTable = <T extends Type.AnyEntity = Type.AnyEntity>({
|
|
40
40
|
classNames,
|
|
41
41
|
schema,
|
|
42
42
|
name = 'example.com/dynamic-table', // Rmove default or make random; this will lead to type collisions.
|
|
43
43
|
rows,
|
|
44
44
|
properties,
|
|
45
|
-
jsonSchema:
|
|
45
|
+
jsonSchema: jsonSchemaProp,
|
|
46
46
|
rowActions,
|
|
47
47
|
onRowClick,
|
|
48
48
|
onRowAction,
|
|
@@ -53,8 +53,8 @@ export const DynamicTable = <T extends Type.Entity.Any = Type.Entity.Any>({
|
|
|
53
53
|
|
|
54
54
|
// TODO(burdon): Remove variance from the props (should be normalized externally; possibly via hooks).
|
|
55
55
|
const { jsonSchema } = useMemo(
|
|
56
|
-
() => getBaseSchema({ typename: name, properties, jsonSchema:
|
|
57
|
-
[name, properties,
|
|
56
|
+
() => getBaseSchema({ typename: name, properties, jsonSchema: jsonSchemaProp, schema }),
|
|
57
|
+
[name, properties, jsonSchemaProp, schema],
|
|
58
58
|
);
|
|
59
59
|
|
|
60
60
|
useEffect(() => {
|
|
@@ -98,8 +98,8 @@ export const DynamicTable = <T extends Type.Entity.Any = Type.Entity.Any>({
|
|
|
98
98
|
|
|
99
99
|
// TODO(burdon): Do we need the outer divs?
|
|
100
100
|
return (
|
|
101
|
-
<div role='none' className={mx('
|
|
102
|
-
<div role='none' className='grid min-
|
|
101
|
+
<div role='none' className={mx('w-full h-full grow grid', classNames)}>
|
|
102
|
+
<div role='none' className='grid min-h-0 overflow-hidden'>
|
|
103
103
|
<Table.Root>
|
|
104
104
|
<Table.Main
|
|
105
105
|
ref={tableRef}
|
|
@@ -8,6 +8,7 @@ import React, { useCallback, useContext, useEffect, useMemo, useState } from 're
|
|
|
8
8
|
import { expect, userEvent, within } from 'storybook/test';
|
|
9
9
|
|
|
10
10
|
import { Obj, Type } from '@dxos/echo';
|
|
11
|
+
import { View } from '@dxos/echo';
|
|
11
12
|
import { invariant } from '@dxos/invariant';
|
|
12
13
|
import { type DxGrid } from '@dxos/lit-grid';
|
|
13
14
|
import '@dxos/lit-ui/dx-tag-picker.pcss';
|
|
@@ -16,7 +17,7 @@ import { useClientStory, withClientProvider } from '@dxos/react-client/testing';
|
|
|
16
17
|
import { useAsyncEffect } from '@dxos/react-ui';
|
|
17
18
|
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
18
19
|
import { translations as formTranslations } from '@dxos/react-ui-form';
|
|
19
|
-
import {
|
|
20
|
+
import { ViewModel } from '@dxos/schema';
|
|
20
21
|
import { type ValueGenerator, createAsyncGenerator } from '@dxos/schema/testing';
|
|
21
22
|
import { withRegistry } from '@dxos/storybook-utils';
|
|
22
23
|
import { Organization, Person } from '@dxos/types';
|
|
@@ -35,7 +36,7 @@ const generator: ValueGenerator = faker as any;
|
|
|
35
36
|
// TODO(burdon): Mutable and immutable views.
|
|
36
37
|
// TODO(burdon): Reconcile schemas types and utils (see API PR).
|
|
37
38
|
// TODO(burdon): Base type for T (with id); see ECHO API PR?
|
|
38
|
-
const useTestModel = <S extends Type.
|
|
39
|
+
const useTestModel = <S extends Type.AnyObj>(schema: S, count: number) => {
|
|
39
40
|
const registry = useContext(RegistryContext);
|
|
40
41
|
const { space } = useClientStory();
|
|
41
42
|
const [object, setObject] = useState<Table.Table>();
|
|
@@ -50,7 +51,7 @@ const useTestModel = <S extends Type.Obj.Any>(schema: S, count: number) => {
|
|
|
50
51
|
return;
|
|
51
52
|
}
|
|
52
53
|
|
|
53
|
-
const { view, jsonSchema } = await
|
|
54
|
+
const { view, jsonSchema } = await ViewModel.makeFromDatabase({ db: space.db, typename: Type.getTypename(schema) });
|
|
54
55
|
const object = Table.make({ view, jsonSchema });
|
|
55
56
|
setObject(object);
|
|
56
57
|
space.db.add(object);
|
|
@@ -87,7 +88,7 @@ const DefaultStory = () => {
|
|
|
87
88
|
const { space } = useClientStory();
|
|
88
89
|
|
|
89
90
|
const handleCreate = useCallback(
|
|
90
|
-
(schema: Type.
|
|
91
|
+
(schema: Type.AnyEntity, values: any) => {
|
|
91
92
|
invariant(Type.isObjectSchema(schema));
|
|
92
93
|
invariant(space);
|
|
93
94
|
return space.db.add(Obj.make(schema, values));
|
|
@@ -96,7 +97,7 @@ const DefaultStory = () => {
|
|
|
96
97
|
);
|
|
97
98
|
|
|
98
99
|
return (
|
|
99
|
-
<div className='
|
|
100
|
+
<div className='w-full h-full grid grid-cols-2 divide-x divide-separator'>
|
|
100
101
|
<TableComponent.Root>
|
|
101
102
|
<TableComponent.Main
|
|
102
103
|
model={orgModel}
|
|
@@ -195,8 +196,9 @@ export const Default: Story = {
|
|
|
195
196
|
const saveButton = await body.findByTestId('save-button');
|
|
196
197
|
await userEvent.click(saveButton);
|
|
197
198
|
|
|
198
|
-
// Verify the relation was set (cell should now contain the org name)
|
|
199
|
-
|
|
199
|
+
// Verify the relation was set (cell should now contain the org name).
|
|
200
|
+
const updatedCell = within(secondGrid).getByTestId('grid.4.0');
|
|
201
|
+
await expect(updatedCell).toHaveTextContent(orgName.substring(0, 4));
|
|
200
202
|
|
|
201
203
|
// Test object creation (new relations) - equivalent to "new relations work as expected" test
|
|
202
204
|
// Find a different cell to test object creation (second row, relations column)
|
|
@@ -231,7 +233,8 @@ export const Default: Story = {
|
|
|
231
233
|
const saveObjectButton = await within(createReferencedObjectForm).findByTestId('save-button');
|
|
232
234
|
await userEvent.click(saveObjectButton);
|
|
233
235
|
|
|
234
|
-
// Verify the new object was created and relation was set
|
|
235
|
-
|
|
236
|
+
// Verify the new object was created and relation was set.
|
|
237
|
+
const updatedNewCell = within(secondGrid).getByTestId('grid.4.1');
|
|
238
|
+
await expect(updatedNewCell).toHaveTextContent(newOrgName);
|
|
236
239
|
},
|
|
237
240
|
} as any;
|
|
@@ -6,24 +6,24 @@ import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
|
6
6
|
import * as Schema from 'effect/Schema';
|
|
7
7
|
import React, { useCallback } from 'react';
|
|
8
8
|
|
|
9
|
-
import { Annotation, type Database, Format, Obj, type QueryAST, Type } from '@dxos/echo';
|
|
9
|
+
import { Annotation, type Database, Format, Obj, type QueryAST, Ref, Type } from '@dxos/echo';
|
|
10
|
+
import { View } from '@dxos/echo';
|
|
10
11
|
import { type Mutable, PropertyMetaAnnotationId } from '@dxos/echo/internal';
|
|
11
12
|
import { invariant } from '@dxos/invariant';
|
|
12
13
|
import { faker } from '@dxos/random';
|
|
13
14
|
import { PublicKey } from '@dxos/react-client';
|
|
14
15
|
import { withClientProvider } from '@dxos/react-client/testing';
|
|
15
|
-
import { ScrollArea } from '@dxos/react-ui';
|
|
16
|
-
import { withTheme } from '@dxos/react-ui/testing';
|
|
16
|
+
import { Panel, ScrollArea } from '@dxos/react-ui';
|
|
17
|
+
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
17
18
|
import { ViewEditor, translations as formTranslations } from '@dxos/react-ui-form';
|
|
18
19
|
import { SyntaxHighlighter } from '@dxos/react-ui-syntax-highlighter';
|
|
19
|
-
import {
|
|
20
|
+
import { ViewModel, getSchemaFromPropertyDefinitions, getTypenameFromQuery } from '@dxos/schema';
|
|
20
21
|
import { TestSchema, createObjectFactory } from '@dxos/schema/testing';
|
|
21
22
|
import { withRegistry } from '@dxos/storybook-utils';
|
|
22
23
|
|
|
23
24
|
import { useTestTableModel } from '../../testing';
|
|
24
25
|
import { translations } from '../../translations';
|
|
25
26
|
import { Table } from '../../types';
|
|
26
|
-
import { TableToolbar } from '../TableToolbar';
|
|
27
27
|
|
|
28
28
|
import { Table as TableComponent } from './Table';
|
|
29
29
|
|
|
@@ -48,7 +48,7 @@ const Example = Schema.Struct({
|
|
|
48
48
|
}),
|
|
49
49
|
),
|
|
50
50
|
description: Schema.optional(Schema.String).annotations({ title: 'Description' }),
|
|
51
|
-
parent: Schema.optional(Schema.suspend(():
|
|
51
|
+
parent: Schema.optional(Schema.suspend((): Ref.RefSchema<Example> => Ref.Ref(Example))).annotations({
|
|
52
52
|
title: 'Parent',
|
|
53
53
|
}),
|
|
54
54
|
}).pipe(
|
|
@@ -119,20 +119,28 @@ const DefaultStory = () => {
|
|
|
119
119
|
|
|
120
120
|
return (
|
|
121
121
|
<div className='grow grid grid-cols-[1fr_350px]'>
|
|
122
|
-
<
|
|
123
|
-
<
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
122
|
+
<TableComponent.Root>
|
|
123
|
+
<Panel.Root>
|
|
124
|
+
<Panel.Toolbar asChild>
|
|
125
|
+
<TableComponent.Toolbar
|
|
126
|
+
classNames='border-b border-subdued-separator'
|
|
127
|
+
onAdd={handleInsertRow}
|
|
128
|
+
onSave={handleSaveView}
|
|
129
|
+
/>
|
|
130
|
+
</Panel.Toolbar>
|
|
131
|
+
<Panel.Content asChild>
|
|
132
|
+
<TableComponent.Main
|
|
133
|
+
ref={tableRef}
|
|
134
|
+
schema={schema}
|
|
135
|
+
model={model}
|
|
136
|
+
presentation={presentation}
|
|
137
|
+
onRowClick={handleRowClick}
|
|
138
|
+
ignoreAttention
|
|
139
|
+
/>
|
|
140
|
+
</Panel.Content>
|
|
141
|
+
</Panel.Root>
|
|
142
|
+
</TableComponent.Root>
|
|
143
|
+
<ScrollArea.Root orientation='vertical' classNames='border-l border-separator'>
|
|
136
144
|
<ScrollArea.Viewport>
|
|
137
145
|
<StoryViewEditor view={table.view.target} schema={schema} db={db} handleDeleteColumn={handleDeleteColumn} />
|
|
138
146
|
<SyntaxHighlighter language='json' className='text-xs'>
|
|
@@ -150,13 +158,14 @@ type StoryProps = { rows?: number };
|
|
|
150
158
|
// Story definitions.
|
|
151
159
|
//
|
|
152
160
|
|
|
153
|
-
// TODO(burdon): Need
|
|
161
|
+
// TODO(burdon): Need simpler story.
|
|
154
162
|
|
|
155
163
|
const meta = {
|
|
156
164
|
title: 'ui/react-ui-table/Table',
|
|
157
165
|
render: DefaultStory,
|
|
158
166
|
decorators: [
|
|
159
167
|
withTheme(),
|
|
168
|
+
withLayout({ layout: 'fullscreen' }),
|
|
160
169
|
withRegistry,
|
|
161
170
|
withClientProvider({
|
|
162
171
|
types: [View.View, Table.Table],
|
|
@@ -164,7 +173,7 @@ const meta = {
|
|
|
164
173
|
createSpace: true,
|
|
165
174
|
onCreateSpace: async ({ space }) => {
|
|
166
175
|
const [schema] = await space.db.schemaRegistry.register([Example]);
|
|
167
|
-
const { view, jsonSchema } = await
|
|
176
|
+
const { view, jsonSchema } = await ViewModel.makeFromDatabase({ db: space.db, typename: schema.typename });
|
|
168
177
|
const table = Table.make({ view, jsonSchema });
|
|
169
178
|
Obj.change(view, (v) => {
|
|
170
179
|
v.projection.fields = [
|
|
@@ -210,7 +219,7 @@ export const StaticSchema: StoryObj = {
|
|
|
210
219
|
createIdentity: true,
|
|
211
220
|
createSpace: true,
|
|
212
221
|
onCreateSpace: async ({ space }) => {
|
|
213
|
-
const { view, jsonSchema } = await
|
|
222
|
+
const { view, jsonSchema } = await ViewModel.makeFromDatabase({
|
|
214
223
|
db: space.db,
|
|
215
224
|
typename: TestSchema.Person.typename,
|
|
216
225
|
});
|
|
@@ -256,7 +265,7 @@ export const ArrayOfObjects: StoryObj = {
|
|
|
256
265
|
createIdentity: true,
|
|
257
266
|
createSpace: true,
|
|
258
267
|
onCreateSpace: async ({ space }) => {
|
|
259
|
-
const { view, jsonSchema } = await
|
|
268
|
+
const { view, jsonSchema } = await ViewModel.makeFromDatabase({
|
|
260
269
|
db: space.db,
|
|
261
270
|
typename: ContactWithArrayOfEmails.typename,
|
|
262
271
|
});
|
|
@@ -314,7 +323,7 @@ export const Tags: Meta<StoryProps> = {
|
|
|
314
323
|
const [storedSchema] = await space.db.schemaRegistry.register([schema]);
|
|
315
324
|
|
|
316
325
|
// Initialize table.
|
|
317
|
-
const { view, jsonSchema } = await
|
|
326
|
+
const { view, jsonSchema } = await ViewModel.makeFromDatabase({ db: space.db, typename });
|
|
318
327
|
const table = Table.make({ view, jsonSchema });
|
|
319
328
|
space.db.add(table);
|
|
320
329
|
|
|
@@ -35,11 +35,13 @@ import {
|
|
|
35
35
|
gridSeparatorInlineEnd,
|
|
36
36
|
} from '@dxos/react-ui-grid';
|
|
37
37
|
import { DxEditRequest } from '@dxos/react-ui-grid';
|
|
38
|
-
import { mx } from '@dxos/ui-theme';
|
|
38
|
+
import { mx, useComposableProps } from '@dxos/ui-theme';
|
|
39
|
+
import { type ComposableProps } from '@dxos/ui-types';
|
|
39
40
|
|
|
40
41
|
import { type InsertRowResult, ModalController, type TableModel, type TablePresentation } from '../../model';
|
|
41
42
|
import { tableButtons, tableControls } from '../../util';
|
|
42
43
|
import { type OnCreateHandler, type TableCellEditorProps, TableValueEditor } from '../TableCellEditor';
|
|
44
|
+
import { TableToolbar } from '../TableToolbar';
|
|
43
45
|
|
|
44
46
|
import { ColumnActionsMenu } from './ColumnActionsMenu';
|
|
45
47
|
import { ColumnSettings } from './ColumnSettings';
|
|
@@ -53,51 +55,37 @@ const emptyColumnMeta = Atom.make<DxGridAxisMeta>({ grid: {} });
|
|
|
53
55
|
// Table.Root
|
|
54
56
|
//
|
|
55
57
|
|
|
56
|
-
export type TableRootProps = PropsWithChildren
|
|
58
|
+
export type TableRootProps = PropsWithChildren;
|
|
57
59
|
|
|
58
|
-
const TableRoot = ({ children
|
|
59
|
-
return
|
|
60
|
-
<div
|
|
61
|
-
role='none'
|
|
62
|
-
className={mx(
|
|
63
|
-
'relative !border-separator [&_.dx-grid]:max-is-[--dx-grid-content-inline-size] [&_.dx-grid]:max-bs-[--dx-grid-content-block-size]',
|
|
64
|
-
role === 'card--popover' && 'popover-card-height',
|
|
65
|
-
role === 'section' && 'attention-surface',
|
|
66
|
-
role === 'card--intrinsic' && '[&_.dx-grid]:bs-[--dx-grid-content-block-size]',
|
|
67
|
-
['card--popover', 'section', 'card--extrinsic'].includes(role) && 'overflow-hidden',
|
|
68
|
-
['article', 'slide'].includes(role) && 'flex flex-col [&_.dx-grid]:grow [&_.dx-grid]:bs-0',
|
|
69
|
-
)}
|
|
70
|
-
>
|
|
71
|
-
{children}
|
|
72
|
-
</div>
|
|
73
|
-
);
|
|
60
|
+
const TableRoot = ({ children }: TableRootProps) => {
|
|
61
|
+
return <>{children}</>;
|
|
74
62
|
};
|
|
75
63
|
|
|
76
64
|
//
|
|
77
65
|
// Table.Main
|
|
78
66
|
//
|
|
79
67
|
|
|
68
|
+
const emptyRowsAtom = Atom.make<unknown[]>([]);
|
|
69
|
+
const emptyCellUpdateAtom = Atom.make<number>(0);
|
|
70
|
+
|
|
80
71
|
export type TableController = {
|
|
81
72
|
update?: (cell?: DxGridPosition) => void;
|
|
82
73
|
handleInsertRowResult?: (insertRowResult?: InsertRowResult) => void;
|
|
83
74
|
};
|
|
84
75
|
|
|
85
|
-
export type TableMainProps<T extends Type.
|
|
76
|
+
export type TableMainProps<T extends Type.AnyEntity = Type.AnyEntity> = ComposableProps<{
|
|
86
77
|
schema?: T;
|
|
87
78
|
model?: TableModel;
|
|
88
79
|
presentation?: TablePresentation;
|
|
89
|
-
// TODO(burdon):
|
|
80
|
+
// TODO(burdon): Factor out attention.
|
|
90
81
|
ignoreAttention?: boolean;
|
|
91
82
|
onCreate?: OnCreateHandler;
|
|
92
83
|
onRowClick?: (row: any) => void;
|
|
93
84
|
testId?: string;
|
|
94
|
-
}
|
|
85
|
+
}>;
|
|
95
86
|
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
const TableMainInner = <T extends Type.Entity.Any = Type.Entity.Any>(
|
|
100
|
-
{ schema, model, presentation, ignoreAttention, onCreate, onRowClick, testId }: TableMainProps<T>,
|
|
87
|
+
const TableMainInner = <T extends Type.AnyEntity = Type.AnyEntity>(
|
|
88
|
+
{ schema, model, presentation, ignoreAttention, onCreate, onRowClick, testId, ...props }: TableMainProps<T>,
|
|
101
89
|
forwardedRef: Ref<TableController>,
|
|
102
90
|
) => {
|
|
103
91
|
const registry = useContext(RegistryContext);
|
|
@@ -424,47 +412,55 @@ const TableMainInner = <T extends Type.Entity.Any = Type.Entity.Any>(
|
|
|
424
412
|
}, [dxGrid, model, presentation]);
|
|
425
413
|
|
|
426
414
|
if (!model || !modals) {
|
|
427
|
-
return <span role='none' className='attention-surface' />;
|
|
415
|
+
return <span role='none' className='dx-attention-surface' />;
|
|
428
416
|
}
|
|
429
417
|
|
|
418
|
+
const { className, ...rest } = useComposableProps(props);
|
|
430
419
|
return (
|
|
431
|
-
<
|
|
432
|
-
<
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
420
|
+
<div {...rest} role='none' className={mx('dx-container relative', className)}>
|
|
421
|
+
<Grid.Root id={model.id ?? 'table-grid'}>
|
|
422
|
+
<TableValueEditor<T>
|
|
423
|
+
model={model}
|
|
424
|
+
modals={modals}
|
|
425
|
+
schema={schema}
|
|
426
|
+
onFocus={handleFocus}
|
|
427
|
+
onSave={handleSave}
|
|
428
|
+
onCreate={onCreate}
|
|
429
|
+
/>
|
|
430
|
+
<Grid.Content
|
|
431
|
+
className={mx('[--dx-grid-base:var(--base-surface)]', gridSeparatorInlineEnd, gridSeparatorBlockEnd)}
|
|
432
|
+
frozen={frozen}
|
|
433
|
+
columns={columnMeta}
|
|
434
|
+
columnDefault={columnDefault}
|
|
435
|
+
rowDefault={rowDefault}
|
|
436
|
+
limitRows={rows.length}
|
|
437
|
+
limitColumns={columnCount}
|
|
438
|
+
overscroll='trap'
|
|
439
|
+
onAxisResize={handleAxisResize}
|
|
440
|
+
onClick={handleGridClick}
|
|
441
|
+
onKeyDownCapture={handleKeyDown}
|
|
442
|
+
onWheelCapture={handleWheel}
|
|
443
|
+
{...(testId && { 'data-testid': testId })}
|
|
444
|
+
ref={setDxGrid}
|
|
445
|
+
/>
|
|
446
|
+
<RowActionsMenu model={model} modals={modals} />
|
|
447
|
+
<ColumnActionsMenu model={model} modals={modals} />
|
|
448
|
+
<ColumnSettings model={model} modals={modals} onNewColumn={handleNewColumn} />
|
|
449
|
+
</Grid.Root>
|
|
450
|
+
</div>
|
|
460
451
|
);
|
|
461
452
|
};
|
|
462
453
|
|
|
463
|
-
const TableMain = forwardRef(TableMainInner) as <T extends Type.
|
|
454
|
+
const TableMain = forwardRef(TableMainInner) as <T extends Type.AnyEntity = Type.AnyEntity>(
|
|
464
455
|
props: TableMainProps<T> & { ref?: Ref<TableController> },
|
|
465
456
|
) => JSX.Element;
|
|
466
457
|
|
|
458
|
+
//
|
|
459
|
+
// Table
|
|
460
|
+
//
|
|
461
|
+
|
|
467
462
|
export const Table = {
|
|
468
463
|
Root: TableRoot,
|
|
469
464
|
Main: TableMain,
|
|
465
|
+
Toolbar: TableToolbar,
|
|
470
466
|
};
|
|
@@ -22,15 +22,15 @@ export const CellValidationMessage = ({
|
|
|
22
22
|
return null;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
const bgClass = variant === 'error' ? 'bg-
|
|
26
|
-
const textClass = variant === 'error' ? 'text-
|
|
25
|
+
const bgClass = variant === 'error' ? 'bg-error-surface' : 'bg-warning-surface';
|
|
26
|
+
const textClass = variant === 'error' ? 'text-error-surface-text' : 'text-warning-surface-text';
|
|
27
27
|
|
|
28
28
|
return (
|
|
29
29
|
<div
|
|
30
30
|
role='none'
|
|
31
|
-
className={`absolute ${bgClass} ${textClass} rounded-
|
|
31
|
+
className={`absolute ${bgClass} ${textClass} rounded-h-sm text-xs p-1`}
|
|
32
32
|
style={{
|
|
33
|
-
...{ '--dx-
|
|
33
|
+
...{ '--dx-grid-cell-width': `${box?.inlineSize ?? 200}px` },
|
|
34
34
|
zIndex: 10,
|
|
35
35
|
insetBlockEnd: `calc(100% - ${box.insetBlockStart}px)`,
|
|
36
36
|
insetInlineStart: box.insetInlineStart,
|
|
@@ -20,9 +20,9 @@ import { narrowSchema } from '../../util';
|
|
|
20
20
|
|
|
21
21
|
const createOptionLabel: Label = ['create new object label', { ns: translationKey }];
|
|
22
22
|
|
|
23
|
-
export type OnCreateHandler = (schema: Type.
|
|
23
|
+
export type OnCreateHandler = (schema: Type.AnyEntity, values: any) => Parameters<typeof Ref.make>[0];
|
|
24
24
|
|
|
25
|
-
export type FormCellEditorProps<T extends Type.
|
|
25
|
+
export type FormCellEditorProps<T extends Type.AnyEntity = Type.AnyEntity> = {
|
|
26
26
|
__gridScope: any;
|
|
27
27
|
schema?: T;
|
|
28
28
|
model?: TableModel;
|
|
@@ -32,7 +32,7 @@ export type FormCellEditorProps<T extends Type.Entity.Any = Type.Entity.Any> = {
|
|
|
32
32
|
onCreate?: OnCreateHandler;
|
|
33
33
|
} & Omit<FormRootProps<any>, 'values' | 'schema' | 'onCreate'>;
|
|
34
34
|
|
|
35
|
-
export const FormCellEditor = <T extends Type.
|
|
35
|
+
export const FormCellEditor = <T extends Type.AnyEntity = Type.AnyEntity>({
|
|
36
36
|
__gridScope,
|
|
37
37
|
schema,
|
|
38
38
|
model,
|
|
@@ -85,8 +85,12 @@ export const FormCellEditor = <T extends Type.Entity.Any = Type.Entity.Any>({
|
|
|
85
85
|
|
|
86
86
|
// NOTE: Important to get a mutable deep clone to eject from the echo object.
|
|
87
87
|
// TODO(wittjosiah): Consider using something like Obj.clone for this use case.
|
|
88
|
-
const
|
|
88
|
+
const initialFormValues = useMemo(() => (originalRow ? JSON.parse(JSON.stringify(originalRow)) : {}), [originalRow]);
|
|
89
|
+
const [formValues, setFormValues] = useState<any>(initialFormValues);
|
|
89
90
|
|
|
91
|
+
const handleValuesChanged = useCallback<NonNullable<FormRootProps<any>['onValuesChanged']>>((values) => {
|
|
92
|
+
setFormValues(values);
|
|
93
|
+
}, []);
|
|
90
94
|
const handleOpenChange = useCallback((nextOpen: boolean) => {
|
|
91
95
|
if (nextOpen === false) {
|
|
92
96
|
setEditing(null);
|
|
@@ -162,7 +166,7 @@ export const FormCellEditor = <T extends Type.Entity.Any = Type.Entity.Any>({
|
|
|
162
166
|
<Popover.Root open={editing} onOpenChange={handleOpenChange}>
|
|
163
167
|
<Popover.VirtualTrigger virtualRef={anchorRef} />
|
|
164
168
|
<Popover.Portal>
|
|
165
|
-
<Popover.Content tabIndex={-1} classNames='
|
|
169
|
+
<Popover.Content tabIndex={-1} classNames='dx-card-popover-width dx-density-fine'>
|
|
166
170
|
<Popover.Arrow />
|
|
167
171
|
<Popover.Viewport>
|
|
168
172
|
<Form.Root
|
|
@@ -170,6 +174,8 @@ export const FormCellEditor = <T extends Type.Entity.Any = Type.Entity.Any>({
|
|
|
170
174
|
autoFocus
|
|
171
175
|
schema={narrowedSchema}
|
|
172
176
|
values={formValues}
|
|
177
|
+
onValuesChanged={handleValuesChanged}
|
|
178
|
+
projection={model?.projection}
|
|
173
179
|
createInitialValuePath={fieldProjection.field.referencePath}
|
|
174
180
|
createOptionIcon='ph--plus--regular'
|
|
175
181
|
createOptionLabel={createOptionLabel}
|