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

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 (116) 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 +476 -282
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/types/index.mjs +1 -1
  7. package/dist/lib/node/{chunk-YSBXNBDJ.cjs → chunk-NB3SFHGA.cjs} +8 -6
  8. package/dist/lib/node/chunk-NB3SFHGA.cjs.map +7 -0
  9. package/dist/lib/node/index.cjs +468 -268
  10. package/dist/lib/node/index.cjs.map +4 -4
  11. package/dist/lib/node/meta.json +1 -1
  12. package/dist/lib/node/types/index.cjs +3 -3
  13. package/dist/lib/node/types/index.cjs.map +1 -1
  14. package/dist/lib/node-esm/{chunk-6OH2NHUX.mjs → chunk-RLVVOZW5.mjs} +6 -4
  15. package/dist/lib/node-esm/chunk-RLVVOZW5.mjs.map +7 -0
  16. package/dist/lib/node-esm/index.mjs +476 -282
  17. package/dist/lib/node-esm/index.mjs.map +4 -4
  18. package/dist/lib/node-esm/meta.json +1 -1
  19. package/dist/lib/node-esm/types/index.mjs +1 -1
  20. package/dist/types/src/_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/Table.stories.tsx +55 -44
  87. package/src/components/Table/Table.tsx +4 -0
  88. package/src/components/TableCellEditor/TableCellEditor.stories.tsx +1 -1
  89. package/src/components/TableToolbar/TableToolbar.tsx +72 -0
  90. package/src/components/{Toolbar → TableToolbar}/index.ts +1 -1
  91. package/src/components/index.ts +1 -1
  92. package/src/hooks/useTableModel.ts +21 -0
  93. package/src/model/table-model.test.ts +0 -5
  94. package/src/model/table-model.ts +41 -99
  95. package/src/model/table-presentation.ts +25 -4
  96. package/src/model/table-sorting.ts +215 -0
  97. package/src/playwright/smoke.spec.ts +21 -14
  98. package/src/translations.ts +2 -1
  99. package/src/types/table.ts +3 -3
  100. package/src/util/table-buttons.ts +33 -3
  101. package/src/util/table-controls.ts +2 -2
  102. package/src/util/table.ts +85 -52
  103. package/dist/lib/browser/chunk-AT7O4RAD.mjs.map +0 -7
  104. package/dist/lib/node/chunk-YSBXNBDJ.cjs.map +0 -7
  105. package/dist/lib/node-esm/chunk-6OH2NHUX.mjs.map +0 -7
  106. package/dist/types/src/components/Toolbar/Toolbar.d.ts +0 -21
  107. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +0 -1
  108. package/dist/types/src/components/Toolbar/common.d.ts +0 -14
  109. package/dist/types/src/components/Toolbar/common.d.ts.map +0 -1
  110. package/dist/types/src/components/Toolbar/index.d.ts +0 -2
  111. package/dist/types/src/components/Toolbar/index.d.ts.map +0 -1
  112. package/dist/types/src/playwright/playwright.config.d.ts +0 -3
  113. package/dist/types/src/playwright/playwright.config.d.ts.map +0 -1
  114. package/src/components/Toolbar/Toolbar.tsx +0 -87
  115. package/src/components/Toolbar/common.tsx +0 -71
  116. /package/src/playwright/{playwright.config.ts → playwright.config.cts} +0 -0
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  TableSchema,
3
3
  TableType
4
- } from "./chunk-AT7O4RAD.mjs";
4
+ } from "./chunk-3FR6NHPD.mjs";
5
5
 
6
6
  // packages/ui/react-ui-table/src/translations.ts
7
7
  var translationKey = "table";
@@ -17,7 +17,7 @@ var translations_default = [
17
17
  "new schema": "New schema",
18
18
  "continue label": "Continue",
19
19
  "create stack section label": "Create table",
20
- "add row": "Add row",
20
+ "add row label": "Add row",
21
21
  "create comment": "Create thread",
22
22
  "column action sort descending": "Sort Descending",
23
23
  "column action sort ascending": "Sort Ascending",
@@ -28,7 +28,8 @@ var translations_default = [
28
28
  "bulk delete row label": "Delete selected rows",
29
29
  "column deleted label": "Column deleted",
30
30
  "new column button label": "Create column",
31
- "create new object label": "Create new object \u201C{{text}}\u201D"
31
+ "create new object label": "Create new object \u201C{{text}}\u201D",
32
+ "save view label": "Save changes to view"
32
33
  }
33
34
  }
34
35
  }
@@ -36,7 +37,7 @@ var translations_default = [
36
37
 
37
38
  // packages/ui/react-ui-table/src/components/Table/Table.tsx
38
39
  import React7, { forwardRef, useCallback as useCallback4, useImperativeHandle, useState as useState2, useMemo as useMemo4 } from "react";
39
- import { getValue as getValue3 } from "@dxos/echo-schema";
40
+ import { getValue as getValue4 } from "@dxos/echo-schema";
40
41
  import { invariant as invariant3 } from "@dxos/invariant";
41
42
  import { Filter, getSpace as getSpace4, fullyQualifiedId } from "@dxos/react-client/echo";
42
43
  import { useTranslation as useTranslation3 } from "@dxos/react-ui";
@@ -54,7 +55,7 @@ var ColumnActionsMenu = ({ model, modals }) => {
54
55
  if (state?.type !== "column") {
55
56
  return null;
56
57
  }
57
- const currentSort = model.sorting;
58
+ const currentSort = model.sorting?.sorting;
58
59
  const isCurrentColumnSorted = currentSort?.fieldId === state.fieldId;
59
60
  return /* @__PURE__ */ React.createElement(DropdownMenu.Root, {
60
61
  modal: false,
@@ -64,13 +65,13 @@ var ColumnActionsMenu = ({ model, modals }) => {
64
65
  virtualRef: modals.trigger
65
66
  }), /* @__PURE__ */ React.createElement(DropdownMenu.Portal, null, /* @__PURE__ */ React.createElement(DropdownMenu.Content, null, /* @__PURE__ */ React.createElement(DropdownMenu.Viewport, null, (!isCurrentColumnSorted || currentSort?.direction === "asc") && /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
66
67
  "data-testid": "column-sort-descending",
67
- onClick: () => model.setSort(state.fieldId, "desc")
68
+ onClick: () => model.sorting?.setSort(state.fieldId, "desc")
68
69
  }, t("column action sort descending")), (!isCurrentColumnSorted || currentSort?.direction === "desc") && /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
69
70
  "data-testid": "column-sort-ascending",
70
- onClick: () => model.setSort(state.fieldId, "asc")
71
+ onClick: () => model.sorting?.setSort(state.fieldId, "asc")
71
72
  }, t("column action sort ascending")), isCurrentColumnSorted && /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
72
73
  "data-testid": "column-clear-sort",
73
- onClick: () => model.clearSort()
74
+ onClick: () => model.sorting?.clearSort()
74
75
  }, t("column action clear sorting")), model.getColumnCount() > 1 && /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
