@dxos/react-ui-table 0.8.1-staging.391c573 → 0.8.1-staging.9eaf14f

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 (191) hide show
  1. package/dist/lib/browser/{chunk-3FR6NHPD.mjs → chunk-YWNRUF4J.mjs} +8 -6
  2. package/dist/lib/browser/chunk-YWNRUF4J.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +625 -225
  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-NB3SFHGA.cjs → chunk-TGG6OZ54.cjs} +10 -8
  8. package/dist/lib/node/chunk-TGG6OZ54.cjs.map +7 -0
  9. package/dist/lib/node/index.cjs +618 -220
  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-RLVVOZW5.mjs → chunk-KKLP54L3.mjs} +8 -6
  15. package/dist/lib/node-esm/chunk-KKLP54L3.mjs.map +7 -0
  16. package/dist/lib/node-esm/index.mjs +625 -225
  17. package/dist/lib/node-esm/index.mjs.map +4 -4
  18. package/dist/lib/node-esm/meta.json +1 -1
  19. package/dist/lib/node-esm/types/index.mjs +1 -1
  20. package/dist/types/src/components/Table/ColumnActionsMenu.d.ts.map +1 -1
  21. package/dist/types/src/components/Table/ColumnSettings.d.ts.map +1 -1
  22. package/dist/types/src/components/Table/DynamicTable.d.ts +24 -0
  23. package/dist/types/src/components/Table/DynamicTable.d.ts.map +1 -0
  24. package/dist/types/src/components/Table/DynamicTable.stories.d.ts +10 -0
  25. package/dist/types/src/components/Table/DynamicTable.stories.d.ts.map +1 -0
  26. package/dist/types/src/components/Table/RowActionsMenu.d.ts.map +1 -1
  27. package/dist/types/src/components/Table/Table.d.ts +1 -0
  28. package/dist/types/src/components/Table/Table.d.ts.map +1 -1
  29. package/dist/types/src/components/Table/Table.stories.d.ts +4 -3
  30. package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
  31. package/dist/types/src/components/Table/index.d.ts +1 -0
  32. package/dist/types/src/components/Table/index.d.ts.map +1 -1
  33. package/dist/types/src/components/Table/relations.stories.d.ts +9 -0
  34. package/dist/types/src/components/Table/relations.stories.d.ts.map +1 -0
  35. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
  36. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -1
  37. package/dist/types/src/components/testing.d.ts +7 -7
  38. package/dist/types/src/components/testing.d.ts.map +1 -1
  39. package/dist/types/src/hooks/useTableModel.d.ts +8 -9
  40. package/dist/types/src/hooks/useTableModel.d.ts.map +1 -1
  41. package/dist/types/src/model/index.d.ts +1 -0
  42. package/dist/types/src/model/index.d.ts.map +1 -1
  43. package/dist/types/src/model/selection-model.d.ts +6 -3
  44. package/dist/types/src/model/selection-model.d.ts.map +1 -1
  45. package/dist/types/src/model/table-model.d.ts +42 -16
  46. package/dist/types/src/model/table-model.d.ts.map +1 -1
  47. package/dist/types/src/model/table-presentation.d.ts +4 -4
  48. package/dist/types/src/model/table-presentation.d.ts.map +1 -1
  49. package/dist/types/src/model/table-sorting.d.ts +2 -2
  50. package/dist/types/src/model/table-sorting.d.ts.map +1 -1
  51. package/dist/types/src/types/table.d.ts +7 -32
  52. package/dist/types/src/types/table.d.ts.map +1 -1
  53. package/dist/types/src/util/dynamic-table.d.ts +31 -0
  54. package/dist/types/src/util/dynamic-table.d.ts.map +1 -0
  55. package/dist/types/src/util/index.d.ts +1 -0
  56. package/dist/types/src/util/index.d.ts.map +1 -1
  57. package/dist/types/src/util/table-controls.d.ts +2 -2
  58. package/dist/types/src/util/table-controls.d.ts.map +1 -1
  59. package/dist/types/src/util/table.d.ts +5 -3
  60. package/dist/types/src/util/table.d.ts.map +1 -1
  61. package/package.json +37 -36
  62. package/src/components/Table/ColumnActionsMenu.tsx +6 -4
  63. package/src/components/Table/ColumnSettings.tsx +5 -6
  64. package/src/components/Table/CreateRefPanel.tsx +3 -3
  65. package/src/components/Table/DynamicTable.stories.tsx +155 -0
  66. package/src/components/Table/DynamicTable.tsx +104 -0
  67. package/src/components/Table/RefPanel.tsx +3 -3
  68. package/src/components/Table/RowActionsMenu.tsx +18 -3
  69. package/src/components/Table/Table.stories.tsx +170 -115
  70. package/src/components/Table/Table.tsx +71 -26
  71. package/src/components/Table/index.ts +1 -0
  72. package/src/components/Table/relations.stories.tsx +113 -0
  73. package/src/components/TableCellEditor/TableCellEditor.stories.tsx +15 -5
  74. package/src/components/TableCellEditor/TableCellEditor.tsx +102 -4
  75. package/src/components/testing.ts +0 -1
  76. package/src/hooks/useTableModel.ts +35 -14
  77. package/src/model/index.ts +1 -0
  78. package/src/model/selection-model.ts +12 -2
  79. package/src/model/table-model.test.ts +2 -2
  80. package/src/model/table-model.ts +117 -32
  81. package/src/model/table-presentation.test.ts +2 -2
  82. package/src/model/table-presentation.ts +94 -22
  83. package/src/model/table-sorting.ts +3 -2
  84. package/src/playwright/smoke.spec.ts +2 -3
  85. package/src/types/table.ts +9 -10
  86. package/src/util/dynamic-table.ts +103 -0
  87. package/src/util/index.ts +1 -0
  88. package/src/util/table-controls.ts +4 -4
  89. package/src/util/table.ts +68 -65
  90. package/dist/lib/browser/_deprecated/index.mjs +0 -1483
  91. package/dist/lib/browser/_deprecated/index.mjs.map +0 -7
  92. package/dist/lib/browser/chunk-3FR6NHPD.mjs.map +0 -7
  93. package/dist/lib/node/_deprecated/index.cjs +0 -1511
  94. package/dist/lib/node/_deprecated/index.cjs.map +0 -7
  95. package/dist/lib/node/chunk-NB3SFHGA.cjs.map +0 -7
  96. package/dist/lib/node-esm/_deprecated/index.mjs +0 -1485
  97. package/dist/lib/node-esm/_deprecated/index.mjs.map +0 -7
  98. package/dist/lib/node-esm/chunk-RLVVOZW5.mjs.map +0 -7
  99. package/dist/types/src/_deprecated/components/Cell/Cell.d.ts +0 -12
  100. package/dist/types/src/_deprecated/components/Cell/Cell.d.ts.map +0 -1
  101. package/dist/types/src/_deprecated/components/Cell/CellCombobox.d.ts +0 -13
  102. package/dist/types/src/_deprecated/components/Cell/CellCombobox.d.ts.map +0 -1
  103. package/dist/types/src/_deprecated/components/Cell/index.d.ts +0 -2
  104. package/dist/types/src/_deprecated/components/Cell/index.d.ts.map +0 -1
  105. package/dist/types/src/_deprecated/components/ColumnMenu/ColumnMenu.d.ts +0 -23
  106. package/dist/types/src/_deprecated/components/ColumnMenu/ColumnMenu.d.ts.map +0 -1
  107. package/dist/types/src/_deprecated/components/ColumnMenu/ColumnMenu.stories.d.ts +0 -36
  108. package/dist/types/src/_deprecated/components/ColumnMenu/ColumnMenu.stories.d.ts.map +0 -1
  109. package/dist/types/src/_deprecated/components/ColumnMenu/ColumnSettings.d.ts +0 -15
  110. package/dist/types/src/_deprecated/components/ColumnMenu/ColumnSettings.d.ts.map +0 -1
  111. package/dist/types/src/_deprecated/components/ColumnMenu/ColumnSettings.stories.d.ts +0 -84
  112. package/dist/types/src/_deprecated/components/ColumnMenu/ColumnSettings.stories.d.ts.map +0 -1
  113. package/dist/types/src/_deprecated/components/ColumnMenu/index.d.ts +0 -3
  114. package/dist/types/src/_deprecated/components/ColumnMenu/index.d.ts.map +0 -1
  115. package/dist/types/src/_deprecated/components/Table/Table.d.ts +0 -20
  116. package/dist/types/src/_deprecated/components/Table/Table.d.ts.map +0 -1
  117. package/dist/types/src/_deprecated/components/Table/Table.stories.d.ts +0 -116
  118. package/dist/types/src/_deprecated/components/Table/Table.stories.d.ts.map +0 -1
  119. package/dist/types/src/_deprecated/components/Table/TableBody.d.ts +0 -12
  120. package/dist/types/src/_deprecated/components/Table/TableBody.d.ts.map +0 -1
  121. package/dist/types/src/_deprecated/components/Table/TableContext.d.ts +0 -13
  122. package/dist/types/src/_deprecated/components/Table/TableContext.d.ts.map +0 -1
  123. package/dist/types/src/_deprecated/components/Table/TableHead.d.ts +0 -9
  124. package/dist/types/src/_deprecated/components/Table/TableHead.d.ts.map +0 -1
  125. package/dist/types/src/_deprecated/components/Table/TableRootContext.d.ts +0 -17
  126. package/dist/types/src/_deprecated/components/Table/TableRootContext.d.ts.map +0 -1
  127. package/dist/types/src/_deprecated/components/Table/index.d.ts +0 -5
  128. package/dist/types/src/_deprecated/components/Table/index.d.ts.map +0 -1
  129. package/dist/types/src/_deprecated/components/Table/props.d.ts +0 -42
  130. package/dist/types/src/_deprecated/components/Table/props.d.ts.map +0 -1
  131. package/dist/types/src/_deprecated/components/index.d.ts +0 -4
  132. package/dist/types/src/_deprecated/components/index.d.ts.map +0 -1
  133. package/dist/types/src/_deprecated/helpers.d.ts +0 -91
  134. package/dist/types/src/_deprecated/helpers.d.ts.map +0 -1
  135. package/dist/types/src/_deprecated/hooks/index.d.ts +0 -5
  136. package/dist/types/src/_deprecated/hooks/index.d.ts.map +0 -1
  137. package/dist/types/src/_deprecated/hooks/useColumnSizing.d.ts +0 -12
  138. package/dist/types/src/_deprecated/hooks/useColumnSizing.d.ts.map +0 -1
  139. package/dist/types/src/_deprecated/hooks/useColumnSorting.d.ts +0 -15
  140. package/dist/types/src/_deprecated/hooks/useColumnSorting.d.ts.map +0 -1
  141. package/dist/types/src/_deprecated/hooks/usePinLastRow.d.ts +0 -3
  142. package/dist/types/src/_deprecated/hooks/usePinLastRow.d.ts.map +0 -1
  143. package/dist/types/src/_deprecated/hooks/useRowSelection.d.ts +0 -7
  144. package/dist/types/src/_deprecated/hooks/useRowSelection.d.ts.map +0 -1
  145. package/dist/types/src/_deprecated/index.d.ts +0 -8
  146. package/dist/types/src/_deprecated/index.d.ts.map +0 -1
  147. package/dist/types/src/_deprecated/schema/Schema.stories.d.ts +0 -11
  148. package/dist/types/src/_deprecated/schema/Schema.stories.d.ts.map +0 -1
  149. package/dist/types/src/_deprecated/schema/column-utils.d.ts +0 -7
  150. package/dist/types/src/_deprecated/schema/column-utils.d.ts.map +0 -1
  151. package/dist/types/src/_deprecated/schema/index.d.ts +0 -3
  152. package/dist/types/src/_deprecated/schema/index.d.ts.map +0 -1
  153. package/dist/types/src/_deprecated/schema/types.d.ts +0 -27
  154. package/dist/types/src/_deprecated/schema/types.d.ts.map +0 -1
  155. package/dist/types/src/_deprecated/theme.d.ts +0 -29
  156. package/dist/types/src/_deprecated/theme.d.ts.map +0 -1
  157. package/dist/types/src/_deprecated/translations.d.ts +0 -21
  158. package/dist/types/src/_deprecated/translations.d.ts.map +0 -1
  159. package/dist/types/src/_deprecated/types.d.ts +0 -26
  160. package/dist/types/src/_deprecated/types.d.ts.map +0 -1
  161. package/src/_deprecated/components/Cell/Cell.tsx +0 -88
  162. package/src/_deprecated/components/Cell/CellCombobox.tsx +0 -103
  163. package/src/_deprecated/components/Cell/index.ts +0 -5
  164. package/src/_deprecated/components/ColumnMenu/ColumnMenu.stories.tsx +0 -129
  165. package/src/_deprecated/components/ColumnMenu/ColumnMenu.tsx +0 -182
  166. package/src/_deprecated/components/ColumnMenu/ColumnSettings.stories.tsx +0 -108
  167. package/src/_deprecated/components/ColumnMenu/ColumnSettings.tsx +0 -207
  168. package/src/_deprecated/components/ColumnMenu/index.ts +0 -6
  169. package/src/_deprecated/components/Table/Table.stories.tsx +0 -508
  170. package/src/_deprecated/components/Table/Table.tsx +0 -301
  171. package/src/_deprecated/components/Table/TableBody.tsx +0 -82
  172. package/src/_deprecated/components/Table/TableContext.tsx +0 -34
  173. package/src/_deprecated/components/Table/TableHead.tsx +0 -78
  174. package/src/_deprecated/components/Table/TableRootContext.ts +0 -39
  175. package/src/_deprecated/components/Table/index.ts +0 -8
  176. package/src/_deprecated/components/Table/props.ts +0 -60
  177. package/src/_deprecated/components/index.ts +0 -7
  178. package/src/_deprecated/helpers.tsx +0 -526
  179. package/src/_deprecated/hooks/index.ts +0 -8
  180. package/src/_deprecated/hooks/useColumnSizing.ts +0 -46
  181. package/src/_deprecated/hooks/useColumnSorting.ts +0 -64
  182. package/src/_deprecated/hooks/usePinLastRow.ts +0 -47
  183. package/src/_deprecated/hooks/useRowSelection.ts +0 -40
  184. package/src/_deprecated/index.ts +0 -12
  185. package/src/_deprecated/schema/Schema.stories.tsx +0 -59
  186. package/src/_deprecated/schema/column-utils.ts +0 -54
  187. package/src/_deprecated/schema/index.ts +0 -6
  188. package/src/_deprecated/schema/types.ts +0 -40
  189. package/src/_deprecated/theme.ts +0 -82
  190. package/src/_deprecated/translations.ts +0 -26
  191. package/src/_deprecated/types.ts +0 -38
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  TableSchema,
3
3
  TableType
