@dxos/react-ui-table 0.6.7-staging.e9eb1ed → 0.6.8-main.046e6cf
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 +189 -213
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/types/src/components/Cell/Cell.d.ts +2 -2
- package/dist/types/src/components/Cell/Cell.d.ts.map +1 -1
- package/dist/types/src/components/Cell/CellCombobox.d.ts +3 -3
- package/dist/types/src/components/Cell/CellCombobox.d.ts.map +1 -1
- package/dist/types/src/components/ColumnMenu/ColumnMenu.d.ts +3 -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/ColumnSettingsForm.d.ts +2 -2
- package/dist/types/src/components/ColumnMenu/ColumnSettingsForm.d.ts.map +1 -1
- package/dist/types/src/components/ColumnMenu/ColumnSettingsForm.stories.d.ts +63 -0
- package/dist/types/src/components/ColumnMenu/ColumnSettingsForm.stories.d.ts.map +1 -0
- package/dist/types/src/components/Table/Table.d.ts +6 -5
- package/dist/types/src/components/Table/Table.d.ts.map +1 -1
- package/dist/types/src/components/Table/Table.stories.d.ts +9 -9
- package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
- package/dist/types/src/components/Table/TableBody.d.ts +2 -2
- package/dist/types/src/components/Table/TableBody.d.ts.map +1 -1
- package/dist/types/src/components/Table/TableContext.d.ts +2 -2
- package/dist/types/src/components/Table/TableContext.d.ts.map +1 -1
- package/dist/types/src/components/Table/TableHead.d.ts +2 -2
- package/dist/types/src/components/Table/TableHead.d.ts.map +1 -1
- package/dist/types/src/components/Table/TableRootContext.d.ts +0 -1
- package/dist/types/src/components/Table/TableRootContext.d.ts.map +1 -1
- package/dist/types/src/components/Table/props.d.ts +0 -1
- package/dist/types/src/components/Table/props.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/useColumnSizing.d.ts +0 -1
- package/dist/types/src/hooks/useColumnSizing.d.ts.map +1 -1
- package/dist/types/src/hooks/useColumnSorting.d.ts.map +1 -1
- package/dist/types/src/hooks/usePinLastRow.d.ts.map +1 -1
- package/dist/types/src/hooks/useRowSelection.d.ts +1 -1
- package/dist/types/src/hooks/useRowSelection.d.ts.map +1 -1
- package/dist/types/src/schema/SchemaToTable.stories.d.ts +2 -1
- package/dist/types/src/schema/SchemaToTable.stories.d.ts.map +1 -1
- package/dist/types/src/schema/schema.d.ts.map +1 -1
- package/dist/types/src/schema/schemaToColumns.d.ts.map +1 -1
- package/dist/types/src/theme.d.ts +6 -10
- package/dist/types/src/theme.d.ts.map +1 -1
- package/package.json +17 -17
- package/src/components/Cell/Cell.tsx +46 -4
- package/src/components/ColumnMenu/ColumnMenu.tsx +6 -8
- package/src/components/ColumnMenu/ColumnSettingsForm.stories.tsx +104 -0
- package/src/components/ColumnMenu/ColumnSettingsForm.tsx +60 -73
- package/src/components/Table/Table.stories.tsx +2 -2
- package/src/components/Table/Table.tsx +12 -7
- package/src/components/Table/TableBody.tsx +2 -1
- package/src/components/Table/TableContext.tsx +1 -1
- package/src/components/Table/TableHead.tsx +3 -4
- package/src/components/Table/props.ts +0 -1
- package/src/helpers.tsx +2 -0
- package/src/hooks/usePinLastRow.ts +1 -18
- package/src/theme.ts +28 -55
- package/dist/types/src/components/Table/TableFooter.d.ts +0 -9
- package/dist/types/src/components/Table/TableFooter.d.ts.map +0 -1
- package/src/components/Table/TableFooter.tsx +0 -45
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import '@dxosTheme';
|
|
2
|
+
import React from 'react';
|
|
2
3
|
declare const _default: {
|
|
3
4
|
title: string;
|
|
4
5
|
args: {};
|
|
@@ -6,6 +7,6 @@ declare const _default: {
|
|
|
6
7
|
};
|
|
7
8
|
export default _default;
|
|
8
9
|
export declare const SchemaTable: {
|
|
9
|
-
render: () => JSX.Element;
|
|
10
|
+
render: () => React.JSX.Element;
|
|
10
11
|
};
|
|
11
12
|
//# sourceMappingURL=SchemaToTable.stories.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SchemaToTable.stories.d.ts","sourceRoot":"","sources":["../../../../src/schema/SchemaToTable.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,YAAY,CAAC;;;;;;
|
|
1
|
+
{"version":3,"file":"SchemaToTable.stories.d.ts","sourceRoot":"","sources":["../../../../src/schema/SchemaToTable.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,YAAY,CAAC;AAIpB,OAAO,KAAK,MAAM,OAAO,CAAC;;;;;;AAS1B,wBAWE;AAuBF,eAAO,MAAM,WAAW;;CAmBvB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../../src/schema/schema.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,CAAC,MAAM,uBAAuB,CAAC;AAEhD,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,SAAS,CAAC;AAG1C,MAAM,MAAM,oBAAoB,GAAG,UAAU,GAAG,SAAS,CAAC;AAG1D,eAAO,MAAM,wBAAwB,WAAY,
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../../src/schema/schema.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,CAAC,MAAM,uBAAuB,CAAC;AAEhD,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,SAAS,CAAC;AAG1C,MAAM,MAAM,oBAAoB,GAAG,UAAU,GAAG,SAAS,CAAC;AAG1D,eAAO,MAAM,wBAAwB,WAAY,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,KAAG,CAAC,MAAM,EAAE,oBAAoB,CAAC,EAwBnG,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schemaToColumns.d.ts","sourceRoot":"","sources":["../../../../src/schema/schemaToColumns.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAEvD,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,mBAAmB,CAAC;AAK3C,eAAO,MAAM,kBAAkB,
|
|
1
|
+
{"version":3,"file":"schemaToColumns.d.ts","sourceRoot":"","sources":["../../../../src/schema/schemaToColumns.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAEvD,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,mBAAmB,CAAC;AAK3C,eAAO,MAAM,kBAAkB,GAAI,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,KAAG,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,EAoCjF,CAAC"}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import { type CellContext } from '@tanstack/react-table';
|
|
2
1
|
import { type ComponentFunction } from '@dxos/react-ui-types';
|
|
3
2
|
import { type TableContextValue, type TableFlags } from './components';
|
|
4
3
|
export declare const currentRow = "!bg-neutral-75 !dark:bg-neutral-850";
|
|
5
4
|
export declare const selectedRow = "!bg-primary-100 dark:!bg-primary-700";
|
|
6
5
|
export declare const flushPadding = "pli-0 plb-0";
|
|
7
|
-
export declare const textPadding = "pli-2 plb-0
|
|
8
|
-
export declare const headPadding = "pli-2 plb-
|
|
9
|
-
export declare const gridCellFocusRing = "focus-within:outline outline-
|
|
6
|
+
export declare const textPadding = "pli-2 plb-0";
|
|
7
|
+
export declare const headPadding = "pli-2 plb-0";
|
|
8
|
+
export declare const gridCellFocusRing = "relative focus-within:outline focus-within:outline-1 outline-primary-500 outline-offset-[-1px]";
|
|
10
9
|
export type TableStyleProps = Partial<TableContextValue<any>>;
|
|
11
10
|
export declare const tableRoot: ComponentFunction<TableStyleProps>;
|
|
12
11
|
export declare const groupTh: ComponentFunction<TableStyleProps>;
|
|
@@ -24,10 +23,7 @@ export type TbodyTrStyleProps = Partial<{
|
|
|
24
23
|
isPinned?: boolean;
|
|
25
24
|
}>;
|
|
26
25
|
export declare const tbodyTr: ComponentFunction<TbodyTrStyleProps>;
|
|
27
|
-
export declare const tdRoot: ComponentFunction<TbodyStyleProps
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
export declare const tfootRoot: ComponentFunction<TfootStyleProps>;
|
|
31
|
-
export declare const tfootTr: ComponentFunction<TfootStyleProps>;
|
|
32
|
-
export declare const tfootTh: ComponentFunction<TfootStyleProps>;
|
|
26
|
+
export declare const tdRoot: ComponentFunction<TbodyStyleProps & {
|
|
27
|
+
pinned?: boolean;
|
|
28
|
+
}>;
|
|
33
29
|
//# sourceMappingURL=theme.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../../src/theme.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../../src/theme.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAE9D,OAAO,EAAE,KAAK,iBAAiB,EAAE,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAEvE,eAAO,MAAM,UAAU,wCAAwC,CAAC;AAChE,eAAO,MAAM,WAAW,yCAAyC,CAAC;AAClE,eAAO,MAAM,YAAY,gBAAgB,CAAC;AAC1C,eAAO,MAAM,WAAW,gBAAgB,CAAC;AACzC,eAAO,MAAM,WAAW,gBAAgB,CAAC;AAEzC,eAAO,MAAM,iBAAiB,mGACoE,CAAC;AAInG,MAAM,MAAM,eAAe,GAAG,OAAO,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC;AAE9D,eAAO,MAAM,SAAS,EAAE,iBAAiB,CAAC,eAAe,CACoC,CAAC;AAE9F,eAAO,MAAM,OAAO,EAAE,iBAAiB,CAAC,eAAe,CACH,CAAC;AAErD,MAAM,MAAM,eAAe,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAElD,eAAO,MAAM,SAAS,EAAE,iBAAiB,CAAC,eAAe,CACqD,CAAC;AAE/G,eAAO,MAAM,OAAO,EAAE,iBAAiB,CAAC,eAAe,CAA2C,CAAC;AAEnG,eAAO,MAAM,OAAO,EAAE,iBAAiB,CAAC,eAAe,CAQpD,CAAC;AAEJ,eAAO,MAAM,eAAe,EAAE,iBAAiB,CAAC;IAAE,UAAU,EAAE,OAAO,CAAA;CAAE,CAUtE,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,OAAO,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC;AAC9D,eAAO,MAAM,SAAS,EAAE,iBAAiB,CAAC,eAAe,CAAkC,CAAC;AAE5F,MAAM,MAAM,iBAAiB,GAAG,OAAO,CAAC;IAAE,YAAY,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AACxF,eAAO,MAAM,OAAO,EAAE,iBAAiB,CAAC,iBAAiB,CAStD,CAAC;AAEJ,eAAO,MAAM,MAAM,EAAE,iBAAiB,CAAC,eAAe,GAAG;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,CAS1E,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/react-ui-table",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.8-main.046e6cf",
|
|
4
4
|
"description": "A table component.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -31,29 +31,29 @@
|
|
|
31
31
|
"@tanstack/react-virtual": "^3.9.0",
|
|
32
32
|
"date-fns": "^3.3.1",
|
|
33
33
|
"effect": "^3.2.7",
|
|
34
|
-
"@dxos/
|
|
35
|
-
"@dxos/
|
|
36
|
-
"@dxos/keys": "0.6.
|
|
37
|
-
"@dxos/
|
|
38
|
-
"@dxos/
|
|
39
|
-
"@dxos/react-ui-searchlist": "0.6.
|
|
40
|
-
"@dxos/react-ui-theme": "0.6.
|
|
41
|
-
"@dxos/react-ui-types": "0.6.
|
|
42
|
-
"@dxos/util": "0.6.
|
|
34
|
+
"@dxos/async": "0.6.8-main.046e6cf",
|
|
35
|
+
"@dxos/invariant": "0.6.8-main.046e6cf",
|
|
36
|
+
"@dxos/keys": "0.6.8-main.046e6cf",
|
|
37
|
+
"@dxos/react-ui": "0.6.8-main.046e6cf",
|
|
38
|
+
"@dxos/log": "0.6.8-main.046e6cf",
|
|
39
|
+
"@dxos/react-ui-searchlist": "0.6.8-main.046e6cf",
|
|
40
|
+
"@dxos/react-ui-theme": "0.6.8-main.046e6cf",
|
|
41
|
+
"@dxos/react-ui-types": "0.6.8-main.046e6cf",
|
|
42
|
+
"@dxos/util": "0.6.8-main.046e6cf"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@phosphor-icons/react": "^2.1.5",
|
|
46
|
-
"@types/react": "
|
|
47
|
-
"@types/react-dom": "
|
|
46
|
+
"@types/react": "~18.2.0",
|
|
47
|
+
"@types/react-dom": "~18.2.0",
|
|
48
48
|
"fast-check": "^3.19.0",
|
|
49
49
|
"react": "~18.2.0",
|
|
50
50
|
"react-dom": "~18.2.0",
|
|
51
51
|
"vite": "^5.3.4",
|
|
52
|
-
"@dxos/echo-
|
|
53
|
-
"@dxos/
|
|
54
|
-
"@dxos/react-ui-theme": "0.6.
|
|
55
|
-
"@dxos/
|
|
56
|
-
"@dxos/storybook-utils": "0.6.
|
|
52
|
+
"@dxos/echo-signals": "0.6.8-main.046e6cf",
|
|
53
|
+
"@dxos/echo-schema": "0.6.8-main.046e6cf",
|
|
54
|
+
"@dxos/react-ui-theme": "0.6.8-main.046e6cf",
|
|
55
|
+
"@dxos/random": "0.6.8-main.046e6cf",
|
|
56
|
+
"@dxos/storybook-utils": "0.6.8-main.046e6cf"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
59
|
"@phosphor-icons/react": "^2.1.5",
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { useFocusableGroup } from '@fluentui/react-tabster';
|
|
6
6
|
import { type Cell as CellType, type RowData } from '@tanstack/react-table';
|
|
7
|
-
import React, { type PropsWithChildren } from 'react';
|
|
7
|
+
import React, { useCallback, type PropsWithChildren, type KeyboardEvent } from 'react';
|
|
8
8
|
|
|
9
9
|
import { tdRoot } from '../../theme';
|
|
10
10
|
import { useTableContext } from '../Table/TableContext';
|
|
@@ -19,10 +19,48 @@ const FocusableCell = <TData extends RowData, TValue>({ cell, children }: CellPr
|
|
|
19
19
|
const tableContext = useTableContext();
|
|
20
20
|
const domAttributes = useFocusableGroup({ tabBehavior: 'limited' });
|
|
21
21
|
|
|
22
|
-
const
|
|
22
|
+
const pinned = tableContext.table.getState().rowPinning?.bottom?.includes(cell.row.id);
|
|
23
|
+
const className = tdRoot({ ...tableContext, pinned }, cell.column.columnDef.meta?.cell?.classNames);
|
|
24
|
+
|
|
25
|
+
const handleKeyDown = useCallback(({ key, currentTarget }: KeyboardEvent<HTMLTableCellElement>) => {
|
|
26
|
+
if (key !== 'Enter') {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const currentRow = currentTarget.closest('tr');
|
|
31
|
+
if (!currentRow) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const cellIndex = Array.from(currentRow.cells || []).indexOf(currentTarget);
|
|
36
|
+
|
|
37
|
+
const nextSibling = currentRow.nextElementSibling;
|
|
38
|
+
if (!(nextSibling instanceof HTMLTableRowElement)) {
|
|
39
|
+
let depth = 0;
|
|
40
|
+
// Poll for the new 'add row' row to be added to the DOM.
|
|
41
|
+
const pollForNewRow = () => {
|
|
42
|
+
const newNextSibling = currentRow.nextElementSibling;
|
|
43
|
+
if (newNextSibling instanceof HTMLTableRowElement) {
|
|
44
|
+
const nextCell = newNextSibling.cells[cellIndex];
|
|
45
|
+
// Find the input within next cell and focus it.
|
|
46
|
+
const input = nextCell.querySelector('input');
|
|
47
|
+
if (input) {
|
|
48
|
+
input.focus();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// TODO(Zan): Use the same utility that sheets uses.
|
|
52
|
+
// Scroll current row into view after it's been hidden behind the sticky add-row row.
|
|
53
|
+
currentRow.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
54
|
+
} else if (depth++ < 100) {
|
|
55
|
+
requestAnimationFrame(pollForNewRow);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
requestAnimationFrame(pollForNewRow);
|
|
59
|
+
}
|
|
60
|
+
}, []);
|
|
23
61
|
|
|
24
62
|
return (
|
|
25
|
-
<td tabIndex={0} {...domAttributes} className={className}>
|
|
63
|
+
<td data-testid='table.cell' tabIndex={0} {...domAttributes} className={className} onKeyDown={handleKeyDown}>
|
|
26
64
|
{children}
|
|
27
65
|
</td>
|
|
28
66
|
);
|
|
@@ -30,7 +68,11 @@ const FocusableCell = <TData extends RowData, TValue>({ cell, children }: CellPr
|
|
|
30
68
|
|
|
31
69
|
const StaticCell = <TData extends RowData, TValue>({ cell, children }: CellProps<TData, TValue>) => {
|
|
32
70
|
const tableContext = useTableContext();
|
|
33
|
-
return
|
|
71
|
+
return (
|
|
72
|
+
<td data-testid='table.cell' className={tdRoot(tableContext, cell.column.columnDef.meta?.cell?.classNames)}>
|
|
73
|
+
{children}
|
|
74
|
+
</td>
|
|
75
|
+
);
|
|
34
76
|
};
|
|
35
77
|
|
|
36
78
|
const Cell = <TData extends RowData, TValue>({ cell, children }: CellProps<TData, TValue>) => {
|
|
@@ -6,7 +6,7 @@ import { X, GearSix, CaretDown, ArrowDown, ArrowUp, ArrowRight, ArrowLeft } from
|
|
|
6
6
|
import { type SortDirection, type HeaderContext, type RowData } from '@tanstack/react-table';
|
|
7
7
|
import React, { useRef, useState, useCallback } from 'react';
|
|
8
8
|
|
|
9
|
-
import { Button,
|
|
9
|
+
import { Button, Popover, DropdownMenu } from '@dxos/react-ui';
|
|
10
10
|
import { getSize, mx } from '@dxos/react-ui-theme';
|
|
11
11
|
|
|
12
12
|
import { ColumnSettingsForm } from './ColumnSettingsForm';
|
|
@@ -59,7 +59,7 @@ export const ColumnMenu = <TData extends RowData, TValue>({
|
|
|
59
59
|
);
|
|
60
60
|
|
|
61
61
|
return (
|
|
62
|
-
<div className='flex items-center justify-
|
|
62
|
+
<div className='flex items-center justify-between'>
|
|
63
63
|
<div className='flex items-center gap-1 truncate' title={title}>
|
|
64
64
|
<SortIndicator direction={sortDirection} onClick={onToggleSort} />
|
|
65
65
|
<div className='truncate'>{title}</div>
|
|
@@ -69,7 +69,7 @@ export const ColumnMenu = <TData extends RowData, TValue>({
|
|
|
69
69
|
<Popover.Root open={isColumnSettingsOpen} onOpenChange={setIsColumnSettingsOpen} modal={false}>
|
|
70
70
|
<DropdownMenu.Trigger ref={columnSettingsAnchorRef} asChild>
|
|
71
71
|
<Popover.Anchor asChild>
|
|
72
|
-
<Button variant='ghost'>
|
|
72
|
+
<Button variant='ghost' data-testid='table.column-menu'>
|
|
73
73
|
<CaretDown className={getSize(4)} />
|
|
74
74
|
</Button>
|
|
75
75
|
</Popover.Anchor>
|
|
@@ -124,7 +124,7 @@ export const ColumnMenu = <TData extends RowData, TValue>({
|
|
|
124
124
|
</>
|
|
125
125
|
)}
|
|
126
126
|
|
|
127
|
-
<DropdownMenu.Item onClick={onOpenColumnSettings}>
|
|
127
|
+
<DropdownMenu.Item onClick={onOpenColumnSettings} data-testid='table.open-column-settings'>
|
|
128
128
|
<span className='grow'>Column settings</span>
|
|
129
129
|
<span className='opacity-50'>
|
|
130
130
|
<GearSix className={mx(getSize(4), 'rotate-90')} />
|
|
@@ -137,10 +137,8 @@ export const ColumnMenu = <TData extends RowData, TValue>({
|
|
|
137
137
|
|
|
138
138
|
<Popover.Portal>
|
|
139
139
|
<Popover.Content>
|
|
140
|
-
<Popover.Viewport
|
|
141
|
-
<
|
|
142
|
-
<ColumnSettingsForm {...props} column={column} onClose={() => setIsColumnSettingsOpen(false)} />
|
|
143
|
-
</DensityProvider>
|
|
140
|
+
<Popover.Viewport>
|
|
141
|
+
<ColumnSettingsForm {...props} column={column} onClose={() => setIsColumnSettingsOpen(false)} />
|
|
144
142
|
</Popover.Viewport>
|
|
145
143
|
<Popover.Arrow />
|
|
146
144
|
</Popover.Content>
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import '@dxosTheme';
|
|
6
|
+
import React from 'react';
|
|
7
|
+
|
|
8
|
+
import { withTheme } from '@dxos/storybook-utils';
|
|
9
|
+
|
|
10
|
+
import { ColumnSettingsForm, type ColumnSettingsFormProps } from './ColumnSettingsForm';
|
|
11
|
+
import { type TableDef } from '../../schema';
|
|
12
|
+
|
|
13
|
+
export default {
|
|
14
|
+
title: 'react-ui-table/ColumnSettingsForm',
|
|
15
|
+
component: ColumnSettingsForm,
|
|
16
|
+
decorators: [withTheme],
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const sampleTableDef: TableDef = {
|
|
20
|
+
id: '1',
|
|
21
|
+
name: 'Sample Table',
|
|
22
|
+
columns: [
|
|
23
|
+
{ id: 'col-1', prop: 'name', type: 'string', label: 'Name' },
|
|
24
|
+
{ id: 'col-2', prop: 'age', type: 'number', label: 'Age', digits: 0 },
|
|
25
|
+
],
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const sampleTablesToReference: TableDef[] = [
|
|
29
|
+
sampleTableDef,
|
|
30
|
+
{
|
|
31
|
+
id: '2',
|
|
32
|
+
name: 'Reference Table',
|
|
33
|
+
columns: [
|
|
34
|
+
{ id: 'ref-col-1', prop: 'id', type: 'string', label: 'ID' },
|
|
35
|
+
{ id: 'ref-col-2', prop: 'description', type: 'string', label: 'Description' },
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
const defaultArgs: ColumnSettingsFormProps = {
|
|
41
|
+
column: {
|
|
42
|
+
id: 'col-1',
|
|
43
|
+
prop: 'name',
|
|
44
|
+
type: 'string',
|
|
45
|
+
label: 'Name',
|
|
46
|
+
},
|
|
47
|
+
tableDef: sampleTableDef,
|
|
48
|
+
tablesToReference: sampleTablesToReference,
|
|
49
|
+
onUpdate: (id, column) => console.log('onUpdate', { id, column }),
|
|
50
|
+
onDelete: (id) => console.log('onDelete', id),
|
|
51
|
+
onClose: () => console.log('onClose'),
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const Default = {
|
|
55
|
+
args: defaultArgs,
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export const NumberColumn = {
|
|
59
|
+
args: {
|
|
60
|
+
...defaultArgs,
|
|
61
|
+
column: {
|
|
62
|
+
id: 'col-2',
|
|
63
|
+
prop: 'age',
|
|
64
|
+
type: 'number',
|
|
65
|
+
label: 'Age',
|
|
66
|
+
digits: 0,
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export const ReferenceColumn = {
|
|
72
|
+
args: {
|
|
73
|
+
...defaultArgs,
|
|
74
|
+
column: {
|
|
75
|
+
id: 'col-3',
|
|
76
|
+
prop: 'reference',
|
|
77
|
+
type: 'ref',
|
|
78
|
+
label: 'Reference',
|
|
79
|
+
refTable: '2',
|
|
80
|
+
refProp: 'ref-col-1',
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export const NewColumn = {
|
|
86
|
+
args: {
|
|
87
|
+
...defaultArgs,
|
|
88
|
+
column: {
|
|
89
|
+
id: 'new-col',
|
|
90
|
+
prop: '',
|
|
91
|
+
type: 'string',
|
|
92
|
+
label: '',
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
};
|
|
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,22 +1,14 @@
|
|
|
1
1
|
//
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
|
-
import {
|
|
5
|
-
import React, { type FC, type PropsWithChildren, useRef, useState } from 'react';
|
|
4
|
+
import React, { useRef, useState } from 'react';
|
|
6
5
|
|
|
7
|
-
import { Button, Input, Select,
|
|
8
|
-
import { getSize, mx } from '@dxos/react-ui-theme';
|
|
6
|
+
import { Button, Input, Select, useTranslation } from '@dxos/react-ui';
|
|
9
7
|
import { safeParseInt } from '@dxos/util';
|
|
10
8
|
|
|
11
9
|
import { type TableDef, type ColumnProps, type ColumnType } from '../../schema';
|
|
12
10
|
import { translationKey } from '../../translations';
|
|
13
11
|
|
|
14
|
-
const Section: FC<PropsWithChildren & { className?: string }> = ({ children, className }) => (
|
|
15
|
-
<div role='none' className={mx('p-2', className)}>
|
|
16
|
-
{children}
|
|
17
|
-
</div>
|
|
18
|
-
);
|
|
19
|
-
|
|
20
12
|
export type ColumnSettingsFormProps = {
|
|
21
13
|
column: ColumnProps;
|
|
22
14
|
tableDef: TableDef;
|
|
@@ -46,10 +38,6 @@ export const ColumnSettingsForm = ({
|
|
|
46
38
|
const propRef = useRef<HTMLInputElement>(null);
|
|
47
39
|
const { t } = useTranslation(translationKey);
|
|
48
40
|
|
|
49
|
-
const handleCancel = () => {
|
|
50
|
-
onClose?.();
|
|
51
|
-
};
|
|
52
|
-
|
|
53
41
|
const handleSave = () => {
|
|
54
42
|
const { prop, refTable, refProp, type, label, digits } = formState;
|
|
55
43
|
|
|
@@ -88,19 +76,22 @@ export const ColumnSettingsForm = ({
|
|
|
88
76
|
};
|
|
89
77
|
|
|
90
78
|
return (
|
|
91
|
-
<div className='
|
|
92
|
-
<
|
|
79
|
+
<div className='p-1 space-y-2'>
|
|
80
|
+
<div className='space-y-1'>
|
|
93
81
|
<Input.Root>
|
|
94
|
-
<Input.Label
|
|
82
|
+
<Input.Label>{t('column label label')}</Input.Label>
|
|
95
83
|
<Input.TextInput
|
|
96
84
|
placeholder='Column label'
|
|
97
85
|
value={formState.label ?? ''}
|
|
98
86
|
onChange={(event) => setFormState((prevState) => ({ ...prevState, label: event.target.value }))}
|
|
99
87
|
autoFocus
|
|
88
|
+
data-testid='table.column-settings.label'
|
|
100
89
|
/>
|
|
101
90
|
</Input.Root>
|
|
91
|
+
</div>
|
|
92
|
+
<div className='space-y-1'>
|
|
102
93
|
<Input.Root>
|
|
103
|
-
<Input.Label
|
|
94
|
+
<Input.Label>{t('property key label')}</Input.Label>
|
|
104
95
|
<Input.TextInput
|
|
105
96
|
ref={propRef}
|
|
106
97
|
placeholder='Property key'
|
|
@@ -110,13 +101,15 @@ export const ColumnSettingsForm = ({
|
|
|
110
101
|
}
|
|
111
102
|
/>
|
|
112
103
|
</Input.Root>
|
|
104
|
+
</div>
|
|
105
|
+
<div className='space-y-1'>
|
|
113
106
|
<Input.Root>
|
|
114
|
-
<Input.Label
|
|
107
|
+
<Input.Label>{t('column type label')}</Input.Label>
|
|
115
108
|
<Select.Root
|
|
116
109
|
value={formState.type}
|
|
117
110
|
onValueChange={(value) => setFormState((prevState) => ({ ...prevState, type: value }))}
|
|
118
111
|
>
|
|
119
|
-
<Select.TriggerButton
|
|
112
|
+
<Select.TriggerButton classNames='is-full' placeholder='Type' />
|
|
120
113
|
<Select.Portal>
|
|
121
114
|
<Select.Content>
|
|
122
115
|
<Select.Viewport>
|
|
@@ -130,60 +123,37 @@ export const ColumnSettingsForm = ({
|
|
|
130
123
|
</Select.Portal>
|
|
131
124
|
</Select.Root>
|
|
132
125
|
</Input.Root>
|
|
133
|
-
</
|
|
126
|
+
</div>
|
|
134
127
|
{formState.type === 'number' && (
|
|
135
|
-
<
|
|
128
|
+
<div className='space-y-1'>
|
|
136
129
|
<Input.Root>
|
|
137
|
-
<Input.Label
|
|
130
|
+
<Input.Label>{t('digits label')}</Input.Label>
|
|
138
131
|
<Input.TextInput
|
|
139
132
|
value={formState.digits ?? ''}
|
|
140
133
|
onChange={(event) => setFormState((prevState) => ({ ...prevState, digits: event.target.value }))}
|
|
141
134
|
/>
|
|
142
135
|
</Input.Root>
|
|
143
|
-
</
|
|
136
|
+
</div>
|
|
144
137
|
)}
|
|
145
138
|
|
|
146
139
|
{formState.type === 'ref' && (
|
|
147
|
-
|
|
148
|
-
<
|
|
149
|
-
<Input.Label classNames='mbe-1 mbs-3'>Table</Input.Label>
|
|
150
|
-
<Select.Root
|
|
151
|
-
value={formState.refTable}
|
|
152
|
-
onValueChange={(value) => setFormState((prevState) => ({ ...prevState, refTable: value }))}
|
|
153
|
-
>
|
|
154
|
-
<Select.TriggerButton placeholder='Table' classNames='is-full' />
|
|
155
|
-
<Select.Portal>
|
|
156
|
-
<Select.Content>
|
|
157
|
-
<Select.Viewport>
|
|
158
|
-
{tablesToReference
|
|
159
|
-
.filter((t) => t.id !== tableDef.id)
|
|
160
|
-
.map(({ id, name }) => (
|
|
161
|
-
<Select.Option key={id} value={id}>
|
|
162
|
-
{name ?? id}
|
|
163
|
-
</Select.Option>
|
|
164
|
-
))}
|
|
165
|
-
</Select.Viewport>
|
|
166
|
-
</Select.Content>
|
|
167
|
-
</Select.Portal>
|
|
168
|
-
</Select.Root>
|
|
169
|
-
</Input.Root>
|
|
170
|
-
|
|
171
|
-
{formState.refTable && (
|
|
140
|
+
<>
|
|
141
|
+
<div className='space-y-1'>
|
|
172
142
|
<Input.Root>
|
|
173
|
-
<Input.Label
|
|
143
|
+
<Input.Label>Table</Input.Label>
|
|
174
144
|
<Select.Root
|
|
175
|
-
value={formState.
|
|
176
|
-
onValueChange={(value) => setFormState((prevState) => ({ ...prevState,
|
|
145
|
+
value={formState.refTable}
|
|
146
|
+
onValueChange={(value) => setFormState((prevState) => ({ ...prevState, refTable: value }))}
|
|
177
147
|
>
|
|
178
|
-
<Select.TriggerButton placeholder='
|
|
148
|
+
<Select.TriggerButton placeholder='Table' classNames='is-full' />
|
|
179
149
|
<Select.Portal>
|
|
180
150
|
<Select.Content>
|
|
181
151
|
<Select.Viewport>
|
|
182
152
|
{tablesToReference
|
|
183
|
-
.
|
|
184
|
-
|
|
153
|
+
.filter((t) => t.id !== tableDef.id)
|
|
154
|
+
.map(({ id, name }) => (
|
|
185
155
|
<Select.Option key={id} value={id}>
|
|
186
|
-
{
|
|
156
|
+
{name ?? id}
|
|
187
157
|
</Select.Option>
|
|
188
158
|
))}
|
|
189
159
|
</Select.Viewport>
|
|
@@ -191,29 +161,46 @@ export const ColumnSettingsForm = ({
|
|
|
191
161
|
</Select.Portal>
|
|
192
162
|
</Select.Root>
|
|
193
163
|
</Input.Root>
|
|
164
|
+
</div>
|
|
165
|
+
{formState.refTable && (
|
|
166
|
+
<div className='space-y-1'>
|
|
167
|
+
<Input.Root>
|
|
168
|
+
<Input.Label>Table property</Input.Label>
|
|
169
|
+
<Select.Root
|
|
170
|
+
value={formState.refProp}
|
|
171
|
+
onValueChange={(value) => setFormState((prevState) => ({ ...prevState, refProp: value }))}
|
|
172
|
+
>
|
|
173
|
+
<Select.TriggerButton placeholder='Property' />
|
|
174
|
+
<Select.Portal>
|
|
175
|
+
<Select.Content>
|
|
176
|
+
<Select.Viewport>
|
|
177
|
+
{tablesToReference
|
|
178
|
+
.find((tableDef) => tableDef.id === formState.refTable)
|
|
179
|
+
?.columns.map(({ id, label }) => (
|
|
180
|
+
<Select.Option key={id} value={id}>
|
|
181
|
+
{label ?? id}
|
|
182
|
+
</Select.Option>
|
|
183
|
+
))}
|
|
184
|
+
</Select.Viewport>
|
|
185
|
+
</Select.Content>
|
|
186
|
+
</Select.Portal>
|
|
187
|
+
</Select.Root>
|
|
188
|
+
</Input.Root>
|
|
189
|
+
</div>
|
|
194
190
|
)}
|
|
195
|
-
|
|
191
|
+
</>
|
|
196
192
|
)}
|
|
197
193
|
|
|
198
|
-
<
|
|
194
|
+
<div role='none' className='h-1' />
|
|
199
195
|
|
|
200
|
-
<
|
|
201
|
-
<Button
|
|
202
|
-
|
|
203
|
-
<div className='grow' />
|
|
204
|
-
<Check className={getSize(5)} />
|
|
205
|
-
</Button>
|
|
206
|
-
<Button classNames='is-full flex gap-2' onClick={handleCancel}>
|
|
207
|
-
<span>{t('cancel label', { ns: 'os' })}</span>
|
|
208
|
-
<div className='grow' />
|
|
209
|
-
<X className={getSize(5)} />
|
|
196
|
+
<div className='flex flex-row justify-end gap-1'>
|
|
197
|
+
<Button onClick={handleDelete} data-testid='table.column-settings.delete'>
|
|
198
|
+
{t('delete label')}
|
|
210
199
|
</Button>
|
|
211
|
-
<Button
|
|
212
|
-
|
|
213
|
-
<div className='grow' />
|
|
214
|
-
<Trash className={getSize(5)} />
|
|
200
|
+
<Button variant='primary' onClick={handleSave} data-testid='table.column-settings.save'>
|
|
201
|
+
{t('save label')}
|
|
215
202
|
</Button>
|
|
216
|
-
</
|
|
203
|
+
</div>
|
|
217
204
|
</div>
|
|
218
205
|
);
|
|
219
206
|
};
|
|
@@ -323,7 +323,7 @@ export const InsertDelete = {
|
|
|
323
323
|
};
|
|
324
324
|
|
|
325
325
|
return (
|
|
326
|
-
<div>
|
|
326
|
+
<div className='space-y-4'>
|
|
327
327
|
<div className='flex flex-row gap-2'>
|
|
328
328
|
<Button onClick={onInsertFirst}>Insert first</Button>
|
|
329
329
|
<Button onClick={onInsertLast}>Insert last</Button>
|
|
@@ -331,7 +331,7 @@ export const InsertDelete = {
|
|
|
331
331
|
<Button onClick={onDeleteLast}>Delete last</Button>
|
|
332
332
|
</div>
|
|
333
333
|
<Table.Root>
|
|
334
|
-
<Table.Viewport
|
|
334
|
+
<Table.Viewport>
|
|
335
335
|
<Table.Main<Item>
|
|
336
336
|
role='grid'
|
|
337
337
|
rowsSelectable='multi'
|
|
@@ -25,12 +25,11 @@ import React, {
|
|
|
25
25
|
memo,
|
|
26
26
|
} from 'react';
|
|
27
27
|
|
|
28
|
-
import { type ThemedClassName, useDefaultValue } from '@dxos/react-ui';
|
|
28
|
+
import { DensityProvider, type ThemedClassName, useDefaultValue } from '@dxos/react-ui';
|
|
29
29
|
import { mx } from '@dxos/react-ui-theme';
|
|
30
30
|
|
|
31
31
|
import { TableBody } from './TableBody';
|
|
32
32
|
import { type TypedTableProvider, TableProvider as UntypedTableProvider, useTableContext } from './TableContext';
|
|
33
|
-
import { TableFooter } from './TableFooter';
|
|
34
33
|
import { TableHead } from './TableHead';
|
|
35
34
|
import { TableRootContext, useTableRootContext } from './TableRootContext';
|
|
36
35
|
import { type TableProps } from './props';
|
|
@@ -41,7 +40,11 @@ type TableRootProps = { children: ReactNode };
|
|
|
41
40
|
|
|
42
41
|
const TableRoot = ({ children }: TableRootProps) => {
|
|
43
42
|
const contextValue = useTableRootContext();
|
|
44
|
-
return
|
|
43
|
+
return (
|
|
44
|
+
<TableRootContext.Provider value={contextValue}>
|
|
45
|
+
<DensityProvider density='fine'>{children}</DensityProvider>
|
|
46
|
+
</TableRootContext.Provider>
|
|
47
|
+
);
|
|
45
48
|
};
|
|
46
49
|
|
|
47
50
|
type TableViewportProps = ThemedClassName<ComponentPropsWithoutRef<typeof Primitive.div>> & {
|
|
@@ -175,7 +178,7 @@ export const TablePrimitive = <TData extends RowData>(props: TableProps<TData>)
|
|
|
175
178
|
* Pure implementation of table outside of context set-up.
|
|
176
179
|
*/
|
|
177
180
|
const TableImpl = <TData extends RowData>(props: TableProps<TData>) => {
|
|
178
|
-
const { debug, classNames, role,
|
|
181
|
+
const { debug, classNames, role, grouping, fullWidth } = props;
|
|
179
182
|
const { table } = useTableContext<TData>();
|
|
180
183
|
|
|
181
184
|
if (debug) {
|
|
@@ -194,13 +197,15 @@ const TableImpl = <TData extends RowData>(props: TableProps<TData>) => {
|
|
|
194
197
|
<table
|
|
195
198
|
role={role}
|
|
196
199
|
className={tableRoot(props, classNames)}
|
|
197
|
-
{
|
|
200
|
+
style={{
|
|
201
|
+
// borderCollapse: 'separate',
|
|
202
|
+
borderSpacing: 0,
|
|
203
|
+
...(!fullWidth && { width: table.getTotalSize() }),
|
|
204
|
+
}}
|
|
198
205
|
>
|
|
199
206
|
<TableHead />
|
|
200
207
|
|
|
201
208
|
{grouping?.length !== 0 ? <TableComponent /> : <GroupedTableContent />}
|
|
202
|
-
|
|
203
|
-
{footer && <TableFooter />}
|
|
204
209
|
</table>
|
|
205
210
|
);
|
|
206
211
|
};
|