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