@dxos/react-ui-table 0.7.5-main.9cb18ac → 0.7.5-main.9d2a38b

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 (67) 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 +418 -276
  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 +410 -262
  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 +418 -276
  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.map +1 -1
  22. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts +18 -0
  23. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts.map +1 -0
  24. package/dist/types/src/components/TableToolbar/index.d.ts +2 -0
  25. package/dist/types/src/components/TableToolbar/index.d.ts.map +1 -0
  26. package/dist/types/src/components/index.d.ts +1 -1
  27. package/dist/types/src/components/index.d.ts.map +1 -1
  28. package/dist/types/src/components/testing.d.ts +1 -1
  29. package/dist/types/src/model/table-model.d.ts +11 -19
  30. package/dist/types/src/model/table-model.d.ts.map +1 -1
  31. package/dist/types/src/model/table-presentation.d.ts.map +1 -1
  32. package/dist/types/src/model/table-sorting.d.ts +53 -0
  33. package/dist/types/src/model/table-sorting.d.ts.map +1 -0
  34. package/dist/types/src/translations.d.ts +2 -1
  35. package/dist/types/src/translations.d.ts.map +1 -1
  36. package/dist/types/src/types/table.d.ts +3 -3
  37. package/dist/types/src/types/table.d.ts.map +1 -1
  38. package/dist/types/src/util/table-buttons.d.ts +15 -1
  39. package/dist/types/src/util/table-buttons.d.ts.map +1 -1
  40. package/dist/types/src/util/table.d.ts +2 -1
  41. package/dist/types/src/util/table.d.ts.map +1 -1
  42. package/dist/types/tsconfig.tsbuildinfo +1 -1
  43. package/package.json +30 -29
  44. package/src/components/Table/ColumnActionsMenu.tsx +4 -4
  45. package/src/components/Table/Table.stories.tsx +33 -21
  46. package/src/components/Table/Table.tsx +4 -0
  47. package/src/components/TableToolbar/TableToolbar.tsx +72 -0
  48. package/src/components/{Toolbar → TableToolbar}/index.ts +1 -1
  49. package/src/components/index.ts +1 -1
  50. package/src/model/table-model.test.ts +0 -5
  51. package/src/model/table-model.ts +40 -98
  52. package/src/model/table-presentation.ts +7 -1
  53. package/src/model/table-sorting.ts +201 -0
  54. package/src/playwright/smoke.spec.ts +18 -11
  55. package/src/translations.ts +2 -1
  56. package/src/types/table.ts +1 -1
  57. package/src/util/table-buttons.ts +33 -3
  58. package/src/util/table.ts +78 -52
  59. package/dist/lib/node/chunk-YSBXNBDJ.cjs.map +0 -7
  60. package/dist/types/src/components/Toolbar/Toolbar.d.ts +0 -21
  61. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +0 -1
  62. package/dist/types/src/components/Toolbar/common.d.ts +0 -14
  63. package/dist/types/src/components/Toolbar/common.d.ts.map +0 -1
  64. package/dist/types/src/components/Toolbar/index.d.ts +0 -2
  65. package/dist/types/src/components/Toolbar/index.d.ts.map +0 -1
  66. package/src/components/Toolbar/Toolbar.tsx +0 -87
  67. 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="ch-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,11 +509,35 @@ 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",
