@dxos/react-ui-table 0.7.5-main.499c70c → 0.7.5-main.6a330ac

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 (117) hide show
  1. package/dist/lib/browser/{chunk-AT7O4RAD.mjs → chunk-3FR6NHPD.mjs} +6 -4
  2. package/dist/lib/browser/chunk-3FR6NHPD.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +482 -284
  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-NB3SFHGA.cjs} +8 -6
  8. package/dist/lib/node/chunk-NB3SFHGA.cjs.map +7 -0
  9. package/dist/lib/node/index.cjs +474 -270
  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-RLVVOZW5.mjs} +6 -4
  15. package/dist/lib/node-esm/chunk-RLVVOZW5.mjs.map +7 -0
  16. package/dist/lib/node-esm/index.mjs +482 -284
  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/_deprecated/components/Cell/Cell.d.ts +2 -2
  21. package/dist/types/src/_deprecated/components/Cell/Cell.d.ts.map +1 -1
  22. package/dist/types/src/_deprecated/components/Cell/CellCombobox.d.ts +1 -2
  23. package/dist/types/src/_deprecated/components/Cell/CellCombobox.d.ts.map +1 -1
  24. package/dist/types/src/_deprecated/components/ColumnMenu/ColumnMenu.d.ts +2 -3
  25. package/dist/types/src/_deprecated/components/ColumnMenu/ColumnMenu.d.ts.map +1 -1
  26. package/dist/types/src/_deprecated/components/ColumnMenu/ColumnMenu.stories.d.ts +6 -7
  27. package/dist/types/src/_deprecated/components/ColumnMenu/ColumnMenu.stories.d.ts.map +1 -1
  28. package/dist/types/src/_deprecated/components/ColumnMenu/ColumnSettings.d.ts +1 -2
  29. package/dist/types/src/_deprecated/components/ColumnMenu/ColumnSettings.d.ts.map +1 -1
  30. package/dist/types/src/_deprecated/components/ColumnMenu/ColumnSettings.stories.d.ts +6 -7
  31. package/dist/types/src/_deprecated/components/ColumnMenu/ColumnSettings.stories.d.ts.map +1 -1
  32. package/dist/types/src/_deprecated/components/Table/Table.d.ts +5 -5
  33. package/dist/types/src/_deprecated/components/Table/Table.d.ts.map +1 -1
  34. package/dist/types/src/_deprecated/components/Table/Table.stories.d.ts +8 -9
  35. package/dist/types/src/_deprecated/components/Table/Table.stories.d.ts.map +1 -1
  36. package/dist/types/src/_deprecated/components/Table/TableBody.d.ts +1 -2
  37. package/dist/types/src/_deprecated/components/Table/TableBody.d.ts.map +1 -1
  38. package/dist/types/src/_deprecated/components/Table/TableContext.d.ts +1 -1
  39. package/dist/types/src/_deprecated/components/Table/TableContext.d.ts.map +1 -1
  40. package/dist/types/src/_deprecated/components/Table/TableHead.d.ts +1 -2
  41. package/dist/types/src/_deprecated/components/Table/TableHead.d.ts.map +1 -1
  42. package/dist/types/src/_deprecated/schema/Schema.stories.d.ts +2 -3
  43. package/dist/types/src/_deprecated/schema/Schema.stories.d.ts.map +1 -1
  44. package/dist/types/src/components/Table/ColumnActionsMenu.d.ts +1 -2
  45. package/dist/types/src/components/Table/ColumnActionsMenu.d.ts.map +1 -1
  46. package/dist/types/src/components/Table/ColumnSettings.d.ts +1 -2
  47. package/dist/types/src/components/Table/ColumnSettings.d.ts.map +1 -1
  48. package/dist/types/src/components/Table/CreateRefPanel.d.ts +1 -2
  49. package/dist/types/src/components/Table/CreateRefPanel.d.ts.map +1 -1
  50. package/dist/types/src/components/Table/RefPanel.d.ts +1 -2
  51. package/dist/types/src/components/Table/RefPanel.d.ts.map +1 -1
  52. package/dist/types/src/components/Table/RowActionsMenu.d.ts +1 -2
  53. package/dist/types/src/components/Table/RowActionsMenu.d.ts.map +1 -1
  54. package/dist/types/src/components/Table/Table.d.ts +1 -1
  55. package/dist/types/src/components/Table/Table.d.ts.map +1 -1
  56. package/dist/types/src/components/Table/Table.stories.d.ts +1 -4
  57. package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
  58. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +1 -2
  59. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
  60. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts +17 -0
  61. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts.map +1 -0
  62. package/dist/types/src/components/TableToolbar/index.d.ts +2 -0
  63. package/dist/types/src/components/TableToolbar/index.d.ts.map +1 -0
  64. package/dist/types/src/components/index.d.ts +1 -1
  65. package/dist/types/src/components/index.d.ts.map +1 -1
  66. package/dist/types/src/components/testing.d.ts +12 -35
  67. package/dist/types/src/components/testing.d.ts.map +1 -1
  68. package/dist/types/src/hooks/useTableModel.d.ts.map +1 -1
  69. package/dist/types/src/model/table-model.d.ts +11 -19
  70. package/dist/types/src/model/table-model.d.ts.map +1 -1
  71. package/dist/types/src/model/table-presentation.d.ts.map +1 -1
  72. package/dist/types/src/model/table-sorting.d.ts +53 -0
  73. package/dist/types/src/model/table-sorting.d.ts.map +1 -0
  74. package/dist/types/src/translations.d.ts +2 -1
  75. package/dist/types/src/translations.d.ts.map +1 -1
  76. package/dist/types/src/types/table.d.ts +21 -90
  77. package/dist/types/src/types/table.d.ts.map +1 -1
  78. package/dist/types/src/util/table-buttons.d.ts +15 -1
  79. package/dist/types/src/util/table-buttons.d.ts.map +1 -1
  80. package/dist/types/src/util/table.d.ts +2 -1
  81. package/dist/types/src/util/table.d.ts.map +1 -1
  82. package/dist/types/tsconfig.tsbuildinfo +1 -1
  83. package/package.json +36 -34
  84. package/src/_deprecated/schema/Schema.stories.tsx +1 -1
  85. package/src/components/Table/ColumnActionsMenu.tsx +4 -4
  86. package/src/components/Table/CreateRefPanel.tsx +3 -4
  87. package/src/components/Table/Table.stories.tsx +55 -44
  88. package/src/components/Table/Table.tsx +4 -0
  89. package/src/components/TableCellEditor/TableCellEditor.stories.tsx +1 -1
  90. package/src/components/TableToolbar/TableToolbar.tsx +72 -0
  91. package/src/components/{Toolbar → TableToolbar}/index.ts +1 -1
  92. package/src/components/index.ts +1 -1
  93. package/src/hooks/useTableModel.ts +21 -0
  94. package/src/model/table-model.test.ts +0 -5
  95. package/src/model/table-model.ts +41 -99
  96. package/src/model/table-presentation.ts +25 -4
  97. package/src/model/table-sorting.ts +215 -0
  98. package/src/playwright/smoke.spec.ts +35 -13
  99. package/src/translations.ts +2 -1
  100. package/src/types/table.ts +3 -3
  101. package/src/util/table-buttons.ts +33 -3
  102. package/src/util/table-controls.ts +2 -2
  103. package/src/util/table.ts +85 -52
  104. package/dist/lib/browser/chunk-AT7O4RAD.mjs.map +0 -7
  105. package/dist/lib/node/chunk-YSBXNBDJ.cjs.map +0 -7
  106. package/dist/lib/node-esm/chunk-6OH2NHUX.mjs.map +0 -7
  107. package/dist/types/src/components/Toolbar/Toolbar.d.ts +0 -21
  108. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +0 -1
  109. package/dist/types/src/components/Toolbar/common.d.ts +0 -14
  110. package/dist/types/src/components/Toolbar/common.d.ts.map +0 -1
  111. package/dist/types/src/components/Toolbar/index.d.ts +0 -2
  112. package/dist/types/src/components/Toolbar/index.d.ts.map +0 -1
  113. package/dist/types/src/playwright/playwright.config.d.ts +0 -3
  114. package/dist/types/src/playwright/playwright.config.d.ts.map +0 -1
  115. package/src/components/Toolbar/Toolbar.tsx +0 -87
  116. package/src/components/Toolbar/common.tsx +0 -71
  117. /package/src/playwright/{playwright.config.ts → playwright.config.cts} +0 -0
