@dxos/react-ui-table 0.8.0 → 0.8.1-main.81238a8

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 (207) hide show
  1. package/dist/lib/browser/{chunk-3FR6NHPD.mjs → chunk-5MKYB7NF.mjs} +5 -7
  2. package/dist/lib/browser/chunk-5MKYB7NF.mjs.map +7 -0
  3. package/dist/lib/browser/{_deprecated → deprecated}/index.mjs +26 -26
  4. package/dist/lib/{node-esm/_deprecated → browser/deprecated}/index.mjs.map +4 -4
  5. package/dist/lib/browser/index.mjs +289 -123
  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 +1 -1
  9. package/dist/lib/node/{chunk-NB3SFHGA.cjs → chunk-NRFKBRPV.cjs} +7 -9
  10. package/dist/lib/node/chunk-NRFKBRPV.cjs.map +7 -0
  11. package/dist/lib/node/{_deprecated → deprecated}/index.cjs +5 -5
  12. package/dist/lib/node/{_deprecated → deprecated}/index.cjs.map +4 -4
  13. package/dist/lib/node/index.cjs +282 -120
  14. package/dist/lib/node/index.cjs.map +4 -4
  15. package/dist/lib/node/meta.json +1 -1
  16. package/dist/lib/node/types/index.cjs +3 -3
  17. package/dist/lib/node/types/index.cjs.map +1 -1
  18. package/dist/lib/node-esm/{chunk-RLVVOZW5.mjs → chunk-SU4D55KI.mjs} +5 -7
  19. package/dist/lib/node-esm/chunk-SU4D55KI.mjs.map +7 -0
  20. package/dist/lib/node-esm/{_deprecated → deprecated}/index.mjs +26 -26
  21. package/dist/lib/node-esm/deprecated/index.mjs.map +7 -0
  22. package/dist/lib/node-esm/index.mjs +289 -123
  23. package/dist/lib/node-esm/index.mjs.map +4 -4
  24. package/dist/lib/node-esm/meta.json +1 -1
  25. package/dist/lib/node-esm/types/index.mjs +1 -1
  26. package/dist/types/src/components/Table/ColumnActionsMenu.d.ts +2 -1
  27. package/dist/types/src/components/Table/ColumnActionsMenu.d.ts.map +1 -1
  28. package/dist/types/src/components/Table/ColumnSettings.d.ts +2 -1
  29. package/dist/types/src/components/Table/ColumnSettings.d.ts.map +1 -1
  30. package/dist/types/src/components/Table/CreateRefPanel.d.ts +2 -1
  31. package/dist/types/src/components/Table/CreateRefPanel.d.ts.map +1 -1
  32. package/dist/types/src/components/Table/DynamicTable.d.ts +19 -0
  33. package/dist/types/src/components/Table/DynamicTable.d.ts.map +1 -0
  34. package/dist/types/src/components/Table/RefPanel.d.ts +2 -1
  35. package/dist/types/src/components/Table/RefPanel.d.ts.map +1 -1
  36. package/dist/types/src/components/Table/RowActionsMenu.d.ts +2 -1
  37. package/dist/types/src/components/Table/RowActionsMenu.d.ts.map +1 -1
  38. package/dist/types/src/components/Table/Table.d.ts +6 -1
  39. package/dist/types/src/components/Table/Table.d.ts.map +1 -1
  40. package/dist/types/src/components/Table/Table.stories.d.ts +2 -1
  41. package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
  42. package/dist/types/src/components/Table/index.d.ts +1 -0
  43. package/dist/types/src/components/Table/index.d.ts.map +1 -1
  44. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +2 -1
  45. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
  46. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts +2 -1
  47. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts.map +1 -1
  48. package/dist/types/src/components/testing.d.ts +14 -7
  49. package/dist/types/src/components/testing.d.ts.map +1 -1
  50. package/dist/types/src/{_deprecated → deprecated}/components/Cell/Cell.d.ts +2 -2
  51. package/dist/types/src/deprecated/components/Cell/Cell.d.ts.map +1 -0
  52. package/dist/types/src/{_deprecated → deprecated}/components/Cell/CellCombobox.d.ts +2 -1
  53. package/dist/types/src/deprecated/components/Cell/CellCombobox.d.ts.map +1 -0
  54. package/dist/types/src/deprecated/components/Cell/index.d.ts.map +1 -0
  55. package/dist/types/src/{_deprecated → deprecated}/components/ColumnMenu/ColumnMenu.d.ts +3 -2
  56. package/dist/types/src/deprecated/components/ColumnMenu/ColumnMenu.d.ts.map +1 -0
  57. package/dist/types/src/{_deprecated → deprecated}/components/ColumnMenu/ColumnMenu.stories.d.ts +3 -2
  58. package/dist/types/src/deprecated/components/ColumnMenu/ColumnMenu.stories.d.ts.map +1 -0
  59. package/dist/types/src/{_deprecated → deprecated}/components/ColumnMenu/ColumnSettings.d.ts +2 -1
  60. package/dist/types/src/deprecated/components/ColumnMenu/ColumnSettings.d.ts.map +1 -0
  61. package/dist/types/src/{_deprecated → deprecated}/components/ColumnMenu/ColumnSettings.stories.d.ts +3 -2
  62. package/dist/types/src/deprecated/components/ColumnMenu/ColumnSettings.stories.d.ts.map +1 -0
  63. package/dist/types/src/deprecated/components/ColumnMenu/index.d.ts.map +1 -0
  64. package/dist/types/src/{_deprecated → deprecated}/components/Table/Table.d.ts +5 -5
  65. package/dist/types/src/deprecated/components/Table/Table.d.ts.map +1 -0
  66. package/dist/types/src/{_deprecated → deprecated}/components/Table/Table.stories.d.ts +8 -7
  67. package/dist/types/src/deprecated/components/Table/Table.stories.d.ts.map +1 -0
  68. package/dist/types/src/{_deprecated → deprecated}/components/Table/TableBody.d.ts +2 -1
  69. package/dist/types/src/deprecated/components/Table/TableBody.d.ts.map +1 -0
  70. package/dist/types/src/{_deprecated → deprecated}/components/Table/TableContext.d.ts +1 -1
  71. package/dist/types/src/deprecated/components/Table/TableContext.d.ts.map +1 -0
  72. package/dist/types/src/{_deprecated → deprecated}/components/Table/TableHead.d.ts +2 -1
  73. package/dist/types/src/deprecated/components/Table/TableHead.d.ts.map +1 -0
  74. package/dist/types/src/deprecated/components/Table/TableRootContext.d.ts.map +1 -0
  75. package/dist/types/src/deprecated/components/Table/index.d.ts.map +1 -0
  76. package/dist/types/src/deprecated/components/Table/props.d.ts.map +1 -0
  77. package/dist/types/src/deprecated/components/index.d.ts.map +1 -0
  78. package/dist/types/src/deprecated/helpers.d.ts.map +1 -0
  79. package/dist/types/src/deprecated/hooks/index.d.ts.map +1 -0
  80. package/dist/types/src/deprecated/hooks/useColumnSizing.d.ts.map +1 -0
  81. package/dist/types/src/deprecated/hooks/useColumnSorting.d.ts.map +1 -0
  82. package/dist/types/src/deprecated/hooks/usePinLastRow.d.ts.map +1 -0
  83. package/dist/types/src/deprecated/hooks/useRowSelection.d.ts.map +1 -0
  84. package/dist/types/src/deprecated/index.d.ts.map +1 -0
  85. package/dist/types/src/{_deprecated → deprecated}/schema/Schema.stories.d.ts +2 -1
  86. package/dist/types/src/deprecated/schema/Schema.stories.d.ts.map +1 -0
  87. package/dist/types/src/deprecated/schema/column-utils.d.ts.map +1 -0
  88. package/dist/types/src/deprecated/schema/index.d.ts.map +1 -0
  89. package/dist/types/src/deprecated/schema/types.d.ts.map +1 -0
  90. package/dist/types/src/deprecated/theme.d.ts.map +1 -0
  91. package/dist/types/src/deprecated/translations.d.ts.map +1 -0
  92. package/dist/types/src/deprecated/types.d.ts.map +1 -0
  93. package/dist/types/src/hooks/useTableModel.d.ts +5 -2
  94. package/dist/types/src/hooks/useTableModel.d.ts.map +1 -1
  95. package/dist/types/src/model/table-model.d.ts +26 -7
  96. package/dist/types/src/model/table-model.d.ts.map +1 -1
  97. package/dist/types/src/model/table-sorting.d.ts.map +1 -1
  98. package/dist/types/src/types/table.d.ts +16 -21
  99. package/dist/types/src/types/table.d.ts.map +1 -1
  100. package/dist/types/src/util/dynamic-table.d.ts +40 -0
  101. package/dist/types/src/util/dynamic-table.d.ts.map +1 -0
  102. package/dist/types/src/util/index.d.ts +1 -0
  103. package/dist/types/src/util/index.d.ts.map +1 -1
  104. package/package.json +35 -35
  105. package/src/components/Table/ColumnSettings.tsx +5 -6
  106. package/src/components/Table/CreateRefPanel.tsx +3 -3
  107. package/src/components/Table/DynamicTable.tsx +86 -0
  108. package/src/components/Table/RefPanel.tsx +3 -3
  109. package/src/components/Table/RowActionsMenu.tsx +13 -0
  110. package/src/components/Table/Table.stories.tsx +27 -2
  111. package/src/components/Table/Table.tsx +29 -10
  112. package/src/components/Table/index.ts +1 -0
  113. package/src/components/testing.ts +1 -0
  114. package/src/{_deprecated → deprecated}/components/Cell/Cell.tsx +2 -2
  115. package/src/{_deprecated → deprecated}/components/Table/TableBody.tsx +2 -2
  116. package/src/{_deprecated → deprecated}/helpers.tsx +2 -2
  117. package/src/{_deprecated → deprecated}/schema/Schema.stories.tsx +1 -1
  118. package/src/hooks/useTableModel.ts +22 -6
  119. package/src/model/table-model.test.ts +1 -1
  120. package/src/model/table-model.ts +76 -21
  121. package/src/model/table-presentation.test.ts +1 -1
  122. package/src/model/table-presentation.ts +3 -3
  123. package/src/model/table-sorting.ts +1 -0
  124. package/src/types/table.ts +5 -7
  125. package/src/util/dynamic-table.ts +71 -0
  126. package/src/util/index.ts +1 -0
  127. package/dist/lib/browser/_deprecated/index.mjs.map +0 -7
  128. package/dist/lib/browser/chunk-3FR6NHPD.mjs.map +0 -7
  129. package/dist/lib/node/chunk-NB3SFHGA.cjs.map +0 -7
  130. package/dist/lib/node-esm/chunk-RLVVOZW5.mjs.map +0 -7
  131. package/dist/types/src/_deprecated/components/Cell/Cell.d.ts.map +0 -1
  132. package/dist/types/src/_deprecated/components/Cell/CellCombobox.d.ts.map +0 -1
  133. package/dist/types/src/_deprecated/components/Cell/index.d.ts.map +0 -1
  134. package/dist/types/src/_deprecated/components/ColumnMenu/ColumnMenu.d.ts.map +0 -1
  135. package/dist/types/src/_deprecated/components/ColumnMenu/ColumnMenu.stories.d.ts.map +0 -1
  136. package/dist/types/src/_deprecated/components/ColumnMenu/ColumnSettings.d.ts.map +0 -1
  137. package/dist/types/src/_deprecated/components/ColumnMenu/ColumnSettings.stories.d.ts.map +0 -1
  138. package/dist/types/src/_deprecated/components/ColumnMenu/index.d.ts.map +0 -1
  139. package/dist/types/src/_deprecated/components/Table/Table.d.ts.map +0 -1
  140. package/dist/types/src/_deprecated/components/Table/Table.stories.d.ts.map +0 -1
  141. package/dist/types/src/_deprecated/components/Table/TableBody.d.ts.map +0 -1
  142. package/dist/types/src/_deprecated/components/Table/TableContext.d.ts.map +0 -1
  143. package/dist/types/src/_deprecated/components/Table/TableHead.d.ts.map +0 -1
  144. package/dist/types/src/_deprecated/components/Table/TableRootContext.d.ts.map +0 -1
  145. package/dist/types/src/_deprecated/components/Table/index.d.ts.map +0 -1
  146. package/dist/types/src/_deprecated/components/Table/props.d.ts.map +0 -1
  147. package/dist/types/src/_deprecated/components/index.d.ts.map +0 -1
  148. package/dist/types/src/_deprecated/helpers.d.ts.map +0 -1
  149. package/dist/types/src/_deprecated/hooks/index.d.ts.map +0 -1
  150. package/dist/types/src/_deprecated/hooks/useColumnSizing.d.ts.map +0 -1
  151. package/dist/types/src/_deprecated/hooks/useColumnSorting.d.ts.map +0 -1
  152. package/dist/types/src/_deprecated/hooks/usePinLastRow.d.ts.map +0 -1
  153. package/dist/types/src/_deprecated/hooks/useRowSelection.d.ts.map +0 -1
  154. package/dist/types/src/_deprecated/index.d.ts.map +0 -1
  155. package/dist/types/src/_deprecated/schema/Schema.stories.d.ts.map +0 -1
  156. package/dist/types/src/_deprecated/schema/column-utils.d.ts.map +0 -1
  157. package/dist/types/src/_deprecated/schema/index.d.ts.map +0 -1
  158. package/dist/types/src/_deprecated/schema/types.d.ts.map +0 -1
  159. package/dist/types/src/_deprecated/theme.d.ts.map +0 -1
  160. package/dist/types/src/_deprecated/translations.d.ts.map +0 -1
  161. package/dist/types/src/_deprecated/types.d.ts.map +0 -1
  162. /package/dist/types/src/{_deprecated → deprecated}/components/Cell/index.d.ts +0 -0
  163. /package/dist/types/src/{_deprecated → deprecated}/components/ColumnMenu/index.d.ts +0 -0
  164. /package/dist/types/src/{_deprecated → deprecated}/components/Table/TableRootContext.d.ts +0 -0
  165. /package/dist/types/src/{_deprecated → deprecated}/components/Table/index.d.ts +0 -0
  166. /package/dist/types/src/{_deprecated → deprecated}/components/Table/props.d.ts +0 -0
  167. /package/dist/types/src/{_deprecated → deprecated}/components/index.d.ts +0 -0
  168. /package/dist/types/src/{_deprecated → deprecated}/helpers.d.ts +0 -0
  169. /package/dist/types/src/{_deprecated → deprecated}/hooks/index.d.ts +0 -0
  170. /package/dist/types/src/{_deprecated → deprecated}/hooks/useColumnSizing.d.ts +0 -0
  171. /package/dist/types/src/{_deprecated → deprecated}/hooks/useColumnSorting.d.ts +0 -0
  172. /package/dist/types/src/{_deprecated → deprecated}/hooks/usePinLastRow.d.ts +0 -0
  173. /package/dist/types/src/{_deprecated → deprecated}/hooks/useRowSelection.d.ts +0 -0
  174. /package/dist/types/src/{_deprecated → deprecated}/index.d.ts +0 -0
  175. /package/dist/types/src/{_deprecated → deprecated}/schema/column-utils.d.ts +0 -0
  176. /package/dist/types/src/{_deprecated → deprecated}/schema/index.d.ts +0 -0
  177. /package/dist/types/src/{_deprecated → deprecated}/schema/types.d.ts +0 -0
  178. /package/dist/types/src/{_deprecated → deprecated}/theme.d.ts +0 -0
  179. /package/dist/types/src/{_deprecated → deprecated}/translations.d.ts +0 -0
  180. /package/dist/types/src/{_deprecated → deprecated}/types.d.ts +0 -0
  181. /package/src/{_deprecated → deprecated}/components/Cell/CellCombobox.tsx +0 -0
  182. /package/src/{_deprecated → deprecated}/components/Cell/index.ts +0 -0
  183. /package/src/{_deprecated → deprecated}/components/ColumnMenu/ColumnMenu.stories.tsx +0 -0
  184. /package/src/{_deprecated → deprecated}/components/ColumnMenu/ColumnMenu.tsx +0 -0
  185. /package/src/{_deprecated → deprecated}/components/ColumnMenu/ColumnSettings.stories.tsx +0 -0
  186. /package/src/{_deprecated → deprecated}/components/ColumnMenu/ColumnSettings.tsx +0 -0
  187. /package/src/{_deprecated → deprecated}/components/ColumnMenu/index.ts +0 -0
  188. /package/src/{_deprecated → deprecated}/components/Table/Table.stories.tsx +0 -0
  189. /package/src/{_deprecated → deprecated}/components/Table/Table.tsx +0 -0
  190. /package/src/{_deprecated → deprecated}/components/Table/TableContext.tsx +0 -0
  191. /package/src/{_deprecated → deprecated}/components/Table/TableHead.tsx +0 -0
  192. /package/src/{_deprecated → deprecated}/components/Table/TableRootContext.ts +0 -0
  193. /package/src/{_deprecated → deprecated}/components/Table/index.ts +0 -0
  194. /package/src/{_deprecated → deprecated}/components/Table/props.ts +0 -0
  195. /package/src/{_deprecated → deprecated}/components/index.ts +0 -0
  196. /package/src/{_deprecated → deprecated}/hooks/index.ts +0 -0
  197. /package/src/{_deprecated → deprecated}/hooks/useColumnSizing.ts +0 -0
  198. /package/src/{_deprecated → deprecated}/hooks/useColumnSorting.ts +0 -0
  199. /package/src/{_deprecated → deprecated}/hooks/usePinLastRow.ts +0 -0
  200. /package/src/{_deprecated → deprecated}/hooks/useRowSelection.ts +0 -0
  201. /package/src/{_deprecated → deprecated}/index.ts +0 -0
  202. /package/src/{_deprecated → deprecated}/schema/column-utils.ts +0 -0
  203. /package/src/{_deprecated → deprecated}/schema/index.ts +0 -0
  204. /package/src/{_deprecated → deprecated}/schema/types.ts +0 -0
  205. /package/src/{_deprecated → deprecated}/theme.ts +0 -0
  206. /package/src/{_deprecated → deprecated}/translations.ts +0 -0
  207. /package/src/{_deprecated → deprecated}/types.ts +0 -0
