@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
@@ -2,7 +2,7 @@ import { createRequire } from 'node:module';const require = createRequire(import
2
2
  import {
3
3
  TableSchema,
4
4
  TableType
5
- } from "./chunk-EFSM52KQ.mjs";
5
+ } from "./chunk-GBT6GD4G.mjs";
6
6
 
7
7
  // packages/ui/react-ui-table/src/translations.ts
8
8
  var translationKey = "table";
@@ -37,8 +37,8 @@ var translations_default = [
37
37
  ];
38
38
 
39
39
  // packages/ui/react-ui-table/src/components/Table/Table.tsx
40
- import { useSignals as _useSignals7 } from "@preact-signals/safe-react/tracking";
41
- import React7, { forwardRef, useCallback as useCallback5, useImperativeHandle, useState as useState2, useMemo as useMemo5, useEffect as useEffect3 } from "react";
40
+ import { useSignals as _useSignals8 } from "@preact-signals/safe-react/tracking";
41
+ import React8, { forwardRef, useCallback as useCallback5, useImperativeHandle, useState as useState3, useMemo as useMemo5, useEffect as useEffect3 } from "react";
42
42
  import { getValue as getValue4 } from "@dxos/echo-schema";
43
43
  import { invariant as invariant4 } from "@dxos/invariant";
44
44
  import { Filter } from "@dxos/react-client/echo";
