@dxos/react-ui-table 0.8.4-main.bc674ce → 0.8.4-main.bcb3aa67d6

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 (108) hide show
  1. package/dist/lib/browser/{chunk-OZBLY7XM.mjs → chunk-BF54SSNL.mjs} +12 -18
  2. package/dist/lib/browser/chunk-BF54SSNL.mjs.map +7 -0
  3. package/dist/lib/browser/{chunk-I5IFW7UF.mjs → chunk-EK6D2CVM.mjs} +37 -32
  4. package/dist/lib/browser/chunk-EK6D2CVM.mjs.map +7 -0
  5. package/dist/lib/browser/index.mjs +200 -173
  6. package/dist/lib/browser/index.mjs.map +4 -4
  7. package/dist/lib/browser/meta.json +1 -1
  8. package/dist/lib/browser/testing/index.mjs +4 -4
  9. package/dist/lib/browser/testing/index.mjs.map +2 -2
  10. package/dist/lib/browser/types/index.mjs +1 -1
  11. package/dist/lib/node-esm/{chunk-DDJKYJFY.mjs → chunk-LYYDF6JP.mjs} +37 -32
  12. package/dist/lib/node-esm/chunk-LYYDF6JP.mjs.map +7 -0
  13. package/dist/lib/node-esm/{chunk-WNZSKIRF.mjs → chunk-SIRDIPHZ.mjs} +12 -18
  14. package/dist/lib/node-esm/chunk-SIRDIPHZ.mjs.map +7 -0
  15. package/dist/lib/node-esm/index.mjs +200 -173
  16. package/dist/lib/node-esm/index.mjs.map +4 -4
  17. package/dist/lib/node-esm/meta.json +1 -1
  18. package/dist/lib/node-esm/testing/index.mjs +4 -4
  19. package/dist/lib/node-esm/testing/index.mjs.map +2 -2
  20. package/dist/lib/node-esm/types/index.mjs +1 -1
  21. package/dist/types/src/components/Table/ColumnSettings.d.ts.map +1 -1
  22. package/dist/types/src/components/Table/DynamicTable.d.ts +5 -4
  23. package/dist/types/src/components/Table/DynamicTable.d.ts.map +1 -1
  24. package/dist/types/src/components/Table/DynamicTable.stories.d.ts +20 -22
  25. package/dist/types/src/components/Table/DynamicTable.stories.d.ts.map +1 -1
  26. package/dist/types/src/components/Table/Relations.stories.d.ts +80 -82
  27. package/dist/types/src/components/Table/Relations.stories.d.ts.map +1 -1
  28. package/dist/types/src/components/Table/Table.d.ts +28 -21
  29. package/dist/types/src/components/Table/Table.d.ts.map +1 -1
  30. package/dist/types/src/components/Table/Table.stories.d.ts +82 -84
  31. package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
  32. package/dist/types/src/components/Table/TableContent.d.ts +21 -0
  33. package/dist/types/src/components/Table/TableContent.d.ts.map +1 -0
  34. package/dist/types/src/components/Table/TableToolbar.d.ts +25 -0
  35. package/dist/types/src/components/Table/TableToolbar.d.ts.map +1 -0
  36. package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts +3 -3
  37. package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts.map +1 -1
  38. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +2 -2
  39. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
  40. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts +22 -24
  41. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -1
  42. package/dist/types/src/components/index.d.ts +0 -1
  43. package/dist/types/src/components/index.d.ts.map +1 -1
  44. package/dist/types/src/hooks/useAddRow.d.ts +1 -1
  45. package/dist/types/src/hooks/useAddRow.d.ts.map +1 -1
  46. package/dist/types/src/hooks/useProjectionModel.d.ts +1 -1
  47. package/dist/types/src/hooks/useProjectionModel.d.ts.map +1 -1
  48. package/dist/types/src/hooks/useTableModel.d.ts +1 -1
  49. package/dist/types/src/model/table-model.d.ts +5 -4
  50. package/dist/types/src/model/table-model.d.ts.map +1 -1
  51. package/dist/types/src/model/table-presentation.d.ts.map +1 -1
  52. package/dist/types/src/playwright/TableManager.d.ts +2 -1
  53. package/dist/types/src/playwright/TableManager.d.ts.map +1 -1
  54. package/dist/types/src/testing/useTestTableModel.d.ts +2 -2
  55. package/dist/types/src/testing/useTestTableModel.d.ts.map +1 -1
  56. package/dist/types/src/translations.d.ts +19 -21
  57. package/dist/types/src/translations.d.ts.map +1 -1
  58. package/dist/types/src/types/Table.d.ts +1 -6
  59. package/dist/types/src/types/Table.d.ts.map +1 -1
  60. package/dist/types/src/util/dynamic-table.d.ts +6 -5
  61. package/dist/types/src/util/dynamic-table.d.ts.map +1 -1
  62. package/dist/types/src/util/dynamic-table.test.d.ts +2 -0
  63. package/dist/types/src/util/dynamic-table.test.d.ts.map +1 -0
  64. package/dist/types/src/util/query-ast.d.ts.map +1 -1
  65. package/dist/types/tsconfig.tsbuildinfo +1 -1
  66. package/package.json +43 -43
  67. package/src/components/Table/ColumnActionsMenu.tsx +5 -5
  68. package/src/components/Table/ColumnSettings.tsx +3 -4
  69. package/src/components/Table/DynamicTable.stories.tsx +6 -5
  70. package/src/components/Table/DynamicTable.tsx +13 -19
  71. package/src/components/Table/Relations.stories.tsx +35 -25
  72. package/src/components/Table/Table.stories.tsx +61 -40
  73. package/src/components/Table/Table.tsx +41 -434
  74. package/src/components/Table/TableContent.tsx +422 -0
  75. package/src/components/{TableToolbar → Table}/TableToolbar.tsx +35 -42
  76. package/src/components/TableCellEditor/CellValidationMessage.tsx +4 -4
  77. package/src/components/TableCellEditor/FormCellEditor.tsx +12 -6
  78. package/src/components/TableCellEditor/TableCellEditor.stories.tsx +6 -5
  79. package/src/components/TableCellEditor/TableCellEditor.tsx +10 -5
  80. package/src/components/index.ts +0 -1
  81. package/src/components/testing.ts +1 -1
  82. package/src/hooks/useAddRow.ts +1 -1
  83. package/src/hooks/useProjectionModel.ts +3 -3
  84. package/src/hooks/useTableModel.ts +1 -1
  85. package/src/model/table-model.test.ts +5 -5
  86. package/src/model/table-model.ts +13 -12
  87. package/src/model/table-presentation.test.ts +5 -5
  88. package/src/model/table-presentation.ts +12 -11
  89. package/src/playwright/TableManager.ts +10 -3
  90. package/src/playwright/playwright.config.ts +1 -1
  91. package/src/playwright/smoke.spec.ts +45 -2
  92. package/src/testing/useTestTableModel.ts +4 -4
  93. package/src/translations.ts +19 -21
  94. package/src/types/Table.ts +11 -22
  95. package/src/util/dynamic-table.test.ts +70 -0
  96. package/src/util/dynamic-table.ts +17 -16
  97. package/src/util/query-ast.ts +3 -0
  98. package/src/util/table-buttons.ts +1 -1
  99. package/src/util/table-controls.ts +2 -2
  100. package/dist/lib/browser/chunk-I5IFW7UF.mjs.map +0 -7
  101. package/dist/lib/browser/chunk-OZBLY7XM.mjs.map +0 -7
  102. package/dist/lib/node-esm/chunk-DDJKYJFY.mjs.map +0 -7
  103. package/dist/lib/node-esm/chunk-WNZSKIRF.mjs.map +0 -7
  104. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts +0 -21
  105. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts.map +0 -1
  106. package/dist/types/src/components/TableToolbar/index.d.ts +0 -2
  107. package/dist/types/src/components/TableToolbar/index.d.ts.map +0 -1
  108. package/src/components/TableToolbar/index.ts +0 -5
