@dxos/react-ui-table 0.8.4-main.c1de068 → 0.8.4-main.f5c0578

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 (90) hide show
  1. package/dist/lib/browser/{chunk-5XLSHLOG.mjs → chunk-ZAOSIG3L.mjs} +382 -319
  2. package/dist/lib/browser/chunk-ZAOSIG3L.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +404 -381
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/testing/index.mjs +4 -2
  7. package/dist/lib/browser/testing/index.mjs.map +3 -3
  8. package/dist/lib/node-esm/{chunk-Y66YLSTC.mjs → chunk-ZOFFI3JJ.mjs} +382 -319
  9. package/dist/lib/node-esm/chunk-ZOFFI3JJ.mjs.map +7 -0
  10. package/dist/lib/node-esm/index.mjs +404 -381
  11. package/dist/lib/node-esm/index.mjs.map +4 -4
  12. package/dist/lib/node-esm/meta.json +1 -1
  13. package/dist/lib/node-esm/testing/index.mjs +4 -2
  14. package/dist/lib/node-esm/testing/index.mjs.map +3 -3
  15. package/dist/types/src/components/Table/ColumnActionsMenu.d.ts +1 -1
  16. package/dist/types/src/components/Table/ColumnActionsMenu.d.ts.map +1 -1
  17. package/dist/types/src/components/Table/ColumnSettings.d.ts +1 -1
  18. package/dist/types/src/components/Table/ColumnSettings.d.ts.map +1 -1
  19. package/dist/types/src/components/Table/CreateRefPanel.d.ts +1 -1
  20. package/dist/types/src/components/Table/CreateRefPanel.d.ts.map +1 -1
  21. package/dist/types/src/components/Table/DynamicTable.d.ts.map +1 -1
  22. package/dist/types/src/components/Table/DynamicTable.stories.d.ts +1 -1
  23. package/dist/types/src/components/Table/DynamicTable.stories.d.ts.map +1 -1
  24. package/dist/types/src/components/Table/{relations.stories.d.ts → Relations.stories.d.ts} +2 -2
  25. package/dist/types/src/components/Table/Relations.stories.d.ts.map +1 -0
  26. package/dist/types/src/components/Table/RowActionsMenu.d.ts +1 -1
  27. package/dist/types/src/components/Table/RowActionsMenu.d.ts.map +1 -1
  28. package/dist/types/src/components/Table/Table.d.ts +1 -0
  29. package/dist/types/src/components/Table/Table.d.ts.map +1 -1
  30. package/dist/types/src/components/Table/Table.stories.d.ts +1 -1
  31. package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
  32. package/dist/types/src/components/TableCellEditor/CellValidationMessage.d.ts.map +1 -1
  33. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +5 -5
  34. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
  35. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -1
  36. package/dist/types/src/components/TableCellEditor/extension.d.ts.map +1 -1
  37. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts.map +1 -1
  38. package/dist/types/src/hooks/useTableModel.d.ts +1 -1
  39. package/dist/types/src/hooks/useTableModel.d.ts.map +1 -1
  40. package/dist/types/src/model/modal-controller.d.ts.map +1 -1
  41. package/dist/types/src/model/selection-model.d.ts.map +1 -1
  42. package/dist/types/src/model/table-model.d.ts +3 -2
  43. package/dist/types/src/model/table-model.d.ts.map +1 -1
  44. package/dist/types/src/model/table-presentation.d.ts +2 -1
  45. package/dist/types/src/model/table-presentation.d.ts.map +1 -1
  46. package/dist/types/src/model/table-sorting.d.ts +2 -2
  47. package/dist/types/src/model/table-sorting.d.ts.map +1 -1
  48. package/dist/types/src/testing/useTestTableModel.d.ts.map +1 -1
  49. package/dist/types/src/translations.d.ts +2 -2
  50. package/dist/types/src/util/dynamic-table.d.ts.map +1 -1
  51. package/dist/types/src/util/table-buttons.d.ts.map +1 -1
  52. package/dist/types/src/util/table-controls.d.ts.map +1 -1
  53. package/dist/types/src/util/table.d.ts +2 -1
  54. package/dist/types/src/util/table.d.ts.map +1 -1
  55. package/dist/types/tsconfig.tsbuildinfo +1 -1
  56. package/package.json +42 -38
  57. package/src/components/Table/ColumnActionsMenu.tsx +1 -1
  58. package/src/components/Table/ColumnSettings.tsx +1 -1
  59. package/src/components/Table/CreateRefPanel.tsx +1 -1
  60. package/src/components/Table/DynamicTable.stories.tsx +3 -2
  61. package/src/components/Table/DynamicTable.tsx +4 -3
  62. package/src/components/Table/{relations.stories.tsx → Relations.stories.tsx} +12 -4
  63. package/src/components/Table/RowActionsMenu.tsx +3 -3
  64. package/src/components/Table/Table.stories.tsx +12 -7
  65. package/src/components/Table/Table.tsx +56 -45
  66. package/src/components/TableCellEditor/CellValidationMessage.tsx +1 -1
  67. package/src/components/TableCellEditor/TableCellEditor.stories.tsx +4 -3
  68. package/src/components/TableCellEditor/TableCellEditor.tsx +16 -20
  69. package/src/components/TableCellEditor/extension.ts +2 -2
  70. package/src/components/TableToolbar/TableToolbar.tsx +2 -2
  71. package/src/components/testing.ts +1 -1
  72. package/src/hooks/useTableModel.ts +1 -1
  73. package/src/model/modal-controller.ts +1 -1
  74. package/src/model/selection-model.ts +3 -2
  75. package/src/model/table-model.test.ts +2 -1
  76. package/src/model/table-model.ts +13 -10
  77. package/src/model/table-presentation.test.ts +3 -2
  78. package/src/model/table-presentation.ts +28 -6
  79. package/src/model/table-sorting.ts +3 -3
  80. package/src/playwright/smoke.spec.ts +92 -0
  81. package/src/testing/useTestTableModel.ts +3 -2
  82. package/src/translations.ts +2 -2
  83. package/src/util/dynamic-table.ts +2 -2
  84. package/src/util/schema.ts +1 -1
  85. package/src/util/table-buttons.ts +2 -1
  86. package/src/util/table-controls.ts +4 -1
  87. package/src/util/table.ts +7 -3
  88. package/dist/lib/browser/chunk-5XLSHLOG.mjs.map +0 -7
  89. package/dist/lib/node-esm/chunk-Y66YLSTC.mjs.map +0 -7
  90. package/dist/types/src/components/Table/relations.stories.d.ts.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/react-ui-table",