4
- } from "./chunk-3FR6NHPD.mjs";
4
+ } from "./chunk-YWNRUF4J.mjs";
5
5
 
6
6
  // packages/ui/react-ui-table/src/translations.ts
7
7
  var translationKey = "table";
@@ -36,15 +36,15 @@ var translations_default = [
36
36
  ];
37
37
 
38
38
  // packages/ui/react-ui-table/src/components/Table/Table.tsx
39
- import React7, { forwardRef, useCallback as useCallback4, useImperativeHandle, useState as useState2, useMemo as useMemo4 } from "react";
39
+ import React7, { forwardRef, useCallback as useCallback4, useImperativeHandle, useState as useState2, useMemo as useMemo4, useEffect as useEffect2 } from "react";
40
40
  import { getValue as getValue4 } from "@dxos/echo-schema";
41
41
  import { invariant as invariant3 } from "@dxos/invariant";
42
- import { Filter, getSpace as getSpace4, fullyQualifiedId } from "@dxos/react-client/echo";
42
+ import { Filter } from "@dxos/react-client/echo";
43
43
  import { useTranslation as useTranslation3 } from "@dxos/react-ui";
44
44
  import { useAttention } from "@dxos/react-ui-attention";
45
- import { Grid, closestCell } from "@dxos/react-ui-grid";
45
+ import { closestCell, Grid } from "@dxos/react-ui-grid";
46
46
  import { mx as mx2 } from "@dxos/react-ui-theme";
47
- import { isNotFalsy } from "@dxos/util";
47
+ import { isNotFalsy, safeParseInt } from "@dxos/util";
48
48
 
49
49
  // packages/ui/react-ui-table/src/components/Table/ColumnActionsMenu.tsx
50
50
  import React from "react";
@@ -72,10 +72,10 @@ var ColumnActionsMenu = ({ model, modals }) => {
72
72
  }, t("column action sort ascending")), isCurrentColumnSorted && /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
73
73
  "data-testid": "column-clear-sort",
74
74
  onClick: () => model.sorting?.clearSort()
75
- }, t("column action clear sorting")), model.getColumnCount() > 1 && /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
75
+ }, t("column action clear sorting")), model.getColumnCount() > 1 && model.features.schemaEditable && /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
76
76
  "data-testid": "column-delete",
77
77
  onClick: () => model.deleteColumn(state.fieldId)
78
- }, t("column action delete")), /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
78
+ }, t("column action delete")), model.features.schemaEditable && /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
79
79
  "data-testid": "column-settings",
80
80
  onClick: () => modals.openColumnSettings()
81
81
  }, t("column action settings"))), /* @__PURE__ */ React.createElement(DropdownMenu.Arrow, null))));
