@dxos/react-ui-table 0.8.3-main.672df60 → 0.8.3-staging.0fa589b

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 (61) hide show
  1. package/dist/lib/browser/{chunk-U6LL2AVU.mjs → chunk-TL7CKQQV.mjs} +4 -3
  2. package/dist/lib/browser/chunk-TL7CKQQV.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +272 -145
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/types/index.mjs +1 -1
  7. package/dist/lib/node/{chunk-CXDGXPM6.cjs → chunk-O2VPBNS5.cjs} +6 -5
  8. package/dist/lib/node/chunk-O2VPBNS5.cjs.map +7 -0
  9. package/dist/lib/node/index.cjs +260 -135
  10. package/dist/lib/node/index.cjs.map +4 -4
  11. package/dist/lib/node/meta.json +1 -1
  12. package/dist/lib/node/types/index.cjs +3 -3
  13. package/dist/lib/node/types/index.cjs.map +1 -1
  14. package/dist/lib/node-esm/{chunk-EFSM52KQ.mjs → chunk-GBT6GD4G.mjs} +4 -3
  15. package/dist/lib/node-esm/chunk-GBT6GD4G.mjs.map +7 -0
  16. package/dist/lib/node-esm/index.mjs +272 -145
  17. package/dist/lib/node-esm/index.mjs.map +4 -4
  18. package/dist/lib/node-esm/meta.json +1 -1
  19. package/dist/lib/node-esm/types/index.mjs +1 -1
  20. package/dist/types/src/components/Table/CreateRefPanel.d.ts.map +1 -1
  21. package/dist/types/src/components/Table/DynamicTable.stories.d.ts.map +1 -1
  22. package/dist/types/src/components/Table/Table.d.ts +2 -0
  23. package/dist/types/src/components/Table/Table.d.ts.map +1 -1
  24. package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
  25. package/dist/types/src/components/Table/relations.stories.d.ts.map +1 -1
  26. package/dist/types/src/components/TableCellEditor/CellValidationMessage.d.ts +7 -0
  27. package/dist/types/src/components/TableCellEditor/CellValidationMessage.d.ts.map +1 -0
  28. package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts.map +1 -1
  29. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
  30. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -1
  31. package/dist/types/src/components/testing.d.ts +2 -2
  32. package/dist/types/src/components/testing.d.ts.map +1 -1
  33. package/dist/types/src/hooks/useTableModel.d.ts.map +1 -1
  34. package/dist/types/src/model/table-model.d.ts +7 -0
  35. package/dist/types/src/model/table-model.d.ts.map +1 -1
  36. package/dist/types/src/types/table.d.ts +5 -4
  37. package/dist/types/src/types/table.d.ts.map +1 -1
  38. package/dist/types/src/util/dynamic-table.d.ts.map +1 -1
  39. package/package.json +34 -33
  40. package/src/components/Table/ColumnSettings.tsx +11 -11
  41. package/src/components/Table/CreateRefPanel.tsx +5 -3
  42. package/src/components/Table/DynamicTable.stories.tsx +3 -2
  43. package/src/components/Table/Table.stories.tsx +19 -16
  44. package/src/components/Table/Table.tsx +13 -3
  45. package/src/components/Table/relations.stories.tsx +15 -10
  46. package/src/components/TableCellEditor/CellValidationMessage.tsx +38 -0
  47. package/src/components/TableCellEditor/FormCellEditor.tsx +3 -1
  48. package/src/components/TableCellEditor/TableCellEditor.stories.tsx +2 -1
  49. package/src/components/TableCellEditor/TableCellEditor.tsx +54 -22
  50. package/src/components/testing.ts +5 -4
  51. package/src/hooks/useTableModel.ts +8 -1
  52. package/src/model/table-model.test.ts +3 -2
  53. package/src/model/table-model.ts +88 -39
  54. package/src/model/table-presentation.test.ts +3 -2
  55. package/src/model/table-presentation.ts +1 -1
  56. package/src/types/table.ts +3 -2
  57. package/src/util/dynamic-table.ts +2 -2
  58. package/src/util/table.ts +11 -10
  59. package/dist/lib/browser/chunk-U6LL2AVU.mjs.map +0 -7
  60. package/dist/lib/node/chunk-CXDGXPM6.cjs.map +0 -7
  61. package/dist/lib/node-esm/chunk-EFSM52KQ.mjs.map +0 -7