@@ -5,24 +5,30 @@
5
5
  import { effect } from '@preact/signals-core';
6
6
  import { useEffect, useState } from 'react';
7
7
 
8
- import { type ReactiveObject } from '@dxos/react-client/echo';
8
+ import { fullyQualifiedId, getSpace, type ReactiveObject } from '@dxos/react-client/echo';
9
9
  import { useSelectionActions } from '@dxos/react-ui-attention';
10
10
  import { type ViewProjection } from '@dxos/schema';
11
11
  import { isNonNullable } from '@dxos/util';
12
12
 
13
- import { type BaseTableRow, TableModel, type TableModelProps } from '../model';
13
+ import { type BaseTableRow, TableModel, type TableModelProps, type TableRowAction } from '../model';
14
14
  import { type TableType } from '../types';
15
15
 
16
16
  export type UseTableModelParams<T extends BaseTableRow = { id: string }> = {
17
17
  table?: TableType;
18
18
  projection?: ViewProjection;
19
19
  objects?: ReactiveObject<T>[];
20
+ onSelectionChanged?: (selection: string[]) => void;
21
+ rowActions?: TableRowAction[];
22
+ onRowAction?: (actionId: string, data: T) => void;
20
23
  } & Pick<TableModelProps<T>, 'onInsertRow' | 'onDeleteRows' | 'onDeleteColumn' | 'onCellUpdate' | 'onRowOrderChanged'>;