75
76
  "data-testid": "column-delete",
76
77
  onClick: () => model.deleteColumn(state.fieldId)
@@ -285,14 +286,13 @@ var RowActionsMenu = ({ model, modals }) => {
285
286
  };
286
287
 
287
288
  // packages/ui/react-ui-table/src/model/table-model.ts
288
- import { computed as computed2, effect as effect2, signal as signal2 } from "@preact/signals-core";
289
- import orderBy from "lodash.orderby";
289
+ import { computed as computed3, effect as effect2, signal as signal3 } from "@preact/signals-core";
290
290
  import { Resource as Resource2 } from "@dxos/context";
291
- import { getValue, setValue, FormatEnum as FormatEnum2 } from "@dxos/echo-schema";
291
+ import { FormatEnum as FormatEnum3, getValue as getValue2, setValue } from "@dxos/echo-schema";
292
292
  import { invariant } from "@dxos/invariant";
293
293
  import { isReactiveObject, makeRef as makeRef2 } from "@dxos/live-object";
294
294
  import { PublicKey as PublicKey2 } from "@dxos/react-client";
295
- import { formatForDisplay, formatForEditing, parseValue } from "@dxos/react-ui-form";
295
+ import { formatForEditing, parseValue } from "@dxos/react-ui-form";
296
296
 
297
297
  // packages/ui/react-ui-table/src/model/selection-model.ts
298
298
  import { computed, effect, signal } from "@preact/signals-core";
@@ -303,73 +303,88 @@ var touch = (value) => value;
303
303
 
304
304
  // packages/ui/react-ui-table/src/util/table.ts
305
305
  import { AST, Format, FormatEnum, S as S2, TypedObject, TypeEnum } from "@dxos/echo-schema";
306
- import { log } from "@dxos/log";
307
306
  import { PublicKey } from "@dxos/react-client";
308
307
  import { create as create2, makeRef } from "@dxos/react-client/echo";