3
- "version": "0.8.4-main.c1de068",
3
+ "version": "0.8.4-main.f5c0578",
4
4
  "description": "A table component.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -10,21 +10,25 @@
10
10
  "type": "module",
11
11
  "exports": {
12
12
  "./deprecated": {
13
+ "source": "./src/deprecated/index.ts",
13
14
  "types": "./dist/types/src/deprecated/index.d.ts",
14
15
  "browser": "./dist/lib/browser/deprecated/index.mjs",
15
16
  "node": "./dist/lib/node-esm/deprecated/index.mjs"
16
17
  },
17
18
  ".": {
19
+ "source": "./src/index.ts",
18
20
  "types": "./dist/types/src/index.d.ts",
19
21
  "browser": "./dist/lib/browser/index.mjs",
20
22
  "node": "./dist/lib/node-esm/index.mjs"
21
23
  },
22
24
  "./testing": {
25
+ "source": "./src/testing/index.ts",
23
26
  "types": "./dist/types/src/testing/index.d.ts",
24
27
  "browser": "./dist/lib/browser/testing/index.mjs",
25
28
  "node": "./dist/lib/node-esm/testing/index.mjs"
26
29
  },
27
30
  "./types": {
31
+ "source": "./src/types/index.ts",
28
32
  "types": "./dist/types/src/types/index.d.ts",
29
33
  "browser": "./dist/lib/browser/types/index.mjs",
30
34
  "node": "./dist/lib/node-esm/types/index.mjs"
@@ -61,51 +65,51 @@
61
65
  "@radix-ui/react-use-controllable-state": "1.1.0",
62
66
  "date-fns": "^3.3.1",
63
67
  "lodash.orderby": "^4.6.0",
64
- "@dxos/context": "0.8.4-main.c1de068",
65
- "@dxos/debug": "0.8.4-main.c1de068",
66
- "@dxos/echo": "0.8.4-main.c1de068",
67
- "@dxos/effect": "0.8.4-main.c1de068",
68
- "@dxos/echo-schema": "0.8.4-main.c1de068",
69
- "@dxos/echo-db": "0.8.4-main.c1de068",
70
- "@dxos/invariant": "0.8.4-main.c1de068",
71
- "@dxos/lit-grid": "0.8.4-main.c1de068",
72
- "@dxos/keys": "0.8.4-main.c1de068",
73
- "@dxos/live-object": "0.8.4-main.c1de068",
74
- "@dxos/plugin-search": "0.8.4-main.c1de068",
75
- "@dxos/log": "0.8.4-main.c1de068",
76
- "@dxos/react-client": "0.8.4-main.c1de068",
77
- "@dxos/react-ui-attention": "0.8.4-main.c1de068",
78
- "@dxos/random": "0.8.4-main.c1de068",
79
- "@dxos/react-ui-form": "0.8.4-main.c1de068",
80
- "@dxos/react-ui-grid": "0.8.4-main.c1de068",
81
- "@dxos/react-ui-editor": "0.8.4-main.c1de068",
82
- "@dxos/react-ui-menu": "0.8.4-main.c1de068",
83
- "@dxos/react-ui-searchlist": "0.8.4-main.c1de068",
84
- "@dxos/react-ui-stack": "0.8.4-main.c1de068",
85
- "@dxos/react-ui-syntax-highlighter": "0.8.4-main.c1de068",
86
- "@dxos/react-ui-tag-picker": "0.8.4-main.c1de068",
87
- "@dxos/react-ui-types": "0.8.4-main.c1de068",
88
- "@dxos/schema": "0.8.4-main.c1de068",
89
- "@dxos/util": "0.8.4-main.c1de068"
68
+ "@dxos/debug": "0.8.4-main.f5c0578",
69
+ "@dxos/context": "0.8.4-main.f5c0578",
70
+ "@dxos/echo": "0.8.4-main.f5c0578",
71
+ "@dxos/echo-db": "0.8.4-main.f5c0578",
72
+ "@dxos/echo-schema": "0.8.4-main.f5c0578",
73
+ "@dxos/effect": "0.8.4-main.f5c0578",
74
+ "@dxos/invariant": "0.8.4-main.f5c0578",
75
+ "@dxos/keys": "0.8.4-main.f5c0578",
76
+ "@dxos/lit-grid": "0.8.4-main.f5c0578",
77
+ "@dxos/live-object": "0.8.4-main.f5c0578",
78
+ "@dxos/log": "0.8.4-main.f5c0578",
79
+ "@dxos/plugin-search": "0.8.4-main.f5c0578",
80
+ "@dxos/random": "0.8.4-main.f5c0578",
81
+ "@dxos/react-client": "0.8.4-main.f5c0578",
82
+ "@dxos/react-ui-editor": "0.8.4-main.f5c0578",
83
+ "@dxos/react-ui-attention": "0.8.4-main.f5c0578",
84
+ "@dxos/react-ui-form": "0.8.4-main.f5c0578",
85
+ "@dxos/react-ui-grid": "0.8.4-main.f5c0578",
86
+ "@dxos/react-ui-menu": "0.8.4-main.f5c0578",
87
+ "@dxos/react-ui-searchlist": "0.8.4-main.f5c0578",
88
+ "@dxos/react-ui-tag-picker": "0.8.4-main.f5c0578",
89
+ "@dxos/react-ui-types": "0.8.4-main.f5c0578",
90
+ "@dxos/react-ui-stack": "0.8.4-main.f5c0578",
91
+ "@dxos/schema": "0.8.4-main.f5c0578",
92
+ "@dxos/react-ui-syntax-highlighter": "0.8.4-main.f5c0578",
93
+ "@dxos/util": "0.8.4-main.f5c0578"
90
94
  },
91
95
  "devDependencies": {
92
96
  "@effect-rx/rx-react": "0.38.0",
93
- "@effect/platform": "0.89.0",
97
+ "@effect/platform": "0.90.2",
94
98
  "@types/lodash.orderby": "^4.6.9",
95
99
  "@types/react": "~18.2.0",
96
100
  "@types/react-dom": "~18.2.0",
97
- "effect": "3.17.0",
101
+ "effect": "3.17.7",
98
102
  "fast-check": "^3.19.0",
99
103
  "react": "~18.2.0",
100
104
  "react-dom": "~18.2.0",
101
105
  "vite": "5.4.7",
102
- "@dxos/echo-signals": "0.8.4-main.c1de068",
103
- "@dxos/plugin-search": "0.8.4-main.c1de068",
104
- "@dxos/random": "0.8.4-main.c1de068",
105
- "@dxos/react-ui": "0.8.4-main.c1de068",
106
- "@dxos/react-ui-theme": "0.8.4-main.c1de068",
107
- "@dxos/storybook-utils": "0.8.4-main.c1de068",
108
- "@dxos/test-utils": "0.8.4-main.c1de068"
106
+ "@dxos/plugin-search": "0.8.4-main.f5c0578",
107
+ "@dxos/random": "0.8.4-main.f5c0578",
108
+ "@dxos/react-ui": "0.8.4-main.f5c0578",
109
+ "@dxos/echo-signals": "0.8.4-main.f5c0578",
110
+ "@dxos/react-ui-theme": "0.8.4-main.f5c0578",
111
+ "@dxos/test-utils": "0.8.4-main.f5c0578",
112
+ "@dxos/storybook-utils": "0.8.4-main.f5c0578"
109
113
  },
110
114
  "peerDependencies": {
111
115
  "@effect-rx/rx-react": "^0.34.1",
@@ -113,8 +117,8 @@
113
117
  "effect": "^3.13.3",
114
118
  "react": "~18.2.0",
115
119
  "react-dom": "~18.2.0",
116
- "@dxos/react-ui": "0.8.4-main.c1de068",
117
- "@dxos/react-ui-theme": "0.8.4-main.c1de068"
120
+ "@dxos/react-ui": "0.8.4-main.f5c0578",
121
+ "@dxos/react-ui-theme": "0.8.4-main.f5c0578"
118
122
  },
119
123
  "publishConfig": {
120
124
  "access": "public"
@@ -6,7 +6,7 @@ import React from 'react';
6
6
 
7
7
  import { DropdownMenu, useTranslation } from '@dxos/react-ui';
8
8
 
9
- import { type TableModel, type ModalController } from '../../model';
9
+ import { type ModalController, type TableModel } from '../../model';
10
10
  import { translationKey } from '../../translations';
11
11
 
12
12
  type ColumnActionsMenuProps = { model: TableModel; modals: ModalController };
@@ -10,7 +10,7 @@ import { Popover } from '@dxos/react-ui';
10
10
  import { FieldEditor } from '@dxos/react-ui-form';
11
11
  import { type FieldType } from '@dxos/schema';
12
12
 
13
- import { type TableModel, type ModalController } from '../../model';
13
+ import { type ModalController, type TableModel } from '../../model';
14
14
 
15
15
  type ColumnSettingsProps = {
16
16
  registry?: SchemaRegistry;
@@ -12,7 +12,7 @@ import { Popover } from '@dxos/react-ui';
12
12
  import { Form } from '@dxos/react-ui-form';
13
13
  import { type GridScopedProps, useGridContext } from '@dxos/react-ui-grid';
14
14
 
15
- import { type TableModel, type ModalController } from '../../model';
15
+ import { type ModalController, type TableModel } from '../../model';
16
16
 
17
17
  export type CreateRefPanelProps = { model?: TableModel; modals: ModalController };
18
18
 
@@ -4,7 +4,7 @@
4
4
 
5
5
  import '@dxos-theme';
6
6
 
7
- import { type StoryObj, type Meta } from '@storybook/react-vite';
7
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
8
8
  import React, { useMemo, useState } from 'react';
9
9
 
10
10
  import { Obj } from '@dxos/echo';
@@ -17,10 +17,11 @@ import { type SchemaPropertyDefinition } from '@dxos/schema';
17
17
  import { Testing } from '@dxos/schema/testing';
18
18
  import { withLayout, withTheme } from '@dxos/storybook-utils';
19
19
 
20
- import { DynamicTable } from './DynamicTable';
21
20
  import { type TableFeatures } from '../../model';
22
21
  import { translations } from '../../translations';
23
22
 
23
+ import { DynamicTable } from './DynamicTable';
24
+
24
25
  faker.seed(0);
25
26
 
26
27
  const useTestPropertiesAndObjects = () => {
@@ -3,16 +3,17 @@
3
3
  //
4
4
 
5
5
  import { type Schema } from 'effect';
6
- import React, { useRef, useMemo, useCallback } from 'react';
6
+ import React, { useCallback, useMemo, useRef } from 'react';
7
7
 
8
8
  import { type JsonSchemaType } from '@dxos/echo-schema';
9
9
  import { type ThemedClassName, useDefaultValue } from '@dxos/react-ui';
10
10
  import { mx } from '@dxos/react-ui-theme';
11
11
 
12
- import { Table, type TableController } from './Table';
13
12
  import { useTableModel } from '../../hooks';
14
13
  import { type TableFeatures, TablePresentation, type TableRowAction } from '../../model';
15
- import { getBaseSchema, makeDynamicTable, type TablePropertyDefinition } from '../../util';
14
+ import { type TablePropertyDefinition, getBaseSchema, makeDynamicTable } from '../../util';
15
+
16
+ import { Table, type TableController } from './Table';
16
17
 
17
18
  type DynamicTableProps = ThemedClassName<{
18
19
  name?: string; // TODO(burdon): Remove?
@@ -4,7 +4,7 @@
4
4
 
5
5
  import '@dxos-theme';
6
6
 
7
- import { type StoryObj, type Meta } from '@storybook/react-vite';
7
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
8
8
  import React, { useEffect, useMemo, useState } from 'react';
9
9
 
10
10
  import { Type } from '@dxos/echo';
@@ -13,16 +13,17 @@ import { faker } from '@dxos/random';
13
13
  import { useClient } from '@dxos/react-client';
14
14
  import { useClientProvider, withClientProvider } from '@dxos/react-client/testing';
15
15
  import { DataType } from '@dxos/schema';
16
- import { createAsyncGenerator, type ValueGenerator } from '@dxos/schema/testing';
16
+ import { type ValueGenerator, createAsyncGenerator } from '@dxos/schema/testing';
17
17
  import { withLayout, withTheme } from '@dxos/storybook-utils';
18
18
 
19
- import { Table } from './Table';
20
19
  import { useTableModel } from '../../hooks';
21
20
  import { type TableFeatures, TablePresentation, type TableRow } from '../../model';
22
21
  import { translations } from '../../translations';
23
22
  import { TableView } from '../../types';
24
23
  import { createTable } from '../../util';
25
24
 
25
+ import { Table } from './Table';
26
+
26
27
  faker.seed(1);
27
28
  const generator: ValueGenerator = faker as any;
28
29
 
@@ -47,14 +48,21 @@ const useTestModel = <S extends Type.Obj.Any>(schema: S, count: number) => {
47
48
  }
48
49
 
49
50
  const timeout = setTimeout(async () => {
50
- const { jsonSchema, view } = await createTable({ client, space, typename: Type.getTypename(schema) });
51
+ const {
52
+ jsonSchema,
53
+ schema: effectSchema,
54
+ view,
55
+ } = await createTable({ client, space, typename: Type.getTypename(schema) });
51
56
  setJsonSchema(jsonSchema);
52
57
  setView(view);
58
+ space.db.add(view);
59
+ await space.db.schemaRegistry.register([effectSchema]);
53
60
  });
54
61
  return () => clearTimeout(timeout);
55
62
  }, [client, space, schema]);
56
63
 
57
64
  const model = useTableModel<TableRow>({ view, schema: jsonSchema, rows: [], features });
65
+
58
66
  useEffect(() => {
59
67
  if (!model || !space) {
60
68
  return;
@@ -4,9 +4,9 @@
4
4
 
5
5
  import React from 'react';
6
6
 
7
- import { DropdownMenu, useTranslation } from '@dxos/react-ui';
7
+ import { DropdownMenu, toLocalizedString, useTranslation } from '@dxos/react-ui';
8
8
 
9
- import { type TableModel, type ModalController } from '../../model';
9
+ import { type ModalController, type TableModel } from '../../model';
10
10
  import { translationKey } from '../../translations';
11
11
 
12
12
  type RowActionsMenuProps = { model: TableModel; modals: ModalController };
@@ -38,7 +38,7 @@ export const RowActionsMenu = ({ model, modals }: RowActionsMenuProps) => {
38
38
  model.handleRowAction(action.id, state.rowIndex);
39
39
  }}
40
40
  >
41
- {t(action.translationKey)}
41
+ {toLocalizedString(action.label, t)}
42
42
  </DropdownMenu.Item>
43
43
  ))}
44
44
  </DropdownMenu.Viewport>
@@ -4,36 +4,38 @@
4
4
 
5
5
  import '@dxos-theme';
6
6
 
7
- import { type StoryObj, type Meta } from '@storybook/react-vite';
7
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
8
8
  import { Schema } from 'effect';
9
9
  import React, { useCallback } from 'react';
10
10
 
11
11
  import { Obj, Type } from '@dxos/echo';
12
12
  import {
13
- FormatEnum,
14
13
  EchoObject,
15
- GeneratorAnnotation,
16
14
  FormatAnnotation,
15
+ FormatEnum,
16
+ GeneratorAnnotation,
17
+ LabelAnnotation,
17
18
  PropertyMetaAnnotationId,
18
19
  } from '@dxos/echo-schema';
19
20
  import { invariant } from '@dxos/invariant';
20
21
  import { faker } from '@dxos/random';
21
22
  import { PublicKey } from '@dxos/react-client';
22
- import { live, type Space } from '@dxos/react-client/echo';
23
+ import { type Space, live } from '@dxos/react-client/echo';
23
24
  import { withClientProvider } from '@dxos/react-client/testing';
24
25
  import { ViewEditor } from '@dxos/react-ui-form';
25
26
  import { SyntaxHighlighter } from '@dxos/react-ui-syntax-highlighter';
26
- import { getSchemaFromPropertyDefinitions, DataType } from '@dxos/schema';
27
+ import { DataType, getSchemaFromPropertyDefinitions } from '@dxos/schema';
27
28
  import { Testing, createObjectFactory } from '@dxos/schema/testing';
28
29
  import { withLayout, withTheme } from '@dxos/storybook-utils';
29
30
 
30
- import { Table } from './Table';
31
31
  import { useTestTableModel } from '../../testing';
32
32
  import { translations } from '../../translations';
33
33
  import { TableView } from '../../types';
34
34
  import { createTable } from '../../util';
35
35
  import { TableToolbar } from '../TableToolbar';
36
36
 
37
+ import { Table } from './Table';
38
+
37
39
  const TestSchema = Schema.Struct({
38
40
  // TODO(wittjosiah): Should be title. Currently name to work with default label.
39
41
  name: Schema.optional(Schema.String).annotations({ title: 'Title' }),
@@ -58,7 +60,10 @@ const TestSchema = Schema.Struct({
58
60
  parent: Schema.optional(Schema.suspend((): Type.Ref<TestSchema> => Type.Ref(TestSchema))).annotations({
59
61
  title: 'Parent',
60
62
  }),
61
- }).pipe(Type.Obj({ typename: `example.com/type/${PublicKey.random().truncate()}`, version: '0.1.0' }));
63
+ }).pipe(
64
+ Type.Obj({ typename: `example.com/type/${PublicKey.random().truncate()}`, version: '0.1.0' }),
65
+ LabelAnnotation.set(['name']),
66
+ );
62
67
  interface TestSchema extends Schema.Schema.Type<typeof TestSchema> {}
63
68
 
64
69
  const StoryViewEditor = ({
@@ -9,10 +9,10 @@ import React, {
9
9
  type WheelEvent,
10
10
  forwardRef,
11
11
  useCallback,
12
+ useEffect,
12
13
  useImperativeHandle,
13
- useState,
14
14
  useMemo,
15
- useEffect,
15
+ useState,
16
16
  } from 'react';
17
17
 
18
18
  import { type Client } from '@dxos/client';
@@ -24,27 +24,28 @@ import { getSpace } from '@dxos/react-client/echo';
24
24
  import { useTranslation } from '@dxos/react-ui';
25
25
  import { useAttention } from '@dxos/react-ui-attention';
26
26
  import {
27
- closestCell,
28
27
  type DxGridElement,
29
- type DxGridPosition,
30
- type GridContentProps,
31
- Grid,
32
28
  type DxGridPlane,
33
29
  type DxGridPlaneRange,
34
- gridSeparatorInlineEnd,
30
+ type DxGridPosition,
31
+ Grid,
32
+ type GridContentProps,
33
+ closestCell,
35
34
  gridSeparatorBlockEnd,
35
+ gridSeparatorInlineEnd,
36
36
  } from '@dxos/react-ui-grid';
37
37
  import { mx } from '@dxos/react-ui-theme';
38
38
  import { isNotFalsy, safeParseInt } from '@dxos/util';
39
39
 
40
+ import { ModalController, type TableModel, type TablePresentation } from '../../model';
41
+ import { translationKey } from '../../translations';
42
+ import { tableButtons, tableControls } from '../../util';
43
+ import { type TableCellEditorProps, TableValueEditor, createOption } from '../TableCellEditor';
44
+
40
45
  import { ColumnActionsMenu } from './ColumnActionsMenu';
41
46
  import { ColumnSettings } from './ColumnSettings';
42
47
  import { CreateRefPanel } from './CreateRefPanel';
43
48
  import { RowActionsMenu } from './RowActionsMenu';
44
- import { ModalController, type TableModel, type TablePresentation } from '../../model';
45
- import { translationKey } from '../../translations';
46
- import { tableButtons, tableControls } from '../../util';
47
- import { createOption, TableValueEditor, type TableCellEditorProps } from '../TableCellEditor';
48
49
 
49
50
  //
50
51
  // Table.Root
@@ -76,6 +77,7 @@ const TableRoot = ({ children, role = 'article' }: TableRootProps) => {
76
77
 
77
78
  export type TableController = {
78
79
  update?: (cell?: DxGridPosition) => void;
80
+ focusDraft?: () => void;
79
81
  };
80
82
 
81
83
  export type TableMainProps = {
@@ -140,9 +142,29 @@ const TableMain = forwardRef<TableController, TableMainProps>(
140
142
  dxGrid.requestUpdate();
141
143
  }
142
144
  },
145
+ focusDraft: () => {
146
+ requestAnimationFrame(() => {
147
+ dxGrid.setFocus({ plane: 'frozenRowsEnd', col: 0, row: 0 });
148
+ dxGrid.refocus();
149
+ });
150
+ },
143
151
  };
144
152
  }, [presentation, dxGrid]);
145
153
 
154
+ const handleSaveDraftRow = useCallback(
155
+ (rowIndex = 0) => {
156
+ if (model && dxGrid) {
157
+ const didCommitSuccessfully = model.commitDraftRow(rowIndex);
158
+ if (didCommitSuccessfully) {
159
+ requestAnimationFrame(() => {
160
+ dxGrid.scrollToEndRow();
161
+ });
162
+ }
163
+ }
164
+ },
165
+ [model, dxGrid],
166
+ );
167
+
146
168
  const handleGridClick = useCallback(
147
169
  (event: MouseEvent) => {
148
170
  const rowIndex = safeParseInt((event.target as HTMLElement).closest('[aria-rowindex]')?.ariaRowIndex ?? '');
@@ -192,14 +214,7 @@ const TableMain = forwardRef<TableController, TableMainProps>(
192
214
  break;
193
215
  }
194
216
  case 'saveDraftRow': {
195
- if (model) {
196
- const didCommitSuccessfully = model.commitDraftRow(data.rowIndex);
197
- if (dxGrid && didCommitSuccessfully) {
198
- requestAnimationFrame(() => {
199
- dxGrid.scrollToEndRow();
200
- });
201
- }
202
- }
217
+ handleSaveDraftRow();
203
218
  break;
204
219
  }
205
220
  }
@@ -240,32 +255,23 @@ const TableMain = forwardRef<TableController, TableMainProps>(
240
255
  );
241
256
 
242
257
  const handleFocus = useCallback<NonNullable<TableCellEditorProps['onFocus']>>(
243
- (increment, delta) => {
244
- if (dxGrid) {
245
- dxGrid.refocus(increment, delta);
246
- }
247
- },
248
- [dxGrid],
249
- );
250
-
251
- const handleEnter = useCallback<NonNullable<TableCellEditorProps['onEnter']>>(
252
- (cell) => {
253
- if (!model?.features.dataEditable) {
254
- return;
255
- }
256
-
257
- // TODO(burdon): Insert row only if bottom row isn't completely blank already.
258
- if (model && cell.row === model.getRowCount() - 1) {
259
- model.insertRow();
260
- if (dxGrid) {
261
- requestAnimationFrame(() => {
262
- dxGrid?.scrollToRow(cell.row + 1);
263
- dxGrid?.refocus('row', 1);
264
- });
258
+ (increment, delta, cell) => {
259
+ if (dxGrid && model) {
260
+ if (cell?.plane === 'grid' && cell?.row >= model.getRowCount() - 1) {
261
+ if (draftRowCount < 1) {
262
+ model.insertRow();
263
+ }
264
+ dxGrid.setFocus({ plane: 'frozenRowsEnd', col: 0, row: 0 });
265
+ } else if (cell?.plane === 'frozenRowsEnd' && increment === 'row') {
266
+ handleSaveDraftRow(cell.row);
267
+ model.insertRow();
268
+ dxGrid.setFocus({ plane: 'frozenRowsEnd', col: 0, row: 0 });
269
+ } else {
270
+ dxGrid.refocus(increment, delta);
265
271
  }
266
272
  }
267
273
  },
268
- [model, dxGrid],
274
+ [dxGrid, model],
269
275
  );
270
276
 
271
277
  const handleKeyDown = useCallback<NonNullable<GridContentProps['onKeyDown']>>(
@@ -282,7 +288,12 @@ const TableMain = forwardRef<TableController, TableMainProps>(
282
288
  switch (event.key) {
283
289
  case 'Backspace':
284
290
  case 'Delete': {
285
- model.setCellData(cell, undefined);
291
+ try {
292
+ model.setCellData(cell, undefined);
293
+ event.preventDefault();
294
+ } catch {
295
+ // Delete results in a validation error; don’t prevent default so dx-grid can emit an edit request.
296
+ }
286
297
  break;
287
298
  }
288
299
  }
@@ -365,6 +376,7 @@ const TableMain = forwardRef<TableController, TableMainProps>(
365
376
 
366
377
  const handleSave = useCallback(() => {
367
378
  dxGrid?.updateCells(true);
379
+ dxGrid?.requestUpdate();
368
380
  }, [dxGrid]);
369
381
 
370
382
  if (!model || !modals) {
@@ -377,7 +389,6 @@ const TableMain = forwardRef<TableController, TableMainProps>(
377
389
  model={model}
378
390
  modals={modals}
379
391
  schema={schema}
380
- onEnter={handleEnter}
381
392
  onFocus={handleFocus}
382
393
  onQuery={handleQuery}
383
394
  onSave={handleSave}
@@ -391,7 +402,7 @@ const TableMain = forwardRef<TableController, TableMainProps>(
391
402
  overscroll='trap'
392
403
  onAxisResize={handleAxisResize}
393
404
  onClick={handleGridClick}
394
- onKeyDown={handleKeyDown}
405
+ onKeyDownCapture={handleKeyDown}
395
406
  onWheelCapture={handleWheel}
396
407
  ref={setDxGrid}
397
408
  />
@@ -4,7 +4,7 @@
4
4
 
5
5
  import React from 'react';
6
6
 
7
- import { useGridContext, type GridScopedProps } from '@dxos/react-ui-grid';
7
+ import { type GridScopedProps, useGridContext } from '@dxos/react-ui-grid';
8
8
 
9
9
  export type CellValidationMessageProps = {
10
10
  validationError: string | null;
@@ -13,17 +13,18 @@ import { invariant } from '@dxos/invariant';
13
13
  import { faker } from '@dxos/random';
14
14
  import { Filter, useQuery } from '@dxos/react-client/echo';
15
15
  import { useClientProvider, withClientProvider } from '@dxos/react-client/testing';
16
- import { defaultRowSize, Grid, type GridEditing } from '@dxos/react-ui-grid';
17
- import { createDefaultSchema, DataType } from '@dxos/schema';
16
+ import { Grid, type GridEditing, defaultRowSize } from '@dxos/react-ui-grid';
17
+ import { DataType, createDefaultSchema } from '@dxos/schema';
18
18
  import { withLayout, withTheme } from '@dxos/storybook-utils';
19
19
 
20
- import { TableCellEditor, type TableCellEditorProps } from './TableCellEditor';
21
20
  import { useTableModel } from '../../hooks';
22
21
  import { type TableFeatures } from '../../model';
23
22
  import { translations } from '../../translations';
24
23
  import { TableView } from '../../types';
25
24
  import { createTable } from '../../util';
26
25
 
26
+ import { TableCellEditor, type TableCellEditorProps } from './TableCellEditor';
27
+
27
28
  type StoryProps = {
28
29
  editing: GridEditing;
29
30
  };
@@ -8,29 +8,29 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
8
8
 
9
9
  import { FormatEnum, TypeEnum } from '@dxos/echo-schema';
10
10
  import { invariant } from '@dxos/invariant';
11
- import { type DxGrid } from '@dxos/lit-grid';
11
+ import { type DxGridAxis, type DxGridPosition } from '@dxos/lit-grid';
12
12
  import { useThemeContext } from '@dxos/react-ui';
13
13
  import { createMarkdownExtensions } from '@dxos/react-ui-editor';
14
14
  import {
15
- cellQuery,
16
- editorKeys,
17
- parseCellIndex,
18
- useGridContext,
19
- type DxGridPlanePosition,
15
+ type EditorBlurHandler,
20
16
  type EditorKeyEvent,
21
17
  type EditorKeyOrBlurHandler,
22
- type EditorBlurHandler,
23
18
  GridCellEditor,
24
19
  type GridCellEditorProps,
25
20
  type GridScopedProps,
21
+ cellQuery,
22
+ editorKeys,
23
+ parseCellIndex,
24
+ useGridContext,
26
25
  } from '@dxos/react-ui-grid';
27
- import { tagPicker, createLinks } from '@dxos/react-ui-tag-picker';
26
+ import { createLinks, tagPicker } from '@dxos/react-ui-tag-picker';
28
27
  import { type FieldProjection } from '@dxos/schema';
29
28
 
29
+ import { type ModalController, type TableModel } from '../../model';
30
+
30
31
  import { CellValidationMessage } from './CellValidationMessage';
31
- import { FormCellEditor } from './FormCellEditor';
32
32
  import { completion } from './extension';
33
- import { type TableModel, type ModalController } from '../../model';
33
+ import { FormCellEditor } from './FormCellEditor';
34
34
 
35
35
  const newValue = Symbol.for('newValue');
36
36
 
@@ -47,8 +47,8 @@ export type TableCellEditorProps = {
47
47
  model?: TableModel;
48
48
  modals?: ModalController;
49
49
  schema?: Schema.AnyNoContext;
50
- onEnter?: (cell: DxGridPlanePosition) => void;
51
- onFocus?: DxGrid['refocus'];
50
+ onEnter?: (cell: DxGridPosition) => void;
51
+ onFocus?: (axis?: DxGridAxis, delta?: -1 | 0 | 1, cell?: DxGridPosition) => void;
52
52
  onSave?: () => void;
53
53
  onQuery?: (field: FieldProjection, text: string) => Promise<QueryResult[]>;
54
54
  };
@@ -121,8 +121,8 @@ export const TableCellEditor = ({
121
121
  const { id: gridId, editing, setEditing } = useGridContext('TableCellEditor', __gridScope);
122
122
  const suppressNextBlur = useRef(false);
123
123
  const { themeMode } = useThemeContext();
124
- const [_validationError, setValidationError] = useState<string | null>(null);
125
- const [_validationVariant, setValidationVariant] = useState<'error' | 'warning'>('error');
124
+ const [validationError, setValidationError] = useState<string | null>(null);
125
+ const [validationVariant, setValidationVariant] = useState<'error' | 'warning'>('error');
126
126
 
127
127
  const fieldProjection = useMemo<FieldProjection | undefined>(() => {
128
128
  if (!model || !editing) {
@@ -225,7 +225,7 @@ export const TableCellEditor = ({
225
225
  onSave?.();
226
226
  onEnter?.(cell);
227
227
  if (event && onFocus) {
228
- onFocus(determineNavigationAxis(event), determineNavigationDelta(event));
228
+ onFocus(determineNavigationAxis(event), determineNavigationDelta(event), cell);
229
229
  }
230
230
  } else {
231
231
  setValidationError(result.error);
@@ -395,11 +395,7 @@ export const TableCellEditor = ({
395
395
 
396
396
  return (
397
397
  <>
398
- <CellValidationMessage
399
- validationError={_validationError}
400
- variant={_validationVariant}
401
- __gridScope={__gridScope}
402
- />
398
+ <CellValidationMessage validationError={validationError} variant={validationVariant} __gridScope={__gridScope} />
403
399
  <GridCellEditor extension={extension} getCellContent={getCellContent} onBlur={handleBlur} slots={editorSlots} />
404
400
  </>
405
401
  );
@@ -3,10 +3,10 @@
3
3
  //
4
4
 
5
5
  import {
6
- autocompletion,
7
- pickedCompletion,
8
6
  type CompletionContext,
9
7
  type CompletionResult,
8
+ autocompletion,
9
+ pickedCompletion,
10
10
  } from '@codemirror/autocomplete';
11
11
  import { type Extension } from '@codemirror/state';
12
12
  import { EditorView } from '@codemirror/view';