@@ -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_NB3SFHGA.TableSchema,
38
+ TableToolbar: () => TableToolbar,
39
+ TableType: () => import_chunk_NB3SFHGA.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_NB3SFHGA = require("./chunk-NB3SFHGA.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,34 @@ 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_signals_core6 = require("@preact/signals-core");
113
+ var import_react9 = require("react");
114
+ var import_react_ui_attention2 = require("@dxos/react-ui-attention");
115
+ var import_util2 = require("@dxos/util");
114
116
  var translationKey = "table";
115
117
  var translations_default = [
116
118
  {
@@ -124,7 +126,7 @@ var translations_default = [
124
126
  "new schema": "New schema",
125
127
  "continue label": "Continue",
126
128
  "create stack section label": "Create table",
127
- "add row": "Add row",
129
+ "add row label": "Add row",
128
130
  "create comment": "Create thread",
129
131
  "column action sort descending": "Sort Descending",
130
132
  "column action sort ascending": "Sort Ascending",
@@ -135,7 +137,8 @@ var translations_default = [
135
137
  "bulk delete row label": "Delete selected rows",
136
138
  "column deleted label": "Column deleted",
137
139
  "new column button label": "Create column",
138
- "create new object label": "Create new object \u201C{{text}}\u201D"
140
+ "create new object label": "Create new object \u201C{{text}}\u201D",
141
+ "save view label": "Save changes to view"
139
142
  }
140
143
  }
141
144
  }
@@ -146,7 +149,7 @@ var ColumnActionsMenu = ({ model, modals }) => {
146
149
  if (state?.type !== "column") {
147
150
  return null;
148
151
  }
149
- const currentSort = model.sorting;
152
+ const currentSort = model.sorting?.sorting;
150
153
  const isCurrentColumnSorted = currentSort?.fieldId === state.fieldId;
151
154
  return /* @__PURE__ */ import_react2.default.createElement(import_react_ui2.DropdownMenu.Root, {
152
155
  modal: false,
@@ -156,13 +159,13 @@ var ColumnActionsMenu = ({ model, modals }) => {
156
159
  virtualRef: modals.trigger
157
160
  }), /* @__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
161
  "data-testid": "column-sort-descending",
159
- onClick: () => model.setSort(state.fieldId, "desc")
162
+ onClick: () => model.sorting?.setSort(state.fieldId, "desc")
160
163
  }, t("column action sort descending")), (!isCurrentColumnSorted || currentSort?.direction === "desc") && /* @__PURE__ */ import_react2.default.createElement(import_react_ui2.DropdownMenu.Item, {
161
164
  "data-testid": "column-sort-ascending",
162
- onClick: () => model.setSort(state.fieldId, "asc")
165
+ onClick: () => model.sorting?.setSort(state.fieldId, "asc")
163
166
  }, t("column action sort ascending")), isCurrentColumnSorted && /* @__PURE__ */ import_react2.default.createElement(import_react_ui2.DropdownMenu.Item, {
164
167
  "data-testid": "column-clear-sort",
165
- onClick: () => model.clearSort()
168
+ onClick: () => model.sorting?.clearSort()
166
169
  }, t("column action clear sorting")), model.getColumnCount() > 1 && /* @__PURE__ */ import_react2.default.createElement(import_react_ui2.DropdownMenu.Item, {
167
170
  "data-testid": "column-delete",
168
171
  onClick: () => model.deleteColumn(state.fieldId)
@@ -242,7 +245,9 @@ var CreateRefPanel = ({ model, modals, __gridScope }) => {
242
245
  if (!space || state?.type !== "createRefPanel") {
243
246
  return;
244
247
  }
245
- const schema2 = space.db.schemaRegistry.getSchema(state.typename)?.schema;
248
+ const [schema2] = space.db.schemaRegistry.query({
249
+ typename: state.typename
250
+ }).runSync();
246
251
  if (schema2) {
247
252
  const omit = import_echo_schema2.S.omit("id");
248
253
  return omit(schema2);
@@ -255,7 +260,9 @@ var CreateRefPanel = ({ model, modals, __gridScope }) => {
255
260
  if (!model || !space || state?.type !== "createRefPanel") {
256
261
  return;
257
262
  }
258
- const schema2 = space.db.schemaRegistry.getSchema(state.typename)?.schema;
263
+ const [schema2] = space.db.schemaRegistry.query({
264
+ typename: state.typename
265
+ }).runSync();
259
266
  if (schema2) {
260
267
  const obj = space.db.add((0, import_echo3.create)(schema2, values));
261
268
  state.onCreate?.(obj);
@@ -348,79 +355,97 @@ var RowActionsMenu = ({ model, modals }) => {
348
355
  }, t(hasSelection ? "bulk delete row label" : "delete row label"))), /* @__PURE__ */ import_react6.default.createElement(import_react_ui6.DropdownMenu.Arrow, null)));
349
356
  };
350
357
  var touch = (value) => value;
351
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/util/table.ts";
352
- var initializeTable = async ({ space, table, initialRow = true }) => {
353
- (0, import_log.log)("initializeTable", {
354
- table
355
- }, {
356
- F: __dxlog_file,
357
- L: 36,
358
- S: void 0,
359
- C: (f, a) => f(...a)
360
- });
361
- const ContactSchema = (0, import_echo_schema4.TypedObject)({
362
- typename: `example.com/type/${import_react_client2.PublicKey.random().truncate()}`,
363
- version: "0.1.0"
364
- })({
365
- name: import_echo_schema4.S.optional(import_echo_schema4.S.String).annotations({
366
- [import_echo_schema4.AST.TitleAnnotationId]: "Name"
367
- }),
368
- active: import_echo_schema4.S.optional(import_echo_schema4.S.Boolean),
369
- email: import_echo_schema4.S.optional(import_echo_schema4.Format.Email),
370
- salary: import_echo_schema4.S.optional(import_echo_schema4.Format.Currency()).annotations({
371
- [import_echo_schema4.AST.TitleAnnotationId]: "Salary"
372
- })
373
- });
374
- const [contactSchema] = await space.db.schemaRegistry.register([
375
- ContactSchema
376
- ]);
377
- table.view = (0, import_echo5.makeRef)((0, import_schema.createView)({
378
- name: "Test",
379
- typename: contactSchema.typename,
380
- jsonSchema: contactSchema.jsonSchema,
381
- fields: [
382
- "name",
383
- "active",
384
- "email",
385
- "salary"
386
- ]
387
- }));
388
- const projection = new import_schema.ViewProjection(contactSchema, table.view.target);
389
- projection.setFieldProjection({
390
- field: {
391
- id: table.view.target.fields.find((f) => f.path === "salary").id,
392
- path: "salary",
393
- size: 150
358
+ var initializeTable = async ({ space, table, initialRow = true, initialSchema }) => {
359
+ if (initialSchema) {
360
+ const schema = await space.db.schemaRegistry.query({
361
+ typename: initialSchema
362
+ }).firstOrUndefined();
363
+ if (!schema) {
364
+ throw new Error(`Schema not found: ${initialSchema}`);
394
365
  }
395
- });
396
- projection.setFieldProjection({
397
- field: {
398
- id: (0, import_schema.createFieldId)(),
399
- path: "manager",
400
- referencePath: "name"
401
- },
402
- props: {
403
- property: "manager",
404
- type: import_echo_schema4.TypeEnum.Ref,
405
- format: import_echo_schema4.FormatEnum.Ref,
406
- referenceSchema: contactSchema.typename,
407
- title: "Manager"
366
+ const fields = (0, import_schema.getSchemaProperties)(schema.ast).filter((prop) => prop.format !== import_echo_schema4.FormatEnum.Ref).map((prop) => prop.name);
367
+ table.view = (0, import_echo5.makeRef)((0, import_schema.createView)({
368
+ // TODO(ZaymonFC): Don't hardcode name?
369
+ name: "View",
370
+ typename: schema.typename,
371
+ jsonSchema: schema.jsonSchema,
372
+ fields
373
+ }));
374
+ return schema;
375
+ } else {
376
+ const ContactSchema = (0, import_echo_schema4.TypedObject)({
377
+ typename: `example.com/type/${import_react_client2.PublicKey.random().truncate()}`,
378
+ version: "0.1.0"
379
+ })({
380
+ name: import_echo_schema4.S.optional(import_echo_schema4.S.String).annotations({
381
+ [import_echo_schema4.AST.TitleAnnotationId]: "Name"
382
+ }),
383
+ active: import_echo_schema4.S.optional(import_echo_schema4.S.Boolean),
384
+ email: import_echo_schema4.S.optional(import_echo_schema4.Format.Email),
385
+ salary: import_echo_schema4.S.optional(import_echo_schema4.Format.Currency()).annotations({
386
+ [import_echo_schema4.AST.TitleAnnotationId]: "Salary"
387
+ })
388
+ });
389
+ const [contactSchema] = await space.db.schemaRegistry.register([
390
+ ContactSchema
391
+ ]);
392
+ table.view = (0, import_echo5.makeRef)((0, import_schema.createView)({
393
+ name: "View",
394
+ typename: contactSchema.typename,
395
+ jsonSchema: contactSchema.jsonSchema,
396
+ fields: [
397
+ "name",
398
+ "email",
399
+ "salary",
400
+ "active"
401
+ ]
402
+ }));
403
+ const projection = new import_schema.ViewProjection(contactSchema, table.view.target);
404
+ projection.setFieldProjection({
405
+ field: {
406
+ id: table.view.target.fields.find((f) => f.path === "salary").id,
407
+ path: "salary",
408
+ size: 150
409
+ }
410
+ });
411
+ projection.setFieldProjection({
412
+ field: {
413
+ id: table.view.target.fields.find((f) => f.path === "active").id,
414
+ path: "active",
415
+ size: 100
416
+ }
417
+ });
418
+ projection.setFieldProjection({
419
+ field: {
420
+ id: (0, import_schema.createFieldId)(),
421
+ path: "manager",
422
+ referencePath: "name"
423
+ },
424
+ props: {
425
+ property: "manager",
426
+ type: import_echo_schema4.TypeEnum.Ref,
427
+ format: import_echo_schema4.FormatEnum.Ref,
428
+ referenceSchema: contactSchema.typename,
429
+ title: "Manager"
430
+ }
431
+ });
432
+ if (initialRow) {
433
+ space.db.add((0, import_echo5.create)(contactSchema, {}));
408
434
  }
409
- });
410
- if (initialRow) {
411
- space.db.add((0, import_echo5.create)(contactSchema, {}));
435
+ return contactSchema;
412
436
  }
413
- return contactSchema;
414
437
  };
415
438
  var BUTTON_IDENTIFIERS = {
416
439
  columnSettings: "data-table-column-settings-button",
417
440
  newColumn: "data-table-new-column-button",
418
441
  referencedCell: "data-table-ref-cell-button",
419
- rowMenu: "data-table-row-menu-button"
442
+ rowMenu: "data-table-row-menu-button",
443
+ sort: "data-table-sort-button"
420
444
  };
421
- var createButton = ({ attr, data, disabled = false, icon, testId }) => {
445
+ var createButton = ({ attr, data, disabled = false, icon, testId, type = "primary" }) => {
422
446
  const dataAttrs = Object.entries(data).map(([k, v]) => `${k}="${v}"`).join(" ");
423
- 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>`;
447
+ const positionClass = type === "primary" ? "inline-end-2" : "inline-end-9";
448
+ 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>`;
424
449
  };
425
450
  var addColumnButton = {
426
451
  attr: BUTTON_IDENTIFIERS.newColumn,
@@ -494,19 +519,43 @@ var rowMenuButton = {
494
519
  rowIndex: Number(el.getAttribute("data-row-index"))
495
520
  })
496
521
  };
522
+ var sortButton = {
523
+ attr: BUTTON_IDENTIFIERS.sort,
524
+ icon: "ph--sort-ascending--regular",
525
+ render: ({ fieldId, direction }) => {
526
+ return createButton({
527
+ attr: BUTTON_IDENTIFIERS.sort,
528
+ icon: direction === "desc" ? "ph--sort-descending--regular" : "ph--sort-ascending--regular",
529
+ data: {
530
+ "data-field-id": fieldId,
531
+ "data-direction": direction ?? ""
532
+ },
533
+ testId: "table-sort-button",
534
+ // TODO(ZaymonFC): All buttons should be rendered into an absolutely positioned flex container.
535
+ // This is a bit hacky.
536
+ type: "secondary"
537
+ });
538
+ },
539
+ getData: (el) => ({
540
+ type: "sort",
541
+ fieldId: el.getAttribute("data-field-id"),
542
+ direction: el.getAttribute("data-direction")
543
+ })
544
+ };
497
545
  var tableButtons = {
498
546
  addColumn: addColumnButton,
499
547
  columnSettings: columnSettingsButton,
500
548
  referencedCell: referencedCellButton,
501
- rowMenu: rowMenuButton
549
+ rowMenu: rowMenuButton,
550
+ sort: sortButton
502
551
  };
503
552
  var CONTROL_IDENTIFIERS = {
504
553
  checkbox: "data-table-checkbox",
505
554
  switch: "data-table-switch"
506
555
  };
507
556
  var BASE_CLASSES = {
508
- checkbox: "absolute inset-block-[.375rem] inline-end-[.375rem] ch-checkbox",
509
- switch: "absolute inset-block-[.25rem] inline-end-[.25rem] ch-checkbox--switch"
557
+ checkbox: "absolute inset-block-[.375rem] inline-end-[.375rem] dx-checkbox",
558
+ switch: "absolute inset-block-[.25rem] inline-end-[.25rem] dx-checkbox--switch"
510
559
  };
511
560
  var renderAttributes = (data) => {
512
561
  return Object.entries(data).map(([k, v]) => `${k}="${v}"`).join(" ");
@@ -630,7 +679,166 @@ var SelectionModel = class extends import_context2.Resource {
630
679
  return this._allSelected;
631
680
  }
632
681
  };
633
- var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/model/table-model.ts";
682
+ var TableSorting = class {
683
+ constructor(rows, _view, _projection) {
684
+ this._view = _view;
685
+ this._projection = _projection;
686
+ this._displayToDataIndex = /* @__PURE__ */ new Map();
687
+ this._localSort = (0, import_signals_core3.signal)(void 0);
688
+ this._rows = rows;
689
+ this._isDirty = (0, import_signals_core3.computed)(() => {
690
+ const local = this._localSort.value;
691
+ const viewSort = this._view?.query.sort?.[0];
692
+ if (local?.type === "cleared") {
693
+ return viewSort !== void 0;
694
+ }
695
+ if (local?.type === "active") {
696
+ if (!viewSort) {
697
+ return true;
698
+ }
699
+ return local.sort.fieldId !== viewSort.fieldId || local.sort.direction !== viewSort.direction;
700
+ }
701
+ return false;
702
+ });
703
+ this.sortedRows = this.initialiseSortedRows();
704
+ }
705
+ /**
706
+ * @reactive
707
+ * @returns Local sort if present, falls back to view sort.
708
+ */
709
+ get sorting() {
710
+ const local = this._localSort.value;
711
+ if (local?.type === "cleared") {
712
+ return void 0;
713
+ }
714
+ if (local?.type === "active") {
715
+ return local.sort;
716
+ }
717
+ return this._view?.query.sort?.[0];
718
+ }
719
+ /**
720
+ * @reactive
721
+ * @returns Whether local sort differs from view sort.
722
+ */
723
+ get isDirty() {
724
+ return this._isDirty.value;
725
+ }
726
+ getDataIndex(displayIndex) {
727
+ return this._displayToDataIndex.get(displayIndex) ?? displayIndex;
728
+ }
729
+ setSort(fieldId, direction) {
730
+ this._localSort.value = {
731
+ type: "active",
732
+ sort: {
733
+ fieldId,
734
+ direction
735
+ }
736
+ };
737
+ }
738
+ toggleSort(fieldId) {
739
+ if (!this._view || !this.sorting || this.sorting.fieldId !== fieldId) {
740
+ return;
741
+ }
742
+ switch (this.sorting.direction) {
743
+ case "asc": {
744
+ this.setSort(fieldId, "desc");
745
+ break;
746
+ }
747
+ case "desc": {
748
+ this.setSort(fieldId, "asc");
749
+ break;
750
+ }
751
+ }
752
+ }
753
+ clearSort() {
754
+ this._localSort.value = {
755
+ type: "cleared"
756
+ };
757
+ }
758
+ save() {
759
+ if (this._view && this._localSort.value !== void 0) {
760
+ if (this._localSort.value.type === "active") {
761
+ this._view.query.sort = [
762
+ this._localSort.value.sort
763
+ ];
764
+ } else {
765
+ this._view.query.sort = [];
766
+ }
767
+ this._localSort.value = void 0;
768
+ }
769
+ }
770
+ //
771
+ // Initialisation.
772
+ //
773
+ initialiseSortedRows() {
774
+ return (0, import_signals_core3.computed)(() => {
775
+ this._displayToDataIndex.clear();
776
+ const sort = this.sorting;
777
+ if (!sort || !this._view) {
778
+ return this._rows.value;
779
+ }
780
+ const field = this._view.fields.find((f) => f.id === sort.fieldId);
781
+ if (!field) {
782
+ return this._rows.value;
783
+ }
784
+ const { props } = this._projection.getFieldProjection(field.id);
785
+ const dataWithIndices = this._rows.value.map((item, index) => {
786
+ const sortValue = this.getSortValue(props, field, item);
787
+ const isEmpty = !(props.type === import_echo_schema5.TypeEnum.Boolean) && (sortValue == null || sortValue === "");
788
+ return {
789
+ item,
790
+ index,
791
+ value: sortValue,
792
+ isEmpty
793
+ };
794
+ });
795
+ const ordered = (0, import_lodash.default)(dataWithIndices, [
796
+ "isEmpty",
797
+ "value"
798
+ ], [
799
+ "asc",
800
+ sort.direction
801
+ ]);
802
+ ordered.forEach(({ index: dataIndex }, displayIndex) => {
803
+ if (displayIndex !== dataIndex) {
804
+ this._displayToDataIndex.set(displayIndex, dataIndex);
805
+ }
806
+ });
807
+ return ordered.map(({ item }) => item);
808
+ });
809
+ }
810
+ getSortValue(props, field, item) {
811
+ const { type, format } = props;
812
+ const value = (0, import_echo_schema5.getValue)(item, field.path);
813
+ if (type === import_echo_schema5.TypeEnum.Boolean) {
814
+ return !!value;
815
+ }
816
+ if (type === import_echo_schema5.TypeEnum.Number) {
817
+ return value;
818
+ }
819
+ if (value == null) {
820
+ return value;
821
+ }
822
+ if (format === import_echo_schema5.FormatEnum.SingleSelect) {
823
+ const options = props.options;
824
+ if (!options) {
825
+ return void 0;
826
+ }
827
+ const option = options.find((option2) => option2.id === value);
828
+ return option ? options.indexOf(option) : void 0;
829
+ }
830
+ if (format === import_echo_schema5.FormatEnum.Ref && field.referencePath) {
831
+ const refValue = (0, import_echo_schema5.getValue)(value.target, field.referencePath);
832
+ return refValue;
833
+ }
834
+ return (0, import_react_ui_form5.formatForDisplay)({
835
+ type,
836
+ format,
837
+ value
838
+ });
839
+ }
840
+ };
841
+ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/model/table-model.ts";
634
842
  var TableModel = class extends import_context.Resource {
635
843
  constructor({ table, projection, sorting = [], pinnedRows = {
636
844
  top: [],
@@ -648,8 +856,6 @@ var TableModel = class extends import_context.Resource {
648
856
  col: 0
649
857
  }
650
858
  });
651
- this._displayToDataIndex = /* @__PURE__ */ new Map();
652
- this._sorting = (0, import_signals_core.signal)(void 0);
653
859
  this._rows = (0, import_signals_core.signal)([]);
654
860
  this.setRows = (obj) => {
655
861
  this._rows.value = obj;
@@ -657,11 +863,11 @@ var TableModel = class extends import_context.Resource {
657
863
  this.getRowCount = () => this._rows.value.length;
658
864
  this.getColumnCount = () => this.table.view?.target?.fields.length ?? 0;
659
865
  this.insertRow = (rowIndex) => {
660
- const row = rowIndex !== void 0 ? this._displayToDataIndex.get(rowIndex) ?? rowIndex : this._rows.value.length;
866
+ const row = rowIndex !== void 0 ? this._sorting.getDataIndex(rowIndex) : this._rows.value.length;
661
867
  this._onInsertRow?.(row);
662
868
  };
663
869
  this.deleteRow = (rowIndex) => {
664
- const row = this._displayToDataIndex.get(rowIndex) ?? rowIndex;
870
+ const row = this._sorting.getDataIndex(rowIndex);
665
871
  const obj = this._rows.value[row];
666
872
  const objectsToDelete = [];
667
873
  if (this._selection.hasSelection.value) {
@@ -678,7 +884,7 @@ var TableModel = class extends import_context.Resource {
678
884
  return void 0;
679
885
  }
680
886
  const field = fields[col];
681
- const dataIndex = this._displayToDataIndex.get(row) ?? row;
887
+ const dataIndex = this._sorting.getDataIndex(row);
682
888
  const value = (0, import_echo_schema3.getValue)(this._rows.value[dataIndex], field.path);
683
889
  if (value == null) {
684
890
  return "";
@@ -701,7 +907,7 @@ var TableModel = class extends import_context.Resource {
701
907
  }
702
908
  };
703
909
  this.setCellData = ({ col, row }, value) => {
704
- const rowIdx = this._displayToDataIndex.get(row) ?? row;
910
+ const rowIdx = this._sorting.getDataIndex(row);
705
911
  const fields = this.table.view?.target?.fields ?? [];
706
912
  if (col < 0 || col >= fields.length) {
707
913
  return;
@@ -727,7 +933,11 @@ var TableModel = class extends import_context.Resource {
727
933
  };
728
934
  this._table = table;
729
935
  this._projection = projection;
730
- this._sorting.value = sorting.at(0);
936
+ this._sorting = new TableSorting(this._rows, table.view?.target, projection);
937
+ if (sorting.length > 0) {
938
+ const [sort] = sorting;
939
+ this._sorting.setSort(sort.fieldId, sort.direction);
940
+ }
731
941
  this._pinnedRows = pinnedRows;
732
942
  this._onInsertRow = onInsertRow;
733
943
  this._onDeleteRows = onDeleteRows;
@@ -742,14 +952,20 @@ var TableModel = class extends import_context.Resource {
742
952
  return this._projection;
743
953
  }
744
954
  get rows() {
745
- return this._sortedRows;
955
+ return this._sorting.sortedRows;
956
+ }
957
+ /**
958
+ * @reactive
959
+ */
960
+ get sorting() {
961
+ return this._sorting;
746
962
  }
747
963
  get pinnedRows() {
748
964
  return this._pinnedRows;
749
965
  }
750
966
  get columnMeta() {
751
967
  (0, import_invariant2.invariant)(this._columnMeta, void 0, {
752
- F: __dxlog_file2,
968
+ F: __dxlog_file,
753
969
  L: 117,
754
970
  S: this,
755
971
  A: [
@@ -759,20 +975,20 @@ var TableModel = class extends import_context.Resource {
759
975
  });
760
976
  return this._columnMeta;
761
977
  }
762
- get sorting() {
763
- return this._sorting.value;
764
- }
765
978
  get selection() {
766
979
  return this._selection;
767
980
  }
981
+ /** @reactive */
982
+ get isViewDirty() {
983
+ return this._sorting.isDirty;
984
+ }
768
985
  //
769
986
  // Initialisation
770
987
  //
771
988
  async _open() {
772
989
  this.initializeColumnMeta();
773
- this.initializeSorting();
774
990
  this.initializeEffects();
775
- this._selection = new SelectionModel(this._sortedRows, () => this._onRowOrderChanged?.());
991
+ this._selection = new SelectionModel(this._sorting.sortedRows, () => this._onRowOrderChanged?.());
776
992
  await this._selection.open(this._ctx);
777
993
  }
778
994
  initializeColumnMeta() {
@@ -802,60 +1018,9 @@ var TableModel = class extends import_context.Resource {
802
1018
  };
803
1019
  });
804
1020
  }
805
- initializeSorting() {
806
- this._sortedRows = (0, import_signals_core.computed)(() => {
807
- this._displayToDataIndex.clear();
808
- const sort = this._sorting.value;
809
- if (!sort) {
810
- return this._rows.value;
811
- }
812
- const field = this._table.view?.target?.fields.find((field2) => field2.id === sort.fieldId);
813
- if (!field) {
814
- return this._rows.value;
815
- }
816
- const { props } = this._projection.getFieldProjection(field.id);
817
- const dataWithIndices = this._rows.value.map((item, index) => {
818
- const rawValue = (0, import_echo_schema3.getValue)(item, field.path);
819
- let sortValue = rawValue;
820
- if (props.type.startsWith("boolean")) {
821
- sortValue = !!rawValue;
822
- } else if (rawValue != null) {
823
- if (props.format === import_echo_schema3.FormatEnum.Ref && field.referencePath) {
824
- sortValue = (0, import_echo_schema3.getValue)(rawValue, field.referencePath);
825
- } else {
826
- sortValue = (0, import_react_ui_form4.formatForDisplay)({
827
- type: props.type,
828
- format: props.format,
829
- value: rawValue
830
- });
831
- }
832
- }
833
- return {
834
- item,
835
- index,
836
- value: sortValue,
837
- isEmpty: !props.type.startsWith("boolean") && (sortValue == null || sortValue === "")
838
- };
839
- });
840
- const sorted = (0, import_lodash.default)(dataWithIndices, [
841
- "isEmpty",
842
- "value"
843
- ], [
844
- "asc",
845
- sort.direction
846
- ]);
847
- for (let displayIndex = 0; displayIndex < sorted.length; displayIndex++) {
848
- const { index: dataIndex } = sorted[displayIndex];
849
- if (displayIndex !== dataIndex) {
850
- this._displayToDataIndex.set(displayIndex, dataIndex);
851
- }
852
- }
853
- return sorted.map(({ item }) => item);
854
- });
855
- }
856
1021
  initializeEffects() {
857
1022
  const rowOrderWatcher = (0, import_signals_core.effect)(() => {
858
- touch(this._sortedRows.value);
1023
+ touch(this._sorting.sortedRows.value);
859
1024
  this._onRowOrderChanged?.();
860
1025
  });
861
1026
  this._ctx.onDispose(rowOrderWatcher);
@@ -864,7 +1029,7 @@ var TableModel = class extends import_context.Resource {
864
1029
  const rowEffects = [];
865
1030
  for (let row = start.row; row <= end.row; row++) {
866
1031
  rowEffects.push((0, import_signals_core.effect)(() => {
867
- const obj = this._sortedRows.value[row];
1032
+ const obj = this._sorting.sortedRows.value[row];
868
1033
  this?._table?.view?.target?.fields.forEach((field) => touch((0, import_echo_schema3.getValue)(obj, field.path)));
869
1034
  this._onCellUpdate?.({
870
1035
  row,
@@ -883,7 +1048,7 @@ var TableModel = class extends import_context.Resource {
883
1048
  * @param {(value: any) => any} update - A function that takes the current value and returns the updated value.
884
1049
  */
885
1050
  updateCellData({ col, row }, update) {
886
- const dataRow = this._displayToDataIndex.get(row) ?? row;
1051
+ const dataRow = this._sorting.getDataIndex(row);
887
1052
  const fields = this.table.view?.target?.fields ?? [];
888
1053
  const field = fields[col];
889
1054
  const value = (0, import_echo_schema3.getValue)(this._rows.value[dataRow], field.path);
@@ -899,9 +1064,6 @@ var TableModel = class extends import_context.Resource {
899
1064
  }
900
1065
  const field = this.table.view.target?.fields.find((field2) => field2.id === fieldId);
901
1066
  if (field && this._onDeleteColumn) {
902
- if (this._sorting.value?.fieldId === fieldId) {
903
- this.clearSort();
904
- }
905
1067
  this._onDeleteColumn(field.id);
906
1068
  }
907
1069
  }
@@ -919,18 +1081,6 @@ var TableModel = class extends import_context.Resource {
919
1081
  }
920
1082
  }
921
1083
  //
922
- // Sorting
923
- //
924
- setSort(fieldId, direction) {
925
- this._sorting.value = {
926
- fieldId,
927
- direction
928
- };
929
- }
930
- clearSort() {
931
- this._sorting.value = void 0;
932
- }
933
- //
934
1084
  // Pinning
935
1085
  //
936
1086
  // TODO(burdon): Change to setPinned(on/off).
@@ -941,11 +1091,17 @@ var TableModel = class extends import_context.Resource {
941
1091
  this._pinnedRows.top = this._pinnedRows.top.filter((index) => index !== rowIndex);
942
1092
  this._pinnedRows.bottom = this._pinnedRows.bottom.filter((index) => index !== rowIndex);
943
1093
  }
1094
+ //
1095
+ // View operations
1096
+ //
1097
+ saveView() {
1098
+ this._sorting.save();
1099
+ }
944
1100
  };
945
- var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/model/modal-controller.ts";
1101
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/model/modal-controller.ts";
946
1102
  var ModalController = class {
947
1103
  constructor() {
948
- this._state = (0, import_signals_core3.signal)({
1104
+ this._state = (0, import_signals_core4.signal)({
949
1105
  type: "closed"
950
1106
  });
951
1107
  this._triggerRef = {
@@ -1005,8 +1161,8 @@ var ModalController = class {
1005
1161
  onCreate
1006
1162
  };
1007
1163
  } else {
1008
- import_log2.log.warn("anchor cell not found while creating new ref", void 0, {
1009
- F: __dxlog_file3,
1164
+ import_log.log.warn("anchor cell not found while creating new ref", void 0, {
1165
+ F: __dxlog_file2,
1010
1166
  L: 86,
1011
1167
  S: this,
1012
1168
  C: (f, a) => f(...a)
@@ -1027,7 +1183,7 @@ var ModalController = class {
1027
1183
  }
1028
1184
  };
1029
1185
  var TablePresentation = class {
1030
- constructor(model, _visibleRange = (0, import_signals_core4.signal)({
1186
+ constructor(model, _visibleRange = (0, import_signals_core5.signal)({
1031
1187
  start: {
1032
1188
  row: 0,
1033
1189
  col: 0
@@ -1066,22 +1222,23 @@ var TablePresentation = class {
1066
1222
  const { props } = this.model.projection.getFieldProjection(field.id);
1067
1223
  const cell = {
1068
1224
  get value() {
1069
- const value = (0, import_echo_schema5.getValue)(obj, field.path);
1225
+ const value = (0, import_echo_schema6.getValue)(obj, field.path);
1070
1226
  if (value == null) {
1071
1227
  return "";
1072
1228
  }
1073
1229
  switch (props.format) {
1074
- case import_echo_schema5.FormatEnum.Boolean: {
1230
+ case import_echo_schema6.FormatEnum.Boolean:
1231
+ case import_echo_schema6.FormatEnum.SingleSelect: {
1075
1232
  return "";
1076
1233
  }
1077
- case import_echo_schema5.FormatEnum.Ref: {
1234
+ case import_echo_schema6.FormatEnum.Ref: {
1078
1235
  if (!field.referencePath) {
1079
1236
  return "";
1080
1237
  }
1081
- return (0, import_echo_schema5.getValue)(value.target, field.referencePath);
1238
+ return (0, import_echo_schema6.getValue)(value.target, field.referencePath);
1082
1239
  }
1083
1240
  default: {
1084
- return (0, import_react_ui_form5.formatForDisplay)({
1241
+ return (0, import_react_ui_form6.formatForDisplay)({
1085
1242
  type: props.type,
1086
1243
  format: props.format,
1087
1244
  value
@@ -1091,22 +1248,22 @@ var TablePresentation = class {
1091
1248
  }
1092
1249
  };
1093
1250
  const classes = [];
1094
- const formatClasses = (0, import_react_ui_form5.cellClassesForFieldType)({
1251
+ const formatClasses = (0, import_react_ui_form6.cellClassesForFieldType)({
1095
1252
  type: props.type,
1096
1253
  format: props.format
1097
1254
  });
1098
1255
  if (formatClasses) {
1099
1256
  classes.push(formatClasses);
1100
1257
  }
1101
- const rowSelectionClasses = (0, import_react_ui_form5.cellClassesForRowSelection)(this.model.selection.isObjectSelected(obj));
1258
+ const rowSelectionClasses = (0, import_react_ui_form6.cellClassesForRowSelection)(this.model.selection.isObjectSelected(obj));
1102
1259
  if (rowSelectionClasses) {
1103
1260
  classes.push(rowSelectionClasses);
1104
1261
  }
1105
1262
  if (classes.length > 0) {
1106
1263
  cell.className = (0, import_react_ui_theme2.mx)(classes.flat());
1107
1264
  }
1108
- if (props.format === import_echo_schema5.FormatEnum.Ref && props.referenceSchema) {
1109
- const targetObj = (0, import_echo_schema5.getValue)(obj, field.path)?.target;
1265
+ if (props.format === import_echo_schema6.FormatEnum.Ref && props.referenceSchema) {
1266
+ const targetObj = (0, import_echo_schema6.getValue)(obj, field.path)?.target;
1110
1267
  if (targetObj) {
1111
1268
  cell.accessoryHtml = tableButtons.referencedCell.render({
1112
1269
  targetId: targetObj.id,
@@ -1114,8 +1271,8 @@ var TablePresentation = class {
1114
1271
  });
1115
1272
  }
1116
1273
  }
1117
- if (props.format === import_echo_schema5.FormatEnum.Boolean) {
1118
- const value = (0, import_echo_schema5.getValue)(obj, field.path);
1274
+ if (props.format === import_echo_schema6.FormatEnum.Boolean) {
1275
+ const value = (0, import_echo_schema6.getValue)(obj, field.path);
1119
1276
  cell.accessoryHtml = tableControls.switch.render({
1120
1277
  colIndex,
1121
1278
  rowIndex: displayIndex,
@@ -1123,6 +1280,16 @@ var TablePresentation = class {
1123
1280
  });
1124
1281
  cell.readonly = true;
1125
1282
  }
1283
+ if (props.format === import_echo_schema6.FormatEnum.SingleSelect) {
1284
+ const value = (0, import_echo_schema6.getValue)(obj, field.path);
1285
+ const options = this.model.projection.getFieldProjection(field.id).props.options;
1286
+ if (options) {
1287
+ const option = options.find((o) => o.id === value);
1288
+ if (option) {
1289
+ cell.accessoryHtml = `<span class="dx-tag" data-hue="${option.color}">${option.title}</span>`;
1290
+ }
1291
+ }
1292
+ }
1126
1293
  const idx = (0, import_react_ui_grid3.toPlaneCellIndex)({
1127
1294
  col: colIndex,
1128
1295
  row: displayIndex
@@ -1145,6 +1312,8 @@ var TablePresentation = class {
1145
1312
  const fields = this.model.table.view?.target?.fields ?? [];
1146
1313
  for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
1147
1314
  const { field, props } = this.model.projection.getFieldProjection(fields[col].id);
1315
+ const sorting = this.model.sorting?.sorting;
1316
+ const direction = sorting?.fieldId === field.id ? sorting.direction : void 0;
1148
1317
  cells[(0, import_react_ui_grid3.toPlaneCellIndex)({
1149
1318
  col,
1150
1319
  row: 0
@@ -1153,9 +1322,16 @@ var TablePresentation = class {
1153
1322
  value: props.title ?? field.path,
1154
1323
  readonly: true,
1155
1324
  resizeHandle: "col",
1156
- accessoryHtml: tableButtons.columnSettings.render({
1325
+ accessoryHtml: `
1326
+ ${direction !== void 0 ? tableButtons.sort.render({
1327
+ fieldId: field.id,
1328
+ direction
1329
+ }) : ""}
1330
+ ${tableButtons.columnSettings.render({
1157
1331
  fieldId: field.id
1158
- })
1332
+ })}
1333
+ `,
1334
+ className: "!bg-gridHeader"
1159
1335
  };
1160
1336
  }
1161
1337
  return cells;
@@ -1164,7 +1340,7 @@ var TablePresentation = class {
1164
1340
  const cells = {};
1165
1341
  for (let row = range.start.row; row <= range.end.row && row < this.model.getRowCount(); row++) {
1166
1342
  const isSelected = this.model.selection.isRowIndexSelected(row);
1167
- const classes = (0, import_react_ui_form5.cellClassesForRowSelection)(isSelected);
1343
+ const classes = (0, import_react_ui_form6.cellClassesForRowSelection)(isSelected);
1168
1344
  cells[(0, import_react_ui_grid3.toPlaneCellIndex)({
1169
1345
  col: 0,
1170
1346
  row
@@ -1184,7 +1360,7 @@ var TablePresentation = class {
1184
1360
  const cells = {};
1185
1361
  for (let row = range.start.row; row <= range.end.row && row < this.model.getRowCount(); row++) {
1186
1362
  const isSelected = this.model.selection.isRowIndexSelected(row);
1187
- const classes = (0, import_react_ui_form5.cellClassesForRowSelection)(isSelected);
1363
+ const classes = (0, import_react_ui_form6.cellClassesForRowSelection)(isSelected);
1188
1364
  cells[(0, import_react_ui_grid3.toPlaneCellIndex)({
1189
1365
  col: 0,
1190
1366
  row
@@ -1205,13 +1381,14 @@ var TablePresentation = class {
1205
1381
  col: 0,
1206
1382
  row: 0
1207
1383
  })]: {
1208
- value: "",
1209
1384
  accessoryHtml: tableControls.checkbox.render({
1210
1385
  rowIndex: 0,
1211
1386
  header: true,
1212
1387
  checked: this.model.selection.allRowsSeleted.value
1213
1388
  }),
1214
- readonly: true
1389
+ className: "!bg-gridHeader",
1390
+ readonly: true,
1391
+ value: ""
1215
1392
  }
1216
1393
  };
1217
1394
  }
@@ -1221,11 +1398,12 @@ var TablePresentation = class {
1221
1398
  col: 0,
1222
1399
  row: 0
1223
1400
  })]: {
1224
- value: "",
1225
1401
  accessoryHtml: tableButtons.addColumn.render({
1226
1402
  disabled: (this.model.table.view?.target?.fields?.length ?? 0) >= import_schema2.VIEW_FIELD_LIMIT
1227
1403
  }),
1228
- readonly: true
1404
+ className: "!bg-gridHeader",
1405
+ readonly: true,
1406
+ value: ""
1229
1407
  }
1230
1408
  };
1231
1409
  }
@@ -1265,7 +1443,7 @@ var completion = ({ debug, onQuery, onMatch }) => {
1265
1443
  })
1266
1444
  ];
1267
1445
  };
1268
- var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx";
1446
+ var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx";
1269
1447
  var newValue = Symbol.for("newValue");
1270
1448
  var createOption = (text) => ({
1271
1449
  [newValue]: true,
@@ -1283,7 +1461,7 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }
1283
1461
  const field = model.projection.view.fields[col];
1284
1462
  const fieldProjection2 = model.projection.getFieldProjection(field.id);
1285
1463
  (0, import_invariant3.invariant)(fieldProjection2, void 0, {
1286
- F: __dxlog_file4,
1464
+ F: __dxlog_file3,
1287
1465
  L: 67,
1288
1466
  S: void 0,
1289
1467
  A: [
@@ -1357,7 +1535,7 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }
1357
1535
  ];
1358
1536
  if (onQuery) {
1359
1537
  switch (fieldProjection.props.format) {
1360
- case import_echo_schema6.FormatEnum.Ref: {
1538
+ case import_echo_schema7.FormatEnum.Ref: {
1361
1539
  extension2.push([
1362
1540
  completion({
1363
1541
  onQuery: (text) => onQuery(fieldProjection, text),
@@ -1431,7 +1609,7 @@ var determineNavigationDelta = ({ key, shift }) => {
1431
1609
  }
1432
1610
  return shift ? -1 : 1;
1433
1611
  };
1434
- var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/Table/Table.tsx";
1612
+ var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/Table/Table.tsx";
1435
1613
  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";
1436
1614
  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";
1437
1615
  var frozen = {
@@ -1499,6 +1677,10 @@ var TableMain = /* @__PURE__ */ (0, import_react.forwardRef)(({ model, presentat
1499
1677
  modals.showReferencePanel(data.targetId, data.schemaId);
1500
1678
  break;
1501
1679
  }
1680
+ case "sort": {
1681
+ model?.sorting?.toggleSort(data.fieldId);
1682
+ break;
1683
+ }
1502
1684
  }
1503
1685
  return;
1504
1686
  }
@@ -1599,8 +1781,8 @@ var TableMain = /* @__PURE__ */ (0, import_react.forwardRef)(({ model, presentat
1599
1781
  if (model && props.referenceSchema && field.referencePath) {
1600
1782
  const space = (0, import_echo.getSpace)(model.table);
1601
1783
  (0, import_invariant.invariant)(space, void 0, {
1602
- F: __dxlog_file5,
1603
- L: 260,
1784
+ F: __dxlog_file4,
1785
+ L: 264,
1604
1786
  S: void 0,
1605
1787
  A: [
1606
1788
  "space",
@@ -1683,73 +1865,76 @@ var Table = {
1683
1865
  Root: TableRoot,
1684
1866
  Main: TableMain
1685
1867
  };
1686
- var buttonStyles = "min-bs-0 p-2";
1687
- var tooltipProps = {
1688
- side: "top",
1689
- classNames: "z-10"
1690
- };
1691
- var ToolbarSeparator = () => /* @__PURE__ */ import_react9.default.createElement("div", {
1692
- role: "separator",
1693
- className: "grow"
1694
- });
1695
- var ToolbarButton = ({ icon, children, ...props }) => {
1696
- return /* @__PURE__ */ import_react9.default.createElement(import_react_ui8.Tooltip.Root, null, /* @__PURE__ */ import_react9.default.createElement(import_react_ui8.Tooltip.Trigger, {
1697
- asChild: true
1698
- }, /* @__PURE__ */ import_react9.default.createElement(import_react_ui8.Toolbar.Button, {
1699
- variant: "ghost",
1700
- ...props,
1701
- classNames: buttonStyles
1702
- }, /* @__PURE__ */ import_react9.default.createElement(import_react_ui8.Icon, {
1703
- icon,
1704
- size: 5
1705
- }), /* @__PURE__ */ import_react9.default.createElement("span", {
1706
- className: "sr-only"
1707
- }, 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))));
1708
- };
1709
- var [ToolbarContextProvider, useToolbarContext] = (0, import_react_context.createContext)("Toolbar");
1710
- var ToolbarRoot = ({ classNames, children, onAction }) => {
1711
- return /* @__PURE__ */ import_react8.default.createElement(ToolbarContextProvider, {
1712
- onAction
1713
- }, /* @__PURE__ */ import_react8.default.createElement(import_react_ui7.Toolbar.Root, {
1714
- classNames: [
1715
- "is-full shrink-0 overflow-x-auto overflow-y-hidden p-1 attention-surface",
1716
- classNames
1717
- ]
1718
- }, children));
1719
- };
1720
- var Editing = () => {
1721
- const { onAction } = useToolbarContext("Editing");
1722
- const { t } = (0, import_react_ui7.useTranslation)(translationKey);
1723
- return /* @__PURE__ */ import_react8.default.createElement(import_react8.default.Fragment, null, /* @__PURE__ */ import_react8.default.createElement(ToolbarButton, {
1724
- value: "add-row",
1868
+ var createTableToolbarActions = (state) => {
1869
+ const add = (0, import_react_ui_menu.createMenuAction)("add-row", {
1870
+ type: "add-row",
1725
1871
  icon: "ph--plus--regular",
1726
- "data-testid": "table.toolbar.add-row",
1727
- onClick: () => onAction?.({
1728
- type: "add-row"
1729
- })
1730
- }, t("add row")));
1731
- };
1732
- var Actions = () => {
1733
- const { onAction } = useToolbarContext("Actions");
1734
- const { t } = (0, import_react_ui7.useTranslation)(translationKey);
1735
- return /* @__PURE__ */ import_react8.default.createElement(import_react8.default.Fragment, null, /* @__PURE__ */ import_react8.default.createElement(ToolbarButton, {
1736
- value: "comment",
1872
+ label: [
1873
+ "add row",
1874
+ {
1875
+ ns: translationKey
1876
+ }
1877
+ ],
1878
+ testId: "table.toolbar.add-row"
1879
+ });
1880
+ const save = (0, import_react_ui_menu.createMenuAction)("save-view", {
1881
+ type: "save-view",
1882
+ icon: "ph--floppy-disk--regular",
1883
+ label: [
1884
+ "save view label",
1885
+ {
1886
+ ns: translationKey
1887
+ }
1888
+ ],
1889
+ testId: "table.toolbar.save-view",
1890
+ iconOnly: false,
1891
+ hidden: !state.viewDirty
1892
+ });
1893
+ const gap = (0, import_react_ui_menu.createGapSeparator)();
1894
+ const comment = (0, import_react_ui_menu.createMenuAction)("comment", {
1895
+ type: "comment",
1737
1896
  icon: "ph--chat-text--regular",
1738
- "data-testid": "table.toolbar.comment",
1739
- onClick: () => onAction?.({
1740
- type: "comment"
1741
- })
1742
- }, t("create comment")));
1897
+ label: [
1898
+ "create comment",
1899
+ {
1900
+ ns: translationKey
1901
+ }
1902
+ ],
1903
+ testId: "table.toolbar.comment"
1904
+ });
1905
+ const nodes = [
1906
+ add,
1907
+ save,
1908
+ ...gap.nodes,
1909
+ comment
1910
+ ];
1911
+ return {
1912
+ nodes,
1913
+ edges: nodes.map(({ id: target }) => ({
1914
+ source: "root",
1915
+ target
1916
+ }))
1917
+ };
1743
1918
  };
1744
- var Toolbar = {
1745
- Root: ToolbarRoot,
1746
- Editing,
1747
- Actions,
1748
- Separator: ToolbarSeparator
1919
+ var TableToolbar = ({ classNames, viewDirty, attendableId, onAction }) => {
1920
+ const state = (0, import_react8.useMemo)(() => (0, import_live_object2.create)({
1921
+ viewDirty
1922
+ }), []);
1923
+ const actionsCreator = (0, import_react8.useCallback)(() => createTableToolbarActions(state), [
1924
+ state
1925
+ ]);
1926
+ const menu = (0, import_react_ui_menu.useMenuActions)(actionsCreator);
1927
+ return /* @__PURE__ */ import_react8.default.createElement(import_react_ui_menu.MenuProvider, {
1928
+ ...menu,
1929
+ attendableId,
1930
+ onAction
1931
+ }, /* @__PURE__ */ import_react8.default.createElement(import_react_ui_menu.ToolbarMenu, {
1932
+ classNames
1933
+ }));
1749
1934
  };
1750
1935
  var useTableModel = ({ objects, table, projection, ...props }) => {
1751
- const [model, setModel] = (0, import_react10.useState)();
1752
- (0, import_react10.useEffect)(() => {
1936
+ const [model, setModel] = (0, import_react9.useState)();
1937
+ (0, import_react9.useEffect)(() => {
1753
1938
  if (!table || !projection) {
1754
1939
  return;
1755
1940
  }
@@ -1771,7 +1956,7 @@ var useTableModel = ({ objects, table, projection, ...props }) => {
1771
1956
  table,
1772
1957
  projection
1773
1958
  ]);
1774
- (0, import_react10.useEffect)(() => {
1959
+ (0, import_react9.useEffect)(() => {
1775
1960
  if (objects) {
1776
1961
  model?.setRows(objects);
1777
1962
  }
@@ -1779,6 +1964,26 @@ var useTableModel = ({ objects, table, projection, ...props }) => {
1779
1964
  model,
1780
1965
  objects
1781
1966
  ]);
1967
+ const { select, clear } = (0, import_react_ui_attention2.useSelectionActions)([
1968
+ table?.id,
1969
+ table?.view?.target?.query.type
1970
+ ].filter(import_util2.isNonNullable));
1971
+ (0, import_react9.useEffect)(() => {
1972
+ if (!model) {
1973
+ return;
1974
+ }
1975
+ const unsubscribe = (0, import_signals_core6.effect)(() => {
1976
+ select([
1977
+ ...model.selection.selection.value
1978
+ ]);
1979
+ });
1980
+ return () => {
1981
+ clear();
1982
+ unsubscribe();
1983
+ };
1984
+ }, [
1985
+ model
1986
+ ]);
1782
1987
  return model;
1783
1988
  };
1784
1989
  // Annotate the CommonJS export names for ESM import in node:
@@ -1790,8 +1995,8 @@ var useTableModel = ({ objects, table, projection, ...props }) => {
1790
1995
  TableModel,
1791
1996
  TablePresentation,
1792
1997
  TableSchema,
1998
+ TableToolbar,
1793
1999
  TableType,
1794
- Toolbar,
1795
2000
  initializeTable,
1796
2001
  renderCheckbox,
1797
2002
  renderSwitch,
@@ -1799,7 +2004,6 @@ var useTableModel = ({ objects, table, projection, ...props }) => {
1799
2004
  tableControls,
1800
2005
  touch,
1801
2006
  translations,
1802
- useTableModel,
1803
- useToolbarContext
2007
+ useTableModel
1804
2008
  });
1805
2009
  //# sourceMappingURL=index.cjs.map