21
24
 
22
25
  export const useTableModel = <T extends BaseTableRow = { id: string }>({
23
26
  objects,
24
27
  table,
25
28
  projection,
29
+ onSelectionChanged,
30
+ rowActions,
31
+ onRowAction,
26
32
  ...props
27
33
  }: UseTableModelParams<T>): TableModel<T> | undefined => {
28
34
  const [model, setModel] = useState<TableModel<T>>();
@@ -33,7 +39,15 @@ export const useTableModel = <T extends BaseTableRow = { id: string }>({
33
39
 
34
40
  let model: TableModel<T> | undefined;
35
41
  const t = setTimeout(async () => {
36
- model = new TableModel<T>({ table, projection, ...props });
42
+ model = new TableModel<T>({
43
+ id: fullyQualifiedId(table),
44
+ space: getSpace(table),
45
+ view: table.view?.target,
46
+ projection,
47
+ rowActions,
48
+ onRowAction,
49
+ ...props,
50
+ });
37
51
  await model.open();
38
52
  setModel(model);
39
53
  });
@@ -42,7 +56,7 @@ export const useTableModel = <T extends BaseTableRow = { id: string }>({
42
56
  clearTimeout(t);
43
57
  void model?.close();
44
58
  };
45
- }, [table, projection]); // TODO(burdon): Trigger if callbacks change?
59
+ }, [table, projection, table?.view?.target, rowActions]); // TODO(burdon): Trigger if callbacks change?
46
60
 
