@dxos/react-ui-table 0.6.14-staging.e15392e → 0.7.1-staging.599df14

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.
Files changed (242) hide show
  1. package/dist/lib/browser/_deprecated/index.mjs +1483 -0
  2. package/dist/lib/browser/_deprecated/index.mjs.map +7 -0
  3. package/dist/lib/browser/chunk-A5W4XWPD.mjs +18 -0
  4. package/dist/lib/browser/chunk-A5W4XWPD.mjs.map +7 -0
  5. package/dist/lib/browser/index.mjs +1274 -1356
  6. package/dist/lib/browser/index.mjs.map +4 -4
  7. package/dist/lib/browser/meta.json +1 -1
  8. package/dist/lib/browser/types/index.mjs +7 -0
  9. package/dist/lib/browser/types/index.mjs.map +7 -0
  10. package/dist/lib/node/_deprecated/index.cjs +1511 -0
  11. package/dist/lib/node/_deprecated/index.cjs.map +7 -0
  12. package/dist/lib/node/chunk-32IGMRME.cjs +40 -0
  13. package/dist/lib/node/chunk-32IGMRME.cjs.map +7 -0
  14. package/dist/lib/node/index.cjs +1380 -0
  15. package/dist/lib/node/index.cjs.map +7 -0
  16. package/dist/lib/node/meta.json +1 -0
  17. package/dist/lib/node/types/index.cjs +29 -0
  18. package/dist/lib/node/types/index.cjs.map +7 -0
  19. package/dist/lib/node-esm/_deprecated/index.mjs +1485 -0
  20. package/dist/lib/node-esm/_deprecated/index.mjs.map +7 -0
  21. package/dist/lib/node-esm/chunk-DWQ4KGLD.mjs +20 -0
  22. package/dist/lib/node-esm/chunk-DWQ4KGLD.mjs.map +7 -0
  23. package/dist/lib/node-esm/index.mjs +1399 -0
  24. package/dist/lib/node-esm/index.mjs.map +7 -0
  25. package/dist/lib/node-esm/meta.json +1 -0
  26. package/dist/lib/node-esm/types/index.mjs +8 -0
  27. package/dist/lib/node-esm/types/index.mjs.map +7 -0
  28. package/dist/types/src/_deprecated/components/Cell/Cell.d.ts.map +1 -0
  29. package/dist/types/src/_deprecated/components/Cell/CellCombobox.d.ts.map +1 -0
  30. package/dist/types/src/_deprecated/components/Cell/index.d.ts.map +1 -0
  31. package/dist/types/src/_deprecated/components/ColumnMenu/ColumnMenu.d.ts.map +1 -0
  32. package/dist/types/src/_deprecated/components/ColumnMenu/ColumnMenu.stories.d.ts.map +1 -0
  33. package/dist/types/src/_deprecated/components/ColumnMenu/ColumnSettings.d.ts.map +1 -0
  34. package/dist/types/src/{components → _deprecated/components}/ColumnMenu/ColumnSettings.stories.d.ts +4 -4
  35. package/dist/types/src/_deprecated/components/ColumnMenu/ColumnSettings.stories.d.ts.map +1 -0
  36. package/dist/types/src/_deprecated/components/ColumnMenu/index.d.ts.map +1 -0
  37. package/dist/types/src/_deprecated/components/Table/Table.d.ts +20 -0
  38. package/dist/types/src/_deprecated/components/Table/Table.d.ts.map +1 -0
  39. package/dist/types/src/_deprecated/components/Table/Table.stories.d.ts +116 -0
  40. package/dist/types/src/_deprecated/components/Table/Table.stories.d.ts.map +1 -0
  41. package/dist/types/src/_deprecated/components/Table/TableBody.d.ts.map +1 -0
  42. package/dist/types/src/_deprecated/components/Table/TableContext.d.ts.map +1 -0
  43. package/dist/types/src/_deprecated/components/Table/TableHead.d.ts.map +1 -0
  44. package/dist/types/src/_deprecated/components/Table/TableRootContext.d.ts.map +1 -0
  45. package/dist/types/src/_deprecated/components/Table/index.d.ts +5 -0
  46. package/dist/types/src/_deprecated/components/Table/index.d.ts.map +1 -0
  47. package/dist/types/src/_deprecated/components/Table/props.d.ts.map +1 -0
  48. package/dist/types/src/_deprecated/components/index.d.ts +4 -0
  49. package/dist/types/src/_deprecated/components/index.d.ts.map +1 -0
  50. package/dist/types/src/_deprecated/helpers.d.ts.map +1 -0
  51. package/dist/types/src/_deprecated/hooks/index.d.ts +5 -0
  52. package/dist/types/src/_deprecated/hooks/index.d.ts.map +1 -0
  53. package/dist/types/src/_deprecated/hooks/useColumnSizing.d.ts.map +1 -0
  54. package/dist/types/src/{hooks → _deprecated/hooks}/useColumnSorting.d.ts +1 -1
  55. package/dist/types/src/_deprecated/hooks/useColumnSorting.d.ts.map +1 -0
  56. package/dist/types/src/_deprecated/hooks/usePinLastRow.d.ts.map +1 -0
  57. package/dist/types/src/_deprecated/hooks/useRowSelection.d.ts.map +1 -0
  58. package/dist/types/src/_deprecated/index.d.ts +8 -0
  59. package/dist/types/src/_deprecated/index.d.ts.map +1 -0
  60. package/dist/types/src/_deprecated/schema/Schema.stories.d.ts.map +1 -0
  61. package/dist/types/src/{schema → _deprecated/schema}/column-utils.d.ts +3 -0
  62. package/dist/types/src/_deprecated/schema/column-utils.d.ts.map +1 -0
  63. package/dist/types/src/_deprecated/schema/index.d.ts.map +1 -0
  64. package/dist/types/src/{schema → _deprecated/schema}/types.d.ts +3 -2
  65. package/dist/types/src/_deprecated/schema/types.d.ts.map +1 -0
  66. package/dist/types/src/_deprecated/theme.d.ts.map +1 -0
  67. package/dist/types/src/_deprecated/translations.d.ts +21 -0
  68. package/dist/types/src/_deprecated/translations.d.ts.map +1 -0
  69. package/dist/types/src/_deprecated/types.d.ts.map +1 -0
  70. package/dist/types/src/components/Table/ColumnActionsMenu.d.ts +8 -0
  71. package/dist/types/src/components/Table/ColumnActionsMenu.d.ts.map +1 -0
  72. package/dist/types/src/components/Table/ColumnSettings.d.ts +8 -0
  73. package/dist/types/src/components/Table/ColumnSettings.d.ts.map +1 -0
  74. package/dist/types/src/components/Table/RowActionsMenu.d.ts +8 -0
  75. package/dist/types/src/components/Table/RowActionsMenu.d.ts.map +1 -0
  76. package/dist/types/src/components/Table/Table.d.ts +13 -15
  77. package/dist/types/src/components/Table/Table.d.ts.map +1 -1
  78. package/dist/types/src/components/Table/Table.stories.d.ts +10 -113
  79. package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
  80. package/dist/types/src/components/Table/index.d.ts +0 -3
  81. package/dist/types/src/components/Table/index.d.ts.map +1 -1
  82. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +17 -0
  83. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -0
  84. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts +11 -0
  85. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -0
  86. package/dist/types/src/components/TableCellEditor/extension.d.ts +12 -0
  87. package/dist/types/src/components/TableCellEditor/extension.d.ts.map +1 -0
  88. package/dist/types/src/components/TableCellEditor/index.d.ts +2 -0
  89. package/dist/types/src/components/TableCellEditor/index.d.ts.map +1 -0
  90. package/dist/types/src/components/Toolbar/Toolbar.d.ts +21 -0
  91. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -0
  92. package/dist/types/src/components/Toolbar/common.d.ts +14 -0
  93. package/dist/types/src/components/Toolbar/common.d.ts.map +1 -0
  94. package/dist/types/src/components/Toolbar/index.d.ts +2 -0
  95. package/dist/types/src/components/Toolbar/index.d.ts.map +1 -0
  96. package/dist/types/src/components/index.d.ts +1 -2
  97. package/dist/types/src/components/index.d.ts.map +1 -1
  98. package/dist/types/src/components/testing.d.ts +97 -0
  99. package/dist/types/src/components/testing.d.ts.map +1 -0
  100. package/dist/types/src/hooks/index.d.ts +1 -4
  101. package/dist/types/src/hooks/index.d.ts.map +1 -1
  102. package/dist/types/src/hooks/useTableModel.d.ts +15 -0
  103. package/dist/types/src/hooks/useTableModel.d.ts.map +1 -0
  104. package/dist/types/src/index.d.ts +3 -4
  105. package/dist/types/src/index.d.ts.map +1 -1
  106. package/dist/types/src/model/index.d.ts +3 -0
  107. package/dist/types/src/model/index.d.ts.map +1 -0
  108. package/dist/types/src/model/modal-controller.d.ts +29 -0
  109. package/dist/types/src/model/modal-controller.d.ts.map +1 -0
  110. package/dist/types/src/model/selection-model.d.ts +22 -0
  111. package/dist/types/src/model/selection-model.d.ts.map +1 -0
  112. package/dist/types/src/model/table-model.d.ts +93 -0
  113. package/dist/types/src/model/table-model.d.ts.map +1 -0
  114. package/dist/types/src/model/table-model.test.d.ts +2 -0
  115. package/dist/types/src/model/table-model.test.d.ts.map +1 -0
  116. package/dist/types/src/translations.d.ts +23 -16
  117. package/dist/types/src/translations.d.ts.map +1 -1
  118. package/dist/types/src/types/index.d.ts +2 -0
  119. package/dist/types/src/types/index.d.ts.map +1 -0
  120. package/dist/types/src/types/table.d.ts +106 -0
  121. package/dist/types/src/types/table.d.ts.map +1 -0
  122. package/dist/types/src/util/grid.d.ts +14 -0
  123. package/dist/types/src/util/grid.d.ts.map +1 -0
  124. package/dist/types/src/util/index.d.ts +5 -0
  125. package/dist/types/src/util/index.d.ts.map +1 -0
  126. package/dist/types/src/util/signals.d.ts +6 -0
  127. package/dist/types/src/util/signals.d.ts.map +1 -0
  128. package/dist/types/src/util/table-buttons.d.ts +24 -0
  129. package/dist/types/src/util/table-buttons.d.ts.map +1 -0
  130. package/dist/types/src/util/table-controls.d.ts +21 -0
  131. package/dist/types/src/util/table-controls.d.ts.map +1 -0
  132. package/dist/types/src/util/table.d.ts +8 -0
  133. package/dist/types/src/util/table.d.ts.map +1 -0
  134. package/package.json +56 -22
  135. package/src/{components → _deprecated/components}/ColumnMenu/ColumnMenu.stories.tsx +4 -4
  136. package/src/{components → _deprecated/components}/ColumnMenu/ColumnSettings.stories.tsx +9 -9
  137. package/src/{components → _deprecated/components}/ColumnMenu/ColumnSettings.tsx +3 -3
  138. package/src/_deprecated/components/Table/Table.stories.tsx +508 -0
  139. package/src/_deprecated/components/Table/Table.tsx +301 -0
  140. package/src/{components → _deprecated/components}/Table/TableHead.tsx +3 -1
  141. package/src/_deprecated/components/Table/index.ts +8 -0
  142. package/src/_deprecated/components/index.ts +7 -0
  143. package/src/{helpers.tsx → _deprecated/helpers.tsx} +4 -3
  144. package/src/_deprecated/hooks/index.ts +8 -0
  145. package/src/_deprecated/index.ts +12 -0
  146. package/src/_deprecated/schema/column-utils.ts +54 -0
  147. package/src/{schema → _deprecated/schema}/types.ts +3 -2
  148. package/src/_deprecated/translations.ts +26 -0
  149. package/src/components/Table/ColumnActionsMenu.tsx +60 -0
  150. package/src/components/Table/ColumnSettings.tsx +76 -0
  151. package/src/components/Table/RowActionsMenu.tsx +36 -0
  152. package/src/components/Table/Table.stories.tsx +197 -467
  153. package/src/components/Table/Table.tsx +177 -256
  154. package/src/components/Table/index.ts +1 -4
  155. package/src/components/TableCellEditor/TableCellEditor.stories.tsx +114 -0
  156. package/src/components/TableCellEditor/TableCellEditor.tsx +155 -0
  157. package/src/components/TableCellEditor/extension.ts +62 -0
  158. package/src/components/TableCellEditor/index.ts +5 -0
  159. package/src/components/Toolbar/Toolbar.tsx +87 -0
  160. package/src/components/Toolbar/common.tsx +71 -0
  161. package/src/components/Toolbar/index.ts +5 -0
  162. package/src/components/index.ts +2 -3
  163. package/src/components/testing.ts +114 -0
  164. package/src/hooks/index.ts +1 -4
  165. package/src/hooks/useTableModel.ts +52 -0
  166. package/src/index.ts +5 -6
  167. package/src/model/index.ts +6 -0
  168. package/src/model/modal-controller.ts +83 -0
  169. package/src/model/selection-model.ts +99 -0
  170. package/src/model/table-model.test.ts +182 -0
  171. package/src/model/table-model.ts +565 -0
  172. package/src/translations.ts +20 -13
  173. package/src/types/index.ts +5 -0
  174. package/src/types/table.ts +13 -0
  175. package/src/util/grid.ts +23 -0
  176. package/src/util/index.ts +8 -0
  177. package/src/util/signals.ts +9 -0
  178. package/src/util/table-buttons.ts +48 -0
  179. package/src/util/table-controls.ts +27 -0
  180. package/src/util/table.ts +77 -0
  181. package/dist/types/src/components/Cell/Cell.d.ts.map +0 -1
  182. package/dist/types/src/components/Cell/CellCombobox.d.ts.map +0 -1
  183. package/dist/types/src/components/Cell/index.d.ts.map +0 -1
  184. package/dist/types/src/components/ColumnMenu/ColumnMenu.d.ts.map +0 -1
  185. package/dist/types/src/components/ColumnMenu/ColumnMenu.stories.d.ts.map +0 -1
  186. package/dist/types/src/components/ColumnMenu/ColumnSettings.d.ts.map +0 -1
  187. package/dist/types/src/components/ColumnMenu/ColumnSettings.stories.d.ts.map +0 -1
  188. package/dist/types/src/components/ColumnMenu/index.d.ts.map +0 -1
  189. package/dist/types/src/components/Table/TableBody.d.ts.map +0 -1
  190. package/dist/types/src/components/Table/TableContext.d.ts.map +0 -1
  191. package/dist/types/src/components/Table/TableHead.d.ts.map +0 -1
  192. package/dist/types/src/components/Table/TableRootContext.d.ts.map +0 -1
  193. package/dist/types/src/components/Table/props.d.ts.map +0 -1
  194. package/dist/types/src/helpers.d.ts.map +0 -1
  195. package/dist/types/src/hooks/useColumnSizing.d.ts.map +0 -1
  196. package/dist/types/src/hooks/useColumnSorting.d.ts.map +0 -1
  197. package/dist/types/src/hooks/usePinLastRow.d.ts.map +0 -1
  198. package/dist/types/src/hooks/useRowSelection.d.ts.map +0 -1
  199. package/dist/types/src/schema/Schema.stories.d.ts.map +0 -1
  200. package/dist/types/src/schema/column-utils.d.ts.map +0 -1
  201. package/dist/types/src/schema/index.d.ts.map +0 -1
  202. package/dist/types/src/schema/types.d.ts.map +0 -1
  203. package/dist/types/src/theme.d.ts.map +0 -1
  204. package/dist/types/src/types.d.ts.map +0 -1
  205. package/src/schema/column-utils.ts +0 -48
  206. /package/dist/types/src/{components → _deprecated/components}/Cell/Cell.d.ts +0 -0
  207. /package/dist/types/src/{components → _deprecated/components}/Cell/CellCombobox.d.ts +0 -0
  208. /package/dist/types/src/{components → _deprecated/components}/Cell/index.d.ts +0 -0
  209. /package/dist/types/src/{components → _deprecated/components}/ColumnMenu/ColumnMenu.d.ts +0 -0
  210. /package/dist/types/src/{components → _deprecated/components}/ColumnMenu/ColumnMenu.stories.d.ts +0 -0
  211. /package/dist/types/src/{components → _deprecated/components}/ColumnMenu/ColumnSettings.d.ts +0 -0
  212. /package/dist/types/src/{components → _deprecated/components}/ColumnMenu/index.d.ts +0 -0
  213. /package/dist/types/src/{components → _deprecated/components}/Table/TableBody.d.ts +0 -0
  214. /package/dist/types/src/{components → _deprecated/components}/Table/TableContext.d.ts +0 -0
  215. /package/dist/types/src/{components → _deprecated/components}/Table/TableHead.d.ts +0 -0
  216. /package/dist/types/src/{components → _deprecated/components}/Table/TableRootContext.d.ts +0 -0
  217. /package/dist/types/src/{components → _deprecated/components}/Table/props.d.ts +0 -0
  218. /package/dist/types/src/{helpers.d.ts → _deprecated/helpers.d.ts} +0 -0
  219. /package/dist/types/src/{hooks → _deprecated/hooks}/useColumnSizing.d.ts +0 -0
  220. /package/dist/types/src/{hooks → _deprecated/hooks}/usePinLastRow.d.ts +0 -0
  221. /package/dist/types/src/{hooks → _deprecated/hooks}/useRowSelection.d.ts +0 -0
  222. /package/dist/types/src/{schema → _deprecated/schema}/Schema.stories.d.ts +0 -0
  223. /package/dist/types/src/{schema → _deprecated/schema}/index.d.ts +0 -0
  224. /package/dist/types/src/{theme.d.ts → _deprecated/theme.d.ts} +0 -0
  225. /package/dist/types/src/{types.d.ts → _deprecated/types.d.ts} +0 -0
  226. /package/src/{components → _deprecated/components}/Cell/Cell.tsx +0 -0
  227. /package/src/{components → _deprecated/components}/Cell/CellCombobox.tsx +0 -0
  228. /package/src/{components → _deprecated/components}/Cell/index.ts +0 -0
  229. /package/src/{components → _deprecated/components}/ColumnMenu/ColumnMenu.tsx +0 -0
  230. /package/src/{components → _deprecated/components}/ColumnMenu/index.ts +0 -0
  231. /package/src/{components → _deprecated/components}/Table/TableBody.tsx +0 -0
  232. /package/src/{components → _deprecated/components}/Table/TableContext.tsx +0 -0
  233. /package/src/{components → _deprecated/components}/Table/TableRootContext.ts +0 -0
  234. /package/src/{components → _deprecated/components}/Table/props.ts +0 -0
  235. /package/src/{hooks → _deprecated/hooks}/useColumnSizing.ts +0 -0
  236. /package/src/{hooks → _deprecated/hooks}/useColumnSorting.ts +0 -0
  237. /package/src/{hooks → _deprecated/hooks}/usePinLastRow.ts +0 -0
  238. /package/src/{hooks → _deprecated/hooks}/useRowSelection.ts +0 -0
  239. /package/src/{schema → _deprecated/schema}/Schema.stories.tsx +0 -0
  240. /package/src/{schema → _deprecated/schema}/index.ts +0 -0
  241. /package/src/{theme.ts → _deprecated/theme.ts} +0 -0
  242. /package/src/{types.ts → _deprecated/types.ts} +0 -0