@@ -281,18 +281,19 @@ var RowActionsMenu = ({ model, modals }) => {
281
281
  // packages/ui/react-ui-table/src/model/table-model.ts
282
282
  import { computed as computed3, effect as effect2, signal as signal3 } from "@preact/signals-core";
283
283
  import { Resource as Resource2 } from "@dxos/context";
284
- import { FormatEnum as FormatEnum3, getValue as getValue2, setValue } from "@dxos/echo-schema";
284
+ import { FormatEnum as FormatEnum3, getValue as getValue2, setValue, getSnapshot, getSchema } from "@dxos/echo-schema";
285
285
  import { invariant } from "@dxos/invariant";
286
- import { isLiveObject, makeRef as makeRef2 } from "@dxos/live-object";
286
+ import { isLiveObject, makeRef } from "@dxos/live-object";
287
287
  import { formatForEditing, parseValue } from "@dxos/react-ui-form";
288
+ import { validateSchema } from "@dxos/schema";
288
289
 
289
290
  // packages/ui/react-ui-table/src/model/selection-model.ts
290
291
  import { computed, effect, signal } from "@preact/signals-core";
291
292
  import { Resource } from "@dxos/context";
292
293
 
293
294
  // packages/ui/react-ui-table/src/util/dynamic-table.ts
295
+ import { Obj, Ref } from "@dxos/echo";
294
296
  import { getTypename, toJsonSchema } from "@dxos/echo-schema";
295
- import { live as live2, makeRef } from "@dxos/live-object";
296
297
  import { createView, getSchemaFromPropertyDefinitions, ViewProjection } from "@dxos/schema";
297
298
  var getBaseSchema = ({ typename, properties, jsonSchema, schema }) => {
298
299
  if (typename && properties) {
@@ -324,9 +325,9 @@ var makeDynamicTable = ({ typename, jsonSchema, properties }) => {
324
325
  fields: properties.map((property) => property.name)
325
326
  }
326
327
  });
327
- const table = live2(TableType, {
328
+ const table = Obj.make(TableType, {
328
329
  name: "dynamic-table",
329
- view: makeRef(view)
330
+ view: Ref.make(view)
330
331
  });
331
332
  const projection = new ViewProjection(jsonSchema, view);
332
333
  if (properties && view.fields) {
@@ -372,9 +373,9 @@ var touch = (value) => value;
372
373
 
373
374
  // packages/ui/react-ui-table/src/util/table.ts
374
375
  import { Schema as Schema2 } from "effect";
375
- import { Format, FormatEnum, Ref, TypedObject, TypeEnum } from "@dxos/echo-schema";
376
+ import { Format, FormatEnum, Ref as Ref2, TypedObject, TypeEnum } from "@dxos/echo-schema";
376
377
  import { PublicKey } from "@dxos/react-client";
377
- import { live as live3 } from "@dxos/react-client/echo";
378
+ import { live as live2 } from "@dxos/react-client/echo";
378
379
  import { createFieldId, createView as createView2, getSchemaProperties, ViewProjection as ViewProjection2 } from "@dxos/schema";
379
380
  var initializeTable = async ({ client, space, table, typename, initialRow = true }) => {
380
381
  if (typename) {
@@ -383,7 +384,7 @@ var initializeTable = async ({ client, space, table, typename, initialRow = true
383
384
  throw new Error(`Schema not found: ${typename}`);
384
385
  }
385
386
  const fields = getSchemaProperties(schema.ast).map((prop) => prop.name);
386
- table.view = Ref.make(createView2({
387
+ table.view = Ref2.make(createView2({
387
388
  // TODO(ZaymonFC): Don't hardcode name?
388
389
  name: "View",
389
390
  typename: schema.typename,
@@ -393,10 +394,10 @@ var initializeTable = async ({ client, space, table, typename, initialRow = true
393
394
  return schema;
394
395
  } else {
395
396
  const [schema] = await space.db.schemaRegistry.register([
396
- ContactSchema
397
+ createContactSchema()
397
398
  ]);
398
399
  const fields = ContactFields;
399
- table.view = Ref.make(createView2({
400
+ table.view = Ref2.make(createView2({
400
401
  name: "View",
401
402
  typename: schema.typename,
402
403
  jsonSchema: schema.jsonSchema,
@@ -404,19 +405,21 @@ var initializeTable = async ({ client, space, table, typename, initialRow = true
404
405
  }));
405
406
  createProjection(schema, table.view.target);
406
407
  if (initialRow) {
407
- space.db.add(live3(schema, {}));
408
+ space.db.add(live2(schema, {}));
408
409
  }
409
410
  return schema;
410
411
  }
411
412
  };
412
- var ContactSchema = TypedObject({
413
+ var createContactSchema = () => TypedObject({
413
414
  typename: `example.com/type/${PublicKey.random().truncate()}`,
414
415
  version: "0.1.0"
415
416
  })({
416
417
  name: Schema2.optional(Schema2.String).annotations({
417
418
  title: "Name"
418
419
  }),
419
- active: Schema2.optional(Schema2.Boolean),
420
+ active: Schema2.optional(Schema2.Boolean).annotations({
421
+ title: "Active"
422
+ }),
420
423
  email: Schema2.optional(Format.Email),
421
424
  salary: Schema2.optional(Format.Currency()).annotations({
422
425
  title: "Salary"
@@ -970,6 +973,61 @@ var TableModel = class extends Resource2 {
970
973
  }
971
974
  }
972
975
  };
976
+ this.validateCellData = async ({ col, row }, value) => {
977
+ const rowIdx = this._sorting.getDataIndex(row);
978
+ const fields = this._view?.fields ?? [];
979
+ if (col < 0 || col >= fields.length) {
980
+ return {
981
+ valid: false,
982
+ error: "Invalid column index"
983
+ };
984
+ }
985
+ const field = fields[col];
986
+ const { props } = this._projection.getFieldProjection(field.id);
987
+ const currentRow = this._rows.value[rowIdx];
988
+ invariant(currentRow, "Invalid row index", {
989
+ F: __dxlog_file,
990
+ L: 355,
991
+ S: this,
992
+ A: [
993
+ "currentRow",
994
+ "'Invalid row index'"
995
+ ]
996
+ });
997
+ const snapshot = getSnapshot(currentRow);
998
+ const transformedValue = editorTextToCellValue(props, value);
999
+ setValue(snapshot, field.path, transformedValue);
1000
+ const schema = getSchema(currentRow);
1001
+ invariant(schema, void 0, {
1002
+ F: __dxlog_file,
1003
+ L: 365,
1004
+ S: this,
1005
+ A: [
1006
+ "schema",
1007
+ ""
1008
+ ]
1009
+ });
1010
+ const validationResult = validateSchema(schema, snapshot);
1011
+ if (validationResult && validationResult.length > 0) {
1012
+ const error = validationResult[0];
1013
+ invariant(error.path === field.path, void 0, {
1014
+ F: __dxlog_file,
1015
+ L: 370,
1016
+ S: this,
1017
+ A: [
1018
+ "error.path === field.path",
1019
+ ""
1020
+ ]
1021
+ });
1022
+ return {
1023
+ valid: false,
1024
+ error: error.message
1025
+ };
1026
+ }
1027
+ return {
1028
+ valid: true
1029
+ };
1030
+ };
973
1031
  this.setCellData = ({ col, row }, value) => {
974
1032
  const rowIdx = this._sorting.getDataIndex(row);
975
1033
  const fields = this._view?.fields ?? [];
@@ -978,36 +1036,11 @@ var TableModel = class extends Resource2 {
978
1036
  }
979
1037
  const field = fields[col];
980
1038
  const { props } = this._projection.getFieldProjection(field.id);
981
- switch (props.format) {
982
- case FormatEnum3.Ref: {
983
- if (isLiveObject(value)) {
984
- setValue(this._rows.value[rowIdx], field.path, makeRef2(value));
985
- }
986
- break;
987
- }
988
- case FormatEnum3.SingleSelect: {
989
- const ids = extractTagIds(value);
990
- if (ids && ids.length > 0) {
991
- setValue(this._rows.value[rowIdx], field.path, ids[0]);
992
- }
993
- break;
994
- }
995
- case FormatEnum3.MultiSelect: {
996
- const ids = extractTagIds(value);
997
- if (ids) {
998
- setValue(this._rows.value[rowIdx], field.path, ids);
999
- }
1000
- break;
1001
- }
1002
- default: {
1003
- setValue(this._rows.value[rowIdx], field.path, parseValue({
1004
- type: props.type,
1005
- format: props.format,
1006
- value
1007
- }));
1008
- break;
1009
- }
1039
+ const transformedValue = editorTextToCellValue(props, value);
1040
+ if (props.format === FormatEnum3.Ref && !isLiveObject(value)) {
1041
+ return;
1010
1042
  }
1043
+ setValue(this._rows.value[rowIdx], field.path, transformedValue);
1011
1044
  };
1012
1045
  this._id = id;
1013
1046
  this._space = space;
@@ -1019,7 +1052,7 @@ var TableModel = class extends Resource2 {
1019
1052
  };
1020
1053
  invariant(!(this._features.dataEditable && this._features.selection.enabled && this._features.selection.mode === "single"), "Single selection is not compatible with editable tables.", {
1021
1054
  F: __dxlog_file,
1022
- L: 115,
1055
+ L: 126,
1023
1056
  S: this,
1024
1057
  A: [
1025
1058
  "!(this._features.dataEditable && this._features.selection.enabled && this._features.selection.mode === 'single')",
@@ -1079,7 +1112,7 @@ var TableModel = class extends Resource2 {
1079
1112
  get columnMeta() {
1080
1113
  invariant(this._columnMeta, void 0, {
1081
1114
  F: __dxlog_file,
1082
- L: 184,
1115
+ L: 195,
1083
1116
  S: this,
1084
1117
  A: [
1085
1118
  "this._columnMeta",
@@ -1214,6 +1247,36 @@ var TableModel = class extends Resource2 {
1214
1247
  this._sorting.save();
1215
1248
  }
1216
1249
  };
1250
+ var editorTextToCellValue = (props, value) => {
1251
+ switch (props.format) {
1252
+ case FormatEnum3.Ref: {
1253
+ if (isLiveObject(value)) {
1254
+ return makeRef(value);
1255
+ } else {
1256
+ return value;
1257
+ }
1258
+ }
1259
+ case FormatEnum3.SingleSelect: {
1260
+ const ids = extractTagIds(value);
1261
+ if (ids && ids.length > 0) {
1262
+ return ids[0];
1263
+ } else {
1264
+ return value;
1265
+ }
1266
+ }
1267
+ case FormatEnum3.MultiSelect: {
1268
+ const ids = extractTagIds(value);
1269
+ return ids || value;
1270
+ }
1271
+ default: {
1272
+ return parseValue({
1273
+ type: props.type,
1274
+ format: props.format,
1275
+ value
1276
+ });
1277
+ }
1278
+ }
1279
+ };
1217
1280
 
1218
1281
  // packages/ui/react-ui-table/src/model/modal-controller.ts
1219
1282
  import { signal as signal4 } from "@preact/signals-core";
@@ -1439,7 +1502,7 @@ var TablePresentation = class {
1439
1502
  const targetObj = getValue3(obj, field.path)?.target;
1440
1503
  if (targetObj) {
1441
1504
  const dxn = getObjectDXN(targetObj)?.toString();
1442
- 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>`;
1505
+ 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>`;
1443
1506
  }
1444
1507
  }
1445
1508
  if (props.format === FormatEnum4.Boolean) {
@@ -1631,29 +1694,58 @@ var cellClassesForRowSelection = (selected, selectionMode) => {
1631
1694
  };
1632
1695
 
1633
1696
  // packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx
1634
- import { useSignals as _useSignals6 } from "@preact-signals/safe-react/tracking";
1635
- import React6, { useCallback as useCallback4, useMemo as useMemo4, useRef as useRef2 } from "react";
1697
+ import { useSignals as _useSignals7 } from "@preact-signals/safe-react/tracking";
1698
+ import React7, { useCallback as useCallback4, useMemo as useMemo4, useRef as useRef2, useState as useState2 } from "react";
1636
1699
  import { FormatEnum as FormatEnum5, TypeEnum as TypeEnum4 } from "@dxos/echo-schema";
1637
1700
  import { invariant as invariant3 } from "@dxos/invariant";
1638
1701
  import { useThemeContext } from "@dxos/react-ui";
1639
1702
  import { createMarkdownExtensions } from "@dxos/react-ui-editor";
1640
- import { cellQuery, editorKeys, parseCellIndex as parseCellIndex2, useGridContext as useGridContext3, GridCellEditor } from "@dxos/react-ui-grid";
1703
+ import { cellQuery, editorKeys, parseCellIndex as parseCellIndex2, useGridContext as useGridContext4, GridCellEditor } from "@dxos/react-ui-grid";
1641
1704
  import { tagPickerExtension, createLinks } from "@dxos/react-ui-tag-picker";
1642
1705
 
1643
- // packages/ui/react-ui-table/src/components/TableCellEditor/FormCellEditor.tsx
1706
+ // packages/ui/react-ui-table/src/components/TableCellEditor/CellValidationMessage.tsx
1644
1707
  import { useSignals as _useSignals5 } from "@preact-signals/safe-react/tracking";
1645
- import React5, { useCallback as useCallback3, useEffect as useEffect2, useMemo as useMemo3, useRef } from "react";
1646
- import { getSnapshot } from "@dxos/echo-schema";
1708
+ import React5 from "react";
1709
+ import { useGridContext as useGridContext2 } from "@dxos/react-ui-grid";
1710
+ var CellValidationMessage = ({ validationError, __gridScope }) => {
1711
+ var _effect = _useSignals5();
1712
+ try {
1713
+ const { editing, editBox: box } = useGridContext2("GridSheetCellEditor", __gridScope);
1714
+ if (!editing || !validationError) {
1715
+ return null;
1716
+ }
1717
+ return /* @__PURE__ */ React5.createElement("div", {
1718
+ role: "none",
1719
+ className: "absolute bg-errorSurface text-errorSurfaceText rounded-bs-sm text-xs p-1",
1720
+ style: {
1721
+ ...{
1722
+ "--dx-gridCellWidth": `${box?.inlineSize ?? 200}px`
1723
+ },
1724
+ zIndex: 10,
1725
+ insetBlockEnd: `calc(100% - ${box.insetBlockStart}px)`,
1726
+ insetInlineStart: box.insetInlineStart,
1727
+ inlineSize: box.inlineSize
1728
+ }
1729
+ }, validationError);
1730
+ } finally {
1731
+ _effect.f();
1732
+ }
1733
+ };
1734
+
1735
+ // packages/ui/react-ui-table/src/components/TableCellEditor/FormCellEditor.tsx
1736
+ import { useSignals as _useSignals6 } from "@preact-signals/safe-react/tracking";
1737
+ import React6, { useCallback as useCallback3, useEffect as useEffect2, useMemo as useMemo3, useRef } from "react";
1738
+ import { getSnapshot as getSnapshot2 } from "@dxos/echo-schema";
1647
1739
  import { invariant as invariant2 } from "@dxos/invariant";
1648
1740
  import { Popover as Popover3 } from "@dxos/react-ui";
1649
1741
  import { Form as Form2 } from "@dxos/react-ui-form";
1650
- import { parseCellIndex, useGridContext as useGridContext2 } from "@dxos/react-ui-grid";
1742
+ import { parseCellIndex, useGridContext as useGridContext3 } from "@dxos/react-ui-grid";
1651
1743
  import { getDeep, setDeep } from "@dxos/util";
1652
1744
  var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/TableCellEditor/FormCellEditor.tsx";
1653
1745
  var FormCellEditor = ({ fieldProjection, model, schema, __gridScope }) => {
1654
- var _effect = _useSignals5();
1746
+ var _effect = _useSignals6();
1655
1747
  try {
1656
- const { editing, setEditing } = useGridContext2("ArrayEditor", __gridScope);
1748
+ const { editing, setEditing } = useGridContext3("ArrayEditor", __gridScope);
1657
1749
  const cellRef = useRef(null);
1658
1750
  useEffect2(() => {
1659
1751
  if (editing && editing.cellElement) {
@@ -1695,7 +1787,7 @@ var FormCellEditor = ({ fieldProjection, model, schema, __gridScope }) => {
1695
1787
  ]);
1696
1788
  const formValues = useMemo3(() => {
1697
1789
  if (originalRow) {
1698
- return getSnapshot(originalRow);
1790
+ return getSnapshot2(originalRow);
1699
1791
  }
1700
1792
  }, [
1701
1793
  originalRow
@@ -1723,15 +1815,15 @@ var FormCellEditor = ({ fieldProjection, model, schema, __gridScope }) => {
1723
1815
  if (!editing) {
1724
1816
  return null;
1725
1817
  }
1726
- return /* @__PURE__ */ React5.createElement(Popover3.Root, {
1818
+ return /* @__PURE__ */ React6.createElement(Popover3.Root, {
1727
1819
  open: editing !== null,
1728
1820
  onOpenChange: handleOpenChange
1729
- }, /* @__PURE__ */ React5.createElement(Popover3.VirtualTrigger, {
1821
+ }, /* @__PURE__ */ React6.createElement(Popover3.VirtualTrigger, {
1730
1822
  virtualRef: cellRef
1731
- }), /* @__PURE__ */ React5.createElement(Popover3.Content, {
1823
+ }), /* @__PURE__ */ React6.createElement(Popover3.Content, {
1732
1824
  tabIndex: -1,
1733
1825
  classNames: "popover-card-width"
1734
- }, /* @__PURE__ */ React5.createElement(Popover3.Arrow, null), /* @__PURE__ */ React5.createElement(Popover3.Viewport, null, /* @__PURE__ */ React5.createElement(Form2, {
1826
+ }, /* @__PURE__ */ React6.createElement(Popover3.Arrow, null), /* @__PURE__ */ React6.createElement(Popover3.Viewport, null, /* @__PURE__ */ React6.createElement(Form2, {
1735
1827
  values: formValues,
1736
1828
  schema: narrowedSchema,
1737
1829
  onSave: handleSave
@@ -1789,9 +1881,9 @@ var createOption = (text) => ({
1789
1881
  });
1790
1882
  var isCreateOption = (data) => typeof data === "object" && data[newValue];
1791
1883
  var TableValueEditor = ({ model, modals, schema, onEnter, onFocus, onQuery, __gridScope }) => {
1792
- var _effect = _useSignals6();
1884
+ var _effect = _useSignals7();
1793
1885
  try {
1794
- const { editing } = useGridContext3("TableValueEditor", __gridScope);
1886
+ const { editing } = useGridContext4("TableValueEditor", __gridScope);
1795
1887
  const fieldProjection = useMemo4(() => {
1796
1888
  if (!model || !editing) {
1797
1889
  return;
@@ -1801,7 +1893,7 @@ var TableValueEditor = ({ model, modals, schema, onEnter, onFocus, onQuery, __gr
1801
1893
  const fieldProjection2 = model.projection.getFieldProjection(field.id);
1802
1894
  invariant3(fieldProjection2, void 0, {
1803
1895
  F: __dxlog_file4,
1804
- L: 73,
1896
+ L: 74,
1805
1897
  S: void 0,
1806
1898
  A: [
1807
1899
  "fieldProjection",
@@ -1814,14 +1906,14 @@ var TableValueEditor = ({ model, modals, schema, onEnter, onFocus, onQuery, __gr
1814
1906
  editing
1815
1907
  ]);
1816
1908
  if (fieldProjection?.props.type === TypeEnum4.Array) {
1817
- return /* @__PURE__ */ React6.createElement(FormCellEditor, {
1909
+ return /* @__PURE__ */ React7.createElement(FormCellEditor, {
1818
1910
  fieldProjection,
1819
1911
  model,
1820
1912
  schema,
1821
1913
  __gridScope
1822
1914
  });
1823
1915
  }
1824
- return /* @__PURE__ */ React6.createElement(TableCellEditor, {
1916
+ return /* @__PURE__ */ React7.createElement(TableCellEditor, {
1825
1917
  model,
1826
1918
  modals,
1827
1919
  onEnter,
@@ -1834,11 +1926,12 @@ var TableValueEditor = ({ model, modals, schema, onEnter, onFocus, onQuery, __gr
1834
1926
  }
1835
1927
  };
1836
1928
  var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }) => {
1837
- var _effect = _useSignals6();
1929
+ var _effect = _useSignals7();
1838
1930
  try {
1839
- const { id: gridId, editing, setEditing } = useGridContext3("TableCellEditor", __gridScope);
1931
+ const { id: gridId, editing, setEditing } = useGridContext4("TableCellEditor", __gridScope);
1840
1932
  const suppressNextBlur = useRef2(false);
1841
1933
  const { themeMode } = useThemeContext();
1934
+ const [_validationError, setValidationError] = useState2(null);
1842
1935
  const fieldProjection = useMemo4(() => {
1843
1936
  if (!model || !editing) {
1844
1937
  return;
@@ -1848,7 +1941,7 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }
1848
1941
  const fieldProjection2 = model.projection.getFieldProjection(field.id);
1849
1942
  invariant3(fieldProjection2, void 0, {
1850
1943
  F: __dxlog_file4,
1851
- L: 114,
1944
+ L: 116,
1852
1945
  S: void 0,
1853
1946
  A: [
1854
1947
  "fieldProjection",
@@ -1860,15 +1953,21 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }
1860
1953
  model,
1861
1954
  editing
1862
1955
  ]);
1863
- const handleEnter = useCallback4((value) => {
1956
+ const handleEnter = useCallback4(async (value) => {
1864
1957
  if (!model || !editing) {
1865
1958
  return;
1866
1959
  }
1867
1960
  const cell = parseCellIndex2(editing.index);
1868
- model.setCellData(cell, value);
1869
- onEnter?.(cell);
1870
- onFocus?.();
1871
- setEditing(null);
1961
+ const result = await model.validateCellData(cell, value);
1962
+ if (result.valid) {
1963
+ setValidationError(null);
1964
+ model.setCellData(cell, value);
1965
+ onEnter?.(cell);
1966
+ onFocus?.();
1967
+ setEditing(null);
1968
+ } else {
1969
+ setValidationError(result.error);
1970
+ }
1872
1971
  }, [
1873
1972
  model,
1874
1973
  editing,
@@ -1876,37 +1975,49 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }
1876
1975
  onFocus,
1877
1976
  setEditing
1878
1977
  ]);
1879
- const handleBlur = useCallback4((value) => {
1978
+ const handleBlur = useCallback4(async (value) => {
1880
1979
  if (!model || !editing) {
1881
1980
  return;
1882
1981
  }
1883
1982
  if (suppressNextBlur.current) {
1884
1983
  suppressNextBlur.current = false;
1885
- return;
1886
- }
1887
- const cell = parseCellIndex2(editing.index);
1888
- if (value !== void 0) {
1889
- model.setCellData(cell, value);
1890
1984
  }
1891
1985
  }, [
1892
1986
  model,
1893
1987
  editing
1894
1988
  ]);
1895
- const handleClose = useCallback4((value, event) => {
1989
+ const handleClose = useCallback4(async (value, event) => {
1896
1990
  if (!model || !editing || !fieldProjection) {
1897
1991
  return;
1898
1992
  }
1899
1993
  const cell = parseCellIndex2(editing.index);
1900
- onEnter?.(cell);
1901
- if (event && onFocus) {
1902
- onFocus(determineNavigationAxis(event), determineNavigationDelta(event));
1994
+ if (value !== void 0) {
1995
+ const result = await model.validateCellData(cell, value);
1996
+ if (result.valid) {
1997
+ setValidationError(null);
1998
+ model.setCellData(cell, value);
1999
+ setEditing(null);
2000
+ onEnter?.(cell);
2001
+ if (event && onFocus) {
2002
+ onFocus(determineNavigationAxis(event), determineNavigationDelta(event));
2003
+ }
2004
+ } else {
2005
+ setValidationError(result.error);
2006
+ }
2007
+ } else {
2008
+ setValidationError(null);
2009
+ setEditing(null);
2010
+ if (event && onFocus) {
2011
+ onFocus(determineNavigationAxis(event), determineNavigationDelta(event));
2012
+ }
1903
2013
  }
1904
2014
  }, [
1905
2015
  model,
1906
2016
  editing,
1907
2017
  onFocus,
1908
2018
  onEnter,
1909
- fieldProjection
2019
+ fieldProjection,
2020
+ setEditing
1910
2021
  ]);
1911
2022
  const extension = useMemo4(() => {
1912
2023
  if (!fieldProjection) {
@@ -1943,9 +2054,9 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }
1943
2054
  return;
1944
2055
  }
1945
2056
  if (mode === "single-select") {
1946
- handleEnter(ids[0]);
2057
+ void handleEnter(ids[0]);
1947
2058
  } else {
1948
- handleEnter(ids);
2059
+ void handleEnter(ids);
1949
2060
  }
1950
2061
  }
1951
2062
  }
@@ -1966,11 +2077,11 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }
1966
2077
  modals.openCreateRef(props.referenceSchema, document.querySelector(cellQuery(editing.index, gridId)), {
1967
2078
  [field.referencePath]: data.text
1968
2079
  }, (data2) => {
1969
- handleEnter(data2);
2080
+ void handleEnter(data2);
1970
2081
  });
1971
2082
  }
1972
2083
  } else {
1973
- handleEnter(data);
2084
+ void handleEnter(data);
1974
2085
  }
1975
2086
  }
1976
2087
  }
@@ -2035,11 +2146,14 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }
2035
2146
  model,
2036
2147
  editing
2037
2148
  ]);
2038
- return /* @__PURE__ */ React6.createElement(GridCellEditor, {
2149
+ return /* @__PURE__ */ React7.createElement(React7.Fragment, null, /* @__PURE__ */ React7.createElement(CellValidationMessage, {
2150
+ validationError: _validationError,
2151
+ __gridScope
2152
+ }), /* @__PURE__ */ React7.createElement(GridCellEditor, {
2039
2153
  extension,
2040
2154
  getCellContent,
2041
2155
  onBlur: handleBlur
2042
- });
2156
+ }));
2043
2157
  } finally {
2044
2158
  _effect.f();
2045
2159
  }
@@ -2072,9 +2186,9 @@ var determineNavigationDelta = ({ key, shift }) => {
2072
2186
  // packages/ui/react-ui-table/src/components/Table/Table.tsx
2073
2187
  var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/Table/Table.tsx";
2074
2188
  var TableRoot = ({ children, role }) => {
2075
- var _effect = _useSignals7();
2189
+ var _effect = _useSignals8();
2076
2190
  try {
2077
- return /* @__PURE__ */ React7.createElement("div", {
2191
+ return /* @__PURE__ */ React8.createElement("div", {
2078
2192
  role: "none",
2079
2193
  className: mx2("relative !border-separator", role === "section" ? "attention-surface overflow-hidden [&_.dx-grid]:max-is-[--dx-grid-content-inline-size]" : "flex flex-col [&_.dx-grid]:grow [&_.dx-grid]:max-is-[--dx-grid-content-inline-size] [&_.dx-grid]:bs-0 [&_.dx-grid]:max-bs-[--dx-grid-content-block-size]")
2080
2194
  }, children);
@@ -2082,10 +2196,10 @@ var TableRoot = ({ children, role }) => {
2082
2196
  _effect.f();
2083
2197
  }
2084
2198
  };
2085
- var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttention, schema, onRowClick }, forwardedRef) => {
2086
- var _effect = _useSignals7();
2199
+ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttention, schema, client, onRowClick }, forwardedRef) => {
2200
+ var _effect = _useSignals8();
2087
2201
  try {
2088
- const [dxGrid, setDxGrid] = useState2(null);
2202
+ const [dxGrid, setDxGrid] = useState3(null);
2089
2203
  const { hasAttention } = useAttention(model?.id ?? "table");
2090
2204
  const { t } = useTranslation3(translationKey);
2091
2205
  const modals = useMemo5(() => new ModalController(), []);
@@ -2277,14 +2391,20 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
2277
2391
  const space = model.space;
2278
2392
  invariant4(space, void 0, {
2279
2393
  F: __dxlog_file5,
2280
- L: 309,
2394
+ L: 311,
2281
2395
  S: void 0,
2282
2396
  A: [
2283
2397
  "space",
2284
2398
  ""
2285
2399
  ]
2286
2400
  });
2287
- const schema2 = space.db.schemaRegistry.getSchema(props.referenceSchema);
2401
+ let schema2;
2402
+ if (client) {
2403
+ schema2 = client.graph.schemaRegistry.getSchema(props.referenceSchema);
2404
+ }
2405
+ if (!schema2) {
2406
+ schema2 = space.db.schemaRegistry.getSchema(props.referenceSchema);
2407
+ }
2288
2408
  if (schema2) {
2289
2409
  const { objects } = await space.db.query(Filter.type(schema2)).run();
2290
2410
  const options = objects.map((obj) => {
@@ -2311,24 +2431,25 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
2311
2431
  return [];
2312
2432
  }, [
2313
2433
  model,
2434
+ client,
2314
2435
  t
2315
2436
  ]);
2316
2437
  if (!model || !modals) {
2317
- return /* @__PURE__ */ React7.createElement("span", {
2438
+ return /* @__PURE__ */ React8.createElement("span", {
2318
2439
  role: "none",
2319
2440
  className: "attention-surface"
2320
2441
  });
2321
2442
  }
2322
- return /* @__PURE__ */ React7.createElement(Grid.Root, {
2443
+ return /* @__PURE__ */ React8.createElement(Grid.Root, {
2323
2444
  id: model.id ?? "table-grid"
2324
- }, /* @__PURE__ */ React7.createElement(TableValueEditor, {
2445
+ }, /* @__PURE__ */ React8.createElement(TableValueEditor, {
2325
2446
  model,
2326
2447
  modals,
2327
2448
  schema,
2328
2449
  onEnter: handleEnter,
2329
2450
  onFocus: handleFocus,
2330
2451
  onQuery: handleQuery
2331
- }), /* @__PURE__ */ React7.createElement(Grid.Content, {
2452
+ }), /* @__PURE__ */ React8.createElement(Grid.Content, {
2332
2453
  className: mx2("[--dx-grid-base:var(--baseSurface)]", gridSeparatorInlineEnd, gridSeparatorBlockEnd),
2333
2454
  frozen,
2334
2455
  // getCells={getCells}
@@ -2341,17 +2462,17 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
2341
2462
  onKeyDown: handleKeyDown,
2342
2463
  onWheelCapture: handleWheel,
2343
2464
  ref: setDxGrid
2344
- }), /* @__PURE__ */ React7.createElement(RowActionsMenu, {
2465
+ }), /* @__PURE__ */ React8.createElement(RowActionsMenu, {
2345
2466
  model,
2346
2467
  modals
2347
- }), /* @__PURE__ */ React7.createElement(ColumnActionsMenu, {
2468
+ }), /* @__PURE__ */ React8.createElement(ColumnActionsMenu, {
2348
2469
  model,
2349
2470
  modals
2350
- }), /* @__PURE__ */ React7.createElement(ColumnSettings, {
2471
+ }), /* @__PURE__ */ React8.createElement(ColumnSettings, {
2351
2472
  model,
2352
2473
  modals,
2353
2474
  onNewColumn: handleNewColumn
2354
- }), /* @__PURE__ */ React7.createElement(CreateRefPanel, {
2475
+ }), /* @__PURE__ */ React8.createElement(CreateRefPanel, {
2355
2476
  model,
2356
2477
  modals
2357
2478
  }));
@@ -2365,22 +2486,23 @@ var Table = {
2365
2486
  };
2366
2487
 
2367
2488
  // packages/ui/react-ui-table/src/components/Table/DynamicTable.tsx
2368
- import { useSignals as _useSignals9 } from "@preact-signals/safe-react/tracking";
2369
- import React8, { useRef as useRef3, useMemo as useMemo6, useCallback as useCallback6 } from "react";
2489
+ import { useSignals as _useSignals10 } from "@preact-signals/safe-react/tracking";
2490
+ import React9, { useRef as useRef3, useMemo as useMemo6, useCallback as useCallback6 } from "react";
2370
2491
  import { useDefaultValue } from "@dxos/react-ui";
2371
2492
  import { mx as mx3 } from "@dxos/react-ui-theme";
2372
2493
 
2373
2494
  // packages/ui/react-ui-table/src/hooks/useTableModel.ts
2374
- import { useSignals as _useSignals8 } from "@preact-signals/safe-react/tracking";
2495
+ import { useSignals as _useSignals9 } from "@preact-signals/safe-react/tracking";
2375
2496
  import { effect as effect3 } from "@preact/signals-core";
2376
- import { useEffect as useEffect4, useState as useState3 } from "react";
2497
+ import orderBy2 from "lodash.orderby";
2498
+ import { useEffect as useEffect4, useState as useState4 } from "react";
2377
2499
  import { fullyQualifiedId, getSpace } from "@dxos/react-client/echo";
2378
2500
  import { useSelectionActions } from "@dxos/react-ui-attention";
2379
2501
  import { isNonNullable } from "@dxos/util";
2380
2502
  var useTableModel = ({ table, projection, rows, rowActions, features, onSelectionChanged, onRowAction, ...props }) => {
2381
- var _effect = _useSignals8();
2503
+ var _effect = _useSignals9();
2382
2504
  try {
2383
- const [model, setModel] = useState3();
2505
+ const [model, setModel] = useState4();
2384
2506
  useEffect4(() => {
2385
2507
  if (!table || !projection) {
2386
2508
  return;
@@ -2413,7 +2535,12 @@ var useTableModel = ({ table, projection, rows, rowActions, features, onSelectio
2413
2535
  ]);
2414
2536
  useEffect4(() => {
2415
2537
  if (rows) {
2416
- model?.setRows(rows);
2538
+ const sortedRows = orderBy2(rows, [
2539
+ (row) => String(row.id)
2540
+ ], [
2541
+ "asc"
2542
+ ]);
2543
+ model?.setRows(sortedRows);
2417
2544
  }
2418
2545
  }, [
2419
2546
  model,
@@ -2450,7 +2577,7 @@ var useTableModel = ({ table, projection, rows, rowActions, features, onSelectio
2450
2577
 
2451
2578
  // packages/ui/react-ui-table/src/components/Table/DynamicTable.tsx
2452
2579
  var DynamicTable = ({ classNames, name = "example.com/dynamic-table", rows, properties, jsonSchema, schema, rowActions, onRowClick, onRowAction, ...props }) => {
2453
- var _effect = _useSignals9();
2580
+ var _effect = _useSignals10();
2454
2581
  try {
2455
2582
  const { table, projection } = useMemo6(() => {
2456
2583
  const props2 = getBaseSchema({
@@ -2499,13 +2626,13 @@ var DynamicTable = ({ classNames, name = "example.com/dynamic-table", rows, prop
2499
2626
  }, [
2500
2627
  model
2501
2628
  ]);
2502
- return /* @__PURE__ */ React8.createElement("div", {
2629
+ return /* @__PURE__ */ React9.createElement("div", {
2503
2630
  role: "none",
2504
2631
  className: mx3("is-full bs-full grow grid", classNames)
2505
- }, /* @__PURE__ */ React8.createElement("div", {
2632
+ }, /* @__PURE__ */ React9.createElement("div", {
2506
2633
  role: "none",
2507
2634
  className: "grid min-bs-0 overflow-hidden"
2508
- }, /* @__PURE__ */ React8.createElement(Table.Root, null, /* @__PURE__ */ React8.createElement(Table.Main, {
2635
+ }, /* @__PURE__ */ React9.createElement(Table.Root, null, /* @__PURE__ */ React9.createElement(Table.Main, {
2509
2636
  ref: tableRef,
2510
2637
  model,
2511
2638
  presentation,
@@ -2518,10 +2645,10 @@ var DynamicTable = ({ classNames, name = "example.com/dynamic-table", rows, prop
2518
2645
  };
2519
2646
 
2520
2647
  // packages/ui/react-ui-table/src/components/TableToolbar/TableToolbar.tsx
2521
- import { useSignals as _useSignals10 } from "@preact-signals/safe-react/tracking";
2648
+ import { useSignals as _useSignals11 } from "@preact-signals/safe-react/tracking";
2522
2649
  import { Rx } from "@effect-rx/rx-react";
2523
- import React9, { useMemo as useMemo7 } from "react";
2524
- import { live as live4 } from "@dxos/live-object";
2650
+ import React10, { useMemo as useMemo7 } from "react";
2651
+ import { live as live3 } from "@dxos/live-object";
2525
2652
  import { createGapSeparator, createMenuAction, MenuProvider, ToolbarMenu, useMenuActions } from "@dxos/react-ui-menu";
2526
2653
  import { rxFromSignal } from "@dxos/react-ui-menu";
2527
2654
  var createTableToolbarActions = ({ state, onAdd, onSave, customActions }) => Rx.make((get) => {
@@ -2570,9 +2697,9 @@ var createTableToolbarActions = ({ state, onAdd, onSave, customActions }) => Rx.
2570
2697
  };
2571
2698
  });
2572
2699
  var TableToolbar = ({ classNames, viewDirty, attendableId, onAdd, onSave, customActions }) => {
2573
- var _effect = _useSignals10();
2700
+ var _effect = _useSignals11();
2574
2701
  try {
2575
- const state = useMemo7(() => live4({
2702
+ const state = useMemo7(() => live3({
2576
2703
  viewDirty
2577
2704
  }), []);
2578
2705
  const actionsCreator = useMemo7(() => createTableToolbarActions({
@@ -2587,10 +2714,10 @@ var TableToolbar = ({ classNames, viewDirty, attendableId, onAdd, onSave, custom
2587
2714
  customActions
2588
2715
  ]);
2589
2716
  const menu = useMenuActions(actionsCreator);
2590
- return /* @__PURE__ */ React9.createElement(MenuProvider, {
2717
+ return /* @__PURE__ */ React10.createElement(MenuProvider, {
2591
2718
  ...menu,
2592
2719
  attendableId
2593
- }, /* @__PURE__ */ React9.createElement(ToolbarMenu, {
2720
+ }, /* @__PURE__ */ React10.createElement(ToolbarMenu, {
2594
2721
  classNames
2595
2722
  }));
2596
2723
  } finally {