47
61
  // Update data.
48
62
  useEffect(() => {
@@ -59,7 +73,9 @@ export const useTableModel = <T extends BaseTableRow = { id: string }>({
59
73
  }
60
74
 
61
75
  const unsubscribe = effect(() => {
62
- select([...model.selection.selection.value]);
76
+ const selectedItems = [...model.selection.selection.value];
77
+ select(selectedItems);
78
+ onSelectionChanged?.(selectedItems);
63
79
  });
64
80
 
65
81
  // Maybe clear the selection here?
@@ -67,7 +83,7 @@ export const useTableModel = <T extends BaseTableRow = { id: string }>({
67
83
  clear();
68
84
  unsubscribe();
69
85
  };
70
- }, [model]);
86
+ }, [model, onSelectionChanged]);
71
87
 
72
88
  return model;
73
89
  };
@@ -108,5 +108,5 @@ const createTableModel = (props: Partial<TableModelProps> = {}): TableModel => {
108
108
  const view = createView({ name: 'Test', typename: schema.typename, jsonSchema: schema.jsonSchema });
109
109
  const projection = new ViewProjection(schema, view);
110
110
  const table = create(TableType, { view: makeRef(view) });
111
- return new TableModel({ table, projection, ...props });
111
+ return new TableModel({ id: table.id, space: undefined, view, projection, ...props });
112
112
  };
