@dxos/react-ui-table 0.6.11 → 0.6.12-main.2d19bf1
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 +41 -125
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/types/src/components/ColumnMenu/ColumnMenu.d.ts +6 -3
- package/dist/types/src/components/ColumnMenu/ColumnMenu.d.ts.map +1 -1
- package/dist/types/src/components/ColumnMenu/ColumnMenu.stories.d.ts +3 -3
- package/dist/types/src/components/ColumnMenu/ColumnMenu.stories.d.ts.map +1 -1
- package/dist/types/src/components/ColumnMenu/ColumnSettings.d.ts +15 -0
- package/dist/types/src/components/ColumnMenu/ColumnSettings.d.ts.map +1 -0
- package/dist/types/src/components/ColumnMenu/ColumnSettings.stories.d.ts +84 -0
- package/dist/types/src/components/ColumnMenu/ColumnSettings.stories.d.ts.map +1 -0
- package/dist/types/src/components/ColumnMenu/index.d.ts +1 -1
- package/dist/types/src/components/ColumnMenu/index.d.ts.map +1 -1
- package/dist/types/src/components/Table/Table.d.ts.map +1 -1
- package/dist/types/src/components/Table/Table.stories.d.ts +21 -9
- package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
- package/dist/types/src/components/Table/TableContext.d.ts +2 -4
- package/dist/types/src/components/Table/TableContext.d.ts.map +1 -1
- package/dist/types/src/components/Table/TableHead.d.ts.map +1 -1
- package/dist/types/src/components/Table/index.d.ts +2 -1
- package/dist/types/src/components/Table/index.d.ts.map +1 -1
- package/dist/types/src/helpers.d.ts +1 -1
- package/dist/types/src/helpers.d.ts.map +1 -1
- package/dist/types/src/hooks/useRowSelection.d.ts.map +1 -1
- package/dist/types/src/schema/{SchemaToTable.stories.d.ts → Schema.stories.d.ts} +2 -3
- package/dist/types/src/schema/Schema.stories.d.ts.map +1 -0
- package/dist/types/src/schema/{schemaToColumns.d.ts → column-utils.d.ts} +2 -2
- package/dist/types/src/schema/column-utils.d.ts.map +1 -0
- package/dist/types/src/schema/index.d.ts +1 -1
- package/dist/types/src/schema/index.d.ts.map +1 -1
- package/dist/types/src/schema/types.d.ts +4 -4
- package/dist/types/src/schema/types.d.ts.map +1 -1
- package/package.json +21 -20
- package/src/components/ColumnMenu/ColumnMenu.stories.tsx +13 -12
- package/src/components/ColumnMenu/ColumnMenu.tsx +8 -5
- package/src/components/ColumnMenu/{ColumnSettingsForm.stories.tsx → ColumnSettings.stories.tsx} +27 -23
- package/src/components/ColumnMenu/{ColumnSettingsForm.tsx → ColumnSettings.tsx} +42 -40
- package/src/components/ColumnMenu/index.ts +1 -1
- package/src/components/Table/Table.stories.tsx +97 -85
- package/src/components/Table/Table.tsx +8 -9
- package/src/components/Table/TableContext.tsx +13 -7
- package/src/components/Table/TableHead.tsx +0 -1
- package/src/components/Table/index.ts +2 -1
- package/src/components/Table/props.ts +4 -4
- package/src/helpers.tsx +4 -6
- package/src/hooks/useRowSelection.ts +1 -0
- package/src/schema/{SchemaToTable.stories.tsx → Schema.stories.tsx} +11 -23
- package/src/schema/{schemaToColumns.ts → column-utils.ts} +9 -9
- package/src/schema/index.ts +1 -1
- package/src/schema/types.ts +8 -6
- package/src/translations.ts +1 -1
- package/dist/types/src/components/ColumnMenu/ColumnSettingsForm.d.ts +0 -12
- package/dist/types/src/components/ColumnMenu/ColumnSettingsForm.d.ts.map +0 -1
- package/dist/types/src/components/ColumnMenu/ColumnSettingsForm.stories.d.ts +0 -63
- package/dist/types/src/components/ColumnMenu/ColumnSettingsForm.stories.d.ts.map +0 -1
- package/dist/types/src/schema/SchemaToTable.stories.d.ts.map +0 -1
- package/dist/types/src/schema/schema.d.ts +0 -5
- package/dist/types/src/schema/schema.d.ts.map +0 -1
- package/dist/types/src/schema/schema.test.d.ts +0 -2
- package/dist/types/src/schema/schema.test.d.ts.map +0 -1
- package/dist/types/src/schema/schemaToColumns.d.ts.map +0 -1
- package/src/schema/schema.test.ts +0 -148
- package/src/schema/schema.ts +0 -93
|
@@ -7,11 +7,12 @@ import '@dxos-theme';
|
|
|
7
7
|
import { type SortDirection } from '@tanstack/react-table';
|
|
8
8
|
import React, { useState } from 'react';
|
|
9
9
|
|
|
10
|
+
import { FieldValueType } from '@dxos/schema';
|
|
10
11
|
import { withTheme } from '@dxos/storybook-utils';
|
|
11
12
|
|
|
12
13
|
import { ColumnMenu } from './ColumnMenu';
|
|
13
|
-
import { type
|
|
14
|
-
import { type
|
|
14
|
+
import { type ColumnSettingsProps } from './ColumnSettings';
|
|
15
|
+
import { type ColumnDef } from '../../schema';
|
|
15
16
|
|
|
16
17
|
export default {
|
|
17
18
|
title: 'react-ui-table/ColumnMenu',
|
|
@@ -19,27 +20,27 @@ export default {
|
|
|
19
20
|
decorators: [withTheme],
|
|
20
21
|
};
|
|
21
22
|
|
|
22
|
-
const defs: Pick<
|
|
23
|
+
const defs: Pick<ColumnSettingsProps, 'tableDef' | 'tablesToReference'> = {
|
|
23
24
|
tableDef: {
|
|
24
25
|
id: '1',
|
|
25
26
|
name: 'table 1',
|
|
26
|
-
columns: [{ id: 'col-1', prop: 'one
|
|
27
|
+
columns: [{ id: 'col-1', prop: 'one', type: FieldValueType.String }],
|
|
27
28
|
},
|
|
28
29
|
tablesToReference: [
|
|
29
30
|
{
|
|
30
31
|
id: '1',
|
|
31
32
|
name: 'table 1',
|
|
32
|
-
columns: [{ id: 'col-1', prop: 'one
|
|
33
|
+
columns: [{ id: 'col-1', prop: 'one', type: FieldValueType.String }],
|
|
33
34
|
},
|
|
34
35
|
{
|
|
35
36
|
id: '2',
|
|
36
37
|
name: 'table 2',
|
|
37
|
-
columns: [{ id: 'col-1', prop: 'two
|
|
38
|
+
columns: [{ id: 'col-1', prop: 'two', type: FieldValueType.String }],
|
|
38
39
|
},
|
|
39
40
|
],
|
|
40
41
|
};
|
|
41
42
|
|
|
42
|
-
const
|
|
43
|
+
const functions: Pick<ColumnSettingsProps, 'onUpdate' | 'onDelete'> = {
|
|
43
44
|
onUpdate: (...args: any) => console.log('onUpdate args', args),
|
|
44
45
|
onDelete: (...args: any) => console.log('onDelete args', args),
|
|
45
46
|
};
|
|
@@ -49,10 +50,10 @@ export const Default = {
|
|
|
49
50
|
column: {
|
|
50
51
|
id: 'test',
|
|
51
52
|
label: 'test',
|
|
52
|
-
} as
|
|
53
|
+
} as ColumnDef,
|
|
53
54
|
|
|
54
55
|
...defs,
|
|
55
|
-
...
|
|
56
|
+
...functions,
|
|
56
57
|
|
|
57
58
|
context: {
|
|
58
59
|
header: {
|
|
@@ -89,11 +90,13 @@ export const ReactiveSort = {
|
|
|
89
90
|
column: {
|
|
90
91
|
id: 'test',
|
|
91
92
|
label: 'test',
|
|
92
|
-
} as
|
|
93
|
+
} as ColumnDef,
|
|
93
94
|
context: {
|
|
94
95
|
header: {
|
|
95
96
|
column: {
|
|
96
97
|
getCanSort: () => true,
|
|
98
|
+
getIsSorted: () => sort,
|
|
99
|
+
clearSorting: () => setSort(false),
|
|
97
100
|
toggleSorting: (desc?: boolean) => {
|
|
98
101
|
if (desc === undefined) {
|
|
99
102
|
setSort(false);
|
|
@@ -103,8 +106,6 @@ export const ReactiveSort = {
|
|
|
103
106
|
setSort('asc');
|
|
104
107
|
}
|
|
105
108
|
},
|
|
106
|
-
getIsSorted: () => sort,
|
|
107
|
-
clearSorting: () => setSort(false),
|
|
108
109
|
getToggleSortingHandler: () => () => {
|
|
109
110
|
if (sort === 'asc') {
|
|
110
111
|
setSort('desc');
|
|
@@ -9,22 +9,25 @@ import React, { useRef, useState, useCallback } from 'react';
|
|
|
9
9
|
import { Button, Popover, DropdownMenu } from '@dxos/react-ui';
|
|
10
10
|
import { getSize, mx } from '@dxos/react-ui-theme';
|
|
11
11
|
|
|
12
|
-
import {
|
|
12
|
+
import { ColumnSettings } from './ColumnSettings';
|
|
13
13
|
import { useSortColumn } from '../../hooks';
|
|
14
|
-
import { type TableDef, type
|
|
14
|
+
import { type TableDef, type ColumnDef } from '../../schema';
|
|
15
15
|
|
|
16
16
|
export type ColumnMenuProps<TData extends RowData, TValue> = {
|
|
17
17
|
context: HeaderContext<TData, TValue>;
|
|
18
18
|
tablesToReference: TableDef[];
|
|
19
19
|
tableDef: TableDef;
|
|
20
|
-
column:
|
|
20
|
+
column: ColumnDef;
|
|
21
21
|
columnOrderable: boolean;
|
|
22
22
|
columnPosition: 'start' | 'end' | undefined;
|
|
23
23
|
onColumnReorder: (columnId: string, direction: 'left' | 'right') => void;
|
|
24
|
-
onUpdate?: (id: string, column:
|
|
24
|
+
onUpdate?: (id: string, column: ColumnDef) => void;
|
|
25
25
|
onDelete?: (id: string) => void;
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
+
/**
|
|
29
|
+
* @deprecated
|
|
30
|
+
*/
|
|
28
31
|
export const ColumnMenu = <TData extends RowData, TValue>({
|
|
29
32
|
column,
|
|
30
33
|
columnOrderable,
|
|
@@ -138,7 +141,7 @@ export const ColumnMenu = <TData extends RowData, TValue>({
|
|
|
138
141
|
<Popover.Portal>
|
|
139
142
|
<Popover.Content>
|
|
140
143
|
<Popover.Viewport>
|
|
141
|
-
<
|
|
144
|
+
<ColumnSettings {...props} column={column} onClose={() => setIsColumnSettingsOpen(false)} />
|
|
142
145
|
</Popover.Viewport>
|
|
143
146
|
<Popover.Arrow />
|
|
144
147
|
</Popover.Content>
|
package/src/components/ColumnMenu/{ColumnSettingsForm.stories.tsx → ColumnSettings.stories.tsx}
RENAMED
|
@@ -3,25 +3,38 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import '@dxos-theme';
|
|
6
|
+
|
|
6
7
|
import React from 'react';
|
|
7
8
|
|
|
8
|
-
import {
|
|
9
|
+
import { FieldValueType } from '@dxos/schema';
|
|
10
|
+
import { withTheme, withLayout } from '@dxos/storybook-utils';
|
|
9
11
|
|
|
10
|
-
import {
|
|
12
|
+
import { ColumnSettings, type ColumnSettingsProps } from './ColumnSettings';
|
|
11
13
|
import { type TableDef } from '../../schema';
|
|
14
|
+
import translations from '../../translations';
|
|
15
|
+
|
|
16
|
+
const Story = (props: ColumnSettingsProps) => (
|
|
17
|
+
<div className='flex w-[240px] m-2 p-2 border border-separator rounded'>
|
|
18
|
+
<ColumnSettings {...props} />
|
|
19
|
+
</div>
|
|
20
|
+
);
|
|
12
21
|
|
|
13
22
|
export default {
|
|
14
|
-
title: 'react-ui-table/
|
|
15
|
-
component:
|
|
16
|
-
decorators: [withTheme],
|
|
23
|
+
title: 'react-ui-table/ColumnSettings',
|
|
24
|
+
component: ColumnSettings,
|
|
25
|
+
decorators: [withTheme, withLayout()],
|
|
26
|
+
parameters: {
|
|
27
|
+
translations,
|
|
28
|
+
},
|
|
29
|
+
render: Story,
|
|
17
30
|
};
|
|
18
31
|
|
|
19
32
|
const sampleTableDef: TableDef = {
|
|
20
33
|
id: '1',
|
|
21
34
|
name: 'Sample Table',
|
|
22
35
|
columns: [
|
|
23
|
-
{ id: 'col-1', prop: 'name', type:
|
|
24
|
-
{ id: 'col-2', prop: 'age', type:
|
|
36
|
+
{ id: 'col-1', prop: 'name', type: FieldValueType.String, label: 'Name' },
|
|
37
|
+
{ id: 'col-2', prop: 'age', type: FieldValueType.Number, label: 'Age', digits: 0 },
|
|
25
38
|
],
|
|
26
39
|
};
|
|
27
40
|
|
|
@@ -31,17 +44,17 @@ const sampleTablesToReference: TableDef[] = [
|
|
|
31
44
|
id: '2',
|
|
32
45
|
name: 'Reference Table',
|
|
33
46
|
columns: [
|
|
34
|
-
{ id: 'ref-col-1', prop: 'id', type:
|
|
35
|
-
{ id: 'ref-col-2', prop: 'description', type:
|
|
47
|
+
{ id: 'ref-col-1', prop: 'id', type: FieldValueType.String, label: 'ID' },
|
|
48
|
+
{ id: 'ref-col-2', prop: 'description', type: FieldValueType.String, label: 'Description' },
|
|
36
49
|
],
|
|
37
50
|
},
|
|
38
51
|
];
|
|
39
52
|
|
|
40
|
-
const defaultArgs:
|
|
53
|
+
const defaultArgs: ColumnSettingsProps = {
|
|
41
54
|
column: {
|
|
42
55
|
id: 'col-1',
|
|
43
56
|
prop: 'name',
|
|
44
|
-
type:
|
|
57
|
+
type: FieldValueType.String,
|
|
45
58
|
label: 'Name',
|
|
46
59
|
},
|
|
47
60
|
tableDef: sampleTableDef,
|
|
@@ -61,7 +74,7 @@ export const NumberColumn = {
|
|
|
61
74
|
column: {
|
|
62
75
|
id: 'col-2',
|
|
63
76
|
prop: 'age',
|
|
64
|
-
type:
|
|
77
|
+
type: FieldValueType.Number,
|
|
65
78
|
label: 'Age',
|
|
66
79
|
digits: 0,
|
|
67
80
|
},
|
|
@@ -74,7 +87,7 @@ export const ReferenceColumn = {
|
|
|
74
87
|
column: {
|
|
75
88
|
id: 'col-3',
|
|
76
89
|
prop: 'reference',
|
|
77
|
-
type:
|
|
90
|
+
type: FieldValueType.Ref,
|
|
78
91
|
label: 'Reference',
|
|
79
92
|
refTable: '2',
|
|
80
93
|
refProp: 'ref-col-1',
|
|
@@ -88,17 +101,8 @@ export const NewColumn = {
|
|
|
88
101
|
column: {
|
|
89
102
|
id: 'new-col',
|
|
90
103
|
prop: '',
|
|
91
|
-
type:
|
|
104
|
+
type: FieldValueType.String,
|
|
92
105
|
label: '',
|
|
93
106
|
},
|
|
94
107
|
},
|
|
95
108
|
};
|
|
96
|
-
|
|
97
|
-
const Template = (args: ColumnSettingsFormProps) => (
|
|
98
|
-
<div className='p-4 max-is-64'>
|
|
99
|
-
<ColumnSettingsForm {...args} />
|
|
100
|
-
</div>
|
|
101
|
-
);
|
|
102
|
-
|
|
103
|
-
export const Interactive = Template.bind({});
|
|
104
|
-
(Interactive as any).args = defaultArgs;
|
|
@@ -1,31 +1,37 @@
|
|
|
1
1
|
//
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
|
+
|
|
4
5
|
import React, { useRef, useState } from 'react';
|
|
5
6
|
|
|
6
7
|
import { Button, Input, Select, useTranslation } from '@dxos/react-ui';
|
|
8
|
+
import { FieldValueTypes } from '@dxos/schema';
|
|
7
9
|
import { safeParseInt } from '@dxos/util';
|
|
8
10
|
|
|
9
|
-
import { type TableDef, type
|
|
11
|
+
import { type TableDef, type ColumnDef } from '../../schema';
|
|
10
12
|
import { translationKey } from '../../translations';
|
|
11
13
|
|
|
12
|
-
export type
|
|
13
|
-
column:
|
|
14
|
+
export type ColumnSettingsProps = {
|
|
15
|
+
column: ColumnDef;
|
|
14
16
|
tableDef: TableDef;
|
|
17
|
+
// TODO(burdon): Rename.
|
|
15
18
|
tablesToReference: TableDef[];
|
|
16
|
-
onUpdate?: (
|
|
17
|
-
onDelete?: (
|
|
19
|
+
onUpdate?: (id: string, column: ColumnDef) => void;
|
|
20
|
+
onDelete?: (id: string) => void;
|
|
18
21
|
onClose?: () => void;
|
|
19
22
|
};
|
|
20
23
|
|
|
21
|
-
|
|
24
|
+
/**
|
|
25
|
+
* @deprecated
|
|
26
|
+
*/
|
|
27
|
+
export const ColumnSettings = ({
|
|
22
28
|
column,
|
|
23
29
|
tableDef,
|
|
24
30
|
tablesToReference,
|
|
25
31
|
onUpdate,
|
|
26
32
|
onDelete,
|
|
27
33
|
onClose,
|
|
28
|
-
}:
|
|
34
|
+
}: ColumnSettingsProps) => {
|
|
29
35
|
const [formState, setFormState] = useState({
|
|
30
36
|
prop: column.id,
|
|
31
37
|
refTable: column.refTable,
|
|
@@ -62,7 +68,7 @@ export const ColumnSettingsForm = ({
|
|
|
62
68
|
id: prop, // TODO(burdon): Make unique.
|
|
63
69
|
prop,
|
|
64
70
|
label,
|
|
65
|
-
type: type as
|
|
71
|
+
type: type as ColumnDef['type'],
|
|
66
72
|
refTable,
|
|
67
73
|
refProp,
|
|
68
74
|
digits: safeParseInt(digits),
|
|
@@ -75,9 +81,10 @@ export const ColumnSettingsForm = ({
|
|
|
75
81
|
onClose?.();
|
|
76
82
|
};
|
|
77
83
|
|
|
84
|
+
// TODO(burdon): Standardize dialog/popup.
|
|
78
85
|
return (
|
|
79
|
-
<div className='
|
|
80
|
-
<div className='
|
|
86
|
+
<div className='flex flex-col w-full gap-4'>
|
|
87
|
+
<div className='flex flex-col gap-2'>
|
|
81
88
|
<Input.Root>
|
|
82
89
|
<Input.Label>{t('column label label')}</Input.Label>
|
|
83
90
|
<Input.TextInput
|
|
@@ -88,8 +95,7 @@ export const ColumnSettingsForm = ({
|
|
|
88
95
|
data-testid='table.column-settings.label'
|
|
89
96
|
/>
|
|
90
97
|
</Input.Root>
|
|
91
|
-
|
|
92
|
-
<div className='space-y-1'>
|
|
98
|
+
|
|
93
99
|
<Input.Root>
|
|
94
100
|
<Input.Label>{t('property key label')}</Input.Label>
|
|
95
101
|
<Input.TextInput
|
|
@@ -101,8 +107,7 @@ export const ColumnSettingsForm = ({
|
|
|
101
107
|
}
|
|
102
108
|
/>
|
|
103
109
|
</Input.Root>
|
|
104
|
-
|
|
105
|
-
<div className='space-y-1'>
|
|
110
|
+
|
|
106
111
|
<Input.Root>
|
|
107
112
|
<Input.Label>{t('column type label')}</Input.Label>
|
|
108
113
|
<Select.Root
|
|
@@ -113,7 +118,7 @@ export const ColumnSettingsForm = ({
|
|
|
113
118
|
<Select.Portal>
|
|
114
119
|
<Select.Content>
|
|
115
120
|
<Select.Viewport>
|
|
116
|
-
{
|
|
121
|
+
{FieldValueTypes.map((type) => (
|
|
117
122
|
<Select.Option key={type} value={type}>
|
|
118
123
|
{t(`${type} column type label`)}
|
|
119
124
|
</Select.Option>
|
|
@@ -123,9 +128,8 @@ export const ColumnSettingsForm = ({
|
|
|
123
128
|
</Select.Portal>
|
|
124
129
|
</Select.Root>
|
|
125
130
|
</Input.Root>
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
<div className='space-y-1'>
|
|
131
|
+
|
|
132
|
+
{formState.type === 'number' && (
|
|
129
133
|
<Input.Root>
|
|
130
134
|
<Input.Label>{t('digits label')}</Input.Label>
|
|
131
135
|
<Input.TextInput
|
|
@@ -133,12 +137,10 @@ export const ColumnSettingsForm = ({
|
|
|
133
137
|
onChange={(event) => setFormState((prevState) => ({ ...prevState, digits: event.target.value }))}
|
|
134
138
|
/>
|
|
135
139
|
</Input.Root>
|
|
136
|
-
|
|
137
|
-
)}
|
|
140
|
+
)}
|
|
138
141
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
<div className='space-y-1'>
|
|
142
|
+
{formState.type === 'ref' && (
|
|
143
|
+
<>
|
|
142
144
|
<Input.Root>
|
|
143
145
|
<Input.Label>Table</Input.Label>
|
|
144
146
|
<Select.Root
|
|
@@ -161,9 +163,8 @@ export const ColumnSettingsForm = ({
|
|
|
161
163
|
</Select.Portal>
|
|
162
164
|
</Select.Root>
|
|
163
165
|
</Input.Root>
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
<div className='space-y-1'>
|
|
166
|
+
|
|
167
|
+
{formState.refTable && (
|
|
167
168
|
<Input.Root>
|
|
168
169
|
<Input.Label>Table property</Input.Label>
|
|
169
170
|
<Select.Root
|
|
@@ -186,20 +187,21 @@ export const ColumnSettingsForm = ({
|
|
|
186
187
|
</Select.Portal>
|
|
187
188
|
</Select.Root>
|
|
188
189
|
</Input.Root>
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
<div
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
190
|
+
)}
|
|
191
|
+
</>
|
|
192
|
+
)}
|
|
193
|
+
</div>
|
|
194
|
+
|
|
195
|
+
<div>
|
|
196
|
+
{/* TODO(burdon): Change delete to cancel. Delete should be menu item. */}
|
|
197
|
+
<div className='flex flex-row justify-end gap-1'>
|
|
198
|
+
<Button onClick={handleDelete} data-testid='table.column-settings.delete'>
|
|
199
|
+
{t('delete label')}
|
|
200
|
+
</Button>
|
|
201
|
+
<Button variant='primary' onClick={handleSave} data-testid='table.column-settings.save'>
|
|
202
|
+
{t('save label')}
|
|
203
|
+
</Button>
|
|
204
|
+
</div>
|
|
203
205
|
</div>
|
|
204
206
|
</div>
|
|
205
207
|
);
|
|
@@ -8,11 +8,11 @@ import { Plugs, PlugsConnected } from '@phosphor-icons/react';
|
|
|
8
8
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
9
9
|
|
|
10
10
|
import { create } from '@dxos/echo-schema';
|
|
11
|
-
import { registerSignalRuntime } from '@dxos/echo-signals/react';
|
|
12
11
|
import { PublicKey } from '@dxos/keys';
|
|
12
|
+
import { log } from '@dxos/log';
|
|
13
13
|
import { faker } from '@dxos/random';
|
|
14
14
|
import { Button, DensityProvider } from '@dxos/react-ui';
|
|
15
|
-
import { withTheme } from '@dxos/storybook-utils';
|
|
15
|
+
import { withSignals, withTheme } from '@dxos/storybook-utils';
|
|
16
16
|
import { range } from '@dxos/util';
|
|
17
17
|
|
|
18
18
|
import { Table } from './Table';
|
|
@@ -406,105 +406,117 @@ export const TenThousandRows = {
|
|
|
406
406
|
},
|
|
407
407
|
};
|
|
408
408
|
|
|
409
|
-
|
|
410
|
-
const state = create({ items: createItems(10) });
|
|
409
|
+
// TODO(burdon): Warning: Encountered two children with the same key.
|
|
411
410
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
if (
|
|
411
|
+
type StoryProps = {
|
|
412
|
+
periodicMutations: boolean;
|
|
413
|
+
mutationInterval: number;
|
|
414
|
+
periodicDeletions: boolean;
|
|
415
|
+
deletionInterval: number;
|
|
416
|
+
periodicInsertions: boolean;
|
|
417
|
+
insertionInterval: number;
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
const Story = ({
|
|
421
|
+
periodicMutations,
|
|
422
|
+
mutationInterval,
|
|
423
|
+
periodicDeletions,
|
|
424
|
+
deletionInterval,
|
|
425
|
+
periodicInsertions,
|
|
426
|
+
insertionInterval,
|
|
427
|
+
}: StoryProps) => {
|
|
428
|
+
const [state] = useState(() => create({ items: createItems(10) }));
|
|
429
|
+
|
|
430
|
+
useEffect(() => {
|
|
431
|
+
if (!periodicMutations) {
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
const i = setInterval(() => {
|
|
436
|
+
if (state.items.length === 0) {
|
|
438
437
|
return;
|
|
439
438
|
}
|
|
440
439
|
|
|
441
|
-
const
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
440
|
+
const idx = Math.floor(Math.random() * state.items.length);
|
|
441
|
+
log('mutating', { idx });
|
|
442
|
+
state.items[idx].name = faker.commerce.productName();
|
|
443
|
+
state.items[idx].count = Math.floor(Math.random() * 1000);
|
|
444
|
+
state.items[idx].started = new Date();
|
|
445
|
+
}, mutationInterval);
|
|
445
446
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
state.items[randomIndex].name = faker.commerce.productName();
|
|
449
|
-
state.items[randomIndex].count = Math.floor(Math.random() * 1000);
|
|
450
|
-
state.items[randomIndex].started = new Date();
|
|
451
|
-
}, mutationInterval);
|
|
447
|
+
return () => clearInterval(i);
|
|
448
|
+
}, [periodicMutations, mutationInterval, state.items]);
|
|
452
449
|
|
|
453
|
-
|
|
454
|
-
|
|
450
|
+
useEffect(() => {
|
|
451
|
+
if (!periodicInsertions) {
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
455
454
|
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
455
|
+
const i = setInterval(() => {
|
|
456
|
+
log('inserting...');
|
|
457
|
+
state.items.push(createItems(1)[0]);
|
|
458
|
+
}, insertionInterval);
|
|
460
459
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
state.items.push(createItems(1)[0]);
|
|
464
|
-
}, insertionInterval);
|
|
460
|
+
return () => clearInterval(i);
|
|
461
|
+
}, [periodicInsertions, insertionInterval, state.items]);
|
|
465
462
|
|
|
466
|
-
|
|
467
|
-
|
|
463
|
+
useEffect(() => {
|
|
464
|
+
if (!periodicDeletions) {
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
468
467
|
|
|
469
|
-
|
|
470
|
-
if (
|
|
468
|
+
const i = setInterval(() => {
|
|
469
|
+
if (state.items.length === 0) {
|
|
471
470
|
return;
|
|
472
471
|
}
|
|
473
472
|
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
console.log('Deleting');
|
|
473
|
+
log('deleting...');
|
|
474
|
+
const randomIndex = Math.floor(Math.random() * state.items.length);
|
|
475
|
+
state.items.splice(randomIndex, 1);
|
|
476
|
+
}, deletionInterval);
|
|
480
477
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
state.items.splice(randomIndex, 1);
|
|
484
|
-
}, deletionInterval);
|
|
478
|
+
return () => clearInterval(i);
|
|
479
|
+
}, [periodicDeletions, deletionInterval, state.items]);
|
|
485
480
|
|
|
486
|
-
|
|
487
|
-
|
|
481
|
+
const onUpdate = useCallback((...args: any[]) => {}, []);
|
|
482
|
+
const columns = useMemo(() => makeColumns(onUpdate), []);
|
|
488
483
|
|
|
489
|
-
|
|
490
|
-
|
|
484
|
+
return (
|
|
485
|
+
<Table.Root>
|
|
486
|
+
<Table.Viewport classNames='fixed inset-0'>
|
|
487
|
+
<Table.Main<Item>
|
|
488
|
+
role='grid'
|
|
489
|
+
rowsSelectable='multi'
|
|
490
|
+
keyAccessor={(row) => row.publicKey.toHex()}
|
|
491
|
+
columns={columns}
|
|
492
|
+
data={state.items}
|
|
493
|
+
fullWidth
|
|
494
|
+
stickyHeader
|
|
495
|
+
border
|
|
496
|
+
pinLastRow
|
|
497
|
+
/>
|
|
498
|
+
</Table.Viewport>
|
|
499
|
+
</Table.Root>
|
|
500
|
+
);
|
|
501
|
+
};
|
|
491
502
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
data={state.items}
|
|
501
|
-
fullWidth
|
|
502
|
-
stickyHeader
|
|
503
|
-
border
|
|
504
|
-
pinLastRow
|
|
505
|
-
/>
|
|
506
|
-
</Table.Viewport>
|
|
507
|
-
</Table.Root>
|
|
508
|
-
);
|
|
503
|
+
export const RealTimeUpdates = {
|
|
504
|
+
argTypes: {
|
|
505
|
+
periodicMutations: { control: 'boolean' },
|
|
506
|
+
mutationInterval: { control: 'number' },
|
|
507
|
+
periodicDeletions: { control: 'boolean' },
|
|
508
|
+
deletionInterval: { control: 'number' },
|
|
509
|
+
periodicInsertions: { control: 'boolean' },
|
|
510
|
+
insertionInterval: { control: 'number' },
|
|
509
511
|
},
|
|
512
|
+
args: {
|
|
513
|
+
periodicMutations: true,
|
|
514
|
+
mutationInterval: 1000,
|
|
515
|
+
periodicDeletions: false,
|
|
516
|
+
deletionInterval: 5000,
|
|
517
|
+
periodicInsertions: false,
|
|
518
|
+
insertionInterval: 3000,
|
|
519
|
+
} satisfies StoryProps,
|
|
520
|
+
decorators: [withSignals],
|
|
521
|
+
render: Story,
|
|
510
522
|
};
|
|
@@ -16,13 +16,13 @@ import {
|
|
|
16
16
|
} from '@tanstack/react-table';
|
|
17
17
|
import React, {
|
|
18
18
|
type ComponentPropsWithoutRef,
|
|
19
|
+
type ReactNode,
|
|
19
20
|
Fragment,
|
|
21
|
+
memo,
|
|
20
22
|
useCallback,
|
|
21
23
|
useEffect,
|
|
22
24
|
useState,
|
|
23
25
|
useContext,
|
|
24
|
-
type ReactNode,
|
|
25
|
-
memo,
|
|
26
26
|
} from 'react';
|
|
27
27
|
|
|
28
28
|
import { DensityProvider, type ThemedClassName, useDefaultValue } from '@dxos/react-ui';
|
|
@@ -55,7 +55,6 @@ const TableViewport = ({ children, classNames, asChild, ...props }: TableViewpor
|
|
|
55
55
|
const { scrollContextRef } = useContext(TableRootContext);
|
|
56
56
|
|
|
57
57
|
const classes = mx(classNames, 'overflow-auto');
|
|
58
|
-
|
|
59
58
|
return asChild ? (
|
|
60
59
|
<Slot ref={scrollContextRef} className={classes} {...props}>
|
|
61
60
|
{children}
|
|
@@ -70,17 +69,17 @@ const TableViewport = ({ children, classNames, asChild, ...props }: TableViewpor
|
|
|
70
69
|
export const TablePrimitive = <TData extends RowData>(props: TableProps<TData>) => {
|
|
71
70
|
const {
|
|
72
71
|
role,
|
|
73
|
-
onColumnResize,
|
|
74
|
-
columnVisibility,
|
|
75
72
|
header = true,
|
|
76
73
|
rowsSelectable,
|
|
77
74
|
debug,
|
|
78
|
-
onDataSelectionChange,
|
|
79
75
|
pinLastRow,
|
|
76
|
+
columnVisibility,
|
|
77
|
+
onColumnResize,
|
|
78
|
+
onDataSelectionChange,
|
|
80
79
|
} = props;
|
|
81
80
|
|
|
82
|
-
const columns = useDefaultValue(props.columns, []);
|
|
83
|
-
const incomingData = useDefaultValue(props.data, []);
|
|
81
|
+
const columns = useDefaultValue(props.columns, () => []);
|
|
82
|
+
const incomingData = useDefaultValue(props.data, () => []);
|
|
84
83
|
|
|
85
84
|
const [data, setData] = useState([...incomingData]);
|
|
86
85
|
|
|
@@ -110,7 +109,7 @@ export const TablePrimitive = <TData extends RowData>(props: TableProps<TData>)
|
|
|
110
109
|
// Columns
|
|
111
110
|
columns,
|
|
112
111
|
defaultColumn: {
|
|
113
|
-
size:
|
|
112
|
+
size: 400, // Required in order remove default width.
|
|
114
113
|
maxSize: 1024,
|
|
115
114
|
},
|
|
116
115
|
|