@dxos/react-ui-table 0.7.5-main.9d26e3a → 0.7.5-main.e9bb01b

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 (70) hide show
  1. package/dist/lib/browser/{chunk-AT7O4RAD.mjs → chunk-T7CTRLHA.mjs} +2 -2
  2. package/dist/lib/browser/{chunk-AT7O4RAD.mjs.map → chunk-T7CTRLHA.mjs.map} +1 -1
  3. package/dist/lib/browser/index.mjs +446 -282
  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-YSBXNBDJ.cjs → chunk-XQRKYO7Q.cjs} +6 -6
  8. package/dist/lib/node/chunk-XQRKYO7Q.cjs.map +7 -0
  9. package/dist/lib/node/index.cjs +438 -268
  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-6OH2NHUX.mjs → chunk-6HE6MLBK.mjs} +2 -2
  15. package/dist/lib/node-esm/{chunk-6OH2NHUX.mjs.map → chunk-6HE6MLBK.mjs.map} +1 -1
  16. package/dist/lib/node-esm/index.mjs +446 -282
  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/Table.d.ts.map +1 -1
  21. package/dist/types/src/components/Table/Table.stories.d.ts +1 -4
  22. package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
  23. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts +18 -0
  24. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts.map +1 -0
  25. package/dist/types/src/components/TableToolbar/index.d.ts +2 -0
  26. package/dist/types/src/components/TableToolbar/index.d.ts.map +1 -0
  27. package/dist/types/src/components/index.d.ts +1 -1
  28. package/dist/types/src/components/index.d.ts.map +1 -1
  29. package/dist/types/src/components/testing.d.ts +1 -1
  30. package/dist/types/src/model/table-model.d.ts +11 -19
  31. package/dist/types/src/model/table-model.d.ts.map +1 -1
  32. package/dist/types/src/model/table-presentation.d.ts.map +1 -1
  33. package/dist/types/src/model/table-sorting.d.ts +53 -0
  34. package/dist/types/src/model/table-sorting.d.ts.map +1 -0
  35. package/dist/types/src/translations.d.ts +2 -1
  36. package/dist/types/src/translations.d.ts.map +1 -1
  37. package/dist/types/src/types/table.d.ts +3 -3
  38. package/dist/types/src/types/table.d.ts.map +1 -1
  39. package/dist/types/src/util/table-buttons.d.ts +15 -1
  40. package/dist/types/src/util/table-buttons.d.ts.map +1 -1
  41. package/dist/types/src/util/table.d.ts +2 -1
  42. package/dist/types/src/util/table.d.ts.map +1 -1
  43. package/dist/types/tsconfig.tsbuildinfo +1 -1
  44. package/package.json +35 -34
  45. package/src/_deprecated/schema/Schema.stories.tsx +1 -1
  46. package/src/components/Table/ColumnActionsMenu.tsx +4 -4
  47. package/src/components/Table/Table.stories.tsx +52 -40
  48. package/src/components/Table/Table.tsx +4 -0
  49. package/src/components/TableToolbar/TableToolbar.tsx +72 -0
  50. package/src/components/{Toolbar → TableToolbar}/index.ts +1 -1
  51. package/src/components/index.ts +1 -1
  52. package/src/model/table-model.test.ts +0 -5
  53. package/src/model/table-model.ts +40 -98
  54. package/src/model/table-presentation.ts +25 -4
  55. package/src/model/table-sorting.ts +215 -0
  56. package/src/playwright/smoke.spec.ts +18 -11
  57. package/src/translations.ts +2 -1
  58. package/src/types/table.ts +1 -1
  59. package/src/util/table-buttons.ts +33 -3
  60. package/src/util/table-controls.ts +2 -2
  61. package/src/util/table.ts +78 -52
  62. package/dist/lib/node/chunk-YSBXNBDJ.cjs.map +0 -7
  63. package/dist/types/src/components/Toolbar/Toolbar.d.ts +0 -21
  64. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +0 -1
  65. package/dist/types/src/components/Toolbar/common.d.ts +0 -14
  66. package/dist/types/src/components/Toolbar/common.d.ts.map +0 -1
  67. package/dist/types/src/components/Toolbar/index.d.ts +0 -2
  68. package/dist/types/src/components/Toolbar/index.d.ts.map +0 -1
  69. package/src/components/Toolbar/Toolbar.tsx +0 -87
  70. package/src/components/Toolbar/common.tsx +0 -71