@@ -6,7 +6,15 @@ import { computed, effect, signal, type ReadonlySignal } from '@preact/signals-c
6
6
 
7
7
  import { type Space } from '@dxos/client/echo';
8
8
  import { Resource } from '@dxos/context';
9
- import { type FieldSortType, FormatEnum, getValue, setValue, type JsonProp } from '@dxos/echo-schema';
9
+ import {
10
+ type FieldSortType,
11
+ FormatEnum,
12
+ getValue,
13
+ setValue,
14
+ type JsonProp,
15
+ getSnapshot,
16
+ getSchema,
17
+ } from '@dxos/echo-schema';
10
18
  import { invariant } from '@dxos/invariant';
11
19
  import { isLiveObject, makeRef } from '@dxos/live-object';
12
20
  import { formatForEditing, parseValue } from '@dxos/react-ui-form';
@@ -16,13 +24,16 @@ import {
16
24
  type DxGridPlanePosition,
17
25
  type DxGridPosition,
18
26
  } from '@dxos/react-ui-grid';
19
- import { type ViewType, type ViewProjection } from '@dxos/schema';
27
+ import { type ViewType, type ViewProjection, type PropertyType, validateSchema } from '@dxos/schema';
20
28
 
21
29
  import { type SelectionMode, SelectionModel } from './selection-model';
22
30
  import { TableSorting } from './table-sorting';
23
31
  import { touch } from '../util';
24
32
  import { extractTagIds } from '../util/tag';
25
33
 
34
+ // TODO(ZaymonFC): Use a common type?
35
+ export type ValidationResult = { valid: true } | { valid: false; error: string };
36
+
26
37
  // TODO(burdon): Use schema types.
27
38
  export type TableRow = Record<JsonProp, any> & { id: string };
28
39
 
@@ -330,54 +341,58 @@ export class TableModel<T extends TableRow = TableRow> extends Resource {
330
341
  }
331
342
  };
332
343
 
