@dxos/react-ui-table 0.8.3-main.7f5a14c → 0.8.3

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 (56) 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 +252 -125
  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 +252 -127
  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 +252 -125
  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/DynamicTable.stories.d.ts.map +1 -1
  21. package/dist/types/src/components/Table/Table.d.ts +2 -0
  22. package/dist/types/src/components/Table/Table.d.ts.map +1 -1
  23. package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
  24. package/dist/types/src/components/Table/relations.stories.d.ts.map +1 -1
  25. package/dist/types/src/components/TableCellEditor/CellValidationMessage.d.ts +7 -0
  26. package/dist/types/src/components/TableCellEditor/CellValidationMessage.d.ts.map +1 -0
  27. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
  28. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -1
  29. package/dist/types/src/components/testing.d.ts +2 -2
  30. package/dist/types/src/components/testing.d.ts.map +1 -1
  31. package/dist/types/src/hooks/useTableModel.d.ts.map +1 -1
  32. package/dist/types/src/model/table-model.d.ts +7 -0
  33. package/dist/types/src/model/table-model.d.ts.map +1 -1
  34. package/dist/types/src/types/table.d.ts +5 -4
  35. package/dist/types/src/types/table.d.ts.map +1 -1
  36. package/dist/types/src/util/dynamic-table.d.ts.map +1 -1
  37. package/package.json +34 -34
  38. package/src/components/Table/DynamicTable.stories.tsx +3 -2
  39. package/src/components/Table/Table.stories.tsx +15 -7
  40. package/src/components/Table/Table.tsx +13 -3
  41. package/src/components/Table/relations.stories.tsx +15 -10
  42. package/src/components/TableCellEditor/CellValidationMessage.tsx +38 -0
  43. package/src/components/TableCellEditor/TableCellEditor.stories.tsx +2 -1
  44. package/src/components/TableCellEditor/TableCellEditor.tsx +54 -22
  45. package/src/components/testing.ts +5 -4
  46. package/src/hooks/useTableModel.ts +8 -1
  47. package/src/model/table-model.test.ts +3 -2
  48. package/src/model/table-model.ts +88 -39
  49. package/src/model/table-presentation.test.ts +3 -2
  50. package/src/model/table-presentation.ts +1 -1
  51. package/src/types/table.ts +3 -2
  52. package/src/util/dynamic-table.ts +2 -2
  53. package/src/util/table.ts +11 -10
  54. package/dist/lib/browser/chunk-U6LL2AVU.mjs.map +0 -7
  55. package/dist/lib/node/chunk-CXDGXPM6.cjs.map +0 -7
  56. package/dist/lib/node-esm/chunk-EFSM52KQ.mjs.map +0 -7