@@ -34,9 +34,9 @@ __export(node_exports, {
34
34
  Table: () => Table,
35
35
  TableModel: () => TableModel,
36
36
  TablePresentation: () => TablePresentation,
37
- TableSchema: () => import_chunk_YSBXNBDJ.TableSchema,
38
- TableType: () => import_chunk_YSBXNBDJ.TableType,
39
- Toolbar: () => Toolbar,
37
+ TableSchema: () => import_chunk_XQRKYO7Q.TableSchema,
38
+ TableToolbar: () => TableToolbar,
39
+ TableType: () => import_chunk_XQRKYO7Q.TableType,
40
40
  initializeTable: () => initializeTable,
41
41
  renderCheckbox: () => renderCheckbox,
42
42
  renderSwitch: () => renderSwitch,
@@ -44,11 +44,10 @@ __export(node_exports, {
44
44
  tableControls: () => tableControls,
45
45
  touch: () => touch,
46
46
  translations: () => translations_default,
47
- useTableModel: () => useTableModel,
48
- useToolbarContext: () => useToolbarContext
47
+ useTableModel: () => useTableModel
49
48
  });
50
49
  module.exports = __toCommonJS(node_exports);
51
- var import_chunk_YSBXNBDJ = require("./chunk-YSBXNBDJ.cjs");
50
+ var import_chunk_XQRKYO7Q = require("./chunk-XQRKYO7Q.cjs");
52
51
  var import_react = __toESM(require("react"));
53
52
  var import_echo_schema = require("@dxos/echo-schema");
54
53
  var import_invariant = require("@dxos/invariant");
@@ -77,7 +76,6 @@ var import_react_ui_form3 = require("@dxos/react-ui-form");
77
76
  var import_react6 = __toESM(require("react"));
78
77
  var import_react_ui6 = require("@dxos/react-ui");
79
78
  var import_signals_core = require("@preact/signals-core");
80
- var import_lodash = __toESM(require("lodash.orderby"));
81
79
  var import_context = require("@dxos/context");
82
80
  var import_echo_schema3 = require("@dxos/echo-schema");
83
81
  var import_invariant2 = require("@dxos/invariant");
@@ -87,30 +85,31 @@ var import_react_ui_form4 = require("@dxos/react-ui-form");
87
85
  var import_signals_core2 = require("@preact/signals-core");
88
86
  var import_context2 = require("@dxos/context");
89
87
  var import_echo_schema4 = require("@dxos/echo-schema");
90
- var import_log = require("@dxos/log");
91
88
  var import_react_client2 = require("@dxos/react-client");
92
89
  var import_echo5 = require("@dxos/react-client/echo");
93
90
  var import_schema = require("@dxos/schema");
94
91
  var import_signals_core3 = require("@preact/signals-core");
95
- var import_log2 = require("@dxos/log");
96
- var import_signals_core4 = require("@preact/signals-core");
92
+ var import_lodash = __toESM(require("lodash.orderby"));
97
93
  var import_echo_schema5 = require("@dxos/echo-schema");
98
94
  var import_react_ui_form5 = require("@dxos/react-ui-form");
95
+ var import_signals_core4 = require("@preact/signals-core");
96
+ var import_log = require("@dxos/log");
97
+ var import_signals_core5 = require("@preact/signals-core");
98
+ var import_echo_schema6 = require("@dxos/echo-schema");
99
+ var import_react_ui_form6 = require("@dxos/react-ui-form");
99
100
  var import_react_ui_grid3 = require("@dxos/react-ui-grid");
100
101
  var import_react_ui_theme2 = require("@dxos/react-ui-theme");
101
102
  var import_schema2 = require("@dxos/schema");
102
103
  var import_react7 = __toESM(require("react"));
103
- var import_echo_schema6 = require("@dxos/echo-schema");
104
+ var import_echo_schema7 = require("@dxos/echo-schema");
104
105
  var import_invariant3 = require("@dxos/invariant");
105
106
  var import_react_ui_grid4 = require("@dxos/react-ui-grid");
106
107
  var import_autocomplete = require("@codemirror/autocomplete");
107
108
  var import_view = require("@codemirror/view");
108
- var import_react_context = require("@radix-ui/react-context");
109
109
  var import_react8 = __toESM(require("react"));
110
- var import_react_ui7 = require("@dxos/react-ui");
111
- var import_react9 = __toESM(require("react"));
112
- var import_react_ui8 = require("@dxos/react-ui");
113
- var import_react10 = require("react");
110
+ var import_live_object2 = require("@dxos/live-object");
111
+ var import_react_ui_menu = require("@dxos/react-ui-menu");
112
+ var import_react9 = require("react");
114
113
  var translationKey = "table";
115
114
  var translations_default = [
116
115
  {
@@ -124,7 +123,7 @@ var translations_default = [
124
123
  "new schema": "New schema",
125
124
  "continue label": "Continue",
126
125
  "create stack section label": "Create table",
127
- "add row": "Add row",
126
+ "add row label": "Add row",
128
127
  "create comment": "Create thread",
129
128
  "column action sort descending": "Sort Descending",
130
129
  "column action sort ascending": "Sort Ascending",
@@ -135,7 +134,8 @@ var translations_default = [
135
134
  "bulk delete row label": "Delete selected rows",
136
135
  "column deleted label": "Column deleted",
137
136
  "new column button label": "Create column",
138
- "create new object label": "Create new object \u201C{{text}}\u201D"
137
+ "create new object label": "Create new object \u201C{{text}}\u201D",
138
+ "save view label": "Save changes to view"
139
139
  }
140
140
  }
141
141
  }
@@ -146,7 +146,7 @@ var ColumnActionsMenu = ({ model, modals }) => {
146
146
  if (state?.type !== "column") {
147
147
  return null;
148
148
  }
149
- const currentSort = model.sorting;
149
+ const currentSort = model.sorting?.sorting;
150
150
  const isCurrentColumnSorted = currentSort?.fieldId === state.fieldId;
151
151
  return /* @__PURE__ */ import_react2.default.createElement(import_react_ui2.DropdownMenu.Root, {
152
152
  modal: false,
@@ -156,13 +156,13 @@ var ColumnActionsMenu = ({ model, modals }) => {
156
156
  virtualRef: modals.trigger
157
157
  }), /* @__PURE__ */ import_react2.default.createElement(import_react_ui2.DropdownMenu.Portal, null, /* @__PURE__ */ import_react2.default.createElement(import_react_ui2.DropdownMenu.Content, null, /* @__PURE__ */ import_react2.default.createElement(import_react_ui2.DropdownMenu.Viewport, null, (!isCurrentColumnSorted || currentSort?.direction === "asc") && /* @__PURE__ */ import_react2.default.createElement(import_react_ui2.DropdownMenu.Item, {
158
158
  "data-testid": "column-sort-descending",
159
- onClick: () => model.setSort(state.fieldId, "desc")
159
+ onClick: () => model.sorting?.setSort(state.fieldId, "desc")
160
160
  }, t("column action sort descending")), (!isCurrentColumnSorted || currentSort?.direction === "desc") && /* @__PURE__ */ import_react2.default.createElement(import_react_ui2.DropdownMenu.Item, {
161
161
  "data-testid": "column-sort-ascending",
162
- onClick: () => model.setSort(state.fieldId, "asc")
162
+ onClick: () => model.sorting?.setSort(state.fieldId, "asc")
163
163
  }, t("column action sort ascending")), isCurrentColumnSorted && /* @__PURE__ */ import_react2.default.createElement(import_react_ui2.DropdownMenu.Item, {
164
164
  "data-testid": "column-clear-sort",
165
- onClick: () => model.clearSort()
165
+ onClick: () => model.sorting?.clearSort()
166
166
  }, t("column action clear sorting")), model.getColumnCount() > 1 && /* @__PURE__ */ import_react2.default.createElement(import_react_ui2.DropdownMenu.Item, {
167
167
  "data-testid": "column-delete",
168
168
  onClick: () => model.deleteColumn(state.fieldId)
@@ -352,79 +352,90 @@ var RowActionsMenu = ({ model, modals }) => {
352
352
  }, t(hasSelection ? "bulk delete row label" : "delete row label"))), /* @__PURE__ */ import_react6.default.createElement(import_react_ui6.DropdownMenu.Arrow, null)));
353
353
  };
354
354
  var touch = (value) => value;
355
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/util/table.ts";
356
- var initializeTable = async ({ space, table, initialRow = true }) => {
357
- (0, import_log.log)("initializeTable", {
358
- table
359
- }, {
360
- F: __dxlog_file,
361
- L: 36,
362
- S: void 0,
363
- C: (f, a) => f(...a)
364
- });
365
- const ContactSchema = (0, import_echo_schema4.TypedObject)({
366
- typename: `example.com/type/${import_react_client2.PublicKey.random().truncate()}`,
367
- version: "0.1.0"
368
- })({
369
- name: import_echo_schema4.S.optional(import_echo_schema4.S.String).annotations({
370
- [import_echo_schema4.AST.TitleAnnotationId]: "Name"
371
- }),
372
- active: import_echo_schema4.S.optional(import_echo_schema4.S.Boolean),
373
- email: import_echo_schema4.S.optional(import_echo_schema4.Format.Email),
374
- salary: import_echo_schema4.S.optional(import_echo_schema4.Format.Currency()).annotations({
375
- [import_echo_schema4.AST.TitleAnnotationId]: "Salary"
376
- })
377
- });
378
- const [contactSchema] = await space.db.schemaRegistry.register([
379
- ContactSchema
380
- ]);
381
- table.view = (0, import_echo5.makeRef)((0, import_schema.createView)({
382
- name: "Test",
383
- typename: contactSchema.typename,
384
- jsonSchema: contactSchema.jsonSchema,
385
- fields: [
386
- "name",
387
- "active",
388
- "email",
389
- "salary"
390
- ]
391
- }));
392
- const projection = new import_schema.ViewProjection(contactSchema, table.view.target);
393
- projection.setFieldProjection({
394
- field: {
395
- id: table.view.target.fields.find((f) => f.path === "salary").id,
396
- path: "salary",
397
- size: 150
355
+ var initializeTable = async ({ space, table, initialRow = true, initialSchema }) => {
356
+ if (initialSchema) {
357
+ const schema = await space.db.schemaRegistry.query({
358
+ typename: initialSchema
359
+ }).firstOrUndefined();
360
+ if (!schema) {
361
+ throw new Error(`Schema not found: ${initialSchema}`);
398
362
  }
399
- });
400
- projection.setFieldProjection({
401
- field: {
402
- id: (0, import_schema.createFieldId)(),
403
- path: "manager",
404
- referencePath: "name"
405
- },
406
- props: {
407
- property: "manager",
408
- type: import_echo_schema4.TypeEnum.Ref,
409
- format: import_echo_schema4.FormatEnum.Ref,
410
- referenceSchema: contactSchema.typename,
411
- title: "Manager"
363
+ const fields = (0, import_schema.getSchemaProperties)(schema.ast).filter((prop) => prop.type !== "object" || prop.format === import_echo_schema4.FormatEnum.Ref).map((prop) => prop.name);
364
+ table.view = (0, import_echo5.makeRef)((0, import_schema.createView)({
365
+ // TODO(ZaymonFC): Don't hardcode name?
366
+ name: "View",
367
+ typename: schema.typename,
368
+ jsonSchema: schema.jsonSchema,
369
+ fields
370
+ }));
371
+ return schema;
372
+ } else {
373
+ const ContactSchema = (0, import_echo_schema4.TypedObject)({
374
+ typename: `example.com/type/${import_react_client2.PublicKey.random().truncate()}`,
375
+ version: "0.1.0"
376
+ })({
377
+ name: import_echo_schema4.S.optional(import_echo_schema4.S.String).annotations({
378
+ [import_echo_schema4.AST.TitleAnnotationId]: "Name"
379
+ }),
380
+ active: import_echo_schema4.S.optional(import_echo_schema4.S.Boolean),
381
+ email: import_echo_schema4.S.optional(import_echo_schema4.Format.Email),
382
+ salary: import_echo_schema4.S.optional(import_echo_schema4.Format.Currency()).annotations({
383
+ [import_echo_schema4.AST.TitleAnnotationId]: "Salary"
384
+ })
385
+ });
386
+ const [contactSchema] = await space.db.schemaRegistry.register([
387
+ ContactSchema
388
+ ]);
389
+ table.view = (0, import_echo5.makeRef)((0, import_schema.createView)({
390
+ name: "View",
391
+ typename: contactSchema.typename,
392
+ jsonSchema: contactSchema.jsonSchema,
393
+ fields: [
394
+ "name",
395
+ "active",
396
+ "email",
397
+ "salary"
398
+ ]
399
+ }));
400
+ const projection = new import_schema.ViewProjection(contactSchema, table.view.target);
401
+ projection.setFieldProjection({
402
+ field: {
403
+ id: table.view.target.fields.find((f) => f.path === "salary").id,
404
+ path: "salary",
405
+ size: 150
406
+ }
407
+ });
408
+ projection.setFieldProjection({
409
+ field: {
410
+ id: (0, import_schema.createFieldId)(),
411
+ path: "manager",
412
+ referencePath: "name"
413
+ },
414
+ props: {
415
+ property: "manager",
416
+ type: import_echo_schema4.TypeEnum.Ref,
417
+ format: import_echo_schema4.FormatEnum.Ref,
418
+ referenceSchema: contactSchema.typename,
419
+ title: "Manager"
420
+ }
421
+ });
422
+ if (initialRow) {
423
+ space.db.add((0, import_echo5.create)(contactSchema, {}));
412
424
  }
413
- });
414
- if (initialRow) {
415
- space.db.add((0, import_echo5.create)(contactSchema, {}));
425
+ return contactSchema;
416
426
  }
417
- return contactSchema;
418
427
  };
419
428
  var BUTTON_IDENTIFIERS = {
420
429
  columnSettings: "data-table-column-settings-button",
421
430
  newColumn: "data-table-new-column-button",
422
431
  referencedCell: "data-table-ref-cell-button",
423
- rowMenu: "data-table-row-menu-button"
432
+ rowMenu: "data-table-row-menu-button",
433
+ sort: "data-table-sort-button"
424
434
  };
425
- var createButton = ({ attr, data, disabled = false, icon, testId }) => {
435
+ var createButton = ({ attr, data, disabled = false, icon, testId, type = "primary" }) => {
426
436
  const dataAttrs = Object.entries(data).map(([k, v]) => `${k}="${v}"`).join(" ");
427
- return `<button ${attr} data-testid="${testId}" class="ch-button is-6 pli-0.5 min-bs-0 absolute inset-block-1 inline-end-2" ${dataAttrs} ${disabled ? "disabled" : ""}><svg><use href="/icons.svg#${icon}"/></svg></button>`;
437
+ const positionClass = type === "primary" ? "inline-end-2" : "inline-end-9";
438
+ return `<button ${attr} data-testid="${testId}" class="dx-button is-6 pli-0.5 min-bs-0 absolute inset-block-1 ${positionClass}" ${dataAttrs} ${disabled ? "disabled" : ""}><svg><use href="/icons.svg#${icon}"/></svg></button>`;
428
439
  };
429
440
  var addColumnButton = {
430
441
  attr: BUTTON_IDENTIFIERS.newColumn,
@@ -498,19 +509,43 @@ var rowMenuButton = {
498
509
  rowIndex: Number(el.getAttribute("data-row-index"))
499
510
  })
500
511
  };
512
+ var sortButton = {
513
+ attr: BUTTON_IDENTIFIERS.sort,
514
+ icon: "ph--sort-ascending--regular",
515
+ render: ({ fieldId, direction }) => {
516
+ return createButton({
517
+ attr: BUTTON_IDENTIFIERS.sort,
518
+ icon: direction === "desc" ? "ph--sort-descending--regular" : "ph--sort-ascending--regular",
519
+ data: {
520
+ "data-field-id": fieldId,
521
+ "data-direction": direction ?? ""
522
+ },
523
+ testId: "table-sort-button",
524
+ // TODO(ZaymonFC): All buttons should be rendered into an absolutely positioned flex container.
525
+ // This is a bit hacky.
526
+ type: "secondary"
527
+ });
528
+ },
529
+ getData: (el) => ({
530
+ type: "sort",
531
+ fieldId: el.getAttribute("data-field-id"),
532
+ direction: el.getAttribute("data-direction")
533
+ })
534
+ };
501
535
  var tableButtons = {
502
536
  addColumn: addColumnButton,
503
537
  columnSettings: columnSettingsButton,
504
538
  referencedCell: referencedCellButton,
505
- rowMenu: rowMenuButton
539
+ rowMenu: rowMenuButton,
540
+ sort: sortButton
506
541
  };
507
542
  var CONTROL_IDENTIFIERS = {
508
543
  checkbox: "data-table-checkbox",
509
544
  switch: "data-table-switch"
510
545
  };
511
546
  var BASE_CLASSES = {
512
- checkbox: "absolute inset-block-[.375rem] inline-end-[.375rem] ch-checkbox",
513
- switch: "absolute inset-block-[.25rem] inline-end-[.25rem] ch-checkbox--switch"
547
+ checkbox: "absolute inset-block-[.375rem] inline-end-[.375rem] dx-checkbox",
548
+ switch: "absolute inset-block-[.25rem] inline-end-[.25rem] dx-checkbox--switch"
514
549
  };
515
550
  var renderAttributes = (data) => {
516
551
  return Object.entries(data).map(([k, v]) => `${k}="${v}"`).join(" ");
@@ -634,7 +669,166 @@ var SelectionModel = class extends import_context2.Resource {
634
669
  return this._allSelected;
635
670
  }
636
671
  };
637
- var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/model/table-model.ts";
672
+ var TableSorting = class {
673
+ constructor(rows, _view, _projection) {
674
+ this._view = _view;
675
+ this._projection = _projection;
676
+ this._displayToDataIndex = /* @__PURE__ */ new Map();
677
+ this._localSort = (0, import_signals_core3.signal)(void 0);
678
+ this._rows = rows;
679
+ this._isDirty = (0, import_signals_core3.computed)(() => {
680
+ const local = this._localSort.value;
681
+ const viewSort = this._view?.query.sort?.[0];
682
+ if (local?.type === "cleared") {
683
+ return viewSort !== void 0;
684
+ }
685
+ if (local?.type === "active") {
686
+ if (!viewSort) {
687
+ return true;
688
+ }
689
+ return local.sort.fieldId !== viewSort.fieldId || local.sort.direction !== viewSort.direction;
690
+ }
691
+ return false;
692
+ });
693
+ this.sortedRows = this.initialiseSortedRows();
694
+ }
695
+ /**
696
+ * @reactive
697
+ * @returns Local sort if present, falls back to view sort.
698
+ */
699
+ get sorting() {
700
+ const local = this._localSort.value;
701
+ if (local?.type === "cleared") {
702
+ return void 0;
703
+ }
704
+ if (local?.type === "active") {
705
+ return local.sort;
706
+ }
707
+ return this._view?.query.sort?.[0];
708
+ }
709
+ /**
710
+ * @reactive
711
+ * @returns Whether local sort differs from view sort.
712
+ */
713
+ get isDirty() {
714
+ return this._isDirty.value;
715
+ }
716
+ getDataIndex(displayIndex) {
717
+ return this._displayToDataIndex.get(displayIndex) ?? displayIndex;
718
+ }
719
+ setSort(fieldId, direction) {
720
+ this._localSort.value = {
721
+ type: "active",
722
+ sort: {
723
+ fieldId,
724
+ direction
725
+ }
726
+ };
727
+ }
728
+ toggleSort(fieldId) {
729
+ if (!this._view || !this.sorting || this.sorting.fieldId !== fieldId) {
730
+ return;
731
+ }
732
+ switch (this.sorting.direction) {
733
+ case "asc": {
734
+ this.setSort(fieldId, "desc");
735
+ break;
736
+ }
737
+ case "desc": {
738
+ this.setSort(fieldId, "asc");
739
+ break;
740
+ }
741
+ }
742
+ }
743
+ clearSort() {
744
+ this._localSort.value = {
745
+ type: "cleared"
746
+ };
747
+ }
748
+ save() {
749
+ if (this._view && this._localSort.value !== void 0) {
750
+ if (this._localSort.value.type === "active") {
751
+ this._view.query.sort = [
752
+ this._localSort.value.sort
753
+ ];
754
+ } else {
755
+ this._view.query.sort = [];
756
+ }
757
+ this._localSort.value = void 0;
758
+ }
759
+ }
760
+ //
761
+ // Initialisation.
762
+ //
763
+ initialiseSortedRows() {
764
+ return (0, import_signals_core3.computed)(() => {
765
+ this._displayToDataIndex.clear();
766
+ const sort = this.sorting;
767
+ if (!sort || !this._view) {
768
+ return this._rows.value;
769
+ }
770
+ const field = this._view.fields.find((f) => f.id === sort.fieldId);
771
+ if (!field) {
772
+ return this._rows.value;
773
+ }
774
+ const { props } = this._projection.getFieldProjection(field.id);
775
+ const dataWithIndices = this._rows.value.map((item, index) => {
776
+ const sortValue = this.getSortValue(props, field, item);
777
+ const isEmpty = !(props.type === import_echo_schema5.TypeEnum.Boolean) && (sortValue == null || sortValue === "");
778
+ return {
779
+ item,
780
+ index,
781
+ value: sortValue,
782
+ isEmpty
783
+ };
784
+ });
785
+ const ordered = (0, import_lodash.default)(dataWithIndices, [
786
+ "isEmpty",
787
+ "value"
788
+ ], [
789
+ "asc",
790
+ sort.direction
791
+ ]);
792
+ ordered.forEach(({ index: dataIndex }, displayIndex) => {
793
+ if (displayIndex !== dataIndex) {
794
+ this._displayToDataIndex.set(displayIndex, dataIndex);
795
+ }
796
+ });
797
+ return ordered.map(({ item }) => item);
798
+ });
799
+ }
800
+ getSortValue(props, field, item) {
801
+ const { type, format } = props;
802
+ const value = (0, import_echo_schema5.getValue)(item, field.path);
803
+ if (type === import_echo_schema5.TypeEnum.Boolean) {
804
+ return !!value;
805
+ }
806
+ if (type === import_echo_schema5.TypeEnum.Number) {
807
+ return value;
808
+ }
809
+ if (value == null) {
810
+ return value;
811
+ }
812
+ if (format === import_echo_schema5.FormatEnum.SingleSelect) {
813
+ const options = props.options;
814
+ if (!options) {
815
+ return void 0;
816
+ }
817
+ const option = options.find((option2) => option2.id === value);
818
+ return option ? options.indexOf(option) : void 0;
819
+ }
820
+ if (format === import_echo_schema5.FormatEnum.Ref && field.referencePath) {
821
+ const refValue = (0, import_echo_schema5.getValue)(value.target, field.referencePath);
822
+ return refValue;
823
+ }
824
+ return (0, import_react_ui_form5.formatForDisplay)({
825
+ type,
826
+ format,
827
+ value
828
+ });
829
+ }
830
+ };
831
+ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/model/table-model.ts";
638
832
  var TableModel = class extends import_context.Resource {
639
833
  constructor({ table, projection, sorting = [], pinnedRows = {
640
834
  top: [],
@@ -652,8 +846,6 @@ var TableModel = class extends import_context.Resource {
652
846
  col: 0
653
847
  }
654
848
  });
655
- this._displayToDataIndex = /* @__PURE__ */ new Map();
656
- this._sorting = (0, import_signals_core.signal)(void 0);
657
849
  this._rows = (0, import_signals_core.signal)([]);
658
850
  this.setRows = (obj) => {
659
851
  this._rows.value = obj;
@@ -661,11 +853,11 @@ var TableModel = class extends import_context.Resource {
661
853
  this.getRowCount = () => this._rows.value.length;
662
854
  this.getColumnCount = () => this.table.view?.target?.fields.length ?? 0;
663
855
  this.insertRow = (rowIndex) => {
664
- const row = rowIndex !== void 0 ? this._displayToDataIndex.get(rowIndex) ?? rowIndex : this._rows.value.length;
856
+ const row = rowIndex !== void 0 ? this._sorting.getDataIndex(rowIndex) : this._rows.value.length;
665
857
  this._onInsertRow?.(row);
666
858
  };
667
859
  this.deleteRow = (rowIndex) => {
668
- const row = this._displayToDataIndex.get(rowIndex) ?? rowIndex;
860
+ const row = this._sorting.getDataIndex(rowIndex);
669
861
  const obj = this._rows.value[row];
670
862
  const objectsToDelete = [];
671
863
  if (this._selection.hasSelection.value) {
@@ -682,7 +874,7 @@ var TableModel = class extends import_context.Resource {
682
874
  return void 0;
683
875
  }
684
876
  const field = fields[col];
685
- const dataIndex = this._displayToDataIndex.get(row) ?? row;
877
+ const dataIndex = this._sorting.getDataIndex(row);
686
878
  const value = (0, import_echo_schema3.getValue)(this._rows.value[dataIndex], field.path);
687
879
  if (value == null) {
688
880
  return "";
@@ -705,7 +897,7 @@ var TableModel = class extends import_context.Resource {
705
897
  }
706
898
  };
707
899
  this.setCellData = ({ col, row }, value) => {
708
- const rowIdx = this._displayToDataIndex.get(row) ?? row;
900
+ const rowIdx = this._sorting.getDataIndex(row);
709
901
  const fields = this.table.view?.target?.fields ?? [];
710
902
  if (col < 0 || col >= fields.length) {
711
903
  return;
@@ -731,7 +923,11 @@ var TableModel = class extends import_context.Resource {
731
923
  };
732
924
  this._table = table;
733
925
  this._projection = projection;
734
- this._sorting.value = sorting.at(0);
926
+ this._sorting = new TableSorting(this._rows, table.view?.target, projection);
927
+ if (sorting.length > 0) {
928
+ const [sort] = sorting;
929
+ this._sorting.setSort(sort.fieldId, sort.direction);
930
+ }
735
931
  this._pinnedRows = pinnedRows;
736
932
  this._onInsertRow = onInsertRow;
737
933
  this._onDeleteRows = onDeleteRows;
@@ -746,14 +942,20 @@ var TableModel = class extends import_context.Resource {
746
942
  return this._projection;
747
943
  }
748
944
  get rows() {
749
- return this._sortedRows;
945
+ return this._sorting.sortedRows;
946
+ }
947
+ /**
948
+ * @reactive
949
+ */
950
+ get sorting() {
951
+ return this._sorting;
750
952
  }
751
953
  get pinnedRows() {
752
954
  return this._pinnedRows;
753
955
  }
754
956
  get columnMeta() {
755
957
  (0, import_invariant2.invariant)(this._columnMeta, void 0, {
756
- F: __dxlog_file2,
958
+ F: __dxlog_file,
757
959
  L: 117,
758
960
  S: this,
759
961
  A: [
@@ -763,20 +965,20 @@ var TableModel = class extends import_context.Resource {
763
965
  });
764
966
  return this._columnMeta;
765
967
  }
766
- get sorting() {
767
- return this._sorting.value;
768
- }
769
968
  get selection() {
770
969
  return this._selection;
771
970
  }
971
+ /** @reactive */
972
+ get isViewDirty() {
973
+ return this._sorting.isDirty;
974
+ }
772
975
  //
773
976
  // Initialisation
774
977
  //
775
978
  async _open() {
776
979
  this.initializeColumnMeta();
777
- this.initializeSorting();
778
980
  this.initializeEffects();
779
- this._selection = new SelectionModel(this._sortedRows, () => this._onRowOrderChanged?.());
981
+ this._selection = new SelectionModel(this._sorting.sortedRows, () => this._onRowOrderChanged?.());
780
982
  await this._selection.open(this._ctx);
781
983
  }
782
984
  initializeColumnMeta() {
@@ -806,60 +1008,9 @@ var TableModel = class extends import_context.Resource {
806
1008
  };
807
1009
  });
808
1010
  }
809
- initializeSorting() {
810
- this._sortedRows = (0, import_signals_core.computed)(() => {
811
- this._displayToDataIndex.clear();
812
- const sort = this._sorting.value;
813
- if (!sort) {
814
- return this._rows.value;
815
- }
816
- const field = this._table.view?.target?.fields.find((field2) => field2.id === sort.fieldId);
817
- if (!field) {
818
- return this._rows.value;
819
- }
820
- const { props } = this._projection.getFieldProjection(field.id);
821
- const dataWithIndices = this._rows.value.map((item, index) => {
822
- const rawValue = (0, import_echo_schema3.getValue)(item, field.path);
823
- let sortValue = rawValue;
824
- if (props.type.startsWith("boolean")) {
825
- sortValue = !!rawValue;
826
- } else if (rawValue != null) {
827
- if (props.format === import_echo_schema3.FormatEnum.Ref && field.referencePath) {
828
- sortValue = (0, import_echo_schema3.getValue)(rawValue, field.referencePath);
829
- } else {
830
- sortValue = (0, import_react_ui_form4.formatForDisplay)({
831
- type: props.type,
832
- format: props.format,
833
- value: rawValue
834
- });
835
- }
836
- }
837
- return {
838
- item,
839
- index,
840
- value: sortValue,
841
- isEmpty: !props.type.startsWith("boolean") && (sortValue == null || sortValue === "")
842
- };
843
- });
844
- const sorted = (0, import_lodash.default)(dataWithIndices, [
845
- "isEmpty",
846
- "value"
847
- ], [
848
- "asc",
849
- sort.direction
850
- ]);
851
- for (let displayIndex = 0; displayIndex < sorted.length; displayIndex++) {
852
- const { index: dataIndex } = sorted[displayIndex];
853
- if (displayIndex !== dataIndex) {
854
- this._displayToDataIndex.set(displayIndex, dataIndex);
855
- }
856
- }
857
- return sorted.map(({ item }) => item);
858
- });
859
- }
860
1011
  initializeEffects() {
861
1012
  const rowOrderWatcher = (0, import_signals_core.effect)(() => {
862
- touch(this._sortedRows.value);
1013
+ touch(this._sorting.sortedRows.value);
863
1014
  this._onRowOrderChanged?.();
864
1015
  });
865
1016
  this._ctx.onDispose(rowOrderWatcher);
@@ -868,7 +1019,7 @@ var TableModel = class extends import_context.Resource {
868
1019
  const rowEffects = [];
869
1020
  for (let row = start.row; row <= end.row; row++) {
870
1021
  rowEffects.push((0, import_signals_core.effect)(() => {
871
- const obj = this._sortedRows.value[row];
1022
+ const obj = this._sorting.sortedRows.value[row];
872
1023
  this?._table?.view?.target?.fields.forEach((field) => touch((0, import_echo_schema3.getValue)(obj, field.path)));
873
1024
  this._onCellUpdate?.({
874
1025
  row,
@@ -887,7 +1038,7 @@ var TableModel = class extends import_context.Resource {
887
1038
  * @param {(value: any) => any} update - A function that takes the current value and returns the updated value.
888
1039
  */
889
1040
  updateCellData({ col, row }, update) {
890
- const dataRow = this._displayToDataIndex.get(row) ?? row;
1041
+ const dataRow = this._sorting.getDataIndex(row);
891
1042
  const fields = this.table.view?.target?.fields ?? [];
892
1043
  const field = fields[col];
893
1044
  const value = (0, import_echo_schema3.getValue)(this._rows.value[dataRow], field.path);
@@ -903,9 +1054,6 @@ var TableModel = class extends import_context.Resource {
903
1054
  }
904
1055
  const field = this.table.view.target?.fields.find((field2) => field2.id === fieldId);
905
1056
  if (field && this._onDeleteColumn) {
906
- if (this._sorting.value?.fieldId === fieldId) {
907
- this.clearSort();
908
- }
909
1057
  this._onDeleteColumn(field.id);
910
1058
  }
911
1059
  }
@@ -923,18 +1071,6 @@ var TableModel = class extends import_context.Resource {
923
1071
  }
924
1072
  }
925
1073
  //
926
- // Sorting
927
- //
928
- setSort(fieldId, direction) {
929
- this._sorting.value = {
930
- fieldId,
931
- direction
932
- };
933
- }
934
- clearSort() {
935
- this._sorting.value = void 0;
936
- }
937
- //
938
1074
  // Pinning
939
1075
  //
940
1076
  // TODO(burdon): Change to setPinned(on/off).
@@ -945,11 +1081,17 @@ var TableModel = class extends import_context.Resource {
945
1081
  this._pinnedRows.top = this._pinnedRows.top.filter((index) => index !== rowIndex);
946
1082
  this._pinnedRows.bottom = this._pinnedRows.bottom.filter((index) => index !== rowIndex);
947
1083
  }
1084
+ //
1085
+ // View operations
1086
+ //
1087
+ saveView() {
1088
+ this._sorting.save();
1089
+ }
948
1090
  };
949
- var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/model/modal-controller.ts";
1091
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/model/modal-controller.ts";
950
1092
  var ModalController = class {
951
1093
  constructor() {
952
- this._state = (0, import_signals_core3.signal)({
1094
+ this._state = (0, import_signals_core4.signal)({
953
1095
  type: "closed"
954
1096
  });
955
1097
  this._triggerRef = {
@@ -1009,8 +1151,8 @@ var ModalController = class {
1009
1151
  onCreate
1010
1152
  };
1011
1153
  } else {
1012
- import_log2.log.warn("anchor cell not found while creating new ref", void 0, {
1013
- F: __dxlog_file3,
1154
+ import_log.log.warn("anchor cell not found while creating new ref", void 0, {
1155
+ F: __dxlog_file2,
1014
1156
  L: 86,
1015
1157
  S: this,
1016
1158
  C: (f, a) => f(...a)
@@ -1031,7 +1173,7 @@ var ModalController = class {
1031
1173
  }
1032
1174
  };
1033
1175
  var TablePresentation = class {
1034
- constructor(model, _visibleRange = (0, import_signals_core4.signal)({
1176
+ constructor(model, _visibleRange = (0, import_signals_core5.signal)({
1035
1177
  start: {
1036
1178
  row: 0,
1037
1179
  col: 0
@@ -1070,22 +1212,23 @@ var TablePresentation = class {
1070
1212
  const { props } = this.model.projection.getFieldProjection(field.id);
1071
1213
  const cell = {
1072
1214
  get value() {
1073
- const value = (0, import_echo_schema5.getValue)(obj, field.path);
1215
+ const value = (0, import_echo_schema6.getValue)(obj, field.path);
1074
1216
  if (value == null) {
1075
1217
  return "";
1076
1218
  }
1077
1219
  switch (props.format) {
1078
- case import_echo_schema5.FormatEnum.Boolean: {
1220
+ case import_echo_schema6.FormatEnum.Boolean:
1221
+ case import_echo_schema6.FormatEnum.SingleSelect: {
1079
1222
  return "";
1080
1223
  }
1081
- case import_echo_schema5.FormatEnum.Ref: {
1224
+ case import_echo_schema6.FormatEnum.Ref: {
1082
1225
  if (!field.referencePath) {
1083
1226
  return "";
1084
1227
  }
1085
- return (0, import_echo_schema5.getValue)(value.target, field.referencePath);
1228
+ return (0, import_echo_schema6.getValue)(value.target, field.referencePath);
1086
1229
  }
1087
1230
  default: {
1088
- return (0, import_react_ui_form5.formatForDisplay)({
1231
+ return (0, import_react_ui_form6.formatForDisplay)({
1089
1232
  type: props.type,
1090
1233
  format: props.format,
1091
1234
  value
@@ -1095,22 +1238,22 @@ var TablePresentation = class {
1095
1238
  }
1096
1239
  };
1097
1240
  const classes = [];
1098
- const formatClasses = (0, import_react_ui_form5.cellClassesForFieldType)({
1241
+ const formatClasses = (0, import_react_ui_form6.cellClassesForFieldType)({
1099
1242
  type: props.type,
1100
1243
  format: props.format
1101
1244
  });
1102
1245
  if (formatClasses) {
1103
1246
  classes.push(formatClasses);
1104
1247
  }
1105
- const rowSelectionClasses = (0, import_react_ui_form5.cellClassesForRowSelection)(this.model.selection.isObjectSelected(obj));
1248
+ const rowSelectionClasses = (0, import_react_ui_form6.cellClassesForRowSelection)(this.model.selection.isObjectSelected(obj));
1106
1249
  if (rowSelectionClasses) {
1107
1250
  classes.push(rowSelectionClasses);
1108
1251
  }
1109
1252
  if (classes.length > 0) {
1110
1253
  cell.className = (0, import_react_ui_theme2.mx)(classes.flat());
1111
1254
  }
1112
- if (props.format === import_echo_schema5.FormatEnum.Ref && props.referenceSchema) {
1113
- const targetObj = (0, import_echo_schema5.getValue)(obj, field.path)?.target;
1255
+ if (props.format === import_echo_schema6.FormatEnum.Ref && props.referenceSchema) {
1256
+ const targetObj = (0, import_echo_schema6.getValue)(obj, field.path)?.target;
1114
1257
  if (targetObj) {
1115
1258
  cell.accessoryHtml = tableButtons.referencedCell.render({
1116
1259
  targetId: targetObj.id,
@@ -1118,8 +1261,8 @@ var TablePresentation = class {
1118
1261
  });
1119
1262
  }
1120
1263
  }
1121
- if (props.format === import_echo_schema5.FormatEnum.Boolean) {
1122
- const value = (0, import_echo_schema5.getValue)(obj, field.path);
1264
+ if (props.format === import_echo_schema6.FormatEnum.Boolean) {
1265
+ const value = (0, import_echo_schema6.getValue)(obj, field.path);
1123
1266
  cell.accessoryHtml = tableControls.switch.render({
1124
1267
  colIndex,
1125
1268
  rowIndex: displayIndex,
@@ -1127,6 +1270,16 @@ var TablePresentation = class {
1127
1270
  });
1128
1271
  cell.readonly = true;
1129
1272
  }
1273
+ if (props.format === import_echo_schema6.FormatEnum.SingleSelect) {
1274
+ const value = (0, import_echo_schema6.getValue)(obj, field.path);
1275
+ const options = this.model.projection.getFieldProjection(field.id).props.options;
1276
+ if (options) {
1277
+ const option = options.find((o) => o.id === value);
1278
+ if (option) {
1279
+ cell.accessoryHtml = `<span class="dx-tag" data-hue="${option.color}">${option.title}</span>`;
1280
+ }
1281
+ }
1282
+ }
1130
1283
  const idx = (0, import_react_ui_grid3.toPlaneCellIndex)({
1131
1284
  col: colIndex,
1132
1285
  row: displayIndex
@@ -1149,6 +1302,8 @@ var TablePresentation = class {
1149
1302
  const fields = this.model.table.view?.target?.fields ?? [];
1150
1303
  for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
1151
1304
  const { field, props } = this.model.projection.getFieldProjection(fields[col].id);
1305
+ const sorting = this.model.sorting?.sorting;
1306
+ const direction = sorting?.fieldId === field.id ? sorting.direction : void 0;
1152
1307
  cells[(0, import_react_ui_grid3.toPlaneCellIndex)({
1153
1308
  col,
1154
1309
  row: 0
@@ -1157,9 +1312,16 @@ var TablePresentation = class {
1157
1312
  value: props.title ?? field.path,
1158
1313
  readonly: true,
1159
1314
  resizeHandle: "col",
1160
- accessoryHtml: tableButtons.columnSettings.render({
1315
+ accessoryHtml: `
1316
+ ${direction !== void 0 ? tableButtons.sort.render({
1317
+ fieldId: field.id,
1318
+ direction
1319
+ }) : ""}
1320
+ ${tableButtons.columnSettings.render({
1161
1321
  fieldId: field.id
1162
- })
1322
+ })}
1323
+ `,
1324
+ className: "!bg-gridHeader"
1163
1325
  };
1164
1326
  }
1165
1327
  return cells;
@@ -1168,7 +1330,7 @@ var TablePresentation = class {
1168
1330
  const cells = {};
1169
1331
  for (let row = range.start.row; row <= range.end.row && row < this.model.getRowCount(); row++) {
1170
1332
  const isSelected = this.model.selection.isRowIndexSelected(row);
1171
- const classes = (0, import_react_ui_form5.cellClassesForRowSelection)(isSelected);
1333
+ const classes = (0, import_react_ui_form6.cellClassesForRowSelection)(isSelected);
1172
1334
  cells[(0, import_react_ui_grid3.toPlaneCellIndex)({
1173
1335
  col: 0,
1174
1336
  row
@@ -1188,7 +1350,7 @@ var TablePresentation = class {
1188
1350
  const cells = {};
1189
1351
  for (let row = range.start.row; row <= range.end.row && row < this.model.getRowCount(); row++) {
1190
1352
  const isSelected = this.model.selection.isRowIndexSelected(row);
1191
- const classes = (0, import_react_ui_form5.cellClassesForRowSelection)(isSelected);
1353
+ const classes = (0, import_react_ui_form6.cellClassesForRowSelection)(isSelected);
1192
1354
  cells[(0, import_react_ui_grid3.toPlaneCellIndex)({
1193
1355
  col: 0,
1194
1356
  row
@@ -1209,13 +1371,14 @@ var TablePresentation = class {
1209
1371
  col: 0,
1210
1372
  row: 0
1211
1373
  })]: {
1212
- value: "",
1213
1374
  accessoryHtml: tableControls.checkbox.render({
1214
1375
  rowIndex: 0,
1215
1376
  header: true,
1216
1377
  checked: this.model.selection.allRowsSeleted.value
1217
1378
  }),
1218
- readonly: true
1379
+ className: "!bg-gridHeader",
1380
+ readonly: true,
1381
+ value: ""
1219
1382
  }
1220
1383
  };
1221
1384
  }
@@ -1225,11 +1388,12 @@ var TablePresentation = class {
1225
1388
  col: 0,
1226
1389
  row: 0
1227
1390
  })]: {
1228
- value: "",
1229
1391
  accessoryHtml: tableButtons.addColumn.render({
1230
1392
  disabled: (this.model.table.view?.target?.fields?.length ?? 0) >= import_schema2.VIEW_FIELD_LIMIT
1231
1393
  }),
1232
- readonly: true
1394
+ className: "!bg-gridHeader",
1395
+ readonly: true,
1396
+ value: ""
1233
1397
  }
1234
1398
  };
1235
1399
  }
@@ -1269,7 +1433,7 @@ var completion = ({ debug, onQuery, onMatch }) => {
1269
1433
  })
1270
1434
  ];
1271
1435
  };
1272
- var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx";
1436
+ var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx";
1273
1437
  var newValue = Symbol.for("newValue");
1274
1438
  var createOption = (text) => ({
1275
1439
  [newValue]: true,
@@ -1287,7 +1451,7 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }
1287
1451
  const field = model.projection.view.fields[col];
1288
1452
  const fieldProjection2 = model.projection.getFieldProjection(field.id);
1289
1453
  (0, import_invariant3.invariant)(fieldProjection2, void 0, {
1290
- F: __dxlog_file4,
1454
+ F: __dxlog_file3,
1291
1455
  L: 67,
1292
1456
  S: void 0,
1293
1457
  A: [
@@ -1361,7 +1525,7 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }
1361
1525
  ];
1362
1526
  if (onQuery) {
1363
1527
  switch (fieldProjection.props.format) {
1364
- case import_echo_schema6.FormatEnum.Ref: {
1528
+ case import_echo_schema7.FormatEnum.Ref: {
1365
1529
  extension2.push([
1366
1530
  completion({
1367
1531
  onQuery: (text) => onQuery(fieldProjection, text),
@@ -1435,7 +1599,7 @@ var determineNavigationDelta = ({ key, shift }) => {
1435
1599
  }
1436
1600
  return shift ? -1 : 1;
1437
1601
  };
1438
- var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/Table/Table.tsx";
1602
+ var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/Table/Table.tsx";
1439
1603
  var inlineEndLine = "[&>.dx-grid]:relative [&>.dx-grid]:after:absolute [&>.dx-grid]:after:inset-block-0 [&>.dx-grid]:after:-inline-end-px [&>.dx-grid]:after:is-px [&>.dx-grid]:after:bg-separator";
1440
1604
  var blockEndLine = "[&>.dx-grid]:before:absolute [&>.dx-grid]:before:inset-inline-0 [&>.dx-grid]:before:-block-end-px [&>.dx-grid]:before:bs-px [&>.dx-grid]:before:bg-separator";
1441
1605
  var frozen = {
@@ -1503,6 +1667,10 @@ var TableMain = /* @__PURE__ */ (0, import_react.forwardRef)(({ model, presentat
1503
1667
  modals.showReferencePanel(data.targetId, data.schemaId);
1504
1668
  break;
1505
1669
  }
1670
+ case "sort": {
1671
+ model?.sorting?.toggleSort(data.fieldId);
1672
+ break;
1673
+ }
1506
1674
  }
1507
1675
  return;
1508
1676
  }
@@ -1603,8 +1771,8 @@ var TableMain = /* @__PURE__ */ (0, import_react.forwardRef)(({ model, presentat
1603
1771
  if (model && props.referenceSchema && field.referencePath) {
1604
1772
  const space = (0, import_echo.getSpace)(model.table);
1605
1773
  (0, import_invariant.invariant)(space, void 0, {
1606
- F: __dxlog_file5,
1607
- L: 260,
1774
+ F: __dxlog_file4,
1775
+ L: 264,
1608
1776
  S: void 0,
1609
1777
  A: [
1610
1778
  "space",
@@ -1687,73 +1855,76 @@ var Table = {
1687
1855
  Root: TableRoot,
1688
1856
  Main: TableMain
1689
1857
  };
1690
- var buttonStyles = "min-bs-0 p-2";
1691
- var tooltipProps = {
1692
- side: "top",
1693
- classNames: "z-10"
1694
- };
1695
- var ToolbarSeparator = () => /* @__PURE__ */ import_react9.default.createElement("div", {
1696
- role: "separator",
1697
- className: "grow"
1698
- });
1699
- var ToolbarButton = ({ icon, children, ...props }) => {
1700
- return /* @__PURE__ */ import_react9.default.createElement(import_react_ui8.Tooltip.Root, null, /* @__PURE__ */ import_react9.default.createElement(import_react_ui8.Tooltip.Trigger, {
1701
- asChild: true
1702
- }, /* @__PURE__ */ import_react9.default.createElement(import_react_ui8.Toolbar.Button, {
1703
- variant: "ghost",
1704
- ...props,
1705
- classNames: buttonStyles
1706
- }, /* @__PURE__ */ import_react9.default.createElement(import_react_ui8.Icon, {
1707
- icon,
1708
- size: 5
1709
- }), /* @__PURE__ */ import_react9.default.createElement("span", {
1710
- className: "sr-only"
1711
- }, children))), /* @__PURE__ */ import_react9.default.createElement(import_react_ui8.Tooltip.Portal, null, /* @__PURE__ */ import_react9.default.createElement(import_react_ui8.Tooltip.Content, tooltipProps, children, /* @__PURE__ */ import_react9.default.createElement(import_react_ui8.Tooltip.Arrow, null))));
1712
- };
1713
- var [ToolbarContextProvider, useToolbarContext] = (0, import_react_context.createContext)("Toolbar");
1714
- var ToolbarRoot = ({ classNames, children, onAction }) => {
1715
- return /* @__PURE__ */ import_react8.default.createElement(ToolbarContextProvider, {
1716
- onAction
1717
- }, /* @__PURE__ */ import_react8.default.createElement(import_react_ui7.Toolbar.Root, {
1718
- classNames: [
1719
- "is-full shrink-0 overflow-x-auto overflow-y-hidden p-1 attention-surface",
1720
- classNames
1721
- ]
1722
- }, children));
1723
- };
1724
- var Editing = () => {
1725
- const { onAction } = useToolbarContext("Editing");
1726
- const { t } = (0, import_react_ui7.useTranslation)(translationKey);
1727
- return /* @__PURE__ */ import_react8.default.createElement(import_react8.default.Fragment, null, /* @__PURE__ */ import_react8.default.createElement(ToolbarButton, {
1728
- value: "add-row",
1858
+ var createTableToolbarActions = (state) => {
1859
+ const add = (0, import_react_ui_menu.createMenuAction)("add-row", {
1860
+ type: "add-row",
1729
1861
  icon: "ph--plus--regular",
1730
- "data-testid": "table.toolbar.add-row",
1731
- onClick: () => onAction?.({
1732
- type: "add-row"
1733
- })
1734
- }, t("add row")));
1735
- };
1736
- var Actions = () => {
1737
- const { onAction } = useToolbarContext("Actions");
1738
- const { t } = (0, import_react_ui7.useTranslation)(translationKey);
1739
- return /* @__PURE__ */ import_react8.default.createElement(import_react8.default.Fragment, null, /* @__PURE__ */ import_react8.default.createElement(ToolbarButton, {
1740
- value: "comment",
1862
+ label: [
1863
+ "add row",
1864
+ {
1865
+ ns: translationKey
1866
+ }
1867
+ ],
1868
+ testId: "table.toolbar.add-row"
1869
+ });
1870
+ const save = (0, import_react_ui_menu.createMenuAction)("save-view", {
1871
+ type: "save-view",
1872
+ icon: "ph--floppy-disk--regular",
1873
+ label: [
1874
+ "save view label",
1875
+ {
1876
+ ns: translationKey
1877
+ }
1878
+ ],
1879
+ testId: "table.toolbar.save-view",
1880
+ iconOnly: false,
1881
+ hidden: !state.viewDirty
1882
+ });
1883
+ const gap = (0, import_react_ui_menu.createGapSeparator)();
1884
+ const comment = (0, import_react_ui_menu.createMenuAction)("comment", {
1885
+ type: "comment",
1741
1886
  icon: "ph--chat-text--regular",
1742
- "data-testid": "table.toolbar.comment",
1743
- onClick: () => onAction?.({
1744
- type: "comment"
1745
- })
1746
- }, t("create comment")));
1887
+ label: [
1888
+ "create comment",
1889
+ {
1890
+ ns: translationKey
1891
+ }
1892
+ ],
1893
+ testId: "table.toolbar.comment"
1894
+ });
1895
+ const nodes = [
1896
+ add,
1897
+ save,
1898
+ ...gap.nodes,
1899
+ comment
1900
+ ];
1901
+ return {
1902
+ nodes,
1903
+ edges: nodes.map(({ id: target }) => ({
1904
+ source: "root",
1905
+ target
1906
+ }))
1907
+ };
1747
1908
  };
1748
- var Toolbar = {
1749
- Root: ToolbarRoot,
1750
- Editing,
1751
- Actions,
1752
- Separator: ToolbarSeparator
1909
+ var TableToolbar = ({ classNames, viewDirty, attendableId, onAction }) => {
1910
+ const state = (0, import_react8.useMemo)(() => (0, import_live_object2.create)({
1911
+ viewDirty
1912
+ }), []);
1913
+ const actionsCreator = (0, import_react8.useCallback)(() => createTableToolbarActions(state), [
1914
+ state
1915
+ ]);
1916
+ const menu = (0, import_react_ui_menu.useMenuActions)(actionsCreator);
1917
+ return /* @__PURE__ */ import_react8.default.createElement(import_react_ui_menu.MenuProvider, {
1918
+ ...menu,
1919
+ attendableId,
1920
+ onAction
1921
+ }, /* @__PURE__ */ import_react8.default.createElement(import_react_ui_menu.ToolbarMenu, {
1922
+ classNames
1923
+ }));
1753
1924
  };
1754
1925
  var useTableModel = ({ objects, table, projection, ...props }) => {
1755
- const [model, setModel] = (0, import_react10.useState)();
1756
- (0, import_react10.useEffect)(() => {
1926
+ const [model, setModel] = (0, import_react9.useState)();
1927
+ (0, import_react9.useEffect)(() => {
1757
1928
  if (!table || !projection) {
1758
1929
  return;
1759
1930
  }
@@ -1775,7 +1946,7 @@ var useTableModel = ({ objects, table, projection, ...props }) => {
1775
1946
  table,
1776
1947
  projection
1777
1948
  ]);
1778
- (0, import_react10.useEffect)(() => {
1949
+ (0, import_react9.useEffect)(() => {
1779
1950
  if (objects) {
1780
1951
  model?.setRows(objects);
1781
1952
  }
@@ -1794,8 +1965,8 @@ var useTableModel = ({ objects, table, projection, ...props }) => {
1794
1965
  TableModel,
1795
1966
  TablePresentation,
1796
1967
  TableSchema,
1968
+ TableToolbar,
1797
1969
  TableType,
1798
- Toolbar,
1799
1970
  initializeTable,
1800
1971
  renderCheckbox,
1801
1972
  renderSwitch,
@@ -1803,7 +1974,6 @@ var useTableModel = ({ objects, table, projection, ...props }) => {
1803
1974
  tableControls,
1804
1975
  touch,
1805
1976
  translations,
1806
- useTableModel,
1807
- useToolbarContext
1977
+ useTableModel
1808
1978
  });
1809
1979
  //# sourceMappingURL=index.cjs.map