309
- import { createFieldId, createView, ViewProjection } from "@dxos/schema";
310
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/util/table.ts";
311
- var initializeTable = async ({ space, table, initialRow = true }) => {
312
- log("initializeTable", {
313
- table
314
- }, {
315
- F: __dxlog_file,
316
- L: 36,
317
- S: void 0,
318
- C: (f, a) => f(...a)
319
- });
320
- const ContactSchema = TypedObject({
321
- typename: `example.com/type/${PublicKey.random().truncate()}`,
322
- version: "0.1.0"
323
- })({
324
- name: S2.optional(S2.String).annotations({
325
- [AST.TitleAnnotationId]: "Name"
326
- }),
327
- active: S2.optional(S2.Boolean),
328
- email: S2.optional(Format.Email),
329
- salary: S2.optional(Format.Currency()).annotations({
330
- [AST.TitleAnnotationId]: "Salary"
331
- })
332
- });
333
- const [contactSchema] = await space.db.schemaRegistry.register([
334
- ContactSchema
335
- ]);
336
- table.view = makeRef(createView({
337
- name: "Test",
338
- typename: contactSchema.typename,
339
- jsonSchema: contactSchema.jsonSchema,
340
- fields: [
341
- "name",
342
- "active",
343
- "email",
344
- "salary"
345
- ]
346
- }));
347
- const projection = new ViewProjection(contactSchema, table.view.target);
348
- projection.setFieldProjection({
349
- field: {
350
- id: table.view.target.fields.find((f) => f.path === "salary").id,
351
- path: "salary",
352
- size: 150
308
+ import { createFieldId, createView, getSchemaProperties, ViewProjection } from "@dxos/schema";
309
+ var initializeTable = async ({ space, table, initialRow = true, initialSchema }) => {
310
+ if (initialSchema) {
311
+ const schema = await space.db.schemaRegistry.query({
312
+ typename: initialSchema
313
+ }).firstOrUndefined();
314
+ if (!schema) {
315
+ throw new Error(`Schema not found: ${initialSchema}`);
353
316
  }
354
- });
355
- projection.setFieldProjection({
356
- field: {
357
- id: createFieldId(),
358
- path: "manager",
359
- referencePath: "name"
360
- },
361
- props: {
362
- property: "manager",
363
- type: TypeEnum.Ref,
364
- format: FormatEnum.Ref,
365
- referenceSchema: contactSchema.typename,
366
- title: "Manager"
317
+ const fields = getSchemaProperties(schema.ast).filter((prop) => prop.format !== FormatEnum.Ref).map((prop) => prop.name);
318
+ table.view = makeRef(createView({
319
+ // TODO(ZaymonFC): Don't hardcode name?
320
+ name: "View",
321
+ typename: schema.typename,
322
+ jsonSchema: schema.jsonSchema,
323
+ fields
324
+ }));
325
+ return schema;
326
+ } else {
327
+ const ContactSchema = TypedObject({
328
+ typename: `example.com/type/${PublicKey.random().truncate()}`,
329
+ version: "0.1.0"
330
+ })({
331
+ name: S2.optional(S2.String).annotations({
332
+ [AST.TitleAnnotationId]: "Name"
333
+ }),
334
+ active: S2.optional(S2.Boolean),
335
+ email: S2.optional(Format.Email),
336
+ salary: S2.optional(Format.Currency()).annotations({
337
+ [AST.TitleAnnotationId]: "Salary"
338
+ })
339
+ });
340
+ const [contactSchema] = await space.db.schemaRegistry.register([
341
+ ContactSchema
342
+ ]);
343
+ table.view = makeRef(createView({
344
+ name: "View",
345
+ typename: contactSchema.typename,
346
+ jsonSchema: contactSchema.jsonSchema,
347
+ fields: [
348
+ "name",
349
+ "email",
350
+ "salary",
351
+ "active"
352
+ ]
353
+ }));
354
+ const projection = new ViewProjection(contactSchema, table.view.target);
355
+ projection.setFieldProjection({
356
+ field: {
357
+ id: table.view.target.fields.find((f) => f.path === "salary").id,
358
+ path: "salary",
359
+ size: 150
360
+ }
361
+ });
362
+ projection.setFieldProjection({
363
+ field: {
364
+ id: table.view.target.fields.find((f) => f.path === "active").id,
365
+ path: "active",
366
+ size: 100
367
+ }
368
+ });
369
+ projection.setFieldProjection({
370
+ field: {
371
+ id: createFieldId(),
372
+ path: "manager",
373
+ referencePath: "name"
374
+ },
375
+ props: {
376
+ property: "manager",
377
+ type: TypeEnum.Ref,
378
+ format: FormatEnum.Ref,
379
+ referenceSchema: contactSchema.typename,
380
+ title: "Manager"
381
+ }
382
+ });
383
+ if (initialRow) {
384
+ space.db.add(create2(contactSchema, {}));
367
385
  }
368
- });
369
- if (initialRow) {
370
- space.db.add(create2(contactSchema, {}));
386
+ return contactSchema;
371
387
  }
372
- return contactSchema;
373
388
  };
374
389
 
375
390
  // packages/ui/react-ui-table/src/util/table-buttons.ts
@@ -377,11 +392,13 @@ var BUTTON_IDENTIFIERS = {
377
392
  columnSettings: "data-table-column-settings-button",
378
393
  newColumn: "data-table-new-column-button",
379
394
  referencedCell: "data-table-ref-cell-button",
380
- rowMenu: "data-table-row-menu-button"
395
+ rowMenu: "data-table-row-menu-button",
396
+ sort: "data-table-sort-button"
381
397
  };
382
- var createButton = ({ attr, data, disabled = false, icon, testId }) => {
398
+ var createButton = ({ attr, data, disabled = false, icon, testId, type = "primary" }) => {
383
399
  const dataAttrs = Object.entries(data).map(([k, v]) => `${k}="${v}"`).join(" ");
384
- 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>`;
400
+ const positionClass = type === "primary" ? "inline-end-2" : "inline-end-9";
401
+ 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>`;
385
402
  };
386
403
  var addColumnButton = {
387
404
  attr: BUTTON_IDENTIFIERS.newColumn,
@@ -455,11 +472,35 @@ var rowMenuButton = {
455
472
  rowIndex: Number(el.getAttribute("data-row-index"))
456
473
  })
457
474
  };
475
+ var sortButton = {
476
+ attr: BUTTON_IDENTIFIERS.sort,
477
+ icon: "ph--sort-ascending--regular",
478
+ render: ({ fieldId, direction }) => {
479
+ return createButton({
480
+ attr: BUTTON_IDENTIFIERS.sort,
481
+ icon: direction === "desc" ? "ph--sort-descending--regular" : "ph--sort-ascending--regular",
482
+ data: {
483
+ "data-field-id": fieldId,
484
+ "data-direction": direction ?? ""
485
+ },
486
+ testId: "table-sort-button",
487
+ // TODO(ZaymonFC): All buttons should be rendered into an absolutely positioned flex container.
488
+ // This is a bit hacky.
489
+ type: "secondary"
490
+ });
491
+ },
492
+ getData: (el) => ({
493
+ type: "sort",
494
+ fieldId: el.getAttribute("data-field-id"),
495
+ direction: el.getAttribute("data-direction")
496
+ })
497
+ };
458
498
  var tableButtons = {
459
499
  addColumn: addColumnButton,
460
500
  columnSettings: columnSettingsButton,
461
501
  referencedCell: referencedCellButton,
462
- rowMenu: rowMenuButton
502
+ rowMenu: rowMenuButton,
503
+ sort: sortButton
463
504
  };
464
505
 
465
506
  // packages/ui/react-ui-table/src/util/table-controls.ts
@@ -468,8 +509,8 @@ var CONTROL_IDENTIFIERS = {
468
509
  switch: "data-table-switch"
469
510
  };
470
511
  var BASE_CLASSES = {
471
- checkbox: "absolute inset-block-[.375rem] inline-end-[.375rem] ch-checkbox",
472
- switch: "absolute inset-block-[.25rem] inline-end-[.25rem] ch-checkbox--switch"
512
+ checkbox: "absolute inset-block-[.375rem] inline-end-[.375rem] dx-checkbox",
513
+ switch: "absolute inset-block-[.25rem] inline-end-[.25rem] dx-checkbox--switch"
473
514
  };
474
515
  var renderAttributes = (data) => {
475
516
  return Object.entries(data).map(([k, v]) => `${k}="${v}"`).join(" ");
@@ -596,8 +637,173 @@ var SelectionModel = class extends Resource {
596
637
  }
597
638
  };
598
639
 
640
+ // packages/ui/react-ui-table/src/model/table-sorting.ts
641
+ import { computed as computed2, signal as signal2 } from "@preact/signals-core";
642
+ import orderBy from "lodash.orderby";
643
+ import { getValue, FormatEnum as FormatEnum2, TypeEnum as TypeEnum2 } from "@dxos/echo-schema";
644
+ import { formatForDisplay } from "@dxos/react-ui-form";
645
+ var TableSorting = class {
646
+ constructor(rows, _view, _projection) {
647
+ this._view = _view;
648
+ this._projection = _projection;
649
+ this._displayToDataIndex = /* @__PURE__ */ new Map();
650
+ this._localSort = signal2(void 0);
651
+ this._rows = rows;
652
+ this._isDirty = computed2(() => {
653
+ const local = this._localSort.value;
654
+ const viewSort = this._view?.query.sort?.[0];
655
+ if (local?.type === "cleared") {
656
+ return viewSort !== void 0;
657
+ }
658
+ if (local?.type === "active") {
659
+ if (!viewSort) {
660
+ return true;
661
+ }
662
+ return local.sort.fieldId !== viewSort.fieldId || local.sort.direction !== viewSort.direction;
663
+ }
664
+ return false;
665
+ });
666
+ this.sortedRows = this.initialiseSortedRows();
667
+ }
668
+ /**
669
+ * @reactive
670
+ * @returns Local sort if present, falls back to view sort.
671
+ */
672
+ get sorting() {
673
+ const local = this._localSort.value;
674
+ if (local?.type === "cleared") {
675
+ return void 0;
676
+ }
677
+ if (local?.type === "active") {
678
+ return local.sort;
679
+ }
680
+ return this._view?.query.sort?.[0];
681
+ }
682
+ /**
683
+ * @reactive
684
+ * @returns Whether local sort differs from view sort.
685
+ */
686
+ get isDirty() {
687
+ return this._isDirty.value;
688
+ }
689
+ getDataIndex(displayIndex) {
690
+ return this._displayToDataIndex.get(displayIndex) ?? displayIndex;
691
+ }
692
+ setSort(fieldId, direction) {
693
+ this._localSort.value = {
694
+ type: "active",
695
+ sort: {
696
+ fieldId,
697
+ direction
698
+ }
699
+ };
700
+ }
701
+ toggleSort(fieldId) {
702
+ if (!this._view || !this.sorting || this.sorting.fieldId !== fieldId) {
703
+ return;
704
+ }
705
+ switch (this.sorting.direction) {
706
+ case "asc": {
707
+ this.setSort(fieldId, "desc");
708
+ break;
709
+ }
710
+ case "desc": {
711
+ this.setSort(fieldId, "asc");
712
+ break;
713
+ }
714
+ }
715
+ }
716
+ clearSort() {
717
+ this._localSort.value = {
718
+ type: "cleared"
719
+ };
720
+ }
721
+ save() {
722
+ if (this._view && this._localSort.value !== void 0) {
723
+ if (this._localSort.value.type === "active") {
724
+ this._view.query.sort = [
725
+ this._localSort.value.sort
726
+ ];
727
+ } else {
728
+ this._view.query.sort = [];
729
+ }
730
+ this._localSort.value = void 0;
731
+ }
732
+ }
733
+ //
734
+ // Initialisation.
735
+ //
736
+ initialiseSortedRows() {
737
+ return computed2(() => {
738
+ this._displayToDataIndex.clear();
739
+ const sort = this.sorting;
740
+ if (!sort || !this._view) {
741
+ return this._rows.value;
742
+ }
743
+ const field = this._view.fields.find((f) => f.id === sort.fieldId);
744
+ if (!field) {
745
+ return this._rows.value;
746
+ }
747
+ const { props } = this._projection.getFieldProjection(field.id);
748
+ const dataWithIndices = this._rows.value.map((item, index) => {
749
+ const sortValue = this.getSortValue(props, field, item);
750
+ const isEmpty = !(props.type === TypeEnum2.Boolean) && (sortValue == null || sortValue === "");
751
+ return {
752
+ item,
753
+ index,
754
+ value: sortValue,
755
+ isEmpty
756
+ };
757
+ });
758
+ const ordered = orderBy(dataWithIndices, [
759
+ "isEmpty",
760
+ "value"
761
+ ], [
762
+ "asc",
763
+ sort.direction
764
+ ]);
765
+ ordered.forEach(({ index: dataIndex }, displayIndex) => {
766
+ if (displayIndex !== dataIndex) {
767
+ this._displayToDataIndex.set(displayIndex, dataIndex);
768
+ }
769
+ });
770
+ return ordered.map(({ item }) => item);
771
+ });
772
+ }
773
+ getSortValue(props, field, item) {
774
+ const { type, format } = props;
775
+ const value = getValue(item, field.path);
776
+ if (type === TypeEnum2.Boolean) {
777
+ return !!value;
778
+ }
779
+ if (type === TypeEnum2.Number) {
780
+ return value;
781
+ }
782
+ if (value == null) {
783
+ return value;
784
+ }
785
+ if (format === FormatEnum2.SingleSelect) {
786
+ const options = props.options;
787
+ if (!options) {
788
+ return void 0;
789
+ }
790
+ const option = options.find((option2) => option2.id === value);
791
+ return option ? options.indexOf(option) : void 0;
792
+ }
793
+ if (format === FormatEnum2.Ref && field.referencePath) {
794
+ const refValue = getValue(value.target, field.referencePath);
795
+ return refValue;
796
+ }
797
+ return formatForDisplay({
798
+ type,
799
+ format,
800
+ value
801
+ });
802
+ }
803
+ };
804
+
599
805
  // packages/ui/react-ui-table/src/model/table-model.ts
600
- var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/model/table-model.ts";
806
+ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/model/table-model.ts";
601
807
  var TableModel = class extends Resource2 {
602
808
  constructor({ table, projection, sorting = [], pinnedRows = {
603
809
  top: [],
@@ -605,7 +811,7 @@ var TableModel = class extends Resource2 {
605
811
  }, onCellUpdate, onDeleteColumn, onDeleteRows, onInsertRow, onRowOrderChanged }) {
606
812
  super();
607
813
  this.id = `table-model-${PublicKey2.random().truncate()}`;
608
- this._visibleRange = signal2({
814
+ this._visibleRange = signal3({
609
815
  start: {
610
816
  row: 0,
611
817
  col: 0
@@ -615,14 +821,7 @@ var TableModel = class extends Resource2 {
615
821
  col: 0
616
822
  }
617
823
  });
618
- /**
619
- * Maps display indices to data indices.
620
- * Used for translating between sorted/displayed order and original data order.
621
- * Keys are display indices, values are corresponding data indices.
622
- */
623
- this._displayToDataIndex = /* @__PURE__ */ new Map();
624
- this._sorting = signal2(void 0);
625
- this._rows = signal2([]);
824
+ this._rows = signal3([]);
626
825
  //
627
826
  // Data
628
827
  //
@@ -632,11 +831,11 @@ var TableModel = class extends Resource2 {
632
831
  this.getRowCount = () => this._rows.value.length;
633
832
  this.getColumnCount = () => this.table.view?.target?.fields.length ?? 0;
634
833
  this.insertRow = (rowIndex) => {
635
- const row = rowIndex !== void 0 ? this._displayToDataIndex.get(rowIndex) ?? rowIndex : this._rows.value.length;
834
+ const row = rowIndex !== void 0 ? this._sorting.getDataIndex(rowIndex) : this._rows.value.length;
636
835
  this._onInsertRow?.(row);
637
836
  };
638
837
  this.deleteRow = (rowIndex) => {
639
- const row = this._displayToDataIndex.get(rowIndex) ?? rowIndex;
838
+ const row = this._sorting.getDataIndex(rowIndex);
640
839
  const obj = this._rows.value[row];
641
840
  const objectsToDelete = [];
642
841
  if (this._selection.hasSelection.value) {
@@ -653,18 +852,18 @@ var TableModel = class extends Resource2 {
653
852
  return void 0;
654
853
  }
655
854
  const field = fields[col];
656
- const dataIndex = this._displayToDataIndex.get(row) ?? row;
657
- const value = getValue(this._rows.value[dataIndex], field.path);
855
+ const dataIndex = this._sorting.getDataIndex(row);
856
+ const value = getValue2(this._rows.value[dataIndex], field.path);
658
857
  if (value == null) {
659
858
  return "";
660
859
  }
661
860
  const { props } = this._projection.getFieldProjection(field.id);
662
861
  switch (props.format) {
663
- case FormatEnum2.Ref: {
862
+ case FormatEnum3.Ref: {
664
863
  if (!field.referencePath) {
665
864
  return "";
666
865
  }
667
- return getValue(value.target, field.referencePath);
866
+ return getValue2(value.target, field.referencePath);
668
867
  }
669
868
  default: {
670
869
  return formatForEditing({
@@ -676,7 +875,7 @@ var TableModel = class extends Resource2 {
676
875
  }
677
876
  };
678
877
  this.setCellData = ({ col, row }, value) => {
679
- const rowIdx = this._displayToDataIndex.get(row) ?? row;
878
+ const rowIdx = this._sorting.getDataIndex(row);
680
879
  const fields = this.table.view?.target?.fields ?? [];
681
880
  if (col < 0 || col >= fields.length) {
682
881
  return;
@@ -684,7 +883,7 @@ var TableModel = class extends Resource2 {
684
883
  const field = fields[col];
685
884
  const { props } = this._projection.getFieldProjection(field.id);
686
885
  switch (props.format) {
687
- case FormatEnum2.Ref: {
886
+ case FormatEnum3.Ref: {
688
887
  if (isReactiveObject(value)) {
689
888
  setValue(this._rows.value[rowIdx], field.path, makeRef2(value));
690
889
  }
@@ -702,7 +901,11 @@ var TableModel = class extends Resource2 {
702
901
  };
703
902
  this._table = table;
704
903
  this._projection = projection;
705
- this._sorting.value = sorting.at(0);
904
+ this._sorting = new TableSorting(this._rows, table.view?.target, projection);
905
+ if (sorting.length > 0) {
906
+ const [sort] = sorting;
907
+ this._sorting.setSort(sort.fieldId, sort.direction);
908
+ }
706
909
  this._pinnedRows = pinnedRows;
707
910
  this._onInsertRow = onInsertRow;
708
911
  this._onDeleteRows = onDeleteRows;
@@ -717,14 +920,20 @@ var TableModel = class extends Resource2 {
717
920
  return this._projection;
718
921
  }
719
922
  get rows() {
720
- return this._sortedRows;
923
+ return this._sorting.sortedRows;
924
+ }
925
+ /**
926
+ * @reactive
927
+ */
928
+ get sorting() {
929
+ return this._sorting;
721
930
  }
722
931
  get pinnedRows() {
723
932
  return this._pinnedRows;
724
933
  }
725
934
  get columnMeta() {
726
935
  invariant(this._columnMeta, void 0, {
727
- F: __dxlog_file2,
936
+ F: __dxlog_file,
728
937
  L: 117,
729
938
  S: this,
730
939
  A: [
@@ -734,24 +943,24 @@ var TableModel = class extends Resource2 {
734
943
  });
735
944
  return this._columnMeta;
736
945
  }
737
- get sorting() {
738
- return this._sorting.value;
739
- }
740
946
  get selection() {
741
947
  return this._selection;
742
948
  }
949
+ /** @reactive */
950
+ get isViewDirty() {
951
+ return this._sorting.isDirty;
952
+ }
743
953
  //
744
954
  // Initialisation
745
955
  //
746
956
  async _open() {
747
957
  this.initializeColumnMeta();
748
- this.initializeSorting();
749
958
  this.initializeEffects();
750
- this._selection = new SelectionModel(this._sortedRows, () => this._onRowOrderChanged?.());
959
+ this._selection = new SelectionModel(this._sorting.sortedRows, () => this._onRowOrderChanged?.());
751
960
  await this._selection.open(this._ctx);
752
961
  }
753
962
  initializeColumnMeta() {
754
- this._columnMeta = computed2(() => {
963
+ this._columnMeta = computed3(() => {
755
964
  const fields = this._table.view?.target?.fields ?? [];
756
965
  const meta = Object.fromEntries(fields.map((field, index) => [
757
966
  index,
@@ -777,60 +986,9 @@ var TableModel = class extends Resource2 {
777
986
  };
778
987
  });
779
988
  }
780
- initializeSorting() {
781
- this._sortedRows = computed2(() => {
782
- this._displayToDataIndex.clear();
783
- const sort = this._sorting.value;
784
- if (!sort) {
785
- return this._rows.value;
786
- }
787
- const field = this._table.view?.target?.fields.find((field2) => field2.id === sort.fieldId);
788
- if (!field) {
789
- return this._rows.value;
790
- }
791
- const { props } = this._projection.getFieldProjection(field.id);
792
- const dataWithIndices = this._rows.value.map((item, index) => {
793
- const rawValue = getValue(item, field.path);
794
- let sortValue = rawValue;
795
- if (props.type.startsWith("boolean")) {
796
- sortValue = !!rawValue;
797
- } else if (rawValue != null) {
798
- if (props.format === FormatEnum2.Ref && field.referencePath) {
799
- sortValue = getValue(rawValue, field.referencePath);
800
- } else {
801
- sortValue = formatForDisplay({
802
- type: props.type,
803
- format: props.format,
804
- value: rawValue
805
- });
806
- }
807
- }
808
- return {
809
- item,
810
- index,
811
- value: sortValue,
812
- isEmpty: !props.type.startsWith("boolean") && (sortValue == null || sortValue === "")
813
- };
814
- });
815
- const sorted = orderBy(dataWithIndices, [
816
- "isEmpty",
817
- "value"
818
- ], [
819
- "asc",
820
- sort.direction
821
- ]);
822
- for (let displayIndex = 0; displayIndex < sorted.length; displayIndex++) {
823
- const { index: dataIndex } = sorted[displayIndex];
824
- if (displayIndex !== dataIndex) {
825
- this._displayToDataIndex.set(displayIndex, dataIndex);
826
- }
827
- }
828
- return sorted.map(({ item }) => item);
829
- });
830
- }
831
989
  initializeEffects() {
832
990
  const rowOrderWatcher = effect2(() => {
833
- touch(this._sortedRows.value);
991
+ touch(this._sorting.sortedRows.value);
834
992
  this._onRowOrderChanged?.();
835
993
  });
836
994
  this._ctx.onDispose(rowOrderWatcher);
@@ -839,8 +997,8 @@ var TableModel = class extends Resource2 {
839
997
  const rowEffects = [];
840
998
  for (let row = start.row; row <= end.row; row++) {
841
999
  rowEffects.push(effect2(() => {
842
- const obj = this._sortedRows.value[row];
843
- this?._table?.view?.target?.fields.forEach((field) => touch(getValue(obj, field.path)));
1000
+ const obj = this._sorting.sortedRows.value[row];
1001
+ this?._table?.view?.target?.fields.forEach((field) => touch(getValue2(obj, field.path)));
844
1002
  this._onCellUpdate?.({
845
1003
  row,
846
1004
  col: start.col,
@@ -858,10 +1016,10 @@ var TableModel = class extends Resource2 {
858
1016
  * @param {(value: any) => any} update - A function that takes the current value and returns the updated value.
859
1017
  */
860
1018
  updateCellData({ col, row }, update) {
861
- const dataRow = this._displayToDataIndex.get(row) ?? row;
1019
+ const dataRow = this._sorting.getDataIndex(row);
862
1020
  const fields = this.table.view?.target?.fields ?? [];
863
1021
  const field = fields[col];
864
- const value = getValue(this._rows.value[dataRow], field.path);
1022
+ const value = getValue2(this._rows.value[dataRow], field.path);
865
1023
  const updatedValue = update(value);
866
1024
  setValue(this._rows.value[dataRow], field.path, updatedValue);
867
1025
  }
@@ -874,9 +1032,6 @@ var TableModel = class extends Resource2 {
874
1032
  }
875
1033
  const field = this.table.view.target?.fields.find((field2) => field2.id === fieldId);
876
1034
  if (field && this._onDeleteColumn) {
877
- if (this._sorting.value?.fieldId === fieldId) {
878
- this.clearSort();
879
- }
880
1035
  this._onDeleteColumn(field.id);
881
1036
  }
882
1037
  }
@@ -894,18 +1049,6 @@ var TableModel = class extends Resource2 {
894
1049
  }
895
1050
  }
896
1051
  //
897
- // Sorting
898
- //
899
- setSort(fieldId, direction) {
900
- this._sorting.value = {
901
- fieldId,
902
- direction
903
- };
904
- }
905
- clearSort() {
906
- this._sorting.value = void 0;
907
- }
908
- //
909
1052
  // Pinning
910
1053
  //
911
1054
  // TODO(burdon): Change to setPinned(on/off).
@@ -916,15 +1059,21 @@ var TableModel = class extends Resource2 {
916
1059
  this._pinnedRows.top = this._pinnedRows.top.filter((index) => index !== rowIndex);
917
1060
  this._pinnedRows.bottom = this._pinnedRows.bottom.filter((index) => index !== rowIndex);
918
1061
  }
1062
+ //
1063
+ // View operations
1064
+ //
1065
+ saveView() {
1066
+ this._sorting.save();
1067
+ }
919
1068
  };
920
1069
 
921
1070
  // packages/ui/react-ui-table/src/model/modal-controller.ts
922
- import { signal as signal3 } from "@preact/signals-core";
923
- import { log as log2 } from "@dxos/log";
924
- var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/model/modal-controller.ts";
1071
+ import { signal as signal4 } from "@preact/signals-core";
1072
+ import { log } from "@dxos/log";
1073
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/model/modal-controller.ts";
925
1074
  var ModalController = class {
926
1075
  constructor() {
927
- this._state = signal3({
1076
+ this._state = signal4({
928
1077
  type: "closed"
929
1078
  });
930
1079
  this._triggerRef = {
@@ -984,8 +1133,8 @@ var ModalController = class {
984
1133
  onCreate
985
1134
  };
986
1135
  } else {
987
- log2.warn("anchor cell not found while creating new ref", void 0, {
988
- F: __dxlog_file3,
1136
+ log.warn("anchor cell not found while creating new ref", void 0, {
1137
+ F: __dxlog_file2,
989
1138
  L: 86,
990
1139
  S: this,
991
1140
  C: (f, a) => f(...a)
@@ -1007,14 +1156,14 @@ var ModalController = class {
1007
1156
  };
1008
1157
 
1009
1158
  // packages/ui/react-ui-table/src/model/table-presentation.ts
1010
- import { signal as signal4 } from "@preact/signals-core";
1011
- import { FormatEnum as FormatEnum3, getValue as getValue2 } from "@dxos/echo-schema";
1159
+ import { signal as signal5 } from "@preact/signals-core";
1160
+ import { FormatEnum as FormatEnum4, getValue as getValue3 } from "@dxos/echo-schema";
1012
1161
  import { cellClassesForFieldType, cellClassesForRowSelection, formatForDisplay as formatForDisplay2 } from "@dxos/react-ui-form";
1013
1162
  import { toPlaneCellIndex } from "@dxos/react-ui-grid";
1014
1163
  import { mx } from "@dxos/react-ui-theme";
1015
1164
  import { VIEW_FIELD_LIMIT } from "@dxos/schema";
1016
1165
  var TablePresentation = class {
1017
- constructor(model, _visibleRange = signal4({
1166
+ constructor(model, _visibleRange = signal5({
1018
1167
  start: {
1019
1168
  row: 0,
1020
1169
  col: 0
@@ -1053,19 +1202,20 @@ var TablePresentation = class {
1053
1202
  const { props } = this.model.projection.getFieldProjection(field.id);
1054
1203
  const cell = {
1055
1204
  get value() {
1056
- const value = getValue2(obj, field.path);
1205
+ const value = getValue3(obj, field.path);
1057
1206
  if (value == null) {
1058
1207
  return "";
1059
1208
  }
1060
1209
  switch (props.format) {
1061
- case FormatEnum3.Boolean: {
1210
+ case FormatEnum4.Boolean:
1211
+ case FormatEnum4.SingleSelect: {
1062
1212
  return "";
1063
1213
  }
1064
- case FormatEnum3.Ref: {
1214
+ case FormatEnum4.Ref: {
1065
1215
  if (!field.referencePath) {
1066
1216
  return "";
1067
1217
  }
1068
- return getValue2(value.target, field.referencePath);
1218
+ return getValue3(value.target, field.referencePath);
1069
1219
  }
1070
1220
  default: {
1071
1221
  return formatForDisplay2({
@@ -1092,8 +1242,8 @@ var TablePresentation = class {
1092
1242
  if (classes.length > 0) {
1093
1243
  cell.className = mx(classes.flat());
1094
1244
  }
1095
- if (props.format === FormatEnum3.Ref && props.referenceSchema) {
1096
- const targetObj = getValue2(obj, field.path)?.target;
1245
+ if (props.format === FormatEnum4.Ref && props.referenceSchema) {
1246
+ const targetObj = getValue3(obj, field.path)?.target;
1097
1247
  if (targetObj) {
1098
1248
  cell.accessoryHtml = tableButtons.referencedCell.render({
1099
1249
  targetId: targetObj.id,
@@ -1101,8 +1251,8 @@ var TablePresentation = class {
1101
1251
  });
1102
1252
  }
1103
1253
  }
1104
- if (props.format === FormatEnum3.Boolean) {
1105
- const value = getValue2(obj, field.path);
1254
+ if (props.format === FormatEnum4.Boolean) {
1255
+ const value = getValue3(obj, field.path);
1106
1256
  cell.accessoryHtml = tableControls.switch.render({
1107
1257
  colIndex,
1108
1258
  rowIndex: displayIndex,
@@ -1110,6 +1260,16 @@ var TablePresentation = class {
1110
1260
  });
1111
1261
  cell.readonly = true;
1112
1262
  }
1263
+ if (props.format === FormatEnum4.SingleSelect) {
1264
+ const value = getValue3(obj, field.path);
1265
+ const options = this.model.projection.getFieldProjection(field.id).props.options;
1266
+ if (options) {
1267
+ const option = options.find((o) => o.id === value);
1268
+ if (option) {
1269
+ cell.accessoryHtml = `<span class="dx-tag" data-hue="${option.color}">${option.title}</span>`;
1270
+ }
1271
+ }
1272
+ }
1113
1273
  const idx = toPlaneCellIndex({
1114
1274
  col: colIndex,
1115
1275
  row: displayIndex
@@ -1132,6 +1292,8 @@ var TablePresentation = class {
1132
1292
  const fields = this.model.table.view?.target?.fields ?? [];
1133
1293
  for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
1134
1294
  const { field, props } = this.model.projection.getFieldProjection(fields[col].id);
1295
+ const sorting = this.model.sorting?.sorting;
1296
+ const direction = sorting?.fieldId === field.id ? sorting.direction : void 0;
1135
1297
  cells[toPlaneCellIndex({
1136
1298
  col,
1137
1299
  row: 0
@@ -1140,9 +1302,16 @@ var TablePresentation = class {
1140
1302
  value: props.title ?? field.path,
1141
1303
  readonly: true,
1142
1304
  resizeHandle: "col",
1143
- accessoryHtml: tableButtons.columnSettings.render({
1305
+ accessoryHtml: `
1306
+ ${direction !== void 0 ? tableButtons.sort.render({
1307
+ fieldId: field.id,
1308
+ direction
1309
+ }) : ""}
1310
+ ${tableButtons.columnSettings.render({
1144
1311
  fieldId: field.id
1145
- })
1312
+ })}
1313
+ `,
1314
+ className: "!bg-gridHeader"
1146
1315
  };
1147
1316
  }
1148
1317
  return cells;
@@ -1192,13 +1361,14 @@ var TablePresentation = class {
1192
1361
  col: 0,
1193
1362
  row: 0
1194
1363
  })]: {
1195
- value: "",
1196
1364
  accessoryHtml: tableControls.checkbox.render({
1197
1365
  rowIndex: 0,
1198
1366
  header: true,
1199
1367
  checked: this.model.selection.allRowsSeleted.value
1200
1368
  }),
1201
- readonly: true
1369
+ className: "!bg-gridHeader",
1370
+ readonly: true,
1371
+ value: ""
1202
1372
  }
1203
1373
  };
1204
1374
  }
@@ -1208,11 +1378,12 @@ var TablePresentation = class {
1208
1378
  col: 0,
1209
1379
  row: 0
1210
1380
  })]: {
1211
- value: "",
1212
1381
  accessoryHtml: tableButtons.addColumn.render({
1213
1382
  disabled: (this.model.table.view?.target?.fields?.length ?? 0) >= VIEW_FIELD_LIMIT
1214
1383
  }),
1215
- readonly: true
1384
+ className: "!bg-gridHeader",
1385
+ readonly: true,
1386
+ value: ""
1216
1387
  }
1217
1388
  };
1218
1389
  }
@@ -1220,7 +1391,7 @@ var TablePresentation = class {
1220
1391
 
1221
1392
  // packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx
1222
1393
  import React6, { useCallback as useCallback3, useMemo as useMemo3, useRef } from "react";
1223
- import { FormatEnum as FormatEnum4 } from "@dxos/echo-schema";
1394
+ import { FormatEnum as FormatEnum5 } from "@dxos/echo-schema";
1224
1395
  import { invariant as invariant2 } from "@dxos/invariant";
1225
1396
  import { cellQuery, editorKeys, parseCellIndex, useGridContext as useGridContext2, GridCellEditor } from "@dxos/react-ui-grid";
1226
1397
 
@@ -1264,7 +1435,7 @@ var completion = ({ debug, onQuery, onMatch }) => {
1264
1435
  };
1265
1436
 
1266
1437
  // packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx
1267
- var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx";
1438
+ var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx";
1268
1439
  var newValue = Symbol.for("newValue");
1269
1440
  var createOption = (text) => ({
1270
1441
  [newValue]: true,
@@ -1282,7 +1453,7 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }
1282
1453
  const field = model.projection.view.fields[col];
1283
1454
  const fieldProjection2 = model.projection.getFieldProjection(field.id);
1284
1455
  invariant2(fieldProjection2, void 0, {
1285
- F: __dxlog_file4,
1456
+ F: __dxlog_file3,
1286
1457
  L: 67,
1287
1458
  S: void 0,
1288
1459
  A: [
@@ -1356,7 +1527,7 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }
1356
1527
  ];
1357
1528
  if (onQuery) {
1358
1529
  switch (fieldProjection.props.format) {
1359
- case FormatEnum4.Ref: {
1530
+ case FormatEnum5.Ref: {
1360
1531
  extension2.push([
1361
1532
  completion({
1362
1533
  onQuery: (text) => onQuery(fieldProjection, text),
@@ -1432,7 +1603,7 @@ var determineNavigationDelta = ({ key, shift }) => {
1432
1603
  };
1433
1604
 
1434
1605
  // packages/ui/react-ui-table/src/components/Table/Table.tsx
1435
- var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/Table/Table.tsx";
1606
+ var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/Table/Table.tsx";
1436
1607
  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";
1437
1608
  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";
1438
1609
  var frozen = {
@@ -1500,6 +1671,10 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
1500
1671
  modals.showReferencePanel(data.targetId, data.schemaId);
1501
1672
  break;
1502
1673
  }
1674
+ case "sort": {
1675
+ model?.sorting?.toggleSort(data.fieldId);
1676
+ break;
1677
+ }
1503
1678
  }
1504
1679
  return;
1505
1680
  }
@@ -1600,8 +1775,8 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
1600
1775
  if (model && props.referenceSchema && field.referencePath) {
1601
1776
  const space = getSpace4(model.table);
1602
1777
  invariant3(space, void 0, {
1603
- F: __dxlog_file5,
1604
- L: 260,
1778
+ F: __dxlog_file4,
1779
+ L: 264,
1605
1780
  S: void 0,
1606
1781
  A: [
1607
1782
  "space",
@@ -1612,7 +1787,7 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
1612
1787
  if (schema) {
1613
1788
  const { objects } = await space.db.query(Filter.schema(schema)).run();
1614
1789
  const options = objects.map((obj) => {
1615
- const value = getValue3(obj, field.referencePath);
1790
+ const value = getValue4(obj, field.referencePath);
1616
1791
  if (!value || typeof value !== "string") {
1617
1792
  return void 0;
1618
1793
  }
@@ -1685,83 +1860,83 @@ var Table = {
1685
1860
  Main: TableMain
1686
1861
  };
1687
1862
 
1688
- // packages/ui/react-ui-table/src/components/Toolbar/Toolbar.tsx
1689
- import { createContext } from "@radix-ui/react-context";
1690
- import React9 from "react";
1691
- import { Toolbar as NaturalToolbar2, useTranslation as useTranslation4 } from "@dxos/react-ui";
1692
-
1693
- // packages/ui/react-ui-table/src/components/Toolbar/common.tsx
1694
- import React8 from "react";
1695
- import { Icon, Toolbar as NaturalToolbar, Tooltip } from "@dxos/react-ui";
1696
- var buttonStyles = "min-bs-0 p-2";
1697
- var tooltipProps = {
1698
- side: "top",
1699
- classNames: "z-10"
1700
- };
1701
- var ToolbarSeparator = () => /* @__PURE__ */ React8.createElement("div", {
1702
- role: "separator",
1703
- className: "grow"
1704
- });
1705
- var ToolbarButton = ({ icon, children, ...props }) => {
1706
- return /* @__PURE__ */ React8.createElement(Tooltip.Root, null, /* @__PURE__ */ React8.createElement(Tooltip.Trigger, {
1707
- asChild: true
1708
- }, /* @__PURE__ */ React8.createElement(NaturalToolbar.Button, {
1709
- variant: "ghost",
1710
- ...props,
1711
- classNames: buttonStyles
1712
- }, /* @__PURE__ */ React8.createElement(Icon, {
1713
- icon,
1714
- size: 5
1715
- }), /* @__PURE__ */ React8.createElement("span", {
1716
- className: "sr-only"
1717
- }, children))), /* @__PURE__ */ React8.createElement(Tooltip.Portal, null, /* @__PURE__ */ React8.createElement(Tooltip.Content, tooltipProps, children, /* @__PURE__ */ React8.createElement(Tooltip.Arrow, null))));
1718
- };
1719
-
1720
- // packages/ui/react-ui-table/src/components/Toolbar/Toolbar.tsx
1721
- var [ToolbarContextProvider, useToolbarContext] = createContext("Toolbar");
1722
- var ToolbarRoot = ({ classNames, children, onAction }) => {
1723
- return /* @__PURE__ */ React9.createElement(ToolbarContextProvider, {
1724
- onAction
1725
- }, /* @__PURE__ */ React9.createElement(NaturalToolbar2.Root, {
1726
- classNames: [
1727
- "is-full shrink-0 overflow-x-auto overflow-y-hidden p-1 attention-surface",
1728
- classNames
1729
- ]
1730
- }, children));
1731
- };
1732
- var Editing = () => {
1733
- const { onAction } = useToolbarContext("Editing");
1734
- const { t } = useTranslation4(translationKey);
1735
- return /* @__PURE__ */ React9.createElement(React9.Fragment, null, /* @__PURE__ */ React9.createElement(ToolbarButton, {
1736
- value: "add-row",
1863
+ // packages/ui/react-ui-table/src/components/TableToolbar/TableToolbar.tsx
1864
+ import React8, { useCallback as useCallback5, useMemo as useMemo5 } from "react";
1865
+ import { create as create3 } from "@dxos/live-object";
1866
+ import { createGapSeparator, createMenuAction, MenuProvider, ToolbarMenu, useMenuActions } from "@dxos/react-ui-menu";
1867
+ var createTableToolbarActions = (state) => {
1868
+ const add = createMenuAction("add-row", {
1869
+ type: "add-row",
1737
1870
  icon: "ph--plus--regular",
1738
- "data-testid": "table.toolbar.add-row",
1739
- onClick: () => onAction?.({
1740
- type: "add-row"
1741
- })
1742
- }, t("add row")));
1743
- };
1744
- var Actions = () => {
1745
- const { onAction } = useToolbarContext("Actions");
1746
- const { t } = useTranslation4(translationKey);
1747
- return /* @__PURE__ */ React9.createElement(React9.Fragment, null, /* @__PURE__ */ React9.createElement(ToolbarButton, {
1748
- value: "comment",
1871
+ label: [
1872
+ "add row",
1873
+ {
1874
+ ns: translationKey
1875
+ }
1876
+ ],
1877
+ testId: "table.toolbar.add-row"
1878
+ });
1879
+ const save = createMenuAction("save-view", {
1880
+ type: "save-view",
1881
+ icon: "ph--floppy-disk--regular",
1882
+ label: [
1883
+ "save view label",
1884
+ {
1885
+ ns: translationKey
1886
+ }
1887
+ ],
1888
+ testId: "table.toolbar.save-view",
1889
+ iconOnly: false,
1890
+ hidden: !state.viewDirty
1891
+ });
1892
+ const gap = createGapSeparator();
1893
+ const comment = createMenuAction("comment", {
1894
+ type: "comment",
1749
1895
  icon: "ph--chat-text--regular",
1750
- "data-testid": "table.toolbar.comment",
1751
- onClick: () => onAction?.({
1752
- type: "comment"
1753
- })
1754
- }, t("create comment")));
1896
+ label: [
1897
+ "create comment",
1898
+ {
1899
+ ns: translationKey
1900
+ }
1901
+ ],
1902
+ testId: "table.toolbar.comment"
1903
+ });
1904
+ const nodes = [
1905
+ add,
1906
+ save,
1907
+ ...gap.nodes,
1908
+ comment
1909
+ ];
1910
+ return {
1911
+ nodes,
1912
+ edges: nodes.map(({ id: target }) => ({
1913
+ source: "root",
1914
+ target
1915
+ }))
1916
+ };
1755
1917
  };
1756
- var Toolbar = {
1757
- Root: ToolbarRoot,
1758
- Editing,
1759
- Actions,
1760
- Separator: ToolbarSeparator
1918
+ var TableToolbar = ({ classNames, viewDirty, attendableId, onAction }) => {
1919
+ const state = useMemo5(() => create3({
1920
+ viewDirty
1921
+ }), []);
1922
+ const actionsCreator = useCallback5(() => createTableToolbarActions(state), [
1923
+ state
1924
+ ]);
1925
+ const menu = useMenuActions(actionsCreator);
1926
+ return /* @__PURE__ */ React8.createElement(MenuProvider, {
1927
+ ...menu,
1928
+ attendableId,
1929
+ onAction
1930
+ }, /* @__PURE__ */ React8.createElement(ToolbarMenu, {
1931
+ classNames
1932
+ }));
1761
1933
  };
1762
1934
 
1763
1935
  // packages/ui/react-ui-table/src/hooks/useTableModel.ts
1936
+ import { effect as effect3 } from "@preact/signals-core";
1764
1937
  import { useEffect as useEffect2, useState as useState3 } from "react";
1938
+ import { useSelectionActions } from "@dxos/react-ui-attention";
1939
+ import { isNonNullable } from "@dxos/util";
1765
1940
  var useTableModel = ({ objects, table, projection, ...props }) => {
1766
1941
  const [model, setModel] = useState3();
1767
1942
  useEffect2(() => {
@@ -1794,6 +1969,26 @@ var useTableModel = ({ objects, table, projection, ...props }) => {
1794
1969
  model,
1795
1970
  objects
1796
1971
  ]);
1972
+ const { select, clear } = useSelectionActions([
1973
+ table?.id,
1974
+ table?.view?.target?.query.type
1975
+ ].filter(isNonNullable));
1976
+ useEffect2(() => {
1977
+ if (!model) {
1978
+ return;
1979
+ }
1980
+ const unsubscribe = effect3(() => {
1981
+ select([
1982
+ ...model.selection.selection.value
1983
+ ]);
1984
+ });
1985
+ return () => {
1986
+ clear();
1987
+ unsubscribe();
1988
+ };
1989
+ }, [
1990
+ model
1991
+ ]);
1797
1992
  return model;
1798
1993
  };
1799
1994
  export {
@@ -1804,8 +1999,8 @@ export {
1804
1999
  TableModel,
1805
2000
  TablePresentation,
1806
2001
  TableSchema,
2002
+ TableToolbar,
1807
2003
  TableType,
1808
- Toolbar,
1809
2004
  initializeTable,
1810
2005
  renderCheckbox,
1811
2006
  renderSwitch,
@@ -1813,7 +2008,6 @@ export {
1813
2008
  tableControls,
1814
2009
  touch,
1815
2010
  translations_default as translations,
1816
- useTableModel,
1817
- useToolbarContext
2011
+ useTableModel
1818
2012
  };
1819
2013
  //# sourceMappingURL=index.mjs.map