333
- public setCellData = ({ col, row }: DxGridPlanePosition, value: any): void => {
344
+ public validateCellData = async ({ col, row }: DxGridPlanePosition, value: any): Promise<ValidationResult> => {
334
345
  const rowIdx = this._sorting.getDataIndex(row);
335
346
  const fields = this._view?.fields ?? [];
336
347
  if (col < 0 || col >= fields.length) {
337
- return;
348
+ return { valid: false, error: 'Invalid column index' };
338
349
  }
339
350
 
340
351
  const field = fields[col];
341
352
  const { props } = this._projection.getFieldProjection(field.id);
342
- switch (props.format) {
343
- case FormatEnum.Ref: {
344
- // TODO(ZaymonFC): This get's called an additional time by the cell editor onBlur, but with the cell editors
345
- // plain string value. Maybe onBlur should be called with the actual value?
346
- if (isLiveObject(value)) {
347
- setValue(this._rows.value[rowIdx], field.path, makeRef(value));
348
- }
349
- break;
350
- }
351
353
 
352
- case FormatEnum.SingleSelect: {
353
- const ids = extractTagIds(value);
354
- if (ids && ids.length > 0) {
355
- setValue(this._rows.value[rowIdx], field.path, ids[0]);
356
- }
357
- break;
358
- }
354
+ const currentRow = this._rows.value[rowIdx];
355
+ invariant(currentRow, 'Invalid row index');
359
356
 
360
- case FormatEnum.MultiSelect: {
361
- const ids = extractTagIds(value);
362
- if (ids) {
363
- setValue(this._rows.value[rowIdx], field.path, ids);
364
- }
365
- break;
366
- }
357
+ // Get a snapshot of the current object.
358
+ const snapshot = getSnapshot(currentRow);
359
+ const transformedValue = editorTextToCellValue(props, value);
367
360
 
368
- default: {
369
- setValue(
370
- this._rows.value[rowIdx],
371
- field.path,
372
- parseValue({
373
- type: props.type,
374
- format: props.format,
375
- value,
376
- }),
377
- );
378
- break;
379
- }
361
+ // Set the proposed value.
362
+ setValue(snapshot, field.path, transformedValue);
363
+
364
+ const schema = getSchema(currentRow);
365
+ invariant(schema);
366
+
367
+ const validationResult = validateSchema(schema, snapshot);
368
+ if (validationResult && validationResult.length > 0) {
369
+ const error = validationResult[0];
370
+ invariant(error.path === field.path);
371
+ return { valid: false, error: error.message };
372
+ }
373
+
374
+ return { valid: true };
375
+ };
376
+
377
+ public setCellData = ({ col, row }: DxGridPlanePosition, value: any): void => {
378
+ const rowIdx = this._sorting.getDataIndex(row);
379
+ const fields = this._view?.fields ?? [];
380
+ if (col < 0 || col >= fields.length) {
381
+ return;
382
+ }
383
+
384
+ const field = fields[col];
385
+ const { props } = this._projection.getFieldProjection(field.id);
386
+ const transformedValue = editorTextToCellValue(props, value);
387
+
388
+ // Special handling for Ref format to preserve existing behavior
389
+ if (props.format === FormatEnum.Ref && !isLiveObject(value)) {
390
+ // TODO(ZaymonFC): This get's called an additional time by the cell editor onBlur, but with the cell editors
391
+ // plain string value. Maybe onBlur should be called with the actual value?
392
+ return;
380
393
  }
394
+
395
+ setValue(this._rows.value[rowIdx], field.path, transformedValue);
381
396
  };
382
397
 
383
398
  /**
@@ -446,3 +461,37 @@ export class TableModel<T extends TableRow = TableRow> extends Resource {
446
461
  this._sorting.save();
447
462
  }
448
463
  }
464
+
465
+ const editorTextToCellValue = (props: PropertyType, value: any): any => {
466
+ switch (props.format) {
467
+ case FormatEnum.Ref: {
468
+ if (isLiveObject(value)) {
469
+ return makeRef(value);
470
+ } else {
471
+ return value;
472
+ }
473
+ }
474
+
475
+ case FormatEnum.SingleSelect: {
476
+ const ids = extractTagIds(value);
477
+ if (ids && ids.length > 0) {
478
+ return ids[0];
479
+ } else {
480
+ return value;
481
+ }
482
+ }
483
+
484
+ case FormatEnum.MultiSelect: {
485
+ const ids = extractTagIds(value);
486
+ return ids || value;
487
+ }
488
+
489
+ default: {
490
+ return parseValue({
491
+ type: props.type,
492
+ format: props.format,
493
+ value,
494
+ });
495
+ }
496
+ }
497
+ };
@@ -5,8 +5,9 @@
5
5
  import { Schema } from 'effect';
6
6
  import { describe, expect, it, beforeEach } from 'vitest';
7
7
 
8
+ import { Obj, Ref } from '@dxos/echo';
8
9
  import { TypedObject } from '@dxos/echo-schema';
9
- import { live, makeRef } from '@dxos/live-object';
10
+ import { live } from '@dxos/live-object';
10
11
  import { createEchoSchema } from '@dxos/live-object/testing';
11
12
  import { createView, ViewProjection } from '@dxos/schema';
12
13
 
@@ -98,6 +99,6 @@ const createTableModel = (props: Partial<TableModelProps> = {}): TableModel => {
98
99
  const schema = createEchoSchema(Test);
99
100
  const view = createView({ name: 'Test', typename: schema.typename, jsonSchema: schema.jsonSchema });
100
101
  const projection = new ViewProjection(schema.jsonSchema, view);
101
- const table = live(TableType, { view: makeRef(view) });
102
+ const table = Obj.make(TableType, { view: Ref.make(view) });
102
103
  return new TableModel({ id: table.id, view, projection, ...props });
103
104
  };
@@ -171,7 +171,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
171
171
  const targetObj = getValue(obj, field.path)?.target;
172
172
  if (targetObj) {
173
173
  const dxn = getObjectDXN(targetObj)?.toString();
174
- cell.accessoryHtml = `<dx-ref-tag refId=${dxn} class="dx-button block is-6 pli-[3px] plb-[3px] pbe-[2px] min-bs-0 absolute inline-end-1"><dx-icon icon="ph--link-simple--regular"/></dx-ref-tag>`;
174
+ cell.accessoryHtml = `<dx-ref-tag refId=${dxn} class="dx-button is-6 pli-[3px] pbe-[2px] min-bs-0 absolute inline-end-1"><dx-icon icon="ph--link-simple--regular"/></dx-ref-tag>`;
175
175
  }
176
176
  }
177
177
 
@@ -5,7 +5,8 @@
5
5
  import { Schema } from 'effect';
6
6
 
7
7
  // import { ThreadType } from '@dxos/plugin-space/types';
8
- import { ObjectId, Ref, Expando, EchoObject, LabelAnnotation } from '@dxos/echo-schema';
8
+ import { Type } from '@dxos/echo';
9
+ import { ObjectId, Ref, Expando, LabelAnnotation } from '@dxos/echo-schema';
9
10
  import { ViewType } from '@dxos/schema';
10
11
 
11
12
  export const TableSchema = Schema.Struct({
@@ -18,7 +19,7 @@ export const TableSchema = Schema.Struct({
18
19
 
19
20
  // TODO(burdon): Move out of react-ui-xxx.
20
21
  export const TableType = TableSchema.pipe(
21
- EchoObject({
22
+ Type.Obj({
22
23
  typename: 'dxos.org/type/Table',
23
24
  version: '0.1.0',
24
25
  }),
@@ -4,9 +4,9 @@
4
4
 
5
5
  import { type Schema } from 'effect';
6
6
 
7
+ import { Obj, Ref } from '@dxos/echo';
7
8
  import { getTypename, toJsonSchema } from '@dxos/echo-schema';
8
9
  import type { JsonSchemaType, SortDirectionType } from '@dxos/echo-schema';
9
- import { live, makeRef } from '@dxos/live-object';
10
10
  import {
11
11
  createView,
12
12
  getSchemaFromPropertyDefinitions,
@@ -69,7 +69,7 @@ export const makeDynamicTable = ({
69
69
  ...(properties && { fields: properties.map((property) => property.name) }),
70
70
  });
71
71
 
72
- const table = live(TableType, { name: 'dynamic-table', view: makeRef(view) });
72
+ const table = Obj.make(TableType, { name: 'dynamic-table', view: Ref.make(view) });
73
73
  const projection = new ViewProjection(jsonSchema, view);
74
74
  if (properties && view.fields) {
75
75
  setProperties(view, projection, properties);
package/src/util/table.ts CHANGED
@@ -56,7 +56,7 @@ export const initializeTable = async ({
56
56
 
57
57
  return schema;
58
58
  } else {
59
- const [schema] = await space.db.schemaRegistry.register([ContactSchema]);
59
+ const [schema] = await space.db.schemaRegistry.register([createContactSchema()]);
60
60
  const fields = ContactFields;
61
61
 
62
62
  table.view = Ref.make(
@@ -79,15 +79,16 @@ export const initializeTable = async ({
79
79
  }
80
80
  };
81
81
 
82
- const ContactSchema = TypedObject({
83
- typename: `example.com/type/${PublicKey.random().truncate()}`,
84
- version: '0.1.0',
85
- })({
86
- name: Schema.optional(Schema.String).annotations({ title: 'Name' }),
87
- active: Schema.optional(Schema.Boolean),
88
- email: Schema.optional(Format.Email),
89
- salary: Schema.optional(Format.Currency()).annotations({ title: 'Salary' }),
90
- });
82
+ const createContactSchema = () =>
83
+ TypedObject({
84
+ typename: `example.com/type/${PublicKey.random().truncate()}`,
85
+ version: '0.1.0',
86
+ })({
87
+ name: Schema.optional(Schema.String).annotations({ title: 'Name' }),
88
+ active: Schema.optional(Schema.Boolean).annotations({ title: 'Active' }),
89
+ email: Schema.optional(Format.Email),
90
+ salary: Schema.optional(Format.Currency()).annotations({ title: 'Salary' }),
91
+ });
91
92
 
92
93
  const ContactFields = ['name', 'email', 'salary', 'active'];
93
94
 
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/types/table.ts"],
4
- "sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport { Schema } from 'effect';\n\n// import { ThreadType } from '@dxos/plugin-space/types';\nimport { ObjectId, Ref, Expando, EchoObject, LabelAnnotation } from '@dxos/echo-schema';\nimport { ViewType } from '@dxos/schema';\n\nexport const TableSchema = Schema.Struct({\n id: ObjectId,\n name: Schema.optional(Schema.String),\n view: Schema.optional(Ref(ViewType)),\n // TODO(burdon): Document why threads is included here?\n threads: Schema.optional(Schema.Array(Ref(Expando /* ThreadType */))),\n}).pipe(LabelAnnotation.set(['name']));\n\n// TODO(burdon): Move out of react-ui-xxx.\nexport const TableType = TableSchema.pipe(\n EchoObject({\n typename: 'dxos.org/type/Table',\n version: '0.1.0',\n }),\n);\nexport interface TableType extends Schema.Schema.Type<typeof TableType> {}\n"],
5
- "mappings": ";AAIA,SAASA,cAAc;AAGvB,SAASC,UAAUC,KAAKC,SAASC,YAAYC,uBAAuB;AACpE,SAASC,gBAAgB;AAElB,IAAMC,cAAcC,OAAOC,OAAO;EACvCC,IAAIC;EACJC,MAAMJ,OAAOK,SAASL,OAAOM,MAAM;EACnCC,MAAMP,OAAOK,SAASG,IAAIC,QAAAA,CAAAA;;EAE1BC,SAASV,OAAOK,SAASL,OAAOW,MAAMH;IAAII;;EAAsB,CAAA,CAAA;AAClE,CAAA,EAAGC,KAAKC,gBAAgBC,IAAI;EAAC;CAAO,CAAA;AAG7B,IAAMC,YAAYjB,YAAYc,KACnCI,WAAW;EACTC,UAAU;EACVC,SAAS;AACX,CAAA,CAAA;",
6
- "names": ["Schema", "ObjectId", "Ref", "Expando", "EchoObject", "LabelAnnotation", "ViewType", "TableSchema", "Schema", "Struct", "id", "ObjectId", "name", "optional", "String", "view", "Ref", "ViewType", "threads", "Array", "Expando", "pipe", "LabelAnnotation", "set", "TableType", "EchoObject", "typename", "version"]
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/types/table.ts"],
4
- "sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport { Schema } from 'effect';\n\n// import { ThreadType } from '@dxos/plugin-space/types';\nimport { ObjectId, Ref, Expando, EchoObject, LabelAnnotation } from '@dxos/echo-schema';\nimport { ViewType } from '@dxos/schema';\n\nexport const TableSchema = Schema.Struct({\n id: ObjectId,\n name: Schema.optional(Schema.String),\n view: Schema.optional(Ref(ViewType)),\n // TODO(burdon): Document why threads is included here?\n threads: Schema.optional(Schema.Array(Ref(Expando /* ThreadType */))),\n}).pipe(LabelAnnotation.set(['name']));\n\n// TODO(burdon): Move out of react-ui-xxx.\nexport const TableType = TableSchema.pipe(\n EchoObject({\n typename: 'dxos.org/type/Table',\n version: '0.1.0',\n }),\n);\nexport interface TableType extends Schema.Schema.Type<typeof TableType> {}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAIA,oBAAuB;AAGvB,yBAAoE;AACpE,oBAAyB;AAElB,IAAMA,cAAcC,qBAAOC,OAAO;EACvCC,IAAIC;EACJC,MAAMJ,qBAAOK,SAASL,qBAAOM,MAAM;EACnCC,MAAMP,qBAAOK,aAASG,wBAAIC,sBAAAA,CAAAA;;EAE1BC,SAASV,qBAAOK,SAASL,qBAAOW,UAAMH;IAAII;;EAAsB,CAAA,CAAA;AAClE,CAAA,EAAGC,KAAKC,mCAAgBC,IAAI;EAAC;CAAO,CAAA;AAG7B,IAAMC,YAAYjB,YAAYc,SACnCI,+BAAW;EACTC,UAAU;EACVC,SAAS;AACX,CAAA,CAAA;",
6
- "names": ["TableSchema", "Schema", "Struct", "id", "ObjectId", "name", "optional", "String", "view", "Ref", "ViewType", "threads", "Array", "Expando", "pipe", "LabelAnnotation", "set", "TableType", "EchoObject", "typename", "version"]
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/types/table.ts"],
4
- "sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport { Schema } from 'effect';\n\n// import { ThreadType } from '@dxos/plugin-space/types';\nimport { ObjectId, Ref, Expando, EchoObject, LabelAnnotation } from '@dxos/echo-schema';\nimport { ViewType } from '@dxos/schema';\n\nexport const TableSchema = Schema.Struct({\n id: ObjectId,\n name: Schema.optional(Schema.String),\n view: Schema.optional(Ref(ViewType)),\n // TODO(burdon): Document why threads is included here?\n threads: Schema.optional(Schema.Array(Ref(Expando /* ThreadType */))),\n}).pipe(LabelAnnotation.set(['name']));\n\n// TODO(burdon): Move out of react-ui-xxx.\nexport const TableType = TableSchema.pipe(\n EchoObject({\n typename: 'dxos.org/type/Table',\n version: '0.1.0',\n }),\n);\nexport interface TableType extends Schema.Schema.Type<typeof TableType> {}\n"],
5
- "mappings": ";;;AAIA,SAASA,cAAc;AAGvB,SAASC,UAAUC,KAAKC,SAASC,YAAYC,uBAAuB;AACpE,SAASC,gBAAgB;AAElB,IAAMC,cAAcC,OAAOC,OAAO;EACvCC,IAAIC;EACJC,MAAMJ,OAAOK,SAASL,OAAOM,MAAM;EACnCC,MAAMP,OAAOK,SAASG,IAAIC,QAAAA,CAAAA;;EAE1BC,SAASV,OAAOK,SAASL,OAAOW,MAAMH;IAAII;;EAAsB,CAAA,CAAA;AAClE,CAAA,EAAGC,KAAKC,gBAAgBC,IAAI;EAAC;CAAO,CAAA;AAG7B,IAAMC,YAAYjB,YAAYc,KACnCI,WAAW;EACTC,UAAU;EACVC,SAAS;AACX,CAAA,CAAA;",
6
- "names": ["Schema", "ObjectId", "Ref", "Expando", "EchoObject", "LabelAnnotation", "ViewType", "TableSchema", "Schema", "Struct", "id", "ObjectId", "name", "optional", "String", "view", "Ref", "ViewType", "threads", "Array", "Expando", "pipe", "LabelAnnotation", "set", "TableType", "EchoObject", "typename", "version"]
7
- }