@@ -29,9 +29,9 @@ import { type ModalController, type TableModel } from '../../model';
29
29
  import { CellValidationMessage } from './CellValidationMessage';
30
30
  import { FormCellEditor, type OnCreateHandler } from './FormCellEditor';
31
31
 
32
- const editorSlots = {
32
+ const documentSlots = {
33
33
  scroll: {
34
- className: '!plb-[--dx-grid-cell-editor-padding-block]',
34
+ className: '!py-(--dx-grid-cell-editor-padding-block)',
35
35
  },
36
36
  };
37
37
 
@@ -42,7 +42,7 @@ export type QueryResult = Pick<Completion, 'label'> & {
42
42
  data: any;
43
43
  };
44
44
 
45
- export type TableCellEditorProps<T extends Type.Entity.Any = Type.Entity.Any> = {
45
+ export type TableCellEditorProps<T extends Type.AnyEntity = Type.AnyEntity> = {
46
46
  schema?: T;
47
47
  model?: TableModel;
48
48
  modals?: ModalController;
@@ -51,7 +51,7 @@ export type TableCellEditorProps<T extends Type.Entity.Any = Type.Entity.Any> =
51
51
  onSave?: () => void;
52
52
  };
53
53
 
54
- export const TableValueEditor = <T extends Type.Entity.Any = Type.Entity.Any>({
54
+ export const TableValueEditor = <T extends Type.AnyEntity = Type.AnyEntity>({
55
55
  __gridScope,
56
56
  schema,
57
57
  model,
@@ -250,7 +250,12 @@ export const TableCellEditor = ({
250
250
  return (
251
251
  <>
252
252
  <CellValidationMessage validationError={validationError} variant={validationVariant} __gridScope={__gridScope} />
253
- <GridCellEditor extensions={extensions} getCellContent={getCellContent} onBlur={handleBlur} slots={editorSlots} />
253
+ <GridCellEditor
254
+ extensions={extensions}
255
+ getCellContent={getCellContent}
256
+ onBlur={handleBlur}
257
+ slots={documentSlots}
258
+ />
254
259
  </>
255
260
  );
256
261
  };
@@ -3,4 +3,3 @@
3
3
  //
4
4
 
5
5
  export * from './Table';
6
- export * from './TableToolbar';
@@ -19,7 +19,7 @@ export const TestSchema = Schema.Struct({
19
19
  netWorth: Schema.optional(Schema.Number),
20
20
  }).pipe(
21
21
  Type.object({
22
- typename: 'example.com/type/Test',
22
+ typename: 'com.example.type.test',
23
23
  version: '0.1.0',
24
24
  }),
25
25
  );
@@ -10,7 +10,7 @@ import { type InsertRowResult } from '../model';
10
10
 
11
11
  export type UseAddRowProps = {
12
12
  db?: Database.Database;
13
- schema?: Type.Obj.Any;
13
+ schema?: Type.AnyObj;
14
14
  };
15
15
 
16
16
  /**
@@ -5,13 +5,13 @@
5
5
  import { type Registry } from '@effect-atom/atom-react';
6
6
  import { useState } from 'react';
7
7
 
8
- import { Type } from '@dxos/echo';
8
+ import { JsonSchema, Type } from '@dxos/echo';
9
9
  import { useAsyncEffect } from '@dxos/react-ui';
10
10
  import { ProjectionModel, createEchoChangeCallback } from '@dxos/schema';
11
11
 
12
12
  import { type Table } from '../types';
13
13
 
14
- export const useProjectionModel = <S extends Type.Entity.Any>(
14
+ export const useProjectionModel = <S extends Type.AnyEntity>(
15
15
  schema: S | undefined,
16
16
  table: Table.Table | undefined,
17
17
  registry: Registry.Registry,
@@ -23,7 +23,7 @@ export const useProjectionModel = <S extends Type.Entity.Any>(
23
23
  const view = await table.view.load();
24
24
  // For mutable schemas (EchoSchema), use the live jsonSchema reference for reactivity.
25
25
  // For immutable schemas, create a snapshot.
26
- const jsonSchema = Type.isMutable(schema) ? schema.jsonSchema : Type.toJsonSchema(schema);
26
+ const jsonSchema = Type.isMutable(schema) ? schema.jsonSchema : JsonSchema.toJsonSchema(schema);
27
27
 
28
28
  // Always use createEchoChangeCallback since the view is ECHO-backed.
29
29
  // Pass schema only when mutable to allow schema mutations.
@@ -29,7 +29,7 @@ export type UseTableModelProps<T extends TableRow = TableRow> = {
29
29
  onRowAction?: (actionId: string, data: T) => void;
30
30
  } & Pick<
31
31
  TableModelProps<T>,
32
- 'features' | 'onInsertRow' | 'onDeleteRows' | 'onDeleteColumn' | 'onCellUpdate' | 'onRowOrderChange'
32
+ 'features' | 'onInsertRow' | 'onDeleteRows' | 'onColumnDelete' | 'onCellUpdate' | 'onRowOrderChange'
33
33
  >;
34
34
 
35
35
  export const useTableModel = <T extends TableRow = TableRow>({
@@ -6,9 +6,9 @@ import { Registry } from '@effect-atom/atom-react';
6
6
  import * as Schema from 'effect/Schema';
7
7
  import { afterEach, beforeEach, describe, expect, test } from 'vitest';
8
8
 
9
- import { Filter, Query, Type } from '@dxos/echo';
9
+ import { Filter, JsonSchema, Query, Type } from '@dxos/echo';
10
10
  import { createEchoSchema } from '@dxos/echo/testing';
11
- import { ProjectionModel, View, createDirectChangeCallback } from '@dxos/schema';
11
+ import { ProjectionModel, ViewModel, createDirectChangeCallback } from '@dxos/schema';
12
12
 
13
13
  import { Table } from '../types';
14
14
 
@@ -121,14 +121,14 @@ const Test = Schema.Struct({
121
121
  completed: Schema.Boolean,
122
122
  }).pipe(
123
123
  Type.object({
124
- typename: 'example.com/type/Test',
124
+ typename: 'com.example.type.test',
125
125
  version: '0.1.0',
126
126
  }),
127
127
  );
128
128
 
129
129
  const createTableModel = (registry: Registry.Registry, props: Partial<TableModelProps> = {}): TableModel => {
130
130
  const schema = createEchoSchema(Test);
131
- const view = View.make({
131
+ const view = ViewModel.make({
132
132
  query: Query.select(Filter.type(schema)),
133
133
  jsonSchema: schema.jsonSchema,
134
134
  });
@@ -137,7 +137,7 @@ const createTableModel = (registry: Registry.Registry, props: Partial<TableModel
137
137
  registry,
138
138
  view,
139
139
  baseSchema: schema.jsonSchema,
140
- change: createDirectChangeCallback(view.projection, schema.jsonSchema),
140
+ change: createDirectChangeCallback(view.projection, JsonSchema.toJsonSchema(schema)),
141
141
  });
142
142
  projection.normalizeView();
143
143
  return new TableModel({
@@ -6,6 +6,7 @@ import { Atom, type Registry } from '@effect-atom/atom-react';
6
6
 
7
7
  import { Resource } from '@dxos/context';
8
8
  import { type Database, Format, Obj, Order, Query, type QueryAST, Ref } from '@dxos/echo';
9
+ import { type View } from '@dxos/echo';
9
10
  import { type JsonProp, type JsonSchemaType, type Mutable, toEffectSchema } from '@dxos/echo/internal';
10
11
  import { getSnapshot } from '@dxos/echo/internal';
11
12
  import { getValue, setValue } from '@dxos/effect';
@@ -19,7 +20,7 @@ import {
19
20
  type DxGridPlaneRange,
20
21
  type DxGridPosition,
21
22
  } from '@dxos/react-ui-grid';
22
- import { type ProjectionModel, type PropertyType, type ValidationError, type View, validateSchema } from '@dxos/schema';
23
+ import { type ProjectionModel, type PropertyType, type ValidationError, validateSchema } from '@dxos/schema';
23
24
 
24
25
  import { type Table } from '../types';
25
26
  import { extractOrder } from '../util';
@@ -122,7 +123,7 @@ export type TableModelProps<T extends TableRow = TableRow> = {
122
123
  onResolveSchema?: (typename: string) => Promise<JsonSchemaType>;
123
124
  onInsertRow?: (data?: any) => InsertRowResult;
124
125
  onDeleteRows?: (index: number, obj: T[]) => void;
125
- onDeleteColumn?: (fieldId: string) => void;
126
+ onColumnDelete?: (fieldId: string) => void;
126
127
  onCellUpdate?: (cell: DxGridPosition) => void;
127
128
  onRowOrderChange?: () => void;
128
129
  onRowAction?: (actionId: string, data: T) => void;
@@ -139,7 +140,7 @@ export class TableModel<T extends TableRow = TableRow> extends Resource {
139
140
 
140
141
  private readonly _onInsertRow?: (data?: any) => InsertRowResult;
141
142
  private readonly _onDeleteRows?: TableModelProps<T>['onDeleteRows'];
142
- private readonly _onDeleteColumn?: TableModelProps<T>['onDeleteColumn'];
143
+ private readonly _onColumnDelete?: TableModelProps<T>['onColumnDelete'];
143
144
  private readonly _onCellUpdate?: TableModelProps<T>['onCellUpdate'];
144
145
  private readonly _onRowOrderChange?: TableModelProps<T>['onRowOrderChange'];
145
146
  private readonly _onRowAction?: TableModelProps<T>['onRowAction'];
@@ -176,7 +177,7 @@ export class TableModel<T extends TableRow = TableRow> extends Resource {
176
177
  pinnedRows = { top: [], bottom: [] },
177
178
  rowActions = [],
178
179
  onCellUpdate,
179
- onDeleteColumn,
180
+ onColumnDelete,
180
181
  onDeleteRows,
181
182
  onInsertRow,
182
183
  onRowOrderChange,
@@ -292,7 +293,7 @@ export class TableModel<T extends TableRow = TableRow> extends Resource {
292
293
  this._rowActions = rowActions;
293
294
  this._onInsertRow = onInsertRow;
294
295
  this._onDeleteRows = onDeleteRows;
295
- this._onDeleteColumn = onDeleteColumn;
296
+ this._onColumnDelete = onColumnDelete;
296
297
  this._onCellUpdate = onCellUpdate;
297
298
  this._onRowOrderChange = onRowOrderChange;
298
299
  this._onRowAction = onRowAction;
@@ -691,7 +692,7 @@ export class TableModel<T extends TableRow = TableRow> extends Resource {
691
692
  const currentRow = this._registry.get(this._rows)[row];
692
693
  invariant(currentRow, 'Invalid row index');
693
694
 
694
- const snapshot = getSnapshot(currentRow);
695
+ const snapshot = { ...getSnapshot(currentRow) };
695
696
  setValue(snapshot, field.path, transformedValue);
696
697
 
697
698
  const schema = Obj.getSchema(currentRow);
@@ -796,8 +797,8 @@ export class TableModel<T extends TableRow = TableRow> extends Resource {
796
797
  }
797
798
 
798
799
  const field = this._projection?.getFields().find((field) => field.id === fieldId);
799
- if (field && this._onDeleteColumn) {
800
- this._onDeleteColumn(field.id);
800
+ if (field && this._onColumnDelete) {
801
+ this._onColumnDelete(field.id);
801
802
  }
802
803
  }
803
804
 
@@ -893,14 +894,14 @@ export class TableModel<T extends TableRow = TableRow> extends Resource {
893
894
  if (field) {
894
895
  // Persist sort to view.query.ast
895
896
  const newQuery = baseQuery.orderBy(Order.property<any>(field.path as string, inMemorySort.direction));
896
- Obj.change(view, (v) => {
897
- v.query.ast = newQuery.ast as Mutable<typeof newQuery.ast>;
897
+ Obj.change(view, (obj) => {
898
+ obj.query.ast = newQuery.ast as Mutable<typeof newQuery.ast>;
898
899
  });
899
900
  }
900
901
  } else {
901
902
  // Clear sort from view.query.ast
902
- Obj.change(view, (v) => {
903
- v.query.ast = baseQuery.ast as Mutable<typeof baseQuery.ast>;
903
+ Obj.change(view, (obj) => {
904
+ obj.query.ast = baseQuery.ast as Mutable<typeof baseQuery.ast>;
904
905
  });
905
906
  }
906
907
 
@@ -6,9 +6,9 @@ import { Registry } from '@effect-atom/atom-react';
6
6
  import * as Schema from 'effect/Schema';
7
7
  import { beforeEach, describe, expect, it } from 'vitest';
8
8
 
9
- import { Filter, Query, Type } from '@dxos/echo';
9
+ import { Filter, JsonSchema, Query, Type } from '@dxos/echo';
10
10
  import { createEchoSchema } from '@dxos/echo/testing';
11
- import { ProjectionModel, View, createDirectChangeCallback } from '@dxos/schema';
11
+ import { ProjectionModel, ViewModel, createDirectChangeCallback } from '@dxos/schema';
12
12
 
13
13
  import { Table } from '../types';
14
14
 
@@ -92,14 +92,14 @@ const Test = Schema.Struct({
92
92
  count: Schema.Number,
93
93
  }).pipe(
94
94
  Type.object({
95
- typename: 'example.com/type/Test',
95
+ typename: 'com.example.type.test',
96
96
  version: '0.1.0',
97
97
  }),
98
98
  );
99
99
 
100
100
  const createTableModel = (registry: Registry.Registry, props: Partial<TableModelProps> = {}): TableModel => {
101
101
  const schema = createEchoSchema(Test);
102
- const view = View.make({
102
+ const view = ViewModel.make({
103
103
  query: Query.select(Filter.type(schema)),
104
104
  jsonSchema: schema.jsonSchema,
105
105
  });
@@ -108,7 +108,7 @@ const createTableModel = (registry: Registry.Registry, props: Partial<TableModel
108
108
  registry,
109
109
  view,
110
110
  baseSchema: schema.jsonSchema,
111
- change: createDirectChangeCallback(view.projection, schema.jsonSchema),
111
+ change: createDirectChangeCallback(view.projection, JsonSchema.toJsonSchema(schema)),
112
112
  });
113
113
  projection.normalizeView();
114
114
  return new TableModel({ registry, object, projection, ...props });
@@ -6,6 +6,7 @@ import { Atom, type Registry } from '@effect-atom/atom-react';
6
6
  import * as Predicate from 'effect/Predicate';
7
7
 
8
8
  import { Obj } from '@dxos/echo';
9
+ import { type View } from '@dxos/echo';
9
10
  import { Format, TypeEnum, getValue } from '@dxos/echo/internal';
10
11
  import { cellClassesForFieldType, formatForDisplay } from '@dxos/react-ui-form';
11
12
  import {
@@ -15,7 +16,7 @@ import {
15
16
  type DxGridPlaneRange,
16
17
  toPlaneCellIndex,
17
18
  } from '@dxos/react-ui-grid';
18
- import { type FieldType, VIEW_FIELD_LIMIT } from '@dxos/schema';
19
+ import { VIEW_FIELD_LIMIT } from '@dxos/schema';
19
20
  import { mx } from '@dxos/ui-theme';
20
21
 
21
22
  import { tableButtons, tableControls } from '../util';
@@ -107,7 +108,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
107
108
  private createDataCell(
108
109
  cells: DxGridPlaneCells,
109
110
  obj: T,
110
- field: FieldType,
111
+ field: View.FieldType,
111
112
  colIndex: number,
112
113
  displayIndex: number,
113
114
  ): void {
@@ -210,7 +211,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
210
211
  const targetObj = getValue(obj, field.path)?.target;
211
212
  if (targetObj) {
212
213
  const dxn = Obj.getDXN(targetObj)?.toString();
213
- cell.accessoryHtml = `<div role="none" class="absolute inline-end-0 inset-block-0 p-[--dx-grid-cell-content-padding-block]"><dx-anchor refId=${dxn} class="dx-button is-6 aspect-square min-bs-0" data-dx-grid-action="accessory"><dx-icon icon="ph--link-simple--regular"/></dx-anchor></div>`;
214
+ cell.accessoryHtml = `<div role="none" class="absolute end-0 inset-y-0 p-(--dx-grid-cell-content-padding-block)"><dx-anchor dxn=${dxn} class="dx-button w-6 aspect-square min-h-0" data-dx-grid-action="accessory"><dx-icon icon="ph--link-simple--regular"/></dx-anchor></div>`;
214
215
  }
215
216
  }
216
217
 
@@ -335,11 +336,11 @@ export class TablePresentation<T extends TableRow = TableRow> {
335
336
  value: '',
336
337
  resizeHandle: 'col',
337
338
  accessoryHtml: `
338
- <span class="grow min-is-0 truncate">${props.title ?? field.path}</span>
339
+ <span class="grow min-w-0 truncate">${props.title ?? field.path}</span>
339
340
  ${direction !== undefined ? tableButtons.sort.render({ fieldId: field.id, direction }) : ''}
340
341
  ${tableButtons.columnSettings.render({ fieldId: field.id })}
341
342
  `,
342
- className: '!bg-toolbarSurface !text-description [&>div]:flex [&>div]:items-stretch',
343
+ className: '!bg-toolbar-surface text-description! [&>div]:flex [&>div]:items-stretch',
343
344
  };
344
345
  }
345
346
 
@@ -382,7 +383,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
382
383
  if (!this.model.features.selection.enabled || this.model.selection.selectionMode === 'single') {
383
384
  return {
384
385
  [toPlaneCellIndex({ col: 0, row: 0 })]: {
385
- className: '!bg-toolbarSurface',
386
+ className: '!bg-toolbar-surface',
386
387
  readonly: true,
387
388
  value: '',
388
389
  },
@@ -396,7 +397,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
396
397
  header: true,
397
398
  checked: this.model.selection.allRowsSelected,
398
399
  }),
399
- className: '!bg-toolbarSurface',
400
+ className: '!bg-toolbar-surface',
400
401
  readonly: true,
401
402
  value: '',
402
403
  },
@@ -411,7 +412,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
411
412
  disabled: (this.model.projection?.getFields()?.length ?? 0) >= VIEW_FIELD_LIMIT,
412
413
  })
413
414
  : undefined,
414
- className: '!bg-toolbarSurface',
415
+ className: '!bg-toolbar-surface',
415
416
  readonly: true,
416
417
  value: '',
417
418
  },
@@ -465,7 +466,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
465
466
  export const cellClassesForRowSelection = (selected: boolean, selectionMode: SelectionMode) => {
466
467
  if (!selected) {
467
468
  if (selectionMode === 'single') {
468
- return ['!cursor-pointer'];
469
+ return ['cursor-pointer!'];
469
470
  } else {
470
471
  return undefined;
471
472
  }
@@ -473,8 +474,8 @@ export const cellClassesForRowSelection = (selected: boolean, selectionMode: Sel
473
474
 
474
475
  switch (selectionMode) {
475
476
  case 'single':
476
- return ['!bg-currentRelated dx-grid__cell--no-focus-unfurl hover:bg-hoverSurface !cursor-pointer'];
477
+ return ['dx-grid__cell--no-focus-unfurl !bg-current-surface hover:bg-hover-surface cursor-pointer!'];
477
478
  case 'multiple':
478
- return ['!bg-gridCellSelected'];
479
+ return ['!bg-grid-cell-selected'];
479
480
  }
480
481
  };
@@ -17,6 +17,7 @@ const TABLE_SELECTORS = {
17
17
  },
18
18
  columnDelete: 'column-delete',
19
19
  rowDelete: 'row-menu-delete',
20
+ addRow: 'table.toolbar.add-row',
20
21
  } as const;
21
22
 
22
23
  export class TableManager {
@@ -53,10 +54,16 @@ export class TableManager {
53
54
  await this.page.getByTestId(TABLE_SELECTORS.columnSort[direction]).click();
54
55
  }
55
56
 
56
- public async addColumn({ label, format }: { label: string; format: string }): Promise<void> {
57
+ public async addRow(): Promise<void> {
58
+ await this.page.getByTestId(TABLE_SELECTORS.addRow).click();
59
+ }
60
+
61
+ public async addColumn({ label, format }: { label: string; format?: string }): Promise<void> {
57
62
  await this.page.getByTestId(TABLE_SELECTORS.newColumnButton).click();
58
- await this.page.getByRole('combobox').click();
59
- await this.page.getByLabel(format).click();
63
+ if (format) {
64
+ await this.page.getByRole('combobox').click();
65
+ await this.page.getByLabel(format).click();
66
+ }
60
67
  await this.page.getByPlaceholder('Property label').click();
61
68
  await this.page.getByPlaceholder('Property label').fill(label);
62
69
  await this.page.getByRole('button', { name: 'Save' }).click();
@@ -10,7 +10,7 @@ export default defineConfig({
10
10
  ...e2ePreset(import.meta.dirname),
11
11
  // TODO(wittjosiah): Avoid hard-coding ports.
12
12
  webServer: {
13
- command: 'moon run storybook-react:serve-e2e -- --port=9004',
13
+ command: 'pnpm storybook dev --ci --quiet --port=9004 --config-dir=.storybook',
14
14
  port: 9004,
15
15
  reuseExistingServer: false,
16
16
  },
@@ -121,8 +121,22 @@ test.describe('Table', () => {
121
121
  await page.close();
122
122
  });
123
123
 
124
- // Rest of add column test remains the same as it's a more complex flow.
125
- test('add column', async ({ browser, browserName }) => {
124
+ test('add column without changing format', async ({ browser, browserName }) => {
125
+ test.skip(browserName === 'webkit');
126
+ test.skip(browserName === 'firefox');
127
+ const { page } = await setupPage(browser, { url: storyUrl });
128
+ const table = new TableManager(page);
129
+
130
+ await table.grid.ready();
131
+ const newColumnLabel = 'DEFAULT FORMAT COL';
132
+
133
+ await table.addColumn({ label: newColumnLabel });
134
+
135
+ await expect(page.getByRole('gridcell', { name: newColumnLabel })).toBeVisible();
136
+ await page.close();
137
+ });
138
+
139
+ test('add column with format', async ({ browser, browserName }) => {
126
140
  test.skip(browserName === 'webkit');
127
141
  test.skip(browserName === 'firefox');
128
142
  const { page } = await setupPage(browser, { url: storyUrl });
@@ -160,6 +174,35 @@ test.describe('Table', () => {
160
174
  await page.close();
161
175
  });
162
176
 
177
+ test('add row and edit cell', async ({ browser, browserName }) => {
178
+ test.skip(browserName === 'webkit');
179
+ test.skip(browserName === 'firefox');
180
+ const { page } = await setupPage(browser, { url: storyUrl });
181
+ const table = new TableManager(page);
182
+
183
+ await table.grid.ready();
184
+
185
+ // Click the CTA row at the bottom to add a new row.
186
+ await table.grid.cell(0, 0, 'frozenRowsEnd').click();
187
+
188
+ // All schema fields are optional so the row is added directly to the grid (not as a draft).
189
+ const newCell = table.grid.cell(0, 10, 'grid');
190
+ await newCell.waitFor({ state: 'visible' });
191
+
192
+ // Focus should already be on the new row; engage edit mode.
193
+ await page.keyboard.press('Enter');
194
+ await page.getByTestId('grid.cell-editor').waitFor({ state: 'visible' });
195
+
196
+ // Type text and confirm.
197
+ const cellContent = 'New row content';
198
+ await page.keyboard.type(cellContent);
199
+ await page.keyboard.press('Enter');
200
+
201
+ // Assert the cell content is saved.
202
+ await expect(newCell).toHaveText(cellContent);
203
+ await page.close();
204
+ });
205
+
163
206
  // TODO(wittjosiah): Remove? Conflicts with story play function which is run as a unit test anyways.
164
207
  test.skip('extant relations work as expected', async ({ browser, browserName }) => {
165
208
  test.skip(browserName === 'webkit');
@@ -10,7 +10,7 @@ import { isMutable } from '@dxos/echo/internal';
10
10
  import { faker } from '@dxos/random';
11
11
  import { Filter, useQuery, useSchema } from '@dxos/react-client/echo';
12
12
  import { useClientStory } from '@dxos/react-client/testing';
13
- import { useGlobalFilteredObjects } from '@dxos/react-ui-searchlist';
13
+ import { useGlobalFilteredObjects } from '@dxos/react-ui-search';
14
14
  import { type ProjectionModel, getTypenameFromQuery } from '@dxos/schema';
15
15
 
16
16
  import { type TableController } from '../components';
@@ -20,7 +20,7 @@ import { Table } from '../types';
20
20
 
21
21
  faker.seed(0); // NOTE(ZaymonFC): Required for smoke tests.
22
22
 
23
- export type TestTableModel<T extends Type.Obj.Any = Type.Obj.Any> = {
23
+ export type TestTableModel<T extends Type.AnyObj = Type.AnyObj> = {
24
24
  schema: T | undefined;
25
25
  table: Table.Table | undefined;
26
26
  projection: ProjectionModel | undefined;
@@ -38,7 +38,7 @@ export type TestTableModel<T extends Type.Obj.Any = Type.Obj.Any> = {
38
38
  * Custom hook to create and manage a test table model for storybook demonstrations.
39
39
  * Provides table data, schema, and handlers for table operations.
40
40
  */
41
- export const useTestTableModel = <T extends Type.Obj.Any = Type.Obj.Any>(): TestTableModel<T> => {
41
+ export const useTestTableModel = <T extends Type.AnyObj = Type.AnyObj>(): TestTableModel<T> => {
42
42
  const registry = useContext(RegistryContext);
43
43
  const { space } = useClientStory();
44
44
  const db = space?.db;
@@ -97,7 +97,7 @@ export const useTestTableModel = <T extends Type.Obj.Any = Type.Obj.Any>(): Test
97
97
  rows: filteredObjects,
98
98
  onInsertRow: addRow,
99
99
  onDeleteRows: handleDeleteRows,
100
- onDeleteColumn: handleDeleteColumn,
100
+ onColumnDelete: handleDeleteColumn,
101
101
  onCellUpdate: handleCellUpdate,
102
102
  onRowOrderChange: handleRowOrderChange,
103
103
  });
@@ -10,27 +10,25 @@ export const translations = [
10
10
  {
11
11
  'en-US': {
12
12
  [translationKey]: {
13
- 'object placeholder': 'New table',
14
- 'create object label': 'Create table',
15
- 'table name placeholder': 'Table name',
16
- 'settings title': 'Table settings',
17
- 'table schema label': 'Type',
18
- 'new schema': 'New type',
19
- 'continue label': 'Continue',
20
- 'create stack section label': 'Create table',
21
- 'add row label': 'Add row',
22
- 'create comment': 'Create thread',
23
- 'column action sort descending': 'Sort Descending',
24
- 'column action sort ascending': 'Sort Ascending',
25
- 'column action clear sorting': 'Clear Sorting',
26
- 'column action settings': 'Column Settings',
27
- 'column action delete': 'Delete Column',
28
- 'delete row label': 'Delete row',
29
- 'bulk delete row label': 'Delete selected rows',
30
- 'column deleted label': 'Column deleted',
31
- 'new column button label': 'Create column',
32
- 'create new object label': 'Create new object “{{text}}”',
33
- 'save view label': 'Save changes to view',
13
+ 'object.placeholder': 'New table',
14
+ 'create-object.label': 'Create table',
15
+ 'table-name.placeholder': 'Table name',
16
+ 'settings.title': 'Table settings',
17
+ 'table-schema.label': 'Type',
18
+ 'continue.label': 'Continue',
19
+ 'create-stack-section.label': 'Create table',
20
+ 'add-row.label': 'Add row',
21
+ 'column-action-sort-descending.menu': 'Sort Descending',
22
+ 'column-action-sort-ascending.menu': 'Sort Ascending',
23
+ 'column-action-clear-sorting.menu': 'Clear Sorting',
24
+ 'column-action-settings.menu': 'Column Settings',
25
+ 'column-action-delete.menu': 'Delete Column',
26
+ 'delete-row.label': 'Delete row',
27
+ 'bulk-delete-row.label': 'Delete selected rows',
28
+ 'column-deleted.label': 'Column deleted',
29
+ 'new-column-button.label': 'Create column',
30
+ 'create-new-object.label': 'Create new object “{{text}}”',
31
+ 'save-view.label': 'Save changes to view',
34
32
  },
35
33
  },
36
34
  },
@@ -6,14 +6,15 @@ import * as Match from 'effect/Match';
6
6
  import * as Schema from 'effect/Schema';
7
7
  import * as SchemaAST from 'effect/SchemaAST';
8
8
 
9
- import { Obj, Ref, Type } from '@dxos/echo';
9
+ import { Annotation, JsonSchema, Obj, Ref, Type } from '@dxos/echo';
10
+ import { View } from '@dxos/echo';
10
11
  import { FormInputAnnotation, type JsonPath, type JsonSchemaType, LabelAnnotation } from '@dxos/echo/internal';
11
- import { View, ViewAnnotation } from '@dxos/schema';
12
+ import { ViewAnnotation } from '@dxos/schema';
12
13
 
13
14
  export const Table = Schema.Struct({
14
15
  name: Schema.String.pipe(Schema.optional),
15
16
 
16
- view: Type.Ref(View.View).pipe(FormInputAnnotation.set(false)),
17
+ view: Ref.Ref(View.View).pipe(FormInputAnnotation.set(false)),
17
18
 
18
19
  sizes: Schema.Record({
19
20
  // TODO(wittjosiah): Should be JsonPath.
@@ -22,11 +23,15 @@ export const Table = Schema.Struct({
22
23
  }).pipe(Schema.mutable, FormInputAnnotation.set(false)),
23
24
  }).pipe(
24
25
  Type.object({
25
- typename: 'dxos.org/type/Table',
26
- version: '0.2.0',
26
+ typename: 'org.dxos.type.table',
27
+ version: '0.1.0',
27
28
  }),
28
29
  LabelAnnotation.set(['name']),
29
30
  ViewAnnotation.set(true),
31
+ Annotation.IconAnnotation.set({
32
+ icon: 'ph--table--regular',
33
+ hue: 'green',
34
+ }),
30
35
  );
31
36
 
32
37
  export interface Table extends Schema.Schema.Type<typeof Table> {}
@@ -47,7 +52,7 @@ export const make = ({ name, sizes = {}, view, jsonSchema }: MakeProps): Table =
47
52
 
48
53
  // Preset sizes.
49
54
  if (jsonSchema) {
50
- const schema = Type.toEffectSchema(jsonSchema);
55
+ const schema = JsonSchema.toEffectSchema(jsonSchema);
51
56
  const properties = SchemaAST.getPropertySignatures(schema.ast);
52
57
  for (const property of properties) {
53
58
  const name = property.name.toString() as JsonPath;
@@ -72,19 +77,3 @@ export const make = ({ name, sizes = {}, view, jsonSchema }: MakeProps): Table =
72
77
 
73
78
  return table;
74
79
  };
75
-
76
- //
77
- // V1
78
- //
79
-
80
- export const TableV1 = Schema.Struct({
81
- sizes: Schema.Record({
82
- key: Schema.String,
83
- value: Schema.Number,
84
- }).pipe(Schema.mutable),
85
- }).pipe(
86
- Type.object({
87
- typename: 'dxos.org/type/Table',
88
- version: '0.1.0',
89
- }),
90
- );