@@ -4,11 +4,11 @@
4
4
 
5
5
  import { computed, effect, signal, type ReadonlySignal } from '@preact/signals-core';
6
6
 
7
+ import { type Space } from '@dxos/client/echo';
7
8
  import { Resource } from '@dxos/context';
8
9
  import { type FieldSortType, FormatEnum, getValue, setValue, type JsonProp } from '@dxos/echo-schema';
9
10
  import { invariant } from '@dxos/invariant';
10
11
  import { isReactiveObject, makeRef } from '@dxos/live-object';
11
- import { PublicKey } from '@dxos/react-client';
12
12
  import { formatForEditing, parseValue } from '@dxos/react-ui-form';
13
13
  import {
14
14
  type DxGridAxisMeta,
@@ -16,17 +16,23 @@ import {
16
16
  type DxGridPlanePosition,
17
17
  type DxGridPosition,
18
18
  } from '@dxos/react-ui-grid';
19
- import { type ViewProjection } from '@dxos/schema';
19
+ import { type ViewType, type ViewProjection } from '@dxos/schema';
20
20
 
21
21
  import { SelectionModel } from './selection-model';
22
22
  import { TableSorting } from './table-sorting';
23
- import { type TableType } from '../types';
24
23
  import { touch } from '../util';
25
24
 
26
25
  export type BaseTableRow = Record<JsonProp, any> & { id: string };
27
26
 
27
+ export type TableRowAction = {
28
+ id: string;
29
+ translationKey: string;
30
+ };
31
+
28
32
  export type TableModelProps<T extends BaseTableRow = { id: string }> = {
29
- table: TableType;
33
+ id?: string;
34
+ space?: Space;
35
+ view?: ViewType;
30
36
  projection: ViewProjection;
31
37
  sorting?: FieldSortType[];
32
38
  pinnedRows?: { top: number[]; bottom: number[] };
@@ -35,12 +41,14 @@ export type TableModelProps<T extends BaseTableRow = { id: string }> = {
35
41
  onDeleteColumn?: (fieldId: string) => void;
36
42
  onCellUpdate?: (cell: DxGridPosition) => void;
37
43
  onRowOrderChanged?: () => void;
44
+ rowActions?: TableRowAction[];
45
+ onRowAction?: (actionId: string, data: T) => void;
38
46
  };
39
47
 
40
48
  export class TableModel<T extends BaseTableRow = { id: string }> extends Resource {
41
- public readonly id = `table-model-${PublicKey.random().truncate()}`;
42
-
43
- private readonly _table: TableType;
49
+ private readonly _id: string | undefined;
50
+ private readonly _space: Space | undefined;
51
+ private readonly _view: ViewType | undefined;
44
52
  private readonly _projection: ViewProjection;
45
53
 
46
54
  private readonly _visibleRange = signal<DxGridPlaneRange>({
@@ -53,6 +61,8 @@ export class TableModel<T extends BaseTableRow = { id: string }> extends Resourc
53
61
  private readonly _onDeleteColumn?: TableModelProps<T>['onDeleteColumn'];
54
62
  private readonly _onCellUpdate?: TableModelProps<T>['onCellUpdate'];
55
63
  private readonly _onRowOrderChanged?: TableModelProps<T>['onRowOrderChanged'];
64
+ private readonly _rowActions: TableRowAction[];
65
+ private readonly _onRowAction?: TableModelProps<T>['onRowAction'];
56
66
 
57
67
  private readonly _rows = signal<T[]>([]);
58
68
  private readonly _sorting: TableSorting<T>;
@@ -62,7 +72,9 @@ export class TableModel<T extends BaseTableRow = { id: string }> extends Resourc
62
72
  private _columnMeta?: ReadonlySignal<DxGridAxisMeta>;
63
73
 
64
74
  constructor({
65
- table,
75
+ id,
76
+ space,
77
+ view,
66
78
  projection,
67
79
  sorting = [],
68
80
  pinnedRows = { top: [], bottom: [] },
@@ -71,11 +83,16 @@ export class TableModel<T extends BaseTableRow = { id: string }> extends Resourc
71
83
  onDeleteRows,
72
84
  onInsertRow,
73
85
  onRowOrderChanged,
86
+ rowActions = [],
87
+ onRowAction,
74
88
  }: TableModelProps<T>) {
75
89
  super();
76
- this._table = table;
90
+ this._id = id;
91
+ this._space = space;
92
+ this._view = view;
77
93
  this._projection = projection;
78
- this._sorting = new TableSorting(this._rows, table.view?.target, projection);
94
+
95
+ this._sorting = new TableSorting(this._rows, this._view, projection);
79
96
 
80
97
  if (sorting.length > 0) {
81
98
  const [sort] = sorting;
@@ -88,10 +105,20 @@ export class TableModel<T extends BaseTableRow = { id: string }> extends Resourc
88
105
  this._onDeleteColumn = onDeleteColumn;
89
106
  this._onCellUpdate = onCellUpdate;
90
107
  this._onRowOrderChanged = onRowOrderChanged;
108
+ this._rowActions = rowActions;
109
+ this._onRowAction = onRowAction;
91
110
  }
92
111
 
93
- public get table() {
94
- return this._table;
112
+ public get id() {
113
+ return this._id;
114
+ }
115
+
116
+ public get space() {
117
+ return this._space;
118
+ }
119
+
120
+ public get view() {
121
+ return this._view;
95
122
  }
96
123
 
97
124
  public get projection() {
@@ -109,6 +136,17 @@ export class TableModel<T extends BaseTableRow = { id: string }> extends Resourc
109
136
  return this._sorting;
110
137
  }
111
138
 
139
+ /**
140
+ * Gets the row data at the specified display index.
141
+ */
142
+ public getRowAt(displayIndex: number): T | undefined {
143
+ if (displayIndex < 0 || displayIndex >= this._sorting.sortedRows.value.length) {
144
+ return undefined;
145
+ }
146
+
147
+ return this._sorting.sortedRows.value[displayIndex];
148
+ }
149
+
112
150
  public get pinnedRows(): NonNullable<TableModelProps<T>['pinnedRows']> {
113
151
  return this._pinnedRows;
114
152
  }
@@ -127,6 +165,10 @@ export class TableModel<T extends BaseTableRow = { id: string }> extends Resourc
127
165
  return this._sorting.isDirty;
128
166
  }
129
167
 
168
+ public get rowActions(): TableRowAction[] {
169
+ return this._rowActions;
170
+ }
171
+
130
172
  //
131
173
  // Initialisation
132
174
  //
@@ -140,7 +182,7 @@ export class TableModel<T extends BaseTableRow = { id: string }> extends Resourc
140
182
 
141
183
  private initializeColumnMeta(): void {
142
184
  this._columnMeta = computed(() => {
143
- const fields = this._table.view?.target?.fields ?? [];
185
+ const fields = this._view?.fields ?? [];
144
186
  const meta = Object.fromEntries(
145
187
  fields.map((field, index: number) => [index, { size: field?.size ?? 256, resizeable: true }]),
146
188
  );
@@ -172,7 +214,7 @@ export class TableModel<T extends BaseTableRow = { id: string }> extends Resourc
172
214
  rowEffects.push(
173
215
  effect(() => {
174
216
  const obj = this._sorting.sortedRows.value[row];
175
- this?._table?.view?.target?.fields.forEach((field) => touch(getValue(obj, field.path)));
217
+ this._view?.fields.forEach((field) => touch(getValue(obj, field.path)));
176
218
  this._onCellUpdate?.({ row, col: start.col, plane: 'grid' });
177
219
  }),
178
220
  );
@@ -193,7 +235,7 @@ export class TableModel<T extends BaseTableRow = { id: string }> extends Resourc
193
235
 
194
236
  public getRowCount = (): number => this._rows.value.length;
195
237
 
196
- public getColumnCount = (): number => this.table.view?.target?.fields.length ?? 0;
238
+ public getColumnCount = (): number => this._view?.fields.length ?? 0;
197
239
 
198
240
  public insertRow = (rowIndex?: number): void => {
199
241
  const row = rowIndex !== undefined ? this._sorting.getDataIndex(rowIndex) : this._rows.value.length;
@@ -215,8 +257,21 @@ export class TableModel<T extends BaseTableRow = { id: string }> extends Resourc
215
257
  this._onDeleteRows?.(row, objectsToDelete);
216
258
  };
217
259
 
260
+ public handleRowAction = (actionId: string, rowIndex: number): void => {
261
+ if (!this._onRowAction) {
262
+ return;
263
+ }
264
+
265
+ const row = this._sorting.getDataIndex(rowIndex);
266
+ const data = this._rows.value[row];
267
+
268
+ if (data) {
269
+ this._onRowAction(actionId, data);
270
+ }
271
+ };
272
+
218
273
  public getCellData = ({ col, row }: DxGridPlanePosition): any => {
219
- const fields = this.table.view?.target?.fields ?? [];
274
+ const fields = this._view?.fields ?? [];
220
275
  if (col < 0 || col >= fields.length) {
221
276
  return undefined;
222
277
  }
@@ -246,7 +301,7 @@ export class TableModel<T extends BaseTableRow = { id: string }> extends Resourc
246
301
 
247
302
  public setCellData = ({ col, row }: DxGridPlanePosition, value: any): void => {
248
303
  const rowIdx = this._sorting.getDataIndex(row);
249
- const fields = this.table.view?.target?.fields ?? [];
304
+ const fields = this._view?.fields ?? [];
250
305
  if (col < 0 || col >= fields.length) {
251
306
  return;
252
307
  }
@@ -285,7 +340,7 @@ export class TableModel<T extends BaseTableRow = { id: string }> extends Resourc
285
340
  */
286
341
  public updateCellData({ col, row }: DxGridPlanePosition, update: (value: any) => any): void {
287
342
  const dataRow = this._sorting.getDataIndex(row);
288
- const fields = this.table.view?.target?.fields ?? [];
343
+ const fields = this._view?.fields ?? [];
289
344
  const field = fields[col];
290
345
 
291
346
  const value = getValue(this._rows.value[dataRow], field.path);
@@ -298,11 +353,11 @@ export class TableModel<T extends BaseTableRow = { id: string }> extends Resourc
298
353
  //
299
354
 
300
355
  public deleteColumn(fieldId: string): void {
301
- if (!this.table.view) {
356
+ if (!this._view) {
302
357
  return;
303
358
  }
304
359
 
305
- const field = this.table.view.target?.fields.find((field) => field.id === fieldId);
360
+ const field = this._view?.fields.find((field) => field.id === fieldId);
306
361
  if (field && this._onDeleteColumn) {
307
362
  this._onDeleteColumn(field.id);
308
363
  }
@@ -313,7 +368,7 @@ export class TableModel<T extends BaseTableRow = { id: string }> extends Resourc
313
368
  //
314
369
 
315
370
  public setColumnWidth(columnIndex: number, width: number): void {
316
- const fields = this.table.view?.target?.fields ?? [];
371
+ const fields = this._view?.fields ?? [];
317
372
  if (columnIndex < fields.length) {
318
373
  const newWidth = Math.max(0, width);
319
374
  const field = fields[columnIndex];
@@ -98,5 +98,5 @@ const createTableModel = (props: Partial<TableModelProps> = {}): TableModel => {
98
98
  const view = createView({ name: 'Test', typename: schema.typename, jsonSchema: schema.jsonSchema });
99
99
  const projection = new ViewProjection(schema, view);
100
100
  const table = create(TableType, { view: makeRef(view) });
101
- return new TableModel({ table, projection, ...props });
101
+ return new TableModel({ id: table.id, view, projection, ...props });
102
102
  };
@@ -55,7 +55,7 @@ export class TablePresentation<T extends BaseTableRow = { id: string }> {
55
55
 
56
56
  private getMainGridCells(range: DxGridPlaneRange): DxGridPlaneCells {
57
57
  const cells: DxGridPlaneCells = {};
58
- const fields = this.model.table.view?.target?.fields ?? [];
58
+ const fields = this.model.view?.fields ?? [];
59
59
 
60
60
  const addCell = (obj: T, field: FieldType, colIndex: number, displayIndex: number): void => {
61
61
  const { props } = this.model.projection.getFieldProjection(field.id);
@@ -151,7 +151,7 @@ export class TablePresentation<T extends BaseTableRow = { id: string }> {
151
151
 
152
152
  private getHeaderCells(range: DxGridPlaneRange): DxGridPlaneCells {
153
153
  const cells: DxGridPlaneCells = {};
154
- const fields = this.model.table.view?.target?.fields ?? [];
154
+ const fields = this.model.view?.fields ?? [];
155
155
  for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
156
156
  const { field, props } = this.model.projection.getFieldProjection(fields[col].id);
157
157
  const sorting = this.model.sorting?.sorting;
@@ -224,7 +224,7 @@ export class TablePresentation<T extends BaseTableRow = { id: string }> {
224
224
  return {
225
225
  [toPlaneCellIndex({ col: 0, row: 0 })]: {
226
226
  accessoryHtml: tableButtons.addColumn.render({
227
- disabled: (this.model.table.view?.target?.fields?.length ?? 0) >= VIEW_FIELD_LIMIT,
227
+ disabled: (this.model.view?.fields?.length ?? 0) >= VIEW_FIELD_LIMIT,
228
228
  }),
229
229
  className: '!bg-gridHeader',
230
230
  readonly: true,
@@ -82,6 +82,7 @@ export class TableSorting<T extends BaseTableRow> {
82
82
  if (local?.type === 'active') {
83
83
  return local.sort;
84
84
  }
85
+
85
86
  return this._view?.query.sort?.[0];
86
87
  }
87
88
 
@@ -2,7 +2,7 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { Ref, ObjectId, S, TypedObject, Expando } from '@dxos/echo-schema';
5
+ import { EchoObject, Expando, LabelAnnotationId, ObjectId, Ref, S } from '@dxos/echo-schema';
6
6
  // import { ThreadType } from '@dxos/plugin-space/types';
7
7
  import { ViewType } from '@dxos/schema';
8
8
 
@@ -12,11 +12,9 @@ export const TableSchema = S.Struct({
12
12
  view: S.optional(Ref(ViewType)),
13
13
  // TODO(burdon): Should not import from plugin. Either factor out type or use reverse deps when supported.
14
14
  threads: S.optional(S.Array(Ref(Expando /* ThreadType */))), // TODO(dmaretskyi): Breaks edge because plugin-space depends on react-client.
15
+ }).annotations({
16
+ [LabelAnnotationId]: 'name',
15
17
  });
16
18
 
17
- // type TableType = S.Schema.Type<typeof TableSchema>;
18
-
19
- export class TableType extends TypedObject({
20
- typename: 'dxos.org/type/Table',
21
- version: '0.1.0',
22
- })(TableSchema.fields) {}
19
+ export const TableType = TableSchema.pipe(EchoObject('dxos.org/type/Table', '0.1.0'));
20
+ export type TableType = S.Schema.Type<typeof TableType>;
@@ -0,0 +1,71 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { type SortDirectionType } from '@dxos/echo-schema';
6
+ import { create, makeRef } from '@dxos/live-object';
7
+ import {
8
+ createView,
9
+ echoSchemaFromPropertyDefinitions,
10
+ ViewProjection,
11
+ type SchemaPropertyDefinition,
12
+ } from '@dxos/schema';
13
+
14
+ import { TableType } from '..';
15
+
16
+ type PropertyDisplayProps = {
17
+ size: number;
18
+ title: string;
19
+ sort: SortDirectionType;
20
+ };
21
+
22
+ export type TablePropertyDefinition = SchemaPropertyDefinition & Partial<PropertyDisplayProps>;
23
+
24
+ export const makeDynamicTable = (typename: string, properties: TablePropertyDefinition[]) => {
25
+ const table = create(TableType, { name: 'dynamic-table' });
26
+ const echoSchema = echoSchemaFromPropertyDefinitions(typename, properties);
27
+ const propertyNames = properties.map((property) => property.name);
28
+
29
+ const view = createView({
30
+ name: 'dynamic-table',
31
+ typename: echoSchema.typename,
32
+ jsonSchema: echoSchema.jsonSchema,
33
+ fields: propertyNames,
34
+ });
35
+
36
+ table.view = makeRef(view);
37
+ const viewProjection = new ViewProjection(echoSchema, view);
38
+
39
+ for (const property of properties) {
40
+ if (!view.fields) {
41
+ continue;
42
+ }
43
+
44
+ const field = view.fields.find((field) => field.path === property.name);
45
+ if (field) {
46
+ if (property.size !== undefined) {
47
+ field.size = property.size;
48
+ }
49
+
50
+ if (property.title !== undefined) {
51
+ const fieldProjection = viewProjection.getFieldProjection(field.id);
52
+ viewProjection.setFieldProjection({
53
+ ...fieldProjection,
54
+ props: { ...fieldProjection.props, title: property.title },
55
+ });
56
+ }
57
+
58
+ if (property.sort) {
59
+ const fieldId = field.id;
60
+ view.query.sort = [{ fieldId, direction: property.sort }];
61
+ }
62
+ }
63
+ }
64
+
65
+ return {
66
+ table,
67
+ schema: echoSchema,
68
+ view,
69
+ viewProjection,
70
+ };
71
+ };
package/src/util/index.ts CHANGED
@@ -2,6 +2,7 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
+ export * from './dynamic-table';
5
6
  export * from './signals';
6
7
  export * from './table';
7
8
  export * from './table-buttons';