@@ -37,9 +37,9 @@ __export(node_exports, {
37
37
  Table: () => Table,
38
38
  TableModel: () => TableModel,
39
39
  TablePresentation: () => TablePresentation,
40
- TableSchema: () => import_chunk_CXDGXPM6.TableSchema,
40
+ TableSchema: () => import_chunk_O2VPBNS5.TableSchema,
41
41
  TableToolbar: () => TableToolbar,
42
- TableType: () => import_chunk_CXDGXPM6.TableType,
42
+ TableType: () => import_chunk_O2VPBNS5.TableType,
43
43
  cellClassesForRowSelection: () => cellClassesForRowSelection,
44
44
  getBaseSchema: () => getBaseSchema,
45
45
  initializeTable: () => initializeTable,
@@ -52,7 +52,7 @@ __export(node_exports, {
52
52
  useTableModel: () => useTableModel
53
53
  });
54
54
  module.exports = __toCommonJS(node_exports);
55
- var import_chunk_CXDGXPM6 = require("./chunk-CXDGXPM6.cjs");
55
+ var import_chunk_O2VPBNS5 = require("./chunk-O2VPBNS5.cjs");
56
56
  var import_tracking = require("@preact-signals/safe-react/tracking");
57
57
  var import_react = __toESM(require("react"));
58
58
  var import_echo_schema = require("@dxos/echo-schema");
@@ -86,16 +86,17 @@ var import_echo_schema2 = require("@dxos/echo-schema");
86
86
  var import_invariant2 = require("@dxos/invariant");
87
87
  var import_live_object = require("@dxos/live-object");
88
88
  var import_react_ui_form3 = require("@dxos/react-ui-form");
89
+ var import_schema = require("@dxos/schema");
89
90
  var import_signals_core2 = require("@preact/signals-core");
90
91
  var import_context2 = require("@dxos/context");
92
+ var import_echo3 = require("@dxos/echo");
91
93
  var import_echo_schema3 = require("@dxos/echo-schema");
92
- var import_live_object2 = require("@dxos/live-object");
93
- var import_schema = require("@dxos/schema");
94
+ var import_schema2 = require("@dxos/schema");
94
95
  var import_effect2 = require("effect");
95
96
  var import_echo_schema4 = require("@dxos/echo-schema");
96
97
  var import_react_client = require("@dxos/react-client");
97
- var import_echo3 = require("@dxos/react-client/echo");
98
- var import_schema2 = require("@dxos/schema");
98
+ var import_echo4 = require("@dxos/react-client/echo");
99
+ var import_schema3 = require("@dxos/schema");
99
100
  var import_effect3 = require("effect");
100
101
  var import_SchemaAST = require("effect/SchemaAST");
101
102
  var import_signals_core3 = require("@preact/signals-core");
@@ -110,7 +111,7 @@ var import_echo_schema6 = require("@dxos/echo-schema");
110
111
  var import_react_ui_form5 = require("@dxos/react-ui-form");
111
112
  var import_react_ui_grid3 = require("@dxos/react-ui-grid");
112
113
  var import_react_ui_theme2 = require("@dxos/react-ui-theme");
113
- var import_schema3 = require("@dxos/schema");
114
+ var import_schema4 = require("@dxos/schema");
114
115
  var import_tracking6 = require("@preact-signals/safe-react/tracking");
115
116
  var import_react6 = __toESM(require("react"));
116
117
  var import_echo_schema7 = require("@dxos/echo-schema");
@@ -121,28 +122,32 @@ var import_react_ui_grid4 = require("@dxos/react-ui-grid");
121
122
  var import_react_ui_tag_picker = require("@dxos/react-ui-tag-picker");
122
123
  var import_tracking7 = require("@preact-signals/safe-react/tracking");
123
124
  var import_react7 = __toESM(require("react"));
125
+ var import_react_ui_grid5 = require("@dxos/react-ui-grid");
126
+ var import_tracking8 = require("@preact-signals/safe-react/tracking");
127
+ var import_react8 = __toESM(require("react"));
124
128
  var import_echo_schema8 = require("@dxos/echo-schema");
125
129
  var import_invariant4 = require("@dxos/invariant");
126
130
  var import_react_ui7 = require("@dxos/react-ui");
127
131
  var import_react_ui_form6 = require("@dxos/react-ui-form");
128
- var import_react_ui_grid5 = require("@dxos/react-ui-grid");
132
+ var import_react_ui_grid6 = require("@dxos/react-ui-grid");
129
133
  var import_util2 = require("@dxos/util");
130
134
  var import_autocomplete = require("@codemirror/autocomplete");
131
135
  var import_view = require("@codemirror/view");
132
- var import_tracking8 = require("@preact-signals/safe-react/tracking");
133
- var import_react8 = __toESM(require("react"));
136
+ var import_tracking9 = require("@preact-signals/safe-react/tracking");
137
+ var import_react9 = __toESM(require("react"));
134
138
  var import_react_ui8 = require("@dxos/react-ui");
135
139
  var import_react_ui_theme3 = require("@dxos/react-ui-theme");
136
- var import_tracking9 = require("@preact-signals/safe-react/tracking");
140
+ var import_tracking10 = require("@preact-signals/safe-react/tracking");
137
141
  var import_signals_core6 = require("@preact/signals-core");
138
- var import_react9 = require("react");
139
- var import_echo4 = require("@dxos/react-client/echo");
142
+ var import_lodash2 = __toESM(require("lodash.orderby"));
143
+ var import_react10 = require("react");
144
+ var import_echo5 = require("@dxos/react-client/echo");
140
145
  var import_react_ui_attention2 = require("@dxos/react-ui-attention");
141
146
  var import_util3 = require("@dxos/util");
142
- var import_tracking10 = require("@preact-signals/safe-react/tracking");
147
+ var import_tracking11 = require("@preact-signals/safe-react/tracking");
143
148
  var import_rx_react = require("@effect-rx/rx-react");
144
- var import_react10 = __toESM(require("react"));
145
- var import_live_object3 = require("@dxos/live-object");
149
+ var import_react11 = __toESM(require("react"));
150
+ var import_live_object2 = require("@dxos/live-object");
146
151
  var import_react_ui_menu = require("@dxos/react-ui-menu");
147
152
  var import_react_ui_menu2 = require("@dxos/react-ui-menu");
148
153
  var translationKey = "table";
@@ -382,7 +387,7 @@ var RowActionsMenu = ({ model, modals }) => {
382
387
  };
383
388
  var getBaseSchema = ({ typename, properties, jsonSchema, schema }) => {
384
389
  if (typename && properties) {
385
- const schema2 = (0, import_schema.getSchemaFromPropertyDefinitions)(typename, properties);
390
+ const schema2 = (0, import_schema2.getSchemaFromPropertyDefinitions)(typename, properties);
386
391
  return {
387
392
  typename: schema2.typename,
388
393
  jsonSchema: schema2.jsonSchema
@@ -402,7 +407,7 @@ var getBaseSchema = ({ typename, properties, jsonSchema, schema }) => {
402
407
  }
403
408
  };
404
409
  var makeDynamicTable = ({ typename, jsonSchema, properties }) => {
405
- const view = (0, import_schema.createView)({
410
+ const view = (0, import_schema2.createView)({
406
411
  name: "dynamic-table",
407
412
  typename,
408
413
  jsonSchema,
@@ -410,11 +415,11 @@ var makeDynamicTable = ({ typename, jsonSchema, properties }) => {
410
415
  fields: properties.map((property) => property.name)
411
416
  }
412
417
  });
413
- const table = (0, import_live_object2.live)(import_chunk_CXDGXPM6.TableType, {
418
+ const table = import_echo3.Obj.make(import_chunk_O2VPBNS5.TableType, {
414
419
  name: "dynamic-table",
415
- view: (0, import_live_object2.makeRef)(view)
420
+ view: import_echo3.Ref.make(view)
416
421
  });
417
- const projection = new import_schema.ViewProjection(jsonSchema, view);
422
+ const projection = new import_schema2.ViewProjection(jsonSchema, view);
418
423
  if (properties && view.fields) {
419
424
  setProperties(view, projection, properties);
420
425
  }
@@ -459,8 +464,8 @@ var initializeTable = async ({ client, space, table, typename, initialRow = true
459
464
  if (!schema) {
460
465
  throw new Error(`Schema not found: ${typename}`);
461
466
  }
462
- const fields = (0, import_schema2.getSchemaProperties)(schema.ast).map((prop) => prop.name);
463
- table.view = import_echo_schema4.Ref.make((0, import_schema2.createView)({
467
+ const fields = (0, import_schema3.getSchemaProperties)(schema.ast).map((prop) => prop.name);
468
+ table.view = import_echo_schema4.Ref.make((0, import_schema3.createView)({
464
469
  // TODO(ZaymonFC): Don't hardcode name?
465
470
  name: "View",
466
471
  typename: schema.typename,
@@ -470,10 +475,10 @@ var initializeTable = async ({ client, space, table, typename, initialRow = true
470
475
  return schema;
471
476
  } else {
472
477
  const [schema] = await space.db.schemaRegistry.register([
473
- ContactSchema
478
+ createContactSchema()
474
479
  ]);
475
480
  const fields = ContactFields;
476
- table.view = import_echo_schema4.Ref.make((0, import_schema2.createView)({
481
+ table.view = import_echo_schema4.Ref.make((0, import_schema3.createView)({
477
482
  name: "View",
478
483
  typename: schema.typename,
479
484
  jsonSchema: schema.jsonSchema,
@@ -481,19 +486,21 @@ var initializeTable = async ({ client, space, table, typename, initialRow = true
481
486
  }));
482
487
  createProjection(schema, table.view.target);
483
488
  if (initialRow) {
484
- space.db.add((0, import_echo3.live)(schema, {}));
489
+ space.db.add((0, import_echo4.live)(schema, {}));
485
490
  }
486
491
  return schema;
487
492
  }
488
493
  };
489
- var ContactSchema = (0, import_echo_schema4.TypedObject)({
494
+ var createContactSchema = () => (0, import_echo_schema4.TypedObject)({
490
495
  typename: `example.com/type/${import_react_client.PublicKey.random().truncate()}`,
491
496
  version: "0.1.0"
492
497
  })({
493
498
  name: import_effect2.Schema.optional(import_effect2.Schema.String).annotations({
494
499
  title: "Name"
495
500
  }),
496
- active: import_effect2.Schema.optional(import_effect2.Schema.Boolean),
501
+ active: import_effect2.Schema.optional(import_effect2.Schema.Boolean).annotations({
502
+ title: "Active"
503
+ }),
497
504
  email: import_effect2.Schema.optional(import_echo_schema4.Format.Email),
498
505
  salary: import_effect2.Schema.optional(import_echo_schema4.Format.Currency()).annotations({
499
506
  title: "Salary"
@@ -506,7 +513,7 @@ var ContactFields = [
506
513
  "active"
507
514
  ];
508
515
  var createProjection = (schema, view) => {
509
- const projection = new import_schema2.ViewProjection(schema.jsonSchema, view);
516
+ const projection = new import_schema3.ViewProjection(schema.jsonSchema, view);
510
517
  projection.setFieldProjection({
511
518
  field: {
512
519
  id: view.fields.find((f) => f.path === "salary").id,
@@ -523,7 +530,7 @@ var createProjection = (schema, view) => {
523
530
  });
524
531
  projection.setFieldProjection({
525
532
  field: {
526
- id: (0, import_schema2.createFieldId)(),
533
+ id: (0, import_schema3.createFieldId)(),
527
534
  path: "manager",
528
535
  referencePath: "name"
529
536
  },
@@ -1024,6 +1031,61 @@ var TableModel = class extends import_context.Resource {
1024
1031
  }
1025
1032
  }
1026
1033
  };
1034
+ this.validateCellData = async ({ col, row }, value) => {
1035
+ const rowIdx = this._sorting.getDataIndex(row);
1036
+ const fields = this._view?.fields ?? [];
1037
+ if (col < 0 || col >= fields.length) {
1038
+ return {
1039
+ valid: false,
1040
+ error: "Invalid column index"
1041
+ };
1042
+ }
1043
+ const field = fields[col];
1044
+ const { props } = this._projection.getFieldProjection(field.id);
1045
+ const currentRow = this._rows.value[rowIdx];
1046
+ (0, import_invariant2.invariant)(currentRow, "Invalid row index", {
1047
+ F: __dxlog_file,
1048
+ L: 355,
1049
+ S: this,
1050
+ A: [
1051
+ "currentRow",
1052
+ "'Invalid row index'"
1053
+ ]
1054
+ });
1055
+ const snapshot = (0, import_echo_schema2.getSnapshot)(currentRow);
1056
+ const transformedValue = editorTextToCellValue(props, value);
1057
+ (0, import_echo_schema2.setValue)(snapshot, field.path, transformedValue);
1058
+ const schema = (0, import_echo_schema2.getSchema)(currentRow);
1059
+ (0, import_invariant2.invariant)(schema, void 0, {
1060
+ F: __dxlog_file,
1061
+ L: 365,
1062
+ S: this,
1063
+ A: [
1064
+ "schema",
1065
+ ""
1066
+ ]
1067
+ });
1068
+ const validationResult = (0, import_schema.validateSchema)(schema, snapshot);
1069
+ if (validationResult && validationResult.length > 0) {
1070
+ const error = validationResult[0];
1071
+ (0, import_invariant2.invariant)(error.path === field.path, void 0, {
1072
+ F: __dxlog_file,
1073
+ L: 370,
1074
+ S: this,
1075
+ A: [
1076
+ "error.path === field.path",
1077
+ ""
1078
+ ]
1079
+ });
1080
+ return {
1081
+ valid: false,
1082
+ error: error.message
1083
+ };
1084
+ }
1085
+ return {
1086
+ valid: true
1087
+ };
1088
+ };
1027
1089
  this.setCellData = ({ col, row }, value) => {
1028
1090
  const rowIdx = this._sorting.getDataIndex(row);
1029
1091
  const fields = this._view?.fields ?? [];
@@ -1032,36 +1094,11 @@ var TableModel = class extends import_context.Resource {
1032
1094
  }
1033
1095
  const field = fields[col];
1034
1096
  const { props } = this._projection.getFieldProjection(field.id);
1035
- switch (props.format) {
1036
- case import_echo_schema2.FormatEnum.Ref: {
1037
- if ((0, import_live_object.isLiveObject)(value)) {
1038
- (0, import_echo_schema2.setValue)(this._rows.value[rowIdx], field.path, (0, import_live_object.makeRef)(value));
1039
- }
1040
- break;
1041
- }
1042
- case import_echo_schema2.FormatEnum.SingleSelect: {
1043
- const ids = extractTagIds(value);
1044
- if (ids && ids.length > 0) {
1045
- (0, import_echo_schema2.setValue)(this._rows.value[rowIdx], field.path, ids[0]);
1046
- }
1047
- break;
1048
- }
1049
- case import_echo_schema2.FormatEnum.MultiSelect: {
1050
- const ids = extractTagIds(value);
1051
- if (ids) {
1052
- (0, import_echo_schema2.setValue)(this._rows.value[rowIdx], field.path, ids);
1053
- }
1054
- break;
1055
- }
1056
- default: {
1057
- (0, import_echo_schema2.setValue)(this._rows.value[rowIdx], field.path, (0, import_react_ui_form3.parseValue)({
1058
- type: props.type,
1059
- format: props.format,
1060
- value
1061
- }));
1062
- break;
1063
- }
1097
+ const transformedValue = editorTextToCellValue(props, value);
1098
+ if (props.format === import_echo_schema2.FormatEnum.Ref && !(0, import_live_object.isLiveObject)(value)) {
1099
+ return;
1064
1100
  }
1101
+ (0, import_echo_schema2.setValue)(this._rows.value[rowIdx], field.path, transformedValue);
1065
1102
  };
1066
1103
  this._id = id;
1067
1104
  this._space = space;
@@ -1073,7 +1110,7 @@ var TableModel = class extends import_context.Resource {
1073
1110
  };
1074
1111
  (0, import_invariant2.invariant)(!(this._features.dataEditable && this._features.selection.enabled && this._features.selection.mode === "single"), "Single selection is not compatible with editable tables.", {
1075
1112
  F: __dxlog_file,
1076
- L: 115,
1113
+ L: 126,
1077
1114
  S: this,
1078
1115
  A: [
1079
1116
  "!(this._features.dataEditable && this._features.selection.enabled && this._features.selection.mode === 'single')",
@@ -1133,7 +1170,7 @@ var TableModel = class extends import_context.Resource {
1133
1170
  get columnMeta() {
1134
1171
  (0, import_invariant2.invariant)(this._columnMeta, void 0, {
1135
1172
  F: __dxlog_file,
1136
- L: 184,
1173
+ L: 195,
1137
1174
  S: this,
1138
1175
  A: [
1139
1176
  "this._columnMeta",
@@ -1268,6 +1305,36 @@ var TableModel = class extends import_context.Resource {
1268
1305
  this._sorting.save();
1269
1306
  }
1270
1307
  };
1308
+ var editorTextToCellValue = (props, value) => {
1309
+ switch (props.format) {
1310
+ case import_echo_schema2.FormatEnum.Ref: {
1311
+ if ((0, import_live_object.isLiveObject)(value)) {
1312
+ return (0, import_live_object.makeRef)(value);
1313
+ } else {
1314
+ return value;
1315
+ }
1316
+ }
1317
+ case import_echo_schema2.FormatEnum.SingleSelect: {
1318
+ const ids = extractTagIds(value);
1319
+ if (ids && ids.length > 0) {
1320
+ return ids[0];
1321
+ } else {
1322
+ return value;
1323
+ }
1324
+ }
1325
+ case import_echo_schema2.FormatEnum.MultiSelect: {
1326
+ const ids = extractTagIds(value);
1327
+ return ids || value;
1328
+ }
1329
+ default: {
1330
+ return (0, import_react_ui_form3.parseValue)({
1331
+ type: props.type,
1332
+ format: props.format,
1333
+ value
1334
+ });
1335
+ }
1336
+ }
1337
+ };
1271
1338
  var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/model/modal-controller.ts";
1272
1339
  var ModalController = class {
1273
1340
  constructor() {
@@ -1480,7 +1547,7 @@ var TablePresentation = class {
1480
1547
  const targetObj = (0, import_echo_schema6.getValue)(obj, field.path)?.target;
1481
1548
  if (targetObj) {
1482
1549
  const dxn = (0, import_echo_schema6.getObjectDXN)(targetObj)?.toString();
1483
- 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>`;
1550
+ 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>`;
1484
1551
  }
1485
1552
  }
1486
1553
  if (props.format === import_echo_schema6.FormatEnum.Boolean) {
@@ -1639,7 +1706,7 @@ var TablePresentation = class {
1639
1706
  row: 0
1640
1707
  })]: {
1641
1708
  accessoryHtml: this.model.features.schemaEditable ? tableButtons.addColumn.render({
1642
- disabled: (this.model.view?.fields?.length ?? 0) >= import_schema3.VIEW_FIELD_LIMIT
1709
+ disabled: (this.model.view?.fields?.length ?? 0) >= import_schema4.VIEW_FIELD_LIMIT
1643
1710
  }) : void 0,
1644
1711
  className: "!bg-toolbarSurface",
1645
1712
  readonly: true,
@@ -1670,20 +1737,44 @@ var cellClassesForRowSelection = (selected, selectionMode) => {
1670
1737
  ];
1671
1738
  }
1672
1739
  };
1740
+ var CellValidationMessage = ({ validationError, __gridScope }) => {
1741
+ var _effect = (0, import_tracking7.useSignals)();
1742
+ try {
1743
+ const { editing, editBox: box } = (0, import_react_ui_grid5.useGridContext)("GridSheetCellEditor", __gridScope);
1744
+ if (!editing || !validationError) {
1745
+ return null;
1746
+ }
1747
+ return /* @__PURE__ */ import_react7.default.createElement("div", {
1748
+ role: "none",
1749
+ className: "absolute bg-errorSurface text-errorSurfaceText rounded-bs-sm text-xs p-1",
1750
+ style: {
1751
+ ...{
1752
+ "--dx-gridCellWidth": `${box?.inlineSize ?? 200}px`
1753
+ },
1754
+ zIndex: 10,
1755
+ insetBlockEnd: `calc(100% - ${box.insetBlockStart}px)`,
1756
+ insetInlineStart: box.insetInlineStart,
1757
+ inlineSize: box.inlineSize
1758
+ }
1759
+ }, validationError);
1760
+ } finally {
1761
+ _effect.f();
1762
+ }
1763
+ };
1673
1764
  var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/TableCellEditor/FormCellEditor.tsx";
1674
1765
  var FormCellEditor = ({ fieldProjection, model, schema, __gridScope }) => {
1675
- var _effect = (0, import_tracking7.useSignals)();
1766
+ var _effect = (0, import_tracking8.useSignals)();
1676
1767
  try {
1677
- const { editing, setEditing } = (0, import_react_ui_grid5.useGridContext)("ArrayEditor", __gridScope);
1678
- const cellRef = (0, import_react7.useRef)(null);
1679
- (0, import_react7.useEffect)(() => {
1768
+ const { editing, setEditing } = (0, import_react_ui_grid6.useGridContext)("ArrayEditor", __gridScope);
1769
+ const cellRef = (0, import_react8.useRef)(null);
1770
+ (0, import_react8.useEffect)(() => {
1680
1771
  if (editing && editing.cellElement) {
1681
1772
  cellRef.current = editing.cellElement;
1682
1773
  }
1683
1774
  }, [
1684
1775
  editing?.cellElement
1685
1776
  ]);
1686
- const narrowedSchema = (0, import_react7.useMemo)(() => {
1777
+ const narrowedSchema = (0, import_react8.useMemo)(() => {
1687
1778
  if (!schema) {
1688
1779
  return void 0;
1689
1780
  }
@@ -1694,9 +1785,9 @@ var FormCellEditor = ({ fieldProjection, model, schema, __gridScope }) => {
1694
1785
  JSON.stringify(schema),
1695
1786
  fieldProjection.field.path
1696
1787
  ]);
1697
- const originalRow = (0, import_react7.useMemo)(() => {
1788
+ const originalRow = (0, import_react8.useMemo)(() => {
1698
1789
  if (model && editing) {
1699
- const cell = (0, import_react_ui_grid5.parseCellIndex)(editing.index);
1790
+ const cell = (0, import_react_ui_grid6.parseCellIndex)(editing.index);
1700
1791
  const row = model.getRowAt(cell.row);
1701
1792
  (0, import_invariant4.invariant)(row, void 0, {
1702
1793
  F: __dxlog_file3,
@@ -1714,14 +1805,14 @@ var FormCellEditor = ({ fieldProjection, model, schema, __gridScope }) => {
1714
1805
  model,
1715
1806
  editing
1716
1807
  ]);
1717
- const formValues = (0, import_react7.useMemo)(() => {
1808
+ const formValues = (0, import_react8.useMemo)(() => {
1718
1809
  if (originalRow) {
1719
1810
  return (0, import_echo_schema8.getSnapshot)(originalRow);
1720
1811
  }
1721
1812
  }, [
1722
1813
  originalRow
1723
1814
  ]);
1724
- const handleSave = (0, import_react7.useCallback)((values) => {
1815
+ const handleSave = (0, import_react8.useCallback)((values) => {
1725
1816
  const path = fieldProjection.field.path;
1726
1817
  const value = (0, import_util2.getDeep)(values, [
1727
1818
  path
@@ -1734,7 +1825,7 @@ var FormCellEditor = ({ fieldProjection, model, schema, __gridScope }) => {
1734
1825
  fieldProjection.field.path,
1735
1826
  originalRow
1736
1827
  ]);
1737
- const handleOpenChange = (0, import_react7.useCallback)((nextOpen) => {
1828
+ const handleOpenChange = (0, import_react8.useCallback)((nextOpen) => {
1738
1829
  if (nextOpen === false) {
1739
1830
  setEditing(null);
1740
1831
  }
@@ -1744,15 +1835,15 @@ var FormCellEditor = ({ fieldProjection, model, schema, __gridScope }) => {
1744
1835
  if (!editing) {
1745
1836
  return null;
1746
1837
  }
1747
- return /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Popover.Root, {
1838
+ return /* @__PURE__ */ import_react8.default.createElement(import_react_ui7.Popover.Root, {
1748
1839
  open: editing !== null,
1749
1840
  onOpenChange: handleOpenChange
1750
- }, /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Popover.VirtualTrigger, {
1841
+ }, /* @__PURE__ */ import_react8.default.createElement(import_react_ui7.Popover.VirtualTrigger, {
1751
1842
  virtualRef: cellRef
1752
- }), /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Popover.Content, {
1843
+ }), /* @__PURE__ */ import_react8.default.createElement(import_react_ui7.Popover.Content, {
1753
1844
  tabIndex: -1,
1754
1845
  classNames: "popover-card-width"
1755
- }, /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Popover.Arrow, null), /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Popover.Viewport, null, /* @__PURE__ */ import_react7.default.createElement(import_react_ui_form6.Form, {
1846
+ }, /* @__PURE__ */ import_react8.default.createElement(import_react_ui7.Popover.Arrow, null), /* @__PURE__ */ import_react8.default.createElement(import_react_ui7.Popover.Viewport, null, /* @__PURE__ */ import_react8.default.createElement(import_react_ui_form6.Form, {
1756
1847
  values: formValues,
1757
1848
  schema: narrowedSchema,
1758
1849
  onSave: handleSave
@@ -1816,7 +1907,7 @@ var TableValueEditor = ({ model, modals, schema, onEnter, onFocus, onQuery, __gr
1816
1907
  const fieldProjection2 = model.projection.getFieldProjection(field.id);
1817
1908
  (0, import_invariant3.invariant)(fieldProjection2, void 0, {
1818
1909
  F: __dxlog_file4,
1819
- L: 73,
1910
+ L: 74,
1820
1911
  S: void 0,
1821
1912
  A: [
1822
1913
  "fieldProjection",
@@ -1854,6 +1945,7 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }
1854
1945
  const { id: gridId, editing, setEditing } = (0, import_react_ui_grid4.useGridContext)("TableCellEditor", __gridScope);
1855
1946
  const suppressNextBlur = (0, import_react6.useRef)(false);
1856
1947
  const { themeMode } = (0, import_react_ui6.useThemeContext)();
1948
+ const [_validationError, setValidationError] = (0, import_react6.useState)(null);
1857
1949
  const fieldProjection = (0, import_react6.useMemo)(() => {
1858
1950
  if (!model || !editing) {
1859
1951
  return;
@@ -1863,7 +1955,7 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }
1863
1955
  const fieldProjection2 = model.projection.getFieldProjection(field.id);
1864
1956
  (0, import_invariant3.invariant)(fieldProjection2, void 0, {
1865
1957
  F: __dxlog_file4,
1866
- L: 114,
1958
+ L: 116,
1867
1959
  S: void 0,
1868
1960
  A: [
1869
1961
  "fieldProjection",
@@ -1875,15 +1967,21 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }
1875
1967
  model,
1876
1968
  editing
1877
1969
  ]);
1878
- const handleEnter = (0, import_react6.useCallback)((value) => {
1970
+ const handleEnter = (0, import_react6.useCallback)(async (value) => {
1879
1971
  if (!model || !editing) {
1880
1972
  return;
1881
1973
  }
1882
1974
  const cell = (0, import_react_ui_grid4.parseCellIndex)(editing.index);
1883
- model.setCellData(cell, value);
1884
- onEnter?.(cell);
1885
- onFocus?.();
1886
- setEditing(null);
1975
+ const result = await model.validateCellData(cell, value);
1976
+ if (result.valid) {
1977
+ setValidationError(null);
1978
+ model.setCellData(cell, value);
1979
+ onEnter?.(cell);
1980
+ onFocus?.();
1981
+ setEditing(null);
1982
+ } else {
1983
+ setValidationError(result.error);
1984
+ }
1887
1985
  }, [
1888
1986
  model,
1889
1987
  editing,
@@ -1891,37 +1989,49 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }
1891
1989
  onFocus,
1892
1990
  setEditing
1893
1991
  ]);
1894
- const handleBlur = (0, import_react6.useCallback)((value) => {
1992
+ const handleBlur = (0, import_react6.useCallback)(async (value) => {
1895
1993
  if (!model || !editing) {
1896
1994
  return;
1897
1995
  }
1898
1996
  if (suppressNextBlur.current) {
1899
1997
  suppressNextBlur.current = false;
1900
- return;
1901
- }
1902
- const cell = (0, import_react_ui_grid4.parseCellIndex)(editing.index);
1903
- if (value !== void 0) {
1904
- model.setCellData(cell, value);
1905
1998
  }
1906
1999
  }, [
1907
2000
  model,
1908
2001
  editing
1909
2002
  ]);
1910
- const handleClose = (0, import_react6.useCallback)((value, event) => {
2003
+ const handleClose = (0, import_react6.useCallback)(async (value, event) => {
1911
2004
  if (!model || !editing || !fieldProjection) {
1912
2005
  return;
1913
2006
  }
1914
2007
  const cell = (0, import_react_ui_grid4.parseCellIndex)(editing.index);
1915
- onEnter?.(cell);
1916
- if (event && onFocus) {
1917
- onFocus(determineNavigationAxis(event), determineNavigationDelta(event));
2008
+ if (value !== void 0) {
2009
+ const result = await model.validateCellData(cell, value);
2010
+ if (result.valid) {
2011
+ setValidationError(null);
2012
+ model.setCellData(cell, value);
2013
+ setEditing(null);
2014
+ onEnter?.(cell);
2015
+ if (event && onFocus) {
2016
+ onFocus(determineNavigationAxis(event), determineNavigationDelta(event));
2017
+ }
2018
+ } else {
2019
+ setValidationError(result.error);
2020
+ }
2021
+ } else {
2022
+ setValidationError(null);
2023
+ setEditing(null);
2024
+ if (event && onFocus) {
2025
+ onFocus(determineNavigationAxis(event), determineNavigationDelta(event));
2026
+ }
1918
2027
  }
1919
2028
  }, [
1920
2029
  model,
1921
2030
  editing,
1922
2031
  onFocus,
1923
2032
  onEnter,
1924
- fieldProjection
2033
+ fieldProjection,
2034
+ setEditing
1925
2035
  ]);
1926
2036
  const extension = (0, import_react6.useMemo)(() => {
1927
2037
  if (!fieldProjection) {
@@ -1958,9 +2068,9 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }
1958
2068
  return;
1959
2069
  }
1960
2070
  if (mode === "single-select") {
1961
- handleEnter(ids[0]);
2071
+ void handleEnter(ids[0]);
1962
2072
  } else {
1963
- handleEnter(ids);
2073
+ void handleEnter(ids);
1964
2074
  }
1965
2075
  }
1966
2076
  }
@@ -1981,11 +2091,11 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }
1981
2091
  modals.openCreateRef(props.referenceSchema, document.querySelector((0, import_react_ui_grid4.cellQuery)(editing.index, gridId)), {
1982
2092
  [field.referencePath]: data.text
1983
2093
  }, (data2) => {
1984
- handleEnter(data2);
2094
+ void handleEnter(data2);
1985
2095
  });
1986
2096
  }
1987
2097
  } else {
1988
- handleEnter(data);
2098
+ void handleEnter(data);
1989
2099
  }
1990
2100
  }
1991
2101
  }
@@ -2050,11 +2160,14 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }
2050
2160
  model,
2051
2161
  editing
2052
2162
  ]);
2053
- return /* @__PURE__ */ import_react6.default.createElement(import_react_ui_grid4.GridCellEditor, {
2163
+ return /* @__PURE__ */ import_react6.default.createElement(import_react6.default.Fragment, null, /* @__PURE__ */ import_react6.default.createElement(CellValidationMessage, {
2164
+ validationError: _validationError,
2165
+ __gridScope
2166
+ }), /* @__PURE__ */ import_react6.default.createElement(import_react_ui_grid4.GridCellEditor, {
2054
2167
  extension,
2055
2168
  getCellContent,
2056
2169
  onBlur: handleBlur
2057
- });
2170
+ }));
2058
2171
  } finally {
2059
2172
  _effect.f();
2060
2173
  }
@@ -2095,7 +2208,7 @@ var TableRoot = ({ children, role }) => {
2095
2208
  _effect.f();
2096
2209
  }
2097
2210
  };
2098
- var TableMain = /* @__PURE__ */ (0, import_react.forwardRef)(({ model, presentation, ignoreAttention, schema, onRowClick }, forwardedRef) => {
2211
+ var TableMain = /* @__PURE__ */ (0, import_react.forwardRef)(({ model, presentation, ignoreAttention, schema, client, onRowClick }, forwardedRef) => {
2099
2212
  var _effect = (0, import_tracking.useSignals)();
2100
2213
  try {
2101
2214
  const [dxGrid, setDxGrid] = (0, import_react.useState)(null);
@@ -2290,14 +2403,20 @@ var TableMain = /* @__PURE__ */ (0, import_react.forwardRef)(({ model, presentat
2290
2403
  const space = model.space;
2291
2404
  (0, import_invariant.invariant)(space, void 0, {
2292
2405
  F: __dxlog_file5,
2293
- L: 309,
2406
+ L: 311,
2294
2407
  S: void 0,
2295
2408
  A: [
2296
2409
  "space",
2297
2410
  ""
2298
2411
  ]
2299
2412
  });
2300
- const schema2 = space.db.schemaRegistry.getSchema(props.referenceSchema);
2413
+ let schema2;
2414
+ if (client) {
2415
+ schema2 = client.graph.schemaRegistry.getSchema(props.referenceSchema);
2416
+ }
2417
+ if (!schema2) {
2418
+ schema2 = space.db.schemaRegistry.getSchema(props.referenceSchema);
2419
+ }
2301
2420
  if (schema2) {
2302
2421
  const { objects } = await space.db.query(import_echo.Filter.type(schema2)).run();
2303
2422
  const options = objects.map((obj) => {
@@ -2324,6 +2443,7 @@ var TableMain = /* @__PURE__ */ (0, import_react.forwardRef)(({ model, presentat
2324
2443
  return [];
2325
2444
  }, [
2326
2445
  model,
2446
+ client,
2327
2447
  t
2328
2448
  ]);
2329
2449
  if (!model || !modals) {
@@ -2377,18 +2497,18 @@ var Table = {
2377
2497
  Main: TableMain
2378
2498
  };
2379
2499
  var useTableModel = ({ table, projection, rows, rowActions, features, onSelectionChanged, onRowAction, ...props }) => {
2380
- var _effect = (0, import_tracking9.useSignals)();
2500
+ var _effect = (0, import_tracking10.useSignals)();
2381
2501
  try {
2382
- const [model, setModel] = (0, import_react9.useState)();
2383
- (0, import_react9.useEffect)(() => {
2502
+ const [model, setModel] = (0, import_react10.useState)();
2503
+ (0, import_react10.useEffect)(() => {
2384
2504
  if (!table || !projection) {
2385
2505
  return;
2386
2506
  }
2387
2507
  let model2;
2388
2508
  const t = setTimeout(async () => {
2389
2509
  model2 = new TableModel({
2390
- id: (0, import_echo4.fullyQualifiedId)(table),
2391
- space: (0, import_echo4.getSpace)(table),
2510
+ id: (0, import_echo5.fullyQualifiedId)(table),
2511
+ space: (0, import_echo5.getSpace)(table),
2392
2512
  view: table.view?.target,
2393
2513
  projection,
2394
2514
  features,
@@ -2410,9 +2530,14 @@ var useTableModel = ({ table, projection, rows, rowActions, features, onSelectio
2410
2530
  features,
2411
2531
  rowActions
2412
2532
  ]);
2413
- (0, import_react9.useEffect)(() => {
2533
+ (0, import_react10.useEffect)(() => {
2414
2534
  if (rows) {
2415
- model?.setRows(rows);
2535
+ const sortedRows = (0, import_lodash2.default)(rows, [
2536
+ (row) => String(row.id)
2537
+ ], [
2538
+ "asc"
2539
+ ]);
2540
+ model?.setRows(sortedRows);
2416
2541
  }
2417
2542
  }, [
2418
2543
  model,
@@ -2422,7 +2547,7 @@ var useTableModel = ({ table, projection, rows, rowActions, features, onSelectio
2422
2547
  table?.id,
2423
2548
  table?.view?.target?.query.typename
2424
2549
  ].filter(import_util3.isNonNullable));
2425
- (0, import_react9.useEffect)(() => {
2550
+ (0, import_react10.useEffect)(() => {
2426
2551
  if (!model) {
2427
2552
  return;
2428
2553
  }
@@ -2447,9 +2572,9 @@ var useTableModel = ({ table, projection, rows, rowActions, features, onSelectio
2447
2572
  }
2448
2573
  };
2449
2574
  var DynamicTable = ({ classNames, name = "example.com/dynamic-table", rows, properties, jsonSchema, schema, rowActions, onRowClick, onRowAction, ...props }) => {
2450
- var _effect = (0, import_tracking8.useSignals)();
2575
+ var _effect = (0, import_tracking9.useSignals)();
2451
2576
  try {
2452
- const { table, projection } = (0, import_react8.useMemo)(() => {
2577
+ const { table, projection } = (0, import_react9.useMemo)(() => {
2453
2578
  const props2 = getBaseSchema({
2454
2579
  typename: name,
2455
2580
  properties,
@@ -2466,11 +2591,11 @@ var DynamicTable = ({ classNames, name = "example.com/dynamic-table", rows, prop
2466
2591
  schema,
2467
2592
  jsonSchema
2468
2593
  ]);
2469
- const tableRef = (0, import_react8.useRef)(null);
2470
- const handleCellUpdate = (0, import_react8.useCallback)((cell) => {
2594
+ const tableRef = (0, import_react9.useRef)(null);
2595
+ const handleCellUpdate = (0, import_react9.useCallback)((cell) => {
2471
2596
  tableRef.current?.update?.(cell);
2472
2597
  }, []);
2473
- const handleRowOrderChange = (0, import_react8.useCallback)(() => {
2598
+ const handleRowOrderChange = (0, import_react9.useCallback)(() => {
2474
2599
  tableRef.current?.update?.();
2475
2600
  }, []);
2476
2601
  const features = (0, import_react_ui8.useDefaultValue)(props.features, () => ({
@@ -2489,20 +2614,20 @@ var DynamicTable = ({ classNames, name = "example.com/dynamic-table", rows, prop
2489
2614
  onRowOrderChange: handleRowOrderChange,
2490
2615
  onRowAction
2491
2616
  });
2492
- const presentation = (0, import_react8.useMemo)(() => {
2617
+ const presentation = (0, import_react9.useMemo)(() => {
2493
2618
  if (model) {
2494
2619
  return new TablePresentation(model);
2495
2620
  }
2496
2621
  }, [
2497
2622
  model
2498
2623
  ]);
2499
- return /* @__PURE__ */ import_react8.default.createElement("div", {
2624
+ return /* @__PURE__ */ import_react9.default.createElement("div", {
2500
2625
  role: "none",
2501
2626
  className: (0, import_react_ui_theme3.mx)("is-full bs-full grow grid", classNames)
2502
- }, /* @__PURE__ */ import_react8.default.createElement("div", {
2627
+ }, /* @__PURE__ */ import_react9.default.createElement("div", {
2503
2628
  role: "none",
2504
2629
  className: "grid min-bs-0 overflow-hidden"
2505
- }, /* @__PURE__ */ import_react8.default.createElement(Table.Root, null, /* @__PURE__ */ import_react8.default.createElement(Table.Main, {
2630
+ }, /* @__PURE__ */ import_react9.default.createElement(Table.Root, null, /* @__PURE__ */ import_react9.default.createElement(Table.Main, {
2506
2631
  ref: tableRef,
2507
2632
  model,
2508
2633
  presentation,
@@ -2559,12 +2684,12 @@ var createTableToolbarActions = ({ state, onAdd, onSave, customActions }) => imp
2559
2684
  };
2560
2685
  });
2561
2686
  var TableToolbar = ({ classNames, viewDirty, attendableId, onAdd, onSave, customActions }) => {
2562
- var _effect = (0, import_tracking10.useSignals)();
2687
+ var _effect = (0, import_tracking11.useSignals)();
2563
2688
  try {
2564
- const state = (0, import_react10.useMemo)(() => (0, import_live_object3.live)({
2689
+ const state = (0, import_react11.useMemo)(() => (0, import_live_object2.live)({
2565
2690
  viewDirty
2566
2691
  }), []);
2567
- const actionsCreator = (0, import_react10.useMemo)(() => createTableToolbarActions({
2692
+ const actionsCreator = (0, import_react11.useMemo)(() => createTableToolbarActions({
2568
2693
  state,
2569
2694
  onAdd,
2570
2695
  onSave,
@@ -2576,10 +2701,10 @@ var TableToolbar = ({ classNames, viewDirty, attendableId, onAdd, onSave, custom
2576
2701
  customActions
2577
2702
  ]);
2578
2703
  const menu = (0, import_react_ui_menu.useMenuActions)(actionsCreator);
2579
- return /* @__PURE__ */ import_react10.default.createElement(import_react_ui_menu.MenuProvider, {
2704
+ return /* @__PURE__ */ import_react11.default.createElement(import_react_ui_menu.MenuProvider, {
2580
2705
  ...menu,
2581
2706
  attendableId
2582
- }, /* @__PURE__ */ import_react10.default.createElement(import_react_ui_menu.ToolbarMenu, {
2707
+ }, /* @__PURE__ */ import_react11.default.createElement(import_react_ui_menu.ToolbarMenu, {
2583
2708
  classNames
2584
2709
  }));
2585
2710
  } finally {