@@ -83,13 +83,12 @@ var ColumnActionsMenu = ({ model, modals }) => {
83
83
 
84
84
  // packages/ui/react-ui-table/src/components/Table/ColumnSettings.tsx
85
85
  import React2, { useCallback, useEffect, useMemo, useState } from "react";
86
- import { getSpace } from "@dxos/react-client/echo";
87
86
  import { DropdownMenu as DropdownMenu2 } from "@dxos/react-ui";
88
87
  import { FieldEditor } from "@dxos/react-ui-form";
89
88
  var ColumnSettings = ({ model, modals, onNewColumn }) => {
90
89
  const [newField, setNewField] = useState();
91
90
  const state = modals.state.value;
92
- const space = getSpace(model?.table);
91
+ const space = model?.space;
93
92
  useEffect(() => {
94
93
  if (state?.type === "columnSettings" && state.mode.type === "create" && model?.projection) {
95
94
  setNewField(model.projection.createFieldProjection());
@@ -107,12 +106,12 @@ var ColumnSettings = ({ model, modals, onNewColumn }) => {
107
106
  if (state?.type === "columnSettings") {
108
107
  const { mode } = state;
109
108
  if (mode.type === "edit") {
110
- return model?.table?.view?.target?.fields.find((f) => f.id === mode.fieldId);
109
+ return model?.view?.fields.find((f) => f.id === mode.fieldId);
111
110
  }
112
111
  }
113
112
  return void 0;
114
113
  }, [
115
- model?.table?.view?.target?.fields,
114
+ model?.view?.fields,
116
115
  state
117
116
  ]);
118
117
  const field = existingField ?? newField;
@@ -130,7 +129,7 @@ var ColumnSettings = ({ model, modals, onNewColumn }) => {
130
129
  state,
131
130
  newField
132
131
  ]);
133
- if (!model?.table?.view?.target || !model.projection || !field) {
132
+ if (!model?.view || !model.projection || !field) {
134
133
  return null;
135
134
  }
136
135
  return /* @__PURE__ */ React2.createElement(DropdownMenu2.Root, {
@@ -141,7 +140,7 @@ var ColumnSettings = ({ model, modals, onNewColumn }) => {
141
140
  }), /* @__PURE__ */ React2.createElement(DropdownMenu2.Portal, null, /* @__PURE__ */ React2.createElement(DropdownMenu2.Content, {
142
141
  classNames: "md:is-64"
143
142
  }, /* @__PURE__ */ React2.createElement(DropdownMenu2.Viewport, null, /* @__PURE__ */ React2.createElement(FieldEditor, {
144
- view: model.table.view.target,
143
+ view: model.view,
145
144
  projection: model.projection,
146
145
  field,
147
146
  registry: space?.db.schemaRegistry,
@@ -153,13 +152,13 @@ var ColumnSettings = ({ model, modals, onNewColumn }) => {
153
152
  // packages/ui/react-ui-table/src/components/Table/CreateRefPanel.tsx
154
153
  import React3, { useCallback as useCallback2, useMemo as useMemo2 } from "react";
155
154
  import { S } from "@dxos/echo-schema";
156
- import { create, getSpace as getSpace2 } from "@dxos/react-client/echo";
155
+ import { create } from "@dxos/react-client/echo";
157
156
  import { Popover } from "@dxos/react-ui";
158
157
  import { Form } from "@dxos/react-ui-form";
159
158
  import { useGridContext } from "@dxos/react-ui-grid";
160
159
  var CreateRefPanel = ({ model, modals, __gridScope }) => {
161
160
  const { id: gridId } = useGridContext("TableCellEditor", __gridScope);
162
- const space = getSpace2(model?.table);
161
+ const space = model?.space;
163
162
  const state = modals.state.value;
164
163
  const schema = useMemo2(() => {
165
164
  if (!space || state?.type !== "createRefPanel") {
@@ -200,7 +199,7 @@ var CreateRefPanel = ({ model, modals, __gridScope }) => {
200
199
  }, [
201
200
  modals
202
201
  ]);
203
- if (!model?.table?.view || !model.projection) {
202
+ if (!model?.view || !model.projection) {
204
203
  return null;
205
204
  }
206
205
  return /* @__PURE__ */ React3.createElement(Popover.Root, {
@@ -226,7 +225,6 @@ var CreateRefPanel = ({ model, modals, __gridScope }) => {
226
225
 
227
226
  // packages/ui/react-ui-table/src/components/Table/RefPanel.tsx
228
227
  import React4 from "react";
229
- import { getSpace as getSpace3 } from "@dxos/react-client/echo";
230
228
  import { Popover as Popover2 } from "@dxos/react-ui";
231
229
  import { Form as Form2 } from "@dxos/react-ui-form";
232
230
  var getRefTargetObj = (space, id) => {
@@ -238,10 +236,10 @@ var getRefTargetObj = (space, id) => {
238
236
  };
239
237
  var RefPanel = ({ model, modals }) => {
240
238
  const state = modals.state.value;
241
- const space = getSpace3(model.table);
239
+ const space = model?.space;
242
240
  const targetObj = getRefTargetObj(space, state?.type === "refPanel" ? state.targetId : void 0);
243
241
  const schema = space && state?.type === "refPanel" ? space.db.schemaRegistry.getSchema(state.typename) : void 0;
244
- if (!model.table?.view || !model.projection) {
242
+ if (!model.view || !model.projection) {
245
243
  return null;
246
244
  }
247
245
  return /* @__PURE__ */ React4.createElement(Popover2.Root, {
@@ -279,10 +277,17 @@ var RowActionsMenu = ({ model, modals }) => {
279
277
  onOpenChange: modals.close
280
278
  }, /* @__PURE__ */ React5.createElement(DropdownMenu3.VirtualTrigger, {
281
279
  virtualRef: modals.trigger
282
- }), /* @__PURE__ */ React5.createElement(DropdownMenu3.Content, null, /* @__PURE__ */ React5.createElement(DropdownMenu3.Viewport, null, /* @__PURE__ */ React5.createElement(DropdownMenu3.Item, {
280
+ }), /* @__PURE__ */ React5.createElement(DropdownMenu3.Content, null, /* @__PURE__ */ React5.createElement(DropdownMenu3.Viewport, null, model.features.dataEditable !== false && /* @__PURE__ */ React5.createElement(DropdownMenu3.Item, {
283
281
  "data-testid": "row-menu-delete",
284
282
  onClick: () => model.deleteRow(state.rowIndex)
285
- }, t(hasSelection ? "bulk delete row label" : "delete row label"))), /* @__PURE__ */ React5.createElement(DropdownMenu3.Arrow, null)));
283
+ }, t(hasSelection ? "bulk delete row label" : "delete row label")), model.rowActions?.map((action) => /* @__PURE__ */ React5.createElement(DropdownMenu3.Item, {
284
+ key: action.id,
285
+ "data-testid": `row-action-${action.id}`,
286
+ onClick: () => {
287
+ modals.close();
288
+ model.handleRowAction(action.id, state.rowIndex);
289
+ }
290
+ }, t(action.translationKey)))), /* @__PURE__ */ React5.createElement(DropdownMenu3.Arrow, null)));
286
291
  };
287
292
 
288
293
  // packages/ui/react-ui-table/src/model/table-model.ts
@@ -290,32 +295,105 @@ import { computed as computed3, effect as effect2, signal as signal3 } from "@pr
290
295
  import { Resource as Resource2 } from "@dxos/context";
291
296
  import { FormatEnum as FormatEnum3, getValue as getValue2, setValue } from "@dxos/echo-schema";
292
297
  import { invariant } from "@dxos/invariant";
293
- import { isReactiveObject, makeRef as makeRef2 } from "@dxos/live-object";
294
- import { PublicKey as PublicKey2 } from "@dxos/react-client";
298
+ import { isReactiveObject, makeRef as makeRef3 } from "@dxos/live-object";
295
299
  import { formatForEditing, parseValue } from "@dxos/react-ui-form";
296
300
 
297
301
  // packages/ui/react-ui-table/src/model/selection-model.ts
298
302
  import { computed, effect, signal } from "@preact/signals-core";
299
303
  import { Resource } from "@dxos/context";
300
304
 
305
+ // packages/ui/react-ui-table/src/util/dynamic-table.ts
306
+ import { create as create2, makeRef } from "@dxos/live-object";
307
+ import { createView, getSchemaFromPropertyDefinitions, ViewProjection } from "@dxos/schema";
308
+ var getBaseSchems = ({ typename, properties, jsonSchema, schema }) => {
309
+ if (typename && properties) {
310
+ const schema2 = getSchemaFromPropertyDefinitions(typename, properties);
311
+ return {
312
+ typename: schema2.typename,
313
+ jsonSchema: schema2.jsonSchema
314
+ };
315
+ } else if (schema) {
316
+ return {
317
+ typename: schema.typename,
318
+ jsonSchema: schema.jsonSchema
319
+ };
320
+ } else if (typename && jsonSchema) {
321
+ return {
322
+ typename,
323
+ jsonSchema
324
+ };
325
+ } else {
326
+ throw new Error("invalid properties");
327
+ }
328
+ };
329
+ var makeDynamicTable = ({ typename, jsonSchema, properties }) => {
330
+ const view = createView({
331
+ name: "dynamic-table",
332
+ typename,
333
+ jsonSchema,
334
+ ...properties && {
335
+ fields: properties.map((property) => property.name)
336
+ }
337
+ });
338
+ const table = create2(TableType, {
339
+ name: "dynamic-table",
340
+ view: makeRef(view)
341
+ });
342
+ const projection = new ViewProjection(jsonSchema, view);
343
+ if (properties && view.fields) {
344
+ setProperties(view, projection, properties);
345
+ }
346
+ return {
347
+ table,
348
+ projection
349
+ };
350
+ };
351
+ var setProperties = (view, projection, properties) => {
352
+ for (const property of properties) {
353
+ const field = view.fields.find((field2) => field2.path === property.name);
354
+ if (field) {
355
+ if (property.size !== void 0) {
356
+ field.size = property.size;
357
+ }
358
+ if (property.title !== void 0) {
359
+ const fieldProjection = projection.getFieldProjection(field.id);
360
+ projection.setFieldProjection({
361
+ ...fieldProjection,
362
+ props: {
363
+ ...fieldProjection.props,
364
+ title: property.title
365
+ }
366
+ });
367
+ }
368
+ if (property.sort) {
369
+ const fieldId = field.id;
370
+ view.query.sort = [
371
+ {
372
+ fieldId,
373
+ direction: property.sort
374
+ }
375
+ ];
376
+ }
377
+ }
378
+ }
379
+ };
380
+
301
381
  // packages/ui/react-ui-table/src/util/signals.ts
302
382
  var touch = (value) => value;
303
383
 
304
384
  // packages/ui/react-ui-table/src/util/table.ts
305
385
  import { AST, Format, FormatEnum, S as S2, TypedObject, TypeEnum } from "@dxos/echo-schema";
306
386
  import { PublicKey } from "@dxos/react-client";
307
- import { create as create2, makeRef } from "@dxos/react-client/echo";
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();
387
+ import { create as create3, makeRef as makeRef2 } from "@dxos/react-client/echo";
388
+ import { createFieldId, createView as createView2, getSchemaProperties, ViewProjection as ViewProjection2 } from "@dxos/schema";
389
+ var initializeTable = async ({ client, space, table, typename, initialRow = true }) => {
390
+ if (typename) {
391
+ const schema = await space.db.graph.getSchemaByTypename(typename, space.db);
314
392
  if (!schema) {
315
- throw new Error(`Schema not found: ${initialSchema}`);
393
+ throw new Error(`Schema not found: ${typename}`);
316
394
  }
317
395
  const fields = getSchemaProperties(schema.ast).filter((prop) => prop.format !== FormatEnum.Ref).map((prop) => prop.name);
318
- table.view = makeRef(createView({
396
+ table.view = makeRef2(createView2({
319
397
  // TODO(ZaymonFC): Don't hardcode name?
320
398
  name: "View",
321
399
  typename: schema.typename,
@@ -324,68 +402,74 @@ var initializeTable = async ({ space, table, initialRow = true, initialSchema })
324
402
  }));
325
403
  return schema;
326
404
  } 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([
405
+ const [schema] = await space.db.schemaRegistry.register([
341
406
  ContactSchema
342
407
  ]);
343
- table.view = makeRef(createView({
408
+ const fields = ContactFields;
409
+ table.view = makeRef2(createView2({
344
410
  name: "View",
345
- typename: contactSchema.typename,
346
- jsonSchema: contactSchema.jsonSchema,
347
- fields: [
348
- "name",
349
- "email",
350
- "salary",
351
- "active"
352
- ]
411
+ typename: schema.typename,
412
+ jsonSchema: schema.jsonSchema,
413
+ fields
353
414
  }));
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
- });
415
+ createProjection(schema, table.view.target);
383
416
  if (initialRow) {
384
- space.db.add(create2(contactSchema, {}));
417
+ space.db.add(create3(schema, {}));
385
418
  }
386
- return contactSchema;
419
+ return schema;
387
420
  }
388
421
  };
422
+ var ContactSchema = TypedObject({
423
+ typename: `example.com/type/${PublicKey.random().truncate()}`,
424
+ version: "0.1.0"
425
+ })({
426
+ name: S2.optional(S2.String).annotations({
427
+ [AST.TitleAnnotationId]: "Name"
428
+ }),
429
+ active: S2.optional(S2.Boolean),
430
+ email: S2.optional(Format.Email),
431
+ salary: S2.optional(Format.Currency()).annotations({
432
+ [AST.TitleAnnotationId]: "Salary"
433
+ })
434
+ });
435
+ var ContactFields = [
436
+ "name",
437
+ "email",
438
+ "salary",
439
+ "active"
440
+ ];
441
+ var createProjection = (schema, view) => {
442
+ const projection = new ViewProjection2(schema.jsonSchema, view);
443
+ projection.setFieldProjection({
444
+ field: {
445
+ id: view.fields.find((f) => f.path === "salary").id,
446
+ path: "salary",
447
+ size: 150
448
+ }
449
+ });
450
+ projection.setFieldProjection({
451
+ field: {
452
+ id: view.fields.find((f) => f.path === "active").id,
453
+ path: "active",
454
+ size: 100
455
+ }
456
+ });
457
+ projection.setFieldProjection({
458
+ field: {
459
+ id: createFieldId(),
460
+ path: "manager",
461
+ referencePath: "name"
462
+ },
463
+ props: {
464
+ property: "manager",
465
+ type: TypeEnum.Ref,
466
+ format: FormatEnum.Ref,
467
+ referenceSchema: schema.typename,
468
+ title: "Manager"
469
+ }
470
+ });
471
+ return projection;
472
+ };
389
473
 
390
474
  // packages/ui/react-ui-table/src/util/table-buttons.ts
391
475
  var BUTTON_IDENTIFIERS = {
@@ -518,7 +602,7 @@ var renderAttributes = (data) => {
518
602
  var renderInput = (baseClass, attrs, checked = false, disabled = false, preventToggle = false, testId) => {
519
603
  return `<input type="checkbox" class="${baseClass}" ${renderAttributes(attrs)} ${checked ? "checked" : ""} ${preventToggle ? 'onclick="return false"' : ""} ${disabled ? "disabled" : ""} data-testid="${testId}"/>`;
520
604
  };
521
- var renderCheckbox = ({ rowIndex, header = false, checked = false, disabled = false }) => {
605
+ var CheckboxStory = ({ rowIndex, header = false, checked = false, disabled = false }) => {
522
606
  const attrs = {
523
607
  [CONTROL_IDENTIFIERS.checkbox]: "",
524
608
  "data-row-index": rowIndex.toString(),
@@ -528,7 +612,7 @@ var renderCheckbox = ({ rowIndex, header = false, checked = false, disabled = fa
528
612
  };
529
613
  return renderInput(BASE_CLASSES.checkbox, attrs, checked, disabled, true, "table-selection");
530
614
  };
531
- var renderSwitch = ({ colIndex, rowIndex, checked = false, disabled = false }) => {
615
+ var SwitchStory = ({ colIndex, rowIndex, checked = false, disabled = false }) => {
532
616
  const attrs = {
533
617
  [CONTROL_IDENTIFIERS.switch]: "",
534
618
  "data-row-index": rowIndex.toString(),
@@ -539,7 +623,7 @@ var renderSwitch = ({ colIndex, rowIndex, checked = false, disabled = false }) =
539
623
  var tableControls = {
540
624
  checkbox: {
541
625
  attr: CONTROL_IDENTIFIERS.checkbox,
542
- render: renderCheckbox,
626
+ render: CheckboxStory,
543
627
  getData: (el) => ({
544
628
  type: "checkbox",
545
629
  rowIndex: Number(el.getAttribute("data-row-index")),
@@ -548,7 +632,7 @@ var tableControls = {
548
632
  },
549
633
  switch: {
550
634
  attr: CONTROL_IDENTIFIERS.switch,
551
- render: renderSwitch,
635
+ render: SwitchStory,
552
636
  getData: (el) => ({
553
637
  type: "switch",
554
638
  rowIndex: Number(el.getAttribute("data-row-index")),
@@ -559,9 +643,10 @@ var tableControls = {
559
643
 
560
644
  // packages/ui/react-ui-table/src/model/selection-model.ts
561
645
  var SelectionModel = class extends Resource {
562
- constructor(_rows, _onSelectionChanged) {
646
+ constructor(_rows, _selectionMode, _onSelectionChanged) {
563
647
  super();
564
648
  this._rows = _rows;
649
+ this._selectionMode = _selectionMode;
565
650
  this._onSelectionChanged = _onSelectionChanged;
566
651
  this._selection = signal(/* @__PURE__ */ new Set());
567
652
  this._validSelectedIds = computed(() => {
@@ -599,6 +684,9 @@ var SelectionModel = class extends Resource {
599
684
  if (newSelection.has(row.id)) {
600
685
  newSelection.delete(row.id);
601
686
  } else {
687
+ if (this._selectionMode === "single") {
688
+ newSelection.clear();
689
+ }
602
690
  newSelection.add(row.id);
603
691
  }
604
692
  this._selection.value = newSelection;
@@ -635,6 +723,9 @@ var SelectionModel = class extends Resource {
635
723
  get allRowsSeleted() {
636
724
  return this._allSelected;
637
725
  }
726
+ get selectionMode() {
727
+ return this._selectionMode;
728
+ }
638
729
  };
639
730
 
640
731
  // packages/ui/react-ui-table/src/model/table-sorting.ts
@@ -804,13 +895,20 @@ var TableSorting = class {
804
895
 
805
896
  // packages/ui/react-ui-table/src/model/table-model.ts
806
897
  var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/model/table-model.ts";
898
+ var defaultFeatures = {
899
+ selection: {
900
+ enabled: true,
901
+ mode: "multiple"
902
+ },
903
+ dataEditable: false,
904
+ schemaEditable: false
905
+ };
807
906
  var TableModel = class extends Resource2 {
808
- constructor({ table, projection, sorting = [], pinnedRows = {
907
+ constructor({ id, space, view, projection, features = {}, sorting = [], pinnedRows = {
809
908
  top: [],
810
909
  bottom: []
811
- }, onCellUpdate, onDeleteColumn, onDeleteRows, onInsertRow, onRowOrderChanged }) {
910
+ }, rowActions = [], onCellUpdate, onDeleteColumn, onDeleteRows, onInsertRow, onRowOrderChange, onRowAction }) {
812
911
  super();
813
- this.id = `table-model-${PublicKey2.random().truncate()}`;
814
912
  this._visibleRange = signal3({
815
913
  start: {
816
914
  row: 0,
@@ -829,7 +927,7 @@ var TableModel = class extends Resource2 {
829
927
  this._rows.value = obj;
830
928
  };
831
929
  this.getRowCount = () => this._rows.value.length;
832
- this.getColumnCount = () => this.table.view?.target?.fields.length ?? 0;
930
+ this.getColumnCount = () => this._view?.fields.length ?? 0;
833
931
  this.insertRow = (rowIndex) => {
834
932
  const row = rowIndex !== void 0 ? this._sorting.getDataIndex(rowIndex) : this._rows.value.length;
835
933
  this._onInsertRow?.(row);
@@ -838,7 +936,7 @@ var TableModel = class extends Resource2 {
838
936
  const row = this._sorting.getDataIndex(rowIndex);
839
937
  const obj = this._rows.value[row];
840
938
  const objectsToDelete = [];
841
- if (this._selection.hasSelection.value) {
939
+ if (this.features.selection.enabled && this._selection.hasSelection.value) {
842
940
  const selectedRows = this._selection.getSelectedRows();
843
941
  objectsToDelete.push(...selectedRows);
844
942
  } else {
@@ -846,8 +944,18 @@ var TableModel = class extends Resource2 {
846
944
  }
847
945
  this._onDeleteRows?.(row, objectsToDelete);
848
946
  };
947
+ this.handleRowAction = (actionId, rowIndex) => {
948
+ if (!this._onRowAction) {
949
+ return;
950
+ }
951
+ const row = this._sorting.getDataIndex(rowIndex);
952
+ const data = this._rows.value[row];
953
+ if (data) {
954
+ this._onRowAction(actionId, data);
955
+ }
956
+ };
849
957
  this.getCellData = ({ col, row }) => {
850
- const fields = this.table.view?.target?.fields ?? [];
958
+ const fields = this._view?.fields ?? [];
851
959
  if (col < 0 || col >= fields.length) {
852
960
  return void 0;
853
961
  }
@@ -876,7 +984,7 @@ var TableModel = class extends Resource2 {
876
984
  };
877
985
  this.setCellData = ({ col, row }, value) => {
878
986
  const rowIdx = this._sorting.getDataIndex(row);
879
- const fields = this.table.view?.target?.fields ?? [];
987
+ const fields = this._view?.fields ?? [];
880
988
  if (col < 0 || col >= fields.length) {
881
989
  return;
882
990
  }
@@ -885,7 +993,7 @@ var TableModel = class extends Resource2 {
885
993
  switch (props.format) {
886
994
  case FormatEnum3.Ref: {
887
995
  if (isReactiveObject(value)) {
888
- setValue(this._rows.value[rowIdx], field.path, makeRef2(value));
996
+ setValue(this._rows.value[rowIdx], field.path, makeRef3(value));
889
997
  }
890
998
  break;
891
999
  }
@@ -899,22 +1007,45 @@ var TableModel = class extends Resource2 {
899
1007
  }
900
1008
  }
901
1009
  };
902
- this._table = table;
1010
+ this._id = id;
1011
+ this._space = space;
1012
+ this._view = view;
903
1013
  this._projection = projection;
904
- this._sorting = new TableSorting(this._rows, table.view?.target, projection);
1014
+ this._features = {
1015
+ ...defaultFeatures,
1016
+ ...features
1017
+ };
1018
+ invariant(!(this._features.dataEditable && this._features.selection.enabled && this._features.selection.mode === "single"), "Single selection is not compatible with editable tables.", {
1019
+ F: __dxlog_file,
1020
+ L: 114,
1021
+ S: this,
1022
+ A: [
1023
+ "!(this._features.dataEditable && this._features.selection.enabled && this._features.selection.mode === 'single')",
1024
+ "'Single selection is not compatible with editable tables.'"
1025
+ ]
1026
+ });
1027
+ this._sorting = new TableSorting(this._rows, this._view, projection);
905
1028
  if (sorting.length > 0) {
906
1029
  const [sort] = sorting;
907
1030
  this._sorting.setSort(sort.fieldId, sort.direction);
908
1031
  }
909
1032
  this._pinnedRows = pinnedRows;
1033
+ this._rowActions = rowActions;
910
1034
  this._onInsertRow = onInsertRow;
911
1035
  this._onDeleteRows = onDeleteRows;
912
1036
  this._onDeleteColumn = onDeleteColumn;
913
1037
  this._onCellUpdate = onCellUpdate;
914
- this._onRowOrderChanged = onRowOrderChanged;
1038
+ this._onRowOrderChange = onRowOrderChange;
1039
+ this._onRowAction = onRowAction;
1040
+ }
1041
+ get id() {
1042
+ return this._id;
915
1043
  }
916
- get table() {
917
- return this._table;
1044
+ get space() {
1045
+ return this._space;
1046
+ }
1047
+ get view() {
1048
+ return this._view;
918
1049
  }
919
1050
  get projection() {
920
1051
  return this._projection;
@@ -922,19 +1053,31 @@ var TableModel = class extends Resource2 {
922
1053
  get rows() {
923
1054
  return this._sorting.sortedRows;
924
1055
  }
1056
+ get features() {
1057
+ return this._features;
1058
+ }
925
1059
  /**
926
1060
  * @reactive
927
1061
  */
928
1062
  get sorting() {
929
1063
  return this._sorting;
930
1064
  }
1065
+ /**
1066
+ * Gets the row data at the specified display index.
1067
+ */
1068
+ getRowAt(displayIndex) {
1069
+ if (displayIndex < 0 || displayIndex >= this._sorting.sortedRows.value.length) {
1070
+ return void 0;
1071
+ }
1072
+ return this._sorting.sortedRows.value[displayIndex];
1073
+ }
931
1074
  get pinnedRows() {
932
1075
  return this._pinnedRows;
933
1076
  }
934
1077
  get columnMeta() {
935
1078
  invariant(this._columnMeta, void 0, {
936
1079
  F: __dxlog_file,
937
- L: 117,
1080
+ L: 183,
938
1081
  S: this,
939
1082
  A: [
940
1083
  "this._columnMeta",
@@ -950,18 +1093,21 @@ var TableModel = class extends Resource2 {
950
1093
  get isViewDirty() {
951
1094
  return this._sorting.isDirty;
952
1095
  }
1096
+ get rowActions() {
1097
+ return this._rowActions;
1098
+ }
953
1099
  //
954
1100
  // Initialisation
955
1101
  //
956
1102
  async _open() {
957
1103
  this.initializeColumnMeta();
958
1104
  this.initializeEffects();
959
- this._selection = new SelectionModel(this._sorting.sortedRows, () => this._onRowOrderChanged?.());
1105
+ this._selection = new SelectionModel(this._sorting.sortedRows, this._features.selection.mode ?? "multiple", () => this._onRowOrderChange?.());
960
1106
  await this._selection.open(this._ctx);
961
1107
  }
962
1108
  initializeColumnMeta() {
963
1109
  this._columnMeta = computed3(() => {
964
- const fields = this._table.view?.target?.fields ?? [];
1110
+ const fields = this._view?.fields ?? [];
965
1111
  const meta = Object.fromEntries(fields.map((field, index) => [
966
1112
  index,
967
1113
  {
@@ -989,7 +1135,7 @@ var TableModel = class extends Resource2 {
989
1135
  initializeEffects() {
990
1136
  const rowOrderWatcher = effect2(() => {
991
1137
  touch(this._sorting.sortedRows.value);
992
- this._onRowOrderChanged?.();
1138
+ this._onRowOrderChange?.();
993
1139
  });
994
1140
  this._ctx.onDispose(rowOrderWatcher);
995
1141
  const rowEffectManager = effect2(() => {
@@ -998,7 +1144,7 @@ var TableModel = class extends Resource2 {
998
1144
  for (let row = start.row; row <= end.row; row++) {
999
1145
  rowEffects.push(effect2(() => {
1000
1146
  const obj = this._sorting.sortedRows.value[row];
1001
- this?._table?.view?.target?.fields.forEach((field) => touch(getValue2(obj, field.path)));
1147
+ this._view?.fields.forEach((field) => touch(getValue2(obj, field.path)));
1002
1148
  this._onCellUpdate?.({
1003
1149
  row,
1004
1150
  col: start.col,
@@ -1017,7 +1163,7 @@ var TableModel = class extends Resource2 {
1017
1163
  */
1018
1164
  updateCellData({ col, row }, update) {
1019
1165
  const dataRow = this._sorting.getDataIndex(row);
1020
- const fields = this.table.view?.target?.fields ?? [];
1166
+ const fields = this._view?.fields ?? [];
1021
1167
  const field = fields[col];
1022
1168
  const value = getValue2(this._rows.value[dataRow], field.path);
1023
1169
  const updatedValue = update(value);
@@ -1027,10 +1173,10 @@ var TableModel = class extends Resource2 {
1027
1173
  // Column Operations
1028
1174
  //
1029
1175
  deleteColumn(fieldId) {
1030
- if (!this.table.view) {
1176
+ if (!this._view) {
1031
1177
  return;
1032
1178
  }
1033
- const field = this.table.view.target?.fields.find((field2) => field2.id === fieldId);
1179
+ const field = this._view?.fields.find((field2) => field2.id === fieldId);
1034
1180
  if (field && this._onDeleteColumn) {
1035
1181
  this._onDeleteColumn(field.id);
1036
1182
  }
@@ -1039,7 +1185,7 @@ var TableModel = class extends Resource2 {
1039
1185
  // Resize
1040
1186
  //
1041
1187
  setColumnWidth(columnIndex, width) {
1042
- const fields = this.table.view?.target?.fields ?? [];
1188
+ const fields = this._view?.fields ?? [];
1043
1189
  if (columnIndex < fields.length) {
1044
1190
  const newWidth = Math.max(0, width);
1045
1191
  const field = fields[columnIndex];
@@ -1158,7 +1304,7 @@ var ModalController = class {
1158
1304
  // packages/ui/react-ui-table/src/model/table-presentation.ts
1159
1305
  import { signal as signal5 } from "@preact/signals-core";
1160
1306
  import { FormatEnum as FormatEnum4, getValue as getValue3 } from "@dxos/echo-schema";
1161
- import { cellClassesForFieldType, cellClassesForRowSelection, formatForDisplay as formatForDisplay2 } from "@dxos/react-ui-form";
1307
+ import { cellClassesForFieldType, formatForDisplay as formatForDisplay2 } from "@dxos/react-ui-form";
1162
1308
  import { toPlaneCellIndex } from "@dxos/react-ui-grid";
1163
1309
  import { mx } from "@dxos/react-ui-theme";
1164
1310
  import { VIEW_FIELD_LIMIT } from "@dxos/schema";
@@ -1177,27 +1323,40 @@ var TablePresentation = class {
1177
1323
  this._visibleRange = _visibleRange;
1178
1324
  }
1179
1325
  getCells(range, plane) {
1326
+ let cells;
1180
1327
  switch (plane) {
1181
1328
  case "grid":
1182
1329
  this._visibleRange.value = range;
1183
- return this.getMainGridCells(range);
1330
+ cells = this.getMainGridCells(range);
1331
+ break;
1184
1332
  case "frozenRowsStart":
1185
- return this.getHeaderCells(range);
1333
+ cells = this.getHeaderCells(range);
1334
+ break;
1186
1335
  case "frozenColsStart":
1187
- return this.getSelectionColumnCells(range);
1336
+ cells = this.getSelectionColumnCells(range);
1337
+ break;
1188
1338
  case "frozenColsEnd":
1189
- return this.getActionColumnCells(range);
1339
+ cells = this.getActionColumnCells(range);
1340
+ break;
1190
1341
  case "fixedStartStart":
1191
- return this.getSelectAllCell();
1342
+ cells = this.getSelectAllCell();
1343
+ break;
1192
1344
  case "fixedStartEnd":
1193
- return this.getNewColumnCell();
1345
+ cells = this.getNewColumnCell();
1346
+ break;
1194
1347
  default:
1195
- return {};
1348
+ cells = {};
1196
1349
  }
1350
+ if (plane === "grid" && this.model.features.dataEditable === false) {
1351
+ Object.values(cells).forEach((cell) => {
1352
+ cell.readonly = "text-select";
1353
+ });
1354
+ }
1355
+ return cells;
1197
1356
  }
1198
1357
  getMainGridCells(range) {
1199
1358
  const cells = {};
1200
- const fields = this.model.table.view?.target?.fields ?? [];
1359
+ const fields = this.model.view?.fields ?? [];
1201
1360
  const addCell = (obj, field, colIndex, displayIndex) => {
1202
1361
  const { props } = this.model.projection.getFieldProjection(field.id);
1203
1362
  const cell = {
@@ -1208,7 +1367,8 @@ var TablePresentation = class {
1208
1367
  }
1209
1368
  switch (props.format) {
1210
1369
  case FormatEnum4.Boolean:
1211
- case FormatEnum4.SingleSelect: {
1370
+ case FormatEnum4.SingleSelect:
1371
+ case FormatEnum4.MultiSelect: {
1212
1372
  return "";
1213
1373
  }
1214
1374
  case FormatEnum4.Ref: {
@@ -1235,7 +1395,7 @@ var TablePresentation = class {
1235
1395
  if (formatClasses) {
1236
1396
  classes.push(formatClasses);
1237
1397
  }
1238
- const rowSelectionClasses = cellClassesForRowSelection(this.model.selection.isObjectSelected(obj));
1398
+ const rowSelectionClasses = cellClassesForRowSelection(this.model.selection.isObjectSelected(obj), this.model.selection.selectionMode);
1239
1399
  if (rowSelectionClasses) {
1240
1400
  classes.push(rowSelectionClasses);
1241
1401
  }
@@ -1258,7 +1418,7 @@ var TablePresentation = class {
1258
1418
  rowIndex: displayIndex,
1259
1419
  checked: value ?? false
1260
1420
  });
1261
- cell.readonly = true;
1421
+ cell.readonly = "no-text-select";
1262
1422
  }
1263
1423
  if (props.format === FormatEnum4.SingleSelect) {
1264
1424
  const value = getValue3(obj, field.path);
@@ -1270,6 +1430,22 @@ var TablePresentation = class {
1270
1430
  }
1271
1431
  }
1272
1432
  }
1433
+ if (props.format === FormatEnum4.MultiSelect) {
1434
+ const values = getValue3(obj, field.path);
1435
+ const options = this.model.projection.getFieldProjection(field.id).props.options;
1436
+ if (options && values && values.length > 0) {
1437
+ const tags = values.map((value) => {
1438
+ const option = options.find((o) => o.id === value);
1439
+ if (option) {
1440
+ return `<span class="dx-tag" data-hue="${option.color}">${option.title}</span>`;
1441
+ }
1442
+ return null;
1443
+ }).filter(Boolean).join(" ");
1444
+ if (tags) {
1445
+ cell.accessoryHtml = tags;
1446
+ }
1447
+ }
1448
+ }
1273
1449
  const idx = toPlaneCellIndex({
1274
1450
  col: colIndex,
1275
1451
  row: displayIndex
@@ -1289,7 +1465,7 @@ var TablePresentation = class {
1289
1465
  }
1290
1466
  getHeaderCells(range) {
1291
1467
  const cells = {};
1292
- const fields = this.model.table.view?.target?.fields ?? [];
1468
+ const fields = this.model.view?.fields ?? [];
1293
1469
  for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
1294
1470
  const { field, props } = this.model.projection.getFieldProjection(fields[col].id);
1295
1471
  const sorting = this.model.sorting?.sorting;
@@ -1320,13 +1496,13 @@ var TablePresentation = class {
1320
1496
  const cells = {};
1321
1497
  for (let row = range.start.row; row <= range.end.row && row < this.model.getRowCount(); row++) {
1322
1498
  const isSelected = this.model.selection.isRowIndexSelected(row);
1323
- const classes = cellClassesForRowSelection(isSelected);
1499
+ const classes = cellClassesForRowSelection(isSelected, this.model.selection.selectionMode);
1324
1500
  cells[toPlaneCellIndex({
1325
1501
  col: 0,
1326
1502
  row
1327
1503
  })] = {
1328
1504
  value: "",
1329
- readonly: true,
1505
+ readonly: "no-text-select",
1330
1506
  className: classes ? mx(classes) : void 0,
1331
1507
  accessoryHtml: tableControls.checkbox.render({
1332
1508
  rowIndex: row,
@@ -1340,7 +1516,7 @@ var TablePresentation = class {
1340
1516
  const cells = {};
1341
1517
  for (let row = range.start.row; row <= range.end.row && row < this.model.getRowCount(); row++) {
1342
1518
  const isSelected = this.model.selection.isRowIndexSelected(row);
1343
- const classes = cellClassesForRowSelection(isSelected);
1519
+ const classes = cellClassesForRowSelection(isSelected, this.model.selection.selectionMode);
1344
1520
  cells[toPlaneCellIndex({
1345
1521
  col: 0,
1346
1522
  row
@@ -1356,6 +1532,18 @@ var TablePresentation = class {
1356
1532
  return cells;
1357
1533
  }
1358
1534
  getSelectAllCell() {
1535
+ if (!this.model.features.selection.enabled || this.model.selection.selectionMode === "single") {
1536
+ return {
1537
+ [toPlaneCellIndex({
1538
+ col: 0,
1539
+ row: 0
1540
+ })]: {
1541
+ className: "!bg-gridHeader",
1542
+ readonly: true,
1543
+ value: ""
1544
+ }
1545
+ };
1546
+ }
1359
1547
  return {
1360
1548
  [toPlaneCellIndex({
1361
1549
  col: 0,
@@ -1378,9 +1566,9 @@ var TablePresentation = class {
1378
1566
  col: 0,
1379
1567
  row: 0
1380
1568
  })]: {
1381
- accessoryHtml: tableButtons.addColumn.render({
1382
- disabled: (this.model.table.view?.target?.fields?.length ?? 0) >= VIEW_FIELD_LIMIT
1383
- }),
1569
+ accessoryHtml: this.model.features.schemaEditable ? tableButtons.addColumn.render({
1570
+ disabled: (this.model.view?.fields?.length ?? 0) >= VIEW_FIELD_LIMIT
1571
+ }) : void 0,
1384
1572
  className: "!bg-gridHeader",
1385
1573
  readonly: true,
1386
1574
  value: ""
@@ -1388,12 +1576,37 @@ var TablePresentation = class {
1388
1576
  };
1389
1577
  }
1390
1578
  };
1579
+ var cellClassesForRowSelection = (selected, selectionMode) => {
1580
+ if (!selected) {
1581
+ if (selectionMode === "single") {
1582
+ return [
1583
+ "!cursor-pointer"
1584
+ ];
1585
+ } else {
1586
+ return void 0;
1587
+ }
1588
+ }
1589
+ switch (selectionMode) {
1590
+ case "single":
1591
+ return [
1592
+ "!bg-currentRelated hover:bg-hoverSurface",
1593
+ "!cursor-pointer"
1594
+ ];
1595
+ case "multiple":
1596
+ return [
1597
+ "!bg-gridCellSelected"
1598
+ ];
1599
+ }
1600
+ };
1391
1601
 
1392
1602
  // packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx
1393
1603
  import React6, { useCallback as useCallback3, useMemo as useMemo3, useRef } from "react";
1394
1604
  import { FormatEnum as FormatEnum5 } from "@dxos/echo-schema";
1395
1605
  import { invariant as invariant2 } from "@dxos/invariant";
1606
+ import { useThemeContext } from "@dxos/react-ui";
1607
+ import { createMarkdownExtensions } from "@dxos/react-ui-editor";
1396
1608
  import { cellQuery, editorKeys, parseCellIndex, useGridContext as useGridContext2, GridCellEditor } from "@dxos/react-ui-grid";
1609
+ import { tagPickerExtension, createLinks } from "@dxos/react-ui-tag-picker";
1397
1610
 
1398
1611
  // packages/ui/react-ui-table/src/components/TableCellEditor/extension.ts
1399
1612
  import { autocompletion, pickedCompletion } from "@codemirror/autocomplete";
@@ -1445,6 +1658,7 @@ var isCreateOption = (data) => typeof data === "object" && data[newValue];
1445
1658
  var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }) => {
1446
1659
  const { id: gridId, editing, setEditing } = useGridContext2("TableCellEditor", __gridScope);
1447
1660
  const suppressNextBlur = useRef(false);
1661
+ const { themeMode } = useThemeContext();
1448
1662
  const fieldProjection = useMemo3(() => {
1449
1663
  if (!model || !editing) {
1450
1664
  return;
@@ -1454,7 +1668,7 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }
1454
1668
  const fieldProjection2 = model.projection.getFieldProjection(field.id);
1455
1669
  invariant2(fieldProjection2, void 0, {
1456
1670
  F: __dxlog_file3,
1457
- L: 67,
1671
+ L: 71,
1458
1672
  S: void 0,
1459
1673
  A: [
1460
1674
  "fieldProjection",
@@ -1477,7 +1691,10 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }
1477
1691
  setEditing(null);
1478
1692
  }, [
1479
1693
  model,
1480
- editing
1694
+ editing,
1695
+ onEnter,
1696
+ onFocus,
1697
+ setEditing
1481
1698
  ]);
1482
1699
  const handleBlur = useCallback3((value) => {
1483
1700
  if (!model || !editing) {
@@ -1509,9 +1726,7 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }
1509
1726
  editing,
1510
1727
  onFocus,
1511
1728
  onEnter,
1512
- fieldProjection,
1513
- determineNavigationAxis,
1514
- determineNavigationDelta
1729
+ fieldProjection
1515
1730
  ]);
1516
1731
  const extension = useMemo3(() => {
1517
1732
  if (!fieldProjection) {
@@ -1525,6 +1740,37 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }
1525
1740
  }
1526
1741
  })
1527
1742
  ];
1743
+ const format = fieldProjection.props.format;
1744
+ if (format === FormatEnum5.SingleSelect || format === FormatEnum5.MultiSelect) {
1745
+ extension2.push(createMarkdownExtensions({
1746
+ themeMode
1747
+ }));
1748
+ const options = fieldProjection.props.options || [];
1749
+ const mode = format === FormatEnum5.SingleSelect ? "single-select" : "multi-select";
1750
+ extension2.push(tagPickerExtension({
1751
+ mode,
1752
+ inGrid: true,
1753
+ onSearch: (text, selectedIds) => {
1754
+ return options.filter((option) => selectedIds.indexOf(option.id) === -1 && (text.length === 0 || option.title.toLowerCase().includes(text.toLowerCase()))).map((option) => ({
1755
+ id: option.id,
1756
+ label: option.title,
1757
+ hue: option.color
1758
+ }));
1759
+ },
1760
+ onUpdate: (ids) => {
1761
+ if (model && editing) {
1762
+ if (ids.length === 0) {
1763
+ return;
1764
+ }
1765
+ if (mode === "single-select") {
1766
+ handleEnter(ids[0]);
1767
+ } else {
1768
+ handleEnter(ids);
1769
+ }
1770
+ }
1771
+ }
1772
+ }));
1773
+ }
1528
1774
  if (onQuery) {
1529
1775
  switch (fieldProjection.props.format) {
1530
1776
  case FormatEnum5.Ref: {
@@ -1560,11 +1806,49 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }
1560
1806
  modals,
1561
1807
  editing,
1562
1808
  fieldProjection,
1563
- handleClose
1809
+ handleClose,
1810
+ themeMode
1564
1811
  ]);
1565
1812
  const getCellContent = useCallback3(() => {
1566
1813
  if (model && editing) {
1567
- const value = model.getCellData(parseCellIndex(editing.index));
1814
+ const cell = parseCellIndex(editing.index);
1815
+ const { col } = cell;
1816
+ const field = model.projection.view.fields[col];
1817
+ const fieldProjection2 = model.projection.getFieldProjection(field.id);
1818
+ if (fieldProjection2?.props.format === FormatEnum5.SingleSelect || fieldProjection2?.props.format === FormatEnum5.MultiSelect) {
1819
+ const value2 = model.getCellData(cell);
1820
+ if (value2 !== void 0) {
1821
+ const options = fieldProjection2.props.options || [];
1822
+ if (fieldProjection2.props.format === FormatEnum5.MultiSelect && Array.isArray(value2)) {
1823
+ const tagItems = value2.map((id) => {
1824
+ const option = options.find((o) => o.id === id);
1825
+ if (option) {
1826
+ return {
1827
+ id,
1828
+ label: option.title,
1829
+ hue: option.color
1830
+ };
1831
+ }
1832
+ return void 0;
1833
+ }).filter((item) => item !== void 0);
1834
+ return createLinks(tagItems);
1835
+ } else {
1836
+ const option = options.find((o) => o.id === value2);
1837
+ if (option) {
1838
+ const tagItem = {
1839
+ id: value2,
1840
+ label: option.title,
1841
+ hue: option.color
1842
+ };
1843
+ return createLinks([
1844
+ tagItem
1845
+ ]);
1846
+ }
1847
+ }
1848
+ }
1849
+ return "";
1850
+ }
1851
+ const value = model.getCellData(cell);
1568
1852
  return value !== void 0 ? String(value) : "";
1569
1853
  }
1570
1854
  }, [
@@ -1606,27 +1890,40 @@ var determineNavigationDelta = ({ key, shift }) => {
1606
1890
  var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/Table/Table.tsx";
1607
1891
  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";
1608
1892
  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";
1609
- var frozen = {
1610
- frozenRowsStart: 1,
1611
- frozenColsStart: 1,
1612
- frozenColsEnd: 1
1613
- };
1614
1893
  var TableRoot = ({ children, role }) => {
1615
1894
  return /* @__PURE__ */ React7.createElement("div", {
1616
1895
  role: "none",
1617
- className: mx2("relative border-bs !border-separator", role === "section" ? "attention-surface overflow-hidden [&_.dx-grid]:max-is-[--dx-grid-content-inline-size]" : "flex flex-col [&_.dx-grid]:grow [&_.dx-grid]:max-is-[--dx-grid-content-inline-size] [&_.dx-grid]:bs-0 [&_.dx-grid]:max-bs-[--dx-grid-content-block-size]")
1896
+ className: mx2("relative !border-separator", role === "section" ? "attention-surface overflow-hidden [&_.dx-grid]:max-is-[--dx-grid-content-inline-size]" : "flex flex-col [&_.dx-grid]:grow [&_.dx-grid]:max-is-[--dx-grid-content-inline-size] [&_.dx-grid]:bs-0 [&_.dx-grid]:max-bs-[--dx-grid-content-block-size]")
1618
1897
  }, children);
1619
1898
  };
1620
- var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttention }, forwardedRef) => {
1899
+ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttention, onRowClick }, forwardedRef) => {
1621
1900
  const [dxGrid, setDxGrid] = useState2(null);
1622
- const { hasAttention } = useAttention(model?.table ? fullyQualifiedId(model.table) : "table");
1901
+ const { hasAttention } = useAttention(model?.id ?? "table");
1623
1902
  const { t } = useTranslation3(translationKey);
1624
1903
  const modals = useMemo4(() => new ModalController(), []);
1904
+ const frozen = useMemo4(() => {
1905
+ const noActionColumn = model?.features.dataEditable === false && model?.features.schemaEditable === false && model.rowActions.length === 0;
1906
+ return {
1907
+ frozenRowsStart: 1,
1908
+ frozenColsStart: model?.features.selection.enabled ? 1 : 0,
1909
+ frozenColsEnd: noActionColumn ? 0 : 1
1910
+ };
1911
+ }, [
1912
+ model
1913
+ ]);
1914
+ useEffect2(() => {
1915
+ if (!presentation || !dxGrid) {
1916
+ return;
1917
+ }
1918
+ dxGrid.getCells = (range, plane) => presentation.getCells(range, plane);
1919
+ }, [
1920
+ presentation,
1921
+ dxGrid
1922
+ ]);
1625
1923
  useImperativeHandle(forwardedRef, () => {
1626
1924
  if (!presentation || !dxGrid) {
1627
1925
  return {};
1628
1926
  }
1629
- dxGrid.getCells = (range, plane) => presentation.getCells(range, plane);
1630
1927
  return {
1631
1928
  update: (cell) => {
1632
1929
  if (cell) {
@@ -1642,6 +1939,16 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
1642
1939
  dxGrid
1643
1940
  ]);
1644
1941
  const handleGridClick = useCallback4((event) => {
1942
+ const rowIndex = safeParseInt(event.target.ariaRowIndex ?? "");
1943
+ if (rowIndex != null) {
1944
+ if (onRowClick) {
1945
+ const row = model?.getRowAt(rowIndex);
1946
+ row && onRowClick(row);
1947
+ }
1948
+ if (model?.features.selection.enabled && model?.selection.selectionMode === "single") {
1949
+ model.selection.toggleSelectionForRowIndex(rowIndex);
1950
+ }
1951
+ }
1645
1952
  if (!modals) {
1646
1953
  return;
1647
1954
  }
@@ -1718,6 +2025,9 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
1718
2025
  dxGrid
1719
2026
  ]);
1720
2027
  const handleEnter = useCallback4((cell) => {
2028
+ if (!model?.features.dataEditable) {
2029
+ return;
2030
+ }
1721
2031
  if (model && cell.row === model.getRowCount() - 1) {
1722
2032
  model.insertRow(cell.row);
1723
2033
  if (dxGrid) {
@@ -1732,6 +2042,9 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
1732
2042
  dxGrid
1733
2043
  ]);
1734
2044
  const handleKeyDown = useCallback4((event) => {
2045
+ if (!model?.features.dataEditable) {
2046
+ return;
2047
+ }
1735
2048
  const cell = closestCell(event.target);
1736
2049
  if (!model || !cell) {
1737
2050
  return;
@@ -1773,10 +2086,10 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
1773
2086
  ]);
1774
2087
  const handleQuery = useCallback4(async ({ field, props }, text) => {
1775
2088
  if (model && props.referenceSchema && field.referencePath) {
1776
- const space = getSpace4(model.table);
2089
+ const space = model.space;
1777
2090
  invariant3(space, void 0, {
1778
2091
  F: __dxlog_file4,
1779
- L: 264,
2092
+ L: 312,
1780
2093
  S: void 0,
1781
2094
  A: [
1782
2095
  "space",
@@ -1809,7 +2122,8 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
1809
2122
  }
1810
2123
  return [];
1811
2124
  }, [
1812
- model
2125
+ model,
2126
+ t
1813
2127
  ]);
1814
2128
  if (!model || !modals) {
1815
2129
  return /* @__PURE__ */ React7.createElement("span", {
@@ -1818,7 +2132,7 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
1818
2132
  });
1819
2133
  }
1820
2134
  return /* @__PURE__ */ React7.createElement(Grid.Root, {
1821
- id: model.table.id ?? "table-grid"
2135
+ id: model.id ?? "table-grid"
1822
2136
  }, /* @__PURE__ */ React7.createElement(TableCellEditor, {
1823
2137
  model,
1824
2138
  modals,
@@ -1826,16 +2140,17 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
1826
2140
  onFocus: handleFocus,
1827
2141
  onQuery: handleQuery
1828
2142
  }), /* @__PURE__ */ React7.createElement(Grid.Content, {
1829
- onWheelCapture: handleWheel,
1830
2143
  className: mx2("[--dx-grid-base:var(--surface-bg)]", inlineEndLine, blockEndLine),
1831
2144
  frozen,
2145
+ // getCells={getCells}
1832
2146
  columns: model.columnMeta.value,
1833
2147
  limitRows: model.getRowCount() ?? 0,
1834
- limitColumns: model.table.view?.target?.fields?.length ?? 0,
2148
+ limitColumns: model.view?.fields?.length ?? 0,
2149
+ overscroll: "trap",
1835
2150
  onAxisResize: handleAxisResize,
1836
2151
  onClick: handleGridClick,
1837
2152
  onKeyDown: handleKeyDown,
1838
- overscroll: "trap",
2153
+ onWheelCapture: handleWheel,
1839
2154
  ref: setDxGrid
1840
2155
  }), /* @__PURE__ */ React7.createElement(RowActionsMenu, {
1841
2156
  model,
@@ -1847,10 +2162,10 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
1847
2162
  model,
1848
2163
  modals,
1849
2164
  onNewColumn: handleNewColumn
1850
- }), /* @__PURE__ */ React7.createElement(RefPanel, {
2165
+ }), /* @__PURE__ */ React7.createElement(CreateRefPanel, {
1851
2166
  model,
1852
2167
  modals
1853
- }), /* @__PURE__ */ React7.createElement(CreateRefPanel, {
2168
+ }), /* @__PURE__ */ React7.createElement(RefPanel, {
1854
2169
  model,
1855
2170
  modals
1856
2171
  }));
@@ -1860,9 +2175,150 @@ var Table = {
1860
2175
  Main: TableMain
1861
2176
  };
1862
2177
 
2178
+ // packages/ui/react-ui-table/src/components/Table/DynamicTable.tsx
2179
+ import React8, { useRef as useRef2, useMemo as useMemo5, useCallback as useCallback5 } from "react";
2180
+ import { useDefaultValue } from "@dxos/react-ui";
2181
+ import { mx as mx3 } from "@dxos/react-ui-theme";
2182
+
2183
+ // packages/ui/react-ui-table/src/hooks/useTableModel.ts
2184
+ import { effect as effect3 } from "@preact/signals-core";
2185
+ import { useEffect as useEffect3, useState as useState3 } from "react";
2186
+ import { fullyQualifiedId, getSpace } from "@dxos/react-client/echo";
2187
+ import { useSelectionActions } from "@dxos/react-ui-attention";
2188
+ import { isNonNullable } from "@dxos/util";
2189
+ var useTableModel = ({ table, projection, rows, rowActions, features, onSelectionChanged, onRowAction, ...props }) => {
2190
+ const [model, setModel] = useState3();
2191
+ useEffect3(() => {
2192
+ if (!table || !projection) {
2193
+ return;
2194
+ }
2195
+ let model2;
2196
+ const t = setTimeout(async () => {
2197
+ model2 = new TableModel({
2198
+ id: fullyQualifiedId(table),
2199
+ space: getSpace(table),
2200
+ view: table.view?.target,
2201
+ projection,
2202
+ features,
2203
+ rowActions,
2204
+ onRowAction,
2205
+ ...props
2206
+ });
2207
+ await model2.open();
2208
+ setModel(model2);
2209
+ });
2210
+ return () => {
2211
+ clearTimeout(t);
2212
+ void model2?.close();
2213
+ };
2214
+ }, [
2215
+ table,
2216
+ projection,
2217
+ table?.view?.target,
2218
+ features,
2219
+ rowActions
2220
+ ]);
2221
+ useEffect3(() => {
2222
+ if (rows) {
2223
+ model?.setRows(rows);
2224
+ }
2225
+ }, [
2226
+ model,
2227
+ rows
2228
+ ]);
2229
+ const { select, clear } = useSelectionActions([
2230
+ table?.id,
2231
+ table?.view?.target?.query.typename
2232
+ ].filter(isNonNullable));
2233
+ useEffect3(() => {
2234
+ if (!model) {
2235
+ return;
2236
+ }
2237
+ const unsubscribe = effect3(() => {
2238
+ const selectedItems = [
2239
+ ...model.selection.selection.value
2240
+ ];
2241
+ select(selectedItems);
2242
+ onSelectionChanged?.(selectedItems);
2243
+ });
2244
+ return () => {
2245
+ clear();
2246
+ unsubscribe();
2247
+ };
2248
+ }, [
2249
+ model,
2250
+ onSelectionChanged
2251
+ ]);
2252
+ return model;
2253
+ };
2254
+
2255
+ // packages/ui/react-ui-table/src/components/Table/DynamicTable.tsx
2256
+ var DynamicTable = ({ classNames, name = "example.com/dynamic-table", rows, properties, jsonSchema, schema, rowActions, onRowClick, onRowAction, ...props }) => {
2257
+ const { table, projection } = useMemo5(() => {
2258
+ const props2 = getBaseSchems({
2259
+ typename: name,
2260
+ properties,
2261
+ jsonSchema,
2262
+ schema
2263
+ });
2264
+ return makeDynamicTable({
2265
+ ...props2,
2266
+ properties
2267
+ });
2268
+ }, [
2269
+ name,
2270
+ properties,
2271
+ schema,
2272
+ jsonSchema
2273
+ ]);
2274
+ const tableRef = useRef2(null);
2275
+ const handleCellUpdate = useCallback5((cell) => {
2276
+ tableRef.current?.update?.(cell);
2277
+ }, []);
2278
+ const handleRowOrderChange = useCallback5(() => {
2279
+ tableRef.current?.update?.();
2280
+ }, []);
2281
+ const features = useDefaultValue(props.features, () => ({
2282
+ selection: {
2283
+ enabled: false
2284
+ },
2285
+ dataEditable: false
2286
+ }));
2287
+ const model = useTableModel({
2288
+ table,
2289
+ rows,
2290
+ projection,
2291
+ features,
2292
+ rowActions,
2293
+ onCellUpdate: handleCellUpdate,
2294
+ onRowOrderChange: handleRowOrderChange,
2295
+ onRowAction
2296
+ });
2297
+ const presentation = useMemo5(() => {
2298
+ if (model) {
2299
+ return new TablePresentation(model);
2300
+ }
2301
+ }, [
2302
+ model
2303
+ ]);
2304
+ return /* @__PURE__ */ React8.createElement("div", {
2305
+ role: "none",
2306
+ className: mx3("is-full bs-full grow grid", classNames)
2307
+ }, /* @__PURE__ */ React8.createElement("div", {
2308
+ role: "none",
2309
+ className: "grid min-bs-0 overflow-hidden"
2310
+ }, /* @__PURE__ */ React8.createElement(Table.Root, null, /* @__PURE__ */ React8.createElement(Table.Main, {
2311
+ ref: tableRef,
2312
+ model,
2313
+ presentation,
2314
+ ignoreAttention: true,
2315
+ onRowClick
2316
+ }))));
2317
+ };
2318
+
1863
2319
  // 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";
2320
+ import React9, { useCallback as useCallback6, useMemo as useMemo6 } from "react";
2321
+ import { create as create4 } from "@dxos/live-object";
1866
2322
  import { createGapSeparator, createMenuAction, MenuProvider, ToolbarMenu, useMenuActions } from "@dxos/react-ui-menu";
1867
2323
  var createTableToolbarActions = (state) => {
1868
2324
  const add = createMenuAction("add-row", {
@@ -1916,94 +2372,38 @@ var createTableToolbarActions = (state) => {
1916
2372
  };
1917
2373
  };
1918
2374
  var TableToolbar = ({ classNames, viewDirty, attendableId, onAction }) => {
1919
- const state = useMemo5(() => create3({
2375
+ const state = useMemo6(() => create4({
1920
2376
  viewDirty
1921
2377
  }), []);
1922
- const actionsCreator = useCallback5(() => createTableToolbarActions(state), [
2378
+ const actionsCreator = useCallback6(() => createTableToolbarActions(state), [
1923
2379
  state
1924
2380
  ]);
1925
2381
  const menu = useMenuActions(actionsCreator);
1926
- return /* @__PURE__ */ React8.createElement(MenuProvider, {
2382
+ return /* @__PURE__ */ React9.createElement(MenuProvider, {
1927
2383
  ...menu,
1928
2384
  attendableId,
1929
2385
  onAction
1930
- }, /* @__PURE__ */ React8.createElement(ToolbarMenu, {
2386
+ }, /* @__PURE__ */ React9.createElement(ToolbarMenu, {
1931
2387
  classNames
1932
2388
  }));
1933
2389
  };
1934
-
1935
- // packages/ui/react-ui-table/src/hooks/useTableModel.ts
1936
- import { effect as effect3 } from "@preact/signals-core";
1937
- import { useEffect as useEffect2, useState as useState3 } from "react";
1938
- import { useSelectionActions } from "@dxos/react-ui-attention";
1939
- import { isNonNullable } from "@dxos/util";
1940
- var useTableModel = ({ objects, table, projection, ...props }) => {
1941
- const [model, setModel] = useState3();
1942
- useEffect2(() => {
1943
- if (!table || !projection) {
1944
- return;
1945
- }
1946
- let model2;
1947
- const t = setTimeout(async () => {
1948
- model2 = new TableModel({
1949
- table,
1950
- projection,
1951
- ...props
1952
- });
1953
- await model2.open();
1954
- setModel(model2);
1955
- });
1956
- return () => {
1957
- clearTimeout(t);
1958
- void model2?.close();
1959
- };
1960
- }, [
1961
- table,
1962
- projection
1963
- ]);
1964
- useEffect2(() => {
1965
- if (objects) {
1966
- model?.setRows(objects);
1967
- }
1968
- }, [
1969
- model,
1970
- objects
1971
- ]);
1972
- const { select, clear } = useSelectionActions([
1973
- table?.id,
1974
- table?.view?.target?.query.typename
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
- ]);
1992
- return model;
1993
- };
1994
2390
  export {
1995
2391
  BUTTON_IDENTIFIERS,
1996
2392
  CONTROL_IDENTIFIERS,
2393
+ CheckboxStory,
2394
+ DynamicTable,
1997
2395
  ModalController,
2396
+ SwitchStory,
1998
2397
  Table,
1999
2398
  TableModel,
2000
2399
  TablePresentation,
2001
2400
  TableSchema,
2002
2401
  TableToolbar,
2003
2402
  TableType,
2403
+ cellClassesForRowSelection,
2404
+ getBaseSchems,
2004
2405
  initializeTable,
2005
- renderCheckbox,
2006
- renderSwitch,
2406
+ makeDynamicTable,
2007
2407
  tableButtons,
2008
2408
  tableControls,
2009
2409
  touch,