@@ -0,0 +1,301 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { type Primitive } from '@radix-ui/react-primitive';
6
+ import { Slot } from '@radix-ui/react-slot';
7
+ import {
8
+ type GroupingState,
9
+ type Row,
10
+ type RowData,
11
+ getCoreRowModel,
12
+ getExpandedRowModel,
13
+ getGroupedRowModel,
14
+ getSortedRowModel,
15
+ useReactTable,
16
+ } from '@tanstack/react-table';
17
+ import React, {
18
+ type ComponentPropsWithoutRef,
19
+ type ReactNode,
20
+ Fragment,
21
+ memo,
22
+ useCallback,
23
+ useEffect,
24
+ useState,
25
+ useContext,
26
+ } from 'react';
27
+
28
+ import { type ThemedClassName, useDefaultValue } from '@dxos/react-ui';
29
+ import { mx } from '@dxos/react-ui-theme';
30
+
31
+ import { TableBody } from './TableBody';
32
+ import { type TypedTableProvider, TableProvider as UntypedTableProvider, useTableContext } from './TableContext';
33
+ import { TableHead } from './TableHead';
34
+ import { TableRootContext, useTableRootContext } from './TableRootContext';
35
+ import { type TableProps } from './props';
36
+ import { useColumnResizing, useColumnSorting, usePinLastRow, useRowSelection } from '../../hooks';
37
+ import { groupTh, tableRoot } from '../../theme';
38
+
39
+ type TableRootProps = { children: ReactNode };
40
+
41
+ const TableRoot = ({ children }: TableRootProps) => {
42
+ const contextValue = useTableRootContext();
43
+ return <TableRootContext.Provider value={contextValue}>{children}</TableRootContext.Provider>;
44
+ };
45
+
46
+ type TableViewportProps = ThemedClassName<ComponentPropsWithoutRef<typeof Primitive.div>> & {
47
+ asChild?: boolean;
48
+ };
49
+
50
+ const TableViewport = ({ children, classNames, asChild, ...props }: TableViewportProps) => {
51
+ const { scrollContextRef } = useContext(TableRootContext);
52
+
53
+ const classes = mx(classNames, 'overflow-auto');
54
+ return asChild ? (
55
+ <Slot ref={scrollContextRef} className={classes} {...props}>
56
+ {children}
57
+ </Slot>
58
+ ) : (
59
+ <div role='none' className={classes} ref={scrollContextRef} {...props}>
60
+ {children}
61
+ </div>
62
+ );
63
+ };
64
+
65
+ export const TablePrimitive = <TData extends RowData>(props: TableProps<TData>) => {
66
+ const {
67
+ role,
68
+ header = true,
69
+ rowsSelectable,
70
+ debug,
71
+ pinLastRow,
72
+ columnVisibility,
73
+ onColumnResize,
74
+ onDataSelectionChange,
75
+ } = props;
76
+
77
+ const columns = useDefaultValue(props.columns, () => []);
78
+ const incomingData = useDefaultValue(props.data, () => []);
79
+
80
+ const [data, setData] = useState([...incomingData]);
81
+
82
+ // Reactivity workaround: https://github.com/dxos/dxos/issues/6376.
83
+ const forceUpdate = useCallback(() => setData([...incomingData]), [incomingData]);
84
+ useEffect(() => forceUpdate(), [JSON.stringify(incomingData), forceUpdate]);
85
+
86
+ const TableProvider = UntypedTableProvider as TypedTableProvider<TData>;
87
+
88
+ const { columnSizing, setColumnSizing, columnSizingInfo, setColumnSizingInfo } = useColumnResizing({
89
+ columns,
90
+ onColumnResize,
91
+ });
92
+
93
+ const { rowSelection, handleRowSelectionChange } = useRowSelection(props);
94
+
95
+ const [grouping, handleGroupingChange] = useState<GroupingState>(props.grouping ?? []);
96
+ useEffect(() => handleGroupingChange(props.grouping ?? []), [handleGroupingChange, props.grouping]);
97
+
98
+ const columnSorting = useColumnSorting();
99
+
100
+ const table = useReactTable({
101
+ // Data
102
+ meta: {},
103
+ data,
104
+
105
+ // Columns
106
+ columns,
107
+ defaultColumn: {
108
+ size: 400, // Required in order remove default width.
109
+ maxSize: 1024,
110
+ },
111
+
112
+ // State
113
+ state: {
114
+ columnVisibility,
115
+ columnSizing,
116
+ columnSizingInfo,
117
+ sorting: columnSorting.sorting,
118
+ rowSelection,
119
+ grouping,
120
+ },
121
+
122
+ // Resize columns
123
+ columnResizeMode: 'onChange',
124
+ enableColumnResizing: true,
125
+ onColumnSizingChange: setColumnSizing,
126
+ onColumnSizingInfoChange: setColumnSizingInfo,
127
+
128
+ // Rows
129
+ getCoreRowModel: getCoreRowModel(),
130
+ getSortedRowModel: getSortedRowModel(),
131
+ getExpandedRowModel: getExpandedRowModel(),
132
+
133
+ // Grouping
134
+ getGroupedRowModel: grouping.length > 1 ? getGroupedRowModel() : undefined,
135
+ onGroupingChange: handleGroupingChange,
136
+
137
+ enableMultiRowSelection: rowsSelectable === 'multi' ? true : undefined,
138
+ enableRowSelection: rowsSelectable === true ? true : undefined,
139
+
140
+ onRowSelectionChange: handleRowSelectionChange,
141
+
142
+ enableSorting: true,
143
+ enableColumnPinning: true,
144
+
145
+ // Debug
146
+ debugTable: debug,
147
+ });
148
+
149
+ useEffect(() => {
150
+ onDataSelectionChange?.(Object.keys(rowSelection).map((id) => table.getRowModel().rowsById[id].original));
151
+ }, [onDataSelectionChange, rowSelection, table]);
152
+
153
+ usePinLastRow(pinLastRow, table, data);
154
+
155
+ // Create additional expansion column if all columns have fixed width.
156
+ const expand = false; // columns.map((column) => column.size).filter(Boolean).length === columns?.length;
157
+
158
+ return (
159
+ <TableProvider
160
+ {...{ ...props, ...columnSorting }}
161
+ table={table}
162
+ header={header}
163
+ expand={expand}
164
+ isGrid={role === 'grid' || role === 'treegrid'}
165
+ >
166
+ <TableImpl<TData> debug={false} {...props} />
167
+ </TableProvider>
168
+ );
169
+ };
170
+
171
+ // TODO(zan): Smush this into the Table component.
172
+ /**
173
+ * Pure implementation of table outside of context set-up.
174
+ */
175
+ const TableImpl = <TData extends RowData>(props: TableProps<TData>) => {
176
+ const { debug, classNames, role, grouping, fullWidth } = props;
177
+ const { table } = useTableContext<TData>();
178
+
179
+ if (debug) {
180
+ return (
181
+ <pre className='font-mono text-xs text-neutral-500 m-1 p-2 ring'>
182
+ <code>{JSON.stringify(table.getState(), undefined, 2)}</code>
183
+ </pre>
184
+ );
185
+ }
186
+
187
+ const isResizingColumn = table.getState().columnSizingInfo.isResizingColumn;
188
+
189
+ const TableComponent = isResizingColumn ? MemoizedVirtualizedTableContent : VirtualizedTableContent;
190
+
191
+ return (
192
+ <table
193
+ role={role}
194
+ className={tableRoot(props, classNames)}
195
+ style={{
196
+ // borderCollapse: 'separate',
197
+ borderSpacing: 0,
198
+ ...(!fullWidth && { width: table.getTotalSize() }),
199
+ }}
200
+ >
201
+ <TableHead />
202
+
203
+ {grouping?.length !== 0 ? <TableComponent /> : <GroupedTableContent />}
204
+ </table>
205
+ );
206
+ };
207
+
208
+ const VirtualizedTableContent = () => {
209
+ const { table } = useTableContext();
210
+ const { virtualizer, dispatch } = useContext(TableRootContext);
211
+
212
+ const centerRows = table.getCenterRows();
213
+ let pinnedRows = [] as Row<unknown>[];
214
+
215
+ useEffect(() => {
216
+ dispatch({ type: 'updateTableCount', count: centerRows.length });
217
+ }, [centerRows.length]);
218
+
219
+ try {
220
+ // TODO(zan): Work out how to sync the row pinning with rendering
221
+ // This is a hack because the first call to this function after a row is deleted will throw an error
222
+ // because the row index is no longer in the table
223
+ // The pin last row hook updates the pinned row key after the row is deleted
224
+ pinnedRows = table.getBottomRows();
225
+ } catch (_) {} // Ignore error
226
+
227
+ const { getTotalSize, getVirtualItems } = virtualizer;
228
+
229
+ const virtualRows = getVirtualItems();
230
+ const totalSize = getTotalSize();
231
+
232
+ const paddingTop = virtualRows.length > 0 ? virtualRows?.[0]?.start || 0 : 0;
233
+ const paddingBottom = virtualRows.length > 0 ? totalSize - (virtualRows?.[virtualRows.length - 1]?.end || 0) : 0;
234
+
235
+ const rowsToRender = [...virtualRows.map((virtualRow) => centerRows[virtualRow.index]), ...pinnedRows].filter(
236
+ (r) => !!r,
237
+ );
238
+
239
+ return (
240
+ <Fragment>
241
+ {paddingTop > 0 && (
242
+ <tbody role='none'>
243
+ <tr role='none'>
244
+ <td style={{ height: `${paddingTop}px` }} role='none' />
245
+ </tr>
246
+ </tbody>
247
+ )}
248
+ <TableBody rows={rowsToRender} />
249
+ {paddingBottom > 0 && (
250
+ <tbody role='none'>
251
+ <tr role='none'>
252
+ <td style={{ height: `${paddingBottom}px` }} role='none' />
253
+ </tr>
254
+ </tbody>
255
+ )}
256
+ </Fragment>
257
+ );
258
+ };
259
+
260
+ export const MemoizedVirtualizedTableContent = memo(VirtualizedTableContent);
261
+
262
+ const GroupedTableContent = () => {
263
+ const {
264
+ table: { getGroupedRowModel, getHeaderGroups, getState },
265
+ debug,
266
+ } = useTableContext();
267
+
268
+ return (
269
+ <>
270
+ {getGroupedRowModel().rows.map((row, i) => {
271
+ return (
272
+ <Fragment key={i}>
273
+ {/* TODO(burdon): Customize group header renderer. */}
274
+ <thead>
275
+ <tr>
276
+ {debug && <th />}
277
+ <th
278
+ // TODO(burdon): Calculate row span.
279
+ colSpan={getHeaderGroups()[0].headers.length}
280
+ className={groupTh({})}
281
+ >
282
+ {getState().grouping[0]}[{String(row.getGroupingValue(getState().grouping[0]))}]
283
+ </th>
284
+ </tr>
285
+ </thead>
286
+ <TableBody rows={row.subRows} />
287
+ </Fragment>
288
+ );
289
+ })}
290
+ </>
291
+ );
292
+ };
293
+
294
+ // TODO(burdon): Floating "add row" jumps by 1 pixel on scroll.
295
+ // TODO(burdon): Blue focus highlight is clipped by 1px on the left.
296
+ // TODO(burdon): Focused row and focus ring passes over the sticky header.
297
+ export const Table = {
298
+ Root: TableRoot,
299
+ Viewport: TableViewport,
300
+ Main: TablePrimitive,
301
+ };
@@ -5,6 +5,8 @@
5
5
  import { flexRender } from '@tanstack/react-table';