@@ -634,7 +669,158 @@ 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.Ref && field.referencePath) {
813
+ const refValue = (0, import_echo_schema5.getValue)(value.target, field.referencePath);
814
+ return refValue;
815
+ }
816
+ return (0, import_react_ui_form5.formatForDisplay)({
817
+ type,
818
+ format,
819
+ value
820
+ });
821
+ }
822
+ };
823
+ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/model/table-model.ts";
638
824
  var TableModel = class extends import_context.Resource {
639
825
  constructor({ table, projection, sorting = [], pinnedRows = {
640
826
  top: [],
@@ -652,8 +838,6 @@ var TableModel = class extends import_context.Resource {
652
838
  col: 0
653
839
  }
654
840
  });
655
- this._displayToDataIndex = /* @__PURE__ */ new Map();
656
- this._sorting = (0, import_signals_core.signal)(void 0);
657
841
  this._rows = (0, import_signals_core.signal)([]);
658
842
  this.setRows = (obj) => {
659
843
  this._rows.value = obj;
@@ -661,11 +845,11 @@ var TableModel = class extends import_context.Resource {
661
845
  this.getRowCount = () => this._rows.value.length;
662
846
  this.getColumnCount = () => this.table.view?.target?.fields.length ?? 0;
663
847
  this.insertRow = (rowIndex) => {
664
- const row = rowIndex !== void 0 ? this._displayToDataIndex.get(rowIndex) ?? rowIndex : this._rows.value.length;
848
+ const row = rowIndex !== void 0 ? this._sorting.getDataIndex(rowIndex) : this._rows.value.length;
665
849
  this._onInsertRow?.(row);
666
850
  };
667
851
  this.deleteRow = (rowIndex) => {
668
- const row = this._displayToDataIndex.get(rowIndex) ?? rowIndex;
852
+ const row = this._sorting.getDataIndex(rowIndex);
669
853
  const obj = this._rows.value[row];
670
854
  const objectsToDelete = [];
671
855
  if (this._selection.hasSelection.value) {
@@ -682,7 +866,7 @@ var TableModel = class extends import_context.Resource {
682
866
  return void 0;
683
867
  }
684
868
  const field = fields[col];
685
- const dataIndex = this._displayToDataIndex.get(row) ?? row;
869
+ const dataIndex = this._sorting.getDataIndex(row);
686
870
  const value = (0, import_echo_schema3.getValue)(this._rows.value[dataIndex], field.path);
687
871
  if (value == null) {
688
872
  return "";
@@ -705,7 +889,7 @@ var TableModel = class extends import_context.Resource {
705
889
  }
706
890
  };
707
891
  this.setCellData = ({ col, row }, value) => {
708
- const rowIdx = this._displayToDataIndex.get(row) ?? row;
892
+ const rowIdx = this._sorting.getDataIndex(row);
709
893
  const fields = this.table.view?.target?.fields ?? [];
710
894
  if (col < 0 || col >= fields.length) {
711
895
  return;
@@ -731,7 +915,11 @@ var TableModel = class extends import_context.Resource {
731
915
  };
732
916
  this._table = table;
733
917
  this._projection = projection;
734
- this._sorting.value = sorting.at(0);
918
+ this._sorting = new TableSorting(this._rows, table.view?.target, projection);
919
+ if (sorting.length > 0) {
920
+ const [sort] = sorting;
921
+ this._sorting.setSort(sort.fieldId, sort.direction);
922
+ }
735
923
  this._pinnedRows = pinnedRows;
736
924
  this._onInsertRow = onInsertRow;
737
925
  this._onDeleteRows = onDeleteRows;
@@ -746,14 +934,20 @@ var TableModel = class extends import_context.Resource {
746
934
  return this._projection;
747
935
  }
748
936
  get rows() {
749
- return this._sortedRows;
937
+ return this._sorting.sortedRows;
938
+ }
939
+ /**
940
+ * @reactive
941
+ */
942
+ get sorting() {
943
+ return this._sorting;
750
944
  }
751
945
  get pinnedRows() {
752
946
  return this._pinnedRows;
753
947
  }
754
948
  get columnMeta() {
755
949
  (0, import_invariant2.invariant)(this._columnMeta, void 0, {
756
- F: __dxlog_file2,
950
+ F: __dxlog_file,
757
951
  L: 117,
758
952
  S: this,
759
953
  A: [
@@ -763,20 +957,20 @@ var TableModel = class extends import_context.Resource {
763
957
  });
764
958
  return this._columnMeta;
765
959
  }
766
- get sorting() {
767
- return this._sorting.value;
768
- }
769
960
  get selection() {
770
961
  return this._selection;
771
962
  }
963
+ /** @reactive */
964
+ get isViewDirty() {
965
+ return this._sorting.isDirty;
966
+ }
772
967
  //
773
968
  // Initialisation
774
969
  //
775
970
  async _open() {
776
971
  this.initializeColumnMeta();
777
- this.initializeSorting();
778
972
  this.initializeEffects();
779
- this._selection = new SelectionModel(this._sortedRows, () => this._onRowOrderChanged?.());
973
+ this._selection = new SelectionModel(this._sorting.sortedRows, () => this._onRowOrderChanged?.());
780
974
  await this._selection.open(this._ctx);
781
975
  }
782
976
  initializeColumnMeta() {
@@ -806,60 +1000,9 @@ var TableModel = class extends import_context.Resource {
806
1000
  };
807
1001
  });
808
1002
  }
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
1003
  initializeEffects() {
861
1004
  const rowOrderWatcher = (0, import_signals_core.effect)(() => {
862
- touch(this._sortedRows.value);
1005
+ touch(this._sorting.sortedRows.value);
863
1006
  this._onRowOrderChanged?.();
864
1007
  });
865
1008
  this._ctx.onDispose(rowOrderWatcher);
@@ -868,7 +1011,7 @@ var TableModel = class extends import_context.Resource {
868
1011
  const rowEffects = [];
869
1012
  for (let row = start.row; row <= end.row; row++) {
870
1013
  rowEffects.push((0, import_signals_core.effect)(() => {
871
- const obj = this._sortedRows.value[row];
1014
+ const obj = this._sorting.sortedRows.value[row];
872
1015
  this?._table?.view?.target?.fields.forEach((field) => touch((0, import_echo_schema3.getValue)(obj, field.path)));
873
1016
  this._onCellUpdate?.({
874
1017
  row,
@@ -887,7 +1030,7 @@ var TableModel = class extends import_context.Resource {
887
1030
  * @param {(value: any) => any} update - A function that takes the current value and returns the updated value.
888
1031
  */
889
1032
  updateCellData({ col, row }, update) {
890
- const dataRow = this._displayToDataIndex.get(row) ?? row;
1033
+ const dataRow = this._sorting.getDataIndex(row);
891
1034
  const fields = this.table.view?.target?.fields ?? [];
892
1035
  const field = fields[col];
893
1036
  const value = (0, import_echo_schema3.getValue)(this._rows.value[dataRow], field.path);
@@ -903,9 +1046,6 @@ var TableModel = class extends import_context.Resource {
903
1046
  }
904
1047
  const field = this.table.view.target?.fields.find((field2) => field2.id === fieldId);
905
1048
  if (field && this._onDeleteColumn) {
906
- if (this._sorting.value?.fieldId === fieldId) {
907
- this.clearSort();
908
- }
909
1049
  this._onDeleteColumn(field.id);
910
1050
  }
911
1051
  }
@@ -923,18 +1063,6 @@ var TableModel = class extends import_context.Resource {
923
1063
  }
924
1064
  }
925
1065
  //
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
1066
  // Pinning
939
1067
  //
940
1068
  // TODO(burdon): Change to setPinned(on/off).
@@ -945,11 +1073,17 @@ var TableModel = class extends import_context.Resource {
945
1073
  this._pinnedRows.top = this._pinnedRows.top.filter((index) => index !== rowIndex);
946
1074
  this._pinnedRows.bottom = this._pinnedRows.bottom.filter((index) => index !== rowIndex);
947
1075
  }
1076
+ //
1077
+ // View operations
1078
+ //
1079
+ saveView() {
1080
+ this._sorting.save();
1081
+ }
948
1082
  };
949
- var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/model/modal-controller.ts";
1083
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/model/modal-controller.ts";
950
1084
  var ModalController = class {
951
1085
  constructor() {
952
- this._state = (0, import_signals_core3.signal)({
1086
+ this._state = (0, import_signals_core4.signal)({
953
1087
  type: "closed"
954
1088
  });
955
1089
  this._triggerRef = {
@@ -1009,8 +1143,8 @@ var ModalController = class {
1009
1143
  onCreate
1010
1144
  };
1011
1145
  } else {
1012
- import_log2.log.warn("anchor cell not found while creating new ref", void 0, {
1013
- F: __dxlog_file3,
1146
+ import_log.log.warn("anchor cell not found while creating new ref", void 0, {
1147
+ F: __dxlog_file2,
1014
1148
  L: 86,
1015
1149
  S: this,
1016
1150
  C: (f, a) => f(...a)
@@ -1031,7 +1165,7 @@ var ModalController = class {
1031
1165
  }
1032
1166
  };
1033
1167
  var TablePresentation = class {
1034
- constructor(model, _visibleRange = (0, import_signals_core4.signal)({
1168
+ constructor(model, _visibleRange = (0, import_signals_core5.signal)({
1035
1169
  start: {
1036
1170
  row: 0,
1037
1171
  col: 0
@@ -1070,22 +1204,22 @@ var TablePresentation = class {
1070
1204
  const { props } = this.model.projection.getFieldProjection(field.id);
1071
1205
  const cell = {
1072
1206
  get value() {
1073
- const value = (0, import_echo_schema5.getValue)(obj, field.path);
1207
+ const value = (0, import_echo_schema6.getValue)(obj, field.path);
1074
1208
  if (value == null) {
1075
1209
  return "";
1076
1210
  }
1077
1211
  switch (props.format) {
1078
- case import_echo_schema5.FormatEnum.Boolean: {
1212
+ case import_echo_schema6.FormatEnum.Boolean: {
1079
1213
  return "";
1080
1214
  }
1081
- case import_echo_schema5.FormatEnum.Ref: {
1215
+ case import_echo_schema6.FormatEnum.Ref: {
1082
1216
  if (!field.referencePath) {
1083
1217
  return "";
1084
1218
  }
1085
- return (0, import_echo_schema5.getValue)(value.target, field.referencePath);
1219
+ return (0, import_echo_schema6.getValue)(value.target, field.referencePath);
1086
1220
  }
1087
1221
  default: {
1088
- return (0, import_react_ui_form5.formatForDisplay)({
1222
+ return (0, import_react_ui_form6.formatForDisplay)({
1089
1223
  type: props.type,
1090
1224
  format: props.format,
1091
1225
  value
@@ -1095,22 +1229,22 @@ var TablePresentation = class {
1095
1229
  }
1096
1230
  };
1097
1231
  const classes = [];
1098
- const formatClasses = (0, import_react_ui_form5.cellClassesForFieldType)({
1232
+ const formatClasses = (0, import_react_ui_form6.cellClassesForFieldType)({
1099
1233
  type: props.type,
1100
1234
  format: props.format
1101
1235
  });
1102
1236
  if (formatClasses) {
1103
1237
  classes.push(formatClasses);
1104
1238
  }
1105
- const rowSelectionClasses = (0, import_react_ui_form5.cellClassesForRowSelection)(this.model.selection.isObjectSelected(obj));
1239
+ const rowSelectionClasses = (0, import_react_ui_form6.cellClassesForRowSelection)(this.model.selection.isObjectSelected(obj));
1106
1240
  if (rowSelectionClasses) {
1107
1241
  classes.push(rowSelectionClasses);
1108
1242
  }
1109
1243
  if (classes.length > 0) {
1110
1244
  cell.className = (0, import_react_ui_theme2.mx)(classes.flat());
1111
1245
  }
1112
- if (props.format === import_echo_schema5.FormatEnum.Ref && props.referenceSchema) {
1113
- const targetObj = (0, import_echo_schema5.getValue)(obj, field.path)?.target;
1246
+ if (props.format === import_echo_schema6.FormatEnum.Ref && props.referenceSchema) {
1247
+ const targetObj = (0, import_echo_schema6.getValue)(obj, field.path)?.target;
1114
1248
  if (targetObj) {
1115
1249
  cell.accessoryHtml = tableButtons.referencedCell.render({
1116
1250
  targetId: targetObj.id,
@@ -1118,8 +1252,8 @@ var TablePresentation = class {
1118
1252
  });
1119
1253
  }
1120
1254
  }
1121
- if (props.format === import_echo_schema5.FormatEnum.Boolean) {
1122
- const value = (0, import_echo_schema5.getValue)(obj, field.path);
1255
+ if (props.format === import_echo_schema6.FormatEnum.Boolean) {
1256
+ const value = (0, import_echo_schema6.getValue)(obj, field.path);
1123
1257
  cell.accessoryHtml = tableControls.switch.render({
1124
1258
  colIndex,
1125
1259
  rowIndex: displayIndex,
@@ -1149,6 +1283,8 @@ var TablePresentation = class {
1149
1283
  const fields = this.model.table.view?.target?.fields ?? [];
1150
1284
  for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
1151
1285
  const { field, props } = this.model.projection.getFieldProjection(fields[col].id);
1286
+ const sorting = this.model.sorting?.sorting;
1287
+ const direction = sorting?.fieldId === field.id ? sorting.direction : void 0;
1152
1288
  cells[(0, import_react_ui_grid3.toPlaneCellIndex)({
1153
1289
  col,
1154
1290
  row: 0
@@ -1157,9 +1293,15 @@ var TablePresentation = class {
1157
1293
  value: props.title ?? field.path,
1158
1294
  readonly: true,
1159
1295
  resizeHandle: "col",
1160
- accessoryHtml: tableButtons.columnSettings.render({
1296
+ accessoryHtml: `
1297
+ ${direction !== void 0 ? tableButtons.sort.render({
1298
+ fieldId: field.id,
1299
+ direction
1300
+ }) : ""}
1301
+ ${tableButtons.columnSettings.render({
1161
1302
  fieldId: field.id
1162
- }),
1303
+ })}
1304
+ `,
1163
1305
  className: "!bg-gridHeader"
1164
1306
  };
1165
1307
  }
@@ -1169,7 +1311,7 @@ var TablePresentation = class {
1169
1311
  const cells = {};
1170
1312
  for (let row = range.start.row; row <= range.end.row && row < this.model.getRowCount(); row++) {
1171
1313
  const isSelected = this.model.selection.isRowIndexSelected(row);
1172
- const classes = (0, import_react_ui_form5.cellClassesForRowSelection)(isSelected);
1314
+ const classes = (0, import_react_ui_form6.cellClassesForRowSelection)(isSelected);
1173
1315
  cells[(0, import_react_ui_grid3.toPlaneCellIndex)({
1174
1316
  col: 0,
1175
1317
  row
@@ -1189,7 +1331,7 @@ var TablePresentation = class {
1189
1331
  const cells = {};
1190
1332
  for (let row = range.start.row; row <= range.end.row && row < this.model.getRowCount(); row++) {
1191
1333
  const isSelected = this.model.selection.isRowIndexSelected(row);
1192
- const classes = (0, import_react_ui_form5.cellClassesForRowSelection)(isSelected);
1334
+ const classes = (0, import_react_ui_form6.cellClassesForRowSelection)(isSelected);
1193
1335
  cells[(0, import_react_ui_grid3.toPlaneCellIndex)({
1194
1336
  col: 0,
1195
1337
  row
@@ -1272,7 +1414,7 @@ var completion = ({ debug, onQuery, onMatch }) => {
1272
1414
  })
1273
1415
  ];
1274
1416
  };
1275
- var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx";
1417
+ var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx";
1276
1418
  var newValue = Symbol.for("newValue");
1277
1419
  var createOption = (text) => ({
1278
1420
  [newValue]: true,
@@ -1290,7 +1432,7 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }
1290
1432
  const field = model.projection.view.fields[col];
1291
1433
  const fieldProjection2 = model.projection.getFieldProjection(field.id);
1292
1434
  (0, import_invariant3.invariant)(fieldProjection2, void 0, {
1293
- F: __dxlog_file4,
1435
+ F: __dxlog_file3,
1294
1436
  L: 67,
1295
1437
  S: void 0,
1296
1438
  A: [
@@ -1364,7 +1506,7 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }
1364
1506
  ];
1365
1507
  if (onQuery) {
1366
1508
  switch (fieldProjection.props.format) {
1367
- case import_echo_schema6.FormatEnum.Ref: {
1509
+ case import_echo_schema7.FormatEnum.Ref: {
1368
1510
  extension2.push([
1369
1511
  completion({
1370
1512
  onQuery: (text) => onQuery(fieldProjection, text),
@@ -1438,7 +1580,7 @@ var determineNavigationDelta = ({ key, shift }) => {
1438
1580
  }
1439
1581
  return shift ? -1 : 1;
1440
1582
  };
1441
- var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/Table/Table.tsx";
1583
+ var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/Table/Table.tsx";
1442
1584
  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";
1443
1585
  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";
1444
1586
  var frozen = {
@@ -1506,6 +1648,10 @@ var TableMain = /* @__PURE__ */ (0, import_react.forwardRef)(({ model, presentat
1506
1648
  modals.showReferencePanel(data.targetId, data.schemaId);
1507
1649
  break;
1508
1650
  }
1651
+ case "sort": {
1652
+ model?.sorting?.toggleSort(data.fieldId);
1653
+ break;
1654
+ }
1509
1655
  }
1510
1656
  return;
1511
1657
  }
@@ -1606,8 +1752,8 @@ var TableMain = /* @__PURE__ */ (0, import_react.forwardRef)(({ model, presentat
1606
1752
  if (model && props.referenceSchema && field.referencePath) {
1607
1753
  const space = (0, import_echo.getSpace)(model.table);
1608
1754
  (0, import_invariant.invariant)(space, void 0, {
1609
- F: __dxlog_file5,
1610
- L: 260,
1755
+ F: __dxlog_file4,
1756
+ L: 264,
1611
1757
  S: void 0,
1612
1758
  A: [
1613
1759
  "space",
@@ -1690,73 +1836,76 @@ var Table = {
1690
1836
  Root: TableRoot,
1691
1837
  Main: TableMain
1692
1838
  };
1693
- var buttonStyles = "min-bs-0 p-2";
1694
- var tooltipProps = {
1695
- side: "top",
1696
- classNames: "z-10"
1697
- };
1698
- var ToolbarSeparator = () => /* @__PURE__ */ import_react9.default.createElement("div", {
1699
- role: "separator",
1700
- className: "grow"
1701
- });
1702
- var ToolbarButton = ({ icon, children, ...props }) => {
1703
- return /* @__PURE__ */ import_react9.default.createElement(import_react_ui8.Tooltip.Root, null, /* @__PURE__ */ import_react9.default.createElement(import_react_ui8.Tooltip.Trigger, {
1704
- asChild: true
1705
- }, /* @__PURE__ */ import_react9.default.createElement(import_react_ui8.Toolbar.Button, {
1706
- variant: "ghost",
1707
- ...props,
1708
- classNames: buttonStyles
1709
- }, /* @__PURE__ */ import_react9.default.createElement(import_react_ui8.Icon, {
1710
- icon,
1711
- size: 5
1712
- }), /* @__PURE__ */ import_react9.default.createElement("span", {
1713
- className: "sr-only"
1714
- }, 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))));
1715
- };
1716
- var [ToolbarContextProvider, useToolbarContext] = (0, import_react_context.createContext)("Toolbar");
1717
- var ToolbarRoot = ({ classNames, children, onAction }) => {
1718
- return /* @__PURE__ */ import_react8.default.createElement(ToolbarContextProvider, {
1719
- onAction
1720
- }, /* @__PURE__ */ import_react8.default.createElement(import_react_ui7.Toolbar.Root, {
1721
- classNames: [
1722
- "is-full shrink-0 overflow-x-auto overflow-y-hidden p-1 attention-surface",
1723
- classNames
1724
- ]
1725
- }, children));
1726
- };
1727
- var Editing = () => {
1728
- const { onAction } = useToolbarContext("Editing");
1729
- const { t } = (0, import_react_ui7.useTranslation)(translationKey);
1730
- return /* @__PURE__ */ import_react8.default.createElement(import_react8.default.Fragment, null, /* @__PURE__ */ import_react8.default.createElement(ToolbarButton, {
1731
- value: "add-row",
1839
+ var createTableToolbarActions = (state) => {
1840
+ const add = (0, import_react_ui_menu.createMenuAction)("add-row", {
1841
+ type: "add-row",
1732
1842
  icon: "ph--plus--regular",
1733
- "data-testid": "table.toolbar.add-row",
1734
- onClick: () => onAction?.({
1735
- type: "add-row"
1736
- })
1737
- }, t("add row")));
1738
- };
1739
- var Actions = () => {
1740
- const { onAction } = useToolbarContext("Actions");
1741
- const { t } = (0, import_react_ui7.useTranslation)(translationKey);
1742
- return /* @__PURE__ */ import_react8.default.createElement(import_react8.default.Fragment, null, /* @__PURE__ */ import_react8.default.createElement(ToolbarButton, {
1743
- value: "comment",
1843
+ label: [
1844
+ "add row",
1845
+ {
1846
+ ns: translationKey
1847
+ }
1848
+ ],
1849
+ testId: "table.toolbar.add-row"
1850
+ });
1851
+ const save = (0, import_react_ui_menu.createMenuAction)("save-view", {
1852
+ type: "save-view",
1853
+ icon: "ph--floppy-disk--regular",
1854
+ label: [
1855
+ "save view label",
1856
+ {
1857
+ ns: translationKey
1858
+ }
1859
+ ],
1860
+ testId: "table.toolbar.save-view",
1861
+ iconOnly: false,
1862
+ hidden: !state.viewDirty
1863
+ });
1864
+ const gap = (0, import_react_ui_menu.createGapSeparator)();
1865
+ const comment = (0, import_react_ui_menu.createMenuAction)("comment", {
1866
+ type: "comment",
1744
1867
  icon: "ph--chat-text--regular",
1745
- "data-testid": "table.toolbar.comment",
1746
- onClick: () => onAction?.({
1747
- type: "comment"
1748
- })
1749
- }, t("create comment")));
1868
+ label: [
1869
+ "create comment",
1870
+ {
1871
+ ns: translationKey
1872
+ }
1873
+ ],
1874
+ testId: "table.toolbar.comment"
1875
+ });
1876
+ const nodes = [
1877
+ add,
1878
+ save,
1879
+ ...gap.nodes,
1880
+ comment
1881
+ ];
1882
+ return {
1883
+ nodes,
1884
+ edges: nodes.map(({ id: target }) => ({
1885
+ source: "root",
1886
+ target
1887
+ }))
1888
+ };
1750
1889
  };
1751
- var Toolbar = {
1752
- Root: ToolbarRoot,
1753
- Editing,
1754
- Actions,
1755
- Separator: ToolbarSeparator
1890
+ var TableToolbar = ({ classNames, viewDirty, attendableId, onAction }) => {
1891
+ const state = (0, import_react8.useMemo)(() => (0, import_live_object2.create)({
1892
+ viewDirty
1893
+ }), []);
1894
+ const actionsCreator = (0, import_react8.useCallback)(() => createTableToolbarActions(state), [
1895
+ state
1896
+ ]);
1897
+ const menu = (0, import_react_ui_menu.useMenuActions)(actionsCreator);
1898
+ return /* @__PURE__ */ import_react8.default.createElement(import_react_ui_menu.MenuProvider, {
1899
+ ...menu,
1900
+ attendableId,
1901
+ onAction
1902
+ }, /* @__PURE__ */ import_react8.default.createElement(import_react_ui_menu.ToolbarMenu, {
1903
+ classNames
1904
+ }));
1756
1905
  };
1757
1906
  var useTableModel = ({ objects, table, projection, ...props }) => {
1758
- const [model, setModel] = (0, import_react10.useState)();
1759
- (0, import_react10.useEffect)(() => {
1907
+ const [model, setModel] = (0, import_react9.useState)();
1908
+ (0, import_react9.useEffect)(() => {
1760
1909
  if (!table || !projection) {
1761
1910
  return;
1762
1911
  }
@@ -1778,7 +1927,7 @@ var useTableModel = ({ objects, table, projection, ...props }) => {
1778
1927
  table,
1779
1928
  projection
1780
1929
  ]);
1781
- (0, import_react10.useEffect)(() => {
1930
+ (0, import_react9.useEffect)(() => {
1782
1931
  if (objects) {
1783
1932
  model?.setRows(objects);
1784
1933
  }
@@ -1797,8 +1946,8 @@ var useTableModel = ({ objects, table, projection, ...props }) => {
1797
1946
  TableModel,
1798
1947
  TablePresentation,
1799
1948
  TableSchema,
1949
+ TableToolbar,
1800
1950
  TableType,
1801
- Toolbar,
1802
1951
  initializeTable,
1803
1952
  renderCheckbox,
1804
1953
  renderSwitch,
@@ -1806,7 +1955,6 @@ var useTableModel = ({ objects, table, projection, ...props }) => {
1806
1955
  tableControls,
1807
1956
  touch,
1808
1957
  translations,
1809
- useTableModel,
1810
- useToolbarContext
1958
+ useTableModel
1811
1959
  });
1812
1960
  //# sourceMappingURL=index.cjs.map