6
6
  import React from 'react';
7
7
 
8
+ import { defaultSizeCol } from '@dxos/react-ui-grid';
9
+
8
10
  import { useTableContext } from './TableContext';
9
11
  import { theadResizeRoot, theadRoot, theadTh, theadTr } from '../../theme';
10
12
 
@@ -24,7 +26,7 @@ const TableHead = (_props: TableHeadProps) => {
24
26
  <tr key={headerGroup.id} className={theadTr(tableContext)}>
25
27
  {/* TODO(burdon): Calc. width. */}
26
28
  {tableContext.debug && (
27
- <th className='font-mono' style={{ width: 32 }}>
29
+ <th className='font-mono' style={{ width: defaultSizeCol }}>
28
30
  #
29
31
  </th>
30
32
  )}
@@ -0,0 +1,8 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ export * from './props';
6
+ export * from './Table';
7
+ export * from './TableContext';
8
+ export * from './TableRootContext';
@@ -0,0 +1,7 @@
1
+ //
2
+ // Copyright 2022 DXOS.org
3
+ //
4
+
5
+ export * from './Cell';
6
+ export * from './ColumnMenu';
7
+ export * from './Table';
@@ -19,6 +19,7 @@ import React, { useCallback, useEffect, useRef, useState } from 'react';
19
19
  import { type PublicKey } from '@dxos/keys';
20
20
  import { log } from '@dxos/log';
21
21
  import { type ClassNameValue, Input, Tooltip } from '@dxos/react-ui';
22
+ import { defaultSizeRow } from '@dxos/react-ui-grid';
22
23
  import { getSize, mx } from '@dxos/react-ui-theme';
23
24
 
24
25
  import { CellCombobox, useTableContext } from './components';
@@ -312,7 +313,7 @@ export class ColumnBuilder<TData extends RowData> {
312
313
  : (cell) => {
313
314
  let value = cell.getValue();
314
315
  // TODO(burdon): Hack to support automerge.
315
- if (typeof value === 'object' && (value as any)?.__typename === 'dxos.Text.v0') {
316
+ if (typeof value === 'object' && (value as any)?.type === 'dxos.Text.v0') {
316
317
  value = (value as any).content;
317
318
  }
318
319
 
@@ -435,7 +436,7 @@ export class ColumnBuilder<TData extends RowData> {
435
436
  >[0] {
436
437
  return {
437
438
  id,
438
- size: 32,
439
+ size: defaultSizeRow,
439
440
  enableResizing: false,
440
441
  meta: { onUpdate, cell: { classNames } },
441
442
  header: ({ table }) => {
@@ -484,7 +485,7 @@ export class ColumnBuilder<TData extends RowData> {
484
485
  const IconOn = on?.Icon ?? Check;
485
486
  const IconOff = off?.Icon ?? X;
486
487
  return {
487
- size: size ?? 32,
488
+ size: size ?? defaultSizeRow,
488
489
  // TODO(zan): Implement sort algorithm.
489
490
  enableSorting: false,
490
491
  header: (column) => <div className={'justify-center'}>{label ?? column.header.id}</div>,
@@ -0,0 +1,8 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ export * from './useColumnSizing';
6
+ export * from './useColumnSorting';
7
+ export * from './usePinLastRow';
8
+ export * from './useRowSelection';
@@ -0,0 +1,12 @@
1
+ //
2
+ // Copyright 2022 DXOS.org
3
+ //
4
+
5
+ export { default as translations } from './translations';
6
+
7
+ export * from './components';
8
+ export * from './helpers';
9
+ export * from './hooks';
10
+ export * from './schema';
11
+ export * from './theme';
12
+ export * from './types';
@@ -0,0 +1,54 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import { type ColumnDef } from '@tanstack/react-table';
6
+
7
+ import { TypeEnum, type S } from '@dxos/echo-schema';
8
+ import { FormatEnum } from '@dxos/echo-schema';
9
+ import { mapSchemaToFields } from '@dxos/schema';
10
+
11
+ import { createColumnBuilder } from '../helpers';
12
+
13
+ /**
14
+ * @deprecated
15
+ */
16
+ export const schemaToColumnDefs = <T>(schema: S.Schema<T, any>): ColumnDef<T, any>[] => {
17
+ const { helper, builder } = createColumnBuilder<T>();
18
+
19
+ return mapSchemaToFields(schema).map(({ property, type, format }) => {
20
+ const propertyKey = property.toString();
21
+
22
+ if (!format) {
23
+ switch (type) {
24
+ case TypeEnum.String: {
25
+ return helper.accessor(
26
+ propertyKey as any,
27
+ builder.string({ label: propertyKey, classNames: [property === 'id' && 'font-mono'] }),
28
+ );
29
+ }
30
+ case TypeEnum.Number: {
31
+ return helper.accessor(propertyKey as any, builder.number({ label: propertyKey }));
32
+ }
33
+ case TypeEnum.Boolean: {
34
+ return helper.accessor(propertyKey as any, builder.switch({ label: propertyKey }));
35
+ }
36
+ default: {
37
+ throw new Error(`Unhandled scalar type: ${type}`);
38
+ }
39
+ }
40
+ }
41
+
42
+ switch (format) {
43
+ case FormatEnum.Date: {
44
+ return helper.accessor(propertyKey as any, builder.date({ label: propertyKey }));
45
+ }
46
+ case FormatEnum.JSON: {
47
+ return helper.accessor(propertyKey as any, builder.json({ label: propertyKey, id: propertyKey }));
48
+ }
49
+ default: {
50
+ throw new Error(`Unhandled format: ${format}`);
51
+ }
52
+ }
53
+ });
54
+ };
@@ -2,7 +2,7 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { type FieldValueType } from '@dxos/schema';
5
+ import { type TypeEnum, type FormatEnum } from '@dxos/echo-schema';
6
6
 
7
7
  /**
8
8
  * @deprecated
@@ -21,7 +21,8 @@ export type TableDef = {
21
21
  export type ColumnDef = {
22
22
  id: string;
23
23
  prop: string;
24
- type: FieldValueType;
24
+ type: TypeEnum;
25
+ format?: FormatEnum;
25
26
  size?: number;
26
27
  label?: string;
27
28
 
@@ -0,0 +1,26 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ export const translationKey = 'table';
6
+
7
+ export default [
8
+ {
9
+ 'en-US': {
10
+ [translationKey]: {
11
+ 'no selection label': ' ',
12
+ 'number column type label': 'Number',
13
+ 'boolean column type label': 'Boolean',
14
+ 'date column type label': 'Date',
15
+ 'string column type label': 'Text',
16
+ 'ref column type label': 'Reference',
17
+ 'digits label': 'Decimal places',
18
+ 'save label': 'Save',
19
+ 'delete label': 'Delete',
20
+ 'column label label': 'Label',
21
+ 'property key label': 'Property',
22
+ 'column type label': 'Type',
23
+ },
24
+ },
25
+ },
26
+ ];
@@ -0,0 +1,60 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import React from 'react';
6
+
7
+ import { DropdownMenu, useTranslation } from '@dxos/react-ui';
8
+
9
+ import { type TableModel } from '../../model';
10
+ import { translationKey } from '../../translations';
11
+
12
+ type ColumnActionsMenuProps = { model?: TableModel };
13
+
14
+ export const ColumnActionsMenu = ({ model }: ColumnActionsMenuProps) => {
15
+ const { t } = useTranslation(translationKey);
16
+ const state = model?.modalController.state.value;
17
+
18
+ if (!model || state?.type !== 'column') {
19
+ return null;
20
+ }
21
+
22
+ const currentSort = model.sorting;
23
+ const isCurrentColumnSorted = currentSort?.fieldId === state.fieldId;
24
+
25
+ return (
26
+ <DropdownMenu.Root modal={false} open={state?.type === 'column'} onOpenChange={model.modalController.close}>
27
+ <DropdownMenu.VirtualTrigger virtualRef={model.modalController.trigger} />
28
+ <DropdownMenu.Portal>
29
+ <DropdownMenu.Content>
30
+ <DropdownMenu.Viewport>
31
+ {(!isCurrentColumnSorted || currentSort?.direction === 'asc') && (
32
+ <DropdownMenu.Item onClick={() => model.setSort(state.fieldId, 'desc')}>
33
+ {t('column action sort descending')}
34
+ </DropdownMenu.Item>
35
+ )}
36
+ {(!isCurrentColumnSorted || currentSort?.direction === 'desc') && (
37
+ <DropdownMenu.Item onClick={() => model.setSort(state.fieldId, 'asc')}>
38
+ {t('column action sort ascending')}
39
+ </DropdownMenu.Item>
40
+ )}
41
+ {isCurrentColumnSorted && (
42
+ <DropdownMenu.Item onClick={() => model.clearSort()}>
43
+ {t('column action clear sorting')}
44
+ </DropdownMenu.Item>
45
+ )}
46
+ {model.getColumnCount() > 1 && (
47
+ <DropdownMenu.Item onClick={() => model.deleteColumn(state.fieldId)}>
48
+ {t('column action delete')}
49
+ </DropdownMenu.Item>
50
+ )}
51
+ <DropdownMenu.Item onClick={() => model.modalController.openColumnSettings()}>
52
+ {t('column action settings')}
53
+ </DropdownMenu.Item>
54
+ </DropdownMenu.Viewport>
55
+ <DropdownMenu.Arrow />
56
+ </DropdownMenu.Content>
57
+ </DropdownMenu.Portal>
58
+ </DropdownMenu.Root>
59
+ );
60
+ };
@@ -0,0 +1,76 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import React, { useCallback, useEffect, useMemo, useState } from 'react';
6
+
7
+ import { getSpace } from '@dxos/react-client/echo';
8
+ import { DropdownMenu } from '@dxos/react-ui';
9
+ import { FieldEditor } from '@dxos/react-ui-form';
10
+ import { type FieldType } from '@dxos/schema';
11
+
12
+ import { type TableModel } from '../../model';
13
+
14
+ type ColumnSettingsProps = { model?: TableModel };
15
+
16
+ export const ColumnSettings = ({ model }: ColumnSettingsProps) => {
17
+ const [newField, setNewField] = useState<FieldType>();
18
+ const state = model?.modalController.state.value;
19
+
20
+ const space = getSpace(model?.table);
21
+
22
+ useEffect(() => {
23
+ if (state?.type === 'columnSettings' && state.mode.type === 'create' && model?.projection) {
24
+ setNewField(model.projection.createFieldProjection());
25
+ } else {
26
+ setNewField(undefined);
27
+ }
28
+ }, [model?.projection, state]);
29
+
30
+ const existingField = useMemo(() => {
31
+ if (state?.type === 'columnSettings') {
32
+ const { mode } = state;
33
+ if (mode.type === 'edit') {
34
+ return model?.table?.view?.fields.find((f) => f.id === mode.fieldId);
35
+ }
36
+ }
37
+ return undefined;
38
+ }, [model?.table?.view?.fields, state]);
39
+
40
+ const field = existingField ?? newField;
41
+
42
+ const handleClose = useCallback(() => {
43
+ model?.modalController.close();
44
+ }, [model?.modalController]);
45
+
46
+ const handleCancel = useCallback(() => {
47
+ if (state?.type === 'columnSettings' && state.mode.type === 'create' && newField) {
48
+ model?.projection?.deleteFieldProjection(newField.id);
49
+ }
50
+ }, [model?.projection, state, newField]);
51
+
52
+ if (!model?.table?.view || !model.projection || !field) {
53
+ return null;
54
+ }
55
+
56
+ return (
57
+ <DropdownMenu.Root modal={false} open={state?.type === 'columnSettings'}>
58
+ <DropdownMenu.VirtualTrigger virtualRef={model.modalController.trigger} />
59
+ <DropdownMenu.Portal>
60
+ <DropdownMenu.Content classNames='md:is-64'>
61
+ <DropdownMenu.Viewport>
62
+ <FieldEditor
63
+ view={model.table.view}
64
+ projection={model.projection}
65
+ field={field}
66
+ registry={space?.db.schemaRegistry}
67
+ onClose={handleClose}
68
+ onCancel={handleCancel}
69
+ />
70
+ </DropdownMenu.Viewport>
71
+ <DropdownMenu.Arrow />
72
+ </DropdownMenu.Content>
73
+ </DropdownMenu.Portal>
74
+ </DropdownMenu.Root>
75
+ );
76
+ };
@@ -0,0 +1,36 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import React from 'react';
6
+
7
+ import { DropdownMenu, useTranslation } from '@dxos/react-ui';
8
+
9
+ import { type TableModel } from '../../model';
10
+ import { translationKey } from '../../translations';
11
+
12
+ type RowActionsMenuProps = { model: TableModel };
13
+
14
+ export const RowActionsMenu = ({ model }: RowActionsMenuProps) => {
15
+ const { t } = useTranslation(translationKey);
16
+ const state = model.modalController.state.value;
17
+ const hasSelection = model.selection.hasSelection.value;
18
+
19
+ if (state?.type !== 'row') {
20
+ return null;
21
+ }
22
+
23
+ return (
24
+ <DropdownMenu.Root modal={false} open={true} onOpenChange={model.modalController.close}>
25
+ <DropdownMenu.VirtualTrigger virtualRef={model.modalController.trigger} />
26
+ <DropdownMenu.Content>
27
+ <DropdownMenu.Viewport>
28
+ <DropdownMenu.Item onClick={() => model.deleteRow(state.rowIndex)}>
29
+ {t(hasSelection ? 'bulk delete row label' : 'delete row label')}
30
+ </DropdownMenu.Item>
31
+ </DropdownMenu.Viewport>
32
+ <DropdownMenu.Arrow />
33
+ </DropdownMenu.Content>
34
+ </DropdownMenu.Root>
